From e8a2aecd2f3ed13d7b9fb74248d455752de19840 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Thu, 3 Sep 2020 15:08:37 +0200 Subject: [PATCH 1/3] std: fix linux uid_t, use uid_t/gid_t in std.os - correct uid_t from i32 to u32 on linux - define uid_t and gid_t for OSes missing definitions - use uid_t/gid_t instead of plain u32s throughout std.os --- lib/std/child_process.zig | 4 +-- lib/std/os.zig | 8 ++--- lib/std/os/bits/darwin.zig | 8 +++-- lib/std/os/bits/dragonfly.zig | 13 ++++++-- lib/std/os/bits/freebsd.zig | 8 +++-- lib/std/os/bits/linux.zig | 8 ++--- lib/std/os/bits/linux/x86_64.zig | 5 +-- lib/std/os/linux.zig | 52 ++++++++++++++++---------------- lib/std/process.zig | 8 ++--- 9 files changed, 65 insertions(+), 49 deletions(-) diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig index 287fc3e7cd..c64fefbc63 100644 --- a/lib/std/child_process.zig +++ b/lib/std/child_process.zig @@ -44,10 +44,10 @@ pub const ChildProcess = struct { stderr_behavior: StdIo, /// Set to change the user id when spawning the child process. - uid: if (builtin.os.tag == .windows) void else ?u32, + uid: if (builtin.os.tag == .windows or builtin.os.tag == .wasi) void else ?os.uid_t, /// Set to change the group id when spawning the child process. - gid: if (builtin.os.tag == .windows) void else ?u32, + gid: if (builtin.os.tag == .windows or builtin.os.tag == .wasi) void else ?os.gid_t, /// Set to change the current working directory when spawning the child process. cwd: ?[]const u8, diff --git a/lib/std/os.zig b/lib/std/os.zig index e8431c386b..3574468a38 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2518,7 +2518,7 @@ pub const SetIdError = error{ PermissionDenied, } || UnexpectedError; -pub fn setuid(uid: u32) SetIdError!void { +pub fn setuid(uid: uid_t) SetIdError!void { switch (errno(system.setuid(uid))) { 0 => return, EAGAIN => return error.ResourceLimitReached, @@ -2528,7 +2528,7 @@ pub fn setuid(uid: u32) SetIdError!void { } } -pub fn setreuid(ruid: u32, euid: u32) SetIdError!void { +pub fn setreuid(ruid: uid_t, euid: uid_t) SetIdError!void { switch (errno(system.setreuid(ruid, euid))) { 0 => return, EAGAIN => return error.ResourceLimitReached, @@ -2538,7 +2538,7 @@ pub fn setreuid(ruid: u32, euid: u32) SetIdError!void { } } -pub fn setgid(gid: u32) SetIdError!void { +pub fn setgid(gid: gid_t) SetIdError!void { switch (errno(system.setgid(gid))) { 0 => return, EAGAIN => return error.ResourceLimitReached, @@ -2548,7 +2548,7 @@ pub fn setgid(gid: u32) SetIdError!void { } } -pub fn setregid(rgid: u32, egid: u32) SetIdError!void { +pub fn setregid(rgid: gid_t, egid: gid_t) SetIdError!void { switch (errno(system.setregid(rgid, egid))) { 0 => return, EAGAIN => return error.ResourceLimitReached, diff --git a/lib/std/os/bits/darwin.zig b/lib/std/os/bits/darwin.zig index 375127f278..ce73d2a6dc 100644 --- a/lib/std/os/bits/darwin.zig +++ b/lib/std/os/bits/darwin.zig @@ -7,9 +7,13 @@ const std = @import("../../std.zig"); const assert = std.debug.assert; const maxInt = std.math.maxInt; +// See: https://opensource.apple.com/source/xnu/xnu-6153.141.1/bsd/sys/_types.h.auto.html +// TODO: audit mode_t/pid_t, should likely be u16/i32 pub const fd_t = c_int; pub const pid_t = c_int; pub const mode_t = c_uint; +pub const uid_t = u32; +pub const gid_t = u32; pub const in_port_t = u16; pub const sa_family_t = u8; @@ -79,8 +83,8 @@ pub const Stat = extern struct { mode: u16, nlink: u16, ino: ino_t, - uid: u32, - gid: u32, + uid: uid_t, + gid: gid_t, rdev: i32, atimesec: isize, atimensec: isize, diff --git a/lib/std/os/bits/dragonfly.zig b/lib/std/os/bits/dragonfly.zig index 8b6d6be212..1412aa5c41 100644 --- a/lib/std/os/bits/dragonfly.zig +++ b/lib/std/os/bits/dragonfly.zig @@ -9,10 +9,17 @@ const maxInt = std.math.maxInt; pub fn S_ISCHR(m: u32) bool { return m & S_IFMT == S_IFCHR; } + +// See: +// - https://gitweb.dragonflybsd.org/dragonfly.git/blob/HEAD:/include/unistd.h +// - https://gitweb.dragonflybsd.org/dragonfly.git/blob/HEAD:/sys/sys/types.h +// TODO: mode_t should probably be changed to a u16, audit pid_t/off_t as well pub const fd_t = c_int; pub const pid_t = c_int; pub const off_t = c_long; pub const mode_t = c_uint; +pub const uid_t = u32; +pub const gid_t = u32; pub const ENOTSUP = EOPNOTSUPP; pub const EWOULDBLOCK = EAGAIN; @@ -151,8 +158,8 @@ pub const Stat = extern struct { dev: c_uint, mode: c_ushort, padding1: u16, - uid: c_uint, - gid: c_uint, + uid: uid_t, + gid: gid_t, rdev: c_uint, atim: timespec, mtim: timespec, @@ -511,7 +518,7 @@ pub const siginfo_t = extern struct { si_errno: c_int, si_code: c_int, si_pid: c_int, - si_uid: c_uint, + si_uid: uid_t, si_status: c_int, si_addr: ?*c_void, si_value: union_sigval, diff --git a/lib/std/os/bits/freebsd.zig b/lib/std/os/bits/freebsd.zig index 22edf4b9d1..32936f7515 100644 --- a/lib/std/os/bits/freebsd.zig +++ b/lib/std/os/bits/freebsd.zig @@ -6,8 +6,12 @@ const std = @import("../../std.zig"); const maxInt = std.math.maxInt; +// See https://svnweb.freebsd.org/base/head/sys/sys/_types.h?view=co +// TODO: audit pid_t/mode_t. They should likely be i32 and u16, respectively pub const fd_t = c_int; pub const pid_t = c_int; +pub const uid_t = u32; +pub const gid_t = u32; pub const mode_t = c_uint; pub const socklen_t = u32; @@ -128,8 +132,8 @@ pub const Stat = extern struct { mode: u16, __pad0: u16, - uid: u32, - gid: u32, + uid: uid_t, + gid: gid_t, __pad1: u32, rdev: u64, diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index 1327eaa330..1e12a278f3 100644 --- a/lib/std/os/bits/linux.zig +++ b/lib/std/os/bits/linux.zig @@ -29,7 +29,7 @@ const is_mips = builtin.arch.isMIPS(); pub const pid_t = i32; pub const fd_t = i32; -pub const uid_t = i32; +pub const uid_t = u32; pub const gid_t = u32; pub const clock_t = isize; @@ -853,7 +853,7 @@ pub const signalfd_siginfo = extern struct { errno: i32, code: i32, pid: u32, - uid: u32, + uid: uid_t, fd: i32, tid: u32, band: u32, @@ -1491,10 +1491,10 @@ pub const Statx = extern struct { nlink: u32, /// User ID of owner - uid: u32, + uid: uid_t, /// Group ID of owner - gid: u32, + gid: gid_t, /// File type and mode mode: u16, diff --git a/lib/std/os/bits/linux/x86_64.zig b/lib/std/os/bits/linux/x86_64.zig index 0800feeddf..0f01c40813 100644 --- a/lib/std/os/bits/linux/x86_64.zig +++ b/lib/std/os/bits/linux/x86_64.zig @@ -7,6 +7,7 @@ const std = @import("../../../std.zig"); const pid_t = linux.pid_t; const uid_t = linux.uid_t; +const gid_t = linux.gid_t; const clock_t = linux.clock_t; const stack_t = linux.stack_t; const sigset_t = linux.sigset_t; @@ -523,8 +524,8 @@ pub const Stat = extern struct { nlink: usize, mode: u32, - uid: u32, - gid: u32, + uid: uid_t, + gid: gid_t, __pad0: u32, rdev: u64, size: off_t, diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 13094b3a3a..5e2a554018 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -655,7 +655,7 @@ pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize { return syscall2(.nanosleep, @ptrToInt(req), @ptrToInt(rem)); } -pub fn setuid(uid: u32) usize { +pub fn setuid(uid: uid_t) usize { if (@hasField(SYS, "setuid32")) { return syscall1(.setuid32, uid); } else { @@ -663,7 +663,7 @@ pub fn setuid(uid: u32) usize { } } -pub fn setgid(gid: u32) usize { +pub fn setgid(gid: gid_t) usize { if (@hasField(SYS, "setgid32")) { return syscall1(.setgid32, gid); } else { @@ -671,7 +671,7 @@ pub fn setgid(gid: u32) usize { } } -pub fn setreuid(ruid: u32, euid: u32) usize { +pub fn setreuid(ruid: uid_t, euid: uid_t) usize { if (@hasField(SYS, "setreuid32")) { return syscall2(.setreuid32, ruid, euid); } else { @@ -679,7 +679,7 @@ pub fn setreuid(ruid: u32, euid: u32) usize { } } -pub fn setregid(rgid: u32, egid: u32) usize { +pub fn setregid(rgid: gid_t, egid: gid_t) usize { if (@hasField(SYS, "setregid32")) { return syscall2(.setregid32, rgid, egid); } else { @@ -687,47 +687,47 @@ pub fn setregid(rgid: u32, egid: u32) usize { } } -pub fn getuid() u32 { +pub fn getuid() uid_t { if (@hasField(SYS, "getuid32")) { - return @as(u32, syscall0(.getuid32)); + return @as(uid_t, syscall0(.getuid32)); } else { - return @as(u32, syscall0(.getuid)); + return @as(uid_t, syscall0(.getuid)); } } -pub fn getgid() u32 { +pub fn getgid() gid_t { if (@hasField(SYS, "getgid32")) { - return @as(u32, syscall0(.getgid32)); + return @as(gid_t, syscall0(.getgid32)); } else { - return @as(u32, syscall0(.getgid)); + return @as(gid_t, syscall0(.getgid)); } } -pub fn geteuid() u32 { +pub fn geteuid() uid_t { if (@hasField(SYS, "geteuid32")) { - return @as(u32, syscall0(.geteuid32)); + return @as(uid_t, syscall0(.geteuid32)); } else { - return @as(u32, syscall0(.geteuid)); + return @as(uid_t, syscall0(.geteuid)); } } -pub fn getegid() u32 { +pub fn getegid() gid_t { if (@hasField(SYS, "getegid32")) { - return @as(u32, syscall0(.getegid32)); + return @as(gid_t, syscall0(.getegid32)); } else { - return @as(u32, syscall0(.getegid)); + return @as(gid_t, syscall0(.getegid)); } } -pub fn seteuid(euid: u32) usize { - return setreuid(std.math.maxInt(u32), euid); +pub fn seteuid(euid: uid_t) usize { + return setresuid(std.math.maxInt(uid_t), euid); } -pub fn setegid(egid: u32) usize { - return setregid(std.math.maxInt(u32), egid); +pub fn setegid(egid: gid_t) usize { + return setregid(std.math.maxInt(gid_t), egid); } -pub fn getresuid(ruid: *u32, euid: *u32, suid: *u32) usize { +pub fn getresuid(ruid: *uid_t, euid: *uid_t, suid: *uid_t) usize { if (@hasField(SYS, "getresuid32")) { return syscall3(.getresuid32, @ptrToInt(ruid), @ptrToInt(euid), @ptrToInt(suid)); } else { @@ -735,7 +735,7 @@ pub fn getresuid(ruid: *u32, euid: *u32, suid: *u32) usize { } } -pub fn getresgid(rgid: *u32, egid: *u32, sgid: *u32) usize { +pub fn getresgid(rgid: *gid_t, egid: *gid_t, sgid: *gid_t) usize { if (@hasField(SYS, "getresgid32")) { return syscall3(.getresgid32, @ptrToInt(rgid), @ptrToInt(egid), @ptrToInt(sgid)); } else { @@ -743,7 +743,7 @@ pub fn getresgid(rgid: *u32, egid: *u32, sgid: *u32) usize { } } -pub fn setresuid(ruid: u32, euid: u32, suid: u32) usize { +pub fn setresuid(ruid: uid_t, euid: uid_t, suid: uid_t) usize { if (@hasField(SYS, "setresuid32")) { return syscall3(.setresuid32, ruid, euid, suid); } else { @@ -751,7 +751,7 @@ pub fn setresuid(ruid: u32, euid: u32, suid: u32) usize { } } -pub fn setresgid(rgid: u32, egid: u32, sgid: u32) usize { +pub fn setresgid(rgid: gid_t, egid: gid_t, sgid: gid_t) usize { if (@hasField(SYS, "setresgid32")) { return syscall3(.setresgid32, rgid, egid, sgid); } else { @@ -759,7 +759,7 @@ pub fn setresgid(rgid: u32, egid: u32, sgid: u32) usize { } } -pub fn getgroups(size: usize, list: *u32) usize { +pub fn getgroups(size: usize, list: *gid_t) usize { if (@hasField(SYS, "getgroups32")) { return syscall2(.getgroups32, size, @ptrToInt(list)); } else { @@ -767,7 +767,7 @@ pub fn getgroups(size: usize, list: *u32) usize { } } -pub fn setgroups(size: usize, list: *const u32) usize { +pub fn setgroups(size: usize, list: *const gid_t) usize { if (@hasField(SYS, "setgroups32")) { return syscall2(.setgroups32, size, @ptrToInt(list)); } else { diff --git a/lib/std/process.zig b/lib/std/process.zig index 69befa2fc8..9cb571714c 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -578,8 +578,8 @@ fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []cons } pub const UserInfo = struct { - uid: u32, - gid: u32, + uid: os.uid_t, + gid: os.gid_t, }; /// POSIX function which gets a uid from username. @@ -607,8 +607,8 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo { var buf: [std.mem.page_size]u8 = undefined; var name_index: usize = 0; var state = State.Start; - var uid: u32 = 0; - var gid: u32 = 0; + var uid: os.uid_t = 0; + var gid: os.gid_t = 0; while (true) { const amt_read = try reader.read(buf[0..]); From 01a365f1b008fc1546f99c339dbae99521c169cd Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Thu, 3 Sep 2020 15:16:26 +0200 Subject: [PATCH 2/3] std: ensure seteuid/setegid do not change saved id --- lib/std/os/linux.zig | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 5e2a554018..3fc8006d06 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -720,11 +720,25 @@ pub fn getegid() gid_t { } pub fn seteuid(euid: uid_t) usize { - return setresuid(std.math.maxInt(uid_t), euid); + // We use setresuid here instead of setreuid to ensure that the saved uid + // is not changed. This is what musl and recent glibc versions do as well. + // + // The setresuid(2) man page says that if -1 is passed the corresponding + // id will not be changed. Since uid_t is unsigned, this wraps around to the + // max value in C. + comptime assert(@typeInfo(uid_t) == .Int and !@typeInfo(uid_t).Int.is_signed); + return setresuid(std.math.maxInt(uid_t), euid, std.math.maxInt(uid_t)); } pub fn setegid(egid: gid_t) usize { - return setregid(std.math.maxInt(gid_t), egid); + // We use setresgid here instead of setregid to ensure that the saved uid + // is not changed. This is what musl and recent glibc versions do as well. + // + // The setresgid(2) man page says that if -1 is passed the corresponding + // id will not be changed. Since gid_t is unsigned, this wraps around to the + // max value in C. + comptime assert(@typeInfo(uid_t) == .Int and !@typeInfo(uid_t).Int.is_signed); + return setresgid(std.math.maxInt(gid_t), egid, std.math.maxInt(gid_t)); } pub fn getresuid(ruid: *uid_t, euid: *uid_t, suid: *uid_t) usize { From d0d6647fdbfbe1a5764c2624e46eee35052d0da6 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Thu, 3 Sep 2020 15:22:43 +0200 Subject: [PATCH 3/3] std: add seteuid/setegid to std.os Currently these are only implemented for linux. --- lib/std/os.zig | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/lib/std/os.zig b/lib/std/os.zig index 3574468a38..8b923989e6 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2512,11 +2512,12 @@ pub fn readlinkatZ(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) Read } } -pub const SetIdError = error{ - ResourceLimitReached, +pub const SetEidError = error{ InvalidUserId, PermissionDenied, -} || UnexpectedError; +}; + +pub const SetIdError = error{ResourceLimitReached} || SetEidError || UnexpectedError; pub fn setuid(uid: uid_t) SetIdError!void { switch (errno(system.setuid(uid))) { @@ -2528,6 +2529,15 @@ pub fn setuid(uid: uid_t) SetIdError!void { } } +pub fn seteuid(uid: uid_t) SetEidError!void { + switch (errno(system.seteuid(uid))) { + 0 => return, + EINVAL => return error.InvalidUserId, + EPERM => return error.PermissionDenied, + else => |err| return unexpectedErrno(err), + } +} + pub fn setreuid(ruid: uid_t, euid: uid_t) SetIdError!void { switch (errno(system.setreuid(ruid, euid))) { 0 => return, @@ -2548,6 +2558,15 @@ pub fn setgid(gid: gid_t) SetIdError!void { } } +pub fn setegid(uid: uid_t) SetEidError!void { + switch (errno(system.setegid(uid))) { + 0 => return, + EINVAL => return error.InvalidUserId, + EPERM => return error.PermissionDenied, + else => |err| return unexpectedErrno(err), + } +} + pub fn setregid(rgid: gid_t, egid: gid_t) SetIdError!void { switch (errno(system.setregid(rgid, egid))) { 0 => return,