Re: [PATCH v2][next] dlm: Replace one-element array with flexible-array member

From: Kees Cook
Date: Sat Oct 08 2022 - 20:26:32 EST




On October 8, 2022 4:17:37 PM PDT, Paulo Miguel Almeida <paulo.miguel.almeida.rodenas@xxxxxxxxx> wrote:
>One-element arrays are deprecated, and we are replacing them with
>flexible array members instead. So, replace one-element array with
>flexible-array member in struct dlm_ls, and refactor the rest of the
>code, accordingly.

Thanks for working on this!

>
>We strive to make changes that don't produce any before/after binary
>output differeces as that makes it easier for the reviewer to accept the
>patch. In this particular instance, it wasn't possible to achieve this
>due to the fact that the ls_name[1] size, which is used as the
>NUL-terminator space, was hidden within the struct's padding as shown
>below.
>
>$ diff <(objdump -M intel -j .text -D dlm.old) <(objdump -M intel -j
>.text -D dlm.new)

I'd suggest different options here, this is harder to map back to the source line.
See https://outflux.net/blog/archives/2022/06/24/finding-binary-differences/
for lots of details. :)

>
>13778c13778
>< c693: 49 8d bc 24 c0 08 00 lea rdi,[r12+0x8c0]
>---
>> c693: 49 8d bc 24 c1 08 00 lea rdi,[r12+0x8c1]

This implies something unexpected changed.

>
>$ pahole dlm.old -C dlm_ls
>...
> int ls_namelen; /* 2232 4 */
> char ls_name[1]; /* 2236 1 */
>
> /* size: 2240, cachelines: 35, members: 90 */
> /* sum members: 2166, holes: 17, sum holes: 71 */
> /* padding: 3 */
> /* paddings: 3, sum paddings: 17 */
> /* forced alignments: 1 */
>} __attribute__((__aligned__(8)));
>
>$ pahole dlm.new -C dlm_ls
>...
> int ls_namelen; /* 2232 4 */
> char ls_name[]; /* 2236 0 */
>
> /* size: 2240, cachelines: 35, members: 90 */
> /* sum members: 2165, holes: 17, sum holes: 71 */
> /* padding: 4 */
> /* paddings: 3, sum paddings: 17 */
> /* forced alignments: 1 */
>} __attribute__((__aligned__(8)));

This has trailing padding, so the struct size didn't actually change.

>This helps with the ongoing efforts to tighten the FORTIFY_SOURCE
>routines on memcpy() and help us make progress towards globally
>enabling -fstrict-flex-arrays=3 [1].
>
>Link: https://github.com/KSPP/linux/issues/79
>Link: https://github.com/KSPP/linux/issues/228
>Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101836 [1]
>
>Signed-off-by: Paulo Miguel Almeida <paulo.miguel.almeida.rodenas@xxxxxxxxx>
>---
>My apologies for v2, there was an accidental <Cr> I added on
>the CC line which messed up the body of my previus email.
>
>This patch sets it right.
>
>---
> fs/dlm/dlm_internal.h | 2 +-
> fs/dlm/lockspace.c | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
>diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
>index e34c3d2639a5..ce2e32ed2ede 100644
>--- a/fs/dlm/dlm_internal.h
>+++ b/fs/dlm/dlm_internal.h
>@@ -670,7 +670,7 @@ struct dlm_ls {
> void *ls_ops_arg;
>
> int ls_namelen;
>- char ls_name[1];
>+ char ls_name[];
> };
>
> /*
>diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
>index bae050df7abf..c3a36f3197da 100644
>--- a/fs/dlm/lockspace.c
>+++ b/fs/dlm/lockspace.c
>@@ -473,7 +473,7 @@ static int new_lockspace(const char *name, const char *cluster,
>
> error = -ENOMEM;
>
>- ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_NOFS);
>+ ls = kzalloc(sizeof(struct dlm_ls) + namelen + 1, GFP_NOFS);

This is allocating 1 more byte than before, since the struct size didn't change. But this has always allocated too much space, due to the struct padding. For a "no binary changes" patch, the above "+ 1" needs to be left off.

I would expect the correct allocation size to be:
offsetof(typeof(*ls), ls_name) + namelen

Question, though: is ls_name _expected_ to be %NUL terminated, and was the prior 3 bytes of extra allocation accidentally required?

-Kees

--
Kees Cook