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.
This commit is contained in:
Andrew Tridgell committed 2026-06-23 11:56:51 +10:00
1 parent 4da4a7ce1e
commit ea7fc12b9c
1 file changed
+13
+13
View File
@@ -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;