public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v2 00/10] Improve fortify support with clang
@ 2024-01-08 20:21 Adhemerval Zanella
  2024-01-08 20:21 ` [PATCH v2 01/10] cdefs.h: Add clang fortify directives Adhemerval Zanella
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: Adhemerval Zanella @ 2024-01-08 20:21 UTC (permalink / raw)
  To: libc-alpha

When using clang, the fortify wrappers show less coverage on both
compile and runtime. For instance, a snippet from tst-fortify.c:

  $ cat t.c
  #include <stdio.h>
  #include <string.h>
  
  const char *str1 = "JIHGFEDCBA";
  
  int main (int argc, char *argv[])
  {
  #define O 0
    struct A { char buf1[9]; char buf2[1]; } a;
    strcpy (a.buf1 + (O + 4), str1 + 5);
  
    return 0;
  }
  $ gcc -O2 t.c  -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=2 -o t
  $ ./t
  *** buffer overflow detected ***: terminated
  Aborted (core dumped)
  $ clang  -O2 t.c  -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=2 -o t
  $ ./t
  $

Although clang does support __builtin___strcpy_chk (which correctly
lowers to __strcpy_chk), the __builtin_object_size passed as third
the argument is not fully correct and thus limits the possible runtime
checks.

This limitation was already being raised some years ago [1], but the
work has been staled.  However, a similar patch has been used for
ChromeOS for some time [2].  Bionic libc also uses a similar approach to
enable fortified wrappers.

Improve its support with clang, requires defining the fortified wrapper
differently. For instance, the read wrapper is currently expanded as:

  extern __inline
  __attribute__((__always_inline__))
  __attribute__((__artificial__))
  __attribute__((__warn_unused_result__))
  ssize_t read (int __fd, void *__buf, size_t __nbytes)
  {
     return __glibc_safe_or_unknown_len (__nbytes,
                                         sizeof (char),
                                         __glibc_objsize0 (__buf))
            ? __read_alias (__fd, __buf, __nbytes)
            : __glibc_unsafe_len (__nbytes,
                                  sizeof (char),
                                  __glibc_objsize0 (__buf))
              ? __read_chk_warn (__fd,
                                 __buf,
                                 __nbytes,
                                 __builtin_object_size (__buf, 0))
              : __read_chk (__fd,
                            __buf,
                            __nbytes,
                            __builtin_object_size (__buf, 0));
  }

The wrapper relies on __builtin_object_size call lowers to a constant at
Compile time and many other operations in the wrapper depend on
having a single, known value for parameters.   Because this is
impossible to have for function parameters, the wrapper depends heavily
on inlining to work and While this is an entirely viable approach on
GCC is not fully reliable on clang.  This is because by the time llvm
gets to inlining and optimizing, there is a minimal reliable source and
type-level information available (more information on a more deep
explanation on how to fortify wrapper works on clang [4]).

To allow the wrapper to work reliably and with the same functionality as
with GCC, clang requires a different approach:

  * __attribute__((diagnose_if(c, “str”, “warning”))) which is a
  * function
    level attribute; if the compiler can determine that 'c' is true at
    compile-time, it will emit a warning with the text 'str1'.  If it
    would be better to emit an error, the wrapper can use "error"
    instead of "warning".

  * __attribute__((overloadable)) which is also a function-level
    attribute; and it allows C++-style overloading to occur on C
functions.

  * __attribute__((pass_object_size(n))) which is a parameter-level
    attribute; and it makes the compiler evaluate
    __builtin_object_size(param, n) at each call site of the function
    that has the parameter and passes it in as a hidden parameter.

    This attribute has two side effects that are key to how FORTIFY
    works:

    1. It can overload solely on pass_object_size (e.g. there are two
       overloads of foo in

         void foo(char * __attribute__((pass_object_size(0))) c);
         void foo(char *);

      (The one with pass_object_size attribute has preceded the
      default one).

    2. A function with at least one pass_object_size parameter can never
       have its address taken (and overload resolution respects this).

Thus the read wrapper can be implemented as follows, without
hindering any fortify coverage compile and runtime: 

Thus the read wrapper can be implemented as follows, without
hindering any fortify coverage compile and runtime:

  extern __inline
  __attribute__((__always_inline__))
  __attribute__((__artificial__))
  __attribute__((__overloadable__))
  __attribute__((__warn_unused_result__))
  ssize_t read (int __fd,
                void *const __attribute__((pass_object_size (0))) __buf,
                size_t __nbytes)
     __attribute__((__diagnose_if__ ((((__builtin_object_size (__buf,
0)) != -1ULL
                                        && (__nbytes) >
(__builtin_object_size (__buf, 0)) / (1))),
                                     "read called with bigger length
than the size of the destination buffer",
                                     "warning")))
  {
    return (__builtin_object_size (__buf, 0) == (size_t) -1)
      ? __read_alias (__fd,
                      __buf,
                      __nbytes)
      : __read_chk (__fd,
                    __buf,
                    __nbytes,
                    __builtin_object_size (__buf, 0));
  }

To avoid changing the current semantic for GCC, a set of macros is
defined to enable the clang required attributes, along with some changes
on internal macros to avoid the need to issue the symbol_chk symbols
(which are done through the __diagnose_if__ attribute for clang).
The read wrapper can be simplified as:

  __fortify_function __attribute_overloadable__ __wur
  ssize_t read (int __fd,
                __fortify_clang_overload_arg0 (void *, ,__buf),
                size_t __nbytes)
       __fortify_clang_warning_only_if_bos0_lt (__nbytes, __buf,
                                                "read called with bigger
length than "
                                                "size of the destination
buffer")

  {
    return __glibc_fortify (read, __nbytes, sizeof (char),
                            __glibc_objsize0 (__buf),
                            __fd, __buf, __nbytes);
  }

There is no expected semantic or code change when using GCC.

Also, clang does not support __va_arg_pack, so variadic functions are
expanded to call va_arg implementations.  The error function must not
have bodies (address takes are expanded to nonfortified calls), and
with the __fortify_function compiler might still create a body with the
C++ mangling name (due to the overload attribute).  In this case, the
function is defined with __fortify_function_error_function macro
instead.

To fully test it, I used my clang branch [4] which allowed me to fully
build all fortify tests with clang. With this patchset, there is no
regressions anymore.

[1] https://sourceware.org/legacy-ml/libc-alpha/2017-09/msg00434.html
[2] https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/refs/heads/main/sys-libs/glibc/files/local/glibc-2.35/0006-glibc-add-clang-style-FORTIFY.patch
[3] https://docs.google.com/document/d/1DFfZDICTbL7RqS74wJVIJ-YnjQOj1SaoqfhbgddFYSM/edit
[4] https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/azanella/clang

Changes from v1:
- Use implementation-namespace identifiers pass_object_size and
  pass_dynamic_object_size.
- Simplify the clang macros and enable it iff for clang 5.0
  (that supports __diagnose_if__).

Adhemerval Zanella (10):
  cdefs.h: Add clang fortify directives
  libio: Improve fortify with clang
  string: Improve fortify with clang
  stdlib: Improve fortify with clang
  unistd: Improve fortify with clang
  socket: Improve fortify with clang
  syslog: Improve fortify with clang
  wcsmbs: Improve fortify with clang
  debug: Improve fcntl.h fortify warnings with clang
  debug: Improve mqueue.h fortify warnings with clang

 io/bits/fcntl2.h               |  92 ++++++++++++++++++
 io/bits/poll2.h                |  29 ++++--
 io/fcntl.h                     |   3 +-
 libio/bits/stdio2.h            | 173 +++++++++++++++++++++++++++++----
 misc/bits/syslog.h             |  14 ++-
 misc/sys/cdefs.h               | 158 +++++++++++++++++++++++++++++-
 posix/bits/unistd.h            | 110 +++++++++++++++------
 rt/bits/mqueue2.h              |  29 ++++++
 rt/mqueue.h                    |   3 +-
 socket/bits/socket2.h          |  20 +++-
 stdlib/bits/stdlib.h           |  40 +++++---
 string/bits/string_fortified.h |  57 ++++++-----
 wcsmbs/bits/wchar2.h           | 167 ++++++++++++++++++++++---------
 13 files changed, 746 insertions(+), 149 deletions(-)

-- 
2.34.1


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

* [PATCH v2 01/10] cdefs.h: Add clang fortify directives
  2024-01-08 20:21 [PATCH v2 00/10] Improve fortify support with clang Adhemerval Zanella
@ 2024-01-08 20:21 ` Adhemerval Zanella
  2024-01-08 20:21 ` [PATCH v2 02/10] libio: Improve fortify with clang Adhemerval Zanella
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Adhemerval Zanella @ 2024-01-08 20:21 UTC (permalink / raw)
  To: libc-alpha

For instance, the read wrapper is currently expanded as:

  extern __inline
  __attribute__((__always_inline__))
  __attribute__((__artificial__))
  __attribute__((__warn_unused_result__))
  ssize_t read (int __fd, void *__buf, size_t __nbytes)
  {
     return __glibc_safe_or_unknown_len (__nbytes,
                                         sizeof (char),
                                         __glibc_objsize0 (__buf))
            ? __read_alias (__fd, __buf, __nbytes)
            : __glibc_unsafe_len (__nbytes,
                                  sizeof (char),
                                  __glibc_objsize0 (__buf))
              ? __read_chk_warn (__fd,
                                 __buf,
                                 __nbytes,
                                 __builtin_object_size (__buf, 0))
              : __read_chk (__fd,
                            __buf,
                            __nbytes,
                            __builtin_object_size (__buf, 0));
  }

The wrapper relies on __builtin_object_size call lowers to a constant at
compile-time and many other operations in the wrapper depends on
having a single, known value for parameters.   Because this is
impossible to have for function parameters, the wrapper depends heavily
on inlining to work and While this is an entirely viable approach on
GCC, it is not fully reliable on clang.  This is because by the time llvm
gets to inlining and optimizing, there is a minimal reliable source and
type-level information available (more information on a more deep
explanation on how to fortify wrapper works on clang [1]).

To allow the wrapper to work reliably and with the same functionality as
with GCC, clang requires a different approach:

  * __attribute__((diagnose_if(c, “str”, “warning”))) which is a function
    level attribute; if the compiler can determine that 'c' is true at
    compile-time, it will emit a warning with the text 'str1'.  If it would
    be better to emit an error, the wrapper can use "error" instead of
    "warning".

  * __attribute__((overloadable)) which is also a function-level attribute;
    and it allows C++-style overloading to occur on C functions.

  * __attribute__((pass_object_size(n))) which is a parameter-level
    attribute; and it makes the compiler evaluate
    __builtin_object_size(param, n) at each call site of the function
    that has the parameter, and passes it in as a hidden parameter.

    This attribute has two side-effects that are key to how FORTIFY works:

    1. It can overload solely on pass_object_size (e.g. there are two
       overloads of foo in

         void foo(char * __attribute__((pass_object_size(0))) c);
         void foo(char *);

      (The one with pass_object_size attribute has precende over the
      default one).

    2. A function with at least one pass_object_size parameter can never
       have its address taken (and overload resolution respects this).

Thus the read wrapper can be implemented as follows, without
hindering any fortify coverage compile and runtime:

  extern __inline
  __attribute__((__always_inline__))
  __attribute__((__artificial__))
  __attribute__((__overloadable__))
  __attribute__((__warn_unused_result__))
  ssize_t read (int __fd,
                 void *const __attribute__((pass_object_size (0))) __buf,
                 size_t __nbytes)
     __attribute__((__diagnose_if__ ((((__builtin_object_size (__buf, 0)) != -1ULL
                                        && (__nbytes) > (__builtin_object_size (__buf, 0)) / (1))),
                                     "read called with bigger length than size of the destination buffer",
                                     "warning")))
  {
    return (__builtin_object_size (__buf, 0) == (size_t) -1)
      ? __read_alias (__fd,
                      __buf,
                      __nbytes)
      : __read_chk (__fd,
                    __buf,
                    __nbytes,
                    __builtin_object_size (__buf, 0));
  }

To avoid changing the current semantic for GCC, a set of macros is
defined to enable the clang required attributes, along with some changes
on internal macros to avoid the need to issue the symbol_chk symbols
(which are done through the __diagnose_if__ attribute for clang).
The read wrapper is simplified as:

  __fortify_function __attribute_overloadable__ __wur
  ssize_t read (int __fd,
                __fortify_clang_overload_arg0 (void *, ,__buf),
                size_t __nbytes)
       __fortify_clang_warning_only_if_bos0_lt (__nbytes, __buf,
                                                "read called with bigger length than "
                                                "size of the destination buffer")

  {
    return __glibc_fortify (read, __nbytes, sizeof (char),
                            __glibc_objsize0 (__buf),
                            __fd, __buf, __nbytes);
  }

There is no expected semantic or code change when using GCC.

Also, clang does not support __va_arg_pack, so variadic functions are
expanded to call va_arg implementations.  The error function must not
have bodies (address takes are expanded to nonfortified calls), and
with the __fortify_function compiler might still create a body with the
C++ mangling name (due to the overload attribute).  In this case, the
function is defined with __fortify_function_error_function macro
instead.

[1] https://docs.google.com/document/d/1DFfZDICTbL7RqS74wJVIJ-YnjQOj1SaoqfhbgddFYSM/edit

Checked on aarch64, armhf, x86_64, and i686.
---
 misc/sys/cdefs.h | 151 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 149 insertions(+), 2 deletions(-)

diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
index 520231dbea..62507044c8 100644
--- a/misc/sys/cdefs.h
+++ b/misc/sys/cdefs.h
@@ -145,6 +145,14 @@
 #endif
 
 
+/* The overloadable attribute was added on clang 2.6. */
+#if defined __clang_major__ \
+    && (__clang_major__ + (__clang_minor__ >= 6) > 2)
+# define __attribute_overloadable__ __attribute__((__overloadable__))
+#else
+# define __attribute_overloadable__
+#endif
+
 /* Fortify support.  */
 #define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1)
 #define __bos0(ptr) __builtin_object_size (ptr, 0)
@@ -187,27 +195,166 @@
 						   __s, __osz))		      \
    && !__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), __s, __osz))
 
+/* To correctly instrument the fortify wrapper clang requires the
+   pass_object_size attribute, and the attribute has the restriction that the
+   argument needs to be 'const'.  Furthermore, to make it usable with C
+   interfaces, clang provides the overload attribute, which provides a C++
+   like function overload support.  The overloaded fortify wrapper with the
+   pass_object_size attribute has precedence over the default symbol.
+
+   Also, clang does not support __va_arg_pack, so variadic functions are
+   expanded to issue va_arg implementations. The error function must not have
+   bodies (address takes are expanded to nonfortified calls), and with
+   __fortify_function compiler might still create a body with the C++
+   mangling name (due to the overload attribute).  In this case, the function
+   is defined with __fortify_function_error_function macro instead.
+
+   The argument size check is also done with a clang-only attribute,
+   __attribute__ ((__diagnose_if__ (...))), different than gcc which calls
+   symbol_chk_warn alias with uses __warnattr attribute.
+
+   The pass_object_size was added on clang 4.0, __diagnose_if__ on 5.0,
+   and pass_dynamic_object_size on 9.0.  */
+#if defined __clang_major__ && __clang_major__ >= 5
+# define __fortify_use_clang 1
+
+# define __fortify_function_error_function static __attribute__((__unused__))
+
+# define __fortify_clang_pass_object_size_n(n) \
+  __attribute__ ((__pass_object_size__ (n)))
+# define __fortify_clang_pass_object_size0 \
+  __fortify_clang_pass_object_size_n (0)
+# define __fortify_clang_pass_object_size \
+  __fortify_clang_pass_object_size_n (__USE_FORTIFY_LEVEL > 1)
+
+# if __clang_major__ >= 9
+#  define __fortify_clang_pass_dynamic_object_size_n(n) \
+  __attribute__ ((__pass_dynamic_object_size__ (n)))
+#  define __fortify_clang_pass_dynamic_object_size0 \
+  __fortify_clang_pass_dynamic_object_size_n (0)
+#  define __fortify_clang_pass_dynamic_object_size \
+  __fortify_clang_pass_dynamic_object_size_n (1)
+# else
+#  define __fortify_clang_pass_dynamic_object_size_n(n)
+#  define __fortify_clang_pass_dynamic_object_size0
+#  define __fortify_clang_pass_dynamic_object_size
+# endif
+
+# define __fortify_clang_bos_static_lt_impl(bos_val, n, s) \
+  ((bos_val) != -1ULL && (n) > (bos_val) / (s))
+# define __fortify_clang_bos_static_lt2(__n, __e, __s) \
+  __fortify_clang_bos_static_lt_impl (__bos (__e), __n, __s)
+# define __fortify_clang_bos_static_lt(__n, __e) \
+  __fortify_clang_bos_static_lt2 (__n, __e, 1)
+# define __fortify_clang_bos0_static_lt2(__n, __e, __s) \
+  __fortify_clang_bos_static_lt_impl (__bos0 (__e), __n, __s)
+# define __fortify_clang_bos0_static_lt(__n, __e) \
+  __fortify_clang_bos0_static_lt2 (__n, __e, 1)
+
+# define __fortify_clang_bosn_args(bos_fn, n, buf, div, complaint) \
+  (__fortify_clang_bos_static_lt_impl (bos_fn (buf), n, div)), (complaint), \
+  "warning"
+
+# define __fortify_clang_warning(__c, __msg) \
+  __attribute__ ((__diagnose_if__ ((__c), (__msg), "warning")))
+# define __fortify_clang_warning_only_if_bos0_lt(n, buf, complaint) \
+  __attribute__ ((__diagnose_if__ \
+		  (__fortify_clang_bosn_args (__bos0, n, buf, 1, complaint))))
+# define __fortify_clang_warning_only_if_bos0_lt2(n, buf, div, complaint) \
+  __attribute__ ((__diagnose_if__ \
+		  (__fortify_clang_bosn_args (__bos0, n, buf, div, complaint))))
+# define __fortify_clang_warning_only_if_bos_lt(n, buf, complaint) \
+  __attribute__ ((__diagnose_if__ \
+		  (__fortify_clang_bosn_args (__bos, n, buf, 1, complaint))))
+# define __fortify_clang_warning_only_if_bos_lt2(n, buf, div, complaint) \
+  __attribute__ ((__diagnose_if__ \
+		  (__fortify_clang_bosn_args (__bos, n, buf, div, complaint))))
+
+# if __USE_FORTIFY_LEVEL == 3
+#  define __fortify_clang_overload_arg(__type, __attr, __name) \
+  __type __attr const __fortify_clang_pass_dynamic_object_size __name
+#  define __fortify_clang_overload_arg0(__type, __attr, __name) \
+  __type __attr const __fortify_clang_pass_dynamic_object_size0 __name
+# else
+#  define __fortify_clang_overload_arg(__type, __attr, __name) \
+  __type __attr const __fortify_clang_pass_object_size __name
+#  define __fortify_clang_overload_arg0(__type, __attr, __name) \
+  __type __attr const __fortify_clang_pass_object_size0 __name
+# endif
+
+# define __fortify_clang_mul_may_overflow(size, n) \
+  ((size | n) >= (((size_t)1) << (8 * sizeof (size_t) / 2)))
+
+# define __fortify_clang_size_too_small(__bos, __dest, __len) \
+  (__bos (__dest) != (size_t) -1 && __bos (__dest) < __len)
+# define __fortify_clang_warn_if_src_too_large(__dest, __src) \
+  __fortify_clang_warning (__fortify_clang_size_too_small (__glibc_objsize, \
+							   __dest, \
+							   __builtin_strlen (__src) + 1), \
+			   "destination buffer will always be overflown by source")
+# define __fortify_clang_warn_if_dest_too_small(__dest, __len) \
+  __fortify_clang_warning (__fortify_clang_size_too_small (__glibc_objsize, \
+                                                           __dest, \
+                                                           __len), \
+                           "function called with bigger length than the destination buffer")
+# define __fortify_clang_warn_if_dest_too_small0(__dest, __len) \
+  __fortify_clang_warning (__fortify_clang_size_too_small (__glibc_objsize0, \
+                                                           __dest, \
+                                                           __len), \
+                           "function called with bigger length than the destination buffer")
+#else
+# define __fortify_use_clang 0
+# define __fortify_clang_warning(__c, __msg)
+# define __fortify_clang_warning_only_if_bos0_lt(__n, __buf, __complaint)
+# define __fortify_clang_warning_only_if_bos0_lt2(__n, __buf, __div, complaint)
+# define __fortify_clang_warning_only_if_bos_lt(__n, __buf, __complaint)
+# define __fortify_clang_warning_only_if_bos_lt2(__n, __buf, div, __complaint)
+# define __fortify_clang_overload_arg(__type, __attr, __name) \
+ __type __attr __name
+# define __fortify_clang_overload_arg0(__type, __attr, __name) \
+  __fortify_clang_overload_arg (__type, __attr, __name)
+# define __fortify_clang_warn_if_src_too_large(__dest, __src)
+# define __fortify_clang_warn_if_dest_too_small(__dest, __len)
+# define __fortify_clang_warn_if_dest_too_small0(__dest, __len)
+#endif
+
+
 /* Fortify function f.  __f_alias, __f_chk and __f_chk_warn must be
    declared.  */
 
-#define __glibc_fortify(f, __l, __s, __osz, ...) \
+#if !__fortify_use_clang
+# define __glibc_fortify(f, __l, __s, __osz, ...) \
   (__glibc_safe_or_unknown_len (__l, __s, __osz)			      \
    ? __ ## f ## _alias (__VA_ARGS__)					      \
    : (__glibc_unsafe_len (__l, __s, __osz)				      \
       ? __ ## f ## _chk_warn (__VA_ARGS__, __osz)			      \
       : __ ## f ## _chk (__VA_ARGS__, __osz)))
+#else
+# define __glibc_fortify(f, __l, __s, __osz, ...) \
+  (__osz == (__SIZE_TYPE__) -1)						      \
+   ? __ ## f ## _alias (__VA_ARGS__)					      \
+   : __ ## f ## _chk (__VA_ARGS__, __osz)
+#endif
 
 /* Fortify function f, where object size argument passed to f is the number of
    elements and not total size.  */
 
-#define __glibc_fortify_n(f, __l, __s, __osz, ...) \
+#if !__fortify_use_clang
+# define __glibc_fortify_n(f, __l, __s, __osz, ...) \
   (__glibc_safe_or_unknown_len (__l, __s, __osz)			      \
    ? __ ## f ## _alias (__VA_ARGS__)					      \
    : (__glibc_unsafe_len (__l, __s, __osz)				      \
       ? __ ## f ## _chk_warn (__VA_ARGS__, (__osz) / (__s))		      \
       : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s))))
+# else
+# define __glibc_fortify_n(f, __l, __s, __osz, ...) \
+  (__osz == (__SIZE_TYPE__) -1)						      \
+   ? __ ## f ## _alias (__VA_ARGS__)					      \
+   : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s))
 #endif
 
+#endif /* __USE_FORTIFY_LEVEL > 0 */
+
 #if __GNUC_PREREQ (4,3)
 # define __warnattr(msg) __attribute__((__warning__ (msg)))
 # define __errordecl(name, msg) \
-- 
2.34.1


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

* [PATCH v2 02/10] libio: Improve fortify with clang
  2024-01-08 20:21 [PATCH v2 00/10] Improve fortify support with clang Adhemerval Zanella
  2024-01-08 20:21 ` [PATCH v2 01/10] cdefs.h: Add clang fortify directives Adhemerval Zanella
