public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 00/15] Improve fortify support with clang
@ 2023-12-21 18:59 Adhemerval Zanella
  2023-12-21 18:59 ` [PATCH 01/15] debug: Adapt fortify tests to libsupport Adhemerval Zanella
                   ` (14 more replies)
  0 siblings, 15 replies; 26+ messages in thread
From: Adhemerval Zanella @ 2023-12-21 18:59 UTC (permalink / raw)
  To: libc-alpha, Siddhesh Poyarekar

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

Adhemerval Zanella (15):
  debug: Adapt fortify tests to libsupport
  debug: Increase tst-fortify checks for compiler without __va_arg_pack
    support
  debug: Add fortify dprintf tests
  debug: Add fortify syslog tests
  debug: Add fortify wprintf tests
  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

 debug/Makefile                 |   7 ++
 debug/test-stpcpy_chk.c        |   2 +-
 debug/test-strcpy_chk.c        |   2 +-
 debug/tst-fortify-syslog.c     | 128 +++++++++++++++++++++
 debug/tst-fortify-wide.c       | 104 +++++++++++++++++
 debug/tst-fortify.c            |  83 +++++++++-----
 debug/tst-longjmp_chk.c        |   8 +-
 debug/tst-longjmp_chk2.c       |   6 +-
 debug/tst-longjmp_chk3.c       |   6 +-
 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               | 201 ++++++++++++++++++++++++++++-----
 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 +++++++++++++++++++--------
 22 files changed, 1064 insertions(+), 220 deletions(-)
 create mode 100644 debug/tst-fortify-syslog.c
 create mode 100644 debug/tst-fortify-wide.c

-- 
2.34.1


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

* [PATCH 01/15] debug: Adapt fortify tests to libsupport
  2023-12-21 18:59 [PATCH 00/15] Improve fortify support with clang Adhemerval Zanella
@ 2023-12-21 18:59 ` Adhemerval Zanella
  2023-12-21 19:54   ` Siddhesh Poyarekar
  2023-12-21 18:59 ` [PATCH 02/15] debug: Increase tst-fortify checks for compiler without __va_arg_pack support Adhemerval Zanella
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 26+ messages in thread
From: Adhemerval Zanella @ 2023-12-21 18:59 UTC (permalink / raw)
  To: libc-alpha, Siddhesh Poyarekar

Checked on aarch64, armhf, x86_64, and i686.
---
 debug/test-stpcpy_chk.c  |  2 +-
 debug/test-strcpy_chk.c  |  2 +-
 debug/tst-fortify.c      | 55 +++++++++++++++++++++-------------------
 debug/tst-longjmp_chk.c  |  8 +++---
 debug/tst-longjmp_chk2.c |  6 ++---
 debug/tst-longjmp_chk3.c |  6 ++---
 6 files changed, 39 insertions(+), 40 deletions(-)

diff --git a/debug/test-stpcpy_chk.c b/debug/test-stpcpy_chk.c
index 938f3c0ceb..0b9fed49cc 100644
--- a/debug/test-stpcpy_chk.c
+++ b/debug/test-stpcpy_chk.c
@@ -19,7 +19,7 @@
 #define STRCPY_RESULT(dst, len) ((dst) + (len))
 #define TEST_MAIN
 #define TEST_NAME "stpcpy_chk"
-#include "../string/test-string.h"
+#include <string/test-string.h>
 
 extern void __attribute__ ((noreturn)) __chk_fail (void);
 char *simple_stpcpy_chk (char *, const char *, size_t);
diff --git a/debug/test-strcpy_chk.c b/debug/test-strcpy_chk.c
index 792e789e1e..684e0bdd9b 100644
--- a/debug/test-strcpy_chk.c
+++ b/debug/test-strcpy_chk.c
@@ -20,7 +20,7 @@
 # define STRCPY_RESULT(dst, len) dst
 # define TEST_MAIN
 # define TEST_NAME "strcpy_chk"
-# include "../string/test-string.h"
+# include <string/test-string.h>
 
 /* This test case implicitly tests the availability of the __chk_fail
    symbol, which is part of the public ABI and may be used
diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c
index 3744aadad4..20e926751a 100644
--- a/debug/tst-fortify.c
+++ b/debug/tst-fortify.c
@@ -23,6 +23,7 @@
 
 #include <assert.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <locale.h>
 #include <obstack.h>
 #include <setjmp.h>
@@ -36,6 +37,10 @@
 #include <sys/select.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <paths.h>
+
+#include <support/temp_file.h>
+#include <support/support.h>
 
 #ifndef _GNU_SOURCE
 # define MEMPCPY memcpy
@@ -52,15 +57,10 @@
 #define obstack_chunk_alloc malloc
 #define obstack_chunk_free free
 
-char *temp_filename;
-static void do_prepare (void);
-static int do_test (void);
-#define PREPARE(argc, argv) do_prepare ()
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+static char *temp_filename;
 
 static void
-do_prepare (void)
+do_prepare (int argc, char *argv[])
 {
   int temp_fd = create_temp_file ("tst-chk1.", &temp_filename);
   if (temp_fd == -1)
@@ -77,10 +77,11 @@ do_prepare (void)
       exit (1);
     }
 }
+#define PREPARE do_prepare
 
-volatile int chk_fail_ok;
-volatile int ret;
-jmp_buf chk_fail_buf;
+static volatile int chk_fail_ok;
+static volatile int ret;
+static jmp_buf chk_fail_buf;
 
 static void
 handler (int sig)
@@ -102,22 +103,22 @@ wchar_t wbuf[10];
 #define buf_size sizeof (buf)
 #endif
 
-volatile size_t l0;
-volatile char *p;
-volatile wchar_t *wp;
-const char *str1 = "JIHGFEDCBA";
-const char *str2 = "F";
-const char *str3 = "%s%n%s%n";
-const char *str4 = "Hello, ";
-const char *str5 = "World!\n";
-const wchar_t *wstr1 = L"JIHGFEDCBA";
-const wchar_t *wstr2 = L"F";
-const wchar_t *wstr3 = L"%s%n%s%n";
-const wchar_t *wstr4 = L"Hello, ";
-const wchar_t *wstr5 = L"World!\n";
-char buf2[10] = "%s";
-int num1 = 67;
-int num2 = 987654;
+static volatile size_t l0;
+static volatile char *p;
+static volatile wchar_t *wp;
+static const char *str1 = "JIHGFEDCBA";
+static const char *str2 = "F";
+static const char *str3 = "%s%n%s%n";
+static const char *str4 = "Hello, ";
+static const char *str5 = "World!\n";
+static const wchar_t *wstr1 = L"JIHGFEDCBA";
+static const wchar_t *wstr2 = L"F";
+static const wchar_t *wstr3 = L"%s%n%s%n";
+static const wchar_t *wstr4 = L"Hello, ";
+static const wchar_t *wstr5 = L"World!\n";
+static char buf2[10] = "%s";
+static int num1 = 67;
+static int num2 = 987654;
 
 #define FAIL() \
   do { printf ("Failure on line %d\n", __LINE__); ret = 1; } while (0)
@@ -1815,3 +1816,5 @@ do_test (void)
 
   return ret;
 }
+
+#include <support/test-driver.c>
diff --git a/debug/tst-longjmp_chk.c b/debug/tst-longjmp_chk.c
index e4e93d2a36..37f858606b 100644
--- a/debug/tst-longjmp_chk.c
+++ b/debug/tst-longjmp_chk.c
@@ -10,11 +10,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 
-
-static int do_test(void);
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
-
+#include <support/support.h>
 
 static jmp_buf b;
 
@@ -76,3 +72,5 @@ do_test (void)
   puts ("second longjmp returned");
   return 1;
 }
+
+#include <support/test-driver.c>
diff --git a/debug/tst-longjmp_chk2.c b/debug/tst-longjmp_chk2.c
index 1810ab44d7..7e1ee3edc5 100644
--- a/debug/tst-longjmp_chk2.c
+++ b/debug/tst-longjmp_chk2.c
@@ -10,9 +10,7 @@
 #include <sys/resource.h>
 #include <unistd.h>
 
-static int do_test (void);
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/support.h>
 
 static jmp_buf mainloop;
 static sigset_t mainsigset;
@@ -126,3 +124,5 @@ do_test (void)
 
   return 0;
 }
+
+#include <support/test-driver.c>
diff --git a/debug/tst-longjmp_chk3.c b/debug/tst-longjmp_chk3.c
index f1e576ad5b..3050806c44 100644
--- a/debug/tst-longjmp_chk3.c
+++ b/debug/tst-longjmp_chk3.c
@@ -20,10 +20,6 @@
 #include <signal.h>
 #include <string.h>
 
-static int do_test (void);
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
-
 static char buf[SIGSTKSZ * 4];
 static jmp_buf jb;
 
@@ -83,3 +79,5 @@ do_test (void)
   puts ("longjmp returned and shouldn't");
   return 1;
 }
+
+#include <support/test-driver.c>
-- 
2.34.1


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

* [PATCH 02/15] debug: Increase tst-fortify checks for compiler without __va_arg_pack support
  2023-12-21 18:59 [PATCH 00/15] Improve fortify support with clang Adhemerval Zanella
  2023-12-21 18:59 ` [PATCH 01/15] debug: Adapt fortify tests to libsupport Adhemerval Zanella
@ 2023-12-21 18:59 ` Adhemerval Zanella
  2023-12-21 20:02   ` Siddhesh Poyarekar
  2023-12-21 18:59 ` [PATCH 03/15] debug: Add fortify dprintf tests Adhemerval Zanella
                   ` (12 subsequent siblings)
  14 siblings, 1 reply; 26+ messages in thread
From: Adhemerval Zanella @ 2023-12-21 18:59 UTC (permalink / raw)
  To: libc-alpha, Siddhesh Poyarekar

The fortify wrappers for varargs functions already add fallbacks to
builtins calls if __va_arg_pack is not supported.

