Message ID | alpine.DEB.2.20.1803072212160.2814@hadrien (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Wed, Mar 07, 2018 at 10:18:21PM +0100, Julia Lawall wrote: > > Otherwise, yes, please. We could build a coccinelle rule for > > additional replacements... > > A potential semantic patch and the changes it generates are attached > below. Himanshu Jha helped with its development. Working on this > uncovered one bug, where the allocated array is too large, because the > size provided for it was a structure size, but actually only pointers to > that structure were to be stored in it. This is cool! Thanks for doing the coccinelle patch! Diffstat: 50 files changed, 81 insertions(+), 124 deletions(-) I find that pretty compelling. I'll repost the kvmalloc_struct patch imminently.
On Wed, 7 Mar 2018, Matthew Wilcox wrote: > On Wed, Mar 07, 2018 at 10:18:21PM +0100, Julia Lawall wrote: > > > Otherwise, yes, please. We could build a coccinelle rule for > > > additional replacements... > > > > A potential semantic patch and the changes it generates are attached > > below. Himanshu Jha helped with its development. Working on this > > uncovered one bug, where the allocated array is too large, because the > > size provided for it was a structure size, but actually only pointers to > > that structure were to be stored in it. > > This is cool! Thanks for doing the coccinelle patch! Diffstat: > > 50 files changed, 81 insertions(+), 124 deletions(-) > > I find that pretty compelling. I'll repost the kvmalloc_struct patch > imminently. Thanks. So it's OK to replace kmalloc and kzalloc, even though they didn't previously consider vmalloc and even though kmalloc doesn't zero? There are a few other cases that use GFP_NOFS and GFP_NOWAIT, but I didn't transform those because the comment says that the flags should be GFP_KERNEL based. Should those be transformed too? julia
On Thu, Mar 08, 2018 at 07:24:47AM +0100, Julia Lawall wrote: > On Wed, 7 Mar 2018, Matthew Wilcox wrote: > > On Wed, Mar 07, 2018 at 10:18:21PM +0100, Julia Lawall wrote: > > > > Otherwise, yes, please. We could build a coccinelle rule for > > > > additional replacements... > > > > > > A potential semantic patch and the changes it generates are attached > > > below. Himanshu Jha helped with its development. Working on this > > > uncovered one bug, where the allocated array is too large, because the > > > size provided for it was a structure size, but actually only pointers to > > > that structure were to be stored in it. > > > > This is cool! Thanks for doing the coccinelle patch! Diffstat: > > > > 50 files changed, 81 insertions(+), 124 deletions(-) > > > > I find that pretty compelling. I'll repost the kvmalloc_struct patch > > imminently. > > Thanks. So it's OK to replace kmalloc and kzalloc, even though they > didn't previously consider vmalloc and even though kmalloc doesn't zero? We'll also need to replace the corresponding places where those structs are freed with kvfree(). Can coccinelle handle that too? > There are a few other cases that use GFP_NOFS and GFP_NOWAIT, but I didn't > transform those because the comment says that the flags should be > GFP_KERNEL based. Should those be transformed too? The problem with non-GFP_KERNEL allocations is that vmalloc may have to allocate page tables, which is always done with an implicit GFP_KERNEL allocation. There's an intent to get rid of GFP_NOFS, but that's not been realised yet (and I'm not sure of our strategy to eliminate it ... I'll send a separate email about that). I'm not sure why anything's trying to allocate with GFP_NOWAIT; can you send a list of those places?
On Thu, 8 Mar 2018, Matthew Wilcox wrote: > On Thu, Mar 08, 2018 at 07:24:47AM +0100, Julia Lawall wrote: > > On Wed, 7 Mar 2018, Matthew Wilcox wrote: > > > On Wed, Mar 07, 2018 at 10:18:21PM +0100, Julia Lawall wrote: > > > > > Otherwise, yes, please. We could build a coccinelle rule for > > > > > additional replacements... > > > > > > > > A potential semantic patch and the changes it generates are attached > > > > below. Himanshu Jha helped with its development. Working on this > > > > uncovered one bug, where the allocated array is too large, because the > > > > size provided for it was a structure size, but actually only pointers to > > > > that structure were to be stored in it. > > > > > > This is cool! Thanks for doing the coccinelle patch! Diffstat: > > > > > > 50 files changed, 81 insertions(+), 124 deletions(-) > > > > > > I find that pretty compelling. I'll repost the kvmalloc_struct patch > > > imminently. > > > > Thanks. So it's OK to replace kmalloc and kzalloc, even though they > > didn't previously consider vmalloc and even though kmalloc doesn't zero? > > We'll also need to replace the corresponding places where those structs > are freed with kvfree(). Can coccinelle handle that too? This would be harder to do 100% reliably. Coccinelle would have to rely on the structure name or the structure type, if the free is in a different function. But I guess that the type should be mostly reliable, since all instances of allocations of the same type should be transformed in the same way. > > > There are a few other cases that use GFP_NOFS and GFP_NOWAIT, but I didn't > > transform those because the comment says that the flags should be > > GFP_KERNEL based. Should those be transformed too? > > The problem with non-GFP_KERNEL allocations is that vmalloc may have to > allocate page tables, which is always done with an implicit GFP_KERNEL > allocation. There's an intent to get rid of GFP_NOFS, but that's not > been realised yet (and I'm not sure of our strategy to eliminate it ... > I'll send a separate email about that). I'm not sure why anything's > trying to allocate with GFP_NOWAIT; can you send a list of those places? drivers/dma/fsl-edma.c: fsl_desc = kzalloc(sizeof(*fsl_desc) + sizeof(struct fsl_edma_sw_tcd) * sg_len, GFP_NOWAIT); drivers/dma/st_fdma.c: fdesc = kzalloc(sizeof(*fdesc) + sizeof(struct st_fdma_sw_node) * sg_len, GFP_NOWAIT); drivers/dma/pxa_dma.c: sw_desc = kzalloc(sizeof(*sw_desc) + nb_hw_desc * sizeof(struct pxad_desc_hw *), GFP_NOWAIT); julia
On Thu, 8 Mar 2018, Matthew Wilcox wrote: > On Thu, Mar 08, 2018 at 07:24:47AM +0100, Julia Lawall wrote: > > On Wed, 7 Mar 2018, Matthew Wilcox wrote: > > > On Wed, Mar 07, 2018 at 10:18:21PM +0100, Julia Lawall wrote: > > > > > Otherwise, yes, please. We could build a coccinelle rule for > > > > > additional replacements... > > > > > > > > A potential semantic patch and the changes it generates are attached > > > > below. Himanshu Jha helped with its development. Working on this > > > > uncovered one bug, where the allocated array is too large, because the > > > > size provided for it was a structure size, but actually only pointers to > > > > that structure were to be stored in it. > > > > > > This is cool! Thanks for doing the coccinelle patch! Diffstat: > > > > > > 50 files changed, 81 insertions(+), 124 deletions(-) > > > > > > I find that pretty compelling. I'll repost the kvmalloc_struct patch > > > imminently. > > > > Thanks. So it's OK to replace kmalloc and kzalloc, even though they > > didn't previously consider vmalloc and even though kmalloc doesn't zero? > > We'll also need to replace the corresponding places where those structs > are freed with kvfree(). Can coccinelle handle that too? Is the use of vmalloc a necessary part of the design? Or could there be a non vmalloc versions for call sites that are already ok with that? julia > > There are a few other cases that use GFP_NOFS and GFP_NOWAIT, but I didn't > > transform those because the comment says that the flags should be > > GFP_KERNEL based. Should those be transformed too? > > The problem with non-GFP_KERNEL allocations is that vmalloc may have to > allocate page tables, which is always done with an implicit GFP_KERNEL > allocation. There's an intent to get rid of GFP_NOFS, but that's not > been realised yet (and I'm not sure of our strategy to eliminate it ... > I'll send a separate email about that). I'm not sure why anything's > trying to allocate with GFP_NOWAIT; can you send a list of those places? >
On Tue, Mar 13, 2018 at 06:19:51PM +0100, Julia Lawall wrote: > On Thu, 8 Mar 2018, Matthew Wilcox wrote: > > On Thu, Mar 08, 2018 at 07:24:47AM +0100, Julia Lawall wrote: > > > Thanks. So it's OK to replace kmalloc and kzalloc, even though they > > > didn't previously consider vmalloc and even though kmalloc doesn't zero? > > > > We'll also need to replace the corresponding places where those structs > > are freed with kvfree(). Can coccinelle handle that too? > > Is the use of vmalloc a necessary part of the design? Or could there be a > non vmalloc versions for call sites that are already ok with that? We can also add kmalloc_struct() along with kmalloc_ab_c that won't fall back to vmalloc but just return NULL.
On Tue, 13 Mar 2018, Matthew Wilcox wrote: > On Tue, Mar 13, 2018 at 06:19:51PM +0100, Julia Lawall wrote: > > On Thu, 8 Mar 2018, Matthew Wilcox wrote: > > > On Thu, Mar 08, 2018 at 07:24:47AM +0100, Julia Lawall wrote: > > > > Thanks. So it's OK to replace kmalloc and kzalloc, even though they > > > > didn't previously consider vmalloc and even though kmalloc doesn't zero? > > > > > > We'll also need to replace the corresponding places where those structs > > > are freed with kvfree(). Can coccinelle handle that too? > > > > Is the use of vmalloc a necessary part of the design? Or could there be a > > non vmalloc versions for call sites that are already ok with that? > > We can also add kmalloc_struct() along with kmalloc_ab_c that won't fall > back to vmalloc but just return NULL. It could be safer than being sure to find all of the relevant kfrees. julia
On Tue, Mar 13, 2018 at 11:32 AM, Matthew Wilcox <willy@infradead.org> wrote: > On Tue, Mar 13, 2018 at 06:19:51PM +0100, Julia Lawall wrote: >> On Thu, 8 Mar 2018, Matthew Wilcox wrote: >> > On Thu, Mar 08, 2018 at 07:24:47AM +0100, Julia Lawall wrote: >> > > Thanks. So it's OK to replace kmalloc and kzalloc, even though they >> > > didn't previously consider vmalloc and even though kmalloc doesn't zero? >> > >> > We'll also need to replace the corresponding places where those structs >> > are freed with kvfree(). Can coccinelle handle that too? >> >> Is the use of vmalloc a necessary part of the design? Or could there be a >> non vmalloc versions for call sites that are already ok with that? > > We can also add kmalloc_struct() along with kmalloc_ab_c that won't fall > back to vmalloc but just return NULL. Did this ever happen? 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...) -Kees
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. 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.
On Sun, Apr 29, 2018 at 1:30 PM, Matthew Wilcox <willy@infradead.org> 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); 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) 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(). That said, I *do* like kmalloc_struct() as it's a very common pattern... 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); } (I just wish C had a sensible way to catch overflow...) -Kees [1] git grep -E 'alloc\([^,]+[^(]\*[^)][^,]+[^(]\*[^)][^,]+[^(]\*[^)][^,]+,'
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@infradead.org> 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);
On 2018-04-30 22:16, Matthew Wilcox wrote: > On Mon, Apr 30, 2018 at 12:02:14PM -0700, Kees Cook wrote: >> >> 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? gcc 5.1+ (I think) have the __builtin_OP_overflow checks that should generate reasonable code. Too bad there's no completely generic check_all_ops_in_this_expression(a+b*c+d/e, or_jump_here). Though it's hard to define what they should be checked against - probably would require all subexpressions (including the variables themselves) to have the same type. plug: https://lkml.org/lkml/2015/7/19/358 Rasmus
On Mon, Apr 30, 2018 at 1:16 PM, Matthew Wilcox <willy@infradead.org> wrote: > On Mon, Apr 30, 2018 at 12:02:14PM -0700, Kees Cook wrote: >> 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 ... Yeah, it was just a quick hack to look for stuff. > >> 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. But it encourages misuse with calloc(N * M, gfp) ... if we removed calloc and kept k[mz]alloc_something(gfp, a, b, c...) I think we'd have better adoption. >> That said, I *do* like kmalloc_struct() as it's a very common pattern... > > Thanks! And way harder to misuse than kmalloc_ab_c(). Yes, quite so. It's really why I went with kmalloc_array_3d(), but now I'm thinking better of it... >> 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. Yup, quite true. Obviously not the final form. ;) I meant to illustrate that we could do compile-time tricks to reorder the division in an efficient manner. >> (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? On the CPU it's not retained across multiple calculations. And the type matters too. This came up recently in a separate thread too: http://openwall.com/lists/kernel-hardening/2018/03/26/4 >> [1] git grep -E 'alloc\([^,]+[^(]\*[^)][^,]+[^(]\*[^)][^,]+[^(]\*[^)][^,]+,' > > I'm impressed, but it's not going to catch > > veryLongPointerNameThatsMeaningfulToMe = kmalloc(initialSize + > numberOfEntries * entrySize + someOtherThing * yourMum, > GFP_KERNEL); Right, it wasn't meant to be exhaustive. I just included it in case anyone wanted to go grepping around for themselves. -Kees
On Mon, Apr 30, 2018 at 11:29:04PM +0200, Rasmus Villemoes wrote: > On 2018-04-30 22:16, Matthew Wilcox wrote: > > On Mon, Apr 30, 2018 at 12:02:14PM -0700, Kees Cook wrote: > >> (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? > > gcc 5.1+ (I think) have the __builtin_OP_overflow checks that should > generate reasonable code. Too bad there's no completely generic > check_all_ops_in_this_expression(a+b*c+d/e, or_jump_here). Though it's > hard to define what they should be checked against - probably would > require all subexpressions (including the variables themselves) to have > the same type. Nevertheless these generate much better code than our current safeguards! extern void *malloc(unsigned long); #define ULONG_MAX (~0UL) #define SZ 8UL void *a(unsigned long a) { if ((ULONG_MAX / SZ) > a) return 0; return malloc(a * SZ); } void *b(unsigned long a) { unsigned long c; if (__builtin_mul_overflow(a, SZ, &c)) return 0; return malloc(c); } (a lot of code uses a constant '8' as sizeof(void *)). Here's the difference with gcc 7.3: 0: 48 b8 fe ff ff ff ff movabs $0x1ffffffffffffffe,%rax 7: ff ff 1f a: 48 39 c7 cmp %rax,%rdi d: 76 09 jbe 18 <a+0x18> f: 48 c1 e7 03 shl $0x3,%rdi 13: e9 00 00 00 00 jmpq 18 <a+0x18> 14: R_X86_64_PLT32 malloc-0x4 18: 31 c0 xor %eax,%eax 1a: c3 retq vs 20: 48 89 f8 mov %rdi,%rax 23: ba 08 00 00 00 mov $0x8,%edx 28: 48 f7 e2 mul %rdx 2b: 48 89 c7 mov %rax,%rdi 2e: 70 05 jo 35 <b+0x15> 30: e9 00 00 00 00 jmpq 35 <b+0x15> 31: R_X86_64_PLT32 malloc-0x4 35: 31 c0 xor %eax,%eax 37: c3 retq We've traded a shl for a mul (because shl doesn't set Overflow, only Carry, and that's only bit 65, not an OR of bits 35-n), but we lose the movabs and cmp. I'd rather run the second code fragment than the first.
On Mon, Apr 30, 2018 at 2:29 PM, Rasmus Villemoes <linux@rasmusvillemoes.dk> wrote: > On 2018-04-30 22:16, Matthew Wilcox wrote: >> On Mon, Apr 30, 2018 at 12:02:14PM -0700, Kees Cook wrote: >>> >>> 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? > > gcc 5.1+ (I think) have the __builtin_OP_overflow checks that should > generate reasonable code. Too bad there's no completely generic > check_all_ops_in_this_expression(a+b*c+d/e, or_jump_here). Though it's > hard to define what they should be checked against - probably would > require all subexpressions (including the variables themselves) to have > the same type. > > plug: https://lkml.org/lkml/2015/7/19/358 That's a very nice series. Why did it never get taken? It seems to do the right things quite correctly. Daniel, while this isn't a perfect solution, is this something you'd use in graphics-land? -Kees
On 2018-05-01 19:00, Kees Cook wrote: > On Mon, Apr 30, 2018 at 2:29 PM, Rasmus Villemoes > <linux@rasmusvillemoes.dk> wrote: >> >> gcc 5.1+ (I think) have the __builtin_OP_overflow checks that should >> generate reasonable code. Too bad there's no completely generic >> check_all_ops_in_this_expression(a+b*c+d/e, or_jump_here). Though it's >> hard to define what they should be checked against - probably would >> require all subexpressions (including the variables themselves) to have >> the same type. >> >> plug: https://lkml.org/lkml/2015/7/19/358 > > That's a very nice series. Why did it never get taken? Well, nobody seemed particularly interested, and then https://lkml.org/lkml/2015/10/28/215 happened... but he did later seem to admit that it could be useful for the multiplication checking, and that "the gcc interface for multiplication overflow is fine". I still think even for unsigned types overflow checking can be subtle. E.g. u32 somevar; if (somevar + sizeof(foo) < somevar) return -EOVERFLOW; somevar += sizeof(this); is broken, because the LHS is promoted to unsigned long/size_t, then so is the RHS for the comparison, and the comparison is thus always false (on 64bit). It gets worse if the two types are more "opaque", and in any case it's not always easy to verify at a glance that the types are the same, or at least that the expression of the widest type is on the RHS. > It seems to do the right things quite correctly. Yes, I wouldn't suggest it without the test module verifying corner cases, and checking it has the same semantics whether used with old or new gcc. Would you shepherd it through if I updated the patches and resent? Rasmus
On Thu, May 3, 2018 at 4:00 PM, Rasmus Villemoes <linux@rasmusvillemoes.dk> wrote: > On 2018-05-01 19:00, Kees Cook wrote: >> On Mon, Apr 30, 2018 at 2:29 PM, Rasmus Villemoes >> <linux@rasmusvillemoes.dk> wrote: >>> >>> gcc 5.1+ (I think) have the __builtin_OP_overflow checks that should >>> generate reasonable code. Too bad there's no completely generic >>> check_all_ops_in_this_expression(a+b*c+d/e, or_jump_here). Though it's >>> hard to define what they should be checked against - probably would >>> require all subexpressions (including the variables themselves) to have >>> the same type. >>> >>> plug: https://lkml.org/lkml/2015/7/19/358 >> >> That's a very nice series. Why did it never get taken? > > Well, nobody seemed particularly interested, and then > https://lkml.org/lkml/2015/10/28/215 happened... but he did later seem > to admit that it could be useful for the multiplication checking, and > that "the gcc interface for multiplication overflow is fine". Oh, excellent. Thank you for that pointer! That conversation covered a lot of ground. I need to think a little more about how to apply the thoughts there with the kmalloc() needs and the GPU driver needs... > I still think even for unsigned types overflow checking can be subtle. E.g. > > u32 somevar; > > if (somevar + sizeof(foo) < somevar) > return -EOVERFLOW; > somevar += sizeof(this); > > is broken, because the LHS is promoted to unsigned long/size_t, then so > is the RHS for the comparison, and the comparison is thus always false > (on 64bit). It gets worse if the two types are more "opaque", and in any > case it's not always easy to verify at a glance that the types are the > same, or at least that the expression of the widest type is on the RHS. That's an excellent example, yes. (And likely worth including in the commit log somewhere.) > >> It seems to do the right things quite correctly. > > Yes, I wouldn't suggest it without the test module verifying corner > cases, and checking it has the same semantics whether used with old or > new gcc. > > Would you shepherd it through if I updated the patches and resent? Yes, though we may need reworking if we actually want to do the try/catch style (since that was talked about with GPU stuff too...) Either way, yes, a refresh would be lovely! :) -Kees
On Thu, May 3, 2018 at 5:36 PM, Kees Cook <keescook@chromium.org> wrote: > On Thu, May 3, 2018 at 4:00 PM, Rasmus Villemoes > <linux@rasmusvillemoes.dk> wrote: >> On 2018-05-01 19:00, Kees Cook wrote: >>> On Mon, Apr 30, 2018 at 2:29 PM, Rasmus Villemoes >>> <linux@rasmusvillemoes.dk> wrote: >>>> >>>> gcc 5.1+ (I think) have the __builtin_OP_overflow checks that should >>>> generate reasonable code. Too bad there's no completely generic >>>> check_all_ops_in_this_expression(a+b*c+d/e, or_jump_here). Though it's >>>> hard to define what they should be checked against - probably would >>>> require all subexpressions (including the variables themselves) to have >>>> the same type. >>>> >>>> plug: https://lkml.org/lkml/2015/7/19/358 >>> >>> That's a very nice series. Why did it never get taken? >> >> Well, nobody seemed particularly interested, and then >> https://lkml.org/lkml/2015/10/28/215 happened... but he did later seem >> to admit that it could be useful for the multiplication checking, and >> that "the gcc interface for multiplication overflow is fine". > > Oh, excellent. Thank you for that pointer! That conversation covered a > lot of ground. I need to think a little more about how to apply the > thoughts there with the kmalloc() needs and the GPU driver needs... > >> I still think even for unsigned types overflow checking can be subtle. E.g. >> >> u32 somevar; >> >> if (somevar + sizeof(foo) < somevar) >> return -EOVERFLOW; >> somevar += sizeof(this); >> >> is broken, because the LHS is promoted to unsigned long/size_t, then so >> is the RHS for the comparison, and the comparison is thus always false >> (on 64bit). It gets worse if the two types are more "opaque", and in any >> case it's not always easy to verify at a glance that the types are the >> same, or at least that the expression of the widest type is on the RHS. > > That's an excellent example, yes. (And likely worth including in the > commit log somewhere.) > >> >>> It seems to do the right things quite correctly. >> >> Yes, I wouldn't suggest it without the test module verifying corner >> cases, and checking it has the same semantics whether used with old or >> new gcc. >> >> Would you shepherd it through if I updated the patches and resent? > > Yes, though we may need reworking if we actually want to do the > try/catch style (since that was talked about with GPU stuff too...) > > Either way, yes, a refresh would be lovely! :) Whatever the case, I think we need to clean up all the kmalloc() math anyway. As mentioned earlier, there are a handful of more complex cases, but the vast majority are just A * B. I've put up a series here now, and I'll send it out soon. I want to think more about 3-factor products, addition, etc: https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/log/?h=kspp/kmalloc/2-factor-products The commit logs need more details (i.e. about making constants the second argument for optimal compiler results, etc), but there's a Coccinelle-generated first pass. -Kees
diff -u -p a/drivers/irqchip/irq-bcm6345-l1.c b/drivers/irqchip/irq-bcm6345-l1.c --- a/drivers/irqchip/irq-bcm6345-l1.c +++ b/drivers/irqchip/irq-bcm6345-l1.c @@ -255,8 +255,8 @@ static int __init bcm6345_l1_init_one(st else if (intc->n_words != n_words) return -EINVAL; - cpu = intc->cpus[idx] = kzalloc(sizeof(*cpu) + n_words * sizeof(u32), - GFP_KERNEL); + cpu = intc->cpus[idx] = kvzalloc_struct(cpu, enable_cache, n_words, + GFP_KERNEL); if (!cpu) return -ENOMEM; diff -u -p a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -263,8 +263,8 @@ static int __init bcm7038_l1_init_one(st else if (intc->n_words != n_words) return -EINVAL; - cpu = intc->cpus[idx] = kzalloc(sizeof(*cpu) + n_words * sizeof(u32), - GFP_KERNEL); + cpu = intc->cpus[idx] = kvzalloc_struct(cpu, mask_cache, n_words, + GFP_KERNEL); if (!cpu) return -ENOMEM; diff -u -p a/drivers/clk/clk-efm32gg.c b/drivers/clk/clk-efm32gg.c --- a/drivers/clk/clk-efm32gg.c +++ b/drivers/clk/clk-efm32gg.c @@ -25,8 +25,7 @@ static void __init efm32gg_cmu_init(stru void __iomem *base; struct clk_hw **hws; - clk_data = kzalloc(sizeof(*clk_data) + - sizeof(*clk_data->hws) * CMU_MAX_CLKS, GFP_KERNEL); + clk_data = kvzalloc_struct(clk_data, hws, CMU_MAX_CLKS, GFP_KERNEL); if (!clk_data) return; diff -u -p a/drivers/clk/clk-gemini.c b/drivers/clk/clk-gemini.c --- a/drivers/clk/clk-gemini.c +++ b/drivers/clk/clk-gemini.c @@ -399,9 +399,8 @@ static void __init gemini_cc_init(struct int ret; int i; - gemini_clk_data = kzalloc(sizeof(*gemini_clk_data) + - sizeof(*gemini_clk_data->hws) * GEMINI_NUM_CLKS, - GFP_KERNEL); + gemini_clk_data = kvzalloc_struct(gemini_clk_data, hws, + GEMINI_NUM_CLKS, GFP_KERNEL); if (!gemini_clk_data) return; diff -u -p a/drivers/clk/clk-stm32h7.c b/drivers/clk/clk-stm32h7.c --- a/drivers/clk/clk-stm32h7.c +++ b/drivers/clk/clk-stm32h7.c @@ -1201,9 +1201,8 @@ static void __init stm32h7_rcc_init(stru const char *hse_clk, *lse_clk, *i2s_clk; struct regmap *pdrm; - clk_data = kzalloc(sizeof(*clk_data) + - sizeof(*clk_data->hws) * STM32H7_MAX_CLKS, - GFP_KERNEL); + clk_data = kvzalloc_struct(clk_data, hws, STM32H7_MAX_CLKS, + GFP_KERNEL); if (!clk_data) return; diff -u -p a/drivers/clk/bcm/clk-iproc-asiu.c b/drivers/clk/bcm/clk-iproc-asiu.c --- a/drivers/clk/bcm/clk-iproc-asiu.c +++ b/drivers/clk/bcm/clk-iproc-asiu.c @@ -197,8 +197,8 @@ void __init iproc_asiu_setup(struct devi if (WARN_ON(!asiu)) return; - asiu->clk_data = kzalloc(sizeof(*asiu->clk_data->hws) * num_clks + - sizeof(*asiu->clk_data), GFP_KERNEL); + asiu->clk_data = kvzalloc_struct(asiu->clk_data, hws, num_clks, + GFP_KERNEL); if (WARN_ON(!asiu->clk_data)) goto err_clks; asiu->clk_data->num = num_clks; diff -u -p a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c --- a/drivers/clk/bcm/clk-iproc-pll.c +++ b/drivers/clk/bcm/clk-iproc-pll.c @@ -744,8 +744,7 @@ void iproc_pll_clk_setup(struct device_n if (WARN_ON(!pll)) return; - clk_data = kzalloc(sizeof(*clk_data->hws) * num_clks + - sizeof(*clk_data), GFP_KERNEL); + clk_data = kvzalloc_struct(clk_data, hws, num_clks, GFP_KERNEL); if (WARN_ON(!clk_data)) goto err_clk_data; clk_data->num = num_clks; diff -u -p a/drivers/clk/clk-asm9260.c b/drivers/clk/clk-asm9260.c --- a/drivers/clk/clk-asm9260.c +++ b/drivers/clk/clk-asm9260.c @@ -273,8 +273,7 @@ static void __init asm9260_acc_init(stru int n; u32 accuracy = 0; - clk_data = kzalloc(sizeof(*clk_data) + - sizeof(*clk_data->hws) * MAX_CLKS, GFP_KERNEL); + clk_data = kvzalloc_struct(clk_data, hws, MAX_CLKS, GFP_KERNEL); if (!clk_data) return; clk_data->num = MAX_CLKS; diff -u -p a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c --- a/drivers/clk/clk-aspeed.c +++ b/drivers/clk/clk-aspeed.c @@ -621,9 +621,8 @@ static void __init aspeed_cc_init(struct if (!scu_base) return; - aspeed_clk_data = kzalloc(sizeof(*aspeed_clk_data) + - sizeof(*aspeed_clk_data->hws) * ASPEED_NUM_CLKS, - GFP_KERNEL); + aspeed_clk_data = kvzalloc_struct(aspeed_clk_data, hws, + ASPEED_NUM_CLKS, GFP_KERNEL); if (!aspeed_clk_data) return; diff -u -p a/drivers/clk/berlin/bg2.c b/drivers/clk/berlin/bg2.c --- a/drivers/clk/berlin/bg2.c +++ b/drivers/clk/berlin/bg2.c @@ -509,8 +509,7 @@ static void __init berlin2_clock_setup(s u8 avpll_flags = 0; int n, ret; - clk_data = kzalloc(sizeof(*clk_data) + - sizeof(*clk_data->hws) * MAX_CLKS, GFP_KERNEL); + clk_data = kvzalloc_struct(clk_data, hws, MAX_CLKS, GFP_KERNEL); if (!clk_data) return; clk_data->num = MAX_CLKS; diff -u -p a/drivers/clk/berlin/bg2q.c b/drivers/clk/berlin/bg2q.c --- a/drivers/clk/berlin/bg2q.c +++ b/drivers/clk/berlin/bg2q.c @@ -295,8 +295,7 @@ static void __init berlin2q_clock_setup( struct clk_hw **hws; int n, ret; - clk_data = kzalloc(sizeof(*clk_data) + - sizeof(*clk_data->hws) * MAX_CLKS, GFP_KERNEL); + clk_data = kvzalloc_struct(clk_data, hws, MAX_CLKS, GFP_KERNEL); if (!clk_data) return; clk_data->num = MAX_CLKS; diff -u -p a/drivers/input/input-leds.c b/drivers/input/input-leds.c --- a/drivers/input/input-leds.c +++ b/drivers/input/input-leds.c @@ -97,8 +97,7 @@ static int input_leds_connect(struct inp if (!num_leds) return -ENXIO; - leds = kzalloc(sizeof(*leds) + num_leds * sizeof(*leds->leds), - GFP_KERNEL); + leds = kvzalloc_struct(leds, leds, num_leds, GFP_KERNEL); if (!leds) return -ENOMEM; diff -u -p a/drivers/input/input-mt.c b/drivers/input/input-mt.c --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c @@ -49,7 +49,7 @@ int input_mt_init_slots(struct input_dev if (mt) return mt->num_slots != num_slots ? -EINVAL : 0; - mt = kzalloc(sizeof(*mt) + num_slots * sizeof(*mt->slots), GFP_KERNEL); + mt = kvzalloc_struct(mt, slots, num_slots, GFP_KERNEL); if (!mt) goto err_mem; diff -u -p a/drivers/dax/device.c b/drivers/dax/device.c --- a/drivers/dax/device.c +++ b/drivers/dax/device.c @@ -586,7 +586,7 @@ struct dev_dax *devm_create_dev_dax(stru if (!count) return ERR_PTR(-EINVAL); - dev_dax = kzalloc(sizeof(*dev_dax) + sizeof(*res) * count, GFP_KERNEL); + dev_dax = kvzalloc_struct(dev_dax, res, count, GFP_KERNEL); if (!dev_dax) return ERR_PTR(-ENOMEM); diff -u -p a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -1286,9 +1286,8 @@ static struct usb_function *f_midi_alloc } /* allocate and initialize one new instance */ - midi = kzalloc( - sizeof(*midi) + opts->in_ports * sizeof(*midi->in_ports_array), - GFP_KERNEL); + midi = kvzalloc_struct(midi, in_ports_array, opts->in_ports, + GFP_KERNEL); if (!midi) { status = -ENOMEM; goto setup_fail; diff -u -p a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -1015,7 +1015,8 @@ int usbatm_usb_probe(struct usb_interfac unsigned int maxpacket, num_packets; /* instance init */ - instance = kzalloc(sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL); + instance = kvzalloc_struct(instance, urbs, + (num_rcv_urbs + num_snd_urbs), GFP_KERNEL); if (!instance) return -ENOMEM; diff -u -p a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c --- a/drivers/hwspinlock/omap_hwspinlock.c +++ b/drivers/hwspinlock/omap_hwspinlock.c @@ -132,7 +132,7 @@ static int omap_hwspinlock_probe(struct num_locks = i * 32; /* actual number of locks in this device */ - bank = kzalloc(sizeof(*bank) + num_locks * sizeof(*hwlock), GFP_KERNEL); + bank = kvzalloc_struct(bank, lock, num_locks, GFP_KERNEL); if (!bank) { ret = -ENOMEM; goto iounmap_base; diff -u -p a/drivers/hwspinlock/u8500_hsem.c b/drivers/hwspinlock/u8500_hsem.c --- a/drivers/hwspinlock/u8500_hsem.c +++ b/drivers/hwspinlock/u8500_hsem.c @@ -119,7 +119,7 @@ static int u8500_hsem_probe(struct platf /* clear all interrupts */ writel(0xFFFF, io_base + HSEM_ICRALL); - bank = kzalloc(sizeof(*bank) + num_locks * sizeof(*hwlock), GFP_KERNEL); + bank = kvzalloc_struct(bank, lock, num_locks, GFP_KERNEL); if (!bank) { ret = -ENOMEM; goto iounmap_base; diff -u -p a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -367,9 +367,9 @@ static struct mvs_info *mvs_pci_alloc(st struct mvs_info *mvi = NULL; struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - mvi = kzalloc(sizeof(*mvi) + - (1L << mvs_chips[ent->driver_data].slot_width) * - sizeof(struct mvs_slot_info), GFP_KERNEL); + mvi = kvzalloc_struct(mvi, slot_info, + (1L << mvs_chips[ent->driver_data].slot_width), + GFP_KERNEL); if (!mvi) return NULL; diff -u -p a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -2633,7 +2633,7 @@ static int crypt_ctr(struct dm_target *t return -EINVAL; } - cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL); + cc = kvzalloc_struct(cc, key, key_size, GFP_KERNEL); if (!cc) { ti->error = "Cannot allocate encryption context"; return -ENOMEM; diff -u -p a/drivers/md/md-linear.c b/drivers/md/md-linear.c --- a/drivers/md/md-linear.c +++ b/drivers/md/md-linear.c @@ -96,8 +96,7 @@ static struct linear_conf *linear_conf(s int i, cnt; bool discard_supported = false; - conf = kzalloc (sizeof (*conf) + raid_disks*sizeof(struct dev_info), - GFP_KERNEL); + conf = kvzalloc_struct(conf, disks, raid_disks, GFP_KERNEL); if (!conf) return NULL; diff -u -p a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -779,8 +779,8 @@ nvkm_perfdom_new(struct nvkm_pm *pm, con sdom = spec; while (sdom->signal_nr) { - dom = kzalloc(sizeof(*dom) + sdom->signal_nr * - sizeof(*dom->signal), GFP_KERNEL); + dom = kvzalloc_struct(dom, signal, sdom->signal_nr, + GFP_KERNEL); if (!dom) return -ENOMEM; diff -u -p a/drivers/gpu/drm/i915/selftests/mock_dmabuf.c b/drivers/gpu/drm/i915/selftests/mock_dmabuf.c --- a/drivers/gpu/drm/i915/selftests/mock_dmabuf.c +++ b/drivers/gpu/drm/i915/selftests/mock_dmabuf.c @@ -145,8 +145,7 @@ static struct dma_buf *mock_dmabuf(int n struct dma_buf *dmabuf; int i; - mock = kmalloc(sizeof(*mock) + npages * sizeof(struct page *), - GFP_KERNEL); + mock = kvzalloc_struct(mock, pages, npages, GFP_KERNEL); if (!mock) return ERR_PTR(-ENOMEM); diff -u -p a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -433,8 +433,7 @@ static struct port_buffer *alloc_buf(str * Allocate buffer and the sg list. The sg list array is allocated * directly after the port_buffer struct. */ - buf = kmalloc(sizeof(*buf) + sizeof(struct scatterlist) * pages, - GFP_KERNEL); + buf = kvzalloc_struct(buf, sg, pages, GFP_KERNEL); if (!buf) goto fail; diff -u -p a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -968,8 +968,7 @@ struct virtqueue *__vring_new_virtqueue( unsigned int i; struct vring_virtqueue *vq; - vq = kmalloc(sizeof(*vq) + vring.num * sizeof(struct vring_desc_state), - GFP_KERNEL); + vq = kvzalloc_struct(vq, desc_state, vring.num, GFP_KERNEL); if (!vq) return NULL; diff -u -p a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c --- a/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-eeprom-parse.c @@ -851,9 +851,7 @@ iwl_parse_eeprom_data(struct device *dev if (WARN_ON(!cfg || !cfg->eeprom_params)) return NULL; - data = kzalloc(sizeof(*data) + - sizeof(struct ieee80211_channel) * IWL_NUM_CHANNELS, - GFP_KERNEL); + data = kvzalloc_struct(data, channels, IWL_NUM_CHANNELS, GFP_KERNEL); if (!data) return NULL; diff -u -p a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c @@ -421,8 +421,7 @@ struct nfp_reprs *nfp_reprs_alloc(unsign { struct nfp_reprs *reprs; - reprs = kzalloc(sizeof(*reprs) + - num_reprs * sizeof(struct net_device *), GFP_KERNEL); + reprs = kvzalloc_struct(reprs, reprs, num_reprs, GFP_KERNEL); if (!reprs) return NULL; reprs->num_reprs = num_reprs; diff -u -p a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -505,8 +505,7 @@ static inline struct rdma_hw_stats *rdma { struct rdma_hw_stats *stats; - stats = kzalloc(sizeof(*stats) + num_counters * sizeof(u64), - GFP_KERNEL); + stats = kvzalloc_struct(stats, value, num_counters, GFP_KERNEL); if (!stats) return NULL; stats->names = names; diff -u -p a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c --- a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c +++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c @@ -289,8 +289,7 @@ struct clip_tbl *t4_init_clip_tbl(unsign if (clipt_size < CLIPT_MIN_HASH_BUCKETS) return NULL; - ctbl = kvzalloc(sizeof(*ctbl) + - clipt_size*sizeof(struct list_head), GFP_KERNEL); + ctbl = kvzalloc_struct(ctbl, hash_list, clipt_size, GFP_KERNEL); if (!ctbl) return NULL; diff -u -p a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -646,7 +646,7 @@ struct l2t_data *t4_init_l2t(unsigned in if (l2t_size < L2T_MIN_HASH_BUCKETS) return NULL; - d = kvzalloc(sizeof(*d) + l2t_size * sizeof(struct l2t_entry), GFP_KERNEL); + d = kvzalloc_struct(d, l2tab, l2t_size, GFP_KERNEL); if (!d) return NULL; diff -u -p a/drivers/net/ethernet/chelsio/cxgb4/sched.c b/drivers/net/ethernet/chelsio/cxgb4/sched.c --- a/drivers/net/ethernet/chelsio/cxgb4/sched.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sched.c @@ -512,7 +512,7 @@ struct sched_table *t4_init_sched(unsign struct sched_table *s; unsigned int i; - s = kvzalloc(sizeof(*s) + sched_size * sizeof(struct sched_class), GFP_KERNEL); + s = kvzalloc_struct(s, tab, sched_size, GFP_KERNEL); if (!s) return NULL; diff -u -p a/drivers/net/ethernet/chelsio/cxgb4/smt.c b/drivers/net/ethernet/chelsio/cxgb4/smt.c --- a/drivers/net/ethernet/chelsio/cxgb4/smt.c +++ b/drivers/net/ethernet/chelsio/cxgb4/smt.c @@ -47,8 +47,7 @@ struct smt_data *t4_init_smt(void) smt_size = SMT_SIZE; - s = kvzalloc(sizeof(*s) + smt_size * sizeof(struct smt_entry), - GFP_KERNEL); + s = kvzalloc_struct(s, smtab, smt_size, GFP_KERNEL); if (!s) return NULL; s->smt_size = smt_size; diff -u -p a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -505,8 +505,7 @@ static inline struct rdma_hw_stats *rdma { struct rdma_hw_stats *stats; - stats = kzalloc(sizeof(*stats) + num_counters * sizeof(u64), - GFP_KERNEL); + stats = kvzalloc_struct(stats, value, num_counters, GFP_KERNEL); if (!stats) return NULL; stats->names = names; diff -u -p a/drivers/misc/vexpress-syscfg.c b/drivers/misc/vexpress-syscfg.c --- a/drivers/misc/vexpress-syscfg.c +++ b/drivers/misc/vexpress-syscfg.c @@ -182,8 +182,7 @@ static struct regmap *vexpress_syscfg_re val = energy_quirk; } - func = kzalloc(sizeof(*func) + sizeof(*func->template) * num, - GFP_KERNEL); + func = kvzalloc_struct(func, template, num, GFP_KERNEL); if (!func) return ERR_PTR(-ENOMEM); diff -u -p a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c --- a/drivers/cpufreq/e_powersaver.c +++ b/drivers/cpufreq/e_powersaver.c @@ -324,9 +324,8 @@ static int eps_cpu_init(struct cpufreq_p states = 2; /* Allocate private data and frequency table for current cpu */ - centaur = kzalloc(sizeof(*centaur) - + (states + 1) * sizeof(struct cpufreq_frequency_table), - GFP_KERNEL); + centaur = kvzalloc_struct(centaur, freq_table, (states + 1), + GFP_KERNEL); if (!centaur) return -ENOMEM; eps_cpu[0] = centaur; diff -u -p a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c --- a/drivers/media/v4l2-core/v4l2-event.c +++ b/drivers/media/v4l2-core/v4l2-event.c @@ -215,8 +215,7 @@ int v4l2_event_subscribe(struct v4l2_fh if (elems < 1) elems = 1; - sev = kvzalloc(sizeof(*sev) + sizeof(struct v4l2_kevent) * elems, - GFP_KERNEL); + sev = kvzalloc_struct(sev, events, elems, GFP_KERNEL); if (!sev) return -ENOMEM; for (i = 0; i < elems; i++) diff -u -p a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -2380,9 +2380,7 @@ static void ib_sa_add_one(struct ib_devi s = rdma_start_port(device); e = rdma_end_port(device); - sa_dev = kzalloc(sizeof *sa_dev + - (e - s + 1) * sizeof (struct ib_sa_port), - GFP_KERNEL); + sa_dev = kvzalloc_struct(sa_dev, port, (e - s + 1), GFP_KERNEL); if (!sa_dev) return; diff -u -p a/drivers/infiniband/core/uverbs_ioctl_merge.c b/drivers/infiniband/core/uverbs_ioctl_merge.c --- a/drivers/infiniband/core/uverbs_ioctl_merge.c +++ b/drivers/infiniband/core/uverbs_ioctl_merge.c @@ -297,9 +297,8 @@ static struct uverbs_method_spec *build_ if (max_attr_buckets >= 0) num_attr_buckets = max_attr_buckets + 1; - method = kzalloc(sizeof(*method) + - num_attr_buckets * sizeof(*method->attr_buckets), - GFP_KERNEL); + method = kvzalloc_struct(method, attr_buckets, num_attr_buckets, + GFP_KERNEL); if (!method) return ERR_PTR(-ENOMEM); @@ -446,9 +445,8 @@ static struct uverbs_object_spec *build_ if (max_method_buckets >= 0) num_method_buckets = max_method_buckets + 1; - object = kzalloc(sizeof(*object) + - num_method_buckets * - sizeof(*object->method_buckets), GFP_KERNEL); + object = kvzalloc_struct(object, method_buckets, num_method_buckets, + GFP_KERNEL); if (!object) return ERR_PTR(-ENOMEM); @@ -469,9 +467,8 @@ static struct uverbs_object_spec *build_ if (methods_max_bucket < 0) continue; - hash = kzalloc(sizeof(*hash) + - sizeof(*hash->methods) * (methods_max_bucket + 1), - GFP_KERNEL); + hash = kvzalloc_struct(hash, methods, + (methods_max_bucket + 1), GFP_KERNEL); if (!hash) { res = -ENOMEM; goto free; @@ -579,9 +576,8 @@ struct uverbs_root_spec *uverbs_alloc_sp if (max_object_buckets >= 0) num_objects_buckets = max_object_buckets + 1; - root_spec = kzalloc(sizeof(*root_spec) + - num_objects_buckets * sizeof(*root_spec->object_buckets), - GFP_KERNEL); + root_spec = kvzalloc_struct(root_spec, object_buckets, + num_objects_buckets, GFP_KERNEL); if (!root_spec) return ERR_PTR(-ENOMEM); root_spec->num_buckets = num_objects_buckets; @@ -603,9 +599,8 @@ struct uverbs_root_spec *uverbs_alloc_sp if (objects_max_bucket < 0) continue; - hash = kzalloc(sizeof(*hash) + - sizeof(*hash->objects) * (objects_max_bucket + 1), - GFP_KERNEL); + hash = kvzalloc_struct(hash, objects, + (objects_max_bucket + 1), GFP_KERNEL); if (!hash) { res = -ENOMEM; goto free; diff -u -p a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c --- a/drivers/infiniband/core/multicast.c +++ b/drivers/infiniband/core/multicast.c @@ -815,8 +815,7 @@ static void mcast_add_one(struct ib_devi int i; int count = 0; - dev = kmalloc(sizeof *dev + device->phys_port_cnt * sizeof *port, - GFP_KERNEL); + dev = kvzalloc_struct(dev, port, device->phys_port_cnt, GFP_KERNEL); if (!dev) return; diff -u -p a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -505,8 +505,7 @@ static inline struct rdma_hw_stats *rdma { struct rdma_hw_stats *stats; - stats = kzalloc(sizeof(*stats) + num_counters * sizeof(u64), - GFP_KERNEL); + stats = kvzalloc_struct(stats, value, num_counters, GFP_KERNEL); if (!stats) return NULL; stats->names = names; diff -u -p a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -3951,8 +3951,7 @@ static void cm_recv_handler(struct ib_ma atomic_long_inc(&port->counter_group[CM_RECV]. counter[attr_id - CM_ATTR_ID_OFFSET]); - work = kmalloc(sizeof(*work) + sizeof(struct sa_path_rec) * paths, - GFP_KERNEL); + work = kvzalloc_struct(work, path, paths, GFP_KERNEL); if (!work) { ib_free_recv_mad(mad_recv_wc); return; diff -u -p a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -1272,9 +1272,7 @@ static void ib_umad_add_one(struct ib_de s = rdma_start_port(device); e = rdma_end_port(device); - umad_dev = kzalloc(sizeof *umad_dev + - (e - s + 1) * sizeof (struct ib_umad_port), - GFP_KERNEL); + umad_dev = kvzalloc_struct(umad_dev, port, (e - s + 1), GFP_KERNEL); if (!umad_dev) return; diff -u -p a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -1065,16 +1065,16 @@ static void ib_cache_update(struct ib_de goto err; } - pkey_cache = kmalloc(sizeof *pkey_cache + tprops->pkey_tbl_len * - sizeof *pkey_cache->table, GFP_KERNEL); + pkey_cache = kvzalloc_struct(pkey_cache, table, tprops->pkey_tbl_len, + GFP_KERNEL); if (!pkey_cache) goto err; pkey_cache->table_len = tprops->pkey_tbl_len; if (!use_roce_gid_table) { - gid_cache = kmalloc(sizeof(*gid_cache) + tprops->gid_tbl_len * - sizeof(*gid_cache->table), GFP_KERNEL); + gid_cache = kvzalloc_struct(gid_cache, table, + tprops->gid_tbl_len, GFP_KERNEL); if (!gid_cache) goto err; diff -u -p a/drivers/infiniband/hw/usnic/usnic_uiom.c b/drivers/infiniband/hw/usnic/usnic_uiom.c --- a/drivers/infiniband/hw/usnic/usnic_uiom.c +++ b/drivers/infiniband/hw/usnic/usnic_uiom.c @@ -155,10 +155,9 @@ static int usnic_uiom_get_pages(unsigned off = 0; while (ret) { - chunk = kmalloc(sizeof(*chunk) + - sizeof(struct scatterlist) * - min_t(int, ret, USNIC_UIOM_PAGE_CHUNK), - GFP_KERNEL); + chunk = kvzalloc_struct(chunk, page_list, + min_t(int, ret, USNIC_UIOM_PAGE_CHUNK), + GFP_KERNEL); if (!chunk) { ret = -ENOMEM; goto out; diff -u -p a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -367,7 +367,7 @@ struct mthca_icm_table *mthca_alloc_icm_ obj_per_chunk = MTHCA_TABLE_CHUNK_SIZE / obj_size; num_icm = DIV_ROUND_UP(nobj, obj_per_chunk); - table = kmalloc(sizeof *table + num_icm * sizeof *table->icm, GFP_KERNEL); + table = kvzalloc_struct(table, icm, num_icm, GFP_KERNEL); if (!table) return NULL; @@ -529,7 +529,7 @@ struct mthca_user_db_table *mthca_init_u return NULL; npages = dev->uar_table.uarc_size / MTHCA_ICM_PAGE_SIZE; - db_tab = kmalloc(sizeof *db_tab + npages * sizeof *db_tab->page, GFP_KERNEL); + db_tab = kvzalloc_struct(db_tab, page, npages, GFP_KERNEL); if (!db_tab) return ERR_PTR(-ENOMEM); diff -u -p a/fs/aio.c b/fs/aio.c --- a/fs/aio.c +++ b/fs/aio.c @@ -669,8 +669,7 @@ static int ioctx_add_table(struct kioctx new_nr = (table ? table->nr : 1) * 4; spin_unlock(&mm->ioctx_lock); - table = kzalloc(sizeof(*table) + sizeof(struct kioctx *) * - new_nr, GFP_KERNEL); + table = kvzalloc_struct(table, table, new_nr, GFP_KERNEL); if (!table) return -ENOMEM; diff -u -p a/mm/memcontrol.c b/mm/memcontrol.c --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -3558,8 +3558,7 @@ static int __mem_cgroup_usage_register_e size = thresholds->primary ? thresholds->primary->size + 1 : 1; /* Allocate memory for new array of thresholds */ - new = kmalloc(sizeof(*new) + size * sizeof(struct mem_cgroup_threshold), - GFP_KERNEL); + new = kvzalloc_struct(new, entries, size, GFP_KERNEL); if (!new) { ret = -ENOMEM; goto unlock; diff -u -p a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -505,8 +505,7 @@ static inline struct rdma_hw_stats *rdma { struct rdma_hw_stats *stats; - stats = kzalloc(sizeof(*stats) + num_counters * sizeof(u64), - GFP_KERNEL); + stats = kvzalloc_struct(stats, value, num_counters, GFP_KERNEL); if (!stats) return NULL; stats->names = names; diff -u -p a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -850,9 +850,7 @@ static struct rpcrdma_sendctx *rpcrdma_s { struct rpcrdma_sendctx *sc; - sc = kzalloc(sizeof(*sc) + - ia->ri_max_send_sges * sizeof(struct ib_sge), - GFP_KERNEL); + sc = kvzalloc_struct(sc, sc_sges, ia->ri_max_send_sges, GFP_KERNEL); if (!sc) return NULL; diff -u -p a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c --- a/net/sunrpc/xprtrdma/svc_rdma_rw.c +++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c @@ -61,9 +61,8 @@ svc_rdma_get_rw_ctxt(struct svcxprt_rdma spin_unlock(&rdma->sc_rw_ctxt_lock); } else { spin_unlock(&rdma->sc_rw_ctxt_lock); - ctxt = kmalloc(sizeof(*ctxt) + - SG_CHUNK_SIZE * sizeof(struct scatterlist), - GFP_KERNEL); + ctxt = kvzalloc_struct(ctxt, rw_first_sgl, SG_CHUNK_SIZE, + GFP_KERNEL); if (!ctxt) goto out; INIT_LIST_HEAD(&ctxt->rw_list); diff -u -p a/net/openvswitch/meter.c b/net/openvswitch/meter.c --- a/net/openvswitch/meter.c +++ b/net/openvswitch/meter.c @@ -206,8 +206,7 @@ static struct dp_meter *dp_meter_create( return ERR_PTR(-EINVAL); /* Allocate and set up the meter before locking anything. */ - meter = kzalloc(n_bands * sizeof(struct dp_meter_band) + - sizeof(*meter), GFP_KERNEL); + meter = kvzalloc_struct(meter, bands, n_bands, GFP_KERNEL); if (!meter) return ERR_PTR(-ENOMEM); diff -u -p a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -657,7 +657,7 @@ static int usX2Y_rate_set(struct usX2Yde struct s_c2 *ra = rate == 48000 ? SetRate48000 : SetRate44100; if (usX2Y->rate != rate) { - us = kzalloc(sizeof(*us) + sizeof(struct urb*) * NOOF_SETRATE_URBS, GFP_KERNEL); + us = kvzalloc_struct(us, urb, NOOF_SETRATE_URBS, GFP_KERNEL); if (NULL == us) { err = -ENOMEM; goto cleanup; diff -u -p a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -128,7 +128,7 @@ static int add_conn_list(struct hda_code { struct hda_conn_list *p; - p = kmalloc(sizeof(*p) + len * sizeof(hda_nid_t), GFP_KERNEL); + p = kvzalloc_struct(p, conns, len, GFP_KERNEL); if (!p) return -ENOMEM; p->len = len;