@ 2024-01-08 20:21 ` Adhemerval Zanella
  2024-01-08 20:21 ` [PATCH v2 03/10] string: " Adhemerval Zanella
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Adhemerval Zanella @ 2024-01-08 20:21 UTC (permalink / raw)
  To: libc-alpha

It improve fortify checks for sprintf, vsprintf, vsnsprintf, fprintf,
dprintf, asprintf, __asprintf, obstack_printf, gets, fgets,
fgets_unlocked, fread, and fread_unlocked.  The runtime checks have
similar support coverage as with GCC.

For function with variadic argument (sprintf, snprintf, fprintf, printf,
dprintf, asprintf, __asprintf, obstack_printf) the fortify wrapper calls
the va_arg version since clang does not support __va_arg_pack.

Checked on aarch64, armhf, x86_64, and i686.
---
 libio/bits/stdio2.h | 173 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 153 insertions(+), 20 deletions(-)

diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h
index f9e8d37610..91a80dd7c6 100644
--- a/libio/bits/stdio2.h
+++ b/libio/bits/stdio2.h
@@ -31,15 +31,29 @@ __NTH (sprintf (char *__restrict __s, const char *__restrict __fmt, ...))
 				  __glibc_objsize (__s), __fmt,
 				  __va_arg_pack ());
 }
+#elif __fortify_use_clang
+/* clang does not have __va_arg_pack, so defer to va_arg version.  */
+__fortify_function_error_function __attribute_overloadable__ int
+__NTH (sprintf (__fortify_clang_overload_arg (char *, __restrict, __s),
+		const char *__restrict __fmt, ...))
+{
+  __gnuc_va_list __fortify_ap;
+  __builtin_va_start (__fortify_ap, __fmt);
+  int __r = __builtin___vsprintf_chk (__s, __USE_FORTIFY_LEVEL - 1,
+				      __glibc_objsize (__s), __fmt,
+				      __fortify_ap);
+  __builtin_va_end (__fortify_ap);
+  return __r;
+}
 #elif !defined __cplusplus
 # define sprintf(str, ...) \
   __builtin___sprintf_chk (str, __USE_FORTIFY_LEVEL - 1,		      \
 			   __glibc_objsize (str), __VA_ARGS__)
 #endif
 
-__fortify_function int
-__NTH (vsprintf (char *__restrict __s, const char *__restrict __fmt,
-		 __gnuc_va_list __ap))
+__fortify_function __attribute_overloadable__ int
+__NTH (vsprintf (__fortify_clang_overload_arg (char *, __restrict, __s),
+		 const char *__restrict __fmt, __gnuc_va_list __ap))
 {
   return __builtin___vsprintf_chk (__s, __USE_FORTIFY_LEVEL - 1,
 				   __glibc_objsize (__s), __fmt, __ap);
@@ -55,15 +69,33 @@ __NTH (snprintf (char *__restrict __s, size_t __n,
 				   __glibc_objsize (__s), __fmt,
 				   __va_arg_pack ());
 }
+# elif __fortify_use_clang
+/* clang does not have __va_arg_pack, so defer to va_arg version.  */
+__fortify_function_error_function __attribute_overloadable__ int
+__NTH (snprintf (__fortify_clang_overload_arg (char *, __restrict, __s),
+		 size_t __n, const char *__restrict __fmt, ...))
+{
+  __gnuc_va_list __fortify_ap;
+  __builtin_va_start (__fortify_ap, __fmt);
+  int __r = __builtin___vsnprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
+				       __glibc_objsize (__s), __fmt,
+				       __fortify_ap);
+  __builtin_va_end (__fortify_ap);
+  return __r;
+}
 # elif !defined __cplusplus
 #  define snprintf(str, len, ...) \
   __builtin___snprintf_chk (str, len, __USE_FORTIFY_LEVEL - 1,		      \
 			    __glibc_objsize (str), __VA_ARGS__)
 # endif
 
