From ea7fc12b9c1cabc4da877a94ccd7cedd0ba9c51b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 23 Jun 2026 10:05:37 +1000 Subject: [PATCH] syscall: do_mknod_at must mkfifoat for an operator-path FIFO on non-Linux The operator_path_resolve branch of do_mknod_at() called mknodat() and returned its result directly, without the FIFO/socket fallback that the bare-path do_mknod() and the secure-relpath branch below it both have. mknodat() can make a FIFO only on Linux; on the BSDs/macOS/Solaris it fails with EINVAL, so creating a special file under an operator-supplied path -- e.g. backing up a FIFO into a --backup-dir -- failed there. Retry race-safely with mkfifoat() on the held parent dirfd, and fail a nested socket closed (EOPNOTSUPP) exactly as the secure-relpath path does. --- syscall.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/syscall.c b/syscall.c index 8f0a5764..2336a385 100644 --- a/syscall.c +++ b/syscall.c @@ -1055,6 +1055,19 @@ int do_mknod_at(const char *pathname, mode_t mode, dev_t dev) if (dfd < 0) return -1; ret = mknodat(dfd, bname, mode, dev); + if (ret < 0) { + /* mknodat() can't make a FIFO/socket on the BSDs/macOS/ + * Solaris (EINVAL); retry race-safely on the held dirfd, + * mirroring the secure-relpath path below. Without this a + * FIFO backup to an operator --backup-dir fails there. */ +#ifdef HAVE_MKFIFOAT + if (S_ISFIFO(mode)) + ret = mkfifoat(dfd, bname, mode); + else +#endif + if (S_ISSOCK(mode)) + errno = EOPNOTSUPP; /* no dirfd-relative socket bind */ + } e = errno; close(dfd); errno = e;