public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v4 0/6] fcntl fortification
@ 2023-07-30 19:25 Sergey Bugaev
  2023-07-30 19:25 ` [PATCH v4 1/6] Fix calling fcntl64 (fd, F_SETLK, &flock64) Sergey Bugaev
                   ` (6 more replies)
  0 siblings, 7 replies; 15+ messages in thread
From: Sergey Bugaev @ 2023-07-30 19:25 UTC (permalink / raw)
  To: libc-alpha

Hello,

this is the v4 of the fcntl fortification work. v1 was at [0], v2 at
[1], v3 at [2].

[0]: https://sourceware.org/pipermail/libc-alpha/2023-May/148332.html
[1]: https://sourceware.org/pipermail/libc-alpha/2023-May/148569.html
[2]: https://sourceware.org/pipermail/libc-alpha/2023-June/149096.html

Changes since v3:

- Rebased onto the latest master.
- Fixed the bug found by Linaro CI (thanks!): F_DUPFD_CLOEXEC is not
  always defined, so it has to be surrounded by ifdef checks too.
- This patchset is now compatible with Frédéric Bérat's work on
  fortifying glibc itself / --enable-fortify-source!
- Fixed a bug: F_GETLK etc may have the same values as F_GETLK64 etc, so
  the previous version of this patchset would complain about F_GETLK64
  usage with struct flock64, since the check for F_GETLK happened first.
  This is now fixed by accepting both struct flock and struct flock64 if
  F_GETLK has the same value as F_GETLK64.
- Found and fixed a few cases of what seems to be actual commmand / type
  confusion in the tests! Specifically, it was calling
  fcntl64 (fd, F_SETLK, &flock64)
  in a few places, which is incorrect according to my understanding and
  my tests of Linux behavior. Please see the first patch for some more
  details, and please correct me if I'm wrong!

I've checked that this builds and passes tests (there are a few test
failures, but they all seem unrelated) for x86_64-linux-gnu and
i686-linux-gnu with and without --enable-fortify-source. I've also
checked that it builds for x86_64-gnu with and without
--enable-fortify-source, but I haven't run the tests.

Sergey

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

* [PATCH v4 1/6] Fix calling fcntl64 (fd, F_SETLK, &flock64)
  2023-07-30 19:25 [PATCH v4 0/6] fcntl fortification Sergey Bugaev
@ 2023-07-30 19:25 ` Sergey Bugaev
  2023-07-31 17:50   ` Adhemerval Zanella Netto
  2023-07-30 19:25 ` [PATCH v4 2/6] support: Add support_fcntl_support_ofd_locks () Sergey Bugaev
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: Sergey Bugaev @ 2023-07-30 19:25 UTC (permalink / raw)
  To: libc-alpha; +Cc: Florian Weimer

F_GETLK, F_SETLK, F_SETLKW must always be used with the regular struct
flock, not struct flock64, even if the function being called is fcntl64.
There are separate commands, F_GETLK64, F_SETLK64, and F_SETLKW64, that
are used with struct flock64. This is in contrast with the OFD locking
commands (F_OFD_GETLK, F_OFD_SETLK, F_OFD_SETLKW) that must be used with
struct flock in fcntl calls, and with struct flock64 in fcntl64 calls.

These mistakes were spotted by enabling the fcntl fortification that is
added in a following commit.

Fixes: 61d3db428176d9d0822e4e680305fe34285edff2
"login: pututxline could fail to overwrite existing entries [BZ #24902]"
Fixes: f6233ab412c3bebebacf65745e775e01506dd58d
"Linux: Add io/tst-o_path-locks test"

Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>
---

Please tell me if I'm misunderstanding this!

 login/tst-pututxline-lockfail.c            | 2 +-
 sysdeps/unix/sysv/linux/tst-o_path-locks.c | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/login/tst-pututxline-lockfail.c b/login/tst-pututxline-lockfail.c
index 214d1106..ca82ba42 100644
--- a/login/tst-pututxline-lockfail.c
+++ b/login/tst-pututxline-lockfail.c
@@ -77,7 +77,7 @@ subprocess_lock_file (void)
      .l_type = F_RDLCK,
      fl.l_whence = SEEK_SET,
     };
-  TEST_COMPARE (fcntl64 (fd, F_SETLKW, &fl), 0);
+  TEST_COMPARE (fcntl64 (fd, F_SETLKW64, &fl), 0);
 
   /* Signal to the main process that the lock has been acquired.  */
   xpthread_barrier_wait (barrier);
diff --git a/sysdeps/unix/sysv/linux/tst-o_path-locks.c b/sysdeps/unix/sysv/linux/tst-o_path-locks.c
index 0036868d..c3d1c0dc 100644
--- a/sysdeps/unix/sysv/linux/tst-o_path-locks.c
+++ b/sysdeps/unix/sysv/linux/tst-o_path-locks.c
@@ -39,7 +39,7 @@ subprocess (void *closure)
 {
   int fd = xopen (path, O_RDWR, 0);
   struct flock64 lock = { .l_type = F_WRLCK, };
-  int ret = fcntl64 (fd, F_SETLK, &lock);
+  int ret = fcntl64 (fd, F_SETLK64, &lock);
   if (ret == 0)
     *shared_errno = 0;
   else
@@ -76,7 +76,7 @@ do_test (void)
   TEST_VERIFY (!probe_lock ());
 
   struct flock64 lock = { .l_type = F_WRLCK, };
-  TEST_COMPARE (fcntl64 (fd, F_SETLK, &lock), 0);
+  TEST_COMPARE (fcntl64 (fd, F_SETLK64, &lock), 0);
 
   /* The lock has been acquired.  */
   TEST_VERIFY (probe_lock ());
@@ -87,7 +87,7 @@ do_test (void)
   TEST_VERIFY (!probe_lock ());
 
   /* But not if it is an O_PATH descriptor.  */
-  TEST_COMPARE (fcntl64 (fd, F_SETLK, &lock), 0);
+  TEST_COMPARE (fcntl64 (fd, F_SETLK64, &lock), 0);
   xclose (xopen (path, O_PATH, 0));
   TEST_VERIFY (probe_lock ());
 
-- 
2.41.0


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

* [PATCH v4 2/6] support: Add support_fcntl_support_ofd_locks ()
  2023-07-30 19:25 [PATCH v4 0/6] fcntl fortification Sergey Bugaev
  2023-07-30 19:25 ` [PATCH v4 1/6] Fix calling fcntl64 (fd, F_SETLK, &flock64) Sergey Bugaev
@ 2023-07-30 19:25 ` Sergey Bugaev
  2023-07-30 19:25 ` [PATCH v4 3/6] cdefs.h: Define __glibc_warn_system_headers_{begin,end} Sergey Bugaev
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Sergey Bugaev @ 2023-07-30 19:25 UTC (permalink / raw)
  To: libc-alpha; +Cc: Adhemerval Zanella

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>
---
 support/Makefile                          |  1 +
 support/support.h                         |  3 ++
 support/support_fcntl_support_ofd_locks.c | 44 +++++++++++++++++++++++
 3 files changed, 48 insertions(+)
 create mode 100644 support/support_fcntl_support_ofd_locks.c

diff --git a/support/Makefile b/support/Makefile
index 917a858b..ab5d46b8 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -58,6 +58,7 @@ libsupport-routines = \
   support_descriptors \
   support_enter_mount_namespace \
   support_enter_network_namespace \
+  support_fcntl_support_ofd_locks \
   support_format_address_family \
   support_format_addrinfo \
   support_format_dns_packet \
diff --git a/support/support.h b/support/support.h
index b7f76bf0..e20d2ce7 100644
--- a/support/support.h
+++ b/support/support.h
@@ -178,6 +178,9 @@ static __inline bool support_itimer_support_time64 (void)
 #endif
 }
 
+/* Return true if the kernel/file supports open file description locks.  */
+extern bool support_fcntl_support_ofd_locks (int fd);
+
 /* Return true if stat supports nanoseconds resolution.  PATH is used
    for tests and its ctime may change.  */
 extern bool support_stat_nanoseconds (const char *path);
diff --git a/support/support_fcntl_support_ofd_locks.c b/support/support_fcntl_support_ofd_locks.c
new file mode 100644
index 00000000..fb197a70
--- /dev/null
+++ b/support/support_fcntl_support_ofd_locks.c
@@ -0,0 +1,44 @@
+/* Return whether the kernel/file supports OFD locks.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   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 <support/support.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+
+bool
+support_fcntl_support_ofd_locks (int fd)
+{
+#ifdef F_OFD_GETLK
+  int res;
+  struct flock flock;
+  memset (&flock, 0, sizeof (flock));
+
+  flock.l_type = F_WRLCK;
+  flock.l_whence = SEEK_SET;
+  flock.l_start = 0;
+  flock.l_len = INT32_MAX;
+  flock.l_pid = 0;
+
+  res = fcntl (fd, F_OFD_GETLK, &flock);
+  return res != -1 || errno != EINVAL;
+#else
+  (void) fd;
+  return false;
+#endif
+}
-- 
2.41.0


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

* [PATCH v4 3/6] cdefs.h: Define __glibc_warn_system_headers_{begin,end}
  2023-07-30 19:25 [PATCH v4 0/6] fcntl fortification Sergey Bugaev
  2023-07-30 19:25 ` [PATCH v4 1/6] Fix calling fcntl64 (fd, F_SETLK, &flock64) Sergey Bugaev
  2023-07-30 19:25 ` [PATCH v4 2/6] support: Add support_fcntl_support_ofd_locks () Sergey Bugaev
@ 2023-07-30 19:25 ` Sergey Bugaev
  2023-07-30 19:25 ` [PATCH v4 4/6] cdefs.h: Enable __errordecl & __warnattr for Clang 14+ Sergey Bugaev
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Sergey Bugaev @ 2023-07-30 19:25 UTC (permalink / raw)
  To: libc-alpha; +Cc: Adhemerval Zanella

By default, GCC supresses warnings inside "system headers". Moreover, it
also supresses warnings resulting from expansion of macros defined in
system headers, even in the expansion itself happens in user code. This
may be desirable most of the time because the user cannot do anything
about the mistakes of the system headers, but sometimes causing a
warning is an intentional effect that a macro has, in which case this
GCC feature gets in a way.

GCC allows turning off the warning suspension feature by passing
-Wsystem-headers; however, that turns it off globally. But by using
"#pragma GCC diagnostic" it can be made to only apply to the relevant
macro definition, in which case GCC only does not supress warnings
resulting from expansion of that one macro.

To that end, introduce __glibc_warn_system_headers_begin and
__glibc_warn_system_headers_end macros that can be used to surround a
macro definition and ensure that warnings inside the macro are not
supressed:

    __glibc_warn_system_headers_begin
    #define foo(x) bar_warn (x)
    __glibc_warn_system_headers_end

This will be used in a following patch which turns fcntl and fcntl64
into macros that cause warnings on argument type mismatch.

Note that "#pragma GCC diagnostic warning" normally overrides any
diagnostic options specified on the command line, and so can even
downgrade severity of a diagnostic from an error to a warning (if, for
instance, -Werror is in effect). But this is not a concern here, since
the actual warning that gets emitted is not "-Wsystem-headers", but some
other specific warning; "-Wsystem-headers" is only used to disable its
supression. So passing -Werror still causes the specific warning to be
treated as an error, and to fail the compilation.

Clang does not seem to support turning -Wsystem-headers on and off with
a pragma, but does not seem to suppress warnings from system-defined
macros either. Hence, the macros added by this patch expand to nothing
under Clang.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>
---
 misc/sys/cdefs.h | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
index 90c21e27..15587848 100644
--- a/misc/sys/cdefs.h
+++ b/misc/sys/cdefs.h
@@ -657,6 +657,21 @@ _Static_assert (0, "IEEE 128-bits long double requires redirection on this platf
 # define __glibc_macro_warning(msg)
 #endif
 
+/* __glibc_warn_system_headers_begin starts a block of code where warnings
+   produced by expanding macros defined in system headers will *not* be
+   supressed.  __glibc_warn_system_headers_end ends such a block.  */
+#if __GNUC_PREREQ (4,8)
+# define __glibc_warn_system_headers1(message) _Pragma (#message)
+# define __glibc_warn_system_headers_begin \
+  __glibc_warn_system_headers1 (GCC diagnostic push) \
+  __glibc_warn_system_headers1 (GCC diagnostic warning "-Wsystem-headers")
+# define __glibc_warn_system_headers_end \
+  __glibc_warn_system_headers1 (GCC diagnostic pop)
+#else
+# define __glibc_warn_system_headers_begin
+# define __glibc_warn_system_headers_end
+#endif
+
 /* Generic selection (ISO C11) is a C-only feature, available in GCC
    since version 4.9.  Previous versions do not provide generic
    selection, even though they might set __STDC_VERSION__ to 201112L,
-- 
2.41.0


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

* [PATCH v4 4/6] cdefs.h: Enable __errordecl & __warnattr for Clang 14+
  2023-07-30 19:25 [PATCH v4 0/6] fcntl fortification Sergey Bugaev
                   ` (2 preceding siblings ...)
  2023-07-30 19:25 ` [PATCH v4 3/6] cdefs.h: Define __glibc_warn_system_headers_{begin,end} Sergey Bugaev
@ 2023-07-30 19:25 ` Sergey Bugaev
  2023-08-02 17:23   ` Adhemerval Zanella Netto
  2023-07-30 19:26 ` [PATCH v4 5/6] io: Add FORTIFY_SOURCE check for fcntl arguments Sergey Bugaev
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: Sergey Bugaev @ 2023-07-30 19:25 UTC (permalink / raw)
  To: libc-alpha

Clang 14 (released in March 2022) has added support for
attribute ((error)) and attribute ((warning)). Enable their usage when
Clang 14 or later is detected, to get nicer diagnostics.

https://reviews.llvm.org/D106030
https://github.com/llvm/llvm-project/commit/846e562dcc6a9a611d844dc0d123da95629a0567

Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>
---
 misc/sys/cdefs.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
index 15587848..5c98f393 100644
--- a/misc/sys/cdefs.h
+++ b/misc/sys/cdefs.h
@@ -208,7 +208,7 @@
       : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s))))
 #endif
 
-#if __GNUC_PREREQ (4,3)
+#if __GNUC_PREREQ (4,3) || __glibc_clang_prereq (14,0)
 # define __warnattr(msg) __attribute__((__warning__ (msg)))
 # define __errordecl(name, msg) \
   extern void name (void) __attribute__((__error__ (msg)))
-- 
2.41.0


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

* [PATCH v4 5/6] io: Add FORTIFY_SOURCE check for fcntl arguments
  2023-07-30 19:25 [PATCH v4 0/6] fcntl fortification Sergey Bugaev
                   ` (3 preceding siblings ...)
  2023-07-30 19:25 ` [PATCH v4 4/6] cdefs.h: Enable __errordecl & __warnattr for Clang 14+ Sergey Bugaev
@ 2023-07-30 19:26 ` Sergey Bugaev
  2023-07-30 19:54   ` Sergey Bugaev
  2023-08-02 19:46   ` Adhemerval Zanella Netto
  2023-07-30 19:26 ` [PATCH v4 6/6] io: Also verify 2-arg fctnl calls at runtime Sergey Bugaev
  2023-07-31 14:40 ` [PATCH v4 0/6] fcntl fortification Zack Weinberg
  6 siblings, 2 replies; 15+ messages in thread
From: Sergey Bugaev @ 2023-07-30 19:26 UTC (permalink / raw)
  To: libc-alpha

Both open () and fcntl () are "overloaded" to accept either 2 or 3
arguments; whether the last argument is required (and, in case of fcntl,
the type of the third argument) depends on the values of the previous
arguments. Since C provides no native support for function overloading,
this is implemented by making these functions vararg. Unfortunately,
this means the compiler is unable to check the number of arguments and
their types for correctness at compile time, and will not diagnose any
mistakes.

To help with this, when FORTIFY_SOURCE is enabled, the special fcntl2.h
header replaces open () with a wrapper that checks the passed number of
arguments, raising a compile-time or run-time error on mismatch. This
commit adds similar handling for fcntl (). Additionally, the fcntl ()
wrapper tries to check that the type of the 3rd argument (if any)
matches the type that the command (passed in the 2nd argument) expects.

tst-ofdlocks-compat is excluded from fortification, since it
intentionally calls fcntl () with an argument of a wrong type while
linking to an old symbol version. The fcntl () call in test-errno is
similarly excluded from fortification, since it intentionally contains
two errors (bad file descriptor, and missing the required 3rd argument)
and tests for getting the expected error code.

Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>
---

Reposting the concern from v3:
In manual/maint.texi, how would I properly update the command for
generating the list of fortified functions to include fcntl / fcntl64 in
absence of __fcntl_2? (The next patch does make it work with __fcntl_2.)

 debug/tst-fortify.c              | 168 +++++++++++
 include/bits/fcntl3.h            |   1 +
 io/Makefile                      |   3 +
 io/bits/fcntl3.h                 | 471 +++++++++++++++++++++++++++++++
 io/fcntl.h                       |   6 +
 manual/maint.texi                |   9 +-
 posix/test-errno.c               |   4 +-
 sysdeps/unix/sysv/linux/Makefile |   4 +
 8 files changed, 663 insertions(+), 3 deletions(-)
 create mode 100644 include/bits/fcntl3.h
 create mode 100644 io/bits/fcntl3.h

diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c
index 3744aada..98654299 100644
--- a/debug/tst-fortify.c
+++ b/debug/tst-fortify.c
@@ -36,6 +36,8 @@
 #include <sys/select.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <support/support.h>
+#include <support/xunistd.h>
 
 #ifndef _GNU_SOURCE
 # define MEMPCPY memcpy
@@ -78,6 +80,15 @@ do_prepare (void)
     }
 }
 
+/* Return VALUE, but do it in a way that the compiler cannot
+   see that it's a compile-time constant.  */
+static inline int
+hide_constant (int value)
+{
+  asm ("" : "+rm" (value));
+  return value;
+}
+
 volatile int chk_fail_ok;
 volatile int ret;
 jmp_buf chk_fail_buf;
@@ -1811,6 +1822,163 @@ do_test (void)
   ppoll (fds, l0 + 2, NULL, NULL);
   CHK_FAIL_END
 # endif
+#endif
+
+  /* Check that we can do basic fcntl operations, both ones that require
+     the third argument, and ones that do not.  */
+  res = fcntl (STDIN_FILENO, F_GETFD);
+  TEST_COMPARE (res, 0);
+  res = fcntl (STDIN_FILENO, F_SETFD, 0);
+  TEST_COMPARE (res, 0);
+
+  /* Check that we can successfully use F_GETLK with struct flock, even though
+     F_GETLK might have the same value as F_GETLK64.  */
+  {
+    struct flock flock;
+    memset (&flock, 0, sizeof (flock));
+    flock.l_type = F_WRLCK;
+    flock.l_whence = SEEK_SET;
+    flock.l_start = 1234;
+    flock.l_len = 5678;
+    flock.l_pid = 0;
+
+    (void) fcntl (STDIN_FILENO, F_GETLK, &flock);
+  }
+
+#ifdef F_OFD_GETLK
+  /* Check for confusion between 32- and 64-bit versions of the fcntl
+     interface.  */
+  int lockfd1 = xopen (temp_filename, O_RDWR, 0);
+  int lockfd2 = xopen (temp_filename, O_RDWR, 0);
+
+  int ofd_locks_supported = support_fcntl_support_ofd_locks (lockfd1);
+
+  if (ofd_locks_supported)
+    {
+      struct flock flock;
+
+      memset (&flock, 0, sizeof (flock));
+      flock.l_type = F_WRLCK;
+      flock.l_whence = SEEK_SET;
+      flock.l_start = 1234;
+      flock.l_len = 5678;
+      flock.l_pid = 0;
+
+      res = fcntl (lockfd1, F_OFD_SETLK, &flock);
+      TEST_COMPARE (res, 0);
+
+      memset (&flock, 0, sizeof (flock));
+      flock.l_type = F_RDLCK;
+      flock.l_whence = SEEK_SET;
+      flock.l_start = 3542;
+      flock.l_len = 411;
+      flock.l_pid = 0;
+
+      res = fcntl (lockfd2, F_OFD_GETLK, &flock);
+      TEST_COMPARE (res, 0);
+      /* Check that we get the expected values.  */
+      TEST_COMPARE (flock.l_type, F_WRLCK);
+      TEST_COMPARE (flock.l_whence, SEEK_SET);
+      TEST_COMPARE (flock.l_start, 1234);
+      TEST_COMPARE (flock.l_len, 5678);
+      TEST_COMPARE (flock.l_pid, -1);
+    }
+#endif
+
+  /* Check that we can do fcntl operations with CMD that is not constant
+     at compile time.  */
+  res = fcntl (STDIN_FILENO, hide_constant (F_GETFD));
+  TEST_COMPARE (res, 0);
+  res = fcntl (STDIN_FILENO, hide_constant (F_SETFD), 0);
+  TEST_COMPARE (res, 0);
+
+#ifdef F_OFD_GETLK
+  if (ofd_locks_supported)
+    {
+      struct flock flock;
+
+      memset (&flock, 0, sizeof (flock));
+      flock.l_type = F_RDLCK;
+      flock.l_whence = SEEK_SET;
+      flock.l_start = 3542;
+      flock.l_len = 411;
+      flock.l_pid = 0;
+
+      res = fcntl (lockfd2, hide_constant (F_OFD_GETLK), &flock);
+      TEST_COMPARE (res, 0);
+      /* Check that we get the expected values.  */
+      TEST_COMPARE (flock.l_type, F_WRLCK);
+      TEST_COMPARE (flock.l_whence, SEEK_SET);
+      TEST_COMPARE (flock.l_start, 1234);
+      TEST_COMPARE (flock.l_len, 5678);
+      TEST_COMPARE (flock.l_pid, -1);
+    }
+#endif
+
+#if defined (__USE_LARGEFILE64) || defined (__USE_TIME_BITS64)
+  /* Also check fcntl64 ().  */
+  res = fcntl64 (STDIN_FILENO, F_GETFD);
+  TEST_COMPARE (res, 0);
+  res = fcntl64 (STDIN_FILENO, F_SETFD, 0);
+  TEST_COMPARE (res, 0);
+  res = fcntl64 (STDIN_FILENO, hide_constant (F_GETFD));
+  TEST_COMPARE (res, 0);
+  res = fcntl64 (STDIN_FILENO, hide_constant (F_SETFD), 0);
+  TEST_COMPARE (res, 0);
+
+  /* Check that we can successfully use F_GETLK64 with struct flock64, even
+     though F_GETLK might have the same value as F_GETLK64.  */
+  {
+    struct flock64 flock64;
+    memset (&flock64, 0, sizeof (flock64));
+    flock64.l_type = F_WRLCK;
+    flock64.l_whence = SEEK_SET;
+    flock64.l_start = 1234;
+    flock64.l_len = 5678;
+    flock64.l_pid = 0;
+
+    (void) fcntl64 (STDIN_FILENO, F_GETLK64, &flock64);
+  }
+
+#ifdef F_OFD_GETLK
+  if (ofd_locks_supported)
+    {
+      struct flock64 flock64;
+
+      memset (&flock64, 0, sizeof (flock64));
+      flock64.l_type = F_RDLCK;
+      flock64.l_whence = SEEK_SET;
+      flock64.l_start = 3542;
+      flock64.l_len = 411;
+      flock64.l_pid = 0;
+
+      res = fcntl64 (lockfd2, F_OFD_GETLK, &flock64);
+      TEST_COMPARE (res, 0);
+      /* Check that we get the expected values.  */
+      TEST_COMPARE (flock64.l_type, F_WRLCK);
+      TEST_COMPARE (flock64.l_whence, SEEK_SET);
+      TEST_COMPARE (flock64.l_start, 1234);
+      TEST_COMPARE (flock64.l_len, 5678);
+      TEST_COMPARE (flock64.l_pid, -1);
+
+      memset (&flock64, 0, sizeof (flock64));
+      flock64.l_type = F_RDLCK;
+      flock64.l_whence = SEEK_SET;
+      flock64.l_start = 3542;
+      flock64.l_len = 411;
+      flock64.l_pid = 0;
+
+      res = fcntl64 (lockfd2, hide_constant (F_OFD_GETLK), &flock64);
+      TEST_COMPARE (res, 0);
+      /* Check that we get the expected values.  */
+      TEST_COMPARE (flock64.l_type, F_WRLCK);
+      TEST_COMPARE (flock64.l_whence, SEEK_SET);
+      TEST_COMPARE (flock64.l_start, 1234);
+      TEST_COMPARE (flock64.l_len, 5678);
+      TEST_COMPARE (flock64.l_pid, -1);
+    }
+#endif
+
 #endif
 
   return ret;
diff --git a/include/bits/fcntl3.h b/include/bits/fcntl3.h
new file mode 100644
index 00000000..d31154f6
--- /dev/null
+++ b/include/bits/fcntl3.h
@@ -0,0 +1 @@
+#include "../../io/bits/fcntl3.h"
diff --git a/io/Makefile b/io/Makefile
index 6ccc0e86..0c43881f 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -25,6 +25,7 @@ include ../Makeconfig
 headers := \
   bits/fcntl.h \
   bits/fcntl2.h \
+  bits/fcntl3.h \
   bits/poll.h \
   bits/poll2.h \
   bits/stat.h \
@@ -153,6 +154,8 @@ routines := \
 routines_no_fortify += \
   getcwd \
   getwd \
+  fcntl \
+  fcntl64 \
   open \
   open64 \
   openat \
diff --git a/io/bits/fcntl3.h b/io/bits/fcntl3.h
new file mode 100644
index 00000000..9016d37e
--- /dev/null
+++ b/io/bits/fcntl3.h
@@ -0,0 +1,471 @@
+/* Checking macros for fcntl functions.
+   Copyright (C) 2007-2023 Free Software Foundation, Inc.
+   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/>.  */
+
+#ifndef	_FCNTL_H
+# error "Never include <bits/fcntl3.h> directly; use <fcntl.h> instead."
+#endif
+
+#ifndef __USE_TIME_BITS64
+
+# ifndef __USE_FILE_OFFSET64
+extern int __REDIRECT (__fcntl_alias, (int __fd, int __cmd, ...), fcntl);
+extern int __REDIRECT (__fcntl_warn, (int __fd, int __cmd, ...), fcntl)
+  __warnattr ("fcntl argument has wrong type for this command");
+# else
+extern int __REDIRECT (__fcntl_alias, (int __fd, int __cmd, ...), fcntl64);
+extern int __REDIRECT (__fcntl_warn, (int __fd, int __cmd, ...), fcntl64)
+  __warnattr ("fcntl argument has wrong type for this command");
+# endif /* __USE_FILE_OFFSET64 */
+
+# ifdef __USE_LARGEFILE64
+extern int __REDIRECT (__fcntl64_alias, (int __fd, int __cmd, ...), fcntl64);
+extern int __REDIRECT (__fcntl64_warn, (int __fd, int __cmd, ...), fcntl64)
+  __warnattr ("fcntl64 argument has wrong type for this command");
+# endif
+
+#else /* __USE_TIME_BITS64 */
+
+extern int __REDIRECT_NTH (__fcntl_alias, (int __fd, int __cmd, ...),
+			   __fcntl_time64);
+extern int __REDIRECT_NTH (__fcntl64_alias, (int __fd, int __cmd, ...),
+			   __fcntl_time64);
+extern int __REDIRECT (__fcntl_warn, (int __fd, int __cmd, ...),
+                        __fcntl_time64)
+  __warnattr ("fcntl argument has wrong type for this command");
+extern int __REDIRECT (__fcntl64_warn, (int __fd, int __cmd, ...),
+                        __fcntl_time64)
+  __warnattr ("fcntl64 argument has wrong type for this command");
+
+#endif /* __USE_TIME_BITS64 */
+
+
+/* Whether the fcntl CMD is known to require an argument.  */
+__extern_always_inline int
+__fcntl_requires_arg (int __cmd)
+{
+  switch (__cmd)
+    {
+    case F_DUPFD:
+#ifdef F_DUPFD_CLOEXEC
+    case F_DUPFD_CLOEXEC:
+#endif
+    case F_SETFD:
+    case F_SETFL:
+#ifdef F_SETLK
+    case F_SETLK:
+    case F_SETLKW:
+    case F_GETLK:
+#endif
+#ifdef F_OFD_SETLK
+    case F_OFD_SETLK:
+    case F_OFD_SETLKW:
+    case F_OFD_GETLK:
+#endif
+#ifdef F_SETOWN
+    case F_SETOWN:
+#endif
+#ifdef F_GETOWN_EX
+    case F_GETOWN_EX:
+    case F_SETOWN_EX:
+    case F_SETSIG:
+#endif
+#ifdef F_SETLEASE
+    case F_SETLEASE:
+    case F_NOTIFY:
+    case F_SETPIPE_SZ:
+    case F_ADD_SEALS:
+    case F_GET_RW_HINT:
+    case F_SET_RW_HINT:
+    case F_GET_FILE_RW_HINT:
+    case F_SET_FILE_RW_HINT:
+#endif
+      return 1;
+
+    default:
+      return 0;
+  }
+}
+
+/* Whether the fcntl CMD requires an int argument.  */
+__extern_always_inline int
+__fcntl_is_int (int __cmd)
+{
+  switch (__cmd)
+    {
+    case F_DUPFD:
+#ifdef F_DUPFD_CLOEXEC
+    case F_DUPFD_CLOEXEC:
+#endif
+    case F_SETFD:
+    case F_SETFL:
+#ifdef F_SETOWN
+    case F_SETOWN:
+#endif
+#ifdef F_SETSIG
+    case F_SETSIG:
+#endif
+#ifdef F_SETLEASE
+    case F_SETLEASE:
+    case F_NOTIFY:
+    case F_SETPIPE_SZ:
+    case F_ADD_SEALS:
+#endif
+      return 1;
+
+    default:
+      return 0;
+    }
+}
+
+/* Whether the fcntl CMD requires a (const uint64_t *) argument.  */
+__extern_always_inline int
+__fcntl_is_const_uint64_t_ptr (int __cmd)
+{
+  switch (__cmd)
+    {
+#ifdef F_SET_RW_HINT
+    case F_SET_RW_HINT:
+    case F_SET_FILE_RW_HINT:
+      return 1;
+#endif
+
+    default:
+      return 0;
+    }
+}
+
+
+/* Whether the fcntl CMD requires an (uint64_t *) argument.  */
+__extern_always_inline int
+__fcntl_is_uint64_t_ptr (int __cmd)
+{
+  switch (__cmd)
+    {
+#ifdef F_GET_RW_HINT
+    case F_GET_RW_HINT:
+    case F_GET_FILE_RW_HINT:
+      return 1;
+#endif
+
+    default:
+      return 0;
+    }
+}
+
+/* Whether the fcntl CMD requires a (const struct f_owner_ex *) argument.  */
+__extern_always_inline int
+__fcntl_is_const_fowner_ex (int __cmd)
+{
+  switch (__cmd)
+    {
+#ifdef F_SETOWN_EX
+    case F_SETOWN_EX:
+      return 1;
+#endif
+
+    default:
+      return 0;
+  }
+}
+
+/* Whether the fcntl CMD requires a (struct f_owner_ex *) argument.  */
+__extern_always_inline int
+__fcntl_is_fowner_ex (int __cmd)
+{
+  switch (__cmd)
+    {
+#ifdef F_GETOWN_EX
+    case F_GETOWN_EX:
+      return 1;
+#endif
+
+    default:
+      return 0;
+  }
+}
+
+/* Whether the fcntl CMD requires either a (const struct flock *) argument
+   or a (const struct flock64 *) argument.  */
+__extern_always_inline int
+__fcntl_is_const_flock_or_64 (int __cmd)
+{
+  switch (__cmd)
+    {
+#if defined (F_SETLK) && defined (F_SETLK64) && F_SETLK == F_SETLK64
+    case F_SETLK:
+    case F_SETLKW:
+      return 1;
+#endif
+
+    default:
+      return 0;
+    }
+}
+
+/* Whether the fcntl CMD requires a (const struct flock *) argument.  */
+__extern_always_inline int
+__fcntl_is_const_flock (int __cmd, int __is_fcntl64)
+{
+  (void) __is_fcntl64;
+  switch (__cmd)
+    {
+#ifdef F_SETLK
+    case F_SETLK:
+    case F_SETLKW:
+      return 1;
+#endif
+
+#ifdef F_OFD_SETLK
+    case F_OFD_SETLK:
+    case F_OFD_SETLKW:
+      return !__is_fcntl64;
+#endif
+
+    default:
+      return 0;
+    }
+}
+
+/* Whether the fcntl CMD requires either a (struct flock *) argument
+   or a (struct flock64 *) argument.  */
+__extern_always_inline int
+__fcntl_is_flock_or_64 (int __cmd)
+{
+  switch (__cmd)
+    {
+#if defined (F_GETLK) && defined (F_GETLK64) && F_GETLK == F_GETLK64
+    case F_GETLK:
+      return 1;
+#endif
+
+    default:
+      return 0;
+    }
+}
+
+
+/* Whether the fcntl CMD requires a (struct flock *) argument.  */
+__extern_always_inline int
+__fcntl_is_flock (int __cmd, int __is_fcntl64)
+{
+  (void) __is_fcntl64;
+  switch (__cmd)
+    {
+#ifdef F_GETLK
+    case F_GETLK:
+      return 1;
+#endif
+
+#ifdef F_OFD_GETLK
+    case F_OFD_GETLK:
+      return !__is_fcntl64;
+#endif
+
+    default:
+      return 0;
+    }
+}
+
+/* Whether the fcntl CMD requires a (const struct flock64 *) argument.  */
+__extern_always_inline int
+__fcntl_is_const_flock64 (int __cmd, int __is_fcntl64)
+{
+  (void) __is_fcntl64;
+  switch (__cmd)
+    {
+#ifdef F_SETLK64
+    case F_SETLK64:
+    case F_SETLKW64:
+      return 1;
+#endif
+
+#ifdef F_OFD_SETLK
+    case F_OFD_SETLK:
+    case F_OFD_SETLKW:
+      return __is_fcntl64;
+#endif
+
+    default:
+      return 0;
+    }
+}
+
+/* Whether the fcntl CMD requires a (struct flock64 *) argument.  */
+__extern_always_inline int
+__fcntl_is_flock64 (int __cmd, int __is_fcntl64)
+{
+  (void) __is_fcntl64;
+  switch (__cmd)
+    {
+#ifdef F_GETLK64
+    case F_GETLK64:
+      return 1;
+#endif
+
+#ifdef F_OFD_GETLK
+    case F_OFD_GETLK:
+      return __is_fcntl64;
+#endif
+
+    default:
+      return 0;
+    }
+}
+
+#ifndef __cplusplus
+
+# define __fcntl_types_compatible(arg, type)				      \
+  __builtin_types_compatible_p (__typeof (arg), type)
+
+#else
+
+extern "C++" {
+
+template<typename, typename>
+struct __fcntl_types_compatible_helper
+{
+  __always_inline static int
+  __compatible ()
+  {
+    return 0;
+  }
+};
+
+template<typename __T>
+struct __fcntl_types_compatible_helper<__T, __T>
+{
+  __always_inline static int
+  __compatible ()
+  {
+    return 1;
+  }
+};
+
+# define __fcntl_types_compatible(arg, type)				      \
+  __fcntl_types_compatible_helper<__typeof (arg), type>::__compatible ()
+
+} /* extern C++ */
+
+#endif /* __cplusplus */
+
+#define __fcntl_type_check_int(arg) __fcntl_types_compatible (arg, int)
+
+#define __fcntl_type_check_const_uint64_t_ptr(arg)			      \
+ (__fcntl_types_compatible (arg, const __uint64_t *)			      \
+  || __fcntl_types_compatible (arg, __uint64_t *))
+
+#define __fcntl_type_check_uint64_t_ptr(arg)				      \
+  __fcntl_types_compatible (arg, __uint64_t *)
+
+#define __fcntl_type_check_const_fowner_ex(arg)				      \
+  (__fcntl_types_compatible (arg, const struct f_owner_ex *)		      \
+   || __fcntl_types_compatible (arg, struct f_owner_ex *))
+
+#define __fcntl_type_check_fowner_ex(arg)				      \
+  __fcntl_types_compatible (arg, struct f_owner_ex *)
+
+#define __fcntl_type_check_const_flock(arg)				      \
+  (__fcntl_types_compatible (arg, const struct flock *)			      \
+   || __fcntl_types_compatible (arg, struct flock *))
+
+#define __fcntl_type_check_flock(arg)					      \
+  __fcntl_types_compatible (arg, struct flock *)
+
+#ifdef __USE_LARGEFILE64
+
+# define __fcntl_type_check_const_flock64(arg)				      \
+  (__fcntl_types_compatible (arg, const struct flock64 *)		      \
+   || __fcntl_types_compatible (arg, struct flock64 *))
+
+# define __fcntl_type_check_flock64(arg)				      \
+  __fcntl_types_compatible (arg, struct flock64 *)
+
+#else
+
+# define __fcntl_type_check_const_flock64(arg) 0
+# define __fcntl_type_check_flock64(arg) 0
+
+#endif /* __USE_LARGEFILE64 */
+
+#define __fcntl_type_check_const_flock_or_64(arg)			      \
+  (__fcntl_type_check_const_flock (arg)					      \
+   || __fcntl_type_check_const_flock64 (arg))
+
+#define __fcntl_type_check_flock_or_64(arg)				      \
+  (__fcntl_type_check_flock (arg) || __fcntl_type_check_flock64 (arg))
+
+#define __fcntl_type_check(cmd, arg, is_fcntl64)			      \
+  (__fcntl_is_int (cmd) ? __fcntl_type_check_int (arg) :		      \
+   __fcntl_is_const_uint64_t_ptr (cmd)					      \
+     ? __fcntl_type_check_const_uint64_t_ptr (arg) :			      \
+   __fcntl_is_uint64_t_ptr (cmd) ? __fcntl_type_check_uint64_t_ptr (arg) :    \
+   __fcntl_is_const_fowner_ex (cmd)					      \
+     ? __fcntl_type_check_const_fowner_ex (arg) :			      \
+   __fcntl_is_fowner_ex (cmd) ? __fcntl_type_check_fowner_ex (arg) :	      \
+   __fcntl_is_const_flock_or_64 (cmd)					      \
+     ? __fcntl_type_check_const_flock_or_64 (arg) :			      \
+   __fcntl_is_flock_or_64 (cmd)						      \
+     ? __fcntl_type_check_flock_or_64 (arg) :				      \
+   __fcntl_is_const_flock (cmd, is_fcntl64)				      \
+     ? __fcntl_type_check_const_flock (arg) :				      \
+   __fcntl_is_flock (cmd, is_fcntl64) ? __fcntl_type_check_flock (arg) :      \
+   __fcntl_is_const_flock64 (cmd, is_fcntl64)				      \
+     ? __fcntl_type_check_const_flock64 (arg) :				      \
+   __fcntl_is_flock64 (cmd, is_fcntl64) ? __fcntl_type_check_flock64 (arg) :  \
+   1)
+
+
+__errordecl (__fcntl_missing_arg,
+             "fcntl with with this command needs 3 arguments");
+
+__fortify_function int
+__fcntl_2_inline (int __fd, int __cmd)
+{
+  if (!__builtin_constant_p (__cmd))
+    return __fcntl_alias (__fd, __cmd);
+
+  if (__fcntl_requires_arg (__cmd))
+    __fcntl_missing_arg ();
+
+  return __fcntl_alias (__fd, __cmd);
+}
+
+__glibc_warn_system_headers_begin
+
+#define fcntl(fd, cmd, ...)						      \
+  (__VA_OPT__ (0 ?) __fcntl_2_inline (fd, cmd)				      \
+   __VA_OPT__ (:							      \
+     !__builtin_constant_p (cmd) ? __fcntl_alias (fd, cmd, __VA_ARGS__)	      \
+        : __fcntl_type_check (cmd, __VA_ARGS__, 0)			      \
+             ? __fcntl_alias (fd, cmd, __VA_ARGS__)			      \
+             : __fcntl_warn (fd, cmd, __VA_ARGS__)))
+
+#ifdef __USE_LARGEFILE64
+
+#define fcntl64(fd, cmd, ...)						      \
+  (__VA_OPT__ (0 ?) __fcntl_2_inline (fd, cmd)				      \
+   __VA_OPT__ (:							      \
+     !__builtin_constant_p (cmd) ? __fcntl64_alias (fd, cmd, __VA_ARGS__)     \
+        : __fcntl_type_check (cmd, __VA_ARGS__, 1)			      \
+             ? __fcntl64_alias (fd, cmd, __VA_ARGS__)			      \
+             : __fcntl64_warn (fd, cmd, __VA_ARGS__)))
+
+
+#endif
+
+__glibc_warn_system_headers_end
diff --git a/io/fcntl.h b/io/fcntl.h
index dd620c08..61738f42 100644
--- a/io/fcntl.h
+++ b/io/fcntl.h
@@ -337,11 +337,17 @@ 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
 # include <bits/fcntl2.h>
 #endif
 
+#if __USE_FORTIFY_LEVEL > 0 && defined (__fortify_function) \
+    && (__GNUC_PREREQ (8, 1) || __glibc_clang_prereq (12, 0))
+# include <bits/fcntl3.h>
+#endif
+
 __END_DECLS
 
 #endif /* fcntl.h  */
diff --git a/manual/maint.texi b/manual/maint.texi
index 89da704f..11509def 100644
--- a/manual/maint.texi
+++ b/manual/maint.texi
@@ -200,7 +200,7 @@ functions but may also include checks for validity of other inputs to
 the functions.
 
 When the @code{_FORTIFY_SOURCE} macro is defined, it enables code that
-validates inputs passed to some functions in @theglibc to determine if
+validates inputs passed to some functions in @theglibc{} to determine if
 they are safe.  If the compiler is unable to determine that the inputs
 to the function call are safe, the call may be replaced by a call to its
 hardened variant that does additional safety checks at runtime.  Some
@@ -221,7 +221,8 @@ returned by the @code{__builtin_object_size} compiler builtin function.
 If the function returns @code{(size_t) -1}, the function call is left
 untouched.  Additionally, this level also enables validation of flags to
 the @code{open}, @code{open64}, @code{openat} and @code{openat64}
-functions.
+functions, as well as validation of the presence and the type of the
+third argument to the @code{fcntl} and @code{fcntl64} functions.
 
 @item @math{2}: This behaves like @math{1}, with the addition of some
 checks that may trap code that is conforming but unsafe, e.g. accepting
@@ -267,6 +268,10 @@ The following functions and macros are fortified in @theglibc{}:
 
 @item @code{explicit_bzero}
 
+@item @code{fcntl}
+
+@item @code{fcntl64}
+
 @item @code{FD_SET}
 
 @item @code{FD_CLR}
diff --git a/posix/test-errno.c b/posix/test-errno.c
index 3685fd15..e73978aa 100644
--- a/posix/test-errno.c
+++ b/posix/test-errno.c
@@ -122,7 +122,9 @@ do_test (void)
   fails |= test_wrp (EBADF, dup2, -1, -1);
   fails |= test_wrp (EBADF, fchdir, -1);
   fails |= test_wrp (EBADF, fchmod, -1, 0);
-  fails |= test_wrp (EBADF, fcntl, -1, 0);
+  /* Parenthesized to avoid the fortification macro, which finds a different
+     error here at compile time.  */
+  fails |= test_wrp (EBADF, (fcntl), -1, 0);
   fails |= test_wrp (EBADF, fstatfs, -1, &sfs);
   fails |= test_wrp (EBADF, fsync, -1);
   fails |= test_wrp (EBADF, ftruncate, -1, 0);
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index be801e3b..ddbf441b 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -246,6 +246,10 @@ ifeq ($(have-GLIBC_2.27)$(build-shared),yesyes)
 tests += \
   tst-ofdlocks-compat \
   # tests
+
+routines_no_fortify += \
+  tst-ofdlocks-compat \
+  # routines_no_fortify
 endif
 
 tests-internal += \
-- 
2.41.0


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

* [PATCH v4 6/6] io: Also verify 2-arg fctnl calls at runtime
  2023-07-30 19:25 [PATCH v4 0/6] fcntl fortification Sergey Bugaev
                   ` (4 preceding siblings ...)
  2023-07-30 19:26 ` [PATCH v4 5/6] io: Add FORTIFY_SOURCE check for fcntl arguments Sergey Bugaev
@ 2023-07-30 19:26 ` Sergey Bugaev
  2023-08-08 18:29   ` Adhemerval Zanella Netto
  2023-07-31 14:40 ` [PATCH v4 0/6] fcntl fortification Zack Weinberg
  6 siblings, 1 reply; 15+ messages in thread
From: Sergey Bugaev @ 2023-07-30 19:26 UTC (permalink / raw)
  To: libc-alpha

This adds a runtime fortification function, __fcntl_2, similar to
__open_2, that checks at runtime whether the actual passed-in command in
fact requires a third argument, and aborts if so.

The abilists have been modified with 'make update-all-abi'.

Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>
---

Compared to v3, now targeting GLIBC_2.39.
You can still drop this patch if you don't want it.

 debug/tst-fortify.c                           | 11 +++++++
 include/fcntl.h                               |  1 +
 io/Makefile                                   |  1 +
 io/Versions                                   |  3 ++
 io/bits/fcntl3.h                              |  4 ++-
 io/fcntl_2.c                                  | 33 +++++++++++++++++++
 manual/maint.texi                             | 10 +++---
 sysdeps/mach/hurd/i386/libc.abilist           |  1 +
 sysdeps/mach/hurd/x86_64/libc.abilist         |  1 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |  1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |  1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist      |  1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist   |  1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |  1 +
 sysdeps/unix/sysv/linux/csky/libc.abilist     |  1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist     |  1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist     |  1 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist     |  1 +
 .../sysv/linux/loongarch/lp64/libc.abilist    |  1 +
 .../sysv/linux/m68k/coldfire/libc.abilist     |  1 +
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |  1 +
 .../sysv/linux/microblaze/be/libc.abilist     |  1 +
 .../sysv/linux/microblaze/le/libc.abilist     |  1 +
 .../sysv/linux/mips/mips32/fpu/libc.abilist   |  1 +
 .../sysv/linux/mips/mips32/nofpu/libc.abilist |  1 +
 .../sysv/linux/mips/mips64/n32/libc.abilist   |  1 +
 .../sysv/linux/mips/mips64/n64/libc.abilist   |  1 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist    |  1 +
 sysdeps/unix/sysv/linux/or1k/libc.abilist     |  1 +
 .../linux/powerpc/powerpc32/fpu/libc.abilist  |  1 +
 .../powerpc/powerpc32/nofpu/libc.abilist      |  1 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |  1 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |  1 +
 .../unix/sysv/linux/riscv/rv32/libc.abilist   |  1 +
 .../unix/sysv/linux/riscv/rv64/libc.abilist   |  1 +
 .../unix/sysv/linux/s390/s390-32/libc.abilist |  1 +
 .../unix/sysv/linux/s390/s390-64/libc.abilist |  1 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist    |  1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist    |  1 +
 .../sysv/linux/sparc/sparc32/libc.abilist     |  1 +
 .../sysv/linux/sparc/sparc64/libc.abilist     |  1 +
 .../unix/sysv/linux/x86_64/64/libc.abilist    |  1 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |  1 +
 43 files changed, 94 insertions(+), 5 deletions(-)
 create mode 100644 io/fcntl_2.c

diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c
index 98654299..f076baee 100644
--- a/debug/tst-fortify.c
+++ b/debug/tst-fortify.c
@@ -1915,6 +1915,12 @@ do_test (void)
     }
 #endif
 
+#if __USE_FORTIFY_LEVEL >= 1
+  CHK_FAIL_START
+  fcntl (STDIN_FILENO, hide_constant (F_SETFD));
+  CHK_FAIL_END
+#endif
+
 #if defined (__USE_LARGEFILE64) || defined (__USE_TIME_BITS64)
   /* Also check fcntl64 ().  */
   res = fcntl64 (STDIN_FILENO, F_GETFD);
@@ -1979,6 +1985,11 @@ do_test (void)
     }
 #endif
 
+# if __USE_FORTIFY_LEVEL >= 1
+  CHK_FAIL_START
+  fcntl64 (STDIN_FILENO, hide_constant (F_SETFD));
+  CHK_FAIL_END
+# endif
 #endif
 
   return ret;
diff --git a/include/fcntl.h b/include/fcntl.h
index be435047..cb86c5e7 100644
--- a/include/fcntl.h
+++ b/include/fcntl.h
@@ -32,6 +32,7 @@ extern int __open64_2 (const char *__path, int __oflag);
 extern int __openat_2 (int __fd, const char *__path, int __oflag);
 extern int __openat64_2 (int __fd, const char *__path, int __oflag);
 
+extern int __fcntl_2 (int __fd, int __cmd);
 
 #if IS_IN (rtld)
 #  include <dl-fcntl.h>
diff --git a/io/Makefile b/io/Makefile
index 0c43881f..7e08ed88 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -72,6 +72,7 @@ routines := \
   fchownat \
   fcntl \
   fcntl64 \
+  fcntl_2 \
   file_change_detection \
   flock \
   fstat \
diff --git a/io/Versions b/io/Versions
index 4e195408..bff2b7cf 100644
--- a/io/Versions
+++ b/io/Versions
@@ -140,6 +140,9 @@ libc {
   GLIBC_2.34 {
     closefrom;
   }
+  GLIBC_2.39 {
+    __fcntl_2;
+  }
   GLIBC_PRIVATE {
     __libc_fcntl64;
     __fcntl_nocancel;
diff --git a/io/bits/fcntl3.h b/io/bits/fcntl3.h
index 9016d37e..bb61f53c 100644
--- a/io/bits/fcntl3.h
+++ b/io/bits/fcntl3.h
@@ -20,6 +20,8 @@
 # error "Never include <bits/fcntl3.h> directly; use <fcntl.h> instead."
 #endif
 
+extern int __fcntl_2 (int __fd, int __cmd);
+
 #ifndef __USE_TIME_BITS64
 
 # ifndef __USE_FILE_OFFSET64
@@ -437,7 +439,7 @@ __fortify_function int
 __fcntl_2_inline (int __fd, int __cmd)
 {
   if (!__builtin_constant_p (__cmd))
-    return __fcntl_alias (__fd, __cmd);
+    return __fcntl_2 (__fd, __cmd);
 
   if (__fcntl_requires_arg (__cmd))
     __fcntl_missing_arg ();
diff --git a/io/fcntl_2.c b/io/fcntl_2.c
new file mode 100644
index 00000000..d9fd9c04
--- /dev/null
+++ b/io/fcntl_2.c
@@ -0,0 +1,33 @@
+/* _FORTIFY_SOURCE wrapper for fcntl.
+   Copyright (C) 2013-2023 Free Software Foundation, Inc.
+   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/>.  */
+
+/* Make sure to get __fcntl_requires_arg from bits/fcntl3.h */
+#undef _FORTIFY_SOURCE
+#define _FORTIFY_SOURCE 1
+
+#include <fcntl.h>
+#include <stdio.h>
+
+int
+__fcntl_2 (int fd, int cmd)
+{
+  if (__fcntl_requires_arg (cmd))
+    __fortify_fail ("invalid fcntl call: this cmd requires an argument");
+
+  return __libc_fcntl64 (fd, cmd);
+}
diff --git a/manual/maint.texi b/manual/maint.texi
index 11509def..9b24e5a0 100644
--- a/manual/maint.texi
+++ b/manual/maint.texi
@@ -244,10 +244,11 @@ depending on the architecture, one may also see fortified variants have
 the @code{_chkieee128} suffix or the @code{__nldbl___} prefix to their
 names.
 
-Another exception is the @code{open} family of functions, where their
-fortified replacements have the @code{__} prefix and a @code{_2} suffix.
-The @code{FD_SET}, @code{FD_CLR} and @code{FD_ISSET} macros use the
-@code{__fdelt_chk} function on fortification.
+Another exception is the @code{open} and @code{fcntl} families of
+functions, where their fortified 2-argument version replacements have the
+@code{__} prefix and a @code{_2} suffix. The @code{FD_SET}, @code{FD_CLR}
+and @code{FD_ISSET} macros use the @code{__fdelt_chk} function on
+fortification.
 
 The following functions and macros are fortified in @theglibc{}:
 @c Generated using the following command:
@@ -256,6 +257,7 @@ The following functions and macros are fortified in @theglibc{}:
 @c   sort -u | grep ^__ |
 @c   grep -v -e ieee128 -e __nldbl -e align_cpy -e "fdelt_warn" |
 @c   sed 's/__fdelt_chk/@item @code{FD_SET}\n\n@item @code{FD_CLR}\n\n@item @code{FD_ISSET}\n/' |
+@c   sed 's/__fcntl_2/@item @code{fcntl}\n\n@item @code{fcntl64}\n/' |
 @c   sed 's/__\(.*\)_\(chk\|2\)/@item @code{\1}\n/'
 
 @itemize @bullet
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index 74a9f427..9e74779c 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2334,6 +2334,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/mach/hurd/x86_64/libc.abilist b/sysdeps/mach/hurd/x86_64/libc.abilist
index 24db98d7..d9261ca1 100644
--- a/sysdeps/mach/hurd/x86_64/libc.abilist
+++ b/sysdeps/mach/hurd/x86_64/libc.abilist
@@ -2114,6 +2114,7 @@ GLIBC_2.38 wprintf F
 GLIBC_2.38 write F
 GLIBC_2.38 writev F
 GLIBC_2.38 wscanf F
+GLIBC_2.39 __fcntl_2 F
 HURD_CTHREADS_0.3 __cthread_getspecific F
 HURD_CTHREADS_0.3 __cthread_keycreate F
 HURD_CTHREADS_0.3 __cthread_setspecific F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index c49363e7..49103c3e 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2673,3 +2673,4 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index d6b1dcaa..77acc615 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2782,6 +2782,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index dfe0c3f7..ef9acbdb 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2434,3 +2434,4 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 6c75e5aa..df4efc55 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -554,6 +554,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 03d6f7ae..bcdc2764 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -551,6 +551,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index d858c108..7013676f 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2710,3 +2710,4 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 82a14f8a..8fc8e661 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2659,6 +2659,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 1950b15d..ee837f3b 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2843,6 +2843,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index d0b9cb27..6b0ade18 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2608,6 +2608,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
index e760a631..99fe672d 100644
--- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
@@ -2194,3 +2194,4 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 35785a3d..4e24bf9a 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -555,6 +555,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 4ab2426e..ab53ab23 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2786,6 +2786,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 38faa162..2b3149e7 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2759,3 +2759,4 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 374d6589..5922edcb 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2756,3 +2756,4 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index fcc5e88e..768948b2 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2751,6 +2751,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 01eb96cd..d0931261 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2749,6 +2749,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index a2748b7b..87b90cf4 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2757,6 +2757,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 0ae7ba49..8b8fb90f 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2659,6 +2659,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 947495a0..706941fc 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2798,3 +2798,4 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
index 115f1039..a5ef08f7 100644
--- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
+++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
@@ -2180,3 +2180,4 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 19c4c325..c9795714 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2825,6 +2825,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 3e043c40..0402ce99 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2858,6 +2858,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index e4f3a766..ea9d4d61 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2579,6 +2579,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index dafe1c4a..67faa8f5 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2893,3 +2893,4 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index b9740a1a..0f5c2079 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2436,3 +2436,4 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index e3b4656a..f18f3b0d 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2636,3 +2636,4 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 84cb7a50..d07a7539 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2823,6 +2823,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 33df3b16..80e01cc6 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2616,6 +2616,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 94cbccd7..9961ef14 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2666,6 +2666,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 3bb316a7..3c8a3da2 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2663,6 +2663,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 6341b491..3cbd4543 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2818,6 +2818,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 8ed1ea29..b3159408 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2631,6 +2631,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 57cfcc20..307e2a7c 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2582,6 +2582,7 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 3f0a9f6d..1bb0cbde 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2688,3 +2688,4 @@ GLIBC_2.38 strlcat F
 GLIBC_2.38 strlcpy F
 GLIBC_2.38 wcslcat F
 GLIBC_2.38 wcslcpy F
+GLIBC_2.39 __fcntl_2 F
-- 
2.41.0


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

* Re: [PATCH v4 5/6] io: Add FORTIFY_SOURCE check for fcntl arguments
  2023-07-30 19:26 ` [PATCH v4 5/6] io: Add FORTIFY_SOURCE check for fcntl arguments Sergey Bugaev
@ 2023-07-30 19:54   ` Sergey Bugaev
  2023-08-02 19:46   ` Adhemerval Zanella Netto
  1 sibling, 0 replies; 15+ messages in thread
From: Sergey Bugaev @ 2023-07-30 19:54 UTC (permalink / raw)
  To: libc-alpha

On Sun, Jul 30, 2023 at 10:26 PM Sergey Bugaev <bugaevc@gmail.com> wrote:
> @@ -153,6 +154,8 @@ routines := \
>  routines_no_fortify += \
>    getcwd \
>    getwd \
> +  fcntl \
> +  fcntl64 \
>    open \
>    open64 \
>    openat \

...and just as I sent it, I noticed I got the order wrong here.

Sergey

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

* Re: [PATCH v4 0/6] fcntl fortification
  2023-07-30 19:25 [PATCH v4 0/6] fcntl fortification Sergey Bugaev
                   ` (5 preceding siblings ...)
  2023-07-30 19:26 ` [PATCH v4 6/6] io: Also verify 2-arg fctnl calls at runtime Sergey Bugaev
@ 2023-07-31 14:40 ` Zack Weinberg
  2023-07-31 17:25   ` Adhemerval Zanella Netto
  6 siblings, 1 reply; 15+ messages in thread
From: Zack Weinberg @ 2023-07-31 14:40 UTC (permalink / raw)
  To: GNU libc development

On Sun, Jul 30, 2023, at 3:25 PM, Sergey Bugaev via Libc-alpha wrote:
> this is the v4 of the fcntl fortification work.

I apologize if this has already been discussed, but I can't find any mention of it. What does this patch do with code that supplies an *unnecessary* third argument to fcntl and/or open? (For example, `open(fname, O_RDONLY, 0)`.

I have seen this fairly often and it's harmless, so I think it should probably continue to be allowed. I can see an argument for warning about this, but I think that belongs in the compiler, with a dedicated -W option to squelch it.

zw

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

* Re: [PATCH v4 0/6] fcntl fortification
  2023-07-31 14:40 ` [PATCH v4 0/6] fcntl fortification Zack Weinberg
@ 2023-07-31 17:25   ` Adhemerval Zanella Netto
  0 siblings, 0 replies; 15+ messages in thread
From: Adhemerval Zanella Netto @ 2023-07-31 17:25 UTC (permalink / raw)
  To: Zack Weinberg, GNU libc development



On 31/07/23 11:40, Zack Weinberg via Libc-alpha wrote:
> On Sun, Jul 30, 2023, at 3:25 PM, Sergey Bugaev via Libc-alpha wrote:
>> this is the v4 of the fcntl fortification work.
> 
> I apologize if this has already been discussed, but I can't find any mention of it. What does this patch do with code that supplies an *unnecessary* third argument to fcntl and/or open? (For example, `open(fname, O_RDONLY, 0)`.
> 
> I have seen this fairly often and it's harmless, so I think it should probably continue to be allowed. I can see an argument for warning about this, but I think that belongs in the compiler, with a dedicated -W option to squelch it.

My understanding reviewing the previous revision is the other way around:
like __open_2 the idea is warn if the fcntl requires a third argument
based on second argument value.  Like fortified open, adding an extra
argument where it is not required should not trigger a fortify issue.

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

* Re: [PATCH v4 1/6] Fix calling fcntl64 (fd, F_SETLK, &flock64)
  2023-07-30 19:25 ` [PATCH v4 1/6] Fix calling fcntl64 (fd, F_SETLK, &flock64) Sergey Bugaev
@ 2023-07-31 17:50   ` Adhemerval Zanella Netto
  2023-08-08 18:40     ` Sergey Bugaev
  0 siblings, 1 reply; 15+ messages in thread
From: Adhemerval Zanella Netto @ 2023-07-31 17:50 UTC (permalink / raw)
  To: Sergey Bugaev, libc-alpha; +Cc: Florian Weimer



On 30/07/23 16:25, Sergey Bugaev via Libc-alpha wrote:
> F_GETLK, F_SETLK, F_SETLKW must always be used with the regular struct
> flock, not struct flock64, even if the function being called is fcntl64.
> There are separate commands, F_GETLK64, F_SETLK64, and F_SETLKW64, that
> are used with struct flock64. This is in contrast with the OFD locking
> commands (F_OFD_GETLK, F_OFD_SETLK, F_OFD_SETLKW) that must be used with
> struct flock in fcntl calls, and with struct flock64 in fcntl64 calls.
> 
> These mistakes were spotted by enabling the fcntl fortification that is
> added in a following commit.
> 
> Fixes: 61d3db428176d9d0822e4e680305fe34285edff2
> "login: pututxline could fail to overwrite existing entries [BZ #24902]"
> Fixes: f6233ab412c3bebebacf65745e775e01506dd58d
> "Linux: Add io/tst-o_path-locks test"
> 
> Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>

Nice, it seems that on both tests the fields that might trigger wrong values
by the kernel reading the struct with a wrong size (l_start and l_len) are 
always being 0 and thus it should not matter.

LGTM, thanks.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

> ---
> 
> Please tell me if I'm misunderstanding this!
> 
>  login/tst-pututxline-lockfail.c            | 2 +-
>  sysdeps/unix/sysv/linux/tst-o_path-locks.c | 6 +++---
>  2 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/login/tst-pututxline-lockfail.c b/login/tst-pututxline-lockfail.c
> index 214d1106..ca82ba42 100644
> --- a/login/tst-pututxline-lockfail.c
> +++ b/login/tst-pututxline-lockfail.c
> @@ -77,7 +77,7 @@ subprocess_lock_file (void)
>       .l_type = F_RDLCK,
>       fl.l_whence = SEEK_SET,
>      };
> -  TEST_COMPARE (fcntl64 (fd, F_SETLKW, &fl), 0);
> +  TEST_COMPARE (fcntl64 (fd, F_SETLKW64, &fl), 0);
>  
>    /* Signal to the main process that the lock has been acquired.  */
>    xpthread_barrier_wait (barrier);
> diff --git a/sysdeps/unix/sysv/linux/tst-o_path-locks.c b/sysdeps/unix/sysv/linux/tst-o_path-locks.c
> index 0036868d..c3d1c0dc 100644
> --- a/sysdeps/unix/sysv/linux/tst-o_path-locks.c
> +++ b/sysdeps/unix/sysv/linux/tst-o_path-locks.c
> @@ -39,7 +39,7 @@ subprocess (void *closure)
>  {
>    int fd = xopen (path, O_RDWR, 0);
>    struct flock64 lock = { .l_type = F_WRLCK, };
> -  int ret = fcntl64 (fd, F_SETLK, &lock);
> +  int ret = fcntl64 (fd, F_SETLK64, &lock);
>    if (ret == 0)
>      *shared_errno = 0;
>    else
> @@ -76,7 +76,7 @@ do_test (void)
>    TEST_VERIFY (!probe_lock ());
>  
>    struct flock64 lock = { .l_type = F_WRLCK, };
> -  TEST_COMPARE (fcntl64 (fd, F_SETLK, &lock), 0);
> +  TEST_COMPARE (fcntl64 (fd, F_SETLK64, &lock), 0);
>  
>    /* The lock has been acquired.  */
>    TEST_VERIFY (probe_lock ());
> @@ -87,7 +87,7 @@ do_test (void)
>    TEST_VERIFY (!probe_lock ());
>  
>    /* But not if it is an O_PATH descriptor.  */
> -  TEST_COMPARE (fcntl64 (fd, F_SETLK, &lock), 0);
> +  TEST_COMPARE (fcntl64 (fd, F_SETLK64, &lock), 0);
>    xclose (xopen (path, O_PATH, 0));
>    TEST_VERIFY (probe_lock ());
>  

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

* Re: [PATCH v4 4/6] cdefs.h: Enable __errordecl & __warnattr for Clang 14+
  2023-07-30 19:25 ` [PATCH v4 4/6] cdefs.h: Enable __errordecl & __warnattr for Clang 14+ Sergey Bugaev
@ 2023-08-02 17:23   ` Adhemerval Zanella Netto
  0 siblings, 0 replies; 15+ messages in thread
From: Adhemerval Zanella Netto @ 2023-08-02 17:23 UTC (permalink / raw)
  To: Sergey Bugaev, libc-alpha



On 30/07/23 16:25, Sergey Bugaev via Libc-alpha wrote:
> Clang 14 (released in March 2022) has added support for
> attribute ((error)) and attribute ((warning)). Enable their usage when
> Clang 14 or later is detected, to get nicer diagnostics.
> 
> https://reviews.llvm.org/D106030
> https://github.com/llvm/llvm-project/commit/846e562dcc6a9a611d844dc0d123da95629a0567
> 
> Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>

LGTM, thanks.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

> ---
>  misc/sys/cdefs.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
> index 15587848..5c98f393 100644
> --- a/misc/sys/cdefs.h
> +++ b/misc/sys/cdefs.h
> @@ -208,7 +208,7 @@
>        : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s))))
>  #endif
>  
> -#if __GNUC_PREREQ (4,3)
> +#if __GNUC_PREREQ (4,3) || __glibc_clang_prereq (14,0)
>  # define __warnattr(msg) __attribute__((__warning__ (msg)))
>  # define __errordecl(name, msg) \
>    extern void name (void) __attribute__((__error__ (msg)))

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

* Re: [PATCH v4 5/6] io: Add FORTIFY_SOURCE check for fcntl arguments
  2023-07-30 19:26 ` [PATCH v4 5/6] io: Add FORTIFY_SOURCE check for fcntl arguments Sergey Bugaev
  2023-07-30 19:54   ` Sergey Bugaev
@ 2023-08-02 19:46   ` Adhemerval Zanella Netto
  1 sibling, 0 replies; 15+ messages in thread
From: Adhemerval Zanella Netto @ 2023-08-02 19:46 UTC (permalink / raw)
  To: libc-alpha, Sergey Bugaev



On 30/07/23 16:26, Sergey Bugaev via Libc-alpha wrote:
> Both open () and fcntl () are "overloaded" to accept either 2 or 3
> arguments; whether the last argument is required (and, in case of fcntl,
> the type of the third argument) depends on the values of the previous
> arguments. Since C provides no native support for function overloading,
> this is implemented by making these functions vararg. Unfortunately,
> this means the compiler is unable to check the number of arguments and
> their types for correctness at compile time, and will not diagnose any
> mistakes.
> 
> To help with this, when FORTIFY_SOURCE is enabled, the special fcntl2.h
> header replaces open () with a wrapper that checks the passed number of
> arguments, raising a compile-time or run-time error on mismatch. This
> commit adds similar handling for fcntl (). Additionally, the fcntl ()
> wrapper tries to check that the type of the 3rd argument (if any)
> matches the type that the command (passed in the 2nd argument) expects.
> 
> tst-ofdlocks-compat is excluded from fortification, since it
> intentionally calls fcntl () with an argument of a wrong type while
> linking to an old symbol version. The fcntl () call in test-errno is
> similarly excluded from fortification, since it intentionally contains
> two errors (bad file descriptor, and missing the required 3rd argument)
> and tests for getting the expected error code.
> 
> Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>

Looks good in general, some minor comments below.

> ---
> 
> Reposting the concern from v3:
> In manual/maint.texi, how would I properly update the command for
> generating the list of fortified functions to include fcntl / fcntl64 in
> absence of __fcntl_2? (The next patch does make it work with __fcntl_2.)

Maybe a better option would to rename __fcntl_2 to __fcntl_2_chk, since
on the script at comments it already filters out such name format.

> 
>  debug/tst-fortify.c              | 168 +++++++++++
>  include/bits/fcntl3.h            |   1 +
>  io/Makefile                      |   3 +
>  io/bits/fcntl3.h                 | 471 +++++++++++++++++++++++++++++++
>  io/fcntl.h                       |   6 +
>  manual/maint.texi                |   9 +-
>  posix/test-errno.c               |   4 +-
>  sysdeps/unix/sysv/linux/Makefile |   4 +
>  8 files changed, 663 insertions(+), 3 deletions(-)
>  create mode 100644 include/bits/fcntl3.h
>  create mode 100644 io/bits/fcntl3.h
> 
> diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c
> index 3744aada..98654299 100644
> --- a/debug/tst-fortify.c
> +++ b/debug/tst-fortify.c
> @@ -36,6 +36,8 @@
>  #include <sys/select.h>
>  #include <sys/socket.h>
>  #include <sys/un.h>
> +#include <support/support.h>
> +#include <support/xunistd.h>
>  
>  #ifndef _GNU_SOURCE
>  # define MEMPCPY memcpy
> @@ -78,6 +80,15 @@ do_prepare (void)
>      }
>  }
>  
> +/* Return VALUE, but do it in a way that the compiler cannot
> +   see that it's a compile-time constant.  */
> +static inline int
> +hide_constant (int value)
> +{
> +  asm ("" : "+rm" (value));
> +  return value;
> +}
> +
>  volatile int chk_fail_ok;
>  volatile int ret;
>  jmp_buf chk_fail_buf;
> @@ -1811,6 +1822,163 @@ do_test (void)
>    ppoll (fds, l0 + 2, NULL, NULL);
>    CHK_FAIL_END
>  # endif
> +#endif
> +
> +  /* Check that we can do basic fcntl operations, both ones that require
> +     the third argument, and ones that do not.  */
> +  res = fcntl (STDIN_FILENO, F_GETFD);
> +  TEST_COMPARE (res, 0);
> +  res = fcntl (STDIN_FILENO, F_SETFD, 0);
> +  TEST_COMPARE (res, 0);
> +
> +  /* Check that we can successfully use F_GETLK with struct flock, even though
> +     F_GETLK might have the same value as F_GETLK64.  */
> +  {
> +    struct flock flock;
> +    memset (&flock, 0, sizeof (flock));
> +    flock.l_type = F_WRLCK;
> +    flock.l_whence = SEEK_SET;
> +    flock.l_start = 1234;
> +    flock.l_len = 5678;
> +    flock.l_pid = 0;
> +
> +    (void) fcntl (STDIN_FILENO, F_GETLK, &flock);
> +  }
> +
> +#ifdef F_OFD_GETLK
> +  /* Check for confusion between 32- and 64-bit versions of the fcntl
> +     interface.  */
> +  int lockfd1 = xopen (temp_filename, O_RDWR, 0);
> +  int lockfd2 = xopen (temp_filename, O_RDWR, 0);
> +
> +  int ofd_locks_supported = support_fcntl_support_ofd_locks (lockfd1);
> +
> +  if (ofd_locks_supported)
> +    {
> +      struct flock flock;
> +
> +      memset (&flock, 0, sizeof (flock));
> +      flock.l_type = F_WRLCK;
> +      flock.l_whence = SEEK_SET;
> +      flock.l_start = 1234;
> +      flock.l_len = 5678;
> +      flock.l_pid = 0;
> +
> +      res = fcntl (lockfd1, F_OFD_SETLK, &flock);
> +      TEST_COMPARE (res, 0);
> +
> +      memset (&flock, 0, sizeof (flock));
> +      flock.l_type = F_RDLCK;
> +      flock.l_whence = SEEK_SET;
> +      flock.l_start = 3542;
> +      flock.l_len = 411;
> +      flock.l_pid = 0;
> +
> +      res = fcntl (lockfd2, F_OFD_GETLK, &flock);
> +      TEST_COMPARE (res, 0);
> +      /* Check that we get the expected values.  */
> +      TEST_COMPARE (flock.l_type, F_WRLCK);
> +      TEST_COMPARE (flock.l_whence, SEEK_SET);
> +      TEST_COMPARE (flock.l_start, 1234);
> +      TEST_COMPARE (flock.l_len, 5678);
> +      TEST_COMPARE (flock.l_pid, -1);
> +    }
> +#endif
> +
> +  /* Check that we can do fcntl operations with CMD that is not constant
> +     at compile time.  */
> +  res = fcntl (STDIN_FILENO, hide_constant (F_GETFD));
> +  TEST_COMPARE (res, 0);
> +  res = fcntl (STDIN_FILENO, hide_constant (F_SETFD), 0);
> +  TEST_COMPARE (res, 0);
> +
> +#ifdef F_OFD_GETLK
> +  if (ofd_locks_supported)
> +    {
> +      struct flock flock;
> +
> +      memset (&flock, 0, sizeof (flock));
> +      flock.l_type = F_RDLCK;
> +      flock.l_whence = SEEK_SET;
> +      flock.l_start = 3542;
> +      flock.l_len = 411;
> +      flock.l_pid = 0;
> +
> +      res = fcntl (lockfd2, hide_constant (F_OFD_GETLK), &flock);
> +      TEST_COMPARE (res, 0);
> +      /* Check that we get the expected values.  */
> +      TEST_COMPARE (flock.l_type, F_WRLCK);
> +      TEST_COMPARE (flock.l_whence, SEEK_SET);
> +      TEST_COMPARE (flock.l_start, 1234);
> +      TEST_COMPARE (flock.l_len, 5678);
> +      TEST_COMPARE (flock.l_pid, -1);
> +    }
> +#endif
> +
> +#if defined (__USE_LARGEFILE64) || defined (__USE_TIME_BITS64)
> +  /* Also check fcntl64 ().  */
> +  res = fcntl64 (STDIN_FILENO, F_GETFD);
> +  TEST_COMPARE (res, 0);
> +  res = fcntl64 (STDIN_FILENO, F_SETFD, 0);
> +  TEST_COMPARE (res, 0);
> +  res = fcntl64 (STDIN_FILENO, hide_constant (F_GETFD));
> +  TEST_COMPARE (res, 0);
> +  res = fcntl64 (STDIN_FILENO, hide_constant (F_SETFD), 0);
> +  TEST_COMPARE (res, 0);
> +
> +  /* Check that we can successfully use F_GETLK64 with struct flock64, even
> +     though F_GETLK might have the same value as F_GETLK64.  */
> +  {
> +    struct flock64 flock64;
> +    memset (&flock64, 0, sizeof (flock64));
> +    flock64.l_type = F_WRLCK;
> +    flock64.l_whence = SEEK_SET;
> +    flock64.l_start = 1234;
> +    flock64.l_len = 5678;
> +    flock64.l_pid = 0;
> +
> +    (void) fcntl64 (STDIN_FILENO, F_GETLK64, &flock64);
> +  }
> +
> +#ifdef F_OFD_GETLK

Add a whitespace for the identation:

# ifdef F_OFD_GETLK

Same for the #endif.

> +  if (ofd_locks_supported)
> +    {
> +      struct flock64 flock64;
> +
> +      memset (&flock64, 0, sizeof (flock64));
> +      flock64.l_type = F_RDLCK;
> +      flock64.l_whence = SEEK_SET;
> +      flock64.l_start = 3542;
> +      flock64.l_len = 411;
> +      flock64.l_pid = 0;
> +
> +      res = fcntl64 (lockfd2, F_OFD_GETLK, &flock64);
> +      TEST_COMPARE (res, 0);
> +      /* Check that we get the expected values.  */
> +      TEST_COMPARE (flock64.l_type, F_WRLCK);
> +      TEST_COMPARE (flock64.l_whence, SEEK_SET);
> +      TEST_COMPARE (flock64.l_start, 1234);
> +      TEST_COMPARE (flock64.l_len, 5678);
> +      TEST_COMPARE (flock64.l_pid, -1);
> +
> +      memset (&flock64, 0, sizeof (flock64));
> +      flock64.l_type = F_RDLCK;
> +      flock64.l_whence = SEEK_SET;
> +      flock64.l_start = 3542;
> +      flock64.l_len = 411;
> +      flock64.l_pid = 0;
> +
> +      res = fcntl64 (lockfd2, hide_constant (F_OFD_GETLK), &flock64);
> +      TEST_COMPARE (res, 0);
> +      /* Check that we get the expected values.  */
> +      TEST_COMPARE (flock64.l_type, F_WRLCK);
> +      TEST_COMPARE (flock64.l_whence, SEEK_SET);
> +      TEST_COMPARE (flock64.l_start, 1234);
> +      TEST_COMPARE (flock64.l_len, 5678);
> +      TEST_COMPARE (flock64.l_pid, -1);
> +    }
> +#endif
> +
>  #endif
>  
>    return ret;
> diff --git a/include/bits/fcntl3.h b/include/bits/fcntl3.h
> new file mode 100644
> index 00000000..d31154f6
> --- /dev/null
> +++ b/include/bits/fcntl3.h
> @@ -0,0 +1 @@
> +#include "../../io/bits/fcntl3.h"

I think it would be clear that se use absolute paths instead of relative.

> diff --git a/io/Makefile b/io/Makefile
> index 6ccc0e86..0c43881f 100644
> --- a/io/Makefile
> +++ b/io/Makefile
> @@ -25,6 +25,7 @@ include ../Makeconfig
>  headers := \
>    bits/fcntl.h \
>    bits/fcntl2.h \
> +  bits/fcntl3.h \
>    bits/poll.h \
>    bits/poll2.h \
>    bits/stat.h \
> @@ -153,6 +154,8 @@ routines := \
>  routines_no_fortify += \
>    getcwd \
>    getwd \
> +  fcntl \
> +  fcntl64 \
>    open \
>    open64 \
>    openat \
> diff --git a/io/bits/fcntl3.h b/io/bits/fcntl3.h
> new file mode 100644
> index 00000000..9016d37e
> --- /dev/null
> +++ b/io/bits/fcntl3.h
> @@ -0,0 +1,471 @@
> +/* Checking macros for fcntl functions.
> +   Copyright (C) 2007-2023 Free Software Foundation, Inc.

I think this should be only 2023.

> +   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/>.  */
> +
> +#ifndef	_FCNTL_H
> +# error "Never include <bits/fcntl3.h> directly; use <fcntl.h> instead."
> +#endif
> +
> +#ifndef __USE_TIME_BITS64
> +
> +# ifndef __USE_FILE_OFFSET64
> +extern int __REDIRECT (__fcntl_alias, (int __fd, int __cmd, ...), fcntl);
> +extern int __REDIRECT (__fcntl_warn, (int __fd, int __cmd, ...), fcntl)
> +  __warnattr ("fcntl argument has wrong type for this command");
> +# else
> +extern int __REDIRECT (__fcntl_alias, (int __fd, int __cmd, ...), fcntl64);
> +extern int __REDIRECT (__fcntl_warn, (int __fd, int __cmd, ...), fcntl64)
> +  __warnattr ("fcntl argument has wrong type for this command");
> +# endif /* __USE_FILE_OFFSET64 */
> +
> +# ifdef __USE_LARGEFILE64
> +extern int __REDIRECT (__fcntl64_alias, (int __fd, int __cmd, ...), fcntl64);
> +extern int __REDIRECT (__fcntl64_warn, (int __fd, int __cmd, ...), fcntl64)
> +  __warnattr ("fcntl64 argument has wrong type for this command");
> +# endif
> +
> +#else /* __USE_TIME_BITS64 */
> +
> +extern int __REDIRECT_NTH (__fcntl_alias, (int __fd, int __cmd, ...),
> +			   __fcntl_time64);
> +extern int __REDIRECT_NTH (__fcntl64_alias, (int __fd, int __cmd, ...),
> +			   __fcntl_time64);
> +extern int __REDIRECT (__fcntl_warn, (int __fd, int __cmd, ...),
> +                        __fcntl_time64)
> +  __warnattr ("fcntl argument has wrong type for this command");
> +extern int __REDIRECT (__fcntl64_warn, (int __fd, int __cmd, ...),
> +                        __fcntl_time64)
> +  __warnattr ("fcntl64 argument has wrong type for this command");
> +
> +#endif /* __USE_TIME_BITS64 */
> +
> +
> +/* Whether the fcntl CMD is known to require an argument.  */
> +__extern_always_inline int
> +__fcntl_requires_arg (int __cmd)
> +{
> +  switch (__cmd)
> +    {
> +    case F_DUPFD:
> +#ifdef F_DUPFD_CLOEXEC
> +    case F_DUPFD_CLOEXEC:
> +#endif
> +    case F_SETFD:
> +    case F_SETFL:
> +#ifdef F_SETLK
> +    case F_SETLK:
> +    case F_SETLKW:
> +    case F_GETLK:
> +#endif
> +#ifdef F_OFD_SETLK
> +    case F_OFD_SETLK:
> +    case F_OFD_SETLKW:
> +    case F_OFD_GETLK:
> +#endif
> +#ifdef F_SETOWN
> +    case F_SETOWN:
> +#endif
> +#ifdef F_GETOWN_EX
> +    case F_GETOWN_EX:
> +    case F_SETOWN_EX:
> +    case F_SETSIG:
> +#endif
> +#ifdef F_SETLEASE
> +    case F_SETLEASE:
> +    case F_NOTIFY:
> +    case F_SETPIPE_SZ:

I don't think assuring that F_SETLEASE is defined F_ADD_SEALS is also defined.
The F_SETLEASE and F_NOTIFY was added on Linux 2.4, and F_SETPIPE_SZ on 2.6.35;
however F_ADD_SEALS was added on 3.17 and we stil support 3.2 as the minimum
version for some architectures.

So I think it would be better to check for '#ifdef F_ADD_SEALS' instead.

> +    case F_ADD_SEALS:
> +    case F_GET_RW_HINT:
> +    case F_SET_RW_HINT:

Same for F_GET_RW_HINT, that was added on 4.13.

> +    case F_GET_FILE_RW_HINT:
> +    case F_SET_FILE_RW_HINT:
> +#endif
> +      return 1;
> +
> +    default:
> +      return 0;
> +  }
> +}
> +
> +/* Whether the fcntl CMD requires an int argument.  */
> +__extern_always_inline int
> +__fcntl_is_int (int __cmd)
> +{
> +  switch (__cmd)
> +    {
> +    case F_DUPFD:
> +#ifdef F_DUPFD_CLOEXEC
> +    case F_DUPFD_CLOEXEC:
> +#endif
> +    case F_SETFD:
> +    case F_SETFL:
> +#ifdef F_SETOWN
> +    case F_SETOWN:
> +#endif
> +#ifdef F_SETSIG
> +    case F_SETSIG:
> +#endif
> +#ifdef F_SETLEASE
> +    case F_SETLEASE:
> +    case F_NOTIFY:
> +    case F_SETPIPE_SZ:
> +    case F_ADD_SEALS:

Same as before.

> +#endif
> +      return 1;
> +
> +    default:
> +      return 0;
> +    }
> +}
> +
> +/* Whether the fcntl CMD requires a (const uint64_t *) argument.  */
> +__extern_always_inline int
> +__fcntl_is_const_uint64_t_ptr (int __cmd)
> +{
> +  switch (__cmd)
> +    {
> +#ifdef F_SET_RW_HINT
> +    case F_SET_RW_HINT:
> +    case F_SET_FILE_RW_HINT:
> +      return 1;
> +#endif
> +
> +    default:
> +      return 0;
> +    }
> +}
> +
> +
> +/* Whether the fcntl CMD requires an (uint64_t *) argument.  */
> +__extern_always_inline int
> +__fcntl_is_uint64_t_ptr (int __cmd)
> +{
> +  switch (__cmd)
> +    {
> +#ifdef F_GET_RW_HINT
> +    case F_GET_RW_HINT:
> +    case F_GET_FILE_RW_HINT:
> +      return 1;
> +#endif
> +
> +    default:
> +      return 0;
> +    }
> +}
> +
> +/* Whether the fcntl CMD requires a (const struct f_owner_ex *) argument.  */
> +__extern_always_inline int
> +__fcntl_is_const_fowner_ex (int __cmd)
> +{
> +  switch (__cmd)
> +    {
> +#ifdef F_SETOWN_EX
> +    case F_SETOWN_EX:
> +      return 1;
> +#endif
> +
> +    default:
> +      return 0;
> +  }
> +}
> +
> +/* Whether the fcntl CMD requires a (struct f_owner_ex *) argument.  */
> +__extern_always_inline int
> +__fcntl_is_fowner_ex (int __cmd)
> +{
> +  switch (__cmd)
> +    {
> +#ifdef F_GETOWN_EX
> +    case F_GETOWN_EX:
> +      return 1;
> +#endif
> +
> +    default:
> +      return 0;
> +  }
> +}
> +
> +/* Whether the fcntl CMD requires either a (const struct flock *) argument
> +   or a (const struct flock64 *) argument.  */
> +__extern_always_inline int
> +__fcntl_is_const_flock_or_64 (int __cmd)
> +{
> +  switch (__cmd)
> +    {
> +#if defined (F_SETLK) && defined (F_SETLK64) && F_SETLK == F_SETLK64
> +    case F_SETLK:
> +    case F_SETLKW:
> +      return 1;
> +#endif
> +
> +    default:
> +      return 0;
> +    }
> +}
> +
> +/* Whether the fcntl CMD requires a (const struct flock *) argument.  */
> +__extern_always_inline int
> +__fcntl_is_const_flock (int __cmd, int __is_fcntl64)
> +{
> +  (void) __is_fcntl64;
> +  switch (__cmd)
> +    {
> +#ifdef F_SETLK
> +    case F_SETLK:
> +    case F_SETLKW:
> +      return 1;
> +#endif
> +
> +#ifdef F_OFD_SETLK
> +    case F_OFD_SETLK:
> +    case F_OFD_SETLKW:
> +      return !__is_fcntl64;
> +#endif
> +
> +    default:
> +      return 0;
> +    }
> +}
> +
> +/* Whether the fcntl CMD requires either a (struct flock *) argument
> +   or a (struct flock64 *) argument.  */
> +__extern_always_inline int
> +__fcntl_is_flock_or_64 (int __cmd)
> +{
> +  switch (__cmd)
> +    {
> +#if defined (F_GETLK) && defined (F_GETLK64) && F_GETLK == F_GETLK64
> +    case F_GETLK:
> +      return 1;
> +#endif
> +
> +    default:
> +      return 0;
> +    }
> +}
> +
> +
> +/* Whether the fcntl CMD requires a (struct flock *) argument.  */
> +__extern_always_inline int
> +__fcntl_is_flock (int __cmd, int __is_fcntl64)
> +{
> +  (void) __is_fcntl64;
> +  switch (__cmd)
> +    {
> +#ifdef F_GETLK
> +    case F_GETLK:
> +      return 1;
> +#endif
> +
> +#ifdef F_OFD_GETLK
> +    case F_OFD_GETLK:
> +      return !__is_fcntl64;
> +#endif
> +
> +    default:
> +      return 0;
> +    }
> +}
> +
> +/* Whether the fcntl CMD requires a (const struct flock64 *) argument.  */
> +__extern_always_inline int
> +__fcntl_is_const_flock64 (int __cmd, int __is_fcntl64)
> +{
> +  (void) __is_fcntl64;
> +  switch (__cmd)
> +    {
> +#ifdef F_SETLK64
> +    case F_SETLK64:
> +    case F_SETLKW64:
> +      return 1;
> +#endif
> +
> +#ifdef F_OFD_SETLK
> +    case F_OFD_SETLK:
> +    case F_OFD_SETLKW:
> +      return __is_fcntl64;
> +#endif
> +
> +    default:
> +      return 0;
> +    }
> +}
> +
> +/* Whether the fcntl CMD requires a (struct flock64 *) argument.  */
> +__extern_always_inline int
> +__fcntl_is_flock64 (int __cmd, int __is_fcntl64)
> +{
> +  (void) __is_fcntl64;
> +  switch (__cmd)
> +    {
> +#ifdef F_GETLK64
> +    case F_GETLK64:
> +      return 1;
> +#endif
> +
> +#ifdef F_OFD_GETLK
> +    case F_OFD_GETLK:
> +      return __is_fcntl64;
> +#endif
> +
> +    default:
> +      return 0;
> +    }
> +}
> +
> +#ifndef __cplusplus
> +
> +# define __fcntl_types_compatible(arg, type)				      \
> +  __builtin_types_compatible_p (__typeof (arg), type)
> +
> +#else
> +
> +extern "C++" {
> +
> +template<typename, typename>
> +struct __fcntl_types_compatible_helper
> +{
> +  __always_inline static int
> +  __compatible ()
> +  {
> +    return 0;
> +  }
> +};
> +
> +template<typename __T>
> +struct __fcntl_types_compatible_helper<__T, __T>
> +{
> +  __always_inline static int
> +  __compatible ()
> +  {
> +    return 1;
> +  }
> +};
> +
> +# define __fcntl_types_compatible(arg, type)				      \
> +  __fcntl_types_compatible_helper<__typeof (arg), type>::__compatible ()
> +
> +} /* extern C++ */
> +
> +#endif /* __cplusplus */
> +
> +#define __fcntl_type_check_int(arg) __fcntl_types_compatible (arg, int)
> +
> +#define __fcntl_type_check_const_uint64_t_ptr(arg)			      \
> + (__fcntl_types_compatible (arg, const __uint64_t *)			      \
> +  || __fcntl_types_compatible (arg, __uint64_t *))
> +
> +#define __fcntl_type_check_uint64_t_ptr(arg)				      \
> +  __fcntl_types_compatible (arg, __uint64_t *)
> +
> +#define __fcntl_type_check_const_fowner_ex(arg)				      \
> +  (__fcntl_types_compatible (arg, const struct f_owner_ex *)		      \
> +   || __fcntl_types_compatible (arg, struct f_owner_ex *))
> +
> +#define __fcntl_type_check_fowner_ex(arg)				      \
> +  __fcntl_types_compatible (arg, struct f_owner_ex *)
> +
> +#define __fcntl_type_check_const_flock(arg)				      \
> +  (__fcntl_types_compatible (arg, const struct flock *)			      \
> +   || __fcntl_types_compatible (arg, struct flock *))
> +
> +#define __fcntl_type_check_flock(arg)					      \
> +  __fcntl_types_compatible (arg, struct flock *)
> +
> +#ifdef __USE_LARGEFILE64
> +
> +# define __fcntl_type_check_const_flock64(arg)				      \
> +  (__fcntl_types_compatible (arg, const struct flock64 *)		      \
> +   || __fcntl_types_compatible (arg, struct flock64 *))
> +
> +# define __fcntl_type_check_flock64(arg)				      \
> +  __fcntl_types_compatible (arg, struct flock64 *)
> +
> +#else
> +
> +# define __fcntl_type_check_const_flock64(arg) 0
> +# define __fcntl_type_check_flock64(arg) 0
> +
> +#endif /* __USE_LARGEFILE64 */
> +
> +#define __fcntl_type_check_const_flock_or_64(arg)			      \
> +  (__fcntl_type_check_const_flock (arg)					      \
> +   || __fcntl_type_check_const_flock64 (arg))
> +
> +#define __fcntl_type_check_flock_or_64(arg)				      \
> +  (__fcntl_type_check_flock (arg) || __fcntl_type_check_flock64 (arg))
> +
> +#define __fcntl_type_check(cmd, arg, is_fcntl64)			      \
> +  (__fcntl_is_int (cmd) ? __fcntl_type_check_int (arg) :		      \
> +   __fcntl_is_const_uint64_t_ptr (cmd)					      \
> +     ? __fcntl_type_check_const_uint64_t_ptr (arg) :			      \
> +   __fcntl_is_uint64_t_ptr (cmd) ? __fcntl_type_check_uint64_t_ptr (arg) :    \
> +   __fcntl_is_const_fowner_ex (cmd)					      \
> +     ? __fcntl_type_check_const_fowner_ex (arg) :			      \
> +   __fcntl_is_fowner_ex (cmd) ? __fcntl_type_check_fowner_ex (arg) :	      \
> +   __fcntl_is_const_flock_or_64 (cmd)					      \
> +     ? __fcntl_type_check_const_flock_or_64 (arg) :			      \
> +   __fcntl_is_flock_or_64 (cmd)						      \
> +     ? __fcntl_type_check_flock_or_64 (arg) :				      \
> +   __fcntl_is_const_flock (cmd, is_fcntl64)				      \
> +     ? __fcntl_type_check_const_flock (arg) :				      \
> +   __fcntl_is_flock (cmd, is_fcntl64) ? __fcntl_type_check_flock (arg) :      \
> +   __fcntl_is_const_flock64 (cmd, is_fcntl64)				      \
> +     ? __fcntl_type_check_const_flock64 (arg) :				      \
> +   __fcntl_is_flock64 (cmd, is_fcntl64) ? __fcntl_type_check_flock64 (arg) :  \
> +   1)
> +
> +
> +__errordecl (__fcntl_missing_arg,
> +             "fcntl with with this command needs 3 arguments");
> +
> +__fortify_function int
> +__fcntl_2_inline (int __fd, int __cmd)
> +{
> +  if (!__builtin_constant_p (__cmd))
> +    return __fcntl_alias (__fd, __cmd);
> +
> +  if (__fcntl_requires_arg (__cmd))
> +    __fcntl_missing_arg ();
> +
> +  return __fcntl_alias (__fd, __cmd);
> +}
> +
> +	
> +
> +#define fcntl(fd, cmd, ...)						      \
> +  (__VA_OPT__ (0 ?) __fcntl_2_inline (fd, cmd)				      \
> +   __VA_OPT__ (:							      \
> +     !__builtin_constant_p (cmd) ? __fcntl_alias (fd, cmd, __VA_ARGS__)	      \
> +        : __fcntl_type_check (cmd, __VA_ARGS__, 0)			      \
> +             ? __fcntl_alias (fd, cmd, __VA_ARGS__)			      \
> +             : __fcntl_warn (fd, cmd, __VA_ARGS__)))
> +
> +#ifdef __USE_LARGEFILE64
> +
> +#define fcntl64(fd, cmd, ...)						      \
> +  (__VA_OPT__ (0 ?) __fcntl_2_inline (fd, cmd)				      \
> +   __VA_OPT__ (:							      \
> +     !__builtin_constant_p (cmd) ? __fcntl64_alias (fd, cmd, __VA_ARGS__)     \
> +        : __fcntl_type_check (cmd, __VA_ARGS__, 1)			      \
> +             ? __fcntl64_alias (fd, cmd, __VA_ARGS__)			      \
> +             : __fcntl64_warn (fd, cmd, __VA_ARGS__)))
> +
> +
> +#endif
> +
> +__glibc_warn_system_headers_end
> diff --git a/io/fcntl.h b/io/fcntl.h
> index dd620c08..61738f42 100644
> --- a/io/fcntl.h
> +++ b/io/fcntl.h
> @@ -337,11 +337,17 @@ extern int posix_fallocate64 (int __fd, off64_t __offset, off64_t __len);
>  
>  
>  /* Define some inlines helping to catch common problems.  */
> +

Spurious new line?

>  #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function \
>      && defined __va_arg_pack_len
>  # include <bits/fcntl2.h>
>  #endif
>  
> +#if __USE_FORTIFY_LEVEL > 0 && defined (__fortify_function) \
> +    && (__GNUC_PREREQ (8, 1) || __glibc_clang_prereq (12, 0))
> +# include <bits/fcntl3.h>
> +#endif
> +
>  __END_DECLS
>  
>  #endif /* fcntl.h  */
> diff --git a/manual/maint.texi b/manual/maint.texi
> index 89da704f..11509def 100644
> --- a/manual/maint.texi
> +++ b/manual/maint.texi
> @@ -200,7 +200,7 @@ functions but may also include checks for validity of other inputs to
>  the functions.
>  
>  When the @code{_FORTIFY_SOURCE} macro is defined, it enables code that
> -validates inputs passed to some functions in @theglibc to determine if
> +validates inputs passed to some functions in @theglibc{} to determine if
>  they are safe.  If the compiler is unable to determine that the inputs
>  to the function call are safe, the call may be replaced by a call to its
>  hardened variant that does additional safety checks at runtime.  Some
> @@ -221,7 +221,8 @@ returned by the @code{__builtin_object_size} compiler builtin function.
>  If the function returns @code{(size_t) -1}, the function call is left
>  untouched.  Additionally, this level also enables validation of flags to
>  the @code{open}, @code{open64}, @code{openat} and @code{openat64}
> -functions.
> +functions, as well as validation of the presence and the type of the
> +third argument to the @code{fcntl} and @code{fcntl64} functions.
>  
>  @item @math{2}: This behaves like @math{1}, with the addition of some
>  checks that may trap code that is conforming but unsafe, e.g. accepting
> @@ -267,6 +268,10 @@ The following functions and macros are fortified in @theglibc{}:
>  
>  @item @code{explicit_bzero}
>  
> +@item @code{fcntl}
> +
> +@item @code{fcntl64}
> +
>  @item @code{FD_SET}
>  
>  @item @code{FD_CLR}
> diff --git a/posix/test-errno.c b/posix/test-errno.c
> index 3685fd15..e73978aa 100644
> --- a/posix/test-errno.c
> +++ b/posix/test-errno.c
> @@ -122,7 +122,9 @@ do_test (void)
>    fails |= test_wrp (EBADF, dup2, -1, -1);
>    fails |= test_wrp (EBADF, fchdir, -1);
>    fails |= test_wrp (EBADF, fchmod, -1, 0);
> -  fails |= test_wrp (EBADF, fcntl, -1, 0);
> +  /* Parenthesized to avoid the fortification macro, which finds a different
> +     error here at compile time.  */
> +  fails |= test_wrp (EBADF, (fcntl), -1, 0);
>    fails |= test_wrp (EBADF, fstatfs, -1, &sfs);
>    fails |= test_wrp (EBADF, fsync, -1);
>    fails |= test_wrp (EBADF, ftruncate, -1, 0);
> diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
> index be801e3b..ddbf441b 100644
> --- a/sysdeps/unix/sysv/linux/Makefile
> +++ b/sysdeps/unix/sysv/linux/Makefile
> @@ -246,6 +246,10 @@ ifeq ($(have-GLIBC_2.27)$(build-shared),yesyes)
>  tests += \
>    tst-ofdlocks-compat \
>    # tests
> +
> +routines_no_fortify += \
> +  tst-ofdlocks-compat \
> +  # routines_no_fortify
>  endif
>  
>  tests-internal += \

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

* Re: [PATCH v4 6/6] io: Also verify 2-arg fctnl calls at runtime
  2023-07-30 19:26 ` [PATCH v4 6/6] io: Also verify 2-arg fctnl calls at runtime Sergey Bugaev
@ 2023-08-08 18:29   ` Adhemerval Zanella Netto
  0 siblings, 0 replies; 15+ messages in thread
From: Adhemerval Zanella Netto @ 2023-08-08 18:29 UTC (permalink / raw)
  To: Sergey Bugaev, libc-alpha



On 30/07/23 16:26, Sergey Bugaev via Libc-alpha wrote:
> This adds a runtime fortification function, __fcntl_2, similar to
> __open_2, that checks at runtime whether the actual passed-in command in
> fact requires a third argument, and aborts if so.
> 
> The abilists have been modified with 'make update-all-abi'.
> 
> Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>

Look good, only a minor change below.

> ---
> 
> Compared to v3, now targeting GLIBC_2.39.
> You can still drop this patch if you don't want it.
> 
>  debug/tst-fortify.c                           | 11 +++++++
>  include/fcntl.h                               |  1 +
>  io/Makefile                                   |  1 +
>  io/Versions                                   |  3 ++
>  io/bits/fcntl3.h                              |  4 ++-
>  io/fcntl_2.c                                  | 33 +++++++++++++++++++
>  manual/maint.texi                             | 10 +++---
>  sysdeps/mach/hurd/i386/libc.abilist           |  1 +
>  sysdeps/mach/hurd/x86_64/libc.abilist         |  1 +
>  sysdeps/unix/sysv/linux/aarch64/libc.abilist  |  1 +
>  sysdeps/unix/sysv/linux/alpha/libc.abilist    |  1 +
>  sysdeps/unix/sysv/linux/arc/libc.abilist      |  1 +
>  sysdeps/unix/sysv/linux/arm/be/libc.abilist   |  1 +
>  sysdeps/unix/sysv/linux/arm/le/libc.abilist   |  1 +
>  sysdeps/unix/sysv/linux/csky/libc.abilist     |  1 +
>  sysdeps/unix/sysv/linux/hppa/libc.abilist     |  1 +
>  sysdeps/unix/sysv/linux/i386/libc.abilist     |  1 +
>  sysdeps/unix/sysv/linux/ia64/libc.abilist     |  1 +
>  .../sysv/linux/loongarch/lp64/libc.abilist    |  1 +
>  .../sysv/linux/m68k/coldfire/libc.abilist     |  1 +
>  .../unix/sysv/linux/m68k/m680x0/libc.abilist  |  1 +
>  .../sysv/linux/microblaze/be/libc.abilist     |  1 +
>  .../sysv/linux/microblaze/le/libc.abilist     |  1 +
>  .../sysv/linux/mips/mips32/fpu/libc.abilist   |  1 +
>  .../sysv/linux/mips/mips32/nofpu/libc.abilist |  1 +
>  .../sysv/linux/mips/mips64/n32/libc.abilist   |  1 +
>  .../sysv/linux/mips/mips64/n64/libc.abilist   |  1 +
>  sysdeps/unix/sysv/linux/nios2/libc.abilist    |  1 +
>  sysdeps/unix/sysv/linux/or1k/libc.abilist     |  1 +
>  .../linux/powerpc/powerpc32/fpu/libc.abilist  |  1 +
>  .../powerpc/powerpc32/nofpu/libc.abilist      |  1 +
>  .../linux/powerpc/powerpc64/be/libc.abilist   |  1 +
>  .../linux/powerpc/powerpc64/le/libc.abilist   |  1 +
>  .../unix/sysv/linux/riscv/rv32/libc.abilist   |  1 +
>  .../unix/sysv/linux/riscv/rv64/libc.abilist   |  1 +
>  .../unix/sysv/linux/s390/s390-32/libc.abilist |  1 +
>  .../unix/sysv/linux/s390/s390-64/libc.abilist |  1 +
>  sysdeps/unix/sysv/linux/sh/be/libc.abilist    |  1 +
>  sysdeps/unix/sysv/linux/sh/le/libc.abilist    |  1 +
>  .../sysv/linux/sparc/sparc32/libc.abilist     |  1 +
>  .../sysv/linux/sparc/sparc64/libc.abilist     |  1 +
>  .../unix/sysv/linux/x86_64/64/libc.abilist    |  1 +
>  .../unix/sysv/linux/x86_64/x32/libc.abilist   |  1 +
>  43 files changed, 94 insertions(+), 5 deletions(-)
>  create mode 100644 io/fcntl_2.c
> 
> diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c
> index 98654299..f076baee 100644
> --- a/debug/tst-fortify.c
> +++ b/debug/tst-fortify.c
> @@ -1915,6 +1915,12 @@ do_test (void)
>      }
>  #endif
>  
> +#if __USE_FORTIFY_LEVEL >= 1
> +  CHK_FAIL_START
> +  fcntl (STDIN_FILENO, hide_constant (F_SETFD));
> +  CHK_FAIL_END
> +#endif
> +
>  #if defined (__USE_LARGEFILE64) || defined (__USE_TIME_BITS64)
>    /* Also check fcntl64 ().  */
>    res = fcntl64 (STDIN_FILENO, F_GETFD);
> @@ -1979,6 +1985,11 @@ do_test (void)
>      }
>  #endif
>  
> +# if __USE_FORTIFY_LEVEL >= 1
> +  CHK_FAIL_START
> +  fcntl64 (STDIN_FILENO, hide_constant (F_SETFD));
> +  CHK_FAIL_END
> +# endif
>  #endif
>  
>    return ret;
> diff --git a/include/fcntl.h b/include/fcntl.h
> index be435047..cb86c5e7 100644
> --- a/include/fcntl.h
> +++ b/include/fcntl.h
> @@ -32,6 +32,7 @@ extern int __open64_2 (const char *__path, int __oflag);
>  extern int __openat_2 (int __fd, const char *__path, int __oflag);
>  extern int __openat64_2 (int __fd, const char *__path, int __oflag);
>  
> +extern int __fcntl_2 (int __fd, int __cmd);
>  
>  #if IS_IN (rtld)
>  #  include <dl-fcntl.h>
> diff --git a/io/Makefile b/io/Makefile
> index 0c43881f..7e08ed88 100644
> --- a/io/Makefile
> +++ b/io/Makefile
> @@ -72,6 +72,7 @@ routines := \
>    fchownat \
>    fcntl \
>    fcntl64 \
> +  fcntl_2 \
>    file_change_detection \
>    flock \
>    fstat \
> diff --git a/io/Versions b/io/Versions
> index 4e195408..bff2b7cf 100644
> --- a/io/Versions
> +++ b/io/Versions
> @@ -140,6 +140,9 @@ libc {
>    GLIBC_2.34 {
>      closefrom;
>    }
> +  GLIBC_2.39 {
> +    __fcntl_2;
> +  }
>    GLIBC_PRIVATE {
>      __libc_fcntl64;
>      __fcntl_nocancel;
> diff --git a/io/bits/fcntl3.h b/io/bits/fcntl3.h
> index 9016d37e..bb61f53c 100644
> --- a/io/bits/fcntl3.h
> +++ b/io/bits/fcntl3.h
> @@ -20,6 +20,8 @@
>  # error "Never include <bits/fcntl3.h> directly; use <fcntl.h> instead."
>  #endif
>  
> +extern int __fcntl_2 (int __fd, int __cmd);
> +

I think this should be marked as __THROW.

>  #ifndef __USE_TIME_BITS64
>  
>  # ifndef __USE_FILE_OFFSET64
> @@ -437,7 +439,7 @@ __fortify_function int
>  __fcntl_2_inline (int __fd, int __cmd)
>  {
>    if (!__builtin_constant_p (__cmd))
> -    return __fcntl_alias (__fd, __cmd);
> +    return __fcntl_2 (__fd, __cmd);
>  
>    if (__fcntl_requires_arg (__cmd))
>      __fcntl_missing_arg ();
> diff --git a/io/fcntl_2.c b/io/fcntl_2.c
> new file mode 100644
> index 00000000..d9fd9c04
> --- /dev/null
> +++ b/io/fcntl_2.c
> @@ -0,0 +1,33 @@
> +/* _FORTIFY_SOURCE wrapper for fcntl.
> +   Copyright (C) 2013-2023 Free Software Foundation, Inc.
> +   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/>.  */
> +
> +/* Make sure to get __fcntl_requires_arg from bits/fcntl3.h */
> +#undef _FORTIFY_SOURCE
> +#define _FORTIFY_SOURCE 1
> +
> +#include <fcntl.h>
> +#include <stdio.h>
> +
> +int
> +__fcntl_2 (int fd, int cmd)
> +{
> +  if (__fcntl_requires_arg (cmd))
> +    __fortify_fail ("invalid fcntl call: this cmd requires an argument");
> +
> +  return __libc_fcntl64 (fd, cmd);
> +}
> diff --git a/manual/maint.texi b/manual/maint.texi
> index 11509def..9b24e5a0 100644
> --- a/manual/maint.texi
> +++ b/manual/maint.texi
> @@ -244,10 +244,11 @@ depending on the architecture, one may also see fortified variants have
>  the @code{_chkieee128} suffix or the @code{__nldbl___} prefix to their
>  names.
>  
> -Another exception is the @code{open} family of functions, where their
> -fortified replacements have the @code{__} prefix and a @code{_2} suffix.
> -The @code{FD_SET}, @code{FD_CLR} and @code{FD_ISSET} macros use the
> -@code{__fdelt_chk} function on fortification.
> +Another exception is the @code{open} and @code{fcntl} families of
> +functions, where their fortified 2-argument version replacements have the
> +@code{__} prefix and a @code{_2} suffix. The @code{FD_SET}, @code{FD_CLR}
> +and @code{FD_ISSET} macros use the @code{__fdelt_chk} function on
> +fortification.
>  
>  The following functions and macros are fortified in @theglibc{}:
>  @c Generated using the following command:
> @@ -256,6 +257,7 @@ The following functions and macros are fortified in @theglibc{}:
>  @c   sort -u | grep ^__ |
>  @c   grep -v -e ieee128 -e __nldbl -e align_cpy -e "fdelt_warn" |
>  @c   sed 's/__fdelt_chk/@item @code{FD_SET}\n\n@item @code{FD_CLR}\n\n@item @code{FD_ISSET}\n/' |
> +@c   sed 's/__fcntl_2/@item @code{fcntl}\n\n@item @code{fcntl64}\n/' |
>  @c   sed 's/__\(.*\)_\(chk\|2\)/@item @code{\1}\n/'
>  
>  @itemize @bullet

Ok.

> diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
> index 74a9f427..9e74779c 100644
> --- a/sysdeps/mach/hurd/i386/libc.abilist
> +++ b/sysdeps/mach/hurd/i386/libc.abilist
> @@ -2334,6 +2334,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/mach/hurd/x86_64/libc.abilist b/sysdeps/mach/hurd/x86_64/libc.abilist
> index 24db98d7..d9261ca1 100644
> --- a/sysdeps/mach/hurd/x86_64/libc.abilist
> +++ b/sysdeps/mach/hurd/x86_64/libc.abilist
> @@ -2114,6 +2114,7 @@ GLIBC_2.38 wprintf F
>  GLIBC_2.38 write F
>  GLIBC_2.38 writev F
>  GLIBC_2.38 wscanf F
> +GLIBC_2.39 __fcntl_2 F
>  HURD_CTHREADS_0.3 __cthread_getspecific F
>  HURD_CTHREADS_0.3 __cthread_keycreate F
>  HURD_CTHREADS_0.3 __cthread_setspecific F
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index c49363e7..49103c3e 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2673,3 +2673,4 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index d6b1dcaa..77acc615 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -2782,6 +2782,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 _IO_fprintf F
>  GLIBC_2.4 _IO_printf F
>  GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
> index dfe0c3f7..ef9acbdb 100644
> --- a/sysdeps/unix/sysv/linux/arc/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
> @@ -2434,3 +2434,4 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
> diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> index 6c75e5aa..df4efc55 100644
> --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> @@ -554,6 +554,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 _Exit F
>  GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
>  GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
> diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> index 03d6f7ae..bcdc2764 100644
> --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> @@ -551,6 +551,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 _Exit F
>  GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
>  GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> index d858c108..7013676f 100644
> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> @@ -2710,3 +2710,4 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index 82a14f8a..8fc8e661 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -2659,6 +2659,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index 1950b15d..ee837f3b 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -2843,6 +2843,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> index d0b9cb27..6b0ade18 100644
> --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> @@ -2608,6 +2608,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> index e760a631..99fe672d 100644
> --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> @@ -2194,3 +2194,4 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index 35785a3d..4e24bf9a 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -555,6 +555,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 _Exit F
>  GLIBC_2.4 _IO_2_1_stderr_ D 0x98
>  GLIBC_2.4 _IO_2_1_stdin_ D 0x98
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index 4ab2426e..ab53ab23 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -2786,6 +2786,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> index 38faa162..2b3149e7 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> @@ -2759,3 +2759,4 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> index 374d6589..5922edcb 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> @@ -2756,3 +2756,4 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index fcc5e88e..768948b2 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -2751,6 +2751,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index 01eb96cd..d0931261 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -2749,6 +2749,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index a2748b7b..87b90cf4 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -2757,6 +2757,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index 0ae7ba49..8b8fb90f 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -2659,6 +2659,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> index 947495a0..706941fc 100644
> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> @@ -2798,3 +2798,4 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
> diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> index 115f1039..a5ef08f7 100644
> --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> @@ -2180,3 +2180,4 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index 19c4c325..c9795714 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -2825,6 +2825,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 _IO_fprintf F
>  GLIBC_2.4 _IO_printf F
>  GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index 3e043c40..0402ce99 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -2858,6 +2858,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 _IO_fprintf F
>  GLIBC_2.4 _IO_printf F
>  GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> index e4f3a766..ea9d4d61 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> @@ -2579,6 +2579,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 _IO_fprintf F
>  GLIBC_2.4 _IO_printf F
>  GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> index dafe1c4a..67faa8f5 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> @@ -2893,3 +2893,4 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> index b9740a1a..0f5c2079 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> @@ -2436,3 +2436,4 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> index e3b4656a..f18f3b0d 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> @@ -2636,3 +2636,4 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index 84cb7a50..d07a7539 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -2823,6 +2823,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 _IO_fprintf F
>  GLIBC_2.4 _IO_printf F
>  GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index 33df3b16..80e01cc6 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -2616,6 +2616,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 _IO_fprintf F
>  GLIBC_2.4 _IO_printf F
>  GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> index 94cbccd7..9961ef14 100644
> --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> @@ -2666,6 +2666,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> index 3bb316a7..3c8a3da2 100644
> --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> @@ -2663,6 +2663,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index 6341b491..3cbd4543 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -2818,6 +2818,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 _IO_fprintf F
>  GLIBC_2.4 _IO_printf F
>  GLIBC_2.4 _IO_sprintf F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index 8ed1ea29..b3159408 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -2631,6 +2631,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index 57cfcc20..307e2a7c 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -2582,6 +2582,7 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F
>  GLIBC_2.4 __confstr_chk F
>  GLIBC_2.4 __fgets_chk F
>  GLIBC_2.4 __fgets_unlocked_chk F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index 3f0a9f6d..1bb0cbde 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2688,3 +2688,4 @@ GLIBC_2.38 strlcat F
>  GLIBC_2.38 strlcpy F
>  GLIBC_2.38 wcslcat F
>  GLIBC_2.38 wcslcpy F
> +GLIBC_2.39 __fcntl_2 F

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

* Re: [PATCH v4 1/6] Fix calling fcntl64 (fd, F_SETLK, &flock64)
  2023-07-31 17:50   ` Adhemerval Zanella Netto
@ 2023-08-08 18:40     ` Sergey Bugaev
  0 siblings, 0 replies; 15+ messages in thread
From: Sergey Bugaev @ 2023-08-08 18:40 UTC (permalink / raw)
  To: Adhemerval Zanella Netto; +Cc: libc-alpha, Florian Weimer, Frederic Berat

Hello,

On Mon, Jul 31, 2023 at 8:50 PM Adhemerval Zanella Netto
<adhemerval.zanella@linaro.org> wrote:
> Nice, it seems that on both tests the fields that might trigger wrong values
> by the kernel reading the struct with a wrong size (l_start and l_len) are
> always being 0 and thus it should not matter.
>
> LGTM, thanks.

But please note that this only really fortifies tests & other code
that uses the public fcntl/fcntl64 API, not callers of __libc_fcntl64,
so it's not a guarantee that there are no more cases of this. Though I
guess this applies equally to all the other fortifications.

Sergey

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

end of thread, other threads:[~2023-08-08 18:40 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-30 19:25 [PATCH v4 0/6] fcntl fortification Sergey Bugaev
2023-07-30 19:25 ` [PATCH v4 1/6] Fix calling fcntl64 (fd, F_SETLK, &flock64) Sergey Bugaev
2023-07-31 17:50   ` Adhemerval Zanella Netto
2023-08-08 18:40     ` Sergey Bugaev
2023-07-30 19:25 ` [PATCH v4 2/6] support: Add support_fcntl_support_ofd_locks () Sergey Bugaev
2023-07-30 19:25 ` [PATCH v4 3/6] cdefs.h: Define __glibc_warn_system_headers_{begin,end} Sergey Bugaev
2023-07-30 19:25 ` [PATCH v4 4/6] cdefs.h: Enable __errordecl & __warnattr for Clang 14+ Sergey Bugaev
2023-08-02 17:23   ` Adhemerval Zanella Netto
2023-07-30 19:26 ` [PATCH v4 5/6] io: Add FORTIFY_SOURCE check for fcntl arguments Sergey Bugaev
2023-07-30 19:54   ` Sergey Bugaev
2023-08-02 19:46   ` Adhemerval Zanella Netto
2023-07-30 19:26 ` [PATCH v4 6/6] io: Also verify 2-arg fctnl calls at runtime Sergey Bugaev
2023-08-08 18:29   ` Adhemerval Zanella Netto
2023-07-31 14:40 ` [PATCH v4 0/6] fcntl fortification Zack Weinberg
2023-07-31 17:25   ` Adhemerval Zanella Netto

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).