From: Mike Yuan Date: Tue, 11 Nov 2025 18:04:38 +0000 (+0100) Subject: fd-util: introduce fd_vet_accmode() X-Git-Tag: v259-rc1~83^2~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7cf4f075670a81babf1501f063f6841cc4e866dd;p=thirdparty%2Fsystemd.git fd-util: introduce fd_vet_accmode() Inspired by #39674 --- diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index 74feb8ad4b8..310f5b82b5b 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -960,6 +960,41 @@ int fd_is_opath(int fd) { return FLAGS_SET(r, O_PATH); } +int fd_vet_accmode(int fd, int mode) { + int flags; + + /* Check if fd is opened with desired access mode. + * + * Returns > 0 on strict match, == 0 if opened for both reading and writing (partial match), + * -EPROTOTYPE otherwise. O_PATH fds are always refused with -EBADFD. + * + * Note that while on O_DIRECTORY -EISDIR will be returned, this should not be relied upon as + * the flag might not have been specified when open() was called originally. */ + + assert(fd >= 0); + assert(IN_SET(mode, O_RDONLY, O_WRONLY, O_RDWR)); + + flags = fcntl(fd, F_GETFL); + if (flags < 0) + return -errno; + + if (FLAGS_SET(flags, O_DIRECTORY)) + return -EISDIR; + + if (FLAGS_SET(flags, O_PATH)) + return -EBADFD; + + flags &= O_ACCMODE_STRICT; + + if (flags == mode) + return 1; + + if (flags == O_RDWR) + return 0; + + return -EPROTOTYPE; +} + int fd_verify_safe_flags_full(int fd, int extra_flags) { int flags, unexpected_flags; diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h index 95184c5783a..baa81b6a662 100644 --- a/src/basic/fd-util.h +++ b/src/basic/fd-util.h @@ -151,6 +151,7 @@ int fd_reopen_propagate_append_and_position(int fd, int flags); int fd_reopen_condition(int fd, int flags, int mask, int *ret_new_fd); int fd_is_opath(int fd); +int fd_vet_accmode(int fd, int mode); int fd_verify_safe_flags_full(int fd, int extra_flags); static inline int fd_verify_safe_flags(int fd) {