Checked on aarch64, armhf, x86_64, and i686.
---
 debug/tst-fortify.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c
index 20e926751a..5cd9d22feb 100644
--- a/debug/tst-fortify.c
+++ b/debug/tst-fortify.c
@@ -130,7 +130,7 @@ static int num2 = 987654;
       chk_fail_ok = 0;				\
       FAIL ();					\
     }
-#if __USE_FORTIFY_LEVEL >= 2 && (!defined __cplusplus || defined __va_arg_pack)
+#if __USE_FORTIFY_LEVEL >= 2
 # define CHK_FAIL2_START CHK_FAIL_START
 # define CHK_FAIL2_END CHK_FAIL_END
 #else
@@ -419,7 +419,6 @@ do_test (void)
   stpncpy (buf + 6, "cd", l0 + 5);
   CHK_FAIL_END
 
-# if !defined __cplusplus || defined __va_arg_pack
   CHK_FAIL_START
   sprintf (buf + 8, "%d", num1);
   CHK_FAIL_END
@@ -439,7 +438,6 @@ do_test (void)
   CHK_FAIL_START
   swprintf (wbuf + 8, l0 + 3, L"%d", num1);
   CHK_FAIL_END
-# endif
 
   memcpy (buf, str1 + 2, 9);
   CHK_FAIL_START
@@ -550,7 +548,6 @@ do_test (void)
       FAIL ();
   }
 
-# if !defined __cplusplus || defined __va_arg_pack
   CHK_FAIL_START
   sprintf (a.buf1 + (O + 7), "%d", num1);
   CHK_FAIL_END
@@ -562,7 +559,6 @@ do_test (void)
   CHK_FAIL_START
   snprintf (a.buf1 + (O + 7), l0 + 3, "%d", num2);
   CHK_FAIL_END
-# endif
 
   memcpy (a.buf1, str1 + (3 - O), 8 + O);
   CHK_FAIL_START
-- 
2.34.1


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

* [PATCH 03/15] debug: Add fortify dprintf tests
  2023-12-21 18:59 [PATCH 00/15] Improve fortify support with clang Adhemerval Zanella
  2023-12-21 18:59 ` [PATCH 01/15] debug: Adapt fortify tests to libsupport Adhemerval Zanella
  2023-12-21 18:59 ` [PATCH 02/15] debug: Increase tst-fortify checks for compiler without __va_arg_pack support Adhemerval Zanella
@ 2023-12-21 18:59 ` Adhemerval Zanella
  2023-12-21 20:03   ` Siddhesh Poyarekar
  2023-12-21 18:59 ` [PATCH 04/15] debug: Add fortify syslog tests Adhemerval Zanella
                   ` (11 subsequent siblings)
  14 siblings, 1 reply; 26+ messages in thread
From: Adhemerval Zanella @ 2023-12-21 18:59 UTC (permalink / raw)
  To: libc-alpha, Siddhesh Poyarekar

Similar to other printf-like ones.

Checked on aarch64, armhf, x86_64, and i686.
---
 debug/tst-fortify.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c
index 5cd9d22feb..888eae25ad 100644
--- a/debug/tst-fortify.c
+++ b/debug/tst-fortify.c
@@ -59,6 +59,8 @@
 
 static char *temp_filename;
 
+static int temp_fd_dprintf;
+
 static void
 do_prepare (int argc, char *argv[])
 {
@@ -76,6 +78,13 @@ do_prepare (int argc, char *argv[])
       unlink (temp_filename);
       exit (1);
     }
+
+  temp_fd_dprintf = create_temp_file ("tst-chk2.", NULL);
+  if (temp_fd_dprintf == -1)
+    {
+      printf ("cannot create temporary file: %m\n");
+      exit (1);
+    }
 }
 #define PREPARE do_prepare
 
@@ -901,6 +910,10 @@ do_test (void)
       || n1 != 1 || n2 != 2)
     FAIL ();
 
+  if (dprintf (temp_fd_dprintf, "%s%n%s%n", str2, &n1, str2, &n2) != 2
+      || n1 != 1 || n2 != 2)
+    FAIL ();
+
   strcpy (buf2 + 2, "%n%s%n");
   /* When the format string is writable and contains %n,
      with -D_FORTIFY_SOURCE=2 it causes __chk_fail.  */
@@ -914,6 +927,11 @@ do_test (void)
     FAIL ();
   CHK_FAIL2_END
 
+  CHK_FAIL2_START
+  if (dprintf (temp_fd_dprintf, buf2, str2, &n1, str2, &n1) != 2)
+    FAIL ();
+  CHK_FAIL2_END
+
   /* But if there is no %n, even writable format string
      should work.  */
   buf2[6] = '\0';
@@ -1263,6 +1281,10 @@ do_test (void)
   snprintf (buf, buf_size, "%3$d\n", 1, 2, 3, 4);
   CHK_FAIL2_END
 
+  CHK_FAIL2_START
+  dprintf (temp_fd_dprintf, "%3$d\n", 1, 2, 3, 4);
+  CHK_FAIL2_END
+
   int sp[2];
   if (socketpair (PF_UNIX, SOCK_STREAM, 0, sp))
     FAIL ();
-- 
2.34.1


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

* [PATCH 04/15] debug: Add fortify syslog tests
  2023-12-21 18:59 [PATCH 00/15] Improve fortify support with clang Adhemerval Zanella
                   ` (2 preceding siblings ...)
  2023-12-21 18:59 ` [PATCH 03/15] debug: Add fortify dprintf tests Adhemerval Zanella
