Jelajahi Sumber

Kernel+LibC: Implement `setregid(2)`

This copies and adapts the setresgid syscall, following in the footsteps
of setreuid and setresuid.
sin-ack 2 tahun lalu
induk
melakukan
70337f3a4b

+ 1 - 0
Kernel/API/Syscall.h

@@ -163,6 +163,7 @@ enum class NeedsBigProcessLock {
     S(sethostname, NeedsBigProcessLock::No)                 \
     S(setkeymap, NeedsBigProcessLock::No)                   \
     S(setpgid, NeedsBigProcessLock::Yes)                    \
+    S(setregid, NeedsBigProcessLock::No)                    \
     S(setresgid, NeedsBigProcessLock::No)                   \
     S(setresuid, NeedsBigProcessLock::No)                   \
     S(setreuid, NeedsBigProcessLock::No)                    \

+ 1 - 0
Kernel/Process.h

@@ -369,6 +369,7 @@ public:
     ErrorOr<FlatPtr> sys$setgid(GroupID);
     ErrorOr<FlatPtr> sys$setreuid(UserID, UserID);
     ErrorOr<FlatPtr> sys$setresuid(UserID, UserID, UserID);
+    ErrorOr<FlatPtr> sys$setregid(GroupID, GroupID);
     ErrorOr<FlatPtr> sys$setresgid(GroupID, GroupID, GroupID);
     ErrorOr<FlatPtr> sys$alarm(unsigned seconds);
     ErrorOr<FlatPtr> sys$faccessat(Userspace<Syscall::SC_faccessat_params const*>);

+ 34 - 0
Kernel/Syscalls/setuid.cpp

@@ -206,6 +206,40 @@ ErrorOr<FlatPtr> Process::sys$setresuid(UserID new_ruid, UserID new_euid, UserID
     });
 }
 
+ErrorOr<FlatPtr> Process::sys$setregid(GroupID new_rgid, GroupID new_egid)
+{
+    VERIFY_NO_PROCESS_BIG_LOCK(this);
+    TRY(require_promise(Pledge::id));
+
+    return with_mutable_protected_data([&](auto& protected_data) -> ErrorOr<FlatPtr> {
+        auto credentials = this->credentials();
+
+        if (new_rgid == (gid_t)-1)
+            new_rgid = credentials->gid();
+        if (new_egid == (gid_t)-1)
+            new_egid = credentials->egid();
+
+        auto ok = [&credentials](GroupID id) { return id == credentials->gid() || id == credentials->egid() || id == credentials->sgid(); };
+        if (!ok(new_rgid) || !ok(new_egid))
+            return EPERM;
+
+        auto new_credentials = TRY(Credentials::create(
+            credentials->uid(),
+            new_rgid,
+            credentials->euid(),
+            new_egid,
+            credentials->suid(),
+            credentials->sgid(),
+            credentials->extra_gids()));
+
+        if (credentials->egid() != new_egid)
+            protected_data.dumpable = false;
+
+        protected_data.credentials = move(new_credentials);
+        return 0;
+    });
+}
+
 ErrorOr<FlatPtr> Process::sys$setresgid(GroupID new_rgid, GroupID new_egid, GroupID new_sgid)
 {
     VERIFY_NO_PROCESS_BIG_LOCK(this);

+ 6 - 0
Userland/Libraries/LibC/unistd.cpp

@@ -790,6 +790,12 @@ int setresuid(uid_t ruid, uid_t euid, uid_t suid)
     __RETURN_WITH_ERRNO(rc, rc, -1);
 }
 
+int setregid(gid_t rgid, gid_t egid)
+{
+    int rc = syscall(SC_setresgid, rgid, egid);
+    __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);

+ 1 - 0
Userland/Libraries/LibC/unistd.h

@@ -71,6 +71,7 @@ int setuid(uid_t);
 int setgid(gid_t);
 int setreuid(uid_t, uid_t);
 int setresuid(uid_t, uid_t, uid_t);
+int setregid(gid_t, gid_t);
 int setresgid(gid_t, gid_t, gid_t);
 pid_t tcgetpgrp(int fd);
 int tcsetpgrp(int fd, pid_t pgid);