[PATCH] linux: Add openat2 (BZ 31664)
Carlos O'Donell
carlos@redhat.com
Thu Nov 6 13:43:18 GMT 2025
On 10/29/25 4:05 PM, Adhemerval Zanella wrote:
> The openat2 syscall was added on Linux 5.6, as an extension of openat.
> Unlike other open-like functions, the kernel only provides the LFS
> variant (so files larger than 4GB always succeed, unlike other
> functions with an offset larger than off_t). Also, similar to other
> open functions, the new symbol is a cancellable entrypoint.
>
> The test case added only stress tests for some of the syscalls' provided
> functionality, and it is based on an existing kernel self-test. Since
> the prototype does not use variadic arguments, there is no need to add
> a fortify wrapper to catch wrong usages.
>
> The documentation mostly defers to the Linux manual pages.
>
> Gnulib added an openat2 module, which uses read-only for the open_how
> argument [1]. There is no clear indication whether the kernel will
> indeed use the argument as in-out, how it would do so, or for which
> kind of functionality [2]. Also, adding a potentially different prototype
> than gnulib only would add extra unnecessary friction and extra
> wrappers to handle it.
>
> Checked on x86_64-linux-gnu.
I experimented with Claude Code to do an LLM-assisted review.
Notes below. Nothing is copyrightable so we should be OK accepting these
changes despite not yet having an LLM content policy.
Please post a v2.
Mostly comment and manual changes.
> [1] https://gitweb.git.savannah.gnu.org/gitweb/?p=gnulib.git;a=commit;h=0b97ffdf32bdab909d02449043447237273df75e
> [2] https://sourceware.org/pipermail/libc-alpha/2025-September/169740.html
> ---
> NEWS | 4 +
> manual/llio.texi | 111 ++++
> sysdeps/unix/sysv/linux/Makefile | 19 +
> sysdeps/unix/sysv/linux/Versions | 3 +
> sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/arc/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/arm/be/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/arm/le/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/bits/fcntl-linux.h | 23 +
> sysdeps/unix/sysv/linux/bits/openat2.h | 61 +++
> sysdeps/unix/sysv/linux/csky/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/hppa/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/i386/libc.abilist | 1 +
> .../sysv/linux/loongarch/lp64/libc.abilist | 1 +
> .../sysv/linux/m68k/coldfire/libc.abilist | 1 +
> .../unix/sysv/linux/m68k/m680x0/libc.abilist | 1 +
> .../sysv/linux/microblaze/be/libc.abilist | 1 +
> .../sysv/linux/microblaze/le/libc.abilist | 1 +
> .../sysv/linux/mips/mips32/fpu/libc.abilist | 1 +
> .../sysv/linux/mips/mips32/nofpu/libc.abilist | 1 +
> .../sysv/linux/mips/mips64/n32/libc.abilist | 1 +
> .../sysv/linux/mips/mips64/n64/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/openat2.c | 29 ++
> sysdeps/unix/sysv/linux/or1k/libc.abilist | 1 +
> .../linux/powerpc/powerpc32/fpu/libc.abilist | 1 +
> .../powerpc/powerpc32/nofpu/libc.abilist | 1 +
> .../linux/powerpc/powerpc64/be/libc.abilist | 1 +
> .../linux/powerpc/powerpc64/le/libc.abilist | 1 +
> .../unix/sysv/linux/riscv/rv32/libc.abilist | 1 +
> .../unix/sysv/linux/riscv/rv64/libc.abilist | 1 +
> .../unix/sysv/linux/s390/s390-32/libc.abilist | 1 +
> .../unix/sysv/linux/s390/s390-64/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/sh/be/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/sh/le/libc.abilist | 1 +
> .../sysv/linux/sparc/sparc32/libc.abilist | 1 +
> .../sysv/linux/sparc/sparc64/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/tst-openat2-consts.py | 63 +++
> sysdeps/unix/sysv/linux/tst-openat2-lfs.c | 1 +
> sysdeps/unix/sysv/linux/tst-openat2.c | 482 ++++++++++++++++++
> .../unix/sysv/linux/x86_64/64/libc.abilist | 1 +
> .../unix/sysv/linux/x86_64/x32/libc.abilist | 1 +
> 42 files changed, 828 insertions(+)
> create mode 100644 sysdeps/unix/sysv/linux/bits/openat2.h
> create mode 100644 sysdeps/unix/sysv/linux/openat2.c
> create mode 100755 sysdeps/unix/sysv/linux/tst-openat2-consts.py
> create mode 100644 sysdeps/unix/sysv/linux/tst-openat2-lfs.c
> create mode 100644 sysdeps/unix/sysv/linux/tst-openat2.c
>
> diff --git a/NEWS b/NEWS
> index 4b1f259fde6..841636ceae9 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -13,6 +13,10 @@ Major new features:
>
> * The ISO C23 memalignment function has been added.
>
> +* On Linux, the openat2 function has been added. It is an extension of
> + openat and provides a superset of its functionality. It is supported only
> + in LFS mode and it is a cancellable entrypoint.
OK.
> +
> Deprecated and removed features, and other changes affecting compatibility:
>
> * Support for dumped heaps has been removed - malloc_set_state() now always
> diff --git a/manual/llio.texi b/manual/llio.texi
> index 806ff0a27d5..0bd9e4e1239 100644
> --- a/manual/llio.texi
> +++ b/manual/llio.texi
> @@ -218,6 +218,117 @@ new, extended API using 64 bit file sizes and offsets transparently
> replaces the old API.
> @end deftypefun
>
> +@deftp {Data Type} {struct open_how}
> +@standards{Linux, fcntl.h}
> +The @code{open_how} structure describes how to open a file using @code{openat2}.
> +
> +@strong{Portability note:} In the future, additional fields can be added
> +to @code{struct open_how} at the end, so that the size of this data
> +type changes. Do not use it in places where this matters, such as
> +structure fields in installed header files, where such a change could
> +affect the application binary interface (ABI).
> +
> +The following generic fields are available.
> +
> +@table @code
> +@item flags
> +This field specifies the file creation and file status flags to use when
> +opening the file.
> +All of the @code{O_*} flags defined for @code{openat} are valid.
> +Unlike than @code{openat}, @code{openat2} returns an error for unknown
s/than//g
Caught by Claude Code in LLM-assited review.
> +or conflicting values.
> +
> +@item mode
> +This field specifies the mode for the new file, similar to @code{mode}
> +argument of @code{openat}. Unlike @code{openat}, @code{openat2}
> +returns an error for invalid values (i.e., values greater than @code{07777}).
> +
> +@item resolve
> +This is a bitmask of flags that affect the resolution of file name components.
> +Unlike @code{O_NOFOLLOW}, it affects all file name components, not just the
> +last one. The following flags are available.
> +
> +@table @code
> +@item RESOLVE_NO_XDEV
> +Disallow traversal of mount points during path resolution (including all
> +bind mounts).
> +
> +@item RESOLVE_NO_MAGICLINKS
> +Disallow all @strong{magic-link} resolution during path resolution. Magic
> +links are symbolic link-like objects that are found in @strong{procfs};
> +for example the @code{/proc/pid/exe}.
> +
> +@item RESOLVE_NO_SYMLINKS
> +Disallow resolution of symbolic links during path resolution.
> +This option implies @code{RESOLVE_NO_MAGICLINKS}.
> +
> +@item RESOLVE_BENEATH
> +Do not permit the path resolution to succeed if any component of the
> +resolution is not a descendant of the directory indicated by @var{dirfd}.
> +This cause absolute symbolic links and absolute values of @var{pathname}
s/cause/causes/g
Caught by Claude Code in LLM-assited review.
> +to be reject.
> +
> +@item RESOLVE_IN_ROOT
> +Treat the directory referred by @var{dirfd} as the root directory
s/referred by/referred to by/g
Caught by Claude Code in LLM-assited review.
> +while resolving the @var{pathname}.
> +Absolute symbolic links and absolute values of @var{pathnames} are
> +interpreted relative to @var{dirfd}.
> +The effect of this flag is as though the calling process has used
> +@code{chroot} to modify its root direftory.
s/direftory/directory/g
Caught by Claude Code in LLM-assited review.
> +
> +@item RESOLVE_CACHED
> +Make the open operation fail unless all path components are already
> +present in the kernel's lookup cache.
> +@end table
OK. Table is correct and contains the data I would expect.
Asked Claude Code to cross-check and it confirmed what I already knew.
> +
> +@end table
> +
> +For additional information, consult the manual page @manpageurl{openat2,2}.
> +@xref{Linux Kernel}.
> +@end deftp
> +
> +
> +@deftypefun int openat2 (int @var{dirfd}, const char *restrict @var{pathname}, const struct open_how *restrict @var{how}, size_t @var{size})
> +@standards{Linux, fcntl.h}
> +@safety{@mtsafe{}@assafe{}@acsafe{}}
> +This function is an extension of the @code{openat} and provides a superset of its
> +functionality. @xref{Descriptor-Relative Access}.
> +
> +The @var{size} argument must equal @code{sizeof *@var{how}}. For portability
> +to future API versions that extend @code{struct open_how}, @code{*@var{how}}
> +should be initialized either by a struct initializer or by @code{memset} to zero.
> +
> +On failure, @code{openat2} returns @math{-1} and sets @code{errno}. It can
> +fail for any of the reasons @code{openat} fails, plus the following reasons:
> +
> +@table @code
> +@item E2BIG
> +An extension that the kernel does support was specified in @code{*@var{how}},
s/does/does not/g
Caught by Claude Code in LLM-assisted review.
> +or a larger struct was used with non-zero members.
> +
> +@item EAGAIN
> +@code{@var{how}->resolve} contains either RESOLVE_IN_ROOT or RESOLVE_BENEATH, and
> +the kernel could not ensure that @code{".."} component did not escape. Or
> +@code{RESOLVE_CACHED} was set, and the open operation cannot be performed
> +using only cached information.
> +
> +@item EINVAL
> +And unknown flag or invalid value was used on @code{*@var{how}}; or
s/And/An/g
Caught by Claude Code in LLM-assited review.
> +@code{@var{how}->mode} is non-zero, but @code{@var{how}->flags} does not contain
> +@code{O_CREAT} or@code{O_TMPFILE}, or @var{size} is smaller than the ones supported
s/or@/or @/g
Caught by Claude Code in LLM-assited review.
> +by the kernel.
> +@end table
> +
> +It can also return all the errors @code{openat} returns, or other errors
> +due to new members added by the kernel.
> +
> +Similar to @code{openat}, @code{openat2} is a cancellation point.
> +
> +Unlike other @code{open}-like functions, this function ignores
> +@code{_FILE_OFFSET_BITS} and always operates in large file mode.
> +@end deftypefun
OK.
> +
> +
> @deftypefn {Obsolete function} int creat (const char *@var{filename}, mode_t @var{mode})
> @standards{POSIX.1, fcntl.h}
> @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}}
> diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
> index d1ac6409b18..971c97889b2 100644
> --- a/sysdeps/unix/sysv/linux/Makefile
> +++ b/sysdeps/unix/sysv/linux/Makefile
> @@ -135,6 +135,7 @@ sysdep_headers += \
> bits/mman-linux.h \
> bits/mman-map-flags-generic.h \
> bits/mman-shared.h \
> + bits/openat2.h \
OK.
> bits/procfs-extra.h \
> bits/procfs-id.h \
> bits/procfs-prregset.h \
> @@ -620,6 +621,7 @@ sysdep_routines += \
> internal_statvfs \
> open64_nocancel \
> open_nocancel \
> + openat2 \
OK.
> openat64_nocancel \
> openat_nocancel \
> pread64_nocancel \
> @@ -640,7 +642,24 @@ tests += \
> tst-fallocate64 \
> tst-getcwd-smallbuff \
> tst-o_path-locks \
> + tst-openat2 \
> + tst-openat2-lfs \
OK. Two new tests.
> # tests
> +
> +tests-special += \
> + $(objpfx)tst-openat2-consts.out \
> + # tests-special
> +$(objpfx)tst-openat2-consts.out: ../sysdeps/unix/sysv/linux/tst-openat2-consts.py
> + $(sysdeps-linux-python) \
> + ../sysdeps/unix/sysv/linux/tst-openat2-consts.py \
> + $(sysdeps-linux-python-cc) \
> + < /dev/null > $@ 2>&1; $(evaluate-test)
> +$(objpfx)tst-openat2-consts.out: $(sysdeps-linux-python-deps)
> +
> +# openat2 only provides LFS support, the tests check if the interface is correctly
> +# provided regardless of the flags.
> +CFLAGS-tst-openat2-lfs.c += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
OK.
> +
> endif
>
> ifeq ($(subdir),elf)
> diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
> index 585dec7689e..7f67562eeaf 100644
> --- a/sysdeps/unix/sysv/linux/Versions
> +++ b/sysdeps/unix/sysv/linux/Versions
> @@ -339,6 +339,9 @@ libc {
> cfsetispeed;
> cfsetspeed;
> }
> + GLIBC_2.43 {
> + openat2;
> + }
OK.
> GLIBC_PRIVATE {
> # functions used in other libraries
> __syscall_rt_sigqueueinfo;
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index ecb1be5bb49..9055099e953 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2770,4 +2770,5 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index 55c22da87f3..6ef24e0ab73 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -3117,6 +3117,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
> index b1e5855b5dd..2f5e7db4b7c 100644
> --- a/sysdeps/unix/sysv/linux/arc/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
> @@ -2531,4 +2531,5 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> index 1ac00b8303f..f783d7fa7eb 100644
> --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> @@ -2823,6 +2823,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> index cf92ab4adae..239e8a41397 100644
> --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> @@ -2820,6 +2820,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
> index f425a4bf22b..650c29d7df8 100644
> --- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
> +++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h
> @@ -455,6 +455,29 @@ extern int name_to_handle_at (int __dfd, const char *__name,
> extern int open_by_handle_at (int __mountdirfd, struct file_handle *__handle,
> int __flags);
>
> +#ifdef __has_include
> +# if __has_include ("linux/openat2.h")
> +# include "linux/openat2.h"
> +# define __glibc_has_open_how 1
> +# endif
> +#endif
> +
> +#include <bits/openat2.h>
> +
> +/* Similar to `openat' but the arguments are packed on HOW with the size
> + USIZE. If flags and mode from HOW are non-zero, then openat2 operates
> + like openat.
> +
> + Unlike openat2, unknown or invalid flags result in an error (EINVAL),
Typo. s/Unlike openat2/Unlike openat/g.
Caught by me and Claude Code in an LLM-assisted review.
> + rather than being ignored. The mode must be zero unless one O_CREAT
> + or O_TMPFILE are set.
> +
> + The kernel does not support legacy non-LFS interface. */
> +extern int openat2 (int __dfd, const char *__restrict __filename,
> + const struct open_how *__restrict __how,
> + size_t __usize)
> + __nonnull ((2, 3));
> +
> #endif /* use GNU */
>
> __END_DECLS
> diff --git a/sysdeps/unix/sysv/linux/bits/openat2.h b/sysdeps/unix/sysv/linux/bits/openat2.h
> new file mode 100644
> index 00000000000..6059095bc13
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/bits/openat2.h
> @@ -0,0 +1,61 @@
> +/* openat2 definition. Linux specific.
> + Copyright (C) 2025 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#ifndef _FCNTL_H
> +# error "Never use <bits/openat2.h> directly; include <fcntl.h> instead."
> +#endif
> +
> +#ifndef __glibc_has_open_how
> +/* Arguments for how openat2 should open the target path. */
> +struct open_how
> +{
> + __uint64_t flags;
> + __uint64_t mode;
> + __uint64_t resolve;
> +};
> +#endif
> +
> +/* how->resolve flags for openat2. */
> +#ifndef RESOLVE_NO_XDEV
> +# define RESOLVE_NO_XDEV 0x01 /* Block mount-point crossings
> + (includes bind-mounts). */
> +#endif
> +#ifndef RESOLVE_NO_MAGICLINKS
> +# define RESOLVE_NO_MAGICLINKS 0x02 /* Block traversal through procfs-style
> + "magic-links". */
> +#endif
> +#ifndef RESOLVE_NO_SYMLINKS
> +# define RESOLVE_NO_SYMLINKS 0x04 /* Block traversal through all symlinks
> + (implies OEXT_NO_MAGICLINKS). */
There is no such thing as OEXT_NO_MAGICLINKS?
This looks like a typo in the Linux kernel headers comment?
Also caught by Claude Code in LLM-assisted review.
Typo appears 3 times in upstream Linux kernel.
> +#endif
> +#ifndef RESOLVE_BENEATH
> +# define RESOLVE_BENEATH 0x08 /* Block "lexical" trickery like
> + "..", symlinks, and absolute
> + paths which escape the dirfd. */
> +#endif
> +#ifndef RESOLVE_IN_ROOT
> +# define RESOLVE_IN_ROOT 0x10 /* Make all jumps to "/" and ".."
> + be scoped inside the dirfd
> + (similar to chroot). */
> +#endif
> +#ifndef RESOLVE_CACHED
> +# define RESOLVE_CACHED 0x20 /* Only complete if resolution can be
> + completed through cached lookup. May
> + return -EAGAIN if that's not
> + possible. */
OK. Constants match.
> +#endif
> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> index 5d00604da52..5fc67a0ecc8 100644
> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> @@ -2807,4 +2807,5 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index 4011dc5cc09..601f4cef1c5 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -2844,6 +2844,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index 3757e41e6f4..d87bac95f1e 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -3027,6 +3027,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> index 8bbb9503862..59ec6a2d920 100644
> --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> @@ -2291,4 +2291,5 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index 74b36e84b6f..46f329c2c82 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -2803,6 +2803,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index b5cf2998c36..3df90353855 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -2970,6 +2970,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> index 547e21eb66c..ab77cdd6bdf 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> @@ -2856,4 +2856,5 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> index f98407da281..503606816af 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> @@ -2853,4 +2853,5 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index 1e207c97c33..231f56378c1 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -2933,6 +2933,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index f947cbb8f52..80e97539be3 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -2907,6 +2907,7 @@ GLIBC_2.4 renameat F
> GLIBC_2.4 symlinkat F
> GLIBC_2.4 unlinkat F
> GLIBC_2.4 unshare F
> +GLIBC_2.41 openat2 F
> GLIBC_2.41 sched_getattr F
> GLIBC_2.41 sched_setattr F
> GLIBC_2.42 __inet_ntop_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index d44b0c41c0d..7f499cd71af 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -2939,6 +2939,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index bdcde501656..8c64d378162 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -2841,6 +2841,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/openat2.c b/sysdeps/unix/sysv/linux/openat2.c
> new file mode 100644
> index 00000000000..77d16915eeb
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/openat2.c
> @@ -0,0 +1,29 @@
> +/* Linux openat2 syscall implementation.
> + Copyright (C) 2025 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <fcntl.h>
> +#include <bits/openat2.h>
> +#include <sysdep-cancel.h>
> +
> +int
> +__openat2 (int dfd, const char *__restrict filename,
> + const struct open_how *__restrict how, size_t usize)
> +{
> + return SYSCALL_CANCEL (openat2, dfd, filename, how, usize);
> +}
> +weak_alias (__openat2, openat2)
> diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> index f2117e1dcc0..451b99196a3 100644
> --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> @@ -2281,4 +2281,5 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index 6e887bcca48..8201d131032 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -3160,6 +3160,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index 247cbc2c8d8..07c9a211892 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -3205,6 +3205,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> index 70fe1f2de82..fe6d427ec4f 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> @@ -2914,6 +2914,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> index 8f82f6c6480..d17b57b51fd 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> @@ -2990,4 +2990,5 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> index 57b5790914d..dad06299831 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> @@ -2534,4 +2534,5 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> index faeaebc5003..ea721159fae 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> @@ -2734,4 +2734,5 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index 62a71df1013..34c8b2b85ef 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -3158,6 +3158,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index 01681666e85..bd1d36bc1f1 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -2951,6 +2951,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> index b93a621870a..681efefe897 100644
> --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> @@ -2850,6 +2850,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> index fb41f72160b..8dc20a90be5 100644
> --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> @@ -2847,6 +2847,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index cbe10bb14c7..830c81ef15f 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -3181,6 +3181,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index 480dc5e8cd8..bc0207cf009 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -2817,6 +2817,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/tst-openat2-consts.py b/sysdeps/unix/sysv/linux/tst-openat2-consts.py
> new file mode 100755
> index 00000000000..9b65d184d73
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/tst-openat2-consts.py
> @@ -0,0 +1,63 @@
> +#!/usr/bin/python3
> +# Test that glibc's sys/openat2.h constants match the kernel's.
> +# Copyright (C) 2025 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/>.
> +
> +import argparse
> +import sys
> +
> +import glibcextract
> +import glibcsyscalls
> +
> +
> +def main():
> + """The main entry point."""
> + parser = argparse.ArgumentParser(
> + description="Test that glibc's sys/openat2.h constants "
> + "match the kernel's.")
> + parser.add_argument('--cc', metavar='CC',
> + help='C compiler (including options) to use')
> + args = parser.parse_args()
> +
> + if glibcextract.compile_c_snippet(
> + '#include <linux/openat2.h>',
> + args.cc).returncode != 0:
> + sys.exit (77)
> +
> + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
> + # Constants in glibc were updated to match Linux v6.8. When glibc
> + # constants are updated this value should be updated to match the
> + # released kernel version from which the constants were taken.
> + linux_version_glibc = (6, 8)
> + def check(cte, exclude=None):
> + return glibcextract.compare_macro_consts(
> + '#define _FCNTL_H\n'
> + '#include <stdint.h>\n'
> + '#include <bits/openat2.h>\n',
> + '#include <asm/fcntl.h>\n'
> + '#include <linux/openat2.h>\n',
> + args.cc,
> + cte,
> + exclude,
> + linux_version_glibc > linux_version_headers,
> + linux_version_headers > linux_version_glibc)
> +
> + status = check('RESOLVE.*')
> + sys.exit(status)
> +
> +if __name__ == '__main__':
> + main()
> diff --git a/sysdeps/unix/sysv/linux/tst-openat2-lfs.c b/sysdeps/unix/sysv/linux/tst-openat2-lfs.c
> new file mode 100644
> index 00000000000..85962d30c17
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/tst-openat2-lfs.c
> @@ -0,0 +1 @@
> +#include "tst-openat2.c"
> diff --git a/sysdeps/unix/sysv/linux/tst-openat2.c b/sysdeps/unix/sysv/linux/tst-openat2.c
> new file mode 100644
> index 00000000000..e52e3870d04
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/tst-openat2.c
> @@ -0,0 +1,482 @@
> +/* Linux openat2 tests.
> + Copyright (C) 2025 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <array_length.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <libgen.h>
> +#include <stdint.h>
> +
> +#include <support/check.h>
> +#include <support/support.h>
> +#include <support/temp_file.h>
> +#include <support/test-driver.h>
> +#include <support/xunistd.h>
> +
> +static int dir_fd;
> +static char *temp_dir;
> +static char *temp_subdir;
> +static char *temp_some_file;
> +
> +#define TEST_DIR_LINK "test_dir_link"
> +#define TEST_DIR_LINK_2 "test_dir_link_2"
> +#define TEMP_DIR_LINK "temp_dir_link"
> +#define INVALID_LINK "invalid-link"
> +#define VALID_LINK "valid-link"
> +
> +static void
> +create_symlink (const char *target, const char *linkpath)
> +{
> + TEST_VERIFY_EXIT (symlinkat (target, dir_fd, linkpath) == 0);
> + add_temp_file (xasprintf ("%s/%s", temp_dir, linkpath));
> +}
> +
> +static void
> +do_prepare (int argc, char *argv[])
> +{
> + /*
> + Construct a test directory with the following structure:
> +
> + temp_dir/
> + |- tst-openat2.xxxxxxx
> + |- test_dir_link -> test_dir (/tmp)
> + |- test_dir_link_2 -> test_dir_link
> + |- temp_dir_link -> temp_dir/tst-openat2.xxxxxxx
> + |- some-file.xxxxxxx
> + |- invalid_link -> temp_dir/tst-openat2.xxxxxxx/some-file.xxxxxxx
> + |- valid_link -> some-file.xxxxxxx
> + |- subdir.xxxxxxx
> + |- some-file.xxxxxxx
> + */
> +
> + temp_dir = support_create_temp_directory ("tst-openat2.");
> + dir_fd = xopen (temp_dir, O_RDONLY | O_DIRECTORY, 0);
> +
> + create_symlink (test_dir, TEST_DIR_LINK);
> + create_symlink (TEST_DIR_LINK, TEST_DIR_LINK_2);
> + create_symlink (temp_dir, TEMP_DIR_LINK);
> +
> + {
> + char *filename;
> + int fd = create_temp_file_in_dir ("some-file.", temp_dir, &filename);
> + TEST_VERIFY_EXIT (fd != -1);
> +
> + create_symlink (filename, INVALID_LINK);
> +
> + create_symlink (basename (filename), VALID_LINK);
> + }
> +
> + temp_subdir = support_create_temp_directory (xasprintf ("%s/subdir.",
> + basename (temp_dir)));
> + {
> + int fd = create_temp_file_in_dir ("some-file.", temp_subdir,
> + &temp_some_file);
> + TEST_VERIFY_EXIT (fd != -1);
> + }
> +}
> +#define PREPARE do_prepare
> +
> +static int
> +do_test_struct (void)
> +{
> + static struct struct_test
> + {
> + struct open_how_ext
> + {
> + struct open_how inner;
> + int extra1;
> + int extra2;
> + int extra3;
> + } arg;
> + size_t size;
> + int err;
> + } tests[] =
> + {
> + {
> + /* Zero size. */
> + .arg.inner.flags = O_RDONLY,
> + .size = 0,
> + .err = EINVAL,
> + },
> + {
> + /* Normal struct. */
> + .arg.inner.flags = O_RDONLY,
> + .size = sizeof (struct open_how),
> + },
> + {
> + /* Larger struct, zeroed out the unused values. */
> + .arg.inner.flags = O_RDONLY,
> + .size = sizeof (struct open_how_ext),
> + },
> + {
> + /* Larger struct, non-zeroed out the unused values. */
> + .arg.inner.flags = O_RDONLY,
> + .arg.extra1 = 0xdeadbeef,
> + .size = sizeof (struct open_how_ext),
> + .err = E2BIG,
> + },
> + {
> + /* Larger struct, non-zeroed out the unused values. */
> + .arg.inner.flags = O_RDONLY,
> + .arg.extra2 = 0xdeadbeef,
> + .size = sizeof (struct open_how_ext),
> + .err = E2BIG,
> + },
> + };
> +
> + for (struct struct_test *t = tests; t != array_end (tests); t++)
> + {
> + int fd = openat2 (AT_FDCWD, ".", (struct open_how *) &t->arg, t->size);
> + if (t->err != 0)
> + {
> + TEST_COMPARE (fd, -1);
> + TEST_COMPARE (errno, t->err);
> + }
> + else
> + TEST_VERIFY (fd >= 0);
> + }
> +
> + return 0;
> +}
> +
> +static int
> +do_test_flags (void)
> +{
> + static struct flag_test
> + {
> + const char *path;
> + struct open_how how;
> + int err;
> + } tests[] =
> + {
> + /* O_TMPFILE is incompatible with O_PATH and O_CREAT. */
> + {
> + .how.flags = O_TMPFILE | O_PATH | O_RDWR,
> + .err = EINVAL },
> + {
> + .how.flags = O_TMPFILE | O_CREAT | O_RDWR,
> + .err = EINVAL },
> +
> + /* O_PATH only permits certain other flags to be set ... */
> + {
> + .how.flags = O_PATH | O_CLOEXEC
> + },
> + {
> + .how.flags = O_PATH | O_DIRECTORY
> + },
> + {
> + .how.flags = O_PATH | O_NOFOLLOW
> + },
> + /* ... and others are absolutely not permitted. */
> + {
> + .how.flags = O_PATH | O_RDWR,
> + .err = EINVAL },
> + {
> + .how.flags = O_PATH | O_CREAT,
> + .err = EINVAL },
> + {
> + .how.flags = O_PATH | O_EXCL,
> + .err = EINVAL },
> + {
> + .how.flags = O_PATH | O_NOCTTY,
> + .err = EINVAL },
> + {
> + .how.flags = O_PATH | O_DIRECT,
> + .err = EINVAL },
> +
> + /* ->mode must only be set with O_{CREAT,TMPFILE}. */
> + {
> + .how.flags = O_RDONLY,
> + .how.mode = 0600,
> + .err = EINVAL },
> + {
> + .how.flags = O_PATH,
> + .how.mode = 0600,
> + .err = EINVAL },
> + {
> + .how.flags = O_CREAT,
> + .how.mode = 0600 },
> + {
> + .how.flags = O_TMPFILE | O_RDWR,
> + .how.mode = 0600 },
> + /* ->mode must only contain 0777 bits. */
> + {
> + .how.flags = O_CREAT, .how.mode = 0xFFFF, .err = EINVAL },
> + {
> + .how.flags = O_CREAT, .how.mode = 0xC000000000000000ULL,
> + .err = EINVAL },
> + {
> + .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0x1337,
> + .err = EINVAL },
> + {
> + .how.flags = O_TMPFILE | O_RDWR,
> + .how.mode = 0x0000A00000000000ULL,
> + .err = EINVAL
> + },
> +
> + /* ->resolve flags must not conflict. */
> + {
> + .how.flags = O_RDONLY,
> + .how.resolve = RESOLVE_BENEATH | RESOLVE_IN_ROOT,
> + .err = EINVAL
> + },
> +
> + /* ->resolve must only contain RESOLVE_* flags. */
> + {
> + .how.flags = O_RDONLY,
> + .how.resolve = 0x1337,
> + .err = EINVAL
> + },
> + {
> + .how.flags = O_CREAT,
> + .how.resolve = 0x1337,
> + .err = EINVAL
> + },
> + {
> + .how.flags = O_TMPFILE | O_RDWR,
> + .how.resolve = 0x1337,
> + .err = EINVAL
> + },
> + {
> + .how.flags = O_PATH,
> + .how.resolve = 0x1337,
> + .err = EINVAL
> + },
> +
> + /* currently unknown upper 32 bit rejected. */
> + {
> + .how.flags = O_RDONLY | (1ULL << 63),
> + .how.resolve = 0,
> + .err = EINVAL
> + },
> + };
> +
> + for (struct flag_test *t = tests; t != array_end (tests); t++)
> + {
> + const char *path;
> + if (t->how.flags & O_CREAT)
> + {
> + char *newfile;
> + int temp_fd = create_temp_file ("tst-openat2.", &newfile);
> + TEST_VERIFY_EXIT (temp_fd != -1);
> + xunlink (newfile);
> + path = newfile;
> + }
> + else
> + path = ".";
> +
> + int fd = openat2 (AT_FDCWD, path, &t->how, sizeof (struct open_how));
> + if (fd != 0 && errno == EOPNOTSUPP)
> + {
> + /* Skip the testcase if FS does not support the operation (e.g.
> + valid O_TMPFILE on NFS). */
> + continue;
> + }
> +
> + if (t->err != 0)
> + {
> + TEST_COMPARE (fd, -1);
> + TEST_COMPARE (errno, t->err);
> + }
> + else
> + TEST_VERIFY (fd >= 0);
> + }
> +
> + return 0;
> +}
> +
> +static void
> +do_test_resolve (void)
> +{
> + int fd;
> +
> + /* TEMP_DIR_LINK links to the absolute temp_dir, which escapes the temporary
> + test directory. */
> + fd = openat2 (dir_fd,
> + TEST_DIR_LINK,
> + &(struct open_how)
> + {
> + .resolve = RESOLVE_BENEATH,
> + },
> + sizeof (struct open_how));
> + TEST_COMPARE (fd, -1);
> + TEST_COMPARE (errno, EXDEV);
OK.
> +
> + /* Same as before, TEMP_DIR_LINK_2 links to TEMP_DIR_LINK. */
> + fd = openat2 (dir_fd,
> + TEST_DIR_LINK_2,
> + &(struct open_how)
> + {
> + .resolve = RESOLVE_BENEATH,
> + },
> + sizeof (struct open_how));
> + TEST_COMPARE (fd, -1);
> + TEST_COMPARE (errno, EXDEV);
> +
> + /* TEMP_DIR_LINK links to the temproary directory itself (dir_fd). */
> + fd = openat2 (dir_fd,
> + TEMP_DIR_LINK,
> + &(struct open_how)
> + {
> + .resolve = RESOLVE_BENEATH,
> + },
> + sizeof (struct open_how));
> + TEST_COMPARE (fd, -1);
> + TEST_COMPARE (errno, EXDEV);
> +
> + /* Although it points to a valid file in same path, the link refers to
> + an absolute path. */
> + fd = openat2 (dir_fd,
> + INVALID_LINK,
> + &(struct open_how)
> + {
> + .resolve = RESOLVE_BENEATH,
> + },
> + sizeof (struct open_how));
> + TEST_COMPARE (fd, -1);
> + TEST_COMPARE (errno, EXDEV);
> +
> + fd = openat2 (dir_fd,
> + VALID_LINK,
> + &(struct open_how)
> + {
> + .resolve = RESOLVE_BENEATH,
> + },
> + sizeof (struct open_how));
> + TEST_VERIFY (fd != -1);
> + xclose (fd);
> +
> + /* There is no such file in temp_dir/tst-openat2.xxxxxxx. */
> + fd = openat2 (dir_fd,
> + "should-not-work",
> + &(struct open_how)
> + {
> + .resolve = RESOLVE_IN_ROOT,
> + },
> + sizeof (struct open_how));
> + TEST_COMPARE (fd, -1);
> + TEST_COMPARE (errno, ENOENT);
> +
> + {
> + int subdir_fd = openat2 (dir_fd,
> + basename (temp_subdir),
> + &(struct open_how)
> + {
> + .flags = O_RDONLY | O_DIRECTORY,
> + .resolve = RESOLVE_IN_ROOT,
> + },
> + sizeof (struct open_how));
> + TEST_VERIFY (subdir_fd != -1);
> +
> + /* Open the file within the subdir.xxxxxx with both tst-openat2.xxxxxxx
> + and tst-openat2.xxxxxxx/subdir.xxxxxxx file descriptors. */
> + fd = openat2 (subdir_fd,
> + basename (temp_some_file),
> + &(struct open_how)
> + {
> + .resolve = RESOLVE_IN_ROOT,
> + },
> + sizeof (struct open_how));
> + TEST_VERIFY (fd != -1);
> + xclose (fd);
> +
> + fd = openat2 (dir_fd,
> + xasprintf ("%s/%s",
> + basename (temp_subdir),
> + basename (temp_some_file)),
> + &(struct open_how)
> + {
> + .resolve = RESOLVE_IN_ROOT,
> + },
> + sizeof (struct open_how));
> + TEST_VERIFY (fd != -1);
> + xclose (fd);
> + }
> +}
> +
> +static int
> +do_test_basic (void)
> +{
> + int fd;
> +
> + fd = openat2 (dir_fd,
> + "some-file",
> + &(struct open_how)
> + {
> + .flags = O_CREAT|O_RDWR|O_EXCL,
> + .mode = 0666,
> + },
> + sizeof (struct open_how));
> + TEST_VERIFY (fd != -1);
> +
> + xwrite (fd, "hello", 5);
> +
> + /* Before closing the file, try using this file descriptor to open
> + another file. This must fail. */
> + {
> + int fd2 = openat2 (fd,
> + "should-not-work",
> + &(struct open_how)
> + {
> + .flags = O_CREAT|O_RDWR|O_EXCL,
> + .mode = 0666,
> + },
> + sizeof (struct open_how));
> + TEST_COMPARE (fd2, -1);
> + TEST_COMPARE (errno, ENOTDIR);
> + }
> +
> + /* Remove the created file. */
> + int cwdfd = xopen (".", O_RDONLY | O_DIRECTORY, 0);
> + TEST_COMPARE (fchdir (dir_fd), 0);
> + xunlink ("some-file");
> + TEST_COMPARE (fchdir (cwdfd), 0);
> +
> + xclose (dir_fd);
> + xclose (cwdfd);
> +
> + fd = openat2 (dir_fd,
> + "some-file",
> + &(struct open_how)
> + {
> + .flags = O_CREAT|O_RDWR|O_EXCL,
> + .mode = 0666,
> + },
> + sizeof (struct open_how));
> + TEST_COMPARE (fd, -1);
> + TEST_COMPARE (errno, EBADF);
> +
> + return 0;
> +}
> +
> +static int
> +do_test (void)
> +{
> + if (openat2 (AT_FDCWD, ".", &(struct open_how) {}, sizeof (struct open_how))
> + == -1 && errno == ENOSYS)
> + FAIL_UNSUPPORTED ("openat2 is not supported by the kernel");
OK. Unsupported.
> +
> + do_test_struct ();
> + do_test_flags ();
> + do_test_resolve ();
> + do_test_basic ();
> +
> + return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index e46f66efdf7..a02b101d236 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -2766,6 +2766,7 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
> GLIBC_2.5 __readlinkat_chk F
> GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index a6edf8778ab..a3f69cc005f 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2785,4 +2785,5 @@ GLIBC_2.42 ullabs F
> GLIBC_2.43 __memset_explicit_chk F
> GLIBC_2.43 memalignment F
> GLIBC_2.43 memset_explicit F
> +GLIBC_2.43 openat2 F
> GLIBC_2.43 umaxabs F
--
Cheers,
Carlos.
More information about the Libc-alpha
mailing list