On 27/07/2021 22.58, Kees Cook wrote:
At its core, FORTIFY_SOURCE uses the compiler's __builtin_object_size() internal[0] to determine the available size at a target address based on the compile-time known structure layout details. It operates in two modes: outer bounds (0) and inner bounds (1). In mode 0, the size of the enclosing structure is used. In mode 1, the size of the specific field is used. For example:
struct object { u16 scalar1; /* 2 bytes */ char array[6]; /* 6 bytes */ u64 scalar2; /* 8 bytes */ u32 scalar3; /* 4 bytes */ } instance;
__builtin_object_size(instance.array, 0) == 18, since the remaining size of the enclosing structure starting from "array" is 18 bytes (6 + 8 + 4).
I think the compiler would usually end up making that struct size 24, with 4 bytes of trailing padding (at least when alignof(u64) is 8). In that case, does __builtin_object_size(instance.array, 0) actually evaluate to 18, or to 22? A quick test on x86-64 suggests the latter, so the memcpy(, , 20) would not be a violation.
Perhaps it's better to base the example on something which doesn't have potential trailing padding - so either add another 4 byte member, or also make scalar2 u32.
Rasmus