diff --git a/headers/posix/unistd.h b/headers/posix/unistd.h index d7ab43d07d..8128b5a357 100644 --- a/headers/posix/unistd.h +++ b/headers/posix/unistd.h @@ -467,6 +467,8 @@ extern gid_t getegid(void); extern uid_t geteuid(void); extern gid_t getgid(void); extern uid_t getuid(void); +extern int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); +extern int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); extern int setgid(gid_t gid); extern int setuid(uid_t uid); @@ -474,6 +476,8 @@ extern int setegid(gid_t gid); extern int seteuid(uid_t uid); extern int setregid(gid_t rgid, gid_t egid); extern int setreuid(uid_t ruid, uid_t euid); +extern int setresgid(gid_t rgid, gid_t egid, gid_t sgid); +extern int setresuid(uid_t ruid, uid_t euid, uid_t suid); extern int getgrouplist(const char* user, gid_t baseGroup, gid_t* groupList, int* groupCount); diff --git a/headers/private/kernel/usergroup.h b/headers/private/kernel/usergroup.h index bf3eadda66..cb303f67f4 100644 --- a/headers/private/kernel/usergroup.h +++ b/headers/private/kernel/usergroup.h @@ -31,10 +31,10 @@ extern "C" { // syscalls -gid_t _user_getgid(bool effective); -uid_t _user_getuid(bool effective); -status_t _user_setregid(gid_t rgid, gid_t egid, bool setAllIfPrivileged); -status_t _user_setreuid(uid_t ruid, uid_t euid, bool setAllIfPrivileged); +status_t _user_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); +status_t _user_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); +status_t _user_setresgid(gid_t rgid, gid_t egid, gid_t sgid, bool setAllIfPrivileged); +status_t _user_setresuid(uid_t ruid, uid_t euid, uid_t suid, bool setAllIfPrivileged); ssize_t _user_getgroups(int groupCount, gid_t* groupList); ssize_t _user_setgroups(int groupCount, const gid_t* groupList); diff --git a/headers/private/system/syscalls.h b/headers/private/system/syscalls.h index b98c48c94c..84615fa680 100644 --- a/headers/private/system/syscalls.h +++ b/headers/private/system/syscalls.h @@ -216,11 +216,11 @@ extern int32 _kern_get_scheduler_mode(void); extern status_t _kern_get_loadavg(struct loadavg* info, size_t size); // user/group functions -extern gid_t _kern_getgid(bool effective); -extern uid_t _kern_getuid(bool effective); -extern status_t _kern_setregid(gid_t rgid, gid_t egid, +extern status_t _kern_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); +extern status_t _kern_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); +extern status_t _kern_setresgid(gid_t rgid, gid_t egid, gid_t sgid, bool setAllIfPrivileged); -extern status_t _kern_setreuid(uid_t ruid, uid_t euid, +extern status_t _kern_setresuid(uid_t ruid, uid_t euid, uid_t suid, bool setAllIfPrivileged); extern ssize_t _kern_getgroups(int groupCount, gid_t* groupList); extern status_t _kern_setgroups(int groupCount, const gid_t* groupList); diff --git a/src/system/kernel/usergroup.cpp b/src/system/kernel/usergroup.cpp index 26f26fbe8f..288d1d8591 100644 --- a/src/system/kernel/usergroup.cpp +++ b/src/system/kernel/usergroup.cpp @@ -37,7 +37,7 @@ is_privileged(Team* team) static status_t -common_setregid(gid_t rgid, gid_t egid, bool setAllIfPrivileged, bool kernel) +common_setresgid(gid_t rgid, gid_t egid, gid_t ssgid, bool setAllIfPrivileged, bool kernel) { Team* team = thread_get_current_thread()->team; @@ -45,7 +45,8 @@ common_setregid(gid_t rgid, gid_t egid, bool setAllIfPrivileged, bool kernel) bool privileged = kernel || is_privileged(team); - gid_t ssgid = team->saved_set_gid; + if (ssgid == (gid_t)-1 || !privileged) + ssgid = team->saved_set_gid; // real gid if (rgid == (gid_t)-1) { @@ -100,7 +101,7 @@ common_setregid(gid_t rgid, gid_t egid, bool setAllIfPrivileged, bool kernel) static status_t -common_setreuid(uid_t ruid, uid_t euid, bool setAllIfPrivileged, bool kernel) +common_setresuid(uid_t ruid, uid_t euid, uid_t ssuid, bool setAllIfPrivileged, bool kernel) { Team* team = thread_get_current_thread()->team; @@ -108,7 +109,14 @@ common_setreuid(uid_t ruid, uid_t euid, bool setAllIfPrivileged, bool kernel) bool privileged = kernel || is_privileged(team); - uid_t ssuid = team->saved_set_uid; + if (ssuid == (uid_t)-1) + ssuid = team->saved_set_uid; + else { + if (!privileged && ssuid != team->effective_uid + && ssuid != team->real_uid && ssuid != team->saved_set_uid) { + return EPERM; + } + } // real uid if (ruid == (uid_t)-1) { @@ -308,35 +316,45 @@ is_in_group(Team* team, gid_t gid) } -gid_t -_kern_getgid(bool effective) +status_t +_kern_setresgid(gid_t rgid, gid_t egid, gid_t ssgid, bool setAllIfPrivileged) { - Team* team = thread_get_current_thread()->team; - - return effective ? team->effective_gid : team->real_gid; -} - - -uid_t -_kern_getuid(bool effective) -{ - Team* team = thread_get_current_thread()->team; - - return effective ? team->effective_uid : team->real_uid; + return common_setresgid(rgid, egid, ssgid, setAllIfPrivileged, true); } status_t -_kern_setregid(gid_t rgid, gid_t egid, bool setAllIfPrivileged) +_kern_setresuid(uid_t ruid, uid_t euid, uid_t ssuid, bool setAllIfPrivileged) { - return common_setregid(rgid, egid, setAllIfPrivileged, true); + return common_setresuid(ruid, euid, ssuid, setAllIfPrivileged, true); } status_t -_kern_setreuid(uid_t ruid, uid_t euid, bool setAllIfPrivileged) +_kern_getresgid(gid_t *rgid, gid_t *egid, gid_t *ssgid) { - return common_setreuid(ruid, euid, setAllIfPrivileged, true); + Team* team = thread_get_current_thread()->team; + if (rgid != NULL) + *rgid = team->real_gid; + if (egid != NULL) + *egid = team->effective_gid; + if (ssgid != NULL) + *ssgid = team->saved_set_gid; + return B_OK; +} + + +status_t +_kern_getresuid(uid_t *ruid, uid_t *euid, gid_t *ssuid) +{ + Team* team = thread_get_current_thread()->team; + if (ruid != NULL) + *ruid = team->real_uid; + if (euid != NULL) + *euid = team->effective_uid; + if (ssuid != NULL) + *ssuid = team->saved_set_uid; + return B_OK; } @@ -357,35 +375,69 @@ _kern_setgroups(int groupCount, const gid_t* groupList) // #pragma mark - Syscalls -gid_t -_user_getgid(bool effective) +status_t +_user_setresgid(gid_t rgid, gid_t egid, gid_t ssgid, bool setAllIfPrivileged) { - Team* team = thread_get_current_thread()->team; - - return effective ? team->effective_gid : team->real_gid; -} - - -uid_t -_user_getuid(bool effective) -{ - Team* team = thread_get_current_thread()->team; - - return effective ? team->effective_uid : team->real_uid; + return common_setresgid(rgid, egid, ssgid, setAllIfPrivileged, false); } status_t -_user_setregid(gid_t rgid, gid_t egid, bool setAllIfPrivileged) +_user_setresuid(uid_t ruid, uid_t euid, uid_t ssuid, bool setAllIfPrivileged) { - return common_setregid(rgid, egid, setAllIfPrivileged, false); + return common_setresuid(ruid, euid, ssuid, setAllIfPrivileged, false); } status_t -_user_setreuid(uid_t ruid, uid_t euid, bool setAllIfPrivileged) +_user_getresgid(gid_t *rgid, gid_t *egid, gid_t *ssgid) { - return common_setreuid(ruid, euid, setAllIfPrivileged, false); + Team* team = thread_get_current_thread()->team; + if (rgid != NULL) { + if (!IS_USER_ADDRESS(rgid) + || user_memcpy(rgid, &team->real_gid, sizeof(uid_t)) != B_OK) { + return B_BAD_ADDRESS; + } + } + if (egid != NULL) { + if (!IS_USER_ADDRESS(egid) + || user_memcpy(egid, &team->effective_gid, sizeof(uid_t)) != B_OK) { + return B_BAD_ADDRESS; + } + } + if (ssgid != NULL) { + if (!IS_USER_ADDRESS(ssgid) + || user_memcpy(ssgid, &team->saved_set_gid, sizeof(uid_t)) != B_OK) { + return B_BAD_ADDRESS; + } + } + return B_OK; +} + + +status_t +_user_getresuid(uid_t *ruid, uid_t *euid, gid_t *ssuid) +{ + Team* team = thread_get_current_thread()->team; + if (ruid != NULL) { + if (!IS_USER_ADDRESS(ruid) + || user_memcpy(ruid, &team->real_uid, sizeof(uid_t)) != B_OK) { + return B_BAD_ADDRESS; + } + } + if (euid != NULL) { + if (!IS_USER_ADDRESS(euid) + || user_memcpy(euid, &team->effective_uid, sizeof(uid_t)) != B_OK) { + return B_BAD_ADDRESS; + } + } + if (ssuid != NULL) { + if (!IS_USER_ADDRESS(ssuid) + || user_memcpy(ssuid, &team->saved_set_uid, sizeof(uid_t)) != B_OK) { + return B_BAD_ADDRESS; + } + } + return B_OK; } diff --git a/src/system/libroot/posix/unistd/usergroup.cpp b/src/system/libroot/posix/unistd/usergroup.cpp index 97f31cff12..7939019972 100644 --- a/src/system/libroot/posix/unistd/usergroup.cpp +++ b/src/system/libroot/posix/unistd/usergroup.cpp @@ -39,70 +39,106 @@ set_errno_if_necessary(const T& result) gid_t getegid(void) { - return _kern_getgid(true); + gid_t egid = 0; + _kern_getresgid(NULL, &egid, NULL); + return egid; } uid_t geteuid(void) { - return _kern_getuid(true); + uid_t euid = 0; + _kern_getresuid(NULL, &euid, NULL); + return euid; } gid_t getgid(void) { - return _kern_getgid(false); + gid_t rgid = 0; + _kern_getresgid(&rgid, NULL, NULL); + return rgid; } uid_t getuid(void) { - return _kern_getuid(false); + uid_t ruid = 0; + _kern_getresuid(&ruid, NULL, NULL); + return ruid; +} + + +int +getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) +{ + return set_errno_if_necessary(_kern_getresgid(rgid, egid, sgid)); +} + + +int +getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) +{ + return set_errno_if_necessary(_kern_getresuid(ruid, euid, suid)); } int setgid(gid_t gid) { - return set_errno_if_necessary(_kern_setregid(gid, (gid_t)-1, true)); + return set_errno_if_necessary(_kern_setresgid(gid, (gid_t)-1, (gid_t)-1, true)); } int setuid(uid_t uid) { - return set_errno_if_necessary(_kern_setreuid(uid, (uid_t)-1, true)); + return set_errno_if_necessary(_kern_setresuid(uid, (uid_t)-1, (uid_t)-1, true)); } int setegid(gid_t gid) { - return set_errno_if_necessary(_kern_setregid((gid_t)-1, gid, false)); + return set_errno_if_necessary(_kern_setresgid((gid_t)-1, gid, (gid_t)-1, false)); } int seteuid(uid_t uid) { - return set_errno_if_necessary(_kern_setreuid((uid_t)-1, uid, false)); + return set_errno_if_necessary(_kern_setresuid((uid_t)-1, uid, (uid_t)-1, false)); } int setregid(gid_t rgid, gid_t egid) { - return set_errno_if_necessary(_kern_setregid(rgid, egid, false)); + return set_errno_if_necessary(_kern_setresgid(rgid, egid, (gid_t)-1, false)); } int setreuid(uid_t ruid, uid_t euid) { - return set_errno_if_necessary(_kern_setreuid(ruid, euid, false)); + return set_errno_if_necessary(_kern_setresuid(ruid, euid, (uid_t)-1, false)); +} + + +int +setresgid(gid_t rgid, gid_t egid, gid_t sgid) +{ + return set_errno_if_necessary(_kern_setresgid(rgid, egid, sgid, false)); +} + + +int +setresuid(uid_t ruid, uid_t euid, uid_t suid) +{ + return set_errno_if_necessary(_kern_setresuid(ruid, euid, suid, false)); }