LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
From: Kees Cook <keescook@chromium.org>
To: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
Dan Carpenter <dan.carpenter@oracle.com>,
Silvio Cesare <silvio.cesare@gmail.com>,
Matthew Wilcox <mawilcox@microsoft.com>
Subject: Re: [GIT PULL] overflow updates (part 2) for v4.18-rc1
Date: Wed, 13 Jun 2018 12:07:29 -0700 [thread overview]
Message-ID: <CAGXu5jLw9kMZRkzL_Q7JdyyprntHF6bdVSE_vjyzect3CenDng@mail.gmail.com> (raw)
In-Reply-To: <CA+55aFy9mqnJCr=6JujNvmTjGu-rm0QYrUNkmKODb0ymQU9O8Q@mail.gmail.com>
On Tue, Jun 12, 2018 at 6:44 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
> On Tue, Jun 12, 2018 at 4:36 PM Kees Cook <keescook@chromium.org> wrote:
>>
>> - Treewide conversions of allocators to use either 2-factor argument
>> variant when available, or array_size() and array3_size() as needed (Kees)
>
> Ok, some of this smells just a tad too much of automation, but I've
> done the pull and it's going through my build tests.
Thanks! Yeah, I tried to beat sense into it to avoid REALLY dumb
things that just looked terrible.
> In some of the cases it turns a compile-time constant into a function
> call, ie this just makes for bigger and slower code for no reason
> what-so-ever.
>
> - ch->tx_array = vzalloc(MIC_DMA_DESC_RX_SIZE * sizeof(*ch->tx_array));
> + ch->tx_array = vzalloc(array_size(MIC_DMA_DESC_RX_SIZE,
> + sizeof(*ch->tx_array)));
>
> At least in the kzalloc/kcalloc conversion it results in more legible code.
I did try to convince my scripting to avoid the less sane conversions,
but as you saw there were still some that fell through. In the end, I
decided to let it stand since because Rasmus's code is so careful, if
array_size() processes constant expressions, it'll produce a constant
expression, so the machine code result actually isn't worse in these
cases. Using the above example, it's the same as without array_size():
struct dma_async_tx_descriptor is 72 bytes
/* size: 72, cachelines: 2, members: 10 */
MIC_DMA_DESC_RX_SIZE is 131068
#define MIC_DMA_DESC_RX_SIZE (128 * 1024 - 4)
131068 * 72 = 0x8ffee0
vzalloc(array_size(MIC_DMA_DESC_RX_SIZE, sizeof(*ch->tx_array)))
ffffffff815e87d0: bf e0 fe 8f 00 mov $0x8ffee0,%edi
ffffffff815e87d5: e8 c6 4b be ff callq <vzalloc>
The same is true for each of these all-constants forms, with each
resolving to the same machine code in my tests:
kmalloc(16 * PAGE_SIZE, GFP_KERNEL)
kmalloc_array(16, PAGE_SIZE, GFP_KERNEL)
kmalloc(array_size(16, PAGE_SIZE), GFP_KERNEL)
16 * 4096 = 0x10000
ffffffff8179810e: ba 04 00 00 00 mov $0x4,%edx
ffffffff81798113: be c0 00 60 00 mov $0x6000c0,%esi
ffffffff81798118: bf 00 00 01 00 mov $0x10000,%edi
ffffffff8179811d: e8 6e b0 a1 ff callq <kmalloc_order_trace>
Obviously, it gets more interesting once there is an actual variable in play:
kmalloc(var * PAGE_SIZE, GFP_KERNEL) does no overflow checking, as
expected, and is what I wanted to eliminate from the kernel:
ffffffff8179810e: 48 63 3d 93 f4 14 01 movslq 0x114f493(%rip),%rdi
ffffffff81798115: be c0 00 60 00 mov $0x6000c0,%esi
ffffffff8179811a: 48 c1 e7 0c shl $0xc,%rdi
ffffffff8179811e: e8 1d af a4 ff callq <__kmalloc>
kmalloc_array(var, PAGE_SIZE, GFP_KERNEL) has its builtin overflow
checking and returns NULL:
ffffffff8179810e: 48 63 05 93 f4 14 01 movslq 0x114f493(%rip),%rax
ffffffff81798115: bf 00 10 00 00 mov $0x1000,%edi
ffffffff8179811a: 48 f7 e7 mul %rdi
ffffffff8179811d: 48 89 c7 mov %rax,%rdi
ffffffff81798120: 70 18 jo ffffffff8179813a
ffffffff81798122: be c0 00 60 00 mov $0x6000c0,%esi
ffffffff81798127: e8 14 af a4 ff callq <__kmalloc>
ffffffff8179812c: 48 89 05 ad ea fd 01 mov %rax,0x1fdeaad(%rip)
ffffffff81798133: 48 83 c4 08 add $0x8,%rsp
ffffffff81798137: 5b pop %rbx
ffffffff81798138: 5d pop %rbp
ffffffff81798139: c3 retq
ffffffff8179813a: 31 c0 xor %eax,%eax
ffffffff8179813c: eb ee jmp ffffffff8179812c
kmalloc(array_size(var, PAGE_SIZE), GFP_KERNEL), (not that this form
should be used, but just to illustrate) performs the saturation
instead of the NULL return:
ffffffff8179810e: 48 63 05 93 f4 14 01 movslq 0x114f493(%rip),%rax
ffffffff81798115: bf 00 10 00 00 mov $0x1000,%edi
ffffffff8179811a: 48 f7 e7 mul %rdi
ffffffff8179811d: 48 89 c7 mov %rax,%rdi
ffffffff81798120: 70 18 jo ffffffff8179813a
ffffffff81798122: be c0 00 60 00 mov $0x6000c0,%esi
ffffffff81798127: e8 14 af a4 ff callq <__kmalloc>
ffffffff8179812c: 48 89 05 ad ea fd 01 mov %rax,0x1fdeaad(%rip)
ffffffff81798133: 48 83 c4 08 add $0x8,%rsp
ffffffff81798137: 5b pop %rbx
ffffffff81798138: 5d pop %rbp
ffffffff81798139: c3 retq
ffffffff8179813a: ba 34 00 00 00 mov $0x34,%edx
ffffffff8179813f: be c0 00 60 00 mov $0x6000c0,%esi
ffffffff81798144: 48 83 cf ff or $0xffffffffffffffff,%rdi
ffffffff81798148: e8 43 b0 a1 ff callq <kmalloc_order_trace>
ffffffff8179814d: eb dd jmp ffffffff8179812c
> To make up for it, there's some conversions *away* from nonsensical expressions:
>
> - hc_name = kzalloc(sizeof(char) * (HSMMC_NAME_LEN + 1), GFP_KERNEL);
> + hc_name = kzalloc(HSMMC_NAME_LEN + 1, GFP_KERNEL);
Yeah, I tried to catch these and some other masked cases. Coccinelle
didn't seem to have a consistent isomorphism for (sizeof(thing)) vs
sizeof(thing), so I also tried to drop redundant parens.
> but I _really_ think you were way too eager to move to array_size()
> even when it made no sense what-so-ever.
>
> But at least with the kcalloc()/kmalloc_array() conversions now
> preferred, those crazy cases are now a minority rather than "most of
> the patch makes code worse".
Net improvement was my goal, yes! :)
> I am *not* looking forward to the conflicts this causes, but maybe it
> won't be too bad. Fingers crossed.
Hopefully it shouldn't be too bad, but that's why I tried to perform
the conversion as late in -rc1 as possible, etc.
Thanks again for the pull! I'll keep my eyes out for new cases that
need conversion. Hopefully we can enhance checkpatch to yell more
loudly too. :)
-Kees
--
Kees Cook
Pixel Security
prev parent reply other threads:[~2018-06-13 19:07 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-06-12 23:35 Kees Cook
2018-06-13 1:44 ` Linus Torvalds
2018-06-13 19:07 ` Kees Cook [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAGXu5jLw9kMZRkzL_Q7JdyyprntHF6bdVSE_vjyzect3CenDng@mail.gmail.com \
--to=keescook@chromium.org \
--cc=dan.carpenter@oracle.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mawilcox@microsoft.com \
--cc=silvio.cesare@gmail.com \
--cc=torvalds@linux-foundation.org \
--subject='Re: [GIT PULL] overflow updates (part 2) for v4.18-rc1' \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).