From a64a544e485cade9d9d7e9ddbc918ad48afa69c2 Mon Sep 17 00:00:00 2001 From: Rui Abreu Date: Sun, 23 Aug 2026 18:39:35 +0100 Subject: [PATCH 1/2] Apply worker file ownership and mode via an open descriptor setup_permissions() opens each entry with O_NOFOLLOW, confirms via fstat that it is still the same object fts_read() classified (matching device and inode), and uses fchown/fchmod on that descriptor instead of lchown/ chmod by pathname. Co-Authored-By: Claude Opus 4.8 --- .../worker-launcher/impl/worker-launcher.c | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/storm-core/src/native/worker-launcher/impl/worker-launcher.c b/storm-core/src/native/worker-launcher/impl/worker-launcher.c index 43b736ade55..19267c72b86 100644 --- a/storm-core/src/native/worker-launcher/impl/worker-launcher.c +++ b/storm-core/src/native/worker-launcher/impl/worker-launcher.c @@ -505,12 +505,41 @@ static int copy_file(int input, const char* in_filename, * If setgid_on_dir is FALSE, don't set sticky bit on group permission on the directory. */ static int setup_permissions(FTSENT* entry, uid_t euser, int user_write, boolean setgid_on_dir) { - if (lchown(entry->fts_path, euser, launcher_gid) != 0) { + mode_t mode = entry->fts_statp->st_mode; + int open_flags = O_RDONLY | O_NOFOLLOW | O_CLOEXEC; + if ((mode & S_IFDIR) == S_IFDIR) { + open_flags = open_flags | O_DIRECTORY; + } + // Open the entry without following symlinks and apply the ownership and + // mode changes to that descriptor (fchown/fchmod) rather than by pathname, + // after confirming via fstat that it is still the same object fts_read() + // classified (same device and inode). + int fd = open(entry->fts_accpath, open_flags); + if (fd == -1) { fprintf(ERRORFILE, "ERROR: Failure to exec app initialization process - %s, fts_path=%s\n", strerror(errno), entry->fts_path); return -1; } - mode_t mode = entry->fts_statp->st_mode; + struct stat fd_stat; + if (fstat(fd, &fd_stat) != 0) { + fprintf(ERRORFILE, "ERROR: Failure to exec app initialization process - %s, fts_path=%s\n", + strerror(errno), entry->fts_path); + close(fd); + return -1; + } + if (fd_stat.st_dev != entry->fts_statp->st_dev + || fd_stat.st_ino != entry->fts_statp->st_ino) { + fprintf(ERRORFILE, "ERROR: Directory entry changed during the walk, not modifying it, fts_path=%s\n", + entry->fts_path); + close(fd); + return -1; + } + if (fchown(fd, euser, launcher_gid) != 0) { + fprintf(ERRORFILE, "ERROR: Failure to exec app initialization process - %s, fts_path=%s\n", + strerror(errno), entry->fts_path); + close(fd); + return -1; + } // Preserve user read and execute and set group read and write. mode_t new_mode = (mode & (S_IRUSR | S_IXUSR)) | S_IRGRP | S_IWGRP; if (user_write) { @@ -523,11 +552,13 @@ static int setup_permissions(FTSENT* entry, uid_t euser, int user_write, boolean new_mode = new_mode | S_ISGID; } } - if (chmod(entry->fts_path, new_mode) != 0) { + if (fchmod(fd, new_mode) != 0) { fprintf(ERRORFILE, "ERROR: Failure to exec app initialization process - %s, fts_path=%s\n", strerror(errno), entry->fts_path); + close(fd); return -1; } + close(fd); return 0; } From 9f5b41ac11e1f35dfb8ef0a60063a25532e99ce2 Mon Sep 17 00:00:00 2001 From: Rui Abreu Date: Mon, 24 Aug 2026 10:12:04 +0100 Subject: [PATCH 2/2] Open worker tree entries with O_NONBLOCK to avoid blocking on a swapped FIFO O_NOFOLLOW rejects a symlink but not a FIFO, so if an entry is replaced by a FIFO between fts_read() classifying it and the open, open(O_RDONLY) would block the launcher. O_NONBLOCK avoids that; it is a no-op for regular files and directories, and the fstat device/inode check still rejects the swapped object. Co-Authored-By: Claude Opus 4.8 --- storm-core/src/native/worker-launcher/impl/worker-launcher.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/storm-core/src/native/worker-launcher/impl/worker-launcher.c b/storm-core/src/native/worker-launcher/impl/worker-launcher.c index 19267c72b86..e07495c2fb7 100644 --- a/storm-core/src/native/worker-launcher/impl/worker-launcher.c +++ b/storm-core/src/native/worker-launcher/impl/worker-launcher.c @@ -506,7 +506,10 @@ static int copy_file(int input, const char* in_filename, */ static int setup_permissions(FTSENT* entry, uid_t euser, int user_write, boolean setgid_on_dir) { mode_t mode = entry->fts_statp->st_mode; - int open_flags = O_RDONLY | O_NOFOLLOW | O_CLOEXEC; + // O_NONBLOCK keeps the open from blocking if the entry has been replaced by a + // FIFO between fts_read() classifying it and this open; it has no effect on + // regular files or directories, and fchown/fchmod on the descriptor still work. + int open_flags = O_RDONLY | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK; if ((mode & S_IFDIR) == S_IFDIR) { open_flags = open_flags | O_DIRECTORY; }