-__fortify_function int
-__NTH (vsnprintf (char *__restrict __s, size_t __n,
-		  const char *__restrict __fmt, __gnuc_va_list __ap))
+__fortify_function __attribute_overloadable__ int
+__NTH (vsnprintf (__fortify_clang_overload_arg (char *, __restrict, __s),
+		  size_t __n, const char *__restrict __fmt,
+		  __gnuc_va_list __ap))
+     __fortify_clang_warning (__fortify_clang_bos_static_lt (__n, __s),
+			      "call to vsnprintf may overflow the destination "
+			      "buffer")
 {
   return __builtin___vsnprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
 				    __glibc_objsize (__s), __fmt, __ap);
@@ -85,6 +117,30 @@ printf (const char *__restrict __fmt, ...)
 {
   return __printf_chk (__USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack ());
 }
+# elif __fortify_use_clang
+/* clang does not have __va_arg_pack, so defer to va_arg version.  */
+__fortify_function_error_function __attribute_overloadable__ __nonnull ((1)) int
+fprintf (__fortify_clang_overload_arg (FILE *, __restrict, __stream),
+	 const char *__restrict __fmt, ...)
+{
+  __gnuc_va_list __fortify_ap;
+  __builtin_va_start (__fortify_ap, __fmt);
+  int __r = __builtin___vfprintf_chk (__stream, __USE_FORTIFY_LEVEL - 1,
+				      __fmt, __fortify_ap);
+  __builtin_va_end (__fortify_ap);
+  return __r;
+}
+
+__fortify_function_error_function __attribute_overloadable__ int
+printf (__fortify_clang_overload_arg (const char *, __restrict, __fmt), ...)
+{
+  __gnuc_va_list __fortify_ap;
+  __builtin_va_start (__fortify_ap, __fmt);
+  int __r = __builtin___vprintf_chk (__USE_FORTIFY_LEVEL - 1, __fmt,
+				     __fortify_ap);
+  __builtin_va_end (__fortify_ap);
+  return __r;
+}
 # elif !defined __cplusplus
 #  define printf(...) \
   __printf_chk (__USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
@@ -92,8 +148,9 @@ printf (const char *__restrict __fmt, ...)
   __fprintf_chk (stream, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
 # endif
 
-__fortify_function int
-vprintf (const char *__restrict __fmt, __gnuc_va_list __ap)
+__fortify_function __attribute_overloadable__ int
+vprintf (__fortify_clang_overload_arg (const char *, __restrict, __fmt),
+	 __gnuc_va_list __ap)
 {
 #ifdef __USE_EXTERN_INLINES
   return __vfprintf_chk (stdout, __USE_FORTIFY_LEVEL - 1, __fmt, __ap);
@@ -117,6 +174,18 @@ dprintf (int __fd, const char *__restrict __fmt, ...)
   return __dprintf_chk (__fd, __USE_FORTIFY_LEVEL - 1, __fmt,
 			__va_arg_pack ());
 }
+#  elif __fortify_use_clang
+__fortify_function_error_function __attribute_overloadable__ int
+dprintf (int __fd, __fortify_clang_overload_arg (const char *, __restrict,
+						 __fmt), ...)
+{
+  __gnuc_va_list __fortify_ap;
+  __builtin_va_start (__fortify_ap, __fmt);
+  int __r = __vdprintf_chk (__fd, __USE_FORTIFY_LEVEL - 1, __fmt,
+			    __fortify_ap);
+  __builtin_va_end (__fortify_ap);
+  return __r;
+}
 #  elif !defined __cplusplus
 #   define dprintf(fd, ...) \
   __dprintf_chk (fd, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
@@ -153,6 +222,43 @@ __NTH (obstack_printf (struct obstack *__restrict __obstack,
   return __obstack_printf_chk (__obstack, __USE_FORTIFY_LEVEL - 1, __fmt,
 			       __va_arg_pack ());
 }
+#  elif __fortify_use_clang
+__fortify_function_error_function __attribute_overloadable__ int
+__NTH (asprintf (__fortify_clang_overload_arg (char **, __restrict, __ptr),
+		 const char *__restrict __fmt, ...))
+{
+  __gnuc_va_list __fortify_ap;
+  __builtin_va_start (__fortify_ap, __fmt);
+  int __r = __vasprintf_chk (__ptr, __USE_FORTIFY_LEVEL - 1, __fmt,
+			     __fortify_ap);
+  __builtin_va_end (__fortify_ap);
+  return __r;
+}
+
+__fortify_function_error_function __attribute_overloadable__ int
+__NTH (__asprintf (__fortify_clang_overload_arg (char **, __restrict, __ptr),
+		   const char *__restrict __fmt, ...))
+{
+  __gnuc_va_list __fortify_ap;
+  __builtin_va_start (__fortify_ap, __fmt);
+  int __r = __vasprintf_chk (__ptr, __USE_FORTIFY_LEVEL - 1, __fmt,
+			     __fortify_ap);
+  __builtin_va_end (__fortify_ap);
+  return __r;
+}
+
+__fortify_function_error_function __attribute_overloadable__ int
+__NTH (obstack_printf (__fortify_clang_overload_arg (struct obstack *,
+						     __restrict, __obstack),
+		       const char *__restrict __fmt, ...))
+{
+  __gnuc_va_list __fortify_ap;
+  __builtin_va_start (__fortify_ap, __fmt);
+  int __r = __obstack_vprintf_chk (__obstack, __USE_FORTIFY_LEVEL - 1,
+				   __fmt, __fortify_ap);
+  __builtin_va_end (__fortify_ap);
+  return __r;
+}
 #  elif !defined __cplusplus
 #   define asprintf(ptr, ...) \
   __asprintf_chk (ptr, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
@@ -182,8 +288,11 @@ __NTH (obstack_vprintf (struct obstack *__restrict __obstack,
 #endif
 
 #if __GLIBC_USE (DEPRECATED_GETS)
-__fortify_function __wur char *
-gets (char *__str)
+__fortify_function __wur __attribute_overloadable__ char *
+gets (__fortify_clang_overload_arg (char *, , __str))
+     __fortify_clang_warning (__glibc_objsize (__str) == (size_t) -1,
+			      "please use fgets or getline instead, gets "
+			      "can not specify buffer size")
 {
   if (__glibc_objsize (__str) != (size_t) -1)
     return __gets_chk (__str, __glibc_objsize (__str));
@@ -192,48 +301,70 @@ gets (char *__str)
 #endif
 
 __fortify_function __wur __fortified_attr_access (__write_only__, 1, 2)
-__nonnull ((3)) char *
-fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
+__nonnull ((3)) __attribute_overloadable__ char *
+fgets (__fortify_clang_overload_arg (char *, __restrict, __s), int __n,
+       FILE *__restrict __stream)
+     __fortify_clang_warning (__fortify_clang_bos_static_lt (__n, __s) && __n > 0,
+			      "fgets called with bigger size than length of "
+			      "destination buffer")
 {
   size_t sz = __glibc_objsize (__s);
   if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
     return __fgets_alias (__s, __n, __stream);
+#if !__fortify_use_clang
   if (__glibc_unsafe_len (__n, sizeof (char), sz))
     return __fgets_chk_warn (__s, sz, __n, __stream);
+#endif
   return __fgets_chk (__s, sz, __n, __stream);
 }
 
-__fortify_function __wur __nonnull ((4)) size_t
-fread (void *__restrict __ptr, size_t __size, size_t __n,
-       FILE *__restrict __stream)
+__fortify_function __wur __nonnull ((4)) __attribute_overloadable__ size_t
+fread (__fortify_clang_overload_arg (void *, __restrict, __ptr),
+       size_t __size, size_t __n, FILE *__restrict __stream)
+     __fortify_clang_warning (__fortify_clang_bos0_static_lt (__size * __n, __ptr)
+			      && !__fortify_clang_mul_may_overflow (__size, __n),
+			      "fread called with bigger size * n than length "
+			      "of destination buffer")
 {
   size_t sz = __glibc_objsize0 (__ptr);
   if (__glibc_safe_or_unknown_len (__n, __size, sz))
     return __fread_alias (__ptr, __size, __n, __stream);
+#if !__fortify_use_clang
   if (__glibc_unsafe_len (__n, __size, sz))
     return __fread_chk_warn (__ptr, sz, __size, __n, __stream);
+#endif
   return __fread_chk (__ptr, sz, __size, __n, __stream);
 }
 
 #ifdef __USE_GNU
 __fortify_function __wur __fortified_attr_access (__write_only__, 1, 2)
-__nonnull ((3)) char *
-fgets_unlocked (char *__restrict __s, int __n, FILE *__restrict __stream)
+__nonnull ((3)) __attribute_overloadable__ char *
+fgets_unlocked (__fortify_clang_overload_arg (char *, __restrict, __s),
+		int __n, FILE *__restrict __stream)
+     __fortify_clang_warning (__fortify_clang_bos_static_lt (__n, __s) && __n > 0,
+			      "fgets called with bigger size than length of "
+			      "destination buffer")
 {
   size_t sz = __glibc_objsize (__s);
   if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
     return __fgets_unlocked_alias (__s, __n, __stream);
+#if !__fortify_use_clang
   if (__glibc_unsafe_len (__n, sizeof (char), sz))
     return __fgets_unlocked_chk_warn (__s, sz, __n, __stream);
+#endif
   return __fgets_unlocked_chk (__s, sz, __n, __stream);
 }
 #endif
 
 #ifdef __USE_MISC
 # undef fread_unlocked
-__fortify_function __wur __nonnull ((4)) size_t
-fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
-		FILE *__restrict __stream)
+__fortify_function __wur __nonnull ((4)) __attribute_overloadable__ size_t
+fread_unlocked (__fortify_clang_overload_arg0 (void *, __restrict, __ptr),
+		size_t __size, size_t __n, FILE *__restrict __stream)
+     __fortify_clang_warning (__fortify_clang_bos0_static_lt (__size * __n, __ptr)
+			      && !__fortify_clang_mul_may_overflow (__size, __n),
+			      "fread_unlocked called with bigger size * n than "
+			      "length of destination buffer")
 {
   size_t sz = __glibc_objsize0 (__ptr);
   if (__glibc_safe_or_unknown_len (__n, __size, sz))
@@ -261,8 +392,10 @@ fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
 # endif
       return __fread_unlocked_alias (__ptr, __size, __n, __stream);
     }
+# if !__fortify_use_clang
   if (__glibc_unsafe_len (__n, __size, sz))
     return __fread_unlocked_chk_warn (__ptr, sz, __size, __n, __stream);
+# endif
   return __fread_unlocked_chk (__ptr, sz, __size, __n, __stream);
 
 }
-- 
2.34.1


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

* [PATCH v2 03/10] string: Improve fortify with clang
  2024-01-08 20:21 [PATCH v2 00/10] Improve fortify support with clang Adhemerval Zanella
  2024-01-08 20:21 ` [PATCH v2 01/10] cdefs.h: Add clang fortify directives Adhemerval Zanella
  2024-01-08 20:21 ` [PATCH v2 02/10] libio: Improve fortify with clang Adhemerval Zanella
@ 2024-01-08 20:21 ` Adhemerval Zanella
  2024-01-08 20:21 ` [PATCH v2 04/10] stdlib: " Adhemerval Zanella
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Adhemerval Zanella @ 2024-01-08 20:21 UTC (permalink / raw)
  To: libc-alpha

It improve fortify checks for strcpy, stpcpy, strncpy, stpncpy, strcat,
strncat, strlcpy, and strlcat.  The runtime and compile checks have
similar coverage as with GCC.

Checked on aarch64, armhf, x86_64, and i686.
---
 string/bits/string_fortified.h | 57 +++++++++++++++++++++-------------
 1 file changed, 35 insertions(+), 22 deletions(-)

diff --git a/string/bits/string_fortified.h b/string/bits/string_fortified.h
index e0714f794c..83b80184a8 100644
--- a/string/bits/string_fortified.h
+++ b/string/bits/string_fortified.h
@@ -73,24 +73,29 @@ __NTH (explicit_bzero (void *__dest, size_t __len))
 }
 #endif
 
-__fortify_function char *
-__NTH (strcpy (char *__restrict __dest, const char *__restrict __src))
+__fortify_function __attribute_overloadable__ char *
+__NTH (strcpy (__fortify_clang_overload_arg (char *, __restrict, __dest),
+	       const char *__restrict __src))
+     __fortify_clang_warn_if_src_too_large (__dest, __src)
 {
   return __builtin___strcpy_chk (__dest, __src, __glibc_objsize (__dest));
 }
 
 #ifdef __USE_XOPEN2K8
-__fortify_function char *
-__NTH (stpcpy (char *__restrict __dest, const char *__restrict __src))
+__fortify_function __attribute_overloadable__ char *
+__NTH (stpcpy (__fortify_clang_overload_arg (char *, __restrict, __dest),
+	       const char *__restrict __src))
+     __fortify_clang_warn_if_src_too_large (__dest, __src)
 {
   return __builtin___stpcpy_chk (__dest, __src, __glibc_objsize (__dest));
 }
 #endif
 
 
-__fortify_function char *
-__NTH (strncpy (char *__restrict __dest, const char *__restrict __src,
-		size_t __len))
+__fortify_function __attribute_overloadable__ char *
+__NTH (strncpy (__fortify_clang_overload_arg (char *, __restrict, __dest),
+		const char *__restrict __src, size_t __len))
+     __fortify_clang_warn_if_dest_too_small (__dest, __len)
 {
   return __builtin___strncpy_chk (__dest, __src, __len,
 				  __glibc_objsize (__dest));
@@ -98,8 +103,10 @@ __NTH (strncpy (char *__restrict __dest, const char *__restrict __src,
 
 #ifdef __USE_XOPEN2K8
 # if __GNUC_PREREQ (4, 7) || __glibc_clang_prereq (2, 6)
-__fortify_function char *
-__NTH (stpncpy (char *__dest, const char *__src, size_t __n))
+__fortify_function __attribute_overloadable__ char *
+__NTH (stpncpy (__fortify_clang_overload_arg (char *, ,__dest),
+		const char *__src, size_t __n))
+     __fortify_clang_warn_if_dest_too_small (__dest, __n)
 {
   return __builtin___stpncpy_chk (__dest, __src, __n,
 				  __glibc_objsize (__dest));
@@ -112,8 +119,9 @@ extern char *__stpncpy_chk (char *__dest, const char *__src, size_t __n,
 extern char *__REDIRECT_NTH (__stpncpy_alias, (char *__dest, const char *__src,
 					       size_t __n), stpncpy);
 
-__fortify_function char *
-__NTH (stpncpy (char *__dest, const char *__src, size_t __n))
+__fortify_function __attribute_overloadable__ char *
+__NTH (stpncpy (__fortify_clang_overload_arg (char *, ,__dest),
+		const char *__src, size_t __n))
 {
   if (__bos (__dest) != (size_t) -1
       && (!__builtin_constant_p (__n) || __n > __bos (__dest)))
@@ -124,16 +132,19 @@ __NTH (stpncpy (char *__dest, const char *__src, size_t __n))
 #endif
 
 
-__fortify_function char *
-__NTH (strcat (char *__restrict __dest, const char *__restrict __src))
+__fortify_function __attribute_overloadable__ char *
+__NTH (strcat (__fortify_clang_overload_arg (char *, __restrict, __dest),
+	       const char *__restrict __src))
+     __fortify_clang_warn_if_src_too_large (__dest, __src)
 {
   return __builtin___strcat_chk (__dest, __src, __glibc_objsize (__dest));
 }
 
 
-__fortify_function char *
-__NTH (strncat (char *__restrict __dest, const char *__restrict __src,
-		size_t __len))
+__fortify_function __attribute_overloadable__ char *
+__NTH (strncat (__fortify_clang_overload_arg (char *, __restrict, __dest),
+		const char *__restrict __src, size_t __len))
+     __fortify_clang_warn_if_src_too_large (__dest, __src)
 {
   return __builtin___strncat_chk (__dest, __src, __len,
 				  __glibc_objsize (__dest));
@@ -146,9 +157,10 @@ extern size_t __REDIRECT_NTH (__strlcpy_alias,
 			      (char *__dest, const char *__src, size_t __n),
 			      strlcpy);
 
-__fortify_function size_t
-__NTH (strlcpy (char *__restrict __dest, const char *__restrict __src,
-		size_t __n))
+__fortify_function __attribute_overloadable__ size_t
+__NTH (strlcpy (__fortify_clang_overload_arg (char *, __restrict, __dest),
+		const char *__restrict __src, size_t __n))
+     __fortify_clang_warn_if_dest_too_small (__dest, __n)
 {
   if (__glibc_objsize (__dest) != (size_t) -1
       && (!__builtin_constant_p (__n > __glibc_objsize (__dest))
@@ -163,9 +175,10 @@ extern size_t __REDIRECT_NTH (__strlcat_alias,
 			      (char *__dest, const char *__src, size_t __n),
 			      strlcat);
 
-__fortify_function size_t
-__NTH (strlcat (char *__restrict __dest, const char *__restrict __src,
-		size_t __n))
+__fortify_function __attribute_overloadable__ size_t
+__NTH (strlcat (__fortify_clang_overload_arg (char *, __restrict, __dest),
+		const char *__restrict __src, size_t __n))
+     __fortify_clang_warn_if_src_too_large (__dest, __src)
 {
   if (__glibc_objsize (__dest) != (size_t) -1
       && (!__builtin_constant_p (__n > __glibc_objsize (__dest))
-- 
2.34.1


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

* [PATCH v2 04/10] stdlib: Improve fortify with clang
  2024-01-08 20:21 [PATCH v2 00/10] Improve fortify support with clang Adhemerval Zanella
                   ` (2 preceding siblings ...)
  2024-01-08 20:21 ` [PATCH v2 03/10] string: " Adhemerval Zanella
@ 2024-01-08 20:21 ` Adhemerval Zanella
  2024-01-08 20:21 ` [PATCH v2 05/10] unistd: " Adhemerval Zanella
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Adhemerval Zanella @ 2024-01-08 20:21 UTC (permalink / raw)
  To: libc-alpha

It improve fortify checks for realpath, ptsname_r, wctomb, mbstowcs,
and wcstombs.  The runtime and compile checks have similar coverage as
with GCC.

Checked on aarch64, armhf, x86_64, and i686.
---
 stdlib/bits/stdlib.h | 40 +++++++++++++++++++++++++++++-----------
 1 file changed, 29 insertions(+), 11 deletions(-)

diff --git a/stdlib/bits/stdlib.h b/stdlib/bits/stdlib.h
index 1c7191ba57..9e31801e80 100644
--- a/stdlib/bits/stdlib.h
+++ b/stdlib/bits/stdlib.h
@@ -33,15 +33,22 @@ extern char *__REDIRECT_NTH (__realpath_chk_warn,
      __warnattr ("second argument of realpath must be either NULL or at "
 		 "least PATH_MAX bytes long buffer");
 
-__fortify_function __wur char *
-__NTH (realpath (const char *__restrict __name, char *__restrict __resolved))
+__fortify_function __attribute_overloadable__ __wur char *
+__NTH (realpath (const char *__restrict __name,
+		 __fortify_clang_overload_arg (char *, __restrict, __resolved)))
+#if defined _LIBC_LIMITS_H_ && defined PATH_MAX
+     __fortify_clang_warning_only_if_bos_lt (PATH_MAX, __resolved,
+					     "second argument of realpath must be "
+					     "either NULL or at least PATH_MAX "
+					     "bytes long buffer")
+#endif
 {
   size_t sz = __glibc_objsize (__resolved);
 
   if (sz == (size_t) -1)
     return __realpath_alias (__name, __resolved);
 
-#if defined _LIBC_LIMITS_H_ && defined PATH_MAX
+#if !__fortify_use_clang && defined _LIBC_LIMITS_H_ && defined PATH_MAX
   if (__glibc_unsafe_len (PATH_MAX, sizeof (char), sz))
     return __realpath_chk_warn (__name, __resolved, sz);
 #endif
@@ -61,8 +68,13 @@ extern int __REDIRECT_NTH (__ptsname_r_chk_warn,
      __nonnull ((2)) __warnattr ("ptsname_r called with buflen bigger than "
 				 "size of buf");
 
-__fortify_function int
-__NTH (ptsname_r (int __fd, char *__buf, size_t __buflen))
+__fortify_function __attribute_overloadable__ int
+__NTH (ptsname_r (int __fd,
+		 __fortify_clang_overload_arg (char *, ,__buf),
+		 size_t __buflen))
+     __fortify_clang_warning_only_if_bos_lt (__buflen, __buf,
+					     "ptsname_r called with buflen "
+					     "bigger than size of buf")
 {
   return __glibc_fortify (ptsname_r, __buflen, sizeof (char),
 			  __glibc_objsize (__buf),
@@ -75,8 +87,8 @@ extern int __wctomb_chk (char *__s, wchar_t __wchar, size_t __buflen)
 extern int __REDIRECT_NTH (__wctomb_alias, (char *__s, wchar_t __wchar),
 			   wctomb) __wur;
 
-__fortify_function __wur int
-__NTH (wctomb (char *__s, wchar_t __wchar))
+__fortify_function __attribute_overloadable__ __wur int
+__NTH (wctomb (__fortify_clang_overload_arg (char *, ,__s), wchar_t __wchar))
 {
   /* We would have to include <limits.h> to get a definition of MB_LEN_MAX.
      But this would only disturb the namespace.  So we define our own
@@ -113,12 +125,17 @@ extern size_t __REDIRECT_NTH (__mbstowcs_chk_warn,
      __warnattr ("mbstowcs called with dst buffer smaller than len "
 		 "* sizeof (wchar_t)");
 
-__fortify_function size_t
-__NTH (mbstowcs (wchar_t *__restrict __dst, const char *__restrict __src,
+__fortify_function __attribute_overloadable__ size_t
+__NTH (mbstowcs (__fortify_clang_overload_arg (wchar_t *, __restrict, __dst),
+		 const char *__restrict __src,
 		 size_t __len))
+     __fortify_clang_warning_only_if_bos0_lt2 (__len, __dst, sizeof (wchar_t),
+					       "mbstowcs called with dst buffer "
+					       "smaller than len * sizeof (wchar_t)")
 {
   if (__builtin_constant_p (__dst == NULL) && __dst == NULL)
     return __mbstowcs_nulldst (__dst, __src, __len);
+
   else
     return __glibc_fortify_n (mbstowcs, __len, sizeof (wchar_t),
 			      __glibc_objsize (__dst), __dst, __src, __len);
@@ -139,8 +156,9 @@ extern size_t __REDIRECT_NTH (__wcstombs_chk_warn,
 			       size_t __len, size_t __dstlen), __wcstombs_chk)
      __warnattr ("wcstombs called with dst buffer smaller than len");
 
-__fortify_function size_t
-__NTH (wcstombs (char *__restrict __dst, const wchar_t *__restrict __src,
+__fortify_function __attribute_overloadable__ size_t
+__NTH (wcstombs (__fortify_clang_overload_arg (char *, __restrict, __dst),
+		 const wchar_t *__restrict __src,
 		 size_t __len))
 {
   return __glibc_fortify (wcstombs, __len, sizeof (char),
-- 
2.34.1


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

* [PATCH v2 05/10] unistd: Improve fortify with clang
  2024-01-08 20:21 [PATCH v2 00/10] Improve fortify support with clang Adhemerval Zanella
                   ` (3 preceding siblings ...)
  2024-01-08 20:21 ` [PATCH v2 04/10] stdlib: " Adhemerval Zanella
@ 2024-01-08 20:21 ` Adhemerval Zanella
  2024-01-08 20:21 ` [PATCH v2 06/10] socket: " Adhemerval Zanella
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Adhemerval Zanella @ 2024-01-08 20:21 UTC (permalink / raw)
  To: libc-alpha

It improve fortify checks for read, pread, pread64, readlink,
readlinkat, getcwd, getwd, confstr, getgroups, ttyname_r, getlogin_r,
gethostname, and getdomainname.  The compile and runtime checks have
similar coverage as with GCC.

Checked on aarch64, armhf, x86_64, and i686.
---
 posix/bits/unistd.h | 110 +++++++++++++++++++++++++++++++++-----------
 1 file changed, 82 insertions(+), 28 deletions(-)

diff --git a/posix/bits/unistd.h b/posix/bits/unistd.h
index bd209ec28e..2757b0619a 100644
--- a/posix/bits/unistd.h
+++ b/posix/bits/unistd.h
@@ -22,8 +22,12 @@
 
 # include <bits/unistd-decl.h>
 
-__fortify_function __wur ssize_t
-read (int __fd, void *__buf, size_t __nbytes)
+__fortify_function __attribute_overloadable__ __wur ssize_t
+read (int __fd, __fortify_clang_overload_arg0 (void *, ,__buf), size_t __nbytes)
+     __fortify_clang_warning_only_if_bos0_lt (__nbytes, __buf,
+					      "read called with bigger length than "
+					      "size of the destination buffer")
+
 {
   return __glibc_fortify (read, __nbytes, sizeof (char),
 			  __glibc_objsize0 (__buf),
@@ -32,16 +36,24 @@ read (int __fd, void *__buf, size_t __nbytes)
 
 #if defined __USE_UNIX98 || defined __USE_XOPEN2K8
 # ifndef __USE_FILE_OFFSET64
-__fortify_function __wur ssize_t
-pread (int __fd, void *__buf, size_t __nbytes, __off_t __offset)
+__fortify_function __attribute_overloadable__ __wur ssize_t
+pread (int __fd, __fortify_clang_overload_arg0 (void *, ,__buf),
+       size_t __nbytes, __off_t __offset)
+     __fortify_clang_warning_only_if_bos0_lt (__nbytes, __buf,
+					      "pread called with bigger length than "
+					      "size of the destination buffer")
 {
   return __glibc_fortify (pread, __nbytes, sizeof (char),
 			  __glibc_objsize0 (__buf),
 			  __fd, __buf, __nbytes, __offset);
 }
 # else
-__fortify_function __wur ssize_t
-pread (int __fd, void *__buf, size_t __nbytes, __off64_t __offset)
+__fortify_function __attribute_overloadable__ __wur ssize_t
+pread (int __fd, __fortify_clang_overload_arg0 (void *, ,__buf),
+       size_t __nbytes, __off64_t __offset)
+     __fortify_clang_warning_only_if_bos0_lt (__nbytes, __buf,
+					      "pread called with bigger length than "
+					      "size of the destination buffer")
 {
   return __glibc_fortify (pread64, __nbytes, sizeof (char),
 			  __glibc_objsize0 (__buf),
@@ -50,8 +62,12 @@ pread (int __fd, void *__buf, size_t __nbytes, __off64_t __offset)
 # endif
 
 # ifdef __USE_LARGEFILE64
-__fortify_function __wur ssize_t
-pread64 (int __fd, void *__buf, size_t __nbytes, __off64_t __offset)
+__fortify_function __attribute_overloadable__ __wur ssize_t
+pread64 (int __fd, __fortify_clang_overload_arg0 (void *, ,__buf),
+	 size_t __nbytes, __off64_t __offset)
+     __fortify_clang_warning_only_if_bos0_lt (__nbytes, __buf,
+					      "pread64 called with bigger length than "
+					      "size of the destination buffer")
 {
   return __glibc_fortify (pread64, __nbytes, sizeof (char),
 			  __glibc_objsize0 (__buf),
@@ -61,9 +77,14 @@ pread64 (int __fd, void *__buf, size_t __nbytes, __off64_t __offset)
 #endif
 
 #if defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K
-__fortify_function __nonnull ((1, 2)) __wur ssize_t
-__NTH (readlink (const char *__restrict __path, char *__restrict __buf,
+__fortify_function __attribute_overloadable__ __nonnull ((1, 2)) __wur ssize_t
+__NTH (readlink (const char *__restrict __path,
+		 __fortify_clang_overload_arg0 (char *, __restrict, __buf),
 		 size_t __len))
+     __fortify_clang_warning_only_if_bos_lt (__len, __buf,
+					     "readlink called with bigger length "
+					     "than size of destination buffer")
+
 {
   return __glibc_fortify (readlink, __len, sizeof (char),
 			  __glibc_objsize (__buf),
@@ -72,9 +93,13 @@ __NTH (readlink (const char *__restrict __path, char *__restrict __buf,
 #endif
 
 #ifdef __USE_ATFILE
-__fortify_function __nonnull ((2, 3)) __wur ssize_t
+__fortify_function __attribute_overloadable__ __nonnull ((2, 3)) __wur ssize_t
 __NTH (readlinkat (int __fd, const char *__restrict __path,
-		   char *__restrict __buf, size_t __len))
+		   __fortify_clang_overload_arg0 (char *, __restrict, __buf),
+		   size_t __len))
+     __fortify_clang_warning_only_if_bos_lt (__len, __buf,
+					     "readlinkat called with bigger length "
+					     "than size of destination buffer")
 {
   return __glibc_fortify (readlinkat, __len, sizeof (char),
 			  __glibc_objsize (__buf),
@@ -82,8 +107,11 @@ __NTH (readlinkat (int __fd, const char *__restrict __path,
 }
 #endif
 
-__fortify_function __wur char *
-__NTH (getcwd (char *__buf, size_t __size))
+__fortify_function __attribute_overloadable__ __wur char *
+__NTH (getcwd (__fortify_clang_overload_arg (char *, , __buf), size_t __size))
+     __fortify_clang_warning_only_if_bos_lt (__size, __buf,
+					     "getcwd called with bigger length "
+					     "than size of destination buffer")
 {
   return __glibc_fortify (getcwd, __size, sizeof (char),
 			  __glibc_objsize (__buf),
@@ -91,8 +119,9 @@ __NTH (getcwd (char *__buf, size_t __size))
 }
 
 #if defined __USE_MISC || defined __USE_XOPEN_EXTENDED
-__fortify_function __nonnull ((1)) __attribute_deprecated__ __wur char *
-__NTH (getwd (char *__buf))
+__fortify_function __attribute_overloadable__ __nonnull ((1))
+__attribute_deprecated__ __wur char *
+__NTH (getwd (__fortify_clang_overload_arg (char *,, __buf)))
 {
   if (__glibc_objsize (__buf) != (size_t) -1)
     return __getwd_chk (__buf, __glibc_objsize (__buf));
@@ -100,8 +129,12 @@ __NTH (getwd (char *__buf))
 }
 #endif
 
-__fortify_function size_t
-__NTH (confstr (int __name, char *__buf, size_t __len))
+__fortify_function __attribute_overloadable__ size_t
+__NTH (confstr (int __name, __fortify_clang_overload_arg (char *, ,__buf),
+		size_t __len))
+     __fortify_clang_warning_only_if_bos_lt (__len, __buf,
+					     "confstr called with bigger length than "
+					     "size of destination buffer")
 {
   return __glibc_fortify (confstr, __len, sizeof (char),
 			  __glibc_objsize (__buf),
@@ -109,8 +142,13 @@ __NTH (confstr (int __name, char *__buf, size_t __len))
 }
 
 
-__fortify_function int
-__NTH (getgroups (int __size, __gid_t __list[]))
+__fortify_function __attribute_overloadable__ int
+__NTH (getgroups (int __size,
+		  __fortify_clang_overload_arg (__gid_t *, ,  __list)))
+     __fortify_clang_warning_only_if_bos_lt (__size * sizeof (__gid_t), __list,
+					     "getgroups called with bigger group "
+					     "count than what can fit into "
+					     "destination buffer")
 {
   return __glibc_fortify (getgroups, __size, sizeof (__gid_t),
 			  __glibc_objsize (__list),
@@ -118,8 +156,13 @@ __NTH (getgroups (int __size, __gid_t __list[]))
 }
 
 
-__fortify_function int
-__NTH (ttyname_r (int __fd, char *__buf, size_t __buflen))
+__fortify_function __attribute_overloadable__ int
+__NTH (ttyname_r (int __fd,
+		 __fortify_clang_overload_arg (char *, ,__buf),
+		 size_t __buflen))
+     __fortify_clang_warning_only_if_bos_lt (__buflen, __buf,
+					     "ttyname_r called with bigger buflen "
+					     "than size of destination buffer")
 {
   return __glibc_fortify (ttyname_r, __buflen, sizeof (char),
 			  __glibc_objsize (__buf),
@@ -128,8 +171,11 @@ __NTH (ttyname_r (int __fd, char *__buf, size_t __buflen))
 
 
 #ifdef __USE_POSIX199506
-__fortify_function int
-getlogin_r (char *__buf, size_t __buflen)
+__fortify_function __attribute_overloadable__ int
+getlogin_r (__fortify_clang_overload_arg (char *, ,__buf), size_t __buflen)
+     __fortify_clang_warning_only_if_bos_lt (__buflen, __buf,
+					     "getlogin_r called with bigger buflen "
+					     "than size of destination buffer")
 {
   return __glibc_fortify (getlogin_r, __buflen, sizeof (char),
 			  __glibc_objsize (__buf),
@@ -139,8 +185,12 @@ getlogin_r (char *__buf, size_t __buflen)
 
 
 #if defined __USE_MISC || defined __USE_UNIX98
-__fortify_function int
-__NTH (gethostname (char *__buf, size_t __buflen))
+__fortify_function __attribute_overloadable__ int
+__NTH (gethostname (__fortify_clang_overload_arg (char *, ,__buf),
+		    size_t __buflen))
+     __fortify_clang_warning_only_if_bos_lt (__buflen, __buf,
+					     "gethostname called with bigger buflen "
+					     "than size of destination buffer")
 {
   return __glibc_fortify (gethostname, __buflen, sizeof (char),
 			  __glibc_objsize (__buf),
@@ -150,8 +200,12 @@ __NTH (gethostname (char *__buf, size_t __buflen))
 
 
 #if defined __USE_MISC || (defined __USE_XOPEN && !defined __USE_UNIX98)
-__fortify_function int
-__NTH (getdomainname (char *__buf, size_t __buflen))
+__fortify_function __attribute_overloadable__ int
+__NTH (getdomainname (__fortify_clang_overload_arg (char *, ,__buf),
+		      size_t __buflen))
+     __fortify_clang_warning_only_if_bos_lt (__buflen, __buf,
+					     "getdomainname called with bigger "
+					     "buflen than size of destination buffer")
 {
   return __glibc_fortify (getdomainname, __buflen, sizeof (char),
 			  __glibc_objsize (__buf),
-- 
2.34.1


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

* [PATCH v2 06/10] socket: Improve fortify with clang
  2024-01-08 20:21 [PATCH v2 00/10] Improve fortify support with clang Adhemerval Zanella
                   ` (4 preceding siblings ...)
  2024-01-08 20:21 ` [PATCH v2 05/10] unistd: " Adhemerval Zanella
@ 2024-01-08 20:21 ` Adhemerval Zanella
  2024-01-08 20:21 ` [PATCH v2 07/10] syslog: " Adhemerval Zanella
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Adhemerval Zanella @ 2024-01-08 20:21 UTC (permalink / raw)
  To: libc-alpha

It improve fortify checks recv, recvfrom, poll, and ppoll.  The compile
and runtime hecks have similar coverage as with GCC.

Checked on aarch64, armhf, x86_64, and i686.
---
 io/bits/poll2.h       | 29 +++++++++++++++++++++--------
 socket/bits/socket2.h | 20 ++++++++++++++++----
 2 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/io/bits/poll2.h b/io/bits/poll2.h
index 6152a8c5e4..24ec1056eb 100644
--- a/io/bits/poll2.h
+++ b/io/bits/poll2.h
@@ -33,8 +33,13 @@ extern int __REDIRECT (__poll_chk_warn, (struct pollfd *__fds, nfds_t __nfds,
 		       __poll_chk)
   __warnattr ("poll called with fds buffer too small file nfds entries");
 
-__fortify_function __fortified_attr_access (__write_only__, 1, 2) int
-poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
+__fortify_function __fortified_attr_access (__write_only__, 1, 2)
+__attribute_overloadable__ int
+poll (__fortify_clang_overload_arg (struct pollfd *, ,__fds), nfds_t __nfds,
+      int __timeout)
+     __fortify_clang_warning_only_if_bos_lt2 (__nfds, __fds, sizeof (*__fds),
+					      "poll called with fds buffer "
+					      "too small file nfds entries")
 {
   return __glibc_fortify (poll, __nfds, sizeof (*__fds),
 			  __glibc_objsize (__fds),
@@ -58,9 +63,13 @@ extern int __REDIRECT (__ppoll64_chk_warn, (struct pollfd *__fds, nfds_t __n,
 		       __ppoll64_chk)
   __warnattr ("ppoll called with fds buffer too small file nfds entries");
 
-__fortify_function __fortified_attr_access (__write_only__, 1, 2) int
-ppoll (struct pollfd *__fds, nfds_t __nfds, const struct timespec *__timeout,
-       const __sigset_t *__ss)
+__fortify_function __fortified_attr_access (__write_only__, 1, 2)
+__attribute_overloadable__ int
+ppoll (__fortify_clang_overload_arg (struct pollfd *, ,__fds), nfds_t __nfds,
+       const struct timespec *__timeout, const __sigset_t *__ss)
+     __fortify_clang_warning_only_if_bos_lt2 (__nfds, __fds, sizeof (*__fds),
+					      "ppoll called with fds buffer "
+					      "too small file nfds entries")
 {
   return __glibc_fortify (ppoll64, __nfds, sizeof (*__fds),
 			  __glibc_objsize (__fds),
@@ -81,9 +90,13 @@ extern int __REDIRECT (__ppoll_chk_warn, (struct pollfd *__fds, nfds_t __nfds,
 		       __ppoll_chk)
   __warnattr ("ppoll called with fds buffer too small file nfds entries");
 
-__fortify_function __fortified_attr_access (__write_only__, 1, 2) int
-ppoll (struct pollfd *__fds, nfds_t __nfds, const struct timespec *__timeout,
-       const __sigset_t *__ss)
+__fortify_function __fortified_attr_access (__write_only__, 1, 2)
+__attribute_overloadable__ int
+ppoll (__fortify_clang_overload_arg (struct pollfd *, ,__fds), nfds_t __nfds,
+       const struct timespec *__timeout, const __sigset_t *__ss)
+     __fortify_clang_warning_only_if_bos_lt2 (__nfds, __fds, sizeof (*__fds),
+					      "ppoll called with fds buffer "
+					      "too small file nfds entries")
 {
   return __glibc_fortify (ppoll, __nfds, sizeof (*__fds),
 			  __glibc_objsize (__fds),
diff --git a/socket/bits/socket2.h b/socket/bits/socket2.h
index a88cb64370..04780f320e 100644
--- a/socket/bits/socket2.h
+++ b/socket/bits/socket2.h
@@ -30,14 +30,20 @@ extern ssize_t __REDIRECT (__recv_chk_warn,
      __warnattr ("recv called with bigger length than size of destination "
 		 "buffer");
 
-__fortify_function ssize_t
-recv (int __fd, void *__buf, size_t __n, int __flags)
+__fortify_function __attribute_overloadable__ ssize_t
+recv (int __fd, __fortify_clang_overload_arg0 (void *, ,__buf), size_t __n,
+      int __flags)
+     __fortify_clang_warning_only_if_bos0_lt (__n, __buf,
+					      "recv called with bigger length than "
+					      "size of destination buffer")
 {
   size_t sz = __glibc_objsize0 (__buf);
   if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
     return __recv_alias (__fd, __buf, __n, __flags);
+#if !__fortify_use_clang
   if (__glibc_unsafe_len (__n, sizeof (char), sz))
     return __recv_chk_warn (__fd, __buf, __n, sz, __flags);
+#endif
   return __recv_chk (__fd, __buf, __n, sz, __flags);
 }
 
@@ -57,15 +63,21 @@ extern ssize_t __REDIRECT (__recvfrom_chk_warn,
      __warnattr ("recvfrom called with bigger length than size of "
 		 "destination buffer");
 
-__fortify_function ssize_t
-recvfrom (int __fd, void *__restrict __buf, size_t __n, int __flags,
+__fortify_function __attribute_overloadable__ ssize_t
+recvfrom (int __fd, __fortify_clang_overload_arg0 (void *, __restrict, __buf),
+	  size_t __n, int __flags,
 	  __SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len)
+     __fortify_clang_warning_only_if_bos0_lt (__n, __buf,
+					      "recvfrom called with bigger length "
+					      "than size of destination buffer")
 {
   size_t sz = __glibc_objsize0 (__buf);
   if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
     return __recvfrom_alias (__fd, __buf, __n, __flags, __addr, __addr_len);
+#if !__fortify_use_clang
   if (__glibc_unsafe_len (__n, sizeof (char), sz))
     return __recvfrom_chk_warn (__fd, __buf, __n, sz, __flags, __addr,
 				__addr_len);
+#endif
   return __recvfrom_chk (__fd, __buf, __n, sz, __flags, __addr, __addr_len);
 }
-- 
2.34.1


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

* [PATCH v2 07/10] syslog: Improve fortify with clang
  2024-01-08 20:21 [PATCH v2 00/10] Improve fortify support with clang Adhemerval Zanella
                   ` (5 preceding siblings ...)
  2024-01-08 20:21 ` [PATCH v2 06/10] socket: " Adhemerval Zanella
@ 2024-01-08 20:21 ` Adhemerval Zanella
  2024-01-08 20:21 ` [PATCH v2 08/10] wcsmbs: " Adhemerval Zanella
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Adhemerval Zanella @ 2024-01-08 20:21 UTC (permalink / raw)
  To: libc-alpha

It improve fortify checks for syslog and vsyslog.  The compile
and runtime hecks have similar coverage as with GCC.

The syslog fortify wrapper calls the va_arg version, since clang does
not support __va_arg_pack.

Checked on aarch64, armhf, x86_64, and i686.
---
 misc/bits/syslog.h | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/misc/bits/syslog.h b/misc/bits/syslog.h
index aadcd42000..100b0c78cc 100644
--- a/misc/bits/syslog.h
+++ b/misc/bits/syslog.h
@@ -36,6 +36,15 @@ syslog (int __pri, const char *__fmt, ...)
 {
   __syslog_chk (__pri, __USE_FORTIFY_LEVEL - 1, __fmt, __va_arg_pack ());
 }
+#elif __fortify_use_clang && defined __USE_MISC
+__fortify_function_error_function __attribute_overloadable__ void
+syslog (int __pri, __fortify_clang_overload_arg (const char *, , __fmt), ...)
+{
+  __gnuc_va_list __fortify_ap;
+  __builtin_va_start (__fortify_ap, __fmt);
+  __vsyslog_chk (__pri, __USE_FORTIFY_LEVEL - 1, __fmt, __fortify_ap);
+  __builtin_va_end (__fortify_ap);
+}
 #elif !defined __cplusplus
 # define syslog(pri, ...) \
   __syslog_chk (pri, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
@@ -43,8 +52,9 @@ syslog (int __pri, const char *__fmt, ...)
 
 
 #ifdef __USE_MISC
-__fortify_function void
-vsyslog (int __pri, const char *__fmt, __gnuc_va_list __ap)
+__fortify_function __attribute_overloadable__ void
+vsyslog (int __pri, __fortify_clang_overload_arg (const char *, ,__fmt),
+	 __gnuc_va_list __ap)
 {
   __vsyslog_chk (__pri,  __USE_FORTIFY_LEVEL - 1, __fmt, __ap);
 }
-- 
2.34.1


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

* [PATCH v2 08/10] wcsmbs: Improve fortify with clang
  2024-01-08 20:21 [PATCH v2 00/10] Improve fortify support with clang Adhemerval Zanella
                   ` (6 preceding siblings ...)
  2024-01-08 20:21 ` [PATCH v2 07/10] syslog: " Adhemerval Zanella
@ 2024-01-08 20:21 ` Adhemerval Zanella
  2024-01-08 20:21 ` [PATCH v2 09/10] debug: Improve fcntl.h fortify warnings " Adhemerval Zanella
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Adhemerval Zanella @ 2024-01-08 20:21 UTC (permalink / raw)
  To: libc-alpha

It improve fortify checks for wmemcpy, wmemmove, wmemset, wcscpy,
wcpcpy, wcsncpy, wcpncpy, wcscat, wcsncat, wcslcpy, wcslcat, swprintf,
fgetws, fgetws_unlocked, wcrtomb, mbsrtowcs, wcsrtombs, mbsnrtowcs, and
wcsnrtombs.  The compile and runtime checks have similar coverage as
with GCC.

Checked on aarch64, armhf, x86_64, and i686.
---
 wcsmbs/bits/wchar2.h | 167 ++++++++++++++++++++++++++++++-------------
 1 file changed, 119 insertions(+), 48 deletions(-)

diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h
index 49f19bca19..9fdff47ee2 100644
--- a/wcsmbs/bits/wchar2.h
+++ b/wcsmbs/bits/wchar2.h
@@ -20,17 +20,24 @@
 # error "Never include <bits/wchar2.h> directly; use <wchar.h> instead."
 #endif
 
-__fortify_function wchar_t *
-__NTH (wmemcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
-		size_t __n))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wmemcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __s1),
+		const wchar_t *__restrict __s2, size_t __n))
+     __fortify_clang_warning_only_if_bos0_lt2 (__n, __s1, sizeof (wchar_t),
+					       "wmemcpy called with length bigger "
+					       "than size of destination buffer")
 {
   return __glibc_fortify_n (wmemcpy, __n, sizeof (wchar_t),
 			    __glibc_objsize0 (__s1),
 			    __s1, __s2, __n);
 }
 
-__fortify_function wchar_t *
-__NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wmemmove (__fortify_clang_overload_arg (wchar_t *, ,__s1),
+		 const wchar_t *__s2, size_t __n))
+     __fortify_clang_warning_only_if_bos0_lt2 (__n, __s1, sizeof (wchar_t),
+					       "wmemmove called with length bigger "
+					       "than size of destination buffer")
 {
   return __glibc_fortify_n (wmemmove, __n, sizeof (wchar_t),
 			    __glibc_objsize0 (__s1),
@@ -38,9 +45,12 @@ __NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n))
 }
 
 #ifdef __USE_GNU
-__fortify_function wchar_t *
-__NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
-		 size_t __n))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wmempcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __s1),
+		 const wchar_t *__restrict __s2, size_t __n))
+     __fortify_clang_warning_only_if_bos0_lt2 (__n, __s1, sizeof (wchar_t),
+					       "wmempcpy called with length bigger "
+					       "than size of destination buffer")
 {
   return __glibc_fortify_n (wmempcpy, __n, sizeof (wchar_t),
 			    __glibc_objsize0 (__s1),
@@ -48,16 +58,21 @@ __NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2,
 }
 #endif
 
-__fortify_function wchar_t *
-__NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wmemset (__fortify_clang_overload_arg (wchar_t *, ,__s), wchar_t __c,
+		size_t __n))
+     __fortify_clang_warning_only_if_bos0_lt2 (__n, __s, sizeof (wchar_t),
+					       "wmemset called with length bigger "
+					       "than size of destination buffer")
 {
   return __glibc_fortify_n (wmemset, __n, sizeof (wchar_t),
 			    __glibc_objsize0 (__s),
 			    __s, __c, __n);
 }
 
-__fortify_function wchar_t *
-__NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wcscpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
+	       const wchar_t *__restrict __src))
 {
   size_t sz = __glibc_objsize (__dest);
   if (sz != (size_t) -1)
@@ -65,8 +80,9 @@ __NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
   return __wcscpy_alias (__dest, __src);
 }
 
-__fortify_function wchar_t *
-__NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wcpcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
+	       const wchar_t *__restrict __src))
 {
   size_t sz = __glibc_objsize (__dest);
   if (sz != (size_t) -1)
@@ -74,26 +90,33 @@ __NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
   return __wcpcpy_alias (__dest, __src);
 }
 
-__fortify_function wchar_t *
-__NTH (wcsncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
-		size_t __n))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wcsncpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
+		const wchar_t *__restrict __src, size_t __n))
+     __fortify_clang_warning_only_if_bos0_lt2 (__n, __dest, sizeof (wchar_t),
+					       "wcsncpy called with length bigger "
+					       "than size of destination buffer")
 {
   return __glibc_fortify_n (wcsncpy, __n, sizeof (wchar_t),
 			    __glibc_objsize (__dest),
 			    __dest, __src, __n);
 }
 
-__fortify_function wchar_t *
-__NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
-		size_t __n))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wcpncpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
+		const wchar_t *__restrict __src, size_t __n))
+     __fortify_clang_warning_only_if_bos0_lt2 (__n, __dest, sizeof (wchar_t),
+					       "wcpncpy called with length bigger "
+					       "than size of destination buffer")
 {
   return __glibc_fortify_n (wcpncpy, __n, sizeof (wchar_t),
 			    __glibc_objsize (__dest),
 			    __dest, __src, __n);
 }
 
-__fortify_function wchar_t *
-__NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wcscat (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
+	       const wchar_t *__restrict __src))
 {
   size_t sz = __glibc_objsize (__dest);
   if (sz != (size_t) -1)
@@ -101,9 +124,9 @@ __NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
   return __wcscat_alias (__dest, __src);
 }
 
-__fortify_function wchar_t *
-__NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
-		size_t __n))
+__fortify_function __attribute_overloadable__ wchar_t *
+__NTH (wcsncat (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
+	       const wchar_t *__restrict __src, size_t __n))
 {
   size_t sz = __glibc_objsize (__dest);
   if (sz != (size_t) -1)
@@ -112,9 +135,12 @@ __NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
 }
 
 #ifdef __USE_MISC
-__fortify_function size_t
-__NTH (wcslcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
-		size_t __n))
+__fortify_function __attribute_overloadable__ size_t
+__NTH (wcslcpy (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
+		const wchar_t *__restrict __src, size_t __n))
+     __fortify_clang_warning_only_if_bos0_lt2 (__n, __dest, sizeof (wchar_t),
+					       "wcslcpy called with length bigger "
+					       "than size of destination buffer")
 {
   if (__glibc_objsize (__dest) != (size_t) -1
       && (!__builtin_constant_p (__n
@@ -125,9 +151,9 @@ __NTH (wcslcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
   return __wcslcpy_alias (__dest, __src, __n);
 }
 
-__fortify_function size_t
-__NTH (wcslcat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
-		size_t __n))
+__fortify_function __attribute_overloadable__ size_t
+__NTH (wcslcat (__fortify_clang_overload_arg (wchar_t *, __restrict, __dest),
+		const wchar_t *__restrict __src, size_t __n))
 {
   if (__glibc_objsize (__dest) != (size_t) -1
       && (!__builtin_constant_p (__n > __glibc_objsize (__dest)
@@ -150,6 +176,23 @@ __NTH (swprintf (wchar_t *__restrict __s, size_t __n,
 			   sz / sizeof (wchar_t), __fmt, __va_arg_pack ());
   return __swprintf_alias (__s, __n, __fmt, __va_arg_pack ());
 }
+#elif __fortify_use_clang
+__fortify_function_error_function __attribute_overloadable__ int
+__NTH (swprintf (__fortify_clang_overload_arg (wchar_t *, __restrict, __s),
+		 size_t __n, const wchar_t *__restrict __fmt, ...))
+{
+  __gnuc_va_list __fortify_ap;
+  __builtin_va_start (__fortify_ap, __fmt);
+  int __r;
+  if (__glibc_objsize (__s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
+    __r = __vswprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
+			   __glibc_objsize (__s) / sizeof (wchar_t),
+			   __fmt, __fortify_ap);
+  else
+    __r = __vswprintf_alias (__s, __n, __fmt, __fortify_ap);
+  __builtin_va_end (__fortify_ap);
+  return __r;
+}
 #elif !defined __cplusplus
 /* XXX We might want to have support in gcc for swprintf.  */
 # define swprintf(s, n, ...) \
@@ -207,34 +250,46 @@ vfwprintf (__FILE *__restrict __stream,
 }
 
 #endif
-__fortify_function __wur wchar_t *
-fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
+__fortify_function __attribute_overloadable__ __wur wchar_t *
+fgetws (__fortify_clang_overload_arg (wchar_t *, __restrict, __s), int __n,
+	__FILE *__restrict __stream)
+     __fortify_clang_warning_only_if_bos_lt2 (__n, __s, sizeof (wchar_t),
+					      "fgetws called with length bigger "
+					      "than size of destination buffer")
 {
   size_t sz = __glibc_objsize (__s);
   if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz))
     return __fgetws_alias (__s, __n, __stream);
+#if !__fortify_use_clang
   if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz))
     return __fgetws_chk_warn (__s, sz / sizeof (wchar_t), __n, __stream);
+#endif
   return __fgetws_chk (__s, sz / sizeof (wchar_t), __n, __stream);
 }
 
 #ifdef __USE_GNU
-__fortify_function __wur wchar_t *
-fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
+__fortify_function __attribute_overloadable__ __wur wchar_t *
+fgetws_unlocked (__fortify_clang_overload_arg (wchar_t *, __restrict, __s),
+		 int __n, __FILE *__restrict __stream)
+     __fortify_clang_warning_only_if_bos_lt2 (__n, __s, sizeof (wchar_t),
+					      "fgetws_unlocked called with length bigger "
+					      "than size of destination buffer")
 {
   size_t sz = __glibc_objsize (__s);
   if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz))
     return __fgetws_unlocked_alias (__s, __n, __stream);
+# if !__fortify_use_clang
   if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz))
     return __fgetws_unlocked_chk_warn (__s, sz / sizeof (wchar_t), __n,
 				       __stream);
+# endif
   return __fgetws_unlocked_chk (__s, sz / sizeof (wchar_t), __n, __stream);
 }
 #endif
 
-__fortify_function __wur size_t
-__NTH (wcrtomb (char *__restrict __s, wchar_t __wchar,
-		mbstate_t *__restrict __ps))
+__fortify_function __attribute_overloadable__ __wur size_t
+__NTH (wcrtomb (__fortify_clang_overload_arg (char *, __restrict, __s),
+		wchar_t __wchar, mbstate_t *__restrict __ps))
 {
   /* We would have to include <limits.h> to get a definition of MB_LEN_MAX.
      But this would only disturb the namespace.  So we define our own
@@ -249,18 +304,26 @@ __NTH (wcrtomb (char *__restrict __s, wchar_t __wchar,
   return __wcrtomb_alias (__s, __wchar, __ps);
 }
 
-__fortify_function size_t
-__NTH (mbsrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
+__fortify_function __attribute_overloadable__ size_t
+__NTH (mbsrtowcs (__fortify_clang_overload_arg (wchar_t *, __restrict, __dst),
+		  const char **__restrict __src,
 		  size_t __len, mbstate_t *__restrict __ps))
+     __fortify_clang_warning_only_if_bos_lt2 (__len, __dst, sizeof (wchar_t),
+					      "mbsrtowcs called with dst buffer "
+					      "smaller than len * sizeof (wchar_t)")
 {
   return __glibc_fortify_n (mbsrtowcs, __len, sizeof (wchar_t),
 			    __glibc_objsize (__dst),
 			    __dst, __src, __len, __ps);
 }
 
-__fortify_function size_t
-__NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
+__fortify_function __attribute_overloadable__ size_t
+__NTH (wcsrtombs (__fortify_clang_overload_arg (char *, __restrict, __dst),
+		  const wchar_t **__restrict __src,
 		  size_t __len, mbstate_t *__restrict __ps))
+     __fortify_clang_warning_only_if_bos_lt (__len, __dst,
+					     "wcsrtombs called with dst buffer "
+					     "smaller than len")
 {
   return __glibc_fortify (wcsrtombs, __len, sizeof (char),
 			  __glibc_objsize (__dst),
@@ -269,18 +332,26 @@ __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
 
 
 #ifdef	__USE_XOPEN2K8
-__fortify_function size_t
-__NTH (mbsnrtowcs (wchar_t *__restrict __dst, const char **__restrict __src,
-		   size_t __nmc, size_t __len, mbstate_t *__restrict __ps))
+__fortify_function __attribute_overloadable__ size_t
+__NTH (mbsnrtowcs (__fortify_clang_overload_arg (wchar_t *, __restrict, __dst),
+		   const char **__restrict __src, size_t __nmc, size_t __len,
+		   mbstate_t *__restrict __ps))
+     __fortify_clang_warning_only_if_bos_lt (sizeof (wchar_t) * __len, __dst,
+					     "mbsnrtowcs called with dst buffer "
+					     "smaller than len * sizeof (wchar_t)")
 {
   return __glibc_fortify_n (mbsnrtowcs, __len, sizeof (wchar_t),
 			    __glibc_objsize (__dst),
 			    __dst, __src, __nmc, __len, __ps);
 }
 
-__fortify_function size_t
-__NTH (wcsnrtombs (char *__restrict __dst, const wchar_t **__restrict __src,
-		   size_t __nwc, size_t __len, mbstate_t *__restrict __ps))
+__fortify_function __attribute_overloadable__ size_t
+__NTH (wcsnrtombs (__fortify_clang_overload_arg (char *, __restrict, __dst),
+		   const wchar_t **__restrict __src, size_t __nwc,
+		   size_t __len, mbstate_t *__restrict __ps))
+     __fortify_clang_warning_only_if_bos_lt (__len, __dst,
+					     "wcsnrtombs called with dst buffer "
+					     "smaller than len")
 {
   return __glibc_fortify (wcsnrtombs, __len, sizeof (char),
 			  __glibc_objsize (__dst),
-- 
2.34.1


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

* [PATCH v2 09/10] debug: Improve fcntl.h fortify warnings with clang
  2024-01-08 20:21 [PATCH v2 00/10] Improve fortify support with clang Adhemerval Zanella
                   ` (7 preceding siblings ...)
  2024-01-08 20:21 ` [PATCH v2 08/10] wcsmbs: " Adhemerval Zanella
@ 2024-01-08 20:21 ` Adhemerval Zanella
  2024-01-08 20:21 ` [PATCH v2 10/10] debug: Improve mqueue.h " Adhemerval Zanella
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Adhemerval Zanella @ 2024-01-08 20:21 UTC (permalink / raw)
  To: libc-alpha

It improves open, open64, openat, and openat64.  The compile and runtime
checks have similar coverage as with GCC.

Checked on aarch64, armhf, x86_64, and i686.
---
 io/bits/fcntl2.h | 92 ++++++++++++++++++++++++++++++++++++++++++++++++
 io/fcntl.h       |  3 +-
 misc/sys/cdefs.h |  9 ++++-
 3 files changed, 101 insertions(+), 3 deletions(-)

diff --git a/io/bits/fcntl2.h b/io/bits/fcntl2.h
index 34f05d793d..e29f842246 100644
--- a/io/bits/fcntl2.h
+++ b/io/bits/fcntl2.h
@@ -32,6 +32,8 @@ extern int __REDIRECT (__open_2, (const char *__path, int __oflag),
 extern int __REDIRECT (__open_alias, (const char *__path, int __oflag, ...),
 		       open64) __nonnull ((1));
 #endif
+
+#ifdef __va_arg_pack_len
 __errordecl (__open_too_many_args,
 	     "open can be called either with 2 or 3 arguments, not more");
 __errordecl (__open_missing_mode,
@@ -58,12 +60,34 @@ open (const char *__path, int __oflag, ...)
 
   return __open_alias (__path, __oflag, __va_arg_pack ());
 }
+#elif __fortify_use_clang
+__fortify_function_error_function __attribute_overloadable__ int
+open (const char *__path, int __oflag, mode_t __mode, ...)
+     __fortify_clang_unavailable ("open can be called either with 2 or 3 arguments, not more");
+
+__fortify_function __attribute_overloadable__ int
+open (__fortify_clang_overload_arg (const char *, ,__path), int __oflag)
+     __fortify_clang_prefer_this_overload
+     __fortify_clang_error (__OPEN_NEEDS_MODE (__oflag),
+			    "open with O_CREAT or O_TMPFILE in second argument needs 3 arguments")
+{
+  return __open_2 (__path, __oflag);
+}
+
+__fortify_function __attribute_overloadable__ int
+open (__fortify_clang_overload_arg (const char *, ,__path), int __oflag,
+      mode_t __mode)
+{
+  return __open_alias (__path, __oflag);
+}
+#endif
 
 
 #ifdef __USE_LARGEFILE64
 extern int __open64_2 (const char *__path, int __oflag) __nonnull ((1));
 extern int __REDIRECT (__open64_alias, (const char *__path, int __oflag,
 					...), open64) __nonnull ((1));
+# ifdef __va_arg_pack_len
 __errordecl (__open64_too_many_args,
 	     "open64 can be called either with 2 or 3 arguments, not more");
 __errordecl (__open64_missing_mode,
@@ -90,6 +114,27 @@ open64 (const char *__path, int __oflag, ...)
 
   return __open64_alias (__path, __oflag, __va_arg_pack ());
 }
+# elif __fortify_use_clang
+__fortify_function_error_function __attribute_overloadable__ int
+open64 (const char *__path, int __oflag, mode_t __mode, ...)
+     __fortify_clang_unavailable ("open64 can be called either with 2 or 3 arguments, not more");
+
+__fortify_function __attribute_overloadable__ int
+open64 (__fortify_clang_overload_arg (const char *, ,__path), int __oflag)
+     __fortify_clang_prefer_this_overload
+     __fortify_clang_error (__OPEN_NEEDS_MODE (__oflag),
+			    "open64 with O_CREAT or O_TMPFILE in second argument needs 3 arguments")
+{
+  return __open64_2 (__path, __oflag);
+}
+
+__fortify_function __attribute_overloadable__ int
+open64 (__fortify_clang_overload_arg (const char *, ,__path), int __oflag,
+	mode_t __mode)
+{
+  return __open64_alias (__path, __oflag);
+}
+# endif
 #endif
 
 
@@ -108,6 +153,8 @@ extern int __REDIRECT (__openat_alias, (int __fd, const char *__path,
 					int __oflag, ...), openat64)
      __nonnull ((2));
 # endif
+
+# ifdef __va_arg_pack_len
 __errordecl (__openat_too_many_args,
 	     "openat can be called either with 3 or 4 arguments, not more");
 __errordecl (__openat_missing_mode,
@@ -134,6 +181,28 @@ openat (int __fd, const char *__path, int __oflag, ...)
 
   return __openat_alias (__fd, __path, __oflag, __va_arg_pack ());
 }
+# elif __fortify_use_clang
+__fortify_function_error_function __attribute_overloadable__ int
+openat (int __fd, const char *__path, int __oflag, mode_t __mode, ...)
+     __fortify_clang_unavailable ("openat can be called either with 3 or 4 arguments, not more");
+
+__fortify_function __attribute_overloadable__ int
+openat (int __fd, __fortify_clang_overload_arg (const char *, ,__path),
+	int __oflag)
+     __fortify_clang_prefer_this_overload
+     __fortify_clang_error (__OPEN_NEEDS_MODE (__oflag),
+			    "openat with O_CREAT or O_TMPFILE in third argument needs 4 arguments")
+{
+  return __openat_2 (__fd, __path, __oflag);
+}
+
+__fortify_function __attribute_overloadable__ int
+openat (int __fd, __fortify_clang_overload_arg (const char *, ,__path),
+	int __oflag, mode_t __mode)
+{
+  return __openat_alias (__fd, __path, __oflag);
+}
+# endif
 
 
 # ifdef __USE_LARGEFILE64
@@ -147,6 +216,7 @@ __errordecl (__openat64_too_many_args,
 __errordecl (__openat64_missing_mode,
 	     "openat64 with O_CREAT or O_TMPFILE in third argument needs 4 arguments");
 
+#  ifdef __va_arg_pack_len
 __fortify_function int
 openat64 (int __fd, const char *__path, int __oflag, ...)
 {
@@ -168,5 +238,27 @@ openat64 (int __fd, const char *__path, int __oflag, ...)
 
   return __openat64_alias (__fd, __path, __oflag, __va_arg_pack ());
 }
+# elif __fortify_use_clang
+__fortify_function_error_function __attribute_overloadable__ int
+openat64 (int __fd, const char *__path, int __oflag, mode_t __mode, ...)
+     __fortify_clang_unavailable ("openat64 can be called either with 3 or 4 arguments, not more");
+
+__fortify_function __attribute_overloadable__ int
+openat64 (int __fd, __fortify_clang_overload_arg (const char *, ,__path),
+	  int __oflag)
+     __fortify_clang_prefer_this_overload
+     __fortify_clang_error (__OPEN_NEEDS_MODE (__oflag),
+			    "openat64 with O_CREAT or O_TMPFILE in third argument needs 4 arguments")
+{
+  return __openat64_2 (__fd, __path, __oflag);
+}
+
+__fortify_function __attribute_overloadable__ int
+openat64 (int __fd, __fortify_clang_overload_arg (const char *, ,__path),
+	  int __oflag, mode_t __mode)
+{
+  return __openat64_alias (__fd, __path, __oflag);
+}
+#  endif
 # endif
 #endif
diff --git a/io/fcntl.h b/io/fcntl.h
index 9cee0b5900..38aa12d7f2 100644
--- a/io/fcntl.h
+++ b/io/fcntl.h
@@ -337,8 +337,7 @@ extern int posix_fallocate64 (int __fd, off64_t __offset, off64_t __len);
 
 
 /* Define some inlines helping to catch common problems.  */
-#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function \
-    && defined __va_arg_pack_len
+#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
 # include <bits/fcntl2.h>
 #endif
 
diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
index 62507044c8..6b03417453 100644
--- a/misc/sys/cdefs.h
+++ b/misc/sys/cdefs.h
@@ -257,7 +257,9 @@
 
 # define __fortify_clang_warning(__c, __msg) \
   __attribute__ ((__diagnose_if__ ((__c), (__msg), "warning")))
-# define __fortify_clang_warning_only_if_bos0_lt(n, buf, complaint) \
+#  define __fortify_clang_error(__c, __msg) \
+  __attribute__ ((__diagnose_if__ ((__c), (__msg), "error")))
+#  define __fortify_clang_warning_only_if_bos0_lt(n, buf, complaint) \
   __attribute__ ((__diagnose_if__ \
 		  (__fortify_clang_bosn_args (__bos0, n, buf, 1, complaint))))
 # define __fortify_clang_warning_only_if_bos0_lt2(n, buf, div, complaint) \
@@ -270,6 +272,11 @@
   __attribute__ ((__diagnose_if__ \
 		  (__fortify_clang_bosn_args (__bos, n, buf, div, complaint))))
 
+#  define __fortify_clang_prefer_this_overload \
+  __attribute__ ((enable_if (1, "")))
+#  define __fortify_clang_unavailable(__msg) \
+  __attribute__ ((unavailable(__msg)))
+
 # if __USE_FORTIFY_LEVEL == 3
 #  define __fortify_clang_overload_arg(__type, __attr, __name) \
   __type __attr const __fortify_clang_pass_dynamic_object_size __name
-- 
2.34.1


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

* [PATCH v2 10/10] debug: Improve mqueue.h fortify warnings with clang
  2024-01-08 20:21 [PATCH v2 00/10] Improve fortify support with clang Adhemerval Zanella
                   ` (8 preceding siblings ...)
  2024-01-08 20:21 ` [PATCH v2 09/10] debug: Improve fcntl.h fortify warnings " Adhemerval Zanella
@ 2024-01-08 20:21 ` Adhemerval Zanella
  2024-01-11 21:53 ` [PATCH v2 00/10] Improve fortify support " Andreas K. Huettel
  2024-02-05 13:26 ` Adhemerval Zanella Netto
  11 siblings, 0 replies; 13+ messages in thread
From: Adhemerval Zanella @ 2024-01-08 20:21 UTC (permalink / raw)
  To: libc-alpha

It improve mq_open.  The compile and runtime checks have similar
coverage as with GCC.

Checked on aarch64, armhf, x86_64, and i686.
---
 rt/bits/mqueue2.h | 29 +++++++++++++++++++++++++++++
 rt/mqueue.h       |  3 +--
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/rt/bits/mqueue2.h b/rt/bits/mqueue2.h
index 0f9d67966f..d6d2d9012d 100644
--- a/rt/bits/mqueue2.h
+++ b/rt/bits/mqueue2.h
@@ -29,6 +29,8 @@ extern mqd_t __mq_open_2 (const char *__name, int __oflag)
 extern mqd_t __REDIRECT_NTH (__mq_open_alias, (const char *__name,
 					       int __oflag, ...), mq_open)
      __nonnull ((1));
+
+#ifdef __va_arg_pack_len
 __errordecl (__mq_open_wrong_number_of_args,
 	     "mq_open can be called either with 2 or 4 arguments");
 __errordecl (__mq_open_missing_mode_and_attr,
@@ -55,3 +57,30 @@ __NTH (mq_open (const char *__name, int __oflag, ...))
 
   return __mq_open_alias (__name, __oflag, __va_arg_pack ());
 }
+#elif __fortify_use_clang
+__fortify_function_error_function __attribute_overloadable__ mqd_t
+__NTH (mq_open (const char *__name, int __oflag, mode_t mode))
+     __fortify_clang_unavailable ("mq_open can be called either with 2 or 4 arguments");
+
+__fortify_function_error_function __attribute_overloadable__ mqd_t
+__NTH (mq_open (const char *__name, int __oflag, mode_t mode,
+		struct mq_attr *attr, ...))
+     __fortify_clang_unavailable ("mq_open can be called either with 2 or 4 arguments");
+
+__fortify_function __attribute_overloadable__ mqd_t
+__NTH (mq_open (__fortify_clang_overload_arg (const char *, ,__name),
+		int __oflag))
+     __fortify_clang_prefer_this_overload
+     __fortify_clang_error ((__oflag & O_CREAT),
+			     "mq_open with O_CREAT in second argument needs 4 arguments")
+{
+  return __mq_open_alias (__name, __oflag);
+}
+
+__fortify_function __attribute_overloadable__ mqd_t
+__NTH (mq_open (__fortify_clang_overload_arg (const char *, ,__name),
+		int __oflag, int __mode, struct mq_attr *__attr))
+{
+  return __mq_open_alias (__name, __oflag, __mode, __attr);
+}
+#endif
diff --git a/rt/mqueue.h b/rt/mqueue.h
index 787cc36df2..d39334ba16 100644
--- a/rt/mqueue.h
+++ b/rt/mqueue.h
@@ -110,8 +110,7 @@ extern int __REDIRECT (mq_timedsend, (mqd_t __mqdes,
 #endif
 
 /* Define some inlines helping to catch common problems.  */
-#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function \
-    && defined __va_arg_pack_len
+#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
 # include <bits/mqueue2.h>
 #endif
 
-- 
2.34.1


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

* Re: [PATCH v2 00/10] Improve fortify support with clang
  2024-01-08 20:21 [PATCH v2 00/10] Improve fortify support with clang Adhemerval Zanella
                   ` (9 preceding siblings ...)
  2024-01-08 20:21 ` [PATCH v2 10/10] debug: Improve mqueue.h " Adhemerval Zanella
@ 2024-01-11 21:53 ` Andreas K. Huettel
  2024-02-05 13:26 ` Adhemerval Zanella Netto
  11 siblings, 0 replies; 13+ messages in thread
From: Andreas K. Huettel @ 2024-01-11 21:53 UTC (permalink / raw)
  To: libc-alpha; +Cc: Adhemerval Zanella

[-- Attachment #1: Type: text/plain, Size: 382 bytes --]

Am Montag, 8. Januar 2024, 21:21:39 CET schrieb Adhemerval Zanella:
> When using clang, the fortify wrappers show less coverage on both
> compile and runtime. For instance, a snippet from tst-fortify.c:
> 

This looks like post-release material to me.

-- 
Andreas K. Hüttel
dilfridge@gentoo.org
Gentoo Linux developer
(council, toolchain, base-system, perl, libreoffice)

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 981 bytes --]

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

* Re: [PATCH v2 00/10] Improve fortify support with clang
  2024-01-08 20:21 [PATCH v2 00/10] Improve fortify support with clang Adhemerval Zanella
                   ` (10 preceding siblings ...)
  2024-01-11 21:53 ` [PATCH v2 00/10] Improve fortify support " Andreas K. Huettel
@ 2024-02-05 13:26 ` Adhemerval Zanella Netto
  11 siblings, 0 replies; 13+ messages in thread
From: Adhemerval Zanella Netto @ 2024-02-05 13:26 UTC (permalink / raw)
  To: libc-alpha

Ping.

On 08/01/24 17:21, Adhemerval Zanella wrote:
> When using clang, the fortify wrappers show less coverage on both
> compile and runtime. For instance, a snippet from tst-fortify.c:
> 
>   $ cat t.c
>   #include <stdio.h>
>   #include <string.h>
>   
>   const char *str1 = "JIHGFEDCBA";
>   
>   int main (int argc, char *argv[])
>   {
>   #define O 0
>     struct A { char buf1[9]; char buf2[1]; } a;
>     strcpy (a.buf1 + (O + 4), str1 + 5);
>   
>     return 0;
>   }
>   $ gcc -O2 t.c  -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=2 -o t
>   $ ./t
>   *** buffer overflow detected ***: terminated
>   Aborted (core dumped)
>   $ clang  -O2 t.c  -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=2 -o t
>   $ ./t
>   $
> 
> Although clang does support __builtin___strcpy_chk (which correctly
> lowers to __strcpy_chk), the __builtin_object_size passed as third
> the argument is not fully correct and thus limits the possible runtime
> checks.
> 
> This limitation was already being raised some years ago [1], but the
> work has been staled.  However, a similar patch has been used for
> ChromeOS for some time [2].  Bionic libc also uses a similar approach to
> enable fortified wrappers.
> 
> Improve its support with clang, requires defining the fortified wrapper
> differently. For instance, the read wrapper is currently expanded as:
> 
>   extern __inline
>   __attribute__((__always_inline__))
>   __attribute__((__artificial__))
>   __attribute__((__warn_unused_result__))
>   ssize_t read (int __fd, void *__buf, size_t __nbytes)
>   {
>      return __glibc_safe_or_unknown_len (__nbytes,
>                                          sizeof (char),
>                                          __glibc_objsize0 (__buf))
>             ? __read_alias (__fd, __buf, __nbytes)
>             : __glibc_unsafe_len (__nbytes,
>                                   sizeof (char),
>                                   __glibc_objsize0 (__buf))
>               ? __read_chk_warn (__fd,
>                                  __buf,
>                                  __nbytes,
>                                  __builtin_object_size (__buf, 0))
>               : __read_chk (__fd,
>                             __buf,
>                             __nbytes,
>                             __builtin_object_size (__buf, 0));
>   }
> 
> The wrapper relies on __builtin_object_size call lowers to a constant at
> Compile time and many other operations in the wrapper depend on
> having a single, known value for parameters.   Because this is
> impossible to have for function parameters, the wrapper depends heavily
> on inlining to work and While this is an entirely viable approach on
> GCC is not fully reliable on clang.  This is because by the time llvm
> gets to inlining and optimizing, there is a minimal reliable source and
> type-level information available (more information on a more deep
> explanation on how to fortify wrapper works on clang [4]).
> 
> To allow the wrapper to work reliably and with the same functionality as
> with GCC, clang requires a different approach:
> 
>   * __attribute__((diagnose_if(c, “str”, “warning”))) which is a
>   * function
>     level attribute; if the compiler can determine that 'c' is true at
>     compile-time, it will emit a warning with the text 'str1'.  If it
>     would be better to emit an error, the wrapper can use "error"
>     instead of "warning".
> 
>   * __attribute__((overloadable)) which is also a function-level
>     attribute; and it allows C++-style overloading to occur on C
> functions.
> 
>   * __attribute__((pass_object_size(n))) which is a parameter-level
>     attribute; and it makes the compiler evaluate
>     __builtin_object_size(param, n) at each call site of the function
>     that has the parameter and passes it in as a hidden parameter.
> 
>     This attribute has two side effects that are key to how FORTIFY
>     works:
> 
>     1. It can overload solely on pass_object_size (e.g. there are two
>        overloads of foo in
> 
>          void foo(char * __attribute__((pass_object_size(0))) c);
>          void foo(char *);
> 
>       (The one with pass_object_size attribute has preceded the
>       default one).
> 
>     2. A function with at least one pass_object_size parameter can never
>        have its address taken (and overload resolution respects this).
> 
> Thus the read wrapper can be implemented as follows, without
> hindering any fortify coverage compile and runtime: 
> 
> Thus the read wrapper can be implemented as follows, without
> hindering any fortify coverage compile and runtime:
> 
>   extern __inline
>   __attribute__((__always_inline__))
>   __attribute__((__artificial__))
>   __attribute__((__overloadable__))
>   __attribute__((__warn_unused_result__))
>   ssize_t read (int __fd,
>                 void *const __attribute__((pass_object_size (0))) __buf,
>                 size_t __nbytes)
>      __attribute__((__diagnose_if__ ((((__builtin_object_size (__buf,
> 0)) != -1ULL
>                                         && (__nbytes) >
> (__builtin_object_size (__buf, 0)) / (1))),
>                                      "read called with bigger length
> than the size of the destination buffer",
>                                      "warning")))
>   {
>     return (__builtin_object_size (__buf, 0) == (size_t) -1)
>       ? __read_alias (__fd,
>                       __buf,
>                       __nbytes)
>       : __read_chk (__fd,
>                     __buf,
>                     __nbytes,
>                     __builtin_object_size (__buf, 0));
>   }
> 
> To avoid changing the current semantic for GCC, a set of macros is
> defined to enable the clang required attributes, along with some changes
> on internal macros to avoid the need to issue the symbol_chk symbols
> (which are done through the __diagnose_if__ attribute for clang).
> The read wrapper can be simplified as:
> 
>   __fortify_function __attribute_overloadable__ __wur
>   ssize_t read (int __fd,
>                 __fortify_clang_overload_arg0 (void *, ,__buf),
>                 size_t __nbytes)
>        __fortify_clang_warning_only_if_bos0_lt (__nbytes, __buf,
>                                                 "read called with bigger
> length than "
>                                                 "size of the destination
> buffer")
> 
>   {
>     return __glibc_fortify (read, __nbytes, sizeof (char),
>                             __glibc_objsize0 (__buf),
>                             __fd, __buf, __nbytes);
>   }
> 
> There is no expected semantic or code change when using GCC.
> 
> Also, clang does not support __va_arg_pack, so variadic functions are
> expanded to call va_arg implementations.  The error function must not
> have bodies (address takes are expanded to nonfortified calls), and
> with the __fortify_function compiler might still create a body with the
> C++ mangling name (due to the overload attribute).  In this case, the
> function is defined with __fortify_function_error_function macro
> instead.
> 
> To fully test it, I used my clang branch [4] which allowed me to fully
> build all fortify tests with clang. With this patchset, there is no
> regressions anymore.
> 
> [1] https://sourceware.org/legacy-ml/libc-alpha/2017-09/msg00434.html
> [2] https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/refs/heads/main/sys-libs/glibc/files/local/glibc-2.35/0006-glibc-add-clang-style-FORTIFY.patch
> [3] https://docs.google.com/document/d/1DFfZDICTbL7RqS74wJVIJ-YnjQOj1SaoqfhbgddFYSM/edit
> [4] https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/azanella/clang
> 
> Changes from v1:
> - Use implementation-namespace identifiers pass_object_size and
>   pass_dynamic_object_size.
> - Simplify the clang macros and enable it iff for clang 5.0
>   (that supports __diagnose_if__).
> 
> Adhemerval Zanella (10):
>   cdefs.h: Add clang fortify directives
>   libio: Improve fortify with clang
>   string: Improve fortify with clang
>   stdlib: Improve fortify with clang
>   unistd: Improve fortify with clang
>   socket: Improve fortify with clang
>   syslog: Improve fortify with clang
>   wcsmbs: Improve fortify with clang
>   debug: Improve fcntl.h fortify warnings with clang
>   debug: Improve mqueue.h fortify warnings with clang
> 
>  io/bits/fcntl2.h               |  92 ++++++++++++++++++
>  io/bits/poll2.h                |  29 ++++--
>  io/fcntl.h                     |   3 +-
>  libio/bits/stdio2.h            | 173 +++++++++++++++++++++++++++++----
>  misc/bits/syslog.h             |  14 ++-
>  misc/sys/cdefs.h               | 158 +++++++++++++++++++++++++++++-
>  posix/bits/unistd.h            | 110 +++++++++++++++------
>  rt/bits/mqueue2.h              |  29 ++++++
>  rt/mqueue.h                    |   3 +-
>  socket/bits/socket2.h          |  20 +++-
>  stdlib/bits/stdlib.h           |  40 +++++---
>  string/bits/string_fortified.h |  57 ++++++-----
>  wcsmbs/bits/wchar2.h           | 167 ++++++++++++++++++++++---------
>  13 files changed, 746 insertions(+), 149 deletions(-)
> 

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

end of thread, other threads:[~2024-02-05 13:26 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-08 20:21 [PATCH v2 00/10] Improve fortify support with clang Adhemerval Zanella
2024-01-08 20:21 ` [PATCH v2 01/10] cdefs.h: Add clang fortify directives Adhemerval Zanella
2024-01-08 20:21 ` [PATCH v2 02/10] libio: Improve fortify with clang Adhemerval Zanella
2024-01-08 20:21 ` [PATCH v2 03/10] string: " Adhemerval Zanella
2024-01-08 20:21 ` [PATCH v2 04/10] stdlib: " Adhemerval Zanella
2024-01-08 20:21 ` [PATCH v2 05/10] unistd: " Adhemerval Zanella
2024-01-08 20:21 ` [PATCH v2 06/10] socket: " Adhemerval Zanella
2024-01-08 20:21 ` [PATCH v2 07/10] syslog: " Adhemerval Zanella
2024-01-08 20:21 ` [PATCH v2 08/10] wcsmbs: " Adhemerval Zanella
2024-01-08 20:21 ` [PATCH v2 09/10] debug: Improve fcntl.h fortify warnings " Adhemerval Zanella
2024-01-08 20:21 ` [PATCH v2 10/10] debug: Improve mqueue.h " Adhemerval Zanella
2024-01-11 21:53 ` [PATCH v2 00/10] Improve fortify support " Andreas K. Huettel
2024-02-05 13:26 ` Adhemerval Zanella Netto

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 read-only IMAP folder(s) and NNTP newsgroup(s).