All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nick Desaulniers <ndesaulniers@google.com>
To: Kees Cook <keescook@chromium.org>
Cc: linux-kernel@vger.kernel.org,
	Rasmus Villemoes <linux@rasmusvillemoes.dk>,
	Daniel Micay <danielmicay@gmail.com>,
	Francis Laniel <laniel_francis@privacyrequired.com>,
	Bart Van Assche <bvanassche@acm.org>,
	David Gow <davidgow@google.com>,
	linux-mm@kvack.org, clang-built-linux@googlegroups.com,
	linux-hardening@vger.kernel.org
Subject: Re: [PATCH for-next 19/25] fortify: Allow strlen() and strnlen() to pass compile-time known lengths
Date: Wed, 25 Aug 2021 15:05:56 -0700	[thread overview]
Message-ID: <CAKwvOdnrO+oagJEiBMmoHrhTJKSRwzb0DK=R_QdVjhiNzb34dg@mail.gmail.com> (raw)
In-Reply-To: <20210822075122.864511-20-keescook@chromium.org>

On Sun, Aug 22, 2021 at 12:57 AM Kees Cook <keescook@chromium.org> wrote:
>
> Under CONFIG_FORTIFY_SOURCE, it is possible for the compiler to perform
> strlen() and strnlen() at compile-time when the string size is known.
> This is required to support compile-time overflow checking in strlcpy().
>
> Signed-off-by: Kees Cook <keescook@chromium.org>
> ---
>  include/linux/fortify-string.h | 47 ++++++++++++++++++++++++++--------
>  1 file changed, 36 insertions(+), 11 deletions(-)
>
> diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h
> index a3cb1d9aacce..e232a63fd826 100644
> --- a/include/linux/fortify-string.h
> +++ b/include/linux/fortify-string.h
> @@ -10,6 +10,18 @@ void __read_overflow(void) __compiletime_error("detected read beyond size of obj
>  void __read_overflow2(void) __compiletime_error("detected read beyond size of object (2nd parameter)");
>  void __write_overflow(void) __compiletime_error("detected write beyond size of object (1st parameter)");
>
> +#define __compiletime_strlen(p)        ({              \
> +       size_t ret = (size_t)-1;                        \
> +       size_t p_size = __builtin_object_size(p, 1);    \
> +       if (p_size != (size_t)-1) {                     \
> +               size_t p_len = p_size - 1;              \
> +               if (__builtin_constant_p(p[p_len]) &&   \
> +                   p[p_len] == '\0')                   \
> +                       ret = __builtin_strlen(p);      \
> +       }                                               \
> +       ret;                                            \
> +})

Can this be a `static inline` function that accepts a `const char *`
and returns a `size_t` rather than a statement expression?

