From 584c69e77abb537a7345222648a397a9963c01b7 Mon Sep 17 00:00:00 2001 From: "Timur I. Bakeyev" Date: Sat, 15 Oct 2022 04:02:43 +0200 Subject: [PATCH 28/28] s3:lib:system - add FreeBSD proc_fd_pattern Add support for FreeBSD equivalent of /proc/self/fd through a special fdescfs mount with option "nodup". This filesystem should be mounted either to the private $PIDDIR/fd/ directory or to /dev/fd in order to provide security and performance characteristics similar to Linux. Signed-off-by: Timur I. Bakeyev Adapted for Samba 4.20 by: Andrea venturoli --- --- source3/lib/system.c.orig 2025-06-27 15:05:05 UTC +++ source3/lib/system.c @@ -1047,6 +1047,68 @@ int sys_get_number_of_cores(void) } #endif +static bool freebsd_fdesc_check(const char *pattern) +{ + char fdesc_path[PATH_MAX]; + int fd, fd2; + + fd = open(lp_pid_directory(), O_DIRECTORY); + if (fd == -1) { + DBG_ERR("%s: failed to open pid directory: %s\n", + lp_pid_directory(), strerror(errno)); + return false; + } + + snprintf(fdesc_path, sizeof(fdesc_path), pattern, fd); + + fd2 = open(fdesc_path, O_DIRECTORY); + if (fd2 == -1) { + /* + * Setting O_DIRECTORY on open of fdescfs mount + * without 'nodup' option will fail with ENOTDIR. + */ + if (errno == ENOTDIR) { + DBG_ERR("%s: fdescfs filesystem is not mounted with " + "'nodup' option. This specific mount option is " + "required in order to enable race-free handling " + "of paths.\n" + "See documentation for Samba's New VFS' " + "for more details. The 'nodup' mount option was " + "introduced in FreeBSD 13.\n", fdesc_path); + close(fd); + return false; + } + DBG_ERR("%s: failed to open fdescfs path: %s\n", + fdesc_path, strerror(errno)); + close(fd); + return false; + } + close(fd); + close(fd2); + + return true; +} + +static char* freebsd_pattern(char *buf, size_t bufsize) { + const char** base; + const char* base_dir[] = { + lp_pid_directory(), /* This is a preferred location */ + "/dev", + NULL + }; + + for(base = &base_dir[0]; *base != NULL; base++) { + snprintf(buf, bufsize, "%s/fd/%%lu", *base); + if(freebsd_fdesc_check(buf)) { + return buf; + } + } + return NULL; +} + +static char proc_fd_pattern_buf[PATH_MAX]; +static const char *proc_fd_pattern = NULL; + bool sys_have_proc_fds(void) { static bool checked = false; @@ -1058,8 +1078,12 @@ bool sys_have_proc_fds(void) return have_proc_fds; } - ret = stat("/proc/self/fd/0", &sb); - have_proc_fds = (ret == 0); + if (freebsd_pattern(proc_fd_pattern_buf, sizeof(proc_fd_pattern_buf)) != NULL) { + have_proc_fds = true; + proc_fd_pattern = proc_fd_pattern_buf; + } else + have_proc_fds = false; + checked = true; return have_proc_fds; @@ -1067,10 +1091,18 @@ char *sys_proc_fd_path(int fd, struct sys_proc_fd_path char *sys_proc_fd_path(int fd, struct sys_proc_fd_path_buf *buf) { + bool have_proc_fds = sys_have_proc_fds(); + SMB_ASSERT(have_proc_fds); +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" +#endif int written = - snprintf(buf->buf, sizeof(buf->buf), "/proc/self/fd/%d", fd); - - SMB_ASSERT(sys_have_proc_fds() && (written >= 0)); + snprintf(buf->buf, sizeof(buf->buf), proc_fd_pattern, fd); +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + SMB_ASSERT(written >= 0); return buf->buf; }