@ 2023-12-21 18:59 ` Adhemerval Zanella
  2023-12-21 20:06   ` Siddhesh Poyarekar
  2023-12-21 18:59 ` [PATCH 05/15] debug: Add fortify wprintf tests Adhemerval Zanella
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 26+ messages in thread
From: Adhemerval Zanella @ 2023-12-21 18:59 UTC (permalink / raw)
  To: libc-alpha, Siddhesh Poyarekar

It requires to be in a container tests to avoid logging bogus
information on the system.  The syslog also requires to be checked in
a different process because the internal printf call will abort with
the internal syslog lock taken (which makes subsequent syslog calls
deadlock).

Checked on aarch64, armhf, x86_64, and i686.
---
 debug/Makefile             |   5 ++
 debug/tst-fortify-syslog.c | 128 +++++++++++++++++++++++++++++++++++++
 2 files changed, 133 insertions(+)
 create mode 100644 debug/tst-fortify-syslog.c

diff --git a/debug/Makefile b/debug/Makefile
index c49e5d86ec..fdc250e209 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -179,6 +179,7 @@ CPPFLAGS-tst-longjmp_chk3.c += $(no-fortify-source),-D_FORTIFY_SOURCE=1
 CPPFLAGS-tst-realpath-chk.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
 CPPFLAGS-tst-chk-cancel.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
 CFLAGS-tst-sprintf-fortify-rdonly.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
+CFLAGS-tst-fortify-syslog.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
 
 # _FORTIFY_SOURCE tests.
 # Auto-generate tests for _FORTIFY_SOURCE for different levels, compilers and
@@ -293,6 +294,10 @@ tests-time64 += \
   $(tests-all-time64-chk) \
   # tests-time64
 
+tests-container += \
+  tst-fortify-syslog \
+  # tests-container
+
 ifeq ($(have-ssp),yes)
 tests += tst-ssp-1
 endif
diff --git a/debug/tst-fortify-syslog.c b/debug/tst-fortify-syslog.c
new file mode 100644
index 0000000000..26a93d9be8
--- /dev/null
+++ b/debug/tst-fortify-syslog.c
@@ -0,0 +1,128 @@
+/* Fortify tests for syslog interface.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   Copyright The GNU Toolchain Authors.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdarg.h>
+#include <setjmp.h>
+#include <syslog.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <support/check.h>
+#include <support/support.h>
+#include <support/capture_subprocess.h>
+
+static const char *str2 = "F";
+static char buf2[10] = "%s";
+
+static volatile int chk_fail_ok;
+static jmp_buf chk_fail_buf;
+
+static void
+handler (int sig)
+{
+  if (chk_fail_ok)
+    {
+      chk_fail_ok = 0;
+      longjmp (chk_fail_buf, 1);
+    }
+  else
+    _exit (127);
+}
+
+#define FAIL()						\
+  do {							\
+      printf ("Failure on line %d\n", __LINE__);	\
+      support_record_failure ();			\
+  } while (0)
+#define CHK_FAIL_START					\
+  chk_fail_ok = 1;					\
+  if (! setjmp (chk_fail_buf))				\
+    {
+#define CHK_FAIL_END					\
+      chk_fail_ok = 0;					\
+      FAIL ();						\
+    }
+
+static void
+call_vsyslog (int priority, const char *format, ...)
+{
+  va_list va;
+  va_start (va, format);
+  vsyslog (priority, format, va);
+  va_end (va);
+}
+
+static void
+run_syslog_chk (void *closure)
+{
+  int n1;
+  CHK_FAIL_START
+  syslog (LOG_USER | LOG_DEBUG, buf2, str2, &n1, str2, &n1);
+  CHK_FAIL_END
+}
+
+static void
+run_vsyslog_chk (void *closure)
+{
+  int n1;
+  CHK_FAIL_START
+  call_vsyslog (LOG_USER | LOG_DEBUG, buf2, str2, &n1, str2, &n1);
+  CHK_FAIL_END
+}
+
+static int
+do_test (void)
+{
+  set_fortify_handler (handler);
+
+  int n1, n2;
+
+  n1 = n2 = 0;
+  syslog (LOG_USER | LOG_DEBUG, "%s%n%s%n", str2, &n1, str2, &n2);
+  TEST_COMPARE (n1, 1);
+  TEST_COMPARE (n2, 2);
+
+  n1 = n2 = 0;
+  call_vsyslog (LOG_USER | LOG_DEBUG, "%s%n%s%n", str2, &n1, str2, &n2);
+  TEST_COMPARE (n1, 1);
+  TEST_COMPARE (n2, 2);
+
+  strcpy (buf2 + 2, "%n%s%n");
+
+  /* The wrapper tests need to be in a subprocess because the abort called by
+     printf does not unlock the internal syslog lock.  */
+  {
+    struct support_capture_subprocess result
+      = support_capture_subprocess (run_syslog_chk, NULL);
+    support_capture_subprocess_check (&result, "syslog", 0, sc_allow_stderr);
+    support_capture_subprocess_free (&result);
+  }
+
+  {
+    struct support_capture_subprocess result
+      = support_capture_subprocess (run_vsyslog_chk, NULL);
+    support_capture_subprocess_check (&result, "syslog", 0, sc_allow_stderr);
+    support_capture_subprocess_free (&result);
+  }
+
+  return 0;
+}
+
+#include <support/test-driver.c>
-- 
2.34.1


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

* [PATCH 05/15] debug: Add fortify wprintf tests
  2023-12-21 18:59 [PATCH 00/15] Improve fortify support with clang Adhemerval Zanella
                   ` (3 preceding siblings ...)
  2023-12-21 18:59 ` [PATCH 04/15] debug: Add fortify syslog tests Adhemerval Zanella
@ 2023-12-21 18:59 ` Adhemerval Zanella
  2023-12-21 20:08   ` Siddhesh Poyarekar
  2023-12-21 18:59 ` [PATCH 06/15] cdefs.h: Add clang fortify directives Adhemerval Zanella
                   ` (9 subsequent siblings)
  14 siblings, 1 reply; 26+ messages in thread
From: Adhemerval Zanella @ 2023-12-21 18:59 UTC (permalink / raw)
  To: libc-alpha, Siddhesh Poyarekar

Similar to other printf-like ones.  It requires to be in a different
process so we can change the orientation of stdout.

Checked on aarch64, armhf, x86_64, and i686.
---
 debug/Makefile           |   2 +
 debug/tst-fortify-wide.c | 104 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 106 insertions(+)
 create mode 100644 debug/tst-fortify-wide.c

diff --git a/debug/Makefile b/debug/Makefile
index fdc250e209..ed90ef7030 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -180,6 +180,7 @@ CPPFLAGS-tst-realpath-chk.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
 CPPFLAGS-tst-chk-cancel.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
 CFLAGS-tst-sprintf-fortify-rdonly.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
 CFLAGS-tst-fortify-syslog.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
+CFLAGS-tst-fortify-wide.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
 
 # _FORTIFY_SOURCE tests.
 # Auto-generate tests for _FORTIFY_SOURCE for different levels, compilers and
@@ -283,6 +284,7 @@ tests = \
   tst-backtrace4 \
   tst-backtrace5 \
   tst-backtrace6 \
+  tst-fortify-wide \
   tst-longjmp_chk \
   tst-longjmp_chk2 \
   tst-realpath-chk \
diff --git a/debug/tst-fortify-wide.c b/debug/tst-fortify-wide.c
new file mode 100644
index 0000000000..6947d04fa6
--- /dev/null
+++ b/debug/tst-fortify-wide.c
@@ -0,0 +1,104 @@
+/* Fortify check for wprintf.
+   Copyright (C) 2004-2023 Free Software Foundation, Inc.
+   Copyright The GNU Toolchain Authors.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <setjmp.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <unistd.h>
+
+#include <support/support.h>
+
+static volatile int chk_fail_ok;
+static volatile int ret;
+static jmp_buf chk_fail_buf;
+
+static void
+handler (int sig)
+{
+  if (chk_fail_ok)
+    {
+      chk_fail_ok = 0;
+      longjmp (chk_fail_buf, 1);
+    }
+  else
+    _exit (127);
+}
+
+static const wchar_t *wstr3 = L"%ls%n%ls%n";
+static const wchar_t *wstr4 = L"Hello, ";
+static const wchar_t *wstr5 = L"World!\n";
+static wchar_t wbuf2[20] = L"%ls";
+
+#define WFAIL \
+  do { wprintf (L"Failure on line %d\n", __LINE__); ret = 1; } while (0)
+#define CHK_FAIL_START \
+  chk_fail_ok = 1;				\
+  if (! setjmp (chk_fail_buf))			\
+    {
+#define CHK_FAIL_END \
+      chk_fail_ok = 0;				\
+      WFAIL;					\
+    }
+
+static int
+do_test (void)
+{
+  set_fortify_handler (handler);
+
+  int n1, n2;
+
+  int orientation = fwide (stdout, 1);
+  if (orientation <= 0)
+    WFAIL;
+
+  /* Constant literals passed directly are always ok
+     (even with warnings about possible bugs from GCC).  */
+  if (wprintf (L"%ls%n%ls%n", wstr4, &n1, wstr5, &n2) != 14
+      || n1 != 7 || n2 != 14)
+    WFAIL;
+
+  /* In this case the format string is not known at compile time,
+     but resides in read-only memory, so is ok.  */
+  if (wprintf (wstr3, wstr4, &n1, wstr5, &n2) != 14
+      || n1 != 7 || n2 != 14)
+    WFAIL;
+
+  wcpcpy (&wbuf2[3], L"%n%ls%n");
+  /* When the format string is writable and contains %n,
+     with -D_FORTIFY_SOURCE=2 it causes __chk_fail.  */
+  CHK_FAIL_START
+  if (wprintf (wbuf2, wstr4, &n1, wstr5, &n1) != 14)
+    WFAIL;
+  CHK_FAIL_END
+
+  /* But if there is no %n, even writable format string
+     should work.  */
+  wbuf2[8] = L'\0';
+  if (wprintf (&wbuf2[5], wstr5) != 7)
+    WFAIL;
+
+  /* Check whether missing N$ formats are detected.  */
+  CHK_FAIL_START
+  wprintf (L"%3$d\n", 1, 2, 3, 4);
+  CHK_FAIL_END
+
+  return ret;
+}
+
+#include <support/test-driver.c>
-- 
2.34.1


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

* [PATCH 06/15] cdefs.h: Add clang fortify directives
  2023-12-21 18:59 [PATCH 00/15] Improve fortify support with clang Adhemerval Zanella
                   ` (4 preceding siblings ...)
  2023-12-21 18:59 ` [PATCH 05/15] debug: Add fortify wprintf tests Adhemerval Zanella
@ 2023-12-21 18:59 ` Adhemerval Zanella
  2023-12-21 21:33   ` Joseph Myers
  2023-12-21 18:59 ` [PATCH 07/15] libio: Improve fortify with clang Adhemerval Zanella
                   ` (8 subsequent siblings)
  14 siblings, 1 reply; 26+ messages in thread
From: Adhemerval Zanella @ 2023-12-21 18:59 UTC (permalink / raw)
  To: libc-alpha, Siddhesh Poyarekar

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 | 194 ++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 166 insertions(+), 28 deletions(-)

diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
index 90c21e2703..659ffc96a7 100644
--- a/misc/sys/cdefs.h
+++ b/misc/sys/cdefs.h
@@ -144,6 +144,35 @@
 # define __END_DECLS
 #endif
 
+/* GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99
+   inline semantics, unless -fgnu89-inline is used.  Using __GNUC_STDC_INLINE__
+   or __GNUC_GNU_INLINE is not a good enough check for gcc because gcc versions
+   older than 4.3 may define these macros and still not guarantee GNU inlining
+   semantics.
+
+   clang++ identifies itself as gcc-4.2, but has support for GNU inlining
+   semantics, that can be checked for by using the __GNUC_STDC_INLINE_ and
+   __GNUC_GNU_INLINE__ macro definitions.  */
+#if (!defined __cplusplus || __GNUC_PREREQ (4,3) \
+     || (defined __clang__ && (defined __GNUC_STDC_INLINE__ \
+			       || defined __GNUC_GNU_INLINE__)))
+# if defined __GNUC_STDC_INLINE__ || defined __cplusplus
+#  define __extern_inline extern __inline __attribute__ ((__gnu_inline__))
+#  define __extern_always_inline \
+  extern __always_inline __attribute__ ((__gnu_inline__))
+# else
+#  define __extern_inline extern __inline
+#  define __extern_always_inline extern __always_inline
+# endif
+#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)
@@ -187,27 +216,162 @@
 						   __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.  */
+#ifdef __extern_always_inline
+# define __fortify_function __extern_always_inline __attribute_artificial__
+# ifdef __clang__
+#  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)
+
+#  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)
+
+#  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
+#else
+# define __fortify_use_clang 0
+#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) \
@@ -452,32 +616,6 @@
 # define __attribute_artificial__ /* Ignore */
 #endif
 
-/* GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99
-   inline semantics, unless -fgnu89-inline is used.  Using __GNUC_STDC_INLINE__
-   or __GNUC_GNU_INLINE is not a good enough check for gcc because gcc versions
-   older than 4.3 may define these macros and still not guarantee GNU inlining
-   semantics.
-
-   clang++ identifies itself as gcc-4.2, but has support for GNU inlining
-   semantics, that can be checked for by using the __GNUC_STDC_INLINE_ and
-   __GNUC_GNU_INLINE__ macro definitions.  */
-#if (!defined __cplusplus || __GNUC_PREREQ (4,3) \
-     || (defined __clang__ && (defined __GNUC_STDC_INLINE__ \
-			       || defined __GNUC_GNU_INLINE__)))
-# if defined __GNUC_STDC_INLINE__ || defined __cplusplus
-#  define __extern_inline extern __inline __attribute__ ((__gnu_inline__))
-#  define __extern_always_inline \
-  extern __always_inline __attribute__ ((__gnu_inline__))
-# else
-#  define __extern_inline extern __inline
-#  define __extern_always_inline extern __always_inline
-# endif
-#endif
-
-#ifdef __extern_always_inline
-# define __fortify_function __extern_always_inline __attribute_artificial__
-#endif
-
 /* GCC 4.3 and above allow passing all anonymous arguments of an
    __extern_always_inline function to some other vararg function.  */
 #if __GNUC_PREREQ (4,3)
-- 
2.34.1


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

* [PATCH 07/15] libio: Improve fortify with clang
  2023-12-21 18:59 [PATCH 00/15] Improve fortify support with clang Adhemerval Zanella
                   ` (5 preceding siblings ...)
  2023-12-21 18:59 ` [PATCH 06/15] cdefs.h: Add clang fortify directives Adhemerval Zanella
@ 2023-12-21 18:59 ` Adhemerval Zanella
  2023-12-21 18:59 ` [PATCH 08/15] string: " Adhemerval Zanella
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 26+ messages in thread
From: Adhemerval Zanella @ 2023-12-21 18:59 UTC (permalink / raw)
  To: libc-alpha, Siddhesh Poyarekar

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 266dccdd1e..7dc75694bd 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] 26+ messages in thread

* [PATCH 08/15] string: Improve fortify with clang
  2023-12-21 18:59 [PATCH 00/15] Improve fortify support with clang Adhemerval Zanella
                   ` (6 preceding siblings ...)
  2023-12-21 18:59 ` [PATCH 07/15] libio: Improve fortify with clang Adhemerval Zanella
@ 2023-12-21 18:59 ` Adhemerval Zanella
  2023-12-21 18:59 ` [PATCH 09/15] stdlib: " Adhemerval Zanella
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 26+ messages in thread
From: Adhemerval Zanella @ 2023-12-21 18:59 UTC (permalink / raw)
  To: libc-alpha, Siddhesh Poyarekar

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 23ef064168..d3ee250642 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] 26+ messages in thread

* [PATCH 09/15] stdlib: Improve fortify with clang
  2023-12-21 18:59 [PATCH 00/15] Improve fortify support with clang Adhemerval Zanella
                   ` (7 preceding siblings ...)
  2023-12-21 18:59 ` [PATCH 08/15] string: " Adhemerval Zanella
@ 2023-12-21 18:59 ` Adhemerval Zanella
  2023-12-21 18:59 ` [PATCH 10/15] unistd: " Adhemerval Zanella
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 26+ messages in thread
From: Adhemerval Zanella @ 2023-12-21 18:59 UTC (permalink / raw)
  To: libc-alpha, Siddhesh Poyarekar

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 c6c0082ad5..1f89c1e69f 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] 26+ messages in thread

* [PATCH 10/15] unistd: Improve fortify with clang
  2023-12-21 18:59 [PATCH 00/15] Improve fortify support with clang Adhemerval Zanella
                   ` (8 preceding siblings ...)
  2023-12-21 18:59 ` [PATCH 09/15] stdlib: " Adhemerval Zanella
@ 2023-12-21 18:59 ` Adhemerval Zanella
  2023-12-21 18:59 ` [PATCH 11/15] socket: " Adhemerval Zanella
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 26+ messages in thread
From: Adhemerval Zanella @ 2023-12-21 18:59 UTC (permalink / raw)
  To: libc-alpha, Siddhesh Poyarekar

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 6a381116a9..cc19865348 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] 26+ messages in thread

* [PATCH 11/15] socket: Improve fortify with clang
  2023-12-21 18:59 [PATCH 00/15] Improve fortify support with clang Adhemerval Zanella
                   ` (9 preceding siblings ...)
  2023-12-21 18:59 ` [PATCH 10/15] unistd: " Adhemerval Zanella
@ 2023-12-21 18:59 ` Adhemerval Zanella
  2023-12-21 18:59 ` [PATCH 12/15] syslog: " Adhemerval Zanella
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 26+ messages in thread
From: Adhemerval Zanella @ 2023-12-21 18:59 UTC (permalink / raw)
  To: libc-alpha, Siddhesh Poyarekar

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 d85d3ff48d..745c29fe0d 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 ffcc671625..f8ad72ff79 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] 26+ messages in thread

* [PATCH 12/15] syslog: Improve fortify with clang
  2023-12-21 18:59 [PATCH 00/15] Improve fortify support with clang Adhemerval Zanella
                   ` (10 preceding siblings ...)
  2023-12-21 18:59 ` [PATCH 11/15] socket: " Adhemerval Zanella
@ 2023-12-21 18:59 ` Adhemerval Zanella
  2023-12-21 18:59 ` [PATCH 13/15] wcsmbs: " Adhemerval Zanella
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 26+ messages in thread
From: Adhemerval Zanella @ 2023-12-21 18:59 UTC (permalink / raw)
  To: libc-alpha, Siddhesh Poyarekar

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 d7de90ed14..969ce9e431 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] 26+ messages in thread

* [PATCH 13/15] wcsmbs: Improve fortify with clang
  2023-12-21 18:59 [PATCH 00/15] Improve fortify support with clang Adhemerval Zanella
                   ` (11 preceding siblings ...)
  2023-12-21 18:59 ` [PATCH 12/15] syslog: " Adhemerval Zanella
@ 2023-12-21 18:59 ` Adhemerval Zanella
  2023-12-21 18:59 ` [PATCH 14/15] debug: Improve fcntl.h fortify warnings " Adhemerval Zanella
  2023-12-21 18:59 ` [PATCH 15/15] debug: Improve mqueue.h " Adhemerval Zanella
  14 siblings, 0 replies; 26+ messages in thread
