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
This commit is contained in:
+2
-2
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user