linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3] docs: deprecated.rst: Add zero-length and one-element arrays
@ 2020-06-08 21:37 Gustavo A. R. Silva
  2020-06-10  5:56 ` Kees Cook
  2020-06-19 19:39 ` Jonathan Corbet
  0 siblings, 2 replies; 3+ messages in thread
From: Gustavo A. R. Silva @ 2020-06-08 21:37 UTC (permalink / raw)
  To: Jonathan Corbet, Kees Cook; +Cc: linux-doc, linux-kernel, Gustavo A. R. Silva

Add zero-length and one-element arrays to the list.

While I continue replacing zero-length and one-element arrays with
flexible-array members, I need a reference to point people to, so
they don't introduce more instances of such arrays. And while here,
add a note to the "open-coded arithmetic in allocator arguments"
section, on the use of struct_size() and the arrays-to-deprecate
mentioned here.

Co-developed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
---
Changes in v3:
 - Add changes written by Kees.
 - Add Co-developed-by tag to include Kees in the changelog text.

Changes in v2:
 - Adjust some markup links for readability.

 Documentation/process/deprecated.rst | 118 +++++++++++++++++++++++++++
 1 file changed, 118 insertions(+)

diff --git a/Documentation/process/deprecated.rst b/Documentation/process/deprecated.rst
index 652e2aa02a66c..bd4c92244de31 100644
--- a/Documentation/process/deprecated.rst
+++ b/Documentation/process/deprecated.rst
@@ -85,6 +85,11 @@ Instead, use the helper::
 
 	header = kzalloc(struct_size(header, item, count), GFP_KERNEL);
 
+.. note:: If you are using struct_size() on a structure containing a zero-length
+        or a one-element array as a trailing array member, please refactor such
+        array usage and switch to a `flexible array member
+        <#zero-length-and-one-element-arrays>`_ instead.
+
 See array_size(), array3_size(), and struct_size(),
 for more details as well as the related check_add_overflow() and
 check_mul_overflow() family of functions.
@@ -200,3 +205,116 @@ All switch/case blocks must end in one of:
 * continue;
 * goto <label>;
 * return [expression];