From: Adhemerval Zanella @ 2023-12-21 18:59 UTC (permalink / raw)
  To: libc-alpha, Siddhesh Poyarekar

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 6e6234d606..c9c4681c82 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] 26+ messages in thread

* [PATCH 14/15] debug: Improve fcntl.h fortify warnings with clang
  2023-12-21 18:59 [PATCH 00/15] Improve fortify support with clang Adhemerval Zanella
                   ` (12 preceding siblings ...)
  2023-12-21 18:59 ` [PATCH 13/15] wcsmbs: " Adhemerval Zanella
@ 2023-12-21 18:59 ` Adhemerval Zanella
  2023-12-21 18:59 ` [PATCH 15/15] debug: Improve mqueue.h " Adhemerval Zanella
  14 siblings, 0 replies; 26+ messages in thread
From: Adhemerval Zanella @ 2023-12-21 18:59 UTC (permalink / raw)
  To: libc-alpha, Siddhesh Poyarekar

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 |  7 ++++
 3 files changed, 100 insertions(+), 2 deletions(-)

diff --git a/io/bits/fcntl2.h b/io/bits/fcntl2.h
index bdb48fa815..6aa7793a81 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 dd620c086f..ac5e5cb72c 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 659ffc96a7..a9022621e2 100644
--- a/misc/sys/cdefs.h
+++ b/misc/sys/cdefs.h
@@ -271,6 +271,8 @@
 
 #  define __fortify_clang_warning(__c, __msg) \
   __attribute__ ((__diagnose_if__ ((__c), (__msg), "warning")))
+#  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))))
@@ -284,6 +286,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] 26+ messages in thread

* [PATCH 15/15] debug: Improve mqueue.h fortify warnings with clang
  2023-12-21 18:59 [PATCH 00/15] Improve fortify support with clang Adhemerval Zanella
                   ` (13 preceding siblings ...)
  2023-12-21 18:59 ` [PATCH 14/15] debug: Improve fcntl.h fortify warnings " Adhemerval Zanella
@ 2023-12-21 18:59 ` Adhemerval Zanella
  14 siblings, 0 replies; 26+ messages in thread
From: Adhemerval Zanella @ 2023-12-21 18:59 UTC (permalink / raw)
  To: libc-alpha, Siddhesh Poyarekar

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 c1d86662dc..69897fd578 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 126a6b54b3..9279763841 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] 26+ messages in thread

* Re: [PATCH 01/15] debug: Adapt fortify tests to libsupport
  2023-12-21 18:59 ` [PATCH 01/15] debug: Adapt fortify tests to libsupport Adhemerval Zanella
