]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lib/fileutils: add ul_open_no_symlinks()
authorKarel Zak <kzak@redhat.com>
Wed, 27 May 2026 08:35:39 +0000 (10:35 +0200)
committerKarel Zak <kzak@redhat.com>
Thu, 28 May 2026 08:27:00 +0000 (10:27 +0200)
Add a helper that opens a path rejecting symlinks at any component,
not just the last one.  Uses openat2(RESOLVE_NO_SYMLINKS) when
available (Linux >= 5.6), falls back to open(O_NOFOLLOW).

Signed-off-by: Karel Zak <kzak@redhat.com>
configure.ac
include/fileutils.h
lib/fileutils.c
meson.build

index 34d6a2cd3e90fb51c33435f2093f24e8cdab3633..12ef78a15164d9180f7b9bcb51cf0b5ed725703b 100644 (file)
@@ -347,6 +347,7 @@ AC_CHECK_HEADERS([ \
        linux/kcmp.h \
        linux/net_namespace.h \
        linux/nsfs.h \
+       linux/openat2.h \
        linux/pr.h \
        linux/raw.h \
        linux/seccomp.h \
index 197e8a0f2e9a06ac64789034ac4e7d2f905ececc..7609576dbf0e333fe67847616bc7f1027db32a71 100644 (file)
@@ -64,6 +64,8 @@ static inline int is_same_inode(const int fd, const struct stat *st)
        return 1;
 }
 
+extern int ul_open_no_symlinks(const char *path, int flags, mode_t mode);
+
 extern int dup_fd_cloexec(int oldfd, int lowfd);
 extern unsigned int get_fd_tabsize(void);
 
index be480dff5a7c1aead25e0e6e8ee4b8b93129cf38..447a342e7012f9cbad0c5681d8d2ce13adb1e6a4 100644 (file)
 #include <unistd.h>
 #include <sys/time.h>
 #include <sys/resource.h>
+#include <sys/syscall.h>
 #include <string.h>
 #include <sys/wait.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifdef HAVE_LINUX_OPENAT2_H
+# include <linux/openat2.h>
+#endif
 
 #include "c.h"
 #include "all-io.h"
@@ -491,3 +498,20 @@ FILE *fopen_at_no_link(int dir, const char *filename,
        return fp;
 }
 #endif /* HAVE_OPENAT */
+
+int ul_open_no_symlinks(const char *path, int flags, mode_t mode)
+{
+#if defined(SYS_openat2) && defined(RESOLVE_NO_SYMLINKS)
+       struct open_how how = {
+               .flags = (__u64) flags,
+               .mode = (__u64) mode,
+               .resolve = RESOLVE_NO_SYMLINKS,
+       };
+       int fd = syscall(SYS_openat2, AT_FDCWD, path, &how, sizeof(how));
+
+       /* only fall back to O_NOFOLLOW if the syscall is unavailable */
+       if (fd >= 0 || errno != ENOSYS)
+               return fd;
+#endif
+       return open(path, flags | O_NOFOLLOW, mode);
+}
index 66cf3a7ce01eedc2e64bb3081e4184ab04891116..d6f2572a0deacb0905a0c35b5e1d913eff10542e 100644 (file)
@@ -123,6 +123,7 @@ headers = '''
         linux/kcmp.h
         linux/net_namespace.h
         linux/nsfs.h
+        linux/openat2.h
         linux/mount.h
         linux/pr.h
         linux/rfkill.h