On 11/24/23 09:28, Gustavo A. R. Silva wrote:


On 11/24/23 04:24, Joey Gouly wrote:
Hi all,

I just hit a boot crash on v6.7-rc2 (arm64, FVP model):

[..]

Checking `struct neighbour`:

    struct neighbour {
        struct neighbour __rcu    *next;
        struct neigh_table    *tbl;
    .. fields ..
        u8            primary_key[0];
    } __randomize_layout;

Due to the `__randomize_layout`, `primary_key` field is being placed before `tbl` (actually it's the same address since it's a 0 length array). That means the memcpy() corrupts the tbl pointer.

I think I just got unlucky with my CONFIG_RANDSTRUCT seed (I can provide it if 
needed), it doesn't look as if it's a new issue.

It seems the issue is caused by this change that was recently added to -rc2:

commit 1ee60356c2dc ("gcc-plugins: randstruct: Only warn about true flexible 
arrays")

Previously, one-element and zero-length arrays were treated as true flexible 
arrays
(however, they are "fake" flex arrays), and __randomize_layout would leave them
untouched at the end of the struct; the same for proper C99 flex-array members. 
But
after the commit above, that's no longer the case: Only C99 flex-array members 
will
behave correctly (remaining untouched at end of the struct), and the other two 
types
of arrays will be randomized.

mmh... it seems that commit 1ee60356c2dc only prevents one-element arrays from 
being
treated as flex arrays, while the code should still keep zero-length arrays 
untouched:

        if (typesize == NULL_TREE && TYPE_DOMAIN(fieldtype) != NULL_TREE &&
            TYPE_MAX_VALUE(TYPE_DOMAIN(fieldtype)) == NULL_TREE)
                return true;

-       if (typesize != NULL_TREE &&
-           (TREE_CONSTANT(typesize) && (!tree_to_uhwi(typesize) ||
-            tree_to_uhwi(typesize) == tree_to_uhwi(elemsize))))
-               return true;
-

Sorry about the confusion.



I couldn't reproduce directly on v6.6 (the offsets for `tbl` and `primary_key` 
didn't overlap).
However I tried changing the zero-length-array to a flexible one:

    +    DECLARE_FLEX_ARRAY(u8, primary_key);
    +    u8        primary_key[0];

Then the field offsets ended up overlapping, and I also got the same crash on 
v6.6.

The right approach is to transform the zero-length array into a C99 flex-array 
member,
like this:

diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 07022bb0d44d..0d28172193fa 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -162,7 +162,7 @@ struct neighbour {
         struct rcu_head         rcu;
         struct net_device       *dev;
         netdevice_tracker       dev_tracker;
-       u8                      primary_key[0];
+       u8                      primary_key[];
  } __randomize_layout;

  struct neigh_ops {

In any case, I think we still should convert [0] to [ ].

--
Gustavo

Reply via email to