@ 2023-12-21 19:54   ` Siddhesh Poyarekar
  0 siblings, 0 replies; 26+ messages in thread
From: Siddhesh Poyarekar @ 2023-12-21 19:54 UTC (permalink / raw)
  To: Adhemerval Zanella, libc-alpha



On 2023-12-21 13:59, Adhemerval Zanella wrote:
> Checked on aarch64, armhf, x86_64, and i686.
> ---

LGTM.

Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>

>   debug/test-stpcpy_chk.c  |  2 +-
>   debug/test-strcpy_chk.c  |  2 +-
>   debug/tst-fortify.c      | 55 +++++++++++++++++++++-------------------
>   debug/tst-longjmp_chk.c  |  8 +++---
>   debug/tst-longjmp_chk2.c |  6 ++---
>   debug/tst-longjmp_chk3.c |  6 ++---
>   6 files changed, 39 insertions(+), 40 deletions(-)
> 
> diff --git a/debug/test-stpcpy_chk.c b/debug/test-stpcpy_chk.c
> index 938f3c0ceb..0b9fed49cc 100644
> --- a/debug/test-stpcpy_chk.c
> +++ b/debug/test-stpcpy_chk.c
> @@ -19,7 +19,7 @@
>   #define STRCPY_RESULT(dst, len) ((dst) + (len))
>   #define TEST_MAIN
>   #define TEST_NAME "stpcpy_chk"
> -#include "../string/test-string.h"
> +#include <string/test-string.h>
>   
>   extern void __attribute__ ((noreturn)) __chk_fail (void);
>   char *simple_stpcpy_chk (char *, const char *, size_t);
> diff --git a/debug/test-strcpy_chk.c b/debug/test-strcpy_chk.c
> index 792e789e1e..684e0bdd9b 100644
> --- a/debug/test-strcpy_chk.c
> +++ b/debug/test-strcpy_chk.c
> @@ -20,7 +20,7 @@
>   # define STRCPY_RESULT(dst, len) dst
>   # define TEST_MAIN
>   # define TEST_NAME "strcpy_chk"
> -# include "../string/test-string.h"
> +# include <string/test-string.h>
>   
>   /* This test case implicitly tests the availability of the __chk_fail
>      symbol, which is part of the public ABI and may be used
> diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c
> index 3744aadad4..20e926751a 100644
> --- a/debug/tst-fortify.c
> +++ b/debug/tst-fortify.c
> @@ -23,6 +23,7 @@
>   
>   #include <assert.h>
>   #include <fcntl.h>
> +#include <limits.h>
>   #include <locale.h>
>   #include <obstack.h>
>   #include <setjmp.h>
> @@ -36,6 +37,10 @@
>   #include <sys/select.h>
>   #include <sys/socket.h>
>   #include <sys/un.h>
> +#include <paths.h>
> +
> +#include <support/temp_file.h>
> +#include <support/support.h>
>   
>   #ifndef _GNU_SOURCE
>   # define MEMPCPY memcpy
> @@ -52,15 +57,10 @@
>   #define obstack_chunk_alloc malloc
>   #define obstack_chunk_free free
>   
> -char *temp_filename;
> -static void do_prepare (void);
> -static int do_test (void);
> -#define PREPARE(argc, argv) do_prepare ()
> -#define TEST_FUNCTION do_test ()
> -#include "../test-skeleton.c"
> +static char *temp_filename;
>   
>   static void
> -do_prepare (void)
> +do_prepare (int argc, char *argv[])
>   {
>     int temp_fd = create_temp_file ("tst-chk1.", &temp_filename);
>     if (temp_fd == -1)
> @@ -77,10 +77,11 @@ do_prepare (void)
>         exit (1);
>       }
>   }
> +#define PREPARE do_prepare
>   
> -volatile int chk_fail_ok;
> -volatile int ret;
> -jmp_buf chk_fail_buf;
> +static volatile int chk_fail_ok;
> +static volatile int ret;
> +static jmp_buf chk_fail_buf;
>   
>   static void
>   handler (int sig)
> @@ -102,22 +103,22 @@ wchar_t wbuf[10];
>   #define buf_size sizeof (buf)
>   #endif
>   
> -volatile size_t l0;
> -volatile char *p;
> -volatile wchar_t *wp;
> -const char *str1 = "JIHGFEDCBA";
> -const char *str2 = "F";
> -const char *str3 = "%s%n%s%n";
> -const char *str4 = "Hello, ";
> -const char *str5 = "World!\n";
> -const wchar_t *wstr1 = L"JIHGFEDCBA";
> -const wchar_t *wstr2 = L"F";
> -const wchar_t *wstr3 = L"%s%n%s%n";
> -const wchar_t *wstr4 = L"Hello, ";
> -const wchar_t *wstr5 = L"World!\n";
> -char buf2[10] = "%s";
> -int num1 = 67;
> -int num2 = 987654;
> +static volatile size_t l0;
> +static volatile char *p;
> +static volatile wchar_t *wp;
> +static const char *str1 = "JIHGFEDCBA";
> +static const char *str2 = "F";
> +static const char *str3 = "%s%n%s%n";
> +static const char *str4 = "Hello, ";
> +static const char *str5 = "World!\n";
> +static const wchar_t *wstr1 = L"JIHGFEDCBA";
> +static const wchar_t *wstr2 = L"F";
> +static const wchar_t *wstr3 = L"%s%n%s%n";
> +static const wchar_t *wstr4 = L"Hello, ";
> +static const wchar_t *wstr5 = L"World!\n";
> +static char buf2[10] = "%s";
> +static int num1 = 67;
> +static int num2 = 987654;
>   
>   #define FAIL() \
>     do { printf ("Failure on line %d\n", __LINE__); ret = 1; } while (0)
> @@ -1815,3 +1816,5 @@ do_test (void)
>   
>     return ret;
>   }
> +
> +#include <support/test-driver.c>
> diff --git a/debug/tst-longjmp_chk.c b/debug/tst-longjmp_chk.c
> index e4e93d2a36..37f858606b 100644
> --- a/debug/tst-longjmp_chk.c
> +++ b/debug/tst-longjmp_chk.c
> @@ -10,11 +10,7 @@
>   #include <stdlib.h>
>   #include <unistd.h>
>   
> -
> -static int do_test(void);
> -#define TEST_FUNCTION do_test ()
> -#include "../test-skeleton.c"
> -
> +#include <support/support.h>
>   
>   static jmp_buf b;
>   
> @@ -76,3 +72,5 @@ do_test (void)
>     puts ("second longjmp returned");
>     return 1;
>   }
> +
> +#include <support/test-driver.c>
> diff --git a/debug/tst-longjmp_chk2.c b/debug/tst-longjmp_chk2.c
> index 1810ab44d7..7e1ee3edc5 100644
> --- a/debug/tst-longjmp_chk2.c
> +++ b/debug/tst-longjmp_chk2.c
> @@ -10,9 +10,7 @@
>   #include <sys/resource.h>
>   #include <unistd.h>
>   
> -static int do_test (void);
> -#define TEST_FUNCTION do_test ()
> -#include "../test-skeleton.c"
> +#include <support/support.h>
>   
>   static jmp_buf mainloop;
>   static sigset_t mainsigset;
> @@ -126,3 +124,5 @@ do_test (void)
>   
>     return 0;
>   }
> +
> +#include <support/test-driver.c>
> diff --git a/debug/tst-longjmp_chk3.c b/debug/tst-longjmp_chk3.c
> index f1e576ad5b..3050806c44 100644
> --- a/debug/tst-longjmp_chk3.c
> +++ b/debug/tst-longjmp_chk3.c
> @@ -20,10 +20,6 @@
>   #include <signal.h>
>   #include <string.h>
>   
> -static int do_test (void);
> -#define TEST_FUNCTION do_test ()
> -#include "../test-skeleton.c"
> -
>   static char buf[SIGSTKSZ * 4];
>   static jmp_buf jb;
>   
> @@ -83,3 +79,5 @@ do_test (void)
>     puts ("longjmp returned and shouldn't");
>     return 1;
>   }
> +
> +#include <support/test-driver.c>

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

* Re: [PATCH 02/15] debug: Increase tst-fortify checks for compiler without __va_arg_pack support
  2023-12-21 18:59 ` [PATCH 02/15] debug: Increase tst-fortify checks for compiler without __va_arg_pack support Adhemerval Zanella
@ 2023-12-21 20:02   ` Siddhesh Poyarekar
  2023-12-21 21:43     ` Joseph Myers
  2023-12-22 12:29     ` Adhemerval Zanella Netto
  0 siblings, 2 replies; 26+ messages in thread
From: Siddhesh Poyarekar @ 2023-12-21 20:02 UTC (permalink / raw)
  To: Adhemerval Zanella, libc-alpha

On 2023-12-21 13:59, Adhemerval Zanella wrote:
> The fortify wrappers for varargs functions already add fallbacks to
> builtins calls if __va_arg_pack is not supported.

... and in fact helps test the #else part with a different compiler, 
like clang.  BTW, I'm not sure if you've seen this, but Serge Guelton 
used to maintain a _FORTIFY_SOURCE testsuite to do comparative testing 
between clang and gcc:

https://github.com/serge-sans-paille/fortify-test-suite

It would be nice to subsume all of that, if there's additional coverage 
there.

LGTM.

Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>

> 
> Checked on aarch64, armhf, x86_64, and i686.
> ---
>   debug/tst-fortify.c | 6 +-----
>   1 file changed, 1 insertion(+), 5 deletions(-)
> 
> diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c
> index 20e926751a..5cd9d22feb 100644
> --- a/debug/tst-fortify.c
> +++ b/debug/tst-fortify.c
> @@ -130,7 +130,7 @@ static int num2 = 987654;
>         chk_fail_ok = 0;				\
>         FAIL ();					\
>       }
> -#if __USE_FORTIFY_LEVEL >= 2 && (!defined __cplusplus || defined __va_arg_pack)
> +#if __USE_FORTIFY_LEVEL >= 2
>   # define CHK_FAIL2_START CHK_FAIL_START
>   # define CHK_FAIL2_END CHK_FAIL_END
>   #else
> @@ -419,7 +419,6 @@ do_test (void)
>     stpncpy (buf + 6, "cd", l0 + 5);
>     CHK_FAIL_END
>   
> -# if !defined __cplusplus || defined __va_arg_pack
>     CHK_FAIL_START
>     sprintf (buf + 8, "%d", num1);
>     CHK_FAIL_END
> @@ -439,7 +438,6 @@ do_test (void)
>     CHK_FAIL_START
>     swprintf (wbuf + 8, l0 + 3, L"%d", num1);
>     CHK_FAIL_END
> -# endif
>   
>     memcpy (buf, str1 + 2, 9);
>     CHK_FAIL_START
> @@ -550,7 +548,6 @@ do_test (void)
>         FAIL ();
>     }
>   
> -# if !defined __cplusplus || defined __va_arg_pack
>     CHK_FAIL_START
>     sprintf (a.buf1 + (O + 7), "%d", num1);
>     CHK_FAIL_END
> @@ -562,7 +559,6 @@ do_test (void)
>     CHK_FAIL_START
>     snprintf (a.buf1 + (O + 7), l0 + 3, "%d", num2);
>     CHK_FAIL_END
> -# endif
>   
>     memcpy (a.buf1, str1 + (3 - O), 8 + O);
>     CHK_FAIL_START

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

* Re: [PATCH 03/15] debug: Add fortify dprintf tests
  2023-12-21 18:59 ` [PATCH 03/15] debug: Add fortify dprintf tests Adhemerval Zanella
