glibc 2.34 adds a closefrom() function call to close a range of file descriptors. This one is problematic for us since pseudo can have its own fds open in the close range.
To handle this we add a specific client side op, OP_CLOSEFROM, similar to OP_CLOSE which closes the fds in the range which aren't pseudo fds. This means manually closing some of the fds ourselves and then modifying the call to closefrom for the rest. Not pretty but I'm struggling to see a better way. It does mean msg/result is used in a new case to let the caller know which fds to close as the range needs to change. This is allowed after the previous static change. Signed-off-by: Richard Purdie <[email protected]> --- enums/op.in | 1 + ports/linux/guts/closefrom.c | 15 +++++++++++ ports/linux/wrapfuncs.in | 1 + pseudo_client.c | 48 ++++++++++++++++++++++++++++++++++-- 4 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 ports/linux/guts/closefrom.c diff --git a/enums/op.in b/enums/op.in index 61ee666..5b5e21b 100644 --- a/enums/op.in +++ b/enums/op.in @@ -27,3 +27,4 @@ remove-xattr, 1 set-xattr, 0 create-xattr, 1 replace-xattr, 1 +closefrom, 0 diff --git a/ports/linux/guts/closefrom.c b/ports/linux/guts/closefrom.c new file mode 100644 index 0000000..35df71e --- /dev/null +++ b/ports/linux/guts/closefrom.c @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2021 Richard Purdie + * + * SPDX-License-Identifier: LGPL-2.1-only + * + * void closefrom(int fd) + */ + pseudo_msg_t *msg; + /* this cleans up internal tables, and shouldn't make it to the server. Avoids pseudo's internal fds */ + msg = pseudo_client_op(OP_CLOSEFROM, 0, fd, -1, 0, 0); + real_closefrom(msg->fd); + +/* return; + * } + */ diff --git a/ports/linux/wrapfuncs.in b/ports/linux/wrapfuncs.in index e978367..793f5d8 100644 --- a/ports/linux/wrapfuncs.in +++ b/ports/linux/wrapfuncs.in @@ -62,3 +62,4 @@ long syscall(long nr, ...); /* hand_wrapped=1 */ int renameat2(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, unsigned int flags); /* flags=AT_SYMLINK_NOFOLLOW */ int prctl(int option, ...); /* hand_wrapped=1 */ int close_range(unsigned int lowfd, unsigned int maxfd, int flags); +void closefrom(int fd); diff --git a/pseudo_client.c b/pseudo_client.c index 546bdb1..a03d6b1 100644 --- a/pseudo_client.c +++ b/pseudo_client.c @@ -983,6 +983,23 @@ pseudo_client_close(int fd) { } } +static void +pseudo_client_closefrom(int fd) { + int i; + if (fd < 0 || fd >= nfds) + return; + + for (i = fd; i < nfds; ++i) { + free(fd_paths[i]); + fd_paths[i] = 0; + + if (i < linked_nfds) { + free(linked_fd_paths[i]); + linked_fd_paths[i] = 0; + } + } +} + /* spawn server */ static int client_spawn_server(void) { @@ -1600,6 +1617,7 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path static char *alloced_path = 0; static size_t alloced_len = 0; int strip_slash; + int startfd, i; #ifdef PSEUDO_PROFILING struct timeval tv1_op, tv2_op; @@ -1627,7 +1645,7 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path } } - if (op != OP_CHROOT && op != OP_CHDIR && op != OP_CLOSE && op != OP_DUP + if (op != OP_CHROOT && op != OP_CHDIR && op != OP_CLOSE && op != OP_CLOSEFROM && op != OP_DUP && pseudo_client_ignore_path_chroot(path, 0)) { if (op == OP_OPEN) { /* Sanitise the path to have no trailing slash as this is convention in the database */ @@ -1900,6 +1918,32 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path case OP_EXEC: do_request = pseudo_client_logging; break; + case OP_CLOSEFROM: + /* no request needed */ + startfd = fd; + if (pseudo_util_debug_fd > startfd) + startfd = pseudo_util_debug_fd + 1; + if (pseudo_localstate_dir_fd > startfd) + startfd = pseudo_localstate_dir_fd + 1; + if (pseudo_pwd_fd > startfd) + startfd = pseudo_pwd_fd + 1; + if (pseudo_grp_fd > startfd) + startfd = pseudo_grp_fd + 1; + if (connect_fd > startfd) + startfd = connect_fd + 1; + for (i = fd; i < startfd; ++i) { + if (i == pseudo_util_debug_fd || i == pseudo_localstate_dir_fd || i == pseudo_pwd_fd || + i == pseudo_grp_fd || i == connect_fd) + continue; + pseudo_client_close(i); + close(i); + } + pseudo_client_closefrom(startfd); + /* tell the caller to close from startfd instead of fd */ + result = &msg; + msg.fd = startfd; + do_request = 0; + break; case OP_CLOSE: /* no request needed */ if (fd >= 0) { @@ -1982,7 +2026,7 @@ pseudo_client_op(pseudo_op_t op, int access, int fd, int dirfd, const char *path break; } /* result can only be set when PSEUDO_XATTRDB resulted in a - * successful store to or read from the local database. + * successful store to or read from the local database or for OP_CLOSEFROM. */ if (do_request && !result) { #ifdef PSEUDO_PROFILING -- 2.32.0
-=-=-=-=-=-=-=-=-=-=-=- Links: You receive all messages sent to this group. View/Reply Online (#155860): https://lists.openembedded.org/g/openembedded-core/message/155860 Mute This Topic: https://lists.openembedded.org/mt/85487320/21656 Group Owner: [email protected] Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub [[email protected]] -=-=-=-=-=-=-=-=-=-=-=-
