diff options
Diffstat (limited to 'sysdeps')
41 files changed, 768 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index f6b59d8..955d316 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 \ bits/procfs-extra.h \ bits/procfs-id.h \ bits/procfs-prregset.h \ @@ -623,6 +624,7 @@ sysdep_routines += \ internal_statvfs \ open64_nocancel \ open_nocancel \ + openat2 \ openat64_nocancel \ openat_nocancel \ pread64_nocancel \ @@ -634,7 +636,12 @@ sysdep_routines += \ xstatconv \ # sysdep_routines +routines_no_fortify += \ + openat2 \ + # routines_no_fortify + sysdep_headers += \ + bits/fcntl-linux-fortify.h \ bits/fcntl-linux.h \ # sysdep_headers @@ -643,7 +650,24 @@ tests += \ tst-fallocate64 \ tst-getcwd-smallbuff \ tst-o_path-locks \ + tst-openat2 \ + tst-openat2-lfs \ # 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 + endif ifeq ($(subdir),elf) diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions index 8f4d71a..c7f199f 100644 --- a/sysdeps/unix/sysv/linux/Versions +++ b/sysdeps/unix/sysv/linux/Versions @@ -341,6 +341,7 @@ libc { } GLIBC_2.43 { mseal; + openat2; } GLIBC_PRIVATE { # functions used in other libraries diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist index d161d26..3156688 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist @@ -2773,4 +2773,5 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 62879b6..8af5b0b 100644 --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist @@ -3120,6 +3120,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 bd5fa65..35fcef2 100644 --- a/sysdeps/unix/sysv/linux/arc/libc.abilist +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist @@ -2534,4 +2534,5 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 7d975da..a6c6b95 100644 --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist @@ -2826,6 +2826,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 c95bbfe..e76015f 100644 --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist @@ -2823,6 +2823,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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-fortify.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux-fortify.h new file mode 100644 index 0000000..e6b414d --- /dev/null +++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux-fortify.h @@ -0,0 +1,49 @@ +/* Checking macros for fcntl functions. Linux version. + 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 include <bits/fcntl-linux-fortify.h> directly; use <fcntl.h> instead." +#endif + +#ifdef __USE_GNU + +extern int __REDIRECT (__openat2_alias, (int __dfd, const char *__filename, + const struct open_how *__how, + size_t __usize), openat2) + __nonnull ((2, 3)); + +#if !__fortify_use_clang +__errordecl (__openat2_invalid_size, + "the specified size is larger than sizeof (struct open_how)"); +#endif + +__fortify_function int +openat2 (int __dfd, const char *__filename, const struct open_how *__how, + size_t __usize) + __fortify_clang_warning (__builtin_constant_p (__usize) + && __usize > sizeof (struct open_how), + "the specified size is larger than sizeof (struct open_how)") +{ +#if !__fortify_use_clang + if (__builtin_constant_p (__usize) && __usize > sizeof (struct open_how)) + __openat2_invalid_size (); +#endif + return __openat2_alias (__dfd, __filename, __how, __usize); +} + +#endif /* use GNU */ diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h index f9b3de1..bdab40f 100644 --- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h +++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h @@ -463,6 +463,33 @@ 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 openat, unknown or invalid flags result in an error (EINVAL), + rather than being ignored. The mode must be zero unless one of O_CREAT + or O_TMPFILE are set. + + The kernel does not support legacy non-LFS interface. */ +extern int openat2 (int __dfd, const char * __filename, + const struct open_how * __how, + __SIZE_TYPE__ __usize) + __nonnull ((2, 3)); + #endif /* use GNU */ +#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function +# include <bits/fcntl-linux-fortify.h> +#endif + __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 0000000..a3fe858 --- /dev/null +++ b/sysdeps/unix/sysv/linux/bits/openat2.h @@ -0,0 +1,60 @@ +/* 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. */ +#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. */ +#endif diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist index 6fc9189..1fb7cdc 100644 --- a/sysdeps/unix/sysv/linux/csky/libc.abilist +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist @@ -2810,4 +2810,5 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 8a83722..0710cce 100644 --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist @@ -2847,6 +2847,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 3b96177..3afe3a8 100644 --- a/sysdeps/unix/sysv/linux/i386/libc.abilist +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist @@ -3030,6 +3030,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 bc39d18..c2b3a66 100644 --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist @@ -2294,4 +2294,5 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 b42b4fe..d685513 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -2806,6 +2806,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 854bf3c..4e3fe9c 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -2973,6 +2973,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 ab3d67b..29f0c5f 100644 --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist @@ -2859,4 +2859,5 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 510b3a2..2ef6283 100644 --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist @@ -2856,4 +2856,5 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 dd2baab..031e896 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist @@ -2936,6 +2936,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 88fa8b9..8dc99d8 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist @@ -2934,6 +2934,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist index 00993fe..054c5b6 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist @@ -2942,6 +2942,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 136da09..13f0148 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist @@ -2844,6 +2844,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 0000000..d45eb05 --- /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 *filename, + const struct open_how *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 1a2a367..e7ffe07 100644 --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist @@ -2284,4 +2284,5 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 f00901f..dea4b20 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist @@ -3163,6 +3163,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 de23059..b45e127 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist @@ -3208,6 +3208,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 1ae78ec..942cf6a 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist @@ -2917,6 +2917,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 53cb317..65d78e5 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist @@ -2993,4 +2993,5 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 e6fd213..dcab30d 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist @@ -2537,4 +2537,5 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 905323b..796ef35 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist @@ -2737,4 +2737,5 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 c35e099..9bd9f5e 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist @@ -3161,6 +3161,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 9f34c5f..8f2350e 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist @@ -2954,6 +2954,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 f26980c..7aa98c5 100644 --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist @@ -2853,6 +2853,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 e8ee581..6bd4f8f 100644 --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist @@ -2850,6 +2850,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 3d0665d..b52cab2 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -3184,6 +3184,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 0b7644d..ff99cd4 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -2820,6 +2820,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 0000000..9b65d18 --- /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 0000000..85962d3 --- /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 0000000..0778b98 --- /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); + + /* 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 temporary 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"); + + 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 85533e9..306cd62 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -2769,6 +2769,7 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal 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 2b2a351..8b9c448 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2788,4 +2788,5 @@ GLIBC_2.43 free_sized F GLIBC_2.43 memalignment F GLIBC_2.43 memset_explicit F GLIBC_2.43 mseal F +GLIBC_2.43 openat2 F GLIBC_2.43 umaxabs F |