@ 2023-12-21 20:03   ` Siddhesh Poyarekar
  0 siblings, 0 replies; 26+ messages in thread
From: Siddhesh Poyarekar @ 2023-12-21 20:03 UTC (permalink / raw)
  To: Adhemerval Zanella, libc-alpha



On 2023-12-21 13:59, Adhemerval Zanella wrote:
> Similar to other printf-like ones.
> 
> Checked on aarch64, armhf, x86_64, and i686.
> ---

Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>

>   debug/tst-fortify.c | 22 ++++++++++++++++++++++
>   1 file changed, 22 insertions(+)
> 
> diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c
> index 5cd9d22feb..888eae25ad 100644
> --- a/debug/tst-fortify.c
> +++ b/debug/tst-fortify.c
> @@ -59,6 +59,8 @@
>   
>   static char *temp_filename;
>   
> +static int temp_fd_dprintf;
> +
>   static void
>   do_prepare (int argc, char *argv[])
>   {
> @@ -76,6 +78,13 @@ do_prepare (int argc, char *argv[])
>         unlink (temp_filename);
>         exit (1);
>       }
> +
> +  temp_fd_dprintf = create_temp_file ("tst-chk2.", NULL);
> +  if (temp_fd_dprintf == -1)
> +    {
> +      printf ("cannot create temporary file: %m\n");
> +      exit (1);
> +    }
>   }
>   #define PREPARE do_prepare
>   
> @@ -901,6 +910,10 @@ do_test (void)
>         || n1 != 1 || n2 != 2)
>       FAIL ();
>   
> +  if (dprintf (temp_fd_dprintf, "%s%n%s%n", str2, &n1, str2, &n2) != 2
> +      || n1 != 1 || n2 != 2)
> +    FAIL ();
> +
>     strcpy (buf2 + 2, "%n%s%n");
>     /* When the format string is writable and contains %n,
>        with -D_FORTIFY_SOURCE=2 it causes __chk_fail.  */
> @@ -914,6 +927,11 @@ do_test (void)
>       FAIL ();
>     CHK_FAIL2_END
>   
> +  CHK_FAIL2_START
> +  if (dprintf (temp_fd_dprintf, buf2, str2, &n1, str2, &n1) != 2)
> +    FAIL ();
> +  CHK_FAIL2_END
> +
>     /* But if there is no %n, even writable format string
>        should work.  */
>     buf2[6] = '\0';
> @@ -1263,6 +1281,10 @@ do_test (void)
>     snprintf (buf, buf_size, "%3$d\n", 1, 2, 3, 4);
>     CHK_FAIL2_END
>   
> +  CHK_FAIL2_START
> +  dprintf (temp_fd_dprintf, "%3$d\n", 1, 2, 3, 4);
> +  CHK_FAIL2_END
> +
>     int sp[2];
>     if (socketpair (PF_UNIX, SOCK_STREAM, 0, sp))
>       FAIL ();

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

* Re: [PATCH 04/15] debug: Add fortify syslog tests
  2023-12-21 18:59 ` [PATCH 04/15] debug: Add fortify syslog tests Adhemerval Zanella
@ 2023-12-21 20:06   ` Siddhesh Poyarekar
  0 siblings, 0 replies; 26+ messages in thread
From: Siddhesh Poyarekar @ 2023-12-21 20:06 UTC (permalink / raw)
  To: Adhemerval Zanella, libc-alpha



On 2023-12-21 13:59, Adhemerval Zanella wrote:
> It requires to be in a container tests to avoid logging bogus
> information on the system.  The syslog also requires to be checked in
> a different process because the internal printf call will abort with
> the internal syslog lock taken (which makes subsequent syslog calls
> deadlock).
> 
> Checked on aarch64, armhf, x86_64, and i686.
> ---

Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>

>   debug/Makefile             |   5 ++
>   debug/tst-fortify-syslog.c | 128 +++++++++++++++++++++++++++++++++++++
>   2 files changed, 133 insertions(+)
>   create mode 100644 debug/tst-fortify-syslog.c
> 
> diff --git a/debug/Makefile b/debug/Makefile
> index c49e5d86ec..fdc250e209 100644
> --- a/debug/Makefile
> +++ b/debug/Makefile
> @@ -179,6 +179,7 @@ CPPFLAGS-tst-longjmp_chk3.c += $(no-fortify-source),-D_FORTIFY_SOURCE=1
>   CPPFLAGS-tst-realpath-chk.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
>   CPPFLAGS-tst-chk-cancel.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
>   CFLAGS-tst-sprintf-fortify-rdonly.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
> +CFLAGS-tst-fortify-syslog.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
>   
>   # _FORTIFY_SOURCE tests.
>   # Auto-generate tests for _FORTIFY_SOURCE for different levels, compilers and
> @@ -293,6 +294,10 @@ tests-time64 += \
>     $(tests-all-time64-chk) \
>     # tests-time64
>   
> +tests-container += \
> +  tst-fortify-syslog \
> +  # tests-container
> +
>   ifeq ($(have-ssp),yes)
>   tests += tst-ssp-1
>   endif
> diff --git a/debug/tst-fortify-syslog.c b/debug/tst-fortify-syslog.c
> new file mode 100644
> index 0000000000..26a93d9be8
> --- /dev/null
> +++ b/debug/tst-fortify-syslog.c
> @@ -0,0 +1,128 @@
> +/* Fortify tests for syslog interface.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +   Copyright The GNU Toolchain Authors.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <stdarg.h>
> +#include <setjmp.h>
> +#include <syslog.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <stdio.h>
> +
> +#include <support/check.h>
> +#include <support/support.h>
> +#include <support/capture_subprocess.h>
> +
> +static const char *str2 = "F";
> +static char buf2[10] = "%s";
> +
> +static volatile int chk_fail_ok;
> +static jmp_buf chk_fail_buf;
> +
> +static void
> +handler (int sig)
> +{
> +  if (chk_fail_ok)
> +    {
> +      chk_fail_ok = 0;
> +      longjmp (chk_fail_buf, 1);
> +    }
> +  else
> +    _exit (127);
> +}
> +
> +#define FAIL()						\
> +  do {							\
> +      printf ("Failure on line %d\n", __LINE__);	\
> +      support_record_failure ();			\
> +  } while (0)
> +#define CHK_FAIL_START					\
> +  chk_fail_ok = 1;					\
> +  if (! setjmp (chk_fail_buf))				\
> +    {
> +#define CHK_FAIL_END					\
> +      chk_fail_ok = 0;					\
> +      FAIL ();						\
> +    }
> +
> +static void
> +call_vsyslog (int priority, const char *format, ...)
> +{
> +  va_list va;
> +  va_start (va, format);
> +  vsyslog (priority, format, va);
> +  va_end (va);
> +}
> +
> +static void
> +run_syslog_chk (void *closure)
> +{
> +  int n1;
> +  CHK_FAIL_START
> +  syslog (LOG_USER | LOG_DEBUG, buf2, str2, &n1, str2, &n1);
> +  CHK_FAIL_END
> +}
> +
> +static void
> +run_vsyslog_chk (void *closure)
> +{
> +  int n1;
> +  CHK_FAIL_START
> +  call_vsyslog (LOG_USER | LOG_DEBUG, buf2, str2, &n1, str2, &n1);
> +  CHK_FAIL_END
> +}
> +
> +static int
> +do_test (void)
> +{
> +  set_fortify_handler (handler);
> +
> +  int n1, n2;
> +
> +  n1 = n2 = 0;
> +  syslog (LOG_USER | LOG_DEBUG, "%s%n%s%n", str2, &n1, str2, &n2);
> +  TEST_COMPARE (n1, 1);
> +  TEST_COMPARE (n2, 2);
> +
> +  n1 = n2 = 0;
> +  call_vsyslog (LOG_USER | LOG_DEBUG, "%s%n%s%n", str2, &n1, str2, &n2);
> +  TEST_COMPARE (n1, 1);
> +  TEST_COMPARE (n2, 2);
> +
> +  strcpy (buf2 + 2, "%n%s%n");
> +
> +  /* The wrapper tests need to be in a subprocess because the abort called by
> +     printf does not unlock the internal syslog lock.  */
> +  {
> +    struct support_capture_subprocess result
> +      = support_capture_subprocess (run_syslog_chk, NULL);
> +    support_capture_subprocess_check (&result, "syslog", 0, sc_allow_stderr);
> +    support_capture_subprocess_free (&result);
> +  }
> +
> +  {
> +    struct support_capture_subprocess result
> +      = support_capture_subprocess (run_vsyslog_chk, NULL);
> +    support_capture_subprocess_check (&result, "syslog", 0, sc_allow_stderr);
> +    support_capture_subprocess_free (&result);
> +  }
> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>

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

* Re: [PATCH 05/15] debug: Add fortify wprintf tests
  2023-12-21 18:59 ` [PATCH 05/15] debug: Add fortify wprintf tests Adhemerval Zanella
@ 2023-12-21 20:08   ` Siddhesh Poyarekar
  2023-12-29 13:56     ` Adhemerval Zanella Netto
  0 siblings, 1 reply; 26+ messages in thread
From: Siddhesh Poyarekar @ 2023-12-21 20:08 UTC (permalink / raw)
  To: Adhemerval Zanella, libc-alpha



On 2023-12-21 13:59, Adhemerval Zanella wrote:
> Similar to other printf-like ones.  It requires to be in a different
> process so we can change the orientation of stdout.
> 
> Checked on aarch64, armhf, x86_64, and i686.
> ---
>   debug/Makefile           |   2 +
>   debug/tst-fortify-wide.c | 104 +++++++++++++++++++++++++++++++++++++++
>   2 files changed, 106 insertions(+)
>   create mode 100644 debug/tst-fortify-wide.c
> 
> diff --git a/debug/Makefile b/debug/Makefile
> index fdc250e209..ed90ef7030 100644
> --- a/debug/Makefile
> +++ b/debug/Makefile
> @@ -180,6 +180,7 @@ CPPFLAGS-tst-realpath-chk.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
>   CPPFLAGS-tst-chk-cancel.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
>   CFLAGS-tst-sprintf-fortify-rdonly.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
>   CFLAGS-tst-fortify-syslog.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
> +CFLAGS-tst-fortify-wide.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
>   
>   # _FORTIFY_SOURCE tests.
>   # Auto-generate tests for _FORTIFY_SOURCE for different levels, compilers and
> @@ -283,6 +284,7 @@ tests = \
>     tst-backtrace4 \
>     tst-backtrace5 \
>     tst-backtrace6 \
> +  tst-fortify-wide \
>     tst-longjmp_chk \
>     tst-longjmp_chk2 \
>     tst-realpath-chk \
> diff --git a/debug/tst-fortify-wide.c b/debug/tst-fortify-wide.c
> new file mode 100644
> index 0000000000..6947d04fa6
> --- /dev/null
> +++ b/debug/tst-fortify-wide.c
> @@ -0,0 +1,104 @@
> +/* Fortify check for wprintf.
> +   Copyright (C) 2004-2023 Free Software Foundation, Inc.
> +   Copyright The GNU Toolchain Authors.

It's a new test, so just 2023 and FSF?  Looks OK otherwise.

> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <setjmp.h>
> +#include <stdio.h>
> +#include <wchar.h>
> +#include <unistd.h>
> +
> +#include <support/support.h>
> +
> +static volatile int chk_fail_ok;
> +static volatile int ret;
> +static jmp_buf chk_fail_buf;
> +
> +static void
> +handler (int sig)
> +{
> +  if (chk_fail_ok)
> +    {
> +      chk_fail_ok = 0;
> +      longjmp (chk_fail_buf, 1);
> +    }
> +  else
> +    _exit (127);
> +}
> +
> +static const wchar_t *wstr3 = L"%ls%n%ls%n";
> +static const wchar_t *wstr4 = L"Hello, ";
> +static const wchar_t *wstr5 = L"World!\n";
> +static wchar_t wbuf2[20] = L"%ls";
> +
> +#define WFAIL \
> +  do { wprintf (L"Failure on line %d\n", __LINE__); ret = 1; } while (0)
> +#define CHK_FAIL_START \
> +  chk_fail_ok = 1;				\
> +  if (! setjmp (chk_fail_buf))			\
> +    {
> +#define CHK_FAIL_END \
> +      chk_fail_ok = 0;				\
> +      WFAIL;					\
> +    }
> +
> +static int
> +do_test (void)
> +{
> +  set_fortify_handler (handler);
> +
> +  int n1, n2;
> +
> +  int orientation = fwide (stdout, 1);
> +  if (orientation <= 0)
> +    WFAIL;
> +
> +  /* Constant literals passed directly are always ok
> +     (even with warnings about possible bugs from GCC).  */
> +  if (wprintf (L"%ls%n%ls%n", wstr4, &n1, wstr5, &n2) != 14
> +      || n1 != 7 || n2 != 14)
> +    WFAIL;
> +
> +  /* In this case the format string is not known at compile time,
> +     but resides in read-only memory, so is ok.  */
> +  if (wprintf (wstr3, wstr4, &n1, wstr5, &n2) != 14
> +      || n1 != 7 || n2 != 14)
> +    WFAIL;
> +
> +  wcpcpy (&wbuf2[3], L"%n%ls%n");
> +  /* When the format string is writable and contains %n,
> +     with -D_FORTIFY_SOURCE=2 it causes __chk_fail.  */
> +  CHK_FAIL_START
> +  if (wprintf (wbuf2, wstr4, &n1, wstr5, &n1) != 14)
> +    WFAIL;
> +  CHK_FAIL_END
> +
> +  /* But if there is no %n, even writable format string
> +     should work.  */
> +  wbuf2[8] = L'\0';
> +  if (wprintf (&wbuf2[5], wstr5) != 7)
> +    WFAIL;
> +
> +  /* Check whether missing N$ formats are detected.  */
> +  CHK_FAIL_START
> +  wprintf (L"%3$d\n", 1, 2, 3, 4);
> +  CHK_FAIL_END
> +
> +  return ret;
> +}
> +
> +#include <support/test-driver.c>

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

* Re: [PATCH 06/15] cdefs.h: Add clang fortify directives
  2023-12-21 18:59 ` [PATCH 06/15] cdefs.h: Add clang fortify directives Adhemerval Zanella
@ 2023-12-21 21:33   ` Joseph Myers
  2023-12-22 12:36     ` Adhemerval Zanella Netto
  0 siblings, 1 reply; 26+ messages in thread
From: Joseph Myers @ 2023-12-21 21:33 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha, Siddhesh Poyarekar

On Thu, 21 Dec 2023, Adhemerval Zanella wrote:

> +#  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_dynamic_object_size_n(n) \
> +  __attribute__ ((pass_dynamic_object_size (n)))

I'd expect these to use implementation-namespace macro names __unused__, 
__pass_object_size__, __pass_dynamic_object_size__; _FORTIFY_SOURCE 
shouldn't use extra names from the user's namespace, regardless of what 
compiler is used.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: [PATCH 02/15] debug: Increase tst-fortify checks for compiler without __va_arg_pack support
  2023-12-21 20:02   ` Siddhesh Poyarekar
@ 2023-12-21 21:43     ` Joseph Myers
  2023-12-22 12:29     ` Adhemerval Zanella Netto
  1 sibling, 0 replies; 26+ messages in thread
From: Joseph Myers @ 2023-12-21 21:43 UTC (permalink / raw)
  To: Siddhesh Poyarekar; +Cc: Adhemerval Zanella, libc-alpha

On Thu, 21 Dec 2023, Siddhesh Poyarekar wrote:

> On 2023-12-21 13:59, Adhemerval Zanella wrote:
> > The fortify wrappers for varargs functions already add fallbacks to
> > builtins calls if __va_arg_pack is not supported.
> 
> ... and in fact helps test the #else part with a different compiler, like
> clang.  BTW, I'm not sure if you've seen this, but Serge Guelton used to
> maintain a _FORTIFY_SOURCE testsuite to do comparative testing between clang
> and gcc:
> 
> https://github.com/serge-sans-paille/fortify-test-suite
> 
> It would be nice to subsume all of that, if there's additional coverage there.

A related (hard) issue is how to run the glibc testsuite with a different 
compiler (whether in the glibc build tree, or, introducing a further 
issue, against an installed copy of glibc) - as one built copy of glibc 
ought to work with multiple compilers, including ones that aren't 
supported for building glibc itself.  (In principle such testing could 
detect ABI incompatibilities as well as header issues; consider e.g. the 
known issues where clang is incompatible with the x86-64 ABI's handling of 
narrower-than-32-bit function arguments and return values, though it's 
quite likely tests would fail to exercise such incompatibilities.)

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: [PATCH 02/15] debug: Increase tst-fortify checks for compiler without __va_arg_pack support
  2023-12-21 20:02   ` Siddhesh Poyarekar
  2023-12-21 21:43     ` Joseph Myers
@ 2023-12-22 12:29     ` Adhemerval Zanella Netto
  1 sibling, 0 replies; 26+ messages in thread
From: Adhemerval Zanella Netto @ 2023-12-22 12:29 UTC (permalink / raw)
  To: Siddhesh Poyarekar, libc-alpha



On 21/12/23 17:02, Siddhesh Poyarekar wrote:
> On 2023-12-21 13:59, Adhemerval Zanella wrote:
>> The fortify wrappers for varargs functions already add fallbacks to
>> builtins calls if __va_arg_pack is not supported.
> 
> ... and in fact helps test the #else part with a different compiler, like clang.  BTW, I'm not sure if you've seen this, but Serge Guelton used to maintain a _FORTIFY_SOURCE testsuite to do comparative testing between clang and gcc:
> 
> https://github.com/serge-sans-paille/fortify-test-suite
> 
> It would be nice to subsume all of that, if there's additional coverage there.

Interesting, I will take a look.  Our tests are still lacking a way to
proper check wrong usages that might trigger compiler warnings/error
(either through the builtins and/or wrapper).

But as I put on cover-letter, I actually tested it by using using on top
of my WIP branch that aims to enable clang build glibc. 

> 
> LGTM.
> 
> Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
> 
>>
>> Checked on aarch64, armhf, x86_64, and i686.
>> ---
>>   debug/tst-fortify.c | 6 +-----
>>   1 file changed, 1 insertion(+), 5 deletions(-)
>>
>> diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c
>> index 20e926751a..5cd9d22feb 100644
>> --- a/debug/tst-fortify.c
>> +++ b/debug/tst-fortify.c
>> @@ -130,7 +130,7 @@ static int num2 = 987654;
>>         chk_fail_ok = 0;                \
>>         FAIL ();                    \
>>       }
>> -#if __USE_FORTIFY_LEVEL >= 2 && (!defined __cplusplus || defined __va_arg_pack)
>> +#if __USE_FORTIFY_LEVEL >= 2
>>   # define CHK_FAIL2_START CHK_FAIL_START
>>   # define CHK_FAIL2_END CHK_FAIL_END
>>   #else
>> @@ -419,7 +419,6 @@ do_test (void)
>>     stpncpy (buf + 6, "cd", l0 + 5);
>>     CHK_FAIL_END
>>   -# if !defined __cplusplus || defined __va_arg_pack
>>     CHK_FAIL_START
>>     sprintf (buf + 8, "%d", num1);
>>     CHK_FAIL_END
>> @@ -439,7 +438,6 @@ do_test (void)
>>     CHK_FAIL_START
>>     swprintf (wbuf + 8, l0 + 3, L"%d", num1);
>>     CHK_FAIL_END
>> -# endif
>>       memcpy (buf, str1 + 2, 9);
>>     CHK_FAIL_START
>> @@ -550,7 +548,6 @@ do_test (void)
>>         FAIL ();
>>     }
>>   -# if !defined __cplusplus || defined __va_arg_pack
>>     CHK_FAIL_START
>>     sprintf (a.buf1 + (O + 7), "%d", num1);
>>     CHK_FAIL_END
>> @@ -562,7 +559,6 @@ do_test (void)
>>     CHK_FAIL_START
>>     snprintf (a.buf1 + (O + 7), l0 + 3, "%d", num2);
>>     CHK_FAIL_END
>> -# endif
>>       memcpy (a.buf1, str1 + (3 - O), 8 + O);
>>     CHK_FAIL_START

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

* Re: [PATCH 06/15] cdefs.h: Add clang fortify directives
  2023-12-21 21:33   ` Joseph Myers
