From: Lennart Poettering Date: Mon, 12 Feb 2024 10:23:54 +0000 (+0100) Subject: missing: change our close_range() syscall wrapper to map glibc's X-Git-Tag: v256-rc1~897 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=39d69836ad47788b7a4ec13f8a4145d5118a50a5;p=thirdparty%2Fsystemd.git missing: change our close_range() syscall wrapper to map glibc's So glibc exposes a close_range() syscall wrapper now, but they decided to use "unsigned" as type for the fds. Which is a bit weird, because fds are universally understood to be "int". The kernel internally uses "unsigned", both for close() and for close_range(), but weirdly, userspace didn't fix that for close_range() unlike what they did for close()... Weird. But anyway, let's follow suit, and make our wrapper match glibc's. Fixes #31270 --- diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index 38866ebb782..d2ff456cc7b 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -308,7 +308,7 @@ static int close_all_fds_special_case(const int except[], size_t n_except) { case 0: /* Close everything. Yay! */ - if (close_range(3, -1, 0) >= 0) + if (close_range(3, INT_MAX, 0) >= 0) return 1; if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno)) { @@ -419,7 +419,7 @@ int close_all_fds(const int except[], size_t n_except) { if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */ return 0; - if (close_range(sorted[n_sorted-1] + 1, -1, 0) >= 0) + if (close_range(sorted[n_sorted-1] + 1, INT_MAX, 0) >= 0) return 0; if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h index d795efd8f28..86280771c49 100644 --- a/src/basic/missing_syscall.h +++ b/src/basic/missing_syscall.h @@ -412,23 +412,14 @@ static inline int missing_execveat(int dirfd, const char *pathname, /* ======================================================================= */ #if !HAVE_CLOSE_RANGE -static inline int missing_close_range(int first_fd, int end_fd, unsigned flags) { +static inline int missing_close_range(unsigned first_fd, unsigned end_fd, unsigned flags) { # ifdef __NR_close_range /* Kernel-side the syscall expects fds as unsigned integers (just like close() actually), while - * userspace exclusively uses signed integers for fds. We don't know just yet how glibc is going to - * wrap this syscall, but let's assume it's going to be similar to what they do for close(), - * i.e. make the same unsigned → signed type change from the raw kernel syscall compared to the - * userspace wrapper. There's only one caveat for this: unlike for close() there's the special - * UINT_MAX fd value for the 'end_fd' argument. Let's safely map that to -1 here. And let's refuse - * any other negative values. */ - if ((first_fd < 0) || (end_fd < 0 && end_fd != -1)) { - errno = -EBADF; - return -1; - } - + * userspace exclusively uses signed integers for fds. glibc chose to expose it 1:1 however, hence we + * do so here too, even if we end up passing signed fds to it most of the time. */ return syscall(__NR_close_range, - (unsigned) first_fd, - end_fd == -1 ? UINT_MAX : (unsigned) end_fd, /* Of course, the compiler should figure out that this is the identity mapping IRL */ + first_fd, + end_fd, flags); # else errno = ENOSYS;