+
+Zero-length and one-element arrays
+----------------------------------
+There is a regular need in the kernel to provide a way to declare having
+a dynamically sized set of trailing elements in a structure. Kernel code
+should always use `"flexible array members" <https://en.wikipedia.org/wiki/Flexible_array_member>`_
+for these cases. The older style of one-element or zero-length arrays should
+no longer be used.
+
+In older C code, dynamically sized trailing elements were done by specifying
+a one-element array at the end of a structure::
+
+        struct something {
+                size_t count;
+                struct foo items[1];
+        };
+
+This led to fragile size calculations via sizeof() (which would need to
+remove the size of the single trailing element to get a correct size of
+the "header"). A `GNU C extension <https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_
+was introduced to allow for zero-length arrays, to avoid these kinds of
+size problems::
+
+        struct something {
+                size_t count;
+                struct foo items[0];
+        };
+
+But this led to other problems, and didn't solve some problems shared by
+both styles, like not being able to detect when such an array is accidentally
+being used _not_ at the end of a structure (which could happen directly, or
+when such a struct was in unions, structs of structs, etc).
+
+C99 introduced "flexible array members", which lacks a numeric size for
+the array declaration entirely::
+
+        struct something {
+                size_t count;
+                struct foo items[];
+        };
+
+This is the way the kernel expects dynamically sized trailing elements
+to be declared. It allows the compiler to generate errors when the
+flexible array does not occur last in the structure, which helps to prevent
+some kind of `undefined behavior
+<https://git.kernel.org/linus/76497732932f15e7323dc805e8ea8dc11bb587cf>`_
+bugs from being inadvertently introduced to the codebase. It also allows
+the compiler to correctly analyze array sizes (via sizeof(),
+`CONFIG_FORTIFY_SOURCE`, and `CONFIG_UBSAN_BOUNDS`). For instance,
+there is no mechanism that warns us that the following application of the
+sizeof() operator to a zero-length array always results in zero::
+
+        struct something {
+                size_t count;
+                struct foo items[0];
+        };
+
+        struct something *instance;
+
+        instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL);
+        instance->count = count;
+
+        size = sizeof(instance->items) * instance->count;
+        memcpy(instance->items, source, size);
+
+At the last line of code above, ``size`` turns out to be ``zero``, when one might
+have thought it represents the total size in bytes of the dynamic memory recently
+allocated for the trailing array ``items``. Here are a couple examples of this
+issue: `link 1
+<https://git.kernel.org/linus/f2cd32a443da694ac4e28fbf4ac6f9d5cc63a539>`_,
+`link 2
+<https://git.kernel.org/linus/ab91c2a89f86be2898cee208d492816ec238b2cf>`_.
+Instead, `flexible array members have incomplete type, and so the sizeof()
+operator may not be applied <https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_,
+so any misuse of such operators will be immediately noticed at build time.
+
+With respect to one-element arrays, one has to be acutely aware that `such arrays
+occupy at least as much space as a single object of the type
+<https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html>`_,
+hence they contribute to the size of the enclosing structure. This is prone
+to error every time people want to calculate the total size of dynamic memory
+to allocate for a structure containing an array of this kind as a member::
+
+        struct something {
+                size_t count;
+                struct foo items[1];
+        };
+
+        struct something *instance;
+
+        instance = kmalloc(struct_size(instance, items, count - 1), GFP_KERNEL);
+        instance->count = count;
+
+        size = sizeof(instance->items) * instance->count;
+        memcpy(instance->items, source, size);
+
+In the example above, we had to remember to calculate ``count - 1`` when using
+the struct_size() helper, otherwise we would have --unintentionally-- allocated
+memory for one too many ``items`` objects. The cleanest and least error-prone way
+to implement this is through the use of a `flexible array member`::
+
+        struct something {
+                size_t count;
+                struct foo items[];
+        };
+
+        struct something *instance;
+
+        instance = kmalloc(struct_size(instance, items, count), GFP_KERNEL);
+        instance->count = count;
+
+        size = sizeof(instance->items[0]) * instance->count;
+        memcpy(instance->items, source, size);
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v3] docs: deprecated.rst: Add zero-length and one-element arrays
  2020-06-08 21:37 [PATCH v3] docs: deprecated.rst: Add zero-length and one-element arrays Gustavo A. R. Silva
@ 2020-06-10  5:56 ` Kees Cook
  2020-06-19 19:39 ` Jonathan Corbet
  1 sibling, 0 replies; 3+ messages in thread
From: Kees Cook @ 2020-06-10  5:56 UTC (permalink / raw)
  To: Gustavo A. R. Silva
  Cc: Jonathan Corbet, linux-doc, linux-kernel, Gustavo A. R. Silva

On Mon, Jun 08, 2020 at 04:37:11PM -0500, Gustavo A. R. Silva wrote:
> Add zero-length and one-element arrays to the list.
> 
> While I continue replacing zero-length and one-element arrays with
> flexible-array members, I need a reference to point people to, so
> they don't introduce more instances of such arrays. And while here,
> add a note to the "open-coded arithmetic in allocator arguments"
> section, on the use of struct_size() and the arrays-to-deprecate
> mentioned here.
> 
> Co-developed-by: Kees Cook <keescook@chromium.org>
> Signed-off-by: Kees Cook <keescook@chromium.org>
> Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>

We hammered this out offlist, hence my SoB, but just in case it's
useful:

Acked-by: Kees Cook <keescook@chromium.org>

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v3] docs: deprecated.rst: Add zero-length and one-element arrays
  2020-06-08 21:37 [PATCH v3] docs: deprecated.rst: Add zero-length and one-element arrays Gustavo A. R. Silva
  2020-06-10  5:56 ` Kees Cook
@ 2020-06-19 19:39 ` Jonathan Corbet
  1 sibling, 0 replies; 3+ messages in thread
From: Jonathan Corbet @ 2020-06-19 19:39 UTC (permalink / raw)
  To: Gustavo A. R. Silva
  Cc: Kees Cook, linux-doc, linux-kernel, Gustavo A. R. Silva

On Mon, 8 Jun 2020 16:37:11 -0500
"Gustavo A. R. Silva" <gustavoars@kernel.org> wrote:

> Add zero-length and one-element arrays to the list.
> 
> While I continue replacing zero-length and one-element arrays with
> flexible-array members, I need a reference to point people to, so
> they don't introduce more instances of such arrays. And while here,
> add a note to the "open-coded arithmetic in allocator arguments"
> section, on the use of struct_size() and the arrays-to-deprecate
> mentioned here.
> 
> Co-developed-by: Kees Cook <keescook@chromium.org>
> Signed-off-by: Kees Cook <keescook@chromium.org>
> Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
> ---
> Changes in v3:
>  - Add changes written by Kees.
>  - Add Co-developed-by tag to include Kees in the changelog text.
> 
> Changes in v2:
>  - Adjust some markup links for readability.
> 
>  Documentation/process/deprecated.rst | 118 +++++++++++++++++++++++++++
>  1 file changed, 118 insertions(+)

Applied, thanks.

jon

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-06-19 19:39 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-08 21:37 [PATCH v3] docs: deprecated.rst: Add zero-length and one-element arrays Gustavo A. R. Silva
2020-06-10  5:56 ` Kees Cook
2020-06-19 19:39 ` Jonathan Corbet

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).