commit:     b55840ebe3278032777a3b52cecc6dac325dcf85
Author:     Mike Gilbert <floppym <AT> gentoo <DOT> org>
AuthorDate: Mon Jun 19 15:50:46 2023 +0000
Commit:     Mike Gilbert <floppym <AT> gentoo <DOT> org>
CommitDate: Wed Jun 21 14:40:08 2023 +0000
URL:        https://gitweb.gentoo.org/proj/sandbox.git/commit/?id=b55840eb

libsbutil: add sb_exists function

This provides a central place to work around a bug on musl where
faccessat sets errno to EINVAL when the kernel does not support
faccessat2.

Bug: https://bugs.gentoo.org/908765
Signed-off-by: Mike Gilbert <floppym <AT> gentoo.org>

 libsandbox/pre_check_openat.c              |  2 +-
 libsandbox/wrapper-funcs/fopen_pre_check.c |  2 +-
 libsbutil/local.mk                         |  1 +
 libsbutil/sb_exists.c                      | 24 ++++++++++++++++++++++++
 libsbutil/sbutil.h                         |  1 +
 libsbutil/src/file.c                       |  2 +-
 6 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/libsandbox/pre_check_openat.c b/libsandbox/pre_check_openat.c
index 8fd3b23..99c03eb 100644
--- a/libsandbox/pre_check_openat.c
+++ b/libsandbox/pre_check_openat.c
@@ -19,7 +19,7 @@ bool sb_openat_pre_check(const char *func, const char 
*pathname, int dirfd, int
        save_errno();
 
        /* Doesn't exist -> skip permission checks */
-       if (faccessat(dirfd, pathname, F_OK, (flags & O_NOFOLLOW) ? 
AT_SYMLINK_NOFOLLOW : 0) == -1) {
+       if (sb_exists(dirfd, pathname, (flags & O_NOFOLLOW) ? 
AT_SYMLINK_NOFOLLOW : 0) == -1) {
                sb_debug_dyn("EARLY FAIL: %s(%s): %s\n", func, pathname, 
strerror(errno));
                return false;
        }

diff --git a/libsandbox/wrapper-funcs/fopen_pre_check.c 
b/libsandbox/wrapper-funcs/fopen_pre_check.c
index 95108e0..e3ed2c6 100644
--- a/libsandbox/wrapper-funcs/fopen_pre_check.c
+++ b/libsandbox/wrapper-funcs/fopen_pre_check.c
@@ -11,7 +11,7 @@ bool sb_fopen_pre_check(const char *func, const char 
*pathname, const char *mode
                save_errno();
 
                /* If we're trying to read, fail normally if file does not stat 
*/
-               if (faccessat(AT_FDCWD, pathname, F_OK, 0) == -1) {
+               if (sb_exists(AT_FDCWD, pathname, 0) == -1) {
                        sb_debug_dyn("EARLY FAIL: %s(%s): %s\n",
                                func, pathname, strerror(errno));
                        return false;

diff --git a/libsbutil/local.mk b/libsbutil/local.mk
index 126c7ce..1cb5de7 100644
--- a/libsbutil/local.mk
+++ b/libsbutil/local.mk
@@ -16,6 +16,7 @@ noinst_LTLIBRARIES += %D%/libsbutil.la
        %D%/environment.c                         \
        %D%/sb_backtrace.c                        \
        %D%/sb_efuncs.c                           \
+       %D%/sb_exists.c                           \
        %D%/sb_gdb.c                              \
        %D%/sb_method.c                           \
        %D%/sb_open.c                             \

diff --git a/libsbutil/sb_exists.c b/libsbutil/sb_exists.c
new file mode 100644
index 0000000..9ec7730
--- /dev/null
+++ b/libsbutil/sb_exists.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2023 Gentoo Authors
+ * Distributed under the terms of the GNU General Public License v2
+ */
+
+#include "headers.h"
+#include "sbutil.h"
+
+/* Wrapper for faccessat to work around buggy behavior on musl */
+int sb_exists(int dirfd, const char *pathname, int flags)
+{
+       struct stat64 buf;
+
+       if (faccessat(dirfd, pathname, F_OK, flags) == 0)
+               return 0;
+
+       /* musl's faccessat gives EINVAL when the kernel does not support
+        * faccessat2 and AT_SYMLINK_NOFOLLOW is set.
+        * https://www.openwall.com/lists/musl/2023/06/19/1 */
+       if (errno != EINVAL)
+               return -1;
+
+       return fstatat64(dirfd, pathname, &buf, flags);
+}

diff --git a/libsbutil/sbutil.h b/libsbutil/sbutil.h
index c146b80..4061dd3 100644
--- a/libsbutil/sbutil.h
+++ b/libsbutil/sbutil.h
@@ -111,6 +111,7 @@ size_t sb_write(int fd, const void *buf, size_t count);
 int sb_close(int fd);
 void sb_close_all_fds(void);
 int sb_copy_file_to_fd(const char *file, int ofd);
+int sb_exists(int dirfd, const char *pathname, int flags);
 
 /* Reliable output */
 __printf(1, 2) void sb_printf(const char *format, ...);

diff --git a/libsbutil/src/file.c b/libsbutil/src/file.c
index 5a361f4..64a6f0e 100644
--- a/libsbutil/src/file.c
+++ b/libsbutil/src/file.c
@@ -15,7 +15,7 @@
 bool
 rc_file_exists (const char *pathname)
 {
-  return faccessat(AT_FDCWD, pathname, F_OK, AT_SYMLINK_NOFOLLOW) == 0;
+  return sb_exists(AT_FDCWD, pathname, AT_SYMLINK_NOFOLLOW) == 0;
 }
 
 bool

Reply via email to