From: Kees Cook <keescook@chromium.org>
To: Alejandro Colomar <alx@kernel.org>
Cc: "Gustavo A. R. Silva" <gustavoars@kernel.org>,
LKML <linux-kernel@vger.kernel.org>,
linux-hardening@vger.kernel.org
Subject: Re: struct_size() using sizeof() vs offsetof()
Date: Wed, 16 Aug 2023 20:05:34 -0700 [thread overview]
Message-ID: <202308161913.91369D4A@keescook> (raw)
In-Reply-To: <74e8cf91-d095-33e3-c548-34d80b691089@kernel.org>
On Thu, Aug 17, 2023 at 02:23:21AM +0200, Alejandro Colomar wrote:
> Hi Kees, Gustavo,
Hi!
> I've been discussing with a friend about the appropriateness of sizeof()
> vs offsetof() for calculating the size of a structure with a flexible
> array member (FAM).
>
> After reading Jens Gustedt's blog post about it[1], we tried some tests,
> and we got some interesting results that discouraged me from using sizeof().
> See below.
When struct_size() was originally implemented this topic came up, and we
opted for potential over-estimation rather than using offsetof() which
could result in under-allocation, and using max() of two different
calculations just seemed like overkill. Additionally, almost all cases of
struct_size() was replacing a literal open-coded version of
sizeof(*ptr) + sizeof(*ptr->array) * count
So avoiding a difference in calculation was nice too.
> But then, said friend pointed to me that the kernel uses sizeof() in
> struct_size(), and we wondered why you would have chosen it. It's safe
> as long as you _know_ that there's no padding, or that the alignment of
> the FAM is as large as the padding (which you probably know in the kernel),
> but it seems safer to use
>
> MAX(sizeof(s), offsetof(s, fam) + sizeof_member(s, fam) * count)
Ironically, this has been under careful examination recently by GCC[1]
too. Though that has mainly been looking at it from the perspective
of how __builtin_object_size() should behave in the face of the new
__counted_by attribute.
> The thing is, if there's any trailing padding in the struct, the FAM may
> overlap the padding, and the calculation with sizeof() will waste a few
> bytes, and if misused to get the location of the FAM, the problem will be
> bigger, as you'll get a wrong location.
Luckily, the _location_ of the FAM is well-defined by the compiler, so
that won't be a problem. However, yes, we can risk wasting some bytes.
> So, I just wanted to pry what and especially why the kernel chose to prefer
> a simple sizeof().
We opted for simple over complex, with the understanding that
over-allocation will be a relatively rare issue that will only waste
limited space (as opposed to potential under-allocation and risking
writing beyond the end of the region).
Here's some example I worked through:
https://godbolt.org/z/9aGjqon9v
But, yes, at the end of the day, struct_size() could be defined as
max(sizeof, offsetof-based struct-size).
Note that struct_size() has been designed to have two additional
behaviors:
- be usable as a constant expression
- saturate at SIZE_MAX
So as long as the max() could do the same (which it should be able to),
it'd likely be fine. I'm open to patches as long as we can validate any
binary differences found in allmodconfig builds. :)
-Kees
[1] https://gcc.gnu.org/pipermail/gcc-patches/2023-August/626672.html
--
Kees Cook
next prev parent reply other threads:[~2023-08-17 3:06 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-17 0:23 struct_size() using sizeof() vs offsetof() Alejandro Colomar
2023-08-17 3:05 ` Kees Cook [this message]
2023-08-17 12:39 ` Alejandro Colomar
2023-08-17 16:05 ` Gustavo A. R. Silva
2023-08-17 18:37 ` Alejandro Colomar
2023-08-21 8:38 ` David Laight
2023-08-21 13:51 ` Alejandro Colomar
2023-08-21 8:16 ` David Laight
2023-08-21 13:45 ` Alejandro Colomar
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=202308161913.91369D4A@keescook \
--to=keescook@chromium.org \
--cc=alx@kernel.org \
--cc=gustavoars@kernel.org \
--cc=linux-hardening@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/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
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox