diff mbox series

[RFC,1/1] io: Add FORTIFY_SOURCE check for fcntl arguments

Message ID 20230519213059.3812385-2-bugaevc@gmail.com
State New
Headers show
Series Attempt to detect missing fcntl argument at compile time | expand

Commit Message

Sergey Bugaev May 19, 2023, 9:30 p.m. UTC
Both open () and fcntl () are "overloaded" to accept either 2 or 3
arguments; whether the last argument is required 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 ().

Recently, Hector Martin <marcan@marcan.st> has identified an issue in
libwebrtc where fcntl (fd, F_DUPFD_CLOEXEC) was invoked without a third
argument [0]. With the patch, the bug would have been detected at
compile time, assuming libwebrtc is built with FORTIFY_SOURCE. Hopefully
this will help detecting similar bugs in existing software, and prevent
more instances of similar bugs from being introduced in the future.

[0]: https://social.treehouse.systems/@marcan/110355001391961285

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

Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>
---
 include/fcntl.h                               |   3 +
 io/Makefile                                   |   2 +-
 io/Versions                                   |   4 +
 io/bits/fcntl2.h                              | 139 ++++++++++++++++++
 io/fcntl64_2.c                                |  33 +++++
 io/fcntl_2.c                                  |  33 +++++
 sysdeps/mach/hurd/i386/libc.abilist           |   2 +
 sysdeps/mach/hurd/x86_64/libc.abilist         |   2 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   2 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |   2 +
 sysdeps/unix/sysv/linux/arc/libc.abilist      |   2 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   2 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   2 +
 sysdeps/unix/sysv/linux/csky/libc.abilist     |   2 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist     |   2 +
 sysdeps/unix/sysv/linux/i386/libc.abilist     |   2 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist     |   2 +
 .../sysv/linux/loongarch/lp64/libc.abilist    |   2 +
 .../sysv/linux/m68k/coldfire/libc.abilist     |   2 +
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   2 +
 .../sysv/linux/microblaze/be/libc.abilist     |   2 +
 .../sysv/linux/microblaze/le/libc.abilist     |   2 +
 .../sysv/linux/mips/mips32/fpu/libc.abilist   |   2 +
 .../sysv/linux/mips/mips32/nofpu/libc.abilist |   2 +
 .../sysv/linux/mips/mips64/n32/libc.abilist   |   2 +
 .../sysv/linux/mips/mips64/n64/libc.abilist   |   2 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist    |   2 +
 sysdeps/unix/sysv/linux/or1k/libc.abilist     |   2 +
 .../linux/powerpc/powerpc32/fpu/libc.abilist  |   2 +
 .../powerpc/powerpc32/nofpu/libc.abilist      |   2 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |   2 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |   2 +
 .../unix/sysv/linux/riscv/rv32/libc.abilist   |   2 +
 .../unix/sysv/linux/riscv/rv64/libc.abilist   |   2 +
 .../unix/sysv/linux/s390/s390-32/libc.abilist |   2 +
 .../unix/sysv/linux/s390/s390-64/libc.abilist |   2 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   2 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   2 +
 .../sysv/linux/sparc/sparc32/libc.abilist     |   2 +
 .../sysv/linux/sparc/sparc64/libc.abilist     |   2 +
 .../unix/sysv/linux/x86_64/64/libc.abilist    |   2 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |   2 +
 42 files changed, 285 insertions(+), 1 deletion(-)
 create mode 100644 io/fcntl64_2.c
 create mode 100644 io/fcntl_2.c

Comments

Joseph Myers May 19, 2023, 9:55 p.m. UTC | #1
I'm concerned about the lack of testcases in this patch.  I'm not sure of 
how we should be checking for compile-time errors (there are several 
existing tests for runtime fortification), but having this functionality 
without testcases seems risky.
Sergey Bugaev May 20, 2023, 11:46 a.m. UTC | #2
Hello,

On Sat, May 20, 2023 at 12:55 AM Joseph Myers <joseph@codesourcery.com> wrote:
> I'm concerned about the lack of testcases in this patch.  I'm not sure of
> how we should be checking for compile-time errors (there are several
> existing tests for runtime fortification), but having this functionality
> without testcases seems risky.

Yes, absolutely, I agree. Let me attempt to add some tests then!

Considering it's unclear how to test for compilation errors, maybe we
don't have to (despite these errors being the main point of the
patch). What's important is ensuring that the fortification doesn't
break legitimate programs, either because of me messing up how
fcntl/fcntl64 are defined in some particular configuration vs how they
are now defined in fcntl2.h, or because of some undefined F_COMMAND
being used in __fcntl_cmd_needs_arg.

I see that there's already debug/tst-fortify.c that gets built and
tested in various configurations (exactly what I need!) and even has
the CHK_FAIL_START / CHK_FAIL_END facilities for catching the SIGABRT
and recording test success. So should I just add a bunch of
fcntl/fcntl64 tests there?

What would be a good way to test for 32-bit vs 64-bit confusion?
Something involving F_OFD_*LK, perhaps?

Is there an existing test for open{at,64,at64} fortification somewhere
that I could copy-paste^W^W take inspiration from?

Sergey
Adhemerval Zanella Netto May 23, 2023, 7:09 p.m. UTC | #3
On 19/05/23 18:30, 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 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 ().
> 
> Recently, Hector Martin <marcan@marcan.st> has identified an issue in
> libwebrtc where fcntl (fd, F_DUPFD_CLOEXEC) was invoked without a third
> argument [0]. With the patch, the bug would have been detected at
> compile time, assuming libwebrtc is built with FORTIFY_SOURCE. Hopefully
> this will help detecting similar bugs in existing software, and prevent
> more instances of similar bugs from being introduced in the future.
> 
> [0]: https://social.treehouse.systems/@marcan/110355001391961285
> 
> The abilists have been modified with 'make update-abi-all'.
> 
> Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>
> ---
>  include/fcntl.h                               |   3 +
>  io/Makefile                                   |   2 +-
>  io/Versions                                   |   4 +
>  io/bits/fcntl2.h                              | 139 ++++++++++++++++++
>  io/fcntl64_2.c                                |  33 +++++
>  io/fcntl_2.c                                  |  33 +++++
>  sysdeps/mach/hurd/i386/libc.abilist           |   2 +
>  sysdeps/mach/hurd/x86_64/libc.abilist         |   2 +
>  sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   2 +
>  sysdeps/unix/sysv/linux/alpha/libc.abilist    |   2 +
>  sysdeps/unix/sysv/linux/arc/libc.abilist      |   2 +
>  sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   2 +
>  sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   2 +
>  sysdeps/unix/sysv/linux/csky/libc.abilist     |   2 +
>  sysdeps/unix/sysv/linux/hppa/libc.abilist     |   2 +
>  sysdeps/unix/sysv/linux/i386/libc.abilist     |   2 +
>  sysdeps/unix/sysv/linux/ia64/libc.abilist     |   2 +
>  .../sysv/linux/loongarch/lp64/libc.abilist    |   2 +
>  .../sysv/linux/m68k/coldfire/libc.abilist     |   2 +
>  .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   2 +
>  .../sysv/linux/microblaze/be/libc.abilist     |   2 +
>  .../sysv/linux/microblaze/le/libc.abilist     |   2 +
>  .../sysv/linux/mips/mips32/fpu/libc.abilist   |   2 +
>  .../sysv/linux/mips/mips32/nofpu/libc.abilist |   2 +
>  .../sysv/linux/mips/mips64/n32/libc.abilist   |   2 +
>  .../sysv/linux/mips/mips64/n64/libc.abilist   |   2 +
>  sysdeps/unix/sysv/linux/nios2/libc.abilist    |   2 +
>  sysdeps/unix/sysv/linux/or1k/libc.abilist     |   2 +
>  .../linux/powerpc/powerpc32/fpu/libc.abilist  |   2 +
>  .../powerpc/powerpc32/nofpu/libc.abilist      |   2 +
>  .../linux/powerpc/powerpc64/be/libc.abilist   |   2 +
>  .../linux/powerpc/powerpc64/le/libc.abilist   |   2 +
>  .../unix/sysv/linux/riscv/rv32/libc.abilist   |   2 +
>  .../unix/sysv/linux/riscv/rv64/libc.abilist   |   2 +
>  .../unix/sysv/linux/s390/s390-32/libc.abilist |   2 +
>  .../unix/sysv/linux/s390/s390-64/libc.abilist |   2 +
>  sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   2 +
>  sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   2 +
>  .../sysv/linux/sparc/sparc32/libc.abilist     |   2 +
>  .../sysv/linux/sparc/sparc64/libc.abilist     |   2 +
>  .../unix/sysv/linux/x86_64/64/libc.abilist    |   2 +
>  .../unix/sysv/linux/x86_64/x32/libc.abilist   |   2 +
>  42 files changed, 285 insertions(+), 1 deletion(-)
>  create mode 100644 io/fcntl64_2.c
>  create mode 100644 io/fcntl_2.c
> 
> diff --git a/include/fcntl.h b/include/fcntl.h
> index d788db2e..7742c002 100644
> --- a/include/fcntl.h
> +++ b/include/fcntl.h
> @@ -32,6 +32,9 @@ 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);
> +extern int __fcntl64_2 (int __fd, int __cmd);
> +
>  
>  /* Makes open () & friends faster on the Hurd, but can only be used (without
>     altering user-visible behavior) when we're sure that the file we're opening
> diff --git a/io/Makefile b/io/Makefile
> index f72571cd..350807ee 100644
> --- a/io/Makefile
> +++ b/io/Makefile
> @@ -41,7 +41,7 @@ routines :=								\
>  	mkdir mkdirat							\
>  	open open_2 open64 open64_2 openat openat_2 openat64 openat64_2	\
>  	read write lseek lseek64 access euidaccess faccessat		\
> -	fcntl fcntl64 flock lockf lockf64				\
> +	fcntl fcntl_2 fcntl64 fcntl64_2 flock lockf lockf64		\
>  	close dup dup2 dup3 pipe pipe2					\
>  	creat creat64							\
>  	chdir fchdir							\
> diff --git a/io/Versions b/io/Versions
> index 4e195408..8409e105 100644
> --- a/io/Versions
> +++ b/io/Versions
> @@ -140,6 +140,10 @@ libc {
>    GLIBC_2.34 {
>      closefrom;
>    }
> +  GLIBC_2.38 {
> +    __fcntl_2;
> +    __fcntl64_2;
> +  }
>    GLIBC_PRIVATE {
>      __libc_fcntl64;
>      __fcntl_nocancel;
> diff --git a/io/bits/fcntl2.h b/io/bits/fcntl2.h
> index bdb48fa8..beb3a628 100644
> --- a/io/bits/fcntl2.h
> +++ b/io/bits/fcntl2.h
> @@ -170,3 +170,142 @@ openat64 (int __fd, const char *__path, int __oflag, ...)
>  }
>  # endif
>  #endif
> +
> +#ifndef __USE_TIME_BITS64
> +
> +# ifndef __USE_FILE_OFFSET64
> +/* Just fcntl ().  */

Does this comment adds anything?  Also I think we avoid to use '()' on function
definition on comments.

> +extern int __fcntl_2 (int __fd, int __cmd);
> +extern int __REDIRECT (__fcntl_alias, (int __fd, int __cmd, ...), fcntl);
> +# else
> +/* fcntl.h redirects fcntl () to fcntl64 ().  */
> +extern int __REDIRECT (__fcntl_2, (int __fd, int __cmd), __fcntl64_2);
> +extern int __REDIRECT (__fcntl_alias, (int __fd, int __cmd, ...), fcntl64);
> +# endif /* __USE_FILE_OFFSET64 */
> +
> +# ifdef __USE_LARGEFILE64
> +/* Just fcntl64 ().  */
> +extern int __fcntl64_2 (int __fd, int __cmd);
> +extern int __REDIRECT (__fcntl64_alias, (int __fd, int __cmd, ...), fcntl64);
> +# endif
> +
> +#else /* __USE_TIME_BITS64 */
> +
> +/* fcntl.h redirects both fcntl () and fcntl64 () to __fcntl_time64 ().  */
> +extern int __fcntl64_2 (int __fd, int __cmd);
> +extern int __REDIRECT (__fcntl_2, (int __fd, int __cmd), __fcntl64_2);
> +extern int __REDIRECT_NTH (__fcntl_alias, (int __fd, int __cmd, ...),
> +			   __fcntl_time64);
> +extern int __REDIRECT_NTH (__fcntl64_alias, (int __fd, int __cmd, ...),
> +			   __fcntl_time64);
> +#endif /* __USE_TIME_BITS64 */
> +
> +__errordecl (__fcntl_too_many_args,
> +             "fcntl can be called either with 2 or 3 arguments, not more");
> +__errordecl (__fcntl_missing_arg,
> +             "fcntl with with this cmd needs 3 arguments");
> +
> +__extern_always_inline int

Should we use  __fortify_function also for this case?

> +__fcntl_cmd_needs_arg (int __cmd)
> +{
> +  switch (__cmd)
> +    {
> +    case F_DUPFD:
> +    case F_DUPFD_CLOEXEC:
> +    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

I think it would be better to condicionalize using __USE_GNU:

#ifdef __USE_GNU
    case F_GETOWN_EX:
    case F_SETOWN_EX:
    case F_SETSIG:
#endif

Since the double underscore symbols are implementation defined one and should
not be used by the application.

> +#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;
> +
> +    case F_GETFD:
> +    case F_GETFL:
> +#ifdef F_GETOWN
> +    case F_GETOWN:
> +#endif
> +#ifdef __F_GETSIG
> +    case __F_GETSIG:
> +#endif
> +#ifdef F_GETLEASE
> +    case F_GETLEASE:
> +    case F_GETPIPE_SZ:
> +    case F_GET_SEALS:
> +#endif
> +    /* For any cmd value we don't know about,
> +       default to not requiring an argument.  */
> +    default:
> +      return 0;
> +    }
> +}

Should be worried that since we don't have const expressions like newer C++
that large switch might ended being extra code on every fcntl call? I think
the __builtin_constant_p check below gives compiler enough information to
avoid it, but I am not sure.

> +
> +__fortify_function int
> +fcntl (int __fd, int __cmd, ...)
> +{
> +  if (__va_arg_pack_len () > 1)
> +    __fcntl_too_many_args ();
> +
> +  if (__builtin_constant_p (__cmd))
> +    {
> +      if (__fcntl_cmd_needs_arg (__cmd) && __va_arg_pack_len () < 1)

No implicit check for function that do not return bool:

  if (__fcntl_cmd_needs_arg (__cmd) == 1 ...)

> +        {
> +          __fcntl_missing_arg ();
> +          return __fcntl_2 (__fd, __cmd);
> +        }
> +      return __fcntl_alias (__fd, __cmd, __va_arg_pack ());
> +    }
> +
> +  if (__va_arg_pack_len () < 1)
> +    return __fcntl_2 (__fd, __cmd);
> +
> +  return __fcntl_alias (__fd, __cmd, __va_arg_pack ());
> +}
> +
> +#ifdef __USE_LARGEFILE64
> +__fortify_function int
> +fcntl64 (int __fd, int __cmd, ...)
> +{
> +  if (__va_arg_pack_len () > 1)
> +    __fcntl_too_many_args ();
> +
> +  if (__builtin_constant_p (__cmd))
> +    {
> +      if (__fcntl_cmd_needs_arg (__cmd) && __va_arg_pack_len () < 1)
> +        {
> +          __fcntl_missing_arg ();
> +          return __fcntl64_2 (__fd, __cmd);
> +        }
> +      return __fcntl64_alias (__fd, __cmd, __va_arg_pack ());
> +    }
> +
> +  if (__va_arg_pack_len () < 1)
> +    return __fcntl64_2 (__fd, __cmd);
> +
> +  return __fcntl64_alias (__fd, __cmd, __va_arg_pack ());
> +}
> +#endif

I think we need also to handle __USE_TIME_BITS64 and add another fcntl debug
symbol to handle; even though for Linux now __fcntl_time64 is just a alias
to __libc_fcntl64.

It is because we even need to add a proper __fcntl_time64 implementation,
the redirection now does:

  fcntl -> __fcntl64_2 -> __libc_fcntl64

Where it should be something like:

  fcntl -> __fcntl_time64_2 -> __fcntl_time64

> diff --git a/io/fcntl64_2.c b/io/fcntl64_2.c
> new file mode 100644
> index 00000000..6352f524
> --- /dev/null
> +++ b/io/fcntl64_2.c
> @@ -0,0 +1,33 @@
> +/* _FORTIFY_SOURCE wrapper for fcntl64.
> +   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_cmd_needs_arg from bits/fcntl2.h */
> +#undef _FORTIFY_SOURCE
> +#define _FORTIFY_SOURCE 1
> +
> +#include <fcntl.h>
> +#include <stdio.h>
> +
> +int
> +__fcntl64_2 (int fd, int cmd)
> +{
> +  if (__fcntl_cmd_needs_arg (cmd))
> +    __fortify_fail ("invalid fcntl64 call: this cmd requires an argument");
> +
> +  return __libc_fcntl64 (fd, cmd);
> +}

Ok.

> diff --git a/io/fcntl_2.c b/io/fcntl_2.c
> new file mode 100644
> index 00000000..fc9303e4
> --- /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_cmd_needs_arg from bits/fcntl2.h */
> +#undef _FORTIFY_SOURCE
> +#define _FORTIFY_SOURCE 1
> +
> +#include <fcntl.h>
> +#include <stdio.h>
> +
> +int
> +__fcntl_2 (int fd, int cmd)
> +{
> +  if (__fcntl_cmd_needs_arg (cmd))
> +    __fortify_fail ("invalid fcntl call: this cmd requires an argument");
> +
> +  return __libc_fcntl (fd, cmd);
> +}

Ok.

> diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
> index 6925222f..fa24d577 100644
> --- a/sysdeps/mach/hurd/i386/libc.abilist
> +++ b/sysdeps/mach/hurd/i386/libc.abilist
> @@ -2294,6 +2294,8 @@ GLIBC_2.36 arc4random_buf F
>  GLIBC_2.36 arc4random_uniform F
>  GLIBC_2.36 c8rtomb F
>  GLIBC_2.36 mbrtoc8 F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/mach/hurd/x86_64/libc.abilist b/sysdeps/mach/hurd/x86_64/libc.abilist
> index a0be5c1a..efb83b16 100644
> --- a/sysdeps/mach/hurd/x86_64/libc.abilist
> +++ b/sysdeps/mach/hurd/x86_64/libc.abilist
> @@ -194,6 +194,8 @@ GLIBC_2.38 __errno_location F
>  GLIBC_2.38 __explicit_bzero_chk F
>  GLIBC_2.38 __fbufsize F
>  GLIBC_2.38 __fcntl F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __fdelt_chk F
>  GLIBC_2.38 __fdelt_warn F
>  GLIBC_2.38 __fentry__ F
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index 0e2d9c30..86144979 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2633,6 +2633,8 @@ GLIBC_2.36 pidfd_open F
>  GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index f1bec197..646c11e3 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -2730,6 +2730,8 @@ GLIBC_2.36 pidfd_open F
>  GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
> index aa874b88..37e9129f 100644
> --- a/sysdeps/unix/sysv/linux/arc/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
> @@ -2394,6 +2394,8 @@ GLIBC_2.36 pidfd_open F
>  GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> index afbd57da..4c9b937e 100644
> --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> @@ -514,6 +514,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> index e7364cd3..8dbf72c5 100644
> --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> @@ -511,6 +511,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> index 913fa592..b58b2b9c 100644
> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> @@ -2670,6 +2670,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index 43af3a98..c80bb835 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -2619,6 +2619,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index af72f8fa..5a737b3d 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -2803,6 +2803,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> index 48cbb0fa..aab6d422 100644
> --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> @@ -2568,6 +2568,8 @@ GLIBC_2.36 pidfd_open F
>  GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> index c15884bb..82da98d2 100644
> --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> @@ -2154,6 +2154,8 @@ GLIBC_2.36 wprintf F
>  GLIBC_2.36 write F
>  GLIBC_2.36 writev F
>  GLIBC_2.36 wscanf F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index 3738db81..f6c80b46 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -515,6 +515,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index ed136277..dc34ea56 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -2746,6 +2746,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> index 83577386..466e4092 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> @@ -2719,6 +2719,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> index 58c5da58..dc27b4e7 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> @@ -2716,6 +2716,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index d3741945..a8dfa647 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -2711,6 +2711,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index 5319fdc2..4defd8dc 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -2709,6 +2709,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index 1743ea6e..824b6b4c 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -2717,6 +2717,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index 9b1f53c6..ff4341a8 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -2619,6 +2619,8 @@ GLIBC_2.36 pidfd_open F
>  GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> index ae1c6ca1..ede0e6eb 100644
> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> @@ -2758,6 +2758,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> index a7c572c9..22525fe8 100644
> --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> @@ -2140,6 +2140,8 @@ GLIBC_2.36 pidfd_open F
>  GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index 074fa031..2938361e 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -2773,6 +2773,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index dfcb4bd2..e1c70a25 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -2806,6 +2806,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> index 63bbccf3..2ce2d974 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> @@ -2527,6 +2527,8 @@ GLIBC_2.36 pidfd_open F
>  GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> index ab85fd61..b1024501 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> @@ -2829,6 +2829,8 @@ GLIBC_2.36 pidfd_open F
>  GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fscanfieee128 F
>  GLIBC_2.38 __isoc23_fwscanf F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> index b716f5c7..833fb747 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> @@ -2396,6 +2396,8 @@ GLIBC_2.36 pidfd_open F
>  GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> index 774e777b..cbd85454 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> @@ -2596,6 +2596,8 @@ GLIBC_2.36 pidfd_open F
>  GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index 8625135c..1442a0b9 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -2771,6 +2771,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index d00c7eb2..1a7f4fc7 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -2564,6 +2564,8 @@ GLIBC_2.36 pidfd_open F
>  GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> index b6303724..3146ce99 100644
> --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> @@ -2626,6 +2626,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> index d8005561..31360691 100644
> --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> @@ -2623,6 +2623,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index 5be55c11..026e9581 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -2766,6 +2766,8 @@ GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
>  GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index 475fdaae..6ecb0d46 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -2591,6 +2591,8 @@ GLIBC_2.36 pidfd_open F
>  GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index 6cfb928b..a37f4ab4 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -2542,6 +2542,8 @@ GLIBC_2.36 pidfd_open F
>  GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index c7350971..3b8790f4 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2648,6 +2648,8 @@ GLIBC_2.36 pidfd_open F
>  GLIBC_2.36 pidfd_send_signal F
>  GLIBC_2.36 process_madvise F
>  GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>  GLIBC_2.38 __isoc23_fscanf F
>  GLIBC_2.38 __isoc23_fwscanf F
>  GLIBC_2.38 __isoc23_scanf F
Siddhesh Poyarekar May 23, 2023, 7:15 p.m. UTC | #4
On 2023-05-19 17:30, 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 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 ().
> 
> Recently, Hector Martin <marcan@marcan.st> has identified an issue in
> libwebrtc where fcntl (fd, F_DUPFD_CLOEXEC) was invoked without a third
> argument [0]. With the patch, the bug would have been detected at
> compile time, assuming libwebrtc is built with FORTIFY_SOURCE. Hopefully
> this will help detecting similar bugs in existing software, and prevent
> more instances of similar bugs from being introduced in the future.
> 
> [0]: https://social.treehouse.systems/@marcan/110355001391961285
> 
> The abilists have been modified with 'make update-abi-all'.
> 
> Signed-off-by: Sergey Bugaev <bugaevc@gmail.com>
> ---
>   include/fcntl.h                               |   3 +
>   io/Makefile                                   |   2 +-
>   io/Versions                                   |   4 +
>   io/bits/fcntl2.h                              | 139 ++++++++++++++++++
>   io/fcntl64_2.c                                |  33 +++++
>   io/fcntl_2.c                                  |  33 +++++
>   sysdeps/mach/hurd/i386/libc.abilist           |   2 +
>   sysdeps/mach/hurd/x86_64/libc.abilist         |   2 +
>   sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   2 +
>   sysdeps/unix/sysv/linux/alpha/libc.abilist    |   2 +
>   sysdeps/unix/sysv/linux/arc/libc.abilist      |   2 +
>   sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   2 +
>   sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   2 +
>   sysdeps/unix/sysv/linux/csky/libc.abilist     |   2 +
>   sysdeps/unix/sysv/linux/hppa/libc.abilist     |   2 +
>   sysdeps/unix/sysv/linux/i386/libc.abilist     |   2 +
>   sysdeps/unix/sysv/linux/ia64/libc.abilist     |   2 +
>   .../sysv/linux/loongarch/lp64/libc.abilist    |   2 +
>   .../sysv/linux/m68k/coldfire/libc.abilist     |   2 +
>   .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   2 +
>   .../sysv/linux/microblaze/be/libc.abilist     |   2 +
>   .../sysv/linux/microblaze/le/libc.abilist     |   2 +
>   .../sysv/linux/mips/mips32/fpu/libc.abilist   |   2 +
>   .../sysv/linux/mips/mips32/nofpu/libc.abilist |   2 +
>   .../sysv/linux/mips/mips64/n32/libc.abilist   |   2 +
>   .../sysv/linux/mips/mips64/n64/libc.abilist   |   2 +
>   sysdeps/unix/sysv/linux/nios2/libc.abilist    |   2 +
>   sysdeps/unix/sysv/linux/or1k/libc.abilist     |   2 +
>   .../linux/powerpc/powerpc32/fpu/libc.abilist  |   2 +
>   .../powerpc/powerpc32/nofpu/libc.abilist      |   2 +
>   .../linux/powerpc/powerpc64/be/libc.abilist   |   2 +
>   .../linux/powerpc/powerpc64/le/libc.abilist   |   2 +
>   .../unix/sysv/linux/riscv/rv32/libc.abilist   |   2 +
>   .../unix/sysv/linux/riscv/rv64/libc.abilist   |   2 +
>   .../unix/sysv/linux/s390/s390-32/libc.abilist |   2 +
>   .../unix/sysv/linux/s390/s390-64/libc.abilist |   2 +
>   sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   2 +
>   sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   2 +
>   .../sysv/linux/sparc/sparc32/libc.abilist     |   2 +
>   .../sysv/linux/sparc/sparc64/libc.abilist     |   2 +
>   .../unix/sysv/linux/x86_64/64/libc.abilist    |   2 +
>   .../unix/sysv/linux/x86_64/x32/libc.abilist   |   2 +
>   42 files changed, 285 insertions(+), 1 deletion(-)
>   create mode 100644 io/fcntl64_2.c
>   create mode 100644 io/fcntl_2.c
> 
> diff --git a/include/fcntl.h b/include/fcntl.h
> index d788db2e..7742c002 100644
> --- a/include/fcntl.h
> +++ b/include/fcntl.h
> @@ -32,6 +32,9 @@ 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);
> +extern int __fcntl64_2 (int __fd, int __cmd);
> +

With my Bikeshed Aesthetics Consultant hat on, the naming of fortified 
variants of file ops functions as *_2 is awkward, they should have been 
*_chk but I don't want to block this good work on that.  The overall 
direction is good IMO (and I see Adhemerval is on it with a deeper 
review), just some notes:

- manual/contrib.texi should be updated to mention fcntl

- Internal users end up calling __libc_fcntl (see dup2.c or grantpt.c 
for example), which will essentially bypass any fortification.  This is 
not a problem today since we don't build glibc with fortification, but 
Frederic Berat[1] has been experimenting with that and we're hoping to 
get at least a subset of glibc fortified for 2.38.  It would be a shame 
to miss fortifying glibc itself.  This is again not a problem that would 
block this patch, but something to be aware of.

>   
>   /* Makes open () & friends faster on the Hurd, but can only be used (without
>      altering user-visible behavior) when we're sure that the file we're opening
> diff --git a/io/Makefile b/io/Makefile
> index f72571cd..350807ee 100644
> --- a/io/Makefile
> +++ b/io/Makefile
> @@ -41,7 +41,7 @@ routines :=								\
>   	mkdir mkdirat							\
>   	open open_2 open64 open64_2 openat openat_2 openat64 openat64_2	\
>   	read write lseek lseek64 access euidaccess faccessat		\
> -	fcntl fcntl64 flock lockf lockf64				\
> +	fcntl fcntl_2 fcntl64 fcntl64_2 flock lockf lockf64		\
>   	close dup dup2 dup3 pipe pipe2					\
>   	creat creat64							\
>   	chdir fchdir							\
> diff --git a/io/Versions b/io/Versions
> index 4e195408..8409e105 100644
> --- a/io/Versions
> +++ b/io/Versions
> @@ -140,6 +140,10 @@ libc {
>     GLIBC_2.34 {
>       closefrom;
>     }
> +  GLIBC_2.38 {
> +    __fcntl_2;
> +    __fcntl64_2;
> +  }
>     GLIBC_PRIVATE {
>       __libc_fcntl64;
>       __fcntl_nocancel;
> diff --git a/io/bits/fcntl2.h b/io/bits/fcntl2.h
> index bdb48fa8..beb3a628 100644
> --- a/io/bits/fcntl2.h
> +++ b/io/bits/fcntl2.h
> @@ -170,3 +170,142 @@ openat64 (int __fd, const char *__path, int __oflag, ...)
>   }
>   # endif
>   #endif
> +
> +#ifndef __USE_TIME_BITS64
> +
> +# ifndef __USE_FILE_OFFSET64
> +/* Just fcntl ().  */
> +extern int __fcntl_2 (int __fd, int __cmd);
> +extern int __REDIRECT (__fcntl_alias, (int __fd, int __cmd, ...), fcntl);
> +# else
> +/* fcntl.h redirects fcntl () to fcntl64 ().  */
> +extern int __REDIRECT (__fcntl_2, (int __fd, int __cmd), __fcntl64_2);
> +extern int __REDIRECT (__fcntl_alias, (int __fd, int __cmd, ...), fcntl64);
> +# endif /* __USE_FILE_OFFSET64 */
> +
> +# ifdef __USE_LARGEFILE64
> +/* Just fcntl64 ().  */
> +extern int __fcntl64_2 (int __fd, int __cmd);
> +extern int __REDIRECT (__fcntl64_alias, (int __fd, int __cmd, ...), fcntl64);
> +# endif
> +
> +#else /* __USE_TIME_BITS64 */
> +
> +/* fcntl.h redirects both fcntl () and fcntl64 () to __fcntl_time64 ().  */
> +extern int __fcntl64_2 (int __fd, int __cmd);
> +extern int __REDIRECT (__fcntl_2, (int __fd, int __cmd), __fcntl64_2);
> +extern int __REDIRECT_NTH (__fcntl_alias, (int __fd, int __cmd, ...),
> +			   __fcntl_time64);
> +extern int __REDIRECT_NTH (__fcntl64_alias, (int __fd, int __cmd, ...),
> +			   __fcntl_time64);
> +#endif /* __USE_TIME_BITS64 */
> +
> +__errordecl (__fcntl_too_many_args,
> +             "fcntl can be called either with 2 or 3 arguments, not more");
> +__errordecl (__fcntl_missing_arg,
> +             "fcntl with with this cmd needs 3 arguments");
> +
> +__extern_always_inline int
> +__fcntl_cmd_needs_arg (int __cmd)
> +{
> +  switch (__cmd)
> +    {
> +    case F_DUPFD:
> +    case F_DUPFD_CLOEXEC:
> +    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;
> +
> +    case F_GETFD:
> +    case F_GETFL:
> +#ifdef F_GETOWN
> +    case F_GETOWN:
> +#endif
> +#ifdef __F_GETSIG
> +    case __F_GETSIG:
> +#endif
> +#ifdef F_GETLEASE
> +    case F_GETLEASE:
> +    case F_GETPIPE_SZ:
> +    case F_GET_SEALS:
> +#endif
> +    /* For any cmd value we don't know about,
> +       default to not requiring an argument.  */
> +    default:
> +      return 0;
> +    }
> +}
> +
> +__fortify_function int
> +fcntl (int __fd, int __cmd, ...)
> +{
> +  if (__va_arg_pack_len () > 1)
> +    __fcntl_too_many_args ();
> +
> +  if (__builtin_constant_p (__cmd))
> +    {
> +      if (__fcntl_cmd_needs_arg (__cmd) && __va_arg_pack_len () < 1)
> +        {
> +          __fcntl_missing_arg ();
> +          return __fcntl_2 (__fd, __cmd);
> +        }
> +      return __fcntl_alias (__fd, __cmd, __va_arg_pack ());
> +    }
> +
> +  if (__va_arg_pack_len () < 1)
> +    return __fcntl_2 (__fd, __cmd);
> +
> +  return __fcntl_alias (__fd, __cmd, __va_arg_pack ());
> +}
> +
> +#ifdef __USE_LARGEFILE64
> +__fortify_function int
> +fcntl64 (int __fd, int __cmd, ...)
> +{
> +  if (__va_arg_pack_len () > 1)
> +    __fcntl_too_many_args ();
> +
> +  if (__builtin_constant_p (__cmd))
> +    {
> +      if (__fcntl_cmd_needs_arg (__cmd) && __va_arg_pack_len () < 1)
> +        {
> +          __fcntl_missing_arg ();

Given that this will error out at compile time, do we even need this 
__fcntl64_2 call?

> +          return __fcntl64_2 (__fd, __cmd);
> +        }
> +      return __fcntl64_alias (__fd, __cmd, __va_arg_pack ());
> +    }
> +
> +  if (__va_arg_pack_len () < 1)
> +    return __fcntl64_2 (__fd, __cmd);
> +
> +  return __fcntl64_alias (__fd, __cmd, __va_arg_pack ());
> +}
> +#endif
> diff --git a/io/fcntl64_2.c b/io/fcntl64_2.c
> new file mode 100644
> index 00000000..6352f524
> --- /dev/null
> +++ b/io/fcntl64_2.c
> @@ -0,0 +1,33 @@
> +/* _FORTIFY_SOURCE wrapper for fcntl64.
> +   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_cmd_needs_arg from bits/fcntl2.h */
> +#undef _FORTIFY_SOURCE
> +#define _FORTIFY_SOURCE 1
> +
> +#include <fcntl.h>
> +#include <stdio.h>
> +
> +int
> +__fcntl64_2 (int fd, int cmd)
> +{
> +  if (__fcntl_cmd_needs_arg (cmd))
> +    __fortify_fail ("invalid fcntl64 call: this cmd requires an argument");
> +
> +  return __libc_fcntl64 (fd, cmd);
> +}
> diff --git a/io/fcntl_2.c b/io/fcntl_2.c
> new file mode 100644
> index 00000000..fc9303e4
> --- /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_cmd_needs_arg from bits/fcntl2.h */
> +#undef _FORTIFY_SOURCE
> +#define _FORTIFY_SOURCE 1
> +
> +#include <fcntl.h>
> +#include <stdio.h>
> +
> +int
> +__fcntl_2 (int fd, int cmd)
> +{
> +  if (__fcntl_cmd_needs_arg (cmd))
> +    __fortify_fail ("invalid fcntl call: this cmd requires an argument");
> +
> +  return __libc_fcntl (fd, cmd);
> +}
> diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
> index 6925222f..fa24d577 100644
> --- a/sysdeps/mach/hurd/i386/libc.abilist
> +++ b/sysdeps/mach/hurd/i386/libc.abilist
> @@ -2294,6 +2294,8 @@ GLIBC_2.36 arc4random_buf F
>   GLIBC_2.36 arc4random_uniform F
>   GLIBC_2.36 c8rtomb F
>   GLIBC_2.36 mbrtoc8 F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/mach/hurd/x86_64/libc.abilist b/sysdeps/mach/hurd/x86_64/libc.abilist
> index a0be5c1a..efb83b16 100644
> --- a/sysdeps/mach/hurd/x86_64/libc.abilist
> +++ b/sysdeps/mach/hurd/x86_64/libc.abilist
> @@ -194,6 +194,8 @@ GLIBC_2.38 __errno_location F
>   GLIBC_2.38 __explicit_bzero_chk F
>   GLIBC_2.38 __fbufsize F
>   GLIBC_2.38 __fcntl F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __fdelt_chk F
>   GLIBC_2.38 __fdelt_warn F
>   GLIBC_2.38 __fentry__ F
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index 0e2d9c30..86144979 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2633,6 +2633,8 @@ GLIBC_2.36 pidfd_open F
>   GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index f1bec197..646c11e3 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -2730,6 +2730,8 @@ GLIBC_2.36 pidfd_open F
>   GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
> index aa874b88..37e9129f 100644
> --- a/sysdeps/unix/sysv/linux/arc/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
> @@ -2394,6 +2394,8 @@ GLIBC_2.36 pidfd_open F
>   GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> index afbd57da..4c9b937e 100644
> --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> @@ -514,6 +514,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> index e7364cd3..8dbf72c5 100644
> --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> @@ -511,6 +511,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> index 913fa592..b58b2b9c 100644
> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> @@ -2670,6 +2670,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index 43af3a98..c80bb835 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -2619,6 +2619,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index af72f8fa..5a737b3d 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -2803,6 +2803,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> index 48cbb0fa..aab6d422 100644
> --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> @@ -2568,6 +2568,8 @@ GLIBC_2.36 pidfd_open F
>   GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> index c15884bb..82da98d2 100644
> --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> @@ -2154,6 +2154,8 @@ GLIBC_2.36 wprintf F
>   GLIBC_2.36 write F
>   GLIBC_2.36 writev F
>   GLIBC_2.36 wscanf F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index 3738db81..f6c80b46 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -515,6 +515,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index ed136277..dc34ea56 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -2746,6 +2746,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> index 83577386..466e4092 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> @@ -2719,6 +2719,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> index 58c5da58..dc27b4e7 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> @@ -2716,6 +2716,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index d3741945..a8dfa647 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -2711,6 +2711,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index 5319fdc2..4defd8dc 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -2709,6 +2709,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index 1743ea6e..824b6b4c 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -2717,6 +2717,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index 9b1f53c6..ff4341a8 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -2619,6 +2619,8 @@ GLIBC_2.36 pidfd_open F
>   GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> index ae1c6ca1..ede0e6eb 100644
> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> @@ -2758,6 +2758,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> index a7c572c9..22525fe8 100644
> --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> @@ -2140,6 +2140,8 @@ GLIBC_2.36 pidfd_open F
>   GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index 074fa031..2938361e 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -2773,6 +2773,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index dfcb4bd2..e1c70a25 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -2806,6 +2806,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> index 63bbccf3..2ce2d974 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> @@ -2527,6 +2527,8 @@ GLIBC_2.36 pidfd_open F
>   GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> index ab85fd61..b1024501 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> @@ -2829,6 +2829,8 @@ GLIBC_2.36 pidfd_open F
>   GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fscanfieee128 F
>   GLIBC_2.38 __isoc23_fwscanf F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> index b716f5c7..833fb747 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> @@ -2396,6 +2396,8 @@ GLIBC_2.36 pidfd_open F
>   GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> index 774e777b..cbd85454 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> @@ -2596,6 +2596,8 @@ GLIBC_2.36 pidfd_open F
>   GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index 8625135c..1442a0b9 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -2771,6 +2771,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index d00c7eb2..1a7f4fc7 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -2564,6 +2564,8 @@ GLIBC_2.36 pidfd_open F
>   GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> index b6303724..3146ce99 100644
> --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> @@ -2626,6 +2626,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> index d8005561..31360691 100644
> --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> @@ -2623,6 +2623,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index 5be55c11..026e9581 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -2766,6 +2766,8 @@ GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
>   GLIBC_2.37 __ppoll64_chk F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index 475fdaae..6ecb0d46 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -2591,6 +2591,8 @@ GLIBC_2.36 pidfd_open F
>   GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index 6cfb928b..a37f4ab4 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -2542,6 +2542,8 @@ GLIBC_2.36 pidfd_open F
>   GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index c7350971..3b8790f4 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2648,6 +2648,8 @@ GLIBC_2.36 pidfd_open F
>   GLIBC_2.36 pidfd_send_signal F
>   GLIBC_2.36 process_madvise F
>   GLIBC_2.36 process_mrelease F
> +GLIBC_2.38 __fcntl64_2 F
> +GLIBC_2.38 __fcntl_2 F
>   GLIBC_2.38 __isoc23_fscanf F
>   GLIBC_2.38 __isoc23_fwscanf F
>   GLIBC_2.38 __isoc23_scanf F

[1] https://patchwork.sourceware.org/project/glibc/list/?series=19418
Sergey Bugaev May 23, 2023, 7:43 p.m. UTC | #5
On Tue, May 23, 2023 at 10:09 PM Adhemerval Zanella Netto
<adhemerval.zanella@linaro.org> wrote:
> > +# ifndef __USE_FILE_OFFSET64
> > +/* Just fcntl ().  */
>
> Does this comment adds anything?  Also I think we avoid to use '()' on function
> definition on comments.

These comments were mainly for myself to keep track of the various
possible configurations -- I decided to leave them in since the reader
of the code might get a little overwhelmed by the combinatorial
explosion of the possible configuration variants as well.

I can remove these comments (or just this one?) if you would prefer that.

> > +__extern_always_inline int
>
> Should we use  __fortify_function also for this case?

I think __fortify_function is supposed to be used on the replacement
functions themselves, not their helpers? if that's not the case, sure.

> > +#ifdef __F_GETOWN_EX
> > +    case __F_GETOWN_EX:
> > +    case __F_SETOWN_EX:
> > +    case __F_SETSIG:
> > +#endif
>
> I think it would be better to condicionalize using __USE_GNU:
>
> #ifdef __USE_GNU
>     case F_GETOWN_EX:
>     case F_SETOWN_EX:
>     case F_SETSIG:
> #endif
>
> Since the double underscore symbols are implementation defined one and should
> not be used by the application.

But that would break on the Hurd, no?

I could do #ifdef F_GETOWN_EX (without the double underscore), but I
wanted to handle __F_GETOWN_EX etc. even if the user has not enabled
them (better handle them than not). In other words, this ifdef is
meant to check for Hurd vs Linux, not for __USE_GNU vs not.

> Should be worried that since we don't have const expressions like newer C++
> that large switch might ended being extra code on every fcntl call? I think
> the __builtin_constant_p check below gives compiler enough information to
> avoid it, but I am not sure.