@ 2023-12-22 12:36     ` Adhemerval Zanella Netto
  0 siblings, 0 replies; 26+ messages in thread
From: Adhemerval Zanella Netto @ 2023-12-22 12:36 UTC (permalink / raw)
  To: Joseph Myers; +Cc: libc-alpha, Siddhesh Poyarekar



On 21/12/23 18:33, Joseph Myers wrote:
> On Thu, 21 Dec 2023, Adhemerval Zanella wrote:
> 
>> +#  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_dynamic_object_size_n(n) \
>> +  __attribute__ ((pass_dynamic_object_size (n)))
> 
> I'd expect these to use implementation-namespace macro names __unused__, 
> __pass_object_size__, __pass_dynamic_object_size__; _FORTIFY_SOURCE 
> shouldn't use extra names from the user's namespace, regardless of what 
> compiler is used.
> 

Right, I think I haven't seen them because our conform tests don't actually
check _FORTIFY_SOURCE (as indicated by conform/linknamespace.py comments).
I will fix it.

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

* Re: [PATCH 05/15] debug: Add fortify wprintf tests
  2023-12-21 20:08   ` Siddhesh Poyarekar
@ 2023-12-29 13:56     ` Adhemerval Zanella Netto
  0 siblings, 0 replies; 26+ messages in thread
From: Adhemerval Zanella Netto @ 2023-12-29 13:56 UTC (permalink / raw)
  To: Siddhesh Poyarekar, libc-alpha



On 21/12/23 17:08, Siddhesh Poyarekar wrote:
> 
> 
> On 2023-12-21 13:59, Adhemerval Zanella wrote:
>> Similar to other printf-like ones.  It requires to be in a different
>> process so we can change the orientation of stdout.
>>
>> Checked on aarch64, armhf, x86_64, and i686.
>> ---
>>   debug/Makefile           |   2 +
>>   debug/tst-fortify-wide.c | 104 +++++++++++++++++++++++++++++++++++++++
>>   2 files changed, 106 insertions(+)
>>   create mode 100644 debug/tst-fortify-wide.c
>>
>> diff --git a/debug/Makefile b/debug/Makefile
>> index fdc250e209..ed90ef7030 100644
>> --- a/debug/Makefile
>> +++ b/debug/Makefile
>> @@ -180,6 +180,7 @@ CPPFLAGS-tst-realpath-chk.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
>>   CPPFLAGS-tst-chk-cancel.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
>>   CFLAGS-tst-sprintf-fortify-rdonly.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
>>   CFLAGS-tst-fortify-syslog.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
>> +CFLAGS-tst-fortify-wide.c += $(no-fortify-source),-D_FORTIFY_SOURCE=2
>>     # _FORTIFY_SOURCE tests.
>>   # Auto-generate tests for _FORTIFY_SOURCE for different levels, compilers and
>> @@ -283,6 +284,7 @@ tests = \
>>     tst-backtrace4 \
>>     tst-backtrace5 \
>>     tst-backtrace6 \
>> +  tst-fortify-wide \
>>     tst-longjmp_chk \
>>     tst-longjmp_chk2 \
>>     tst-realpath-chk \
>> diff --git a/debug/tst-fortify-wide.c b/debug/tst-fortify-wide.c
>> new file mode 100644
>> index 0000000000..6947d04fa6
>> --- /dev/null
>> +++ b/debug/tst-fortify-wide.c
>> @@ -0,0 +1,104 @@
>> +/* Fortify check for wprintf.
>> +   Copyright (C) 2004-2023 Free Software Foundation, Inc.
>> +   Copyright The GNU Toolchain Authors.
> 
> It's a new test, so just 2023 and FSF?  Looks OK otherwise.

It is a new test, I will adjust it before commit it.

> 
>> +   This file is part of the GNU C Library.
>> +
>> +   The GNU C Library is free software; you can redistribute it and/or
>> +   modify it under the terms of the GNU Lesser General Public
>> +   License as published by the Free Software Foundation; either
>> +   version 2.1 of the License, or (at your option) any later version.
>> +
>> +   The GNU C Library is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> +   Lesser General Public License for more details.
>> +
>> +   You should have received a copy of the GNU Lesser General Public
>> +   License along with the GNU C Library; if not, see
>> +   <https://www.gnu.org/licenses/>.  */
>> +
>> +#include <setjmp.h>
>> +#include <stdio.h>
>> +#include <wchar.h>
>> +#include <unistd.h>
>> +
>> +#include <support/support.h>
>> +
>> +static volatile int chk_fail_ok;
>> +static volatile int ret;
>> +static jmp_buf chk_fail_buf;
>> +
>> +static void
>> +handler (int sig)
>> +{
>> +  if (chk_fail_ok)
>> +    {
>> +      chk_fail_ok = 0;
>> +      longjmp (chk_fail_buf, 1);
>> +    }
>> +  else
>> +    _exit (127);
>> +}
>> +
>> +static const wchar_t *wstr3 = L"%ls%n%ls%n";
>> +static const wchar_t *wstr4 = L"Hello, ";
>> +static const wchar_t *wstr5 = L"World!\n";
>> +static wchar_t wbuf2[20] = L"%ls";
>> +
>> +#define WFAIL \
>> +  do { wprintf (L"Failure on line %d\n", __LINE__); ret = 1; } while (0)
>> +#define CHK_FAIL_START \
>> +  chk_fail_ok = 1;                \
>> +  if (! setjmp (chk_fail_buf))            \
>> +    {
>> +#define CHK_FAIL_END \
>> +      chk_fail_ok = 0;                \
>> +      WFAIL;                    \
>> +    }
>> +
>> +static int
>> +do_test (void)
>> +{
>> +  set_fortify_handler (handler);
>> +
>> +  int n1, n2;
>> +
>> +  int orientation = fwide (stdout, 1);
>> +  if (orientation <= 0)
>> +    WFAIL;
>> +
>> +  /* Constant literals passed directly are always ok
>> +     (even with warnings about possible bugs from GCC).  */
>> +  if (wprintf (L"%ls%n%ls%n", wstr4, &n1, wstr5, &n2) != 14
>> +      || n1 != 7 || n2 != 14)
>> +    WFAIL;
>> +
>> +  /* In this case the format string is not known at compile time,
>> +     but resides in read-only memory, so is ok.  */
>> +  if (wprintf (wstr3, wstr4, &n1, wstr5, &n2) != 14
>> +      || n1 != 7 || n2 != 14)
>> +    WFAIL;
>> +
>> +  wcpcpy (&wbuf2[3], L"%n%ls%n");
>> +  /* When the format string is writable and contains %n,
>> +     with -D_FORTIFY_SOURCE=2 it causes __chk_fail.  */
>> +  CHK_FAIL_START
>> +  if (wprintf (wbuf2, wstr4, &n1, wstr5, &n1) != 14)
>> +    WFAIL;
>> +  CHK_FAIL_END
>> +
>> +  /* But if there is no %n, even writable format string
>> +     should work.  */
>> +  wbuf2[8] = L'\0';
>> +  if (wprintf (&wbuf2[5], wstr5) != 7)
>> +    WFAIL;
>> +
>> +  /* Check whether missing N$ formats are detected.  */
>> +  CHK_FAIL_START
>> +  wprintf (L"%3$d\n", 1, 2, 3, 4);
>> +  CHK_FAIL_END
>> +
>> +  return ret;
>> +}
>> +
>> +#include <support/test-driver.c>

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

end of thread, other threads:[~2023-12-29 13:56 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-21 18:59 [PATCH 00/15] Improve fortify support with clang Adhemerval Zanella
2023-12-21 18:59 ` [PATCH 01/15] debug: Adapt fortify tests to libsupport Adhemerval Zanella
2023-12-21 19:54   ` Siddhesh Poyarekar
2023-12-21 18:59 ` [PATCH 02/15] debug: Increase tst-fortify checks for compiler without __va_arg_pack support Adhemerval Zanella
2023-12-21 20:02   ` Siddhesh Poyarekar
2023-12-21 21:43     ` Joseph Myers
2023-12-22 12:29     ` Adhemerval Zanella Netto
2023-12-21 18:59 ` [PATCH 03/15] debug: Add fortify dprintf tests Adhemerval Zanella
2023-12-21 20:03   ` Siddhesh Poyarekar
2023-12-21 18:59 ` [PATCH 04/15] debug: Add fortify syslog tests Adhemerval Zanella
2023-12-21 20:06   ` Siddhesh Poyarekar
2023-12-21 18:59 ` [PATCH 05/15] debug: Add fortify wprintf tests Adhemerval Zanella
2023-12-21 20:08   ` Siddhesh Poyarekar
2023-12-29 13:56     ` Adhemerval Zanella Netto
2023-12-21 18:59 ` [PATCH 06/15] cdefs.h: Add clang fortify directives Adhemerval Zanella
2023-12-21 21:33   ` Joseph Myers
2023-12-22 12:36     ` Adhemerval Zanella Netto
2023-12-21 18:59 ` [PATCH 07/15] libio: Improve fortify with clang Adhemerval Zanella
2023-12-21 18:59 ` [PATCH 08/15] string: " Adhemerval Zanella
2023-12-21 18:59 ` [PATCH 09/15] stdlib: " Adhemerval Zanella
2023-12-21 18:59 ` [PATCH 10/15] unistd: " Adhemerval Zanella
2023-12-21 18:59 ` [PATCH 11/15] socket: " Adhemerval Zanella
2023-12-21 18:59 ` [PATCH 12/15] syslog: " Adhemerval Zanella
2023-12-21 18:59 ` [PATCH 13/15] wcsmbs: " Adhemerval Zanella
2023-12-21 18:59 ` [PATCH 14/15] debug: Improve fcntl.h fortify warnings " Adhemerval Zanella
2023-12-21 18:59 ` [PATCH 15/15] debug: Improve mqueue.h " Adhemerval Zanella

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