mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 16:37:35 +00:00
Kernel+LibC: Implement seteuid() and friends!
Add seteuid()/setegid() under _POSIX_SAVED_IDS semantics, which also requires adding suid and sgid to Process, and changing setuid()/setgid() to honor these semantics. The exact semantics aren't specified by POSIX and differ between different Unix implementations. This patch makes serenity follow FreeBSD. The 2002 USENIX paper "Setuid Demystified" explains the differences well. In addition to seteuid() and setegid() this also adds setreuid()/setregid() and setresuid()/setresgid(), and the accessors getresuid()/getresgid(). Also reorder uid/euid functions so that they are the same order everywhere (namely, the order that geteuid()/getuid() already have).
This commit is contained in:
parent
0001bbf182
commit
a38754d9f2
5 changed files with 251 additions and 26 deletions
|
@ -986,9 +986,9 @@ int Process::do_exec(NonnullRefPtr<FileDescription> 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<Custody> cwd, RefPtr<Custody> 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);
|
||||
|
|
|
@ -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<gid_t>& 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 };
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -177,16 +177,6 @@ int execlp(const char* filename, const char* arg0, ...)
|
|||
return execvpe(filename, const_cast<char* const*>(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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue