diff options
Diffstat (limited to 'src/nested.zig')
| -rw-r--r-- | src/nested.zig | 31 |
1 files changed, 25 insertions, 6 deletions
diff --git a/src/nested.zig b/src/nested.zig index 0db38ad9..16cea6a1 100644 --- a/src/nested.zig +++ b/src/nested.zig @@ -316,6 +316,27 @@ pub fn sendLook(pid: libc.pid_t, path: []const u8, line: usize) bool { return true; } +/// The three things ensureSocketDir has to know about a path, from whichever +/// call the platform actually offers. Darwin has fstatat and no statx; on +/// linux std.c.fstatat is `void` — glibc hides it behind a versioned symbol +/// std cannot name — so linux asks statx for the same three fields. Both +/// spellings refuse to follow a symlink, which is the point of asking. +const DirFacts = struct { mode: u32, uid: libc.uid_t }; + +fn statNoFollow(path: [:0]const u8) ?DirFacts { + if (comptime darwin) { + var st: libc.Stat = undefined; + if (libc.fstatat(libc.AT.FDCWD, path, &st, libc.AT.SYMLINK_NOFOLLOW) != 0) return null; + return .{ .mode = st.mode, .uid = st.uid }; + } else { + const linux = std.os.linux; + var stx: linux.Statx = undefined; + const want: linux.STATX = .{ .TYPE = true, .MODE = true, .UID = true }; + if (libc.statx(linux.AT.FDCWD, path, linux.AT.SYMLINK_NOFOLLOW, want, &stx) != 0) return null; + return .{ .mode = stx.mode, .uid = stx.uid }; + } +} + /// Create the socket directory if it is missing and refuse it unless it is a /// directory WE own with nothing granted to group or other. A planted path is /// the whole attack on a socket that runs commands, and $XDG_RUNTIME_DIR @@ -334,14 +355,12 @@ fn ensureSocketDir(dir: [:0]const u8) bool { partial[i] = '/'; } _ = libc.mkdir(dir, 0o700); - // fstatat rather than statx: the same three answers, on both platforms, - // and not following the symlink is the point — one where the directory - // should be is exactly the plant this guards against. - var st: libc.Stat = undefined; - if (libc.fstatat(libc.AT.FDCWD, dir, &st, libc.AT.SYMLINK_NOFOLLOW) != 0) return false; + // A symlink where the directory should be is exactly the plant this + // guards against, so the stat above it does not follow one. + const st = statNoFollow(dir) orelse return false; const IFMT: u32 = 0o170000; const IFDIR: u32 = 0o040000; - if (@as(u32, st.mode) & IFMT != IFDIR) return false; + if (st.mode & IFMT != IFDIR) return false; if (st.uid != libc.getuid()) return false; return st.mode & 0o077 == 0; } |