Yes, __builtin_constant_p is, AFAIK, some compiler magic that
"guarantees" (quoted since I'm not sure if it's actually guaranteed,
but I've never seen it behave otherwise) that in the true branch the
value is treated as a compile-time constant.

In practice (see what the tst-fortify compiles to!), with -O2 this
whole thing is fully optimized away, and the generated code contains
the very same calls to fcntl (or fcntl64, or whatever) that it would
if there never was any fortification -- except you get compile-time
errors if you forget the argument when it's required. So there's zero
run-time cost.

If the cmd argument is a c-t const, that is -- otherwise it calls the
_2 versions and does the check at runtime, yes. But that's only extra
code (as in code size) once, in glibc, not at the call sites.

> > +      if (__fcntl_cmd_needs_arg (__cmd) && __va_arg_pack_len () < 1)
>
> No implicit check for function that do not return bool:
>
>   if (__fcntl_cmd_needs_arg (__cmd) == 1 ...)

Why? Is it just a code style thing?

> I think we need also to handle __USE_TIME_BITS64 and add another fcntl debug
> symbol to handle; even though for Linux now __fcntl_time64 is just a alias
> to __libc_fcntl64.
>
> It is because we even need to add a proper __fcntl_time64 implementation,
> the redirection now does:
>
>   fcntl -> __fcntl64_2 -> __libc_fcntl64
>
> Where it should be something like:
>
>   fcntl -> __fcntl_time64_2 -> __fcntl_time64

The idea here was that the 2-argument version of fcntl clearly does
not deal with time, either 32- or 64-bit...

Sergey
Adhemerval Zanella Netto May 23, 2023, 7:56 p.m. UTC | #6
On 23/05/23 16:43, Sergey Bugaev wrote:
> On Tue, May 23, 2023 at 10:09 PM Adhemerval Zanella Netto
> <adhemerval.zanella@linaro.org> wrote:
>>> +# ifndef __USE_FILE_OFFSET64
>>> +/* Just fcntl ().  */
>>
>> Does this comment adds anything?  Also I think we avoid to use '()' on function
>> definition on comments.
> 
> These comments were mainly for myself to keep track of the various
> possible configurations -- I decided to leave them in since the reader
> of the code might get a little overwhelmed by the combinatorial
> explosion of the possible configuration variants as well.
> 
> I can remove these comments (or just this one?) if you would prefer that.

I am chiming in because it is an installed header, but this should be ok.

> 
>>> +__extern_always_inline int
>>
>> Should we use  __fortify_function also for this case?
> 
> I think __fortify_function is supposed to be used on the replacement
> functions themselves, not their helpers? if that's not the case, sure.

The __fortify_function mainly adds the artificial attribute, which improves
the error message to make on the call site instead of the decorated function.
If the error messages from wrong fnctl usage are ok, I think we can skip
the __fortify_function usage here.

> 
>>> +#ifdef __F_GETOWN_EX
>>> +    case __F_GETOWN_EX:
>>> +    case __F_SETOWN_EX:
>>> +    case __F_SETSIG:
>>> +#endif
>>
>> I think it would be better to condicionalize using __USE_GNU:
>>
>> #ifdef __USE_GNU
>>     case F_GETOWN_EX:
>>     case F_SETOWN_EX:
>>     case F_SETSIG:
>> #endif
>>
>> Since the double underscore symbols are implementation defined one and should
>> not be used by the application.
> 
> But that would break on the Hurd, no?
> 
> I could do #ifdef F_GETOWN_EX (without the double underscore), but I
> wanted to handle __F_GETOWN_EX etc. even if the user has not enabled
> them (better handle them than not). In other words, this ifdef is
> meant to check for Hurd vs Linux, not for __USE_GNU vs not.

But user will actually use F_GETOWN_EX, not __F_GETOWN_EX; so I think 
check for F_GETOWN_EX define as well.

> 
>> Should be worried that since we don't have const expressions like newer C++
>> that large switch might ended being extra code on every fcntl call? I think
>> the __builtin_constant_p check below gives compiler enough information to
>> avoid it, but I am not sure.
> 
> Yes, __builtin_constant_p is, AFAIK, some compiler magic that
> "guarantees" (quoted since I'm not sure if it's actually guaranteed,
> but I've never seen it behave otherwise) that in the true branch the
> value is treated as a compile-time constant.
> 
> In practice (see what the tst-fortify compiles to!), with -O2 this
> whole thing is fully optimized away, and the generated code contains
> the very same calls to fcntl (or fcntl64, or whatever) that it would
> if there never was any fortification -- except you get compile-time
> errors if you forget the argument when it's required. So there's zero
> run-time cost.
> 
> If the cmd argument is a c-t const, that is -- otherwise it calls the
> _2 versions and does the check at runtime, yes. But that's only extra
> code (as in code size) once, in glibc, not at the call sites.

Fair enough.

> 
>>> +      if (__fcntl_cmd_needs_arg (__cmd) && __va_arg_pack_len () < 1)
>>
>> No implicit check for function that do not return bool:
>>
>>   if (__fcntl_cmd_needs_arg (__cmd) == 1 ...)
> 
> Why? Is it just a code style thing?

Yes, it is from the glibc code style (check 'Boolean Coercions' [1]).

[1] https://sourceware.org/glibc/wiki/Style_and_Conventions

> 
>> I think we need also to handle __USE_TIME_BITS64 and add another fcntl debug
>> symbol to handle; even though for Linux now __fcntl_time64 is just a alias
>> to __libc_fcntl64.
>>
>> It is because we even need to add a proper __fcntl_time64 implementation,
>> the redirection now does:
>>
>>   fcntl -> __fcntl64_2 -> __libc_fcntl64
>>
>> Where it should be something like:
>>
>>   fcntl -> __fcntl_time64_2 -> __fcntl_time64
> 
> The idea here was that the 2-argument version of fcntl clearly does
> not deal with time, either 32- or 64-bit...

And that's why we don't have a __fcntl_time64 implementation.  But Florian
has asked to add one anyway if we even eventually need to handle some time
related structure.

I think we can skip this for now, but at least add a comment stating that
if we even need to handle time related field with fcntl we will a new
redirection.
Sergey Bugaev May 23, 2023, 8:01 p.m. UTC | #7
Hello,

On Tue, May 23, 2023 at 10:15 PM Siddhesh Poyarekar <siddhesh@gotplt.org> wrote:
> *_chk but I don't want to block this good work on that.  The overall
> direction is good IMO

Yay, thanks!

> - manual/contrib.texi should be updated to mention fcntl

Do you mean manual/maint.texi? manual/contrib.texi seems to contain a
list of contributors.

> - Internal users end up calling __libc_fcntl (see dup2.c or grantpt.c
> for example), which will essentially bypass any fortification.  This is
> not a problem today since we don't build glibc with fortification, but
> Frederic Berat[1] has been experimenting with that and we're hoping to
> get at least a subset of glibc fortified for 2.38.  It would be a shame
> to miss fortifying glibc itself.  This is again not a problem that would
> block this patch, but something to be aware of.

Yes, I've thought of this, but I don't know what I could change in
this patch to make it friendlier to in-glibc fortification. I've
generally done things the same way as the open* fortification does; so
I don't think this would be adding any new complications compared to
what's already in there.

> Given that this will error out at compile time, do we even need this
> __fcntl64_2 call?

Same as for the open* fortification: this call will only fail at
compile time if the cmd is a compile-time constant. If it's not (which
is a rare, but valid case), we need to do the check at runtime. Note
that if cmd _is_ a compile-time constant and does not require the 3rd
arg, this will call the regular fcntl, not the _2 version; the _2
version is only for non-compile-time-const cmd-s.

Sergey
Sergey Bugaev May 23, 2023, 8:06 p.m. UTC | #8
On Tue, May 23, 2023 at 11:01 PM Sergey Bugaev <bugaevc@gmail.com> wrote:
> Same as for the open* fortification: this call will only fail at
> compile time if the cmd is a compile-time constant. If it's not (which
> is a rare, but valid case), we need to do the check at runtime. Note
> that if cmd _is_ a compile-time constant and does not require the 3rd
> arg, this will call the regular fcntl, not the _2 version; the _2
> version is only for non-compile-time-const cmd-s.

Ah, no, I see what you mean: you mean we don't strictly speaking need
the __fcntl64_2 call immediately following __fcntl_missing_arg.

I guess we don't -- maybe the corresponding change needs to be done to
the open* fortification as well then.

Sergey
Sergey Bugaev May 23, 2023, 8:24 p.m. UTC | #9
On Tue, May 23, 2023 at 10:57 PM Adhemerval Zanella Netto
<adhemerval.zanella@linaro.org> wrote:
> >>> +      if (__fcntl_cmd_needs_arg (__cmd) && __va_arg_pack_len () < 1)
> >>
> >> No implicit check for function that do not return bool:
> >>
> >>   if (__fcntl_cmd_needs_arg (__cmd) == 1 ...)
> >
> > Why? Is it just a code style thing?
>
> Yes, it is from the glibc code style (check 'Boolean Coercions' [1]).
>
> [1] https://sourceware.org/glibc/wiki/Style_and_Conventions

[I don't mean to argue, and surely you know better, and not that I
care about this], but I read that as saying that implicit
integer-to-bool conversions are frowned upon, not ints used as bools
(because C used to lack a bool type). In other words: if you have an
integer variable that can have many different values and you want to
check it against 0, you're supposed to write out the != 0 explicitly.
But if what you have is essentially a boolean, but you use int/1/0
instead of bool/true/false, then just checking if (my_bool) should be
fine, and doing != 0 would be awkward -- no?

I've surely seen glibc code use if (my_bool) without the != 0 when
my_bool is declared as an int. __libc_enable_secure is one example.

> > The idea here was that the 2-argument version of fcntl clearly does
> > not deal with time, either 32- or 64-bit...
>
> And that's why we don't have a __fcntl_time64 implementation.  But Florian
> has asked to add one anyway if we even eventually need to handle some time
> related structure.
>
> I think we can skip this for now, but at least add a comment stating that
> if we even need to handle time related field with fcntl we will a new
> redirection.

Hm, either I'm failing to understand what you're saying (which is
possible: it is late at night), or maybe I didn't make my point clear:

if what you're concerned is what the _2 functions end up calling
(__fcntl_time64 vs __libc_fcntl64), then it does not matter because
they're only used for 2-argument variant of fcntl, which can not
possibly deal with any time-related structures (nor any structures),
exactly because there's no third argument where a structure could be
passed. The 2-arg variant is basically for simple getters that return
an int.

But if something is off (wrt time64 vs not) in the main fortification
/ redirection code, then I surely need to fix that -- then please
clarify what specific configuration / case you're talking about.

Sergey
Sergey Bugaev May 23, 2023, 8:44 p.m. UTC | #10
On Tue, May 23, 2023, 23:24 Sergey Bugaev <bugaevc@gmail.com> wrote:
> if what you're concerned is what the _2 functions end up calling
> (__fcntl_time64 vs __libc_fcntl64), then it does not matter because
> they're only used for 2-argument variant of fcntl, which can not
> possibly deal with any time-related structures (nor any structures),
> exactly because there's no third argument where a structure could be
> passed. The 2-arg variant is basically for simple getters that return
> an int.

And now that I think of it, there's also no reason to have separate
__fcntl64_2 & __fcntl_2 functions either, is there?

Sergey
Florian Weimer May 23, 2023, 9:46 p.m. UTC | #11
* Sergey Bugaev via Libc-alpha:

