diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 420dfcd160..c0a308df4c 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -986,9 +986,9 @@ int Process::do_exec(NonnullRefPtr main_program_description, Ve if (!(main_program_description->custody()->mount_flags() & MS_NOSUID)) { if (main_program_metadata.is_setuid()) - m_euid = main_program_metadata.uid; + m_euid = m_suid = main_program_metadata.uid; if (main_program_metadata.is_setgid()) - m_egid = main_program_metadata.gid; + m_egid = m_sgid = main_program_metadata.gid; } Thread::current->set_default_signal_dispositions(); @@ -1386,10 +1386,12 @@ Process* Process::create_kernel_process(Thread*& first_thread, String&& name, vo Process::Process(Thread*& first_thread, const String& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel ring, RefPtr cwd, RefPtr executable, TTY* tty, Process* fork_parent) : m_name(move(name)) , m_pid(allocate_pid()) - , m_uid(uid) - , m_gid(gid) , m_euid(uid) , m_egid(gid) + , m_uid(uid) + , m_gid(gid) + , m_suid(uid) + , m_sgid(gid) , m_ring(ring) , m_executable(move(executable)) , m_cwd(move(cwd)) @@ -2125,23 +2127,147 @@ int Process::sys$killpg(int pgrp, int signum) return do_killpg(pgrp, signum); } +int Process::sys$seteuid(uid_t euid) +{ + REQUIRE_PROMISE(id); + + // This has FreeBSD semantics. + // Linux and Solaris also allow m_euid. + if (euid != m_uid && euid != m_suid && !is_superuser()) + return -EPERM; + + m_euid = euid; + return 0; +} + +int Process::sys$setegid(gid_t egid) +{ + REQUIRE_PROMISE(id); + + // This has FreeBSD semantics. + // Linux and Solaris also allow m_egid. + if (egid != m_gid && egid != m_sgid && !is_superuser()) + return -EPERM; + + m_egid = egid; + return 0; +} + int Process::sys$setuid(uid_t uid) { REQUIRE_PROMISE(id); - if (uid != m_uid && !is_superuser()) + + // Linux and Solaris require real or saved. + // FreeBSD requires real or effective. + if (uid != m_uid && uid != m_euid && !is_superuser()) return -EPERM; + + // Solaris and Linux only set uid and suid if is_superuser(), + // FreeBSD always sets all 3. m_uid = uid; m_euid = uid; + m_suid = uid; return 0; } int Process::sys$setgid(gid_t gid) { REQUIRE_PROMISE(id); - if (gid != m_gid && !is_superuser()) + + // Linux and Solaris require real or saved. + // FreeBSD requires real or effective. + if (gid != m_gid && gid != m_egid && !is_superuser()) return -EPERM; + + // Solaris and Linux only set uid and suid if is_superuser(), + // FreeBSD always sets all 3. m_gid = gid; m_egid = gid; + m_sgid = gid; + return 0; +} + +int Process::sys$setreuid(uid_t ruid, uid_t euid) +{ + REQUIRE_PROMISE(id); + + // This has FreeBSD semantics. + // Linux and Solaris also allow id == m_suid. + auto ok = [this](uid_t id) { return id == (uid_t)-1 || id == m_uid || id == m_euid; }; + if ((!ok(ruid) || !ok(euid)) && !is_superuser()) + return -EPERM; + + if (ruid != (uid_t)-1) + m_uid = ruid; + if (euid != (uid_t)-1) + m_euid = euid; + + if (ruid != (uid_t)-1 || m_euid != m_uid) + m_suid = m_euid; + + return 0; +} + +int Process::sys$setregid(gid_t rgid, gid_t egid) +{ + REQUIRE_PROMISE(id); + + // This has FreeBSD semantics. + // Linux and Solaris also allow id == m_sgid. + auto ok = [this](gid_t id) { return id == (gid_t)-1 || id == m_gid || id == m_egid; }; + if ((!ok(rgid) || !ok(egid)) && !is_superuser()) + return -EPERM; + + if (rgid != (gid_t)-1) + m_gid = rgid; + if (egid != (gid_t)-1) + m_egid = egid; + + if (rgid != (gid_t)-1 || m_egid != m_gid) + m_sgid = m_egid; + + return 0; +} + +int Process::sys$setresuid(uid_t ruid, uid_t euid, uid_t suid) +{ + REQUIRE_PROMISE(id); + + if (ruid == (uid_t)-1) + ruid = m_uid; + if (euid == (uid_t)-1) + euid = m_euid; + if (suid == (uid_t)-1) + suid = m_suid; + + auto ok = [this](uid_t id) { return id == m_uid || id == m_euid || id == m_suid; }; + if ((!ok(ruid) || !ok(euid) || !ok(suid)) && !is_superuser()) + return -EPERM; + + m_uid = ruid; + m_euid = euid; + m_suid = suid; + return 0; +} + +int Process::sys$setresgid(gid_t rgid, gid_t egid, gid_t sgid) +{ + REQUIRE_PROMISE(id); + + if (rgid == (gid_t)-1) + rgid = m_gid; + if (egid == (gid_t)-1) + egid = m_egid; + if (sgid == (gid_t)-1) + sgid = m_sgid; + + auto ok = [this](gid_t id) { return id == m_gid || id == m_egid || id == m_sgid; }; + if ((!ok(rgid) || !ok(egid) || !ok(sgid)) && !is_superuser()) + return -EPERM; + + m_gid = rgid; + m_egid = egid; + m_sgid = sgid; return 0; } @@ -2384,6 +2510,28 @@ pid_t Process::sys$getppid() return m_ppid; } +int Process::sys$getresuid(uid_t* ruid, uid_t* euid, uid_t* suid) +{ + REQUIRE_PROMISE(stdio); + if (!validate_write_typed(ruid) || !validate_write_typed(euid) || !validate_write_typed(suid)) + return -EFAULT; + copy_to_user(ruid, &m_uid); + copy_to_user(euid, &m_euid); + copy_to_user(suid, &m_suid); + return 0; +} + +int Process::sys$getresgid(gid_t* rgid, gid_t* egid, gid_t* sgid) +{ + REQUIRE_PROMISE(stdio); + if (!validate_write_typed(rgid) || !validate_write_typed(egid) || !validate_write_typed(sgid)) + return -EFAULT; + copy_to_user(rgid, &m_gid); + copy_to_user(egid, &m_egid); + copy_to_user(sgid, &m_sgid); + return 0; +} + mode_t Process::sys$umask(mode_t mask) { REQUIRE_PROMISE(stdio); diff --git a/Kernel/Process.h b/Kernel/Process.h index b125dcf522..ffa533d66e 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -142,11 +142,13 @@ public: pid_t pid() const { return m_pid; } pid_t sid() const { return m_sid; } pid_t pgid() const { return m_pgid; } - uid_t uid() const { return m_uid; } - gid_t gid() const { return m_gid; } const FixedArray& extra_gids() const { return m_extra_gids; } uid_t euid() const { return m_euid; } gid_t egid() const { return m_egid; } + uid_t uid() const { return m_uid; } + gid_t gid() const { return m_gid; } + uid_t suid() const { return m_suid; } + gid_t sgid() const { return m_sgid; } pid_t ppid() const { return m_ppid; } pid_t exec_tid() const { return m_exec_tid; } @@ -192,6 +194,8 @@ public: gid_t sys$getegid(); pid_t sys$getpid(); pid_t sys$getppid(); + int sys$getresuid(uid_t*, uid_t*, uid_t*); + int sys$getresgid(gid_t*, gid_t*, gid_t*); mode_t sys$umask(mode_t); int sys$open(const Syscall::SC_open_params*); int sys$close(int fd); @@ -241,8 +245,14 @@ public: int sys$setgroups(ssize_t, const gid_t*); int sys$pipe(int pipefd[2], int flags); int sys$killpg(int pgrp, int sig); - int sys$setgid(gid_t); + int sys$seteuid(uid_t); + int sys$setegid(gid_t); int sys$setuid(uid_t); + int sys$setgid(gid_t); + int sys$setreuid(uid_t, uid_t); + int sys$setregid(gid_t, gid_t); + int sys$setresuid(uid_t, uid_t, uid_t); + int sys$setresgid(gid_t, gid_t, gid_t); unsigned sys$alarm(unsigned seconds); int sys$access(const char* pathname, size_t path_length, int mode); int sys$fcntl(int fd, int cmd, u32 extra_arg); @@ -480,13 +490,16 @@ private: String m_name; pid_t m_pid { 0 }; - uid_t m_uid { 0 }; - gid_t m_gid { 0 }; - uid_t m_euid { 0 }; - gid_t m_egid { 0 }; pid_t m_sid { 0 }; pid_t m_pgid { 0 }; + uid_t m_euid { 0 }; + gid_t m_egid { 0 }; + uid_t m_uid { 0 }; + gid_t m_gid { 0 }; + uid_t m_suid { 0 }; + gid_t m_sgid { 0 }; + pid_t m_exec_tid { 0 }; static const int m_max_open_file_descriptors { FD_SETSIZE }; diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h index 303d84b9b5..e6585879ca 100644 --- a/Kernel/Syscall.h +++ b/Kernel/Syscall.h @@ -54,8 +54,13 @@ namespace Kernel { __ENUMERATE_SYSCALL(kill) \ __ENUMERATE_SYSCALL(getuid) \ __ENUMERATE_SYSCALL(exit) \ + __ENUMERATE_SYSCALL(geteuid) \ + __ENUMERATE_SYSCALL(getegid) \ __ENUMERATE_SYSCALL(getgid) \ __ENUMERATE_SYSCALL(getpid) \ + __ENUMERATE_SYSCALL(getppid) \ + __ENUMERATE_SYSCALL(getresuid) \ + __ENUMERATE_SYSCALL(getresgid) \ __ENUMERATE_SYSCALL(waitid) \ __ENUMERATE_SYSCALL(mmap) \ __ENUMERATE_SYSCALL(munmap) \ @@ -78,12 +83,9 @@ namespace Kernel { __ENUMERATE_SYSCALL(getpgrp) \ __ENUMERATE_SYSCALL(fork) \ __ENUMERATE_SYSCALL(execve) \ - __ENUMERATE_SYSCALL(geteuid) \ - __ENUMERATE_SYSCALL(getegid) \ __ENUMERATE_SYSCALL(dup) \ __ENUMERATE_SYSCALL(dup2) \ __ENUMERATE_SYSCALL(sigaction) \ - __ENUMERATE_SYSCALL(getppid) \ __ENUMERATE_SYSCALL(umask) \ __ENUMERATE_SYSCALL(getgroups) \ __ENUMERATE_SYSCALL(setgroups) \ @@ -92,8 +94,14 @@ namespace Kernel { __ENUMERATE_SYSCALL(sigpending) \ __ENUMERATE_SYSCALL(pipe) \ __ENUMERATE_SYSCALL(killpg) \ + __ENUMERATE_SYSCALL(seteuid) \ + __ENUMERATE_SYSCALL(setegid) \ __ENUMERATE_SYSCALL(setuid) \ __ENUMERATE_SYSCALL(setgid) \ + __ENUMERATE_SYSCALL(setreuid) \ + __ENUMERATE_SYSCALL(setregid) \ + __ENUMERATE_SYSCALL(setresuid) \ + __ENUMERATE_SYSCALL(setresgid) \ __ENUMERATE_SYSCALL(alarm) \ __ENUMERATE_SYSCALL(fstat) \ __ENUMERATE_SYSCALL(access) \ diff --git a/Libraries/LibC/unistd.cpp b/Libraries/LibC/unistd.cpp index dc97b2f2b6..a9ed5e7e69 100644 --- a/Libraries/LibC/unistd.cpp +++ b/Libraries/LibC/unistd.cpp @@ -177,16 +177,6 @@ int execlp(const char* filename, const char* arg0, ...) return execvpe(filename, const_cast(args.data()), environ); } -uid_t getuid() -{ - return syscall(SC_getuid); -} - -gid_t getgid() -{ - return syscall(SC_getgid); -} - uid_t geteuid() { return syscall(SC_geteuid); @@ -197,6 +187,16 @@ gid_t getegid() return syscall(SC_getegid); } +uid_t getuid() +{ + return syscall(SC_getuid); +} + +gid_t getgid() +{ + return syscall(SC_getgid); +} + pid_t getpid() { return syscall(SC_getpid); @@ -207,6 +207,16 @@ pid_t getppid() return syscall(SC_getppid); } +int getresuid(uid_t* ruid, uid_t* euid, uid_t* suid) +{ + return syscall(SC_getresuid, ruid, euid, suid); +} + +int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) +{ + return syscall(SC_getresgid, rgid, egid, sgid); +} + pid_t getsid(pid_t pid) { int rc = syscall(SC_getsid, pid); @@ -457,6 +467,18 @@ unsigned int alarm(unsigned int seconds) return syscall(SC_alarm, seconds); } +int seteuid(uid_t euid) +{ + int rc = syscall(SC_seteuid, euid); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + +int setegid(gid_t egid) +{ + int rc = syscall(SC_setegid, egid); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + int setuid(uid_t uid) { int rc = syscall(SC_setuid, uid); @@ -469,6 +491,30 @@ int setgid(gid_t gid) __RETURN_WITH_ERRNO(rc, rc, -1); } +int setreuid(uid_t ruid, uid_t euid) +{ + int rc = syscall(SC_setreuid, ruid, euid); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + +int setregid(gid_t rgid, gid_t egid) +{ + int rc = syscall(SC_setregid, rgid, egid); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + +int setresuid(uid_t ruid, uid_t euid, uid_t suid) +{ + int rc = syscall(SC_setresuid, ruid, euid, suid); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + +int setresgid(gid_t rgid, gid_t egid, gid_t sgid) +{ + int rc = syscall(SC_setresgid, rgid, egid, sgid); + __RETURN_WITH_ERRNO(rc, rc, -1); +} + int access(const char* pathname, int mode) { if (!pathname) { diff --git a/Libraries/LibC/unistd.h b/Libraries/LibC/unistd.h index 1dfb4801ef..12d1e2c057 100644 --- a/Libraries/LibC/unistd.h +++ b/Libraries/LibC/unistd.h @@ -84,10 +84,18 @@ uid_t getuid(); gid_t getgid(); pid_t getpid(); pid_t getppid(); +int getresuid(uid_t *, uid_t *, uid_t *); +int getresgid(gid_t *, gid_t *, gid_t *); int getgroups(int size, gid_t list[]); int setgroups(size_t, const gid_t*); +int seteuid(uid_t); +int setegid(gid_t); int setuid(uid_t); int setgid(gid_t); +int setreuid(uid_t, uid_t); +int setregid(gid_t, gid_t); +int setresuid(uid_t, uid_t, uid_t); +int setresgid(gid_t, gid_t, gid_t); pid_t tcgetpgrp(int fd); int tcsetpgrp(int fd, pid_t pgid); ssize_t read(int fd, void* buf, size_t count); @@ -157,6 +165,8 @@ enum { #define MS_RDONLY (1 << 4) #define MS_REMOUNT (1 << 5) +#define _POSIX_SAVED_IDS + /* * We aren't fully compliant (don't support policies, and don't have a wide * range of values), but we do have process priorities.