> +
>  #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
>  extern void *__underlying_memchr(const void *p, int c, __kernel_size_t size) __RENAME(memchr);
>  extern int __underlying_memcmp(const void *p, const void *q, __kernel_size_t size) __RENAME(memcmp);
> @@ -60,21 +72,31 @@ extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(st
>  __FORTIFY_INLINE __kernel_size_t strnlen(const char *p, __kernel_size_t maxlen)
>  {
>         size_t p_size = __builtin_object_size(p, 1);
> -       __kernel_size_t ret = __real_strnlen(p, maxlen < p_size ? maxlen : p_size);
> +       size_t p_len = __compiletime_strlen(p);
> +       size_t ret;
> +
> +       /* We can take compile-time actions when maxlen is const. */
> +       if (__builtin_constant_p(maxlen) && p_len != (size_t)-1) {
> +               /* If p is const, we can use its compile-time-known len. */
> +               if (maxlen >= p_size)
> +                       return p_len;
> +       }
>
> +       /* Do no check characters beyond the end of p. */

s/no/not/

> +       ret = __real_strnlen(p, maxlen < p_size ? maxlen : p_size);
>         if (p_size <= ret && maxlen != ret)
>                 fortify_panic(__func__);
>         return ret;
>  }
>
> +/* defined after fortified strnlen to reuse it. */
>  __FORTIFY_INLINE __kernel_size_t strlen(const char *p)
>  {
>         __kernel_size_t ret;
>         size_t p_size = __builtin_object_size(p, 1);
>
> -       /* Work around gcc excess stack consumption issue */
> -       if (p_size == (size_t)-1 ||
> -               (__builtin_constant_p(p[p_size - 1]) && p[p_size - 1] == '\0'))
> +       /* Give up if we don't know how large p is. */
> +       if (p_size == (size_t)-1)
>                 return __underlying_strlen(p);
>         ret = strnlen(p, p_size);
>         if (p_size <= ret)
> @@ -86,24 +108,27 @@ __FORTIFY_INLINE __kernel_size_t strlen(const char *p)
>  extern size_t __real_strlcpy(char *, const char *, size_t) __RENAME(strlcpy);
>  __FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size)
>  {
> -       size_t ret;
>         size_t p_size = __builtin_object_size(p, 1);
>         size_t q_size = __builtin_object_size(q, 1);
> +       size_t q_len;   /* Full count of source string length. */
> +       size_t len;     /* Count of characters going into destination. */
>
>         if (p_size == (size_t)-1 && q_size == (size_t)-1)
>                 return __real_strlcpy(p, q, size);
> -       ret = strlen(q);
> -       if (size) {
> -               size_t len = (ret >= size) ? size - 1 : ret;
> -
> -               if (__builtin_constant_p(len) && len >= p_size)
> +       q_len = strlen(q);
> +       len = (q_len >= size) ? size - 1 : q_len;
> +       if (__builtin_constant_p(size) && __builtin_constant_p(q_len) && size) {
> +               /* Write size is always larger than destintation. */

s/destintation/destination/

> +               if (len >= p_size)
>                         __write_overflow();
> +       }
> +       if (size) {
>                 if (len >= p_size)
>                         fortify_panic(__func__);
>                 __underlying_memcpy(p, q, len);
>                 p[len] = '\0';
>         }
> -       return ret;
> +       return q_len;
>  }
>
>  /* defined after fortified strnlen to reuse it */
> --
> 2.30.2
>
> --
> You received this message because you are subscribed to the Google Groups "Clang Built Linux" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to clang-built-linux+unsubscribe@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/clang-built-linux/20210822075122.864511-20-keescook%40chromium.org.



-- 
Thanks,
~Nick Desaulniers

  reply	other threads:[~2021-08-25 22:06 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-22  7:50 [PATCH for-next 00/25] Prepare for better FORTIFY_SOURCE Kees Cook
2021-08-22  7:50 ` [PATCH for-next 01/25] scsi: ibmvscsi: Avoid multi-field memset() overflow by aiming at srp Kees Cook
2021-08-22  7:50   ` Kees Cook
2021-08-22  7:50 ` [PATCH for-next 02/25] powerpc: Split memset() to avoid multi-field overflow Kees Cook
2021-08-22  7:50   ` Kees Cook
2021-08-22  7:51 ` [PATCH for-next 03/25] stddef: Fix kerndoc for sizeof_field() and offsetofend() Kees Cook
2021-08-22  7:51 ` [PATCH for-next 04/25] stddef: Introduce struct_group() helper macro Kees Cook
2021-08-22  7:51 ` [PATCH for-next 05/25] cxl/core: Replace unions with struct_group() Kees Cook
2021-08-22  7:51 ` [PATCH for-next 06/25] bnxt_en: Use struct_group_attr() for memcpy() region Kees Cook
2021-08-22  7:51 ` [PATCH for-next 07/25] iommu/amd: Use struct_group() " Kees Cook
2021-08-22  7:51 ` [PATCH for-next 08/25] drm/mga/mga_ioc32: " Kees Cook
2021-08-22  7:51 ` [PATCH for-next 09/25] HID: cp2112: " Kees Cook
2021-08-22  7:51 ` [PATCH for-next 10/25] HID: roccat: Use struct_group() to zero kone_mouse_event Kees Cook
2021-08-22  7:51 ` [PATCH for-next 11/25] can: flexcan: Use struct_group() to zero struct flexcan_regs regions Kees Cook
2021-08-22  7:51 ` [PATCH for-next 12/25] cm4000_cs: Use struct_group() to zero struct cm4000_dev region Kees Cook
2021-08-22  7:51 ` [PATCH for-next 13/25] compiler_types.h: Remove __compiletime_object_size() Kees Cook
2021-08-23  6:43   ` Rasmus Villemoes
2021-08-25 19:43     ` Nick Desaulniers
2021-08-25 19:43       ` Nick Desaulniers
2021-08-22  7:51 ` [PATCH for-next 14/25] lib/string: Move helper functions out of string.c Kees Cook
2021-08-25 21:48   ` Nick Desaulniers
2021-08-25 21:48     ` Nick Desaulniers
2021-08-26  2:47     ` Kees Cook
2021-08-26 18:08       ` Nick Desaulniers
2021-08-26 18:08         ` Nick Desaulniers
2021-08-22  7:51 ` [PATCH for-next 15/25] fortify: Move remaining fortify helpers into fortify-string.h Kees Cook
2021-08-25 21:59   ` Nick Desaulniers
2021-08-25 21:59     ` Nick Desaulniers
2021-08-22  7:51 ` [PATCH for-next 16/25] fortify: Explicitly disable Clang support Kees Cook
2021-08-25 19:41   ` Nick Desaulniers
2021-08-25 19:41     ` Nick Desaulniers
2021-08-22  7:51 ` [PATCH for-next 17/25] fortify: Fix dropped strcpy() compile-time write overflow check Kees Cook
2021-08-25 21:55   ` Nick Desaulniers
2021-08-25 21:55     ` Nick Desaulniers
2021-08-22  7:51 ` [PATCH for-next 18/25] fortify: Prepare to improve strnlen() and strlen() warnings Kees Cook
2021-08-25 22:01   ` Nick Desaulniers
2021-08-25 22:01     ` Nick Desaulniers
2021-08-22  7:51 ` [PATCH for-next 19/25] fortify: Allow strlen() and strnlen() to pass compile-time known lengths Kees Cook
2021-08-25 22:05   ` Nick Desaulniers [this message]
2021-08-25 22:05     ` Nick Desaulniers
2021-08-26  2:56     ` Kees Cook
2021-08-26 18:02       ` Nick Desaulniers
2021-08-26 18:02         ` Nick Desaulniers
2021-08-22  7:51 ` [PATCH for-next 20/25] fortify: Add compile-time FORTIFY_SOURCE tests Kees Cook
2021-08-22  7:51 ` [PATCH for-next 21/25] lib: Introduce CONFIG_TEST_MEMCPY Kees Cook
2021-08-24  7:00   ` David Gow
2021-08-24  7:00     ` David Gow
2021-08-25  2:32     ` Kees Cook
2021-10-18 15:46   ` Arnd Bergmann
2021-10-18 19:28     ` Kees Cook
2021-08-22  7:51 ` [PATCH for-next 22/25] string.h: Introduce memset_after() for wiping trailing members/padding Kees Cook
2021-08-22  7:51 ` [PATCH for-next 23/25] xfrm: Use memset_after() to clear padding Kees Cook
2021-08-22  7:51 ` [PATCH for-next 24/25] string.h: Introduce memset_startat() for wiping trailing members and padding Kees Cook
2021-08-22  7:51 ` [PATCH for-next 25/25] btrfs: Use memset_startat() to clear end of struct Kees Cook

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='CAKwvOdnrO+oagJEiBMmoHrhTJKSRwzb0DK=R_QdVjhiNzb34dg@mail.gmail.com' \
    --to=ndesaulniers@google.com \
    --cc=bvanassche@acm.org \
    --cc=clang-built-linux@googlegroups.com \
    --cc=danielmicay@gmail.com \
    --cc=davidgow@google.com \
    --cc=keescook@chromium.org \
    --cc=laniel_francis@privacyrequired.com \
    --cc=linux-hardening@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=linux@rasmusvillemoes.dk \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.