> Both open () and fcntl () are "overloaded" to accept either 2 or 3
> arguments; whether the last argument is required 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 ().
>
> Recently, Hector Martin <marcan@marcan.st> has identified an issue in
> libwebrtc where fcntl (fd, F_DUPFD_CLOEXEC) was invoked without a third
> argument [0]. With the patch, the bug would have been detected at
> compile time, assuming libwebrtc is built with FORTIFY_SOURCE. Hopefully
> this will help detecting similar bugs in existing software, and prevent
> more instances of similar bugs from being introduced in the future.

A while ago, I looked into implementing this with
__builtin_types_compatible_p and __builtin_choose_expr.  It seemed
feasible (although I didn't complete it), but C++ would require a
completely different implementation.

I'm not sure if this goes in the right direction.  Maybe we should add
specialized functions for the common fcntl requests.  This way, we'd
get compile-time type checking in a far more maintainable manner.
Sergey Bugaev May 24, 2023, 7:31 a.m. UTC | #12
Hello,

On Wed, May 24, 2023 at 12:46 AM Florian Weimer <fw@deneb.enyo.de> wrote:
> A while ago, I looked into implementing this with
> __builtin_types_compatible_p and __builtin_choose_expr.  It seemed
> feasible (although I didn't complete it), but C++ would require a
> completely different implementation.
>
> I'm not sure if this goes in the right direction.  Maybe we should add
> specialized functions for the common fcntl requests.  This way, we'd
> get compile-time type checking in a far more maintainable manner.

Interesting -- I have thought of doing type checking, but haven't
found a way to make it work.

There doesn't seem to be a way to extract an argument value / type out
of a __builtin_va_arg_pack. Even if you know that
__builtin_va_arg_pack_len () == 1, you cannot do:

int arg = __builtin_va_arg_pack ();

or

int __fcntl3_int (int fd, int cmd, int arg);
__fcntl3_int (fd, cmd, __builtin_va_arg_pack ());

In other words: __builtin_va_arg_pack () does not behave like a macro
that gets textually expanded to the anonymous argument(s), but really
as a value of the "..." "argument".

You can do typeof (__builtin_va_arg_pack ()), but it just always ends
up being an int, no matter what you actually pass. You could use the
regular va_arg (), but that of course requires you to specify the type
to cast to yourself, so no point in doing that.

Maybe it's possible to achieve with some preprocessor trickery?

Sergey
Florian Weimer May 24, 2023, 8:29 a.m. UTC | #13
* Sergey Bugaev via Libc-alpha:

> Hello,
>
> On Wed, May 24, 2023 at 12:46 AM Florian Weimer <fw@deneb.enyo.de> wrote:
>> A while ago, I looked into implementing this with
>> __builtin_types_compatible_p and __builtin_choose_expr.  It seemed
>> feasible (although I didn't complete it), but C++ would require a
>> completely different implementation.
>>
>> I'm not sure if this goes in the right direction.  Maybe we should add
>> specialized functions for the common fcntl requests.  This way, we'd
>> get compile-time type checking in a far more maintainable manner.
>
> Interesting -- I have thought of doing type checking, but haven't
> found a way to make it work.
>
> There doesn't seem to be a way to extract an argument value / type out
> of a __builtin_va_arg_pack. Even if you know that
> __builtin_va_arg_pack_len () == 1, you cannot do:
>
> int arg = __builtin_va_arg_pack ();
>
> or
>
> int __fcntl3_int (int fd, int cmd, int arg);
> __fcntl3_int (fd, cmd, __builtin_va_arg_pack ());
>
> In other words: __builtin_va_arg_pack () does not behave like a macro
> that gets textually expanded to the anonymous argument(s), but really
> as a value of the "..." "argument".

In my attempt, the top level looks like this:

+#define fcntl(fd, cmd, ...)                                             \
+  (__builtin_constant_p (cmd)                                           \
+   ? __builtin_choose_expression                                        \
+   (__fcntl_is_void (cmd), __fcntl_void (fd, cmd, __VA_ARGS__),           \
+    __builtin_choose_expression                                         \
+    (__fcntl_is_int (cmd), __fcntl_int (fd, cmd, __VA_ARGS__),            \
+     __builtin_choose_expression                                        \
+     (__fcntl_is_flock_const (cmd), __fcntl_flock_const (fd, cmd, __VA_ARGS__), \
+      __builtin_choose_expression                                       \
+      (__fcntl_is_flock (cmd), __fcntl_flock (fd, cmd, __VA_ARGS__),      \
+       __builtin_chose_expression                                       \
+       (__fcntl_is_flock64_const (cmd), __fcntl_flock64_const (fd, cmd, __VA_ARGS__), \
+        __builtin_choose_expression                                     \
+        (__fcntl_is_flock64 (cmd), __fcntl_flock64 (fd, cmd, __VA_ARGS__), \
+         __builtin_choose_expression                                    \
+         (__fcntl_is_flock32_const (cmd), __fcntl_flock32_const (fd, cmd, __VA_ARGS__), \
+          __builtin_choose_expression                                   \
+          (__fcntl_is_flock32 (cmd), __fcntl_flock32 (fd, cmd, __VA_ARGS__), \
+           __fcntl_unchecked (fd, cmd, __VA_ARGS__)))))))))             \
+   : __fcntl_unchecked (fd, cmd, __VA_ARGS__))

IIRC, it doesn't quite work because __builtin_choose_expression only
suppresses errors, but not warnings, in the branch that wasn't chosen. 8-(

Maybe this is something that could be fixed with _Generic, using
__builtin_choose_expression for the __fcntl_is_void check only.

The type predicts look like this:

+#ifdef F_SETLK64
+# define __fcntl_is_flock64_const(cmd) \
+  ((cmd) == F_SETLK64 || (cmd) == F_SETLKW64)
+# define __fcntl_is_flock64(cmd) ((cmd) == F_GETLK64)
+#else
+# define __fcntl_is_flock64_const(cmd) 0
+# define __fcntl_is_flock64(cmd) 0
+#endif

The helper wrappers are simple redirects to the existing exported
function, with transparent unions to handle the aliases.

+#if defined (__USE_LARGEFILE64) && defined (__OFF_T_MATCHES_OFF64_T)
+typedef union __attribute__ ((__transparent_union__))
+{
+  struct flock *__flock;
+  struct flock64 *__flock64;
+} __flock_pointer;
+typedef union __attribute__ ((__transparent_union__))
+{
+  const struct flock *__flock;
+  const struct flock64 *__flock64;
+} __flock_const_pointer;
+#else /* flock and flock64 are distinct */
+typedef struct flock *__flock_pointer;
+typedef const struct flock *__flock_const_pointer;
+#endif
+
+int __REDIRECT (__fcntl_flock, (int, int, __flock_pointer), __fcntl_chk) __wur;
+int __REDIRECT (__fcntl_flock_const, (int, int, __flock_const_pointer),
+                __fcntl_chk) __wur;
+int __REDIRECT (__fcntl_flock32, (int, int, struct flock *),
+                __fcntl_chk) __wur;
+int __REDIRECT (__fcntl_flock32_const, (int, int, const struct flock *),
+                __fcntl_chk) __wur;
+#ifdef __USE_LARGEFILE64
+int __REDIRECT (__fcntl_flock64, (int, int, struct flock64 *),
+                __fcntl_chk) __wur;
+int __REDIRECT (__fcntl_flock64_const, (int, int, const struct flock64 *),
+                __fcntl_chk) __wur;
+#endif

The compiler will then warn about the type mismatches
(-Wincompatible-pointer-types is not an error by default, for backwards
compatibility).  But as I said, I don't think this approach worked
because __builtin_choose_expression does not suppress those warnings.

I'm attaching my broken patch.  It's based on commit ef4f97648dc9584
(from 2016).

Thanks,
Florian
Sergey Bugaev May 24, 2023, 10:51 a.m. UTC | #14
On Wed, May 24, 2023 at 11:29 AM Florian Weimer <fweimer@redhat.com> wrote:>
> I'm attaching my broken patch.  It's based on commit ef4f97648dc9584
> (from 2016).

Thank you, that's helpful.

A couple more issues with your patch (I understand that it's WIP and broken):

1. You're doing

int __fcntl_chk (int, int, ...);
int __REDIRECT (__fcntl_int, (int, int, int __arg), __fcntl_chk);

This is not OK, the ABI may be different between vararg- and
non-vararg functions.

2. It doesn't do the runtime check if called with 2 args and non-c-t-const cmd.

> IIRC, it doesn't quite work because __builtin_choose_expression only
> suppresses errors, but not warnings, in the branch that wasn't chosen. 8-(
>
> Maybe this is something that could be fixed with _Generic, using
> __builtin_choose_expression for the __fcntl_is_void check only.

Yes -- I've sketched something up using _Generic and it appears to
work great: https://godbolt.org/z/8zdzo3T5Y

It does do preprocessor trickery ("friendship ended with
__builtin_va_arg_pack_len, now __VA_OPT__ is my best friend") and does
not use __builtin_choose_expr at all, so should be C++-compatible too
(try with -xc++).

This, too, is obviously a prototype, and does not do runtime _2
checking nor 64-bit handling and so on.

What do you think? Is this direction worth pursuing?

Sergey
Florian Weimer May 24, 2023, 11:18 a.m. UTC | #15
* Sergey Bugaev:

> On Wed, May 24, 2023 at 11:29 AM Florian Weimer <fweimer@redhat.com> wrote:>
>> I'm attaching my broken patch.  It's based on commit ef4f97648dc9584
>> (from 2016).
>
> Thank you, that's helpful.
>
> A couple more issues with your patch (I understand that it's WIP and broken):
>
> 1. You're doing
>
> int __fcntl_chk (int, int, ...);
> int __REDIRECT (__fcntl_int, (int, int, int __arg), __fcntl_chk);
>
> This is not OK, the ABI may be different between vararg- and
> non-vararg functions.

Right, I planned to make __fcntl_chk non-variadic in its implementation.
We unconditionally read the argument already.

Variadic calls to non-variadic functions are okay for our ABIs, we need
that for K&R compatibility anyway.

> 2. It doesn't do the runtime check if called with 2 args and
> non-c-t-const cmd.

That's possible, I don't remember.

>> IIRC, it doesn't quite work because __builtin_choose_expression only
>> suppresses errors, but not warnings, in the branch that wasn't chosen. 8-(
>>
>> Maybe this is something that could be fixed with _Generic, using
>> __builtin_choose_expression for the __fcntl_is_void check only.
>
> Yes -- I've sketched something up using _Generic and it appears to
> work great: https://godbolt.org/z/8zdzo3T5Y
>
> It does do preprocessor trickery ("friendship ended with
> __builtin_va_arg_pack_len, now __VA_OPT__ is my best friend") and does
> not use __builtin_choose_expr at all, so should be C++-compatible too
> (try with -xc++).

Right, it doesn't look too bad actually.

> This, too, is obviously a prototype, and does not do runtime _2
> checking nor 64-bit handling and so on.
>
> What do you think? Is this direction worth pursuing?

I think so, yes.

Thanks,
Florian
Siddhesh Poyarekar May 24, 2023, 11:46 a.m. UTC | #16
On 2023-05-24 07:18, Florian Weimer via Libc-alpha wrote:
>>> IIRC, it doesn't quite work because __builtin_choose_expression only
>>> suppresses errors, but not warnings, in the branch that wasn't chosen. 8-(
>>>
>>> Maybe this is something that could be fixed with _Generic, using
>>> __builtin_choose_expression for the __fcntl_is_void check only.
>>
>> Yes -- I've sketched something up using _Generic and it appears to
>> work great: https://godbolt.org/z/8zdzo3T5Y
>>
>> It does do preprocessor trickery ("friendship ended with
>> __builtin_va_arg_pack_len, now __VA_OPT__ is my best friend") and does
>> not use __builtin_choose_expr at all, so should be C++-compatible too
>> (try with -xc++).
> 
> Right, it doesn't look too bad actually.
> 
>> This, too, is obviously a prototype, and does not do runtime _2
>> checking nor 64-bit handling and so on.
>>
>> What do you think? Is this direction worth pursuing?
> 
> I think so, yes.

Please be sure to make the _Generic bits conditional on __USE_ISOC11.

Thanks,
Sid
Adhemerval Zanella Netto May 24, 2023, 12:04 p.m. UTC | #17
On 23/05/23 17:24, Sergey Bugaev wrote:
> On Tue, May 23, 2023 at 10:57 PM Adhemerval Zanella Netto
> <adhemerval.zanella@linaro.org> wrote:
>>>>> +      if (__fcntl_cmd_needs_arg (__cmd) && __va_arg_pack_len () < 1)
>>>>
>>>> No implicit check for function that do not return bool:
>>>>
>>>>   if (__fcntl_cmd_needs_arg (__cmd) == 1 ...)
>>>
>>> Why? Is it just a code style thing?
>>
>> Yes, it is from the glibc code style (check 'Boolean Coercions' [1]).
>>
>> [1] https://sourceware.org/glibc/wiki/Style_and_Conventions
> 
> [I don't mean to argue, and surely you know better, and not that I
> care about this], but I read that as saying that implicit
> integer-to-bool conversions are frowned upon, not ints used as bools
> (because C used to lack a bool type). In other words: if you have an
> integer variable that can have many different values and you want to
> check it against 0, you're supposed to write out the != 0 explicitly.
> But if what you have is essentially a boolean, but you use int/1/0
> instead of bool/true/false, then just checking if (my_bool) should be
> fine, and doing != 0 would be awkward -- no?
> 
> I've surely seen glibc code use if (my_bool) without the != 0 when
> my_bool is declared as an int. __libc_enable_secure is one example.

The interger as bool is not the problem, specially on a installed header
that won't be easy to use 'bool' (due namespace pollution, standard 
conformance, etc.).  And sure some usage of implicit conversions might
have slip in review, but I think it should follow the code guide lines
anyway (unless we revise it).

> 
>>> The idea here was that the 2-argument version of fcntl clearly does
>>> not deal with time, either 32- or 64-bit...
>>
>> And that's why we don't have a __fcntl_time64 implementation.  But Florian
>> has asked to add one anyway if we even eventually need to handle some time
>> related structure.
>>
>> I think we can skip this for now, but at least add a comment stating that
>> if we even need to handle time related field with fcntl we will a new
>> redirection.
> 
> Hm, either I'm failing to understand what you're saying (which is
> possible: it is late at night), or maybe I didn't make my point clear:
> 
> if what you're concerned is what the _2 functions end up calling
> (__fcntl_time64 vs __libc_fcntl64), then it does not matter because
> they're only used for 2-argument variant of fcntl, which can not
> possibly deal with any time-related structures (nor any structures),
> exactly because there's no third argument where a structure could be
> passed. The 2-arg variant is basically for simple getters that return
> an int.
> 
> But if something is off (wrt time64 vs not) in the main fortification
> / redirection code, then I surely need to fix that -- then please
> clarify what specific configuration / case you're talking about.

Right, I see your point now.

> Ah, no, I see what you mean: you mean we don't strictly speaking need
> the __fcntl64_2 call immediately following __fcntl_missing_arg.
> 
> I guess we don't -- maybe the corresponding change needs to be done to
> the open* fortification as well then.

Agree.
Andreas Schwab May 24, 2023, 12:12 p.m. UTC | #18
On Mai 24 2023, Siddhesh Poyarekar wrote:

> Please be sure to make the _Generic bits conditional on __USE_ISOC11.

That's not enough.  GCC 4.7 supports C11, but _Generic has only been
added in GCC 4.9.
Florian Weimer May 24, 2023, 12:18 p.m. UTC | #19
* Andreas Schwab:

> On Mai 24 2023, Siddhesh Poyarekar wrote:
>
>> Please be sure to make the _Generic bits conditional on __USE_ISOC11.
>
> That's not enough.  GCC 4.7 supports C11, but _Generic has only been
> added in GCC 4.9.

We also generally do not prevent the use of compiler extensions in
strict feature modes.  I think this should use a compiler version check
and maybe a fallback check against C17 compiler support if we do not
need any extensions (assuming that all C17 compilers implement _Generic,
so that an exception like the one you mentioned for GCC does not apply
vis-a-vis C17).

Thanks,
Florian
Sergey Bugaev May 24, 2023, 12:37 p.m. UTC | #20
On Wed, May 24, 2023 at 3:18 PM Florian Weimer <fweimer@redhat.com> wrote:
> We also generally do not prevent the use of compiler extensions in
> strict feature modes.  I think this should use a compiler version check
> and maybe a fallback check against C17 compiler support if we do not
> need any extensions (assuming that all C17 compilers implement _Generic,
> so that an exception like the one you mentioned for GCC does not apply
> vis-a-vis C17).

Do I understand this correctly? -- you want the check to be

#if  (__STDC_VERSION__ >= 201710L) || (__GNUC_PREREQ (4, 9) &&
__STDC_VERSION__ >= 201112L)

right?

Why even care for compilers other than modern GCC (and Clang
pretending to be GCC), considering the fortifications use very
GCC-specific intrinsics (__builtin_*, attributes)?

Sergey
Florian Weimer May 24, 2023, 12:45 p.m. UTC | #21
* Sergey Bugaev:

> On Wed, May 24, 2023 at 3:18 PM Florian Weimer <fweimer@redhat.com> wrote:
>> We also generally do not prevent the use of compiler extensions in
>> strict feature modes.  I think this should use a compiler version check
>> and maybe a fallback check against C17 compiler support if we do not
>> need any extensions (assuming that all C17 compilers implement _Generic,
>> so that an exception like the one you mentioned for GCC does not apply
>> vis-a-vis C17).
>
> Do I understand this correctly? -- you want the check to be
>
> #if  (__STDC_VERSION__ >= 201710L) || (__GNUC_PREREQ (4, 9) &&
> __STDC_VERSION__ >= 201112L)
>
> right?

More like this:

#if  __STDC_VERSION__ >= 201710L) || __GNUC_PREREQ (4, 9)

If you have GCC 4.9, __STDC_VERSION__ does not matter if you use
__extension__ in front of _Generic (untested).  Clang would benefit from
another version conditional.

But we may not need _Generic after all.

> Why even care for compilers other than modern GCC (and Clang
> pretending to be GCC), considering the fortifications use very
> GCC-specific intrinsics (__builtin_*, attributes)?

Some of us want to reproduce things with older compilers, for bisecting
regressions for example.  For that, the headers better remain
compatible.  And GCC 4.8 is still very widely used (although not with
current GCC headers, admittedly).

Thanks,
Florian
Sergey Bugaev May 24, 2023, 1:02 p.m. UTC | #22
On Wed, May 24, 2023 at 3:45 PM Florian Weimer <fweimer@redhat.com> wrote:
> If you have GCC 4.9, __STDC_VERSION__ does not matter if you use
> __extension__ in front of _Generic (untested).  Clang would benefit from
> another version conditional.

So *that's* what __extension__ is for! Makes sense, thanks.

> But we may not need _Generic after all.

Indeed, this seems to work just as well:

#define __fcntl_type_check(cmd, arg)
                     \
  (__fcntl_is_int (cmd) ? __builtin_types_compatible_p (typeof (arg),
int) :                \
  (__fcntl_is_flock (cmd) ? __builtin_types_compatible_p (typeof
(arg), struct flock *) : 1))

And __builtin_types_compatible_p appears to have been introduced in GCC 3.1.

Sergey
Florian Weimer May 24, 2023, 1:18 p.m. UTC | #23
* Sergey Bugaev:

> On Wed, May 24, 2023 at 3:45 PM Florian Weimer <fweimer@redhat.com> wrote:
>> If you have GCC 4.9, __STDC_VERSION__ does not matter if you use
>> __extension__ in front of _Generic (untested).  Clang would benefit from
>> another version conditional.
>
> So *that's* what __extension__ is for! Makes sense, thanks.

I'm not 100% sure if we need it because _Generic is reserved in any
standards version.

>> But we may not need _Generic after all.
>
> Indeed, this seems to work just as well:
>
> #define __fcntl_type_check(cmd, arg)
>                      \
>   (__fcntl_is_int (cmd) ? __builtin_types_compatible_p (typeof (arg),
> int) :                \
>   (__fcntl_is_flock (cmd) ? __builtin_types_compatible_p (typeof
> (arg), struct flock *) : 1))

Fair enough.  This needs __typeof (or maybe __extension__ __typeof), by
the way.

Thanks,
Florian
diff mbox series

Patch

diff --git a/include/fcntl.h b/include/fcntl.h
index d788db2e..7742c002 100644
--- a/include/fcntl.h
+++ b/include/fcntl.h
@@ -32,6 +32,9 @@  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);
+extern int __fcntl64_2 (int __fd, int __cmd);
+
 
 /* Makes open () & friends faster on the Hurd, but can only be used (without
    altering user-visible behavior) when we're sure that the file we're opening
diff --git a/io/Makefile b/io/Makefile
index f72571cd..350807ee 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -41,7 +41,7 @@  routines :=								\
 	mkdir mkdirat							\
 	open open_2 open64 open64_2 openat openat_2 openat64 openat64_2	\
 	read write lseek lseek64 access euidaccess faccessat		\
-	fcntl fcntl64 flock lockf lockf64				\
+	fcntl fcntl_2 fcntl64 fcntl64_2 flock lockf lockf64		\
 	close dup dup2 dup3 pipe pipe2					\
 	creat creat64							\
 	chdir fchdir							\
diff --git a/io/Versions b/io/Versions
index 4e195408..8409e105 100644
--- a/io/Versions
+++ b/io/Versions
@@ -140,6 +140,10 @@  libc {
   GLIBC_2.34 {
     closefrom;
   }
+  GLIBC_2.38 {
+    __fcntl_2;
+    __fcntl64_2;
+  }
   GLIBC_PRIVATE {
     __libc_fcntl64;
     __fcntl_nocancel;
diff --git a/io/bits/fcntl2.h b/io/bits/fcntl2.h
index bdb48fa8..beb3a628 100644
--- a/io/bits/fcntl2.h
+++ b/io/bits/fcntl2.h
@@ -170,3 +170,142 @@  openat64 (int __fd, const char *__path, int __oflag, ...)
 }
 # endif
 #endif
+
+#ifndef __USE_TIME_BITS64
+
+# ifndef __USE_FILE_OFFSET64
+/* Just fcntl ().  */
+extern int __fcntl_2 (int __fd, int __cmd);
+extern int __REDIRECT (__fcntl_alias, (int __fd, int __cmd, ...), fcntl);
+# else
+/* fcntl.h redirects fcntl () to fcntl64 ().  */
+extern int __REDIRECT (__fcntl_2, (int __fd, int __cmd), __fcntl64_2);
+extern int __REDIRECT (__fcntl_alias, (int __fd, int __cmd, ...), fcntl64);
+# endif /* __USE_FILE_OFFSET64 */
+
+# ifdef __USE_LARGEFILE64
+/* Just fcntl64 ().  */
+extern int __fcntl64_2 (int __fd, int __cmd);
+extern int __REDIRECT (__fcntl64_alias, (int __fd, int __cmd, ...), fcntl64);
+# endif
+
+#else /* __USE_TIME_BITS64 */
+
+/* fcntl.h redirects both fcntl () and fcntl64 () to __fcntl_time64 ().  */
+extern int __fcntl64_2 (int __fd, int __cmd);
+extern int __REDIRECT (__fcntl_2, (int __fd, int __cmd), __fcntl64_2);
+extern int __REDIRECT_NTH (__fcntl_alias, (int __fd, int __cmd, ...),
+			   __fcntl_time64);
+extern int __REDIRECT_NTH (__fcntl64_alias, (int __fd, int __cmd, ...),
+			   __fcntl_time64);
+#endif /* __USE_TIME_BITS64 */
+
+__errordecl (__fcntl_too_many_args,
+             "fcntl can be called either with 2 or 3 arguments, not more");
+__errordecl (__fcntl_missing_arg,
+             "fcntl with with this cmd needs 3 arguments");
+
+__extern_always_inline int
+__fcntl_cmd_needs_arg (int __cmd)
+{
+  switch (__cmd)
+    {
+    case F_DUPFD:
+    case F_DUPFD_CLOEXEC:
+    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;
+
+    case F_GETFD:
+    case F_GETFL:
+#ifdef F_GETOWN
+    case F_GETOWN:
+#endif
+#ifdef __F_GETSIG
+    case __F_GETSIG:
+#endif
+#ifdef F_GETLEASE
+    case F_GETLEASE:
+    case F_GETPIPE_SZ:
+    case F_GET_SEALS:
+#endif
+    /* For any cmd value we don't know about,
+       default to not requiring an argument.  */
+    default:
+      return 0;
+    }
+}
+
+__fortify_function int
+fcntl (int __fd, int __cmd, ...)
+{
+  if (__va_arg_pack_len () > 1)
+    __fcntl_too_many_args ();
+
+  if (__builtin_constant_p (__cmd))
+    {
+      if (__fcntl_cmd_needs_arg (__cmd) && __va_arg_pack_len () < 1)
+        {
+          __fcntl_missing_arg ();
+          return __fcntl_2 (__fd, __cmd);
+        }
+      return __fcntl_alias (__fd, __cmd, __va_arg_pack ());
+    }
+
+  if (__va_arg_pack_len () < 1)
+    return __fcntl_2 (__fd, __cmd);
+
+  return __fcntl_alias (__fd, __cmd, __va_arg_pack ());
+}
+
+#ifdef __USE_LARGEFILE64
+__fortify_function int
+fcntl64 (int __fd, int __cmd, ...)
+{
+  if (__va_arg_pack_len () > 1)
+    __fcntl_too_many_args ();
+
+  if (__builtin_constant_p (__cmd))
+    {
+      if (__fcntl_cmd_needs_arg (__cmd) && __va_arg_pack_len () < 1)
+        {
+          __fcntl_missing_arg ();
+          return __fcntl64_2 (__fd, __cmd);
+        }
+      return __fcntl64_alias (__fd, __cmd, __va_arg_pack ());
+    }
+
+  if (__va_arg_pack_len () < 1)
+    return __fcntl64_2 (__fd, __cmd);
+
+  return __fcntl64_alias (__fd, __cmd, __va_arg_pack ());
+}
+#endif
diff --git a/io/fcntl64_2.c b/io/fcntl64_2.c
new file mode 100644
index 00000000..6352f524
--- /dev/null
+++ b/io/fcntl64_2.c
@@ -0,0 +1,33 @@ 
+/* _FORTIFY_SOURCE wrapper for fcntl64.
+   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_cmd_needs_arg from bits/fcntl2.h */
+#undef _FORTIFY_SOURCE
+#define _FORTIFY_SOURCE 1
+
+#include <fcntl.h>
+#include <stdio.h>
+
+int
+__fcntl64_2 (int fd, int cmd)
+{
+  if (__fcntl_cmd_needs_arg (cmd))
+    __fortify_fail ("invalid fcntl64 call: this cmd requires an argument");
+
+  return __libc_fcntl64 (fd, cmd);
+}
diff --git a/io/fcntl_2.c b/io/fcntl_2.c
new file mode 100644
index 00000000..fc9303e4
--- /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_cmd_needs_arg from bits/fcntl2.h */
+#undef _FORTIFY_SOURCE
+#define _FORTIFY_SOURCE 1
+
+#include <fcntl.h>
+#include <stdio.h>
+
+int
+__fcntl_2 (int fd, int cmd)
+{
+  if (__fcntl_cmd_needs_arg (cmd))
+    __fortify_fail ("invalid fcntl call: this cmd requires an argument");
+
+  return __libc_fcntl (fd, cmd);
+}
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index 6925222f..fa24d577 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2294,6 +2294,8 @@  GLIBC_2.36 arc4random_buf F
 GLIBC_2.36 arc4random_uniform F
 GLIBC_2.36 c8rtomb F
 GLIBC_2.36 mbrtoc8 F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/mach/hurd/x86_64/libc.abilist b/sysdeps/mach/hurd/x86_64/libc.abilist
index a0be5c1a..efb83b16 100644
--- a/sysdeps/mach/hurd/x86_64/libc.abilist
+++ b/sysdeps/mach/hurd/x86_64/libc.abilist
@@ -194,6 +194,8 @@  GLIBC_2.38 __errno_location F
 GLIBC_2.38 __explicit_bzero_chk F
 GLIBC_2.38 __fbufsize F
 GLIBC_2.38 __fcntl F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __fdelt_chk F
 GLIBC_2.38 __fdelt_warn F
 GLIBC_2.38 __fentry__ F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 0e2d9c30..86144979 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2633,6 +2633,8 @@  GLIBC_2.36 pidfd_open F
 GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index f1bec197..646c11e3 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2730,6 +2730,8 @@  GLIBC_2.36 pidfd_open F
 GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index aa874b88..37e9129f 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2394,6 +2394,8 @@  GLIBC_2.36 pidfd_open F
 GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index afbd57da..4c9b937e 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -514,6 +514,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index e7364cd3..8dbf72c5 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -511,6 +511,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 913fa592..b58b2b9c 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2670,6 +2670,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 43af3a98..c80bb835 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2619,6 +2619,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index af72f8fa..5a737b3d 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2803,6 +2803,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 48cbb0fa..aab6d422 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2568,6 +2568,8 @@  GLIBC_2.36 pidfd_open F
 GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
index c15884bb..82da98d2 100644
--- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
@@ -2154,6 +2154,8 @@  GLIBC_2.36 wprintf F
 GLIBC_2.36 write F
 GLIBC_2.36 writev F
 GLIBC_2.36 wscanf F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 3738db81..f6c80b46 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -515,6 +515,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index ed136277..dc34ea56 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2746,6 +2746,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 83577386..466e4092 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2719,6 +2719,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 58c5da58..dc27b4e7 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2716,6 +2716,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index d3741945..a8dfa647 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2711,6 +2711,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 5319fdc2..4defd8dc 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2709,6 +2709,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 1743ea6e..824b6b4c 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2717,6 +2717,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 9b1f53c6..ff4341a8 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2619,6 +2619,8 @@  GLIBC_2.36 pidfd_open F
 GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index ae1c6ca1..ede0e6eb 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2758,6 +2758,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
index a7c572c9..22525fe8 100644
--- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
+++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
@@ -2140,6 +2140,8 @@  GLIBC_2.36 pidfd_open F
 GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 074fa031..2938361e 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2773,6 +2773,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index dfcb4bd2..e1c70a25 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2806,6 +2806,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 63bbccf3..2ce2d974 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2527,6 +2527,8 @@  GLIBC_2.36 pidfd_open F
 GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index ab85fd61..b1024501 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2829,6 +2829,8 @@  GLIBC_2.36 pidfd_open F
 GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fscanfieee128 F
 GLIBC_2.38 __isoc23_fwscanf F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index b716f5c7..833fb747 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2396,6 +2396,8 @@  GLIBC_2.36 pidfd_open F
 GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 774e777b..cbd85454 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2596,6 +2596,8 @@  GLIBC_2.36 pidfd_open F
 GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 8625135c..1442a0b9 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2771,6 +2771,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index d00c7eb2..1a7f4fc7 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2564,6 +2564,8 @@  GLIBC_2.36 pidfd_open F
 GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index b6303724..3146ce99 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2626,6 +2626,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index d8005561..31360691 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2623,6 +2623,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 5be55c11..026e9581 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2766,6 +2766,8 @@  GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
 GLIBC_2.37 __ppoll64_chk F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 475fdaae..6ecb0d46 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2591,6 +2591,8 @@  GLIBC_2.36 pidfd_open F
 GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 6cfb928b..a37f4ab4 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2542,6 +2542,8 @@  GLIBC_2.36 pidfd_open F
 GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index c7350971..3b8790f4 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2648,6 +2648,8 @@  GLIBC_2.36 pidfd_open F
 GLIBC_2.36 pidfd_send_signal F
 GLIBC_2.36 process_madvise F
 GLIBC_2.36 process_mrelease F
+GLIBC_2.38 __fcntl64_2 F
+GLIBC_2.38 __fcntl_2 F
 GLIBC_2.38 __isoc23_fscanf F
 GLIBC_2.38 __isoc23_fwscanf F
 GLIBC_2.38 __isoc23_scanf F