summaryrefslogtreecommitdiff
path: root/src/nested.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/nested.zig')
-rw-r--r--src/nested.zig31
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;
}