On Mon, Apr 30, 2018 at 12:02:14PM -0700, Kees Cook wrote: > On Sun, Apr 29, 2018 at 1:30 PM, Matthew Wilcox <willy@xxxxxxxxxxxxx> wrote: > > On Sun, Apr 29, 2018 at 09:59:27AM -0700, Kees Cook wrote: > >> Did this ever happen? > > > > Not yet. I brought it up at LSFMM, and I'll repost the patches soon. > > > >> I'd also like to see kmalloc_array_3d() or > >> something that takes three size arguments. We have a lot of this > >> pattern too: > >> > >> kmalloc(sizeof(foo) * A * B, gfp...) > >> > >> And we could turn that into: > >> > >> kmalloc_array_3d(sizeof(foo), A, B, gfp...) > > > > Are either of A or B constant? Because if so, we could just use > > kmalloc_array. If not, then kmalloc_array_3d becomes a little more > > expensive than kmalloc_array because we have to do a divide at runtime > > instead of compile-time. that's still better than allocating too few > > bytes, of course. > > Yeah, getting the order of the division is nice. Some thoughts below... > > > > > I'm wondering how far down the abc + ab + ac + bc + d rabbit-hole we're > > going to end up going. As far as we have to, I guess. > > Well, the common patterns I've seen so far are: > > a > ab > abc > a + bc > ab + cd > > For any longer multiplications, I've only found[1]: > > drivers/staging/rtl8188eu/os_dep/osdep_service.c: void **a = > kzalloc(h * sizeof(void *) + h * w * size, GFP_KERNEL); That's pretty good, although it's just an atrocious vendor driver and it turns out all of those things are constants, and it'd be far better off with just declaring an array. I bet they used to declare one on the stack ... > At the end of the day, though, I don't really like having all these > different names... > > kmalloc(), kmalloc_array(), kmalloc_ab_c(), kmalloc_array_3d() > > with their "matching" zeroing function: > > kzalloc(), kcalloc(), kzalloc_ab_c(), kmalloc_array_3d(..., gfp | __GFP_ZERO) Yes, it's not very regular. > For the multiplication cases, I wonder if we could just have: > > kmalloc_multN(gfp, a, b, c, ...) > kzalloc_multN(gfp, a, b, c, ...) > > and we can replace all kcalloc() users with kzalloc_mult2(), all > kmalloc_array() users with kmalloc_mult2(), the abc uses with > kmalloc_mult3(). I'm reluctant to do away with kcalloc() as it has the obvious heritage from user-space calloc() with the addition of GFP flags. > That said, I *do* like kmalloc_struct() as it's a very common pattern... Thanks! And way harder to misuse than kmalloc_ab_c(). > Or maybe, just leave the pattern in the name? kmalloc_ab(), > kmalloc_abc(), kmalloc_ab_c(), kmalloc_ab_cd() ? > > Getting the constant ordering right could be part of the macro > definition, maybe? i.e.: > > static inline void *kmalloc_ab(size_t a, size_t b, gfp_t flags) > { > if (__builtin_constant_p(a) && a != 0 && \ > b > SIZE_MAX / a) > return NULL; > else if (__builtin_constant_p(b) && b != 0 && \ > a > SIZE_MAX / b) > return NULL; > > return kmalloc(a * b, flags); > } Ooh, if neither a nor b is constant, it just didn't do a check ;-( This stuff is hard. > (I just wish C had a sensible way to catch overflow...) Every CPU I ever worked with had an "overflow" bit ... do we have a friend on the C standards ctte who might figure out a way to let us write code that checks it? > -Kees > > [1] git grep -E 'alloc\([^,]+[^(]\*[^)][^,]+[^(]\*[^)][^,]+[^(]\*[^)][^,]+,' I'm impressed, but it's not going to catch veryLongPointerNameThatsMeaningfulToMe = kmalloc(initialSize + numberOfEntries * entrySize + someOtherThing * yourMum, GFP_KERNEL);