From 23f923bcafe1fc51b083913a455f05efd1f9139e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Sun, 8 Jun 2025 14:13:27 +0200 Subject: [PATCH] libbsd: add closefrom() and close_range() Change-Id: I9c88948d6c4d5a32e3aa06cd696e2ce24c2d298f Reviewed-on: https://review.haiku-os.org/c/haiku/+/9334 Reviewed-by: waddlesplash Tested-by: Commit checker robot --- headers/compatibility/bsd/unistd.h | 3 +++ headers/posix/unistd.h | 2 ++ headers/private/kernel/vfs.h | 1 + headers/private/system/syscalls.h | 1 + src/bin/debug/strace/fcntl.cpp | 15 ++++++++++++ src/libs/bsd/Jamfile | 1 + src/libs/bsd/closefrom.cpp | 26 +++++++++++++++++++++ src/system/kernel/fs/fd.cpp | 37 ++++++++++++++++++++++++++++++ 8 files changed, 86 insertions(+) create mode 100644 src/libs/bsd/closefrom.cpp diff --git a/headers/compatibility/bsd/unistd.h b/headers/compatibility/bsd/unistd.h index 5bc3045954..7cae8159b6 100644 --- a/headers/compatibility/bsd/unistd.h +++ b/headers/compatibility/bsd/unistd.h @@ -28,6 +28,9 @@ char *getusershell(void); int issetugid(void); void setusershell(void); +int closefrom(int lowFd); +int close_range(u_int minFd, u_int maxFd, int flags); + #ifdef __cplusplus } #endif diff --git a/headers/posix/unistd.h b/headers/posix/unistd.h index f02ada8aa9..cef93f48e1 100644 --- a/headers/posix/unistd.h +++ b/headers/posix/unistd.h @@ -327,6 +327,8 @@ # define SEEK_HOLE 4 #endif +#define CLOSE_RANGE_CLOEXEC 0x4 + #ifdef __cplusplus extern "C" { diff --git a/headers/private/kernel/vfs.h b/headers/private/kernel/vfs.h index d7cc2550ed..a07d265598 100644 --- a/headers/private/kernel/vfs.h +++ b/headers/private/kernel/vfs.h @@ -255,6 +255,7 @@ int _user_dup2(int ofd, int nfd, int flags); status_t _user_lock_node(int fd); status_t _user_unlock_node(int fd); status_t _user_preallocate(int fd, off_t offset, off_t length); +status_t _user_close_range(u_int minFd, u_int maxFd, int flags); /* socket user prototypes (implementation in socket.cpp) */ int _user_socket(int family, int type, int protocol); diff --git a/headers/private/system/syscalls.h b/headers/private/system/syscalls.h index 8793ca687e..07988e6449 100644 --- a/headers/private/system/syscalls.h +++ b/headers/private/system/syscalls.h @@ -355,6 +355,7 @@ extern status_t _kern_unlock_node(int fd); extern status_t _kern_get_next_fd_info(team_id team, uint32 *_cookie, struct fd_info *info, size_t infoSize); extern status_t _kern_preallocate(int fd, off_t offset, off_t length); +extern status_t _kern_close_range(u_int minFd, u_int maxFd, int flags); // socket functions extern int _kern_socket(int family, int type, int protocol); diff --git a/src/bin/debug/strace/fcntl.cpp b/src/bin/debug/strace/fcntl.cpp index f61ef56872..d617475586 100644 --- a/src/bin/debug/strace/fcntl.cpp +++ b/src/bin/debug/strace/fcntl.cpp @@ -44,6 +44,13 @@ static const FlagsTypeHandler::FlagInfo kOpenFlagInfos[] = { }; +static const FlagsTypeHandler::FlagInfo kCloseRangeFlagInfos[] = { + FLAG_INFO_ENTRY(CLOSE_RANGE_CLOEXEC), + + { 0, NULL } +}; + + struct fcntl_info { unsigned int index; const char *name; @@ -69,6 +76,7 @@ static const fcntl_info kFcntls[] = { }; static FlagsTypeHandler::FlagsList kOpenFlags; +static FlagsTypeHandler::FlagsList kCloseRangeFlags; static EnumTypeHandler::EnumMap kFcntlNames; static TypeHandlerSelector::SelectMap kFcntlTypeHandlers; @@ -79,6 +87,10 @@ patch_fcntl() kOpenFlags.push_back(kOpenFlagInfos[i]); } + for (int i = 0; kCloseRangeFlagInfos[i].name != NULL; i++) { + kCloseRangeFlags.push_back(kCloseRangeFlagInfos[i]); + } + for (int i = 0; kFcntls[i].name != NULL; i++) { kFcntlNames[kFcntls[i].index] = kFcntls[i].name; if (kFcntls[i].handler != NULL) @@ -90,6 +102,9 @@ patch_fcntl() Syscall *open = get_syscall("_kern_open"); open->GetParameter("openMode")->SetHandler(new FlagsTypeHandler(kOpenFlags)); + Syscall *closeRange = get_syscall("_kern_close_range"); + closeRange->GetParameter("flags")->SetHandler(new FlagsTypeHandler(kCloseRangeFlags)); + Syscall *fcntl = get_syscall("_kern_fcntl"); fcntl->GetParameter("op")->SetHandler(new EnumTypeHandler(kFcntlNames)); fcntl->GetParameter("argument")->SetHandler( diff --git a/src/libs/bsd/Jamfile b/src/libs/bsd/Jamfile index d0dac23f74..de85d7b1ca 100644 --- a/src/libs/bsd/Jamfile +++ b/src/libs/bsd/Jamfile @@ -13,6 +13,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { SharedLibrary [ MultiArchDefaultGristFiles libbsd.so ] : arc4random.c arc4random_uniform.c + closefrom.cpp daemon.c dl_iterate_phdr.c err.c diff --git a/src/libs/bsd/closefrom.cpp b/src/libs/bsd/closefrom.cpp new file mode 100644 index 0000000000..7389ce3ca7 --- /dev/null +++ b/src/libs/bsd/closefrom.cpp @@ -0,0 +1,26 @@ +/* + * Copyright 2025, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include +#include + + +extern "C" int +closefrom(int lowFd) +{ + RETURN_AND_SET_ERRNO(_kern_close_range(lowFd, ~0, 0)); +} + + +extern "C" int +close_range(u_int minFd, u_int maxFd, int flags) +{ + RETURN_AND_SET_ERRNO(_kern_close_range(minFd, maxFd, flags)); +} + diff --git a/src/system/kernel/fs/fd.cpp b/src/system/kernel/fs/fd.cpp index 26ad2c0c21..43c427cac3 100644 --- a/src/system/kernel/fs/fd.cpp +++ b/src/system/kernel/fs/fd.cpp @@ -857,6 +857,27 @@ common_close(int fd, bool kernel) } +static status_t +common_close_range(u_int minFd, u_int maxFd, int flags, bool kernel) +{ + if (maxFd < minFd) + return B_BAD_VALUE; + struct io_context* context = get_current_io_context(kernel); + maxFd = min_c(maxFd, context->table_size - 1); + if ((flags & CLOSE_RANGE_CLOEXEC) == 0) { + for (u_int fd = minFd; fd <= maxFd; fd++) + close_fd_index(context, fd); + } else { + WriteLocker locker(context->lock); + for (u_int fd = minFd; fd <= maxFd; fd++) { + if (context->fds[fd] != NULL) + fd_set_close_on_exec(context, fd, true); + } + } + return B_OK; +} + + status_t user_fd_kernel_ioctl(int fd, uint32 op, void* buffer, size_t length) { @@ -1018,6 +1039,15 @@ _user_close(int fd) } +status_t +_user_close_range(u_int minFd, u_int maxFd, int flags) +{ + if ((flags & ~(CLOSE_RANGE_CLOEXEC)) != 0) + return B_BAD_VALUE; + return common_close_range(minFd, maxFd, flags, false); +} + + int _user_dup(int fd) { @@ -1210,6 +1240,13 @@ _kern_close(int fd) } +status_t +_kern_close_range(u_int minFd, u_int maxFd, int flags) +{ + return common_close_range(minFd, maxFd, flags, true); +} + + int _kern_dup(int fd) {