Add man pages for seteuid() and friends.

Also add an overview page that explains the general concepts.
This commit is contained in:
Nico Weber 2020-06-30 15:32:10 -04:00 committed by Andreas Kling
parent 9b4e6f6a23
commit 1f323076f0
Notes: sideshowbarker 2024-07-19 05:12:34 +09:00
13 changed files with 273 additions and 0 deletions

View file

@ -0,0 +1 @@
geteuid.md

View file

@ -0,0 +1,25 @@
## Name
geteuid, getegid - get effective user / group id
## Synopsis
```**c++
#include <unistd.h>
uid_t geteuid(void);
gid_t getegid(void);
```
## Description
Returns the effective user or group id.
## See also
* [`setuid_overview`(7)](../man7/setuid_overview.md)
* [`getuid`(2) / `getgid`(2)](getuid.md)
* [`getresuid`(2) / `getresgid`(2)](getresuid.md)
* [`seteuid`(2) / `setegid`(2)](seteuid.md)
* [`setuid`(2) / `setgid`(2)](setuid.md)
* [`setresuid`(2) / `setresgid`(2)](setresuid.md)

View file

@ -0,0 +1 @@
getuid.md

View file

@ -0,0 +1 @@
getresuid.md

View file

@ -0,0 +1,34 @@
## Name
getresuid, getresgid - get real, effective, and saved user / group ID
## Synopsis
```**c++
#include <unistd.h>
int getresuid(uid_t*, uid_t*, uid_t*);
int getresgid(gid_t*, gid_t*, gid_t*);
```
## Description
Returns the real, effective, and saved user or group ID.
## Return value
If the call was set successful, returns 0.
Else, returns -1 and sets `errno` to describe the error.
## Errors
* `EFAULT`: One of the passed pointers is not valid, writeable pointer in the current process.
## See also
* [`setuid_overview`(7)](../man7/setuid_overview.md)
* [`geteuid`(2) / `getegid`(2)](geteuid.md)
* [`getuid`(2) / `getgid`(2)](getuid.md)
* [`seteuid`(2) / `setegid`(2)](seteuid.md)
* [`setuid`(2) / `setgid`(2)](setuid.md)
* [`setresuid`(2) / `setresgid`(2)](setresuid.md)

View file

@ -0,0 +1,25 @@
## Name
getuid, getgid - get real user / group id
## Synopsis
```**c++
#include <unistd.h>
uid_t getuid(void);
gid_t getgid(void);
```
## Description
Returns the real user or group id.
## See also
* [`setuid_overview`(7)](../man7/setuid_overview.md)
* [`geteuid`(2) / `getegid`(2)](geteuid.md)
* [`getresuid`(2) / `getresgid`(2)](getresuid.md)
* [`seteuid`(2) / `setegid`(2)](seteuid.md)
* [`setuid`(2) / `setgid`(2)](setuid.md)
* [`setresuid`(2) / `setresgid`(2)](setresuid.md)

View file

@ -0,0 +1 @@
seteuid.md

View file

@ -0,0 +1,38 @@
## Name
seteuid, setegid - set effective user / group ID
## Synopsis
```**c++
#include <unistd.h>
int seteuid(uid_t);
int setegid(gid_t);
```
## Description
Sets the effective user or group ID.
For non-superusers, the effective ID can only be set to the current real or saved ID.
In particular, `seteuid(geteuid())` will fail if the current effective user ID is not equal to the current real or saved ID.
## Return value
If the call was set successful, returns 0.
Else, returns -1 and sets `errno` to describe the error.
## Errors
* `EPERM`: The new ID is not equal to the real ID or saved ID, and the user is not superuser.
## See also
* [`setuid_overview`(7)](../man7/setuid_overview.md)
* [`geteuid`(2) / `getegid`(2)](geteuid.md)
* [`getuid`(2) / `getgid`(2)](getuid.md)
* [`getresuid`(2) / `getresgid`(2)](getresuid.md)
* [`setuid`(2) / `setgid`(2)](setuid.md)
* [`setresuid`(2) / `setresgid`(2)](setresuid.md)

View file

@ -0,0 +1 @@
setuid.md

View file

@ -0,0 +1 @@
setresuid.md

View file

@ -0,0 +1,38 @@
## Name
setresuid, setresgid - set real, effective, and saved user / group ID
## Synopsis
```**c++
#include <unistd.h>
int setresuid(uid_t, uid_t, uid_t);
int setresgid(gid_t, gid_t, gid_t);
```
## Description
Sets all of real, effective, and saved user or group ID to the given values.
An argument of `-1` keeps the corresponding ID unchanged.
For non-superusers, each of the given values has to be equal to any of the current real, effective, or saved IDs for the call to succeed.
## Return value
If the call was set successful, returns 0.
Else, returns -1 and sets `errno` to describe the error.
## Errors
* `EPERM`: At least one of the passed IDs was not equal to the current real, effective, or saved ID, and the user is not superuser.
## See also
* [`setuid_overview`(7)](../man7/setuid_overview.md)
* [`geteuid`(2) / `getegid`(2)](geteuid.md)
* [`getuid`(2) / `getgid`(2)](getuid.md)
* [`getresuid`(2) / `getresgid`(2)](getresuid.md)
* [`seteuid`(2) / `setegid`(2)](seteuid.md)
* [`setuid`(2) / `setgid`(2)](setuid.md)

View file

@ -0,0 +1,36 @@
## Name
setuid, setgid - set user / group ID
## Synopsis
```**c++
#include <unistd.h>
int setuid(uid_t);
int setgid(gid_t);
```
## Description
Sets all of real, effective, and saved user or group ID to the given ID.
For non-superusers, the given ID has to be equal to the current real or effective ID for the call to succeed.
## Return value
If the call was set successful, returns 0.
Else, returns -1 and sets `errno` to describe the error.
## Errors
* `EPERM`: The new ID is not equal to the real ID or effective ID, and the user is not superuser.
## See also
* [`setuid_overview`(7)](../man7/setuid_overview.md)
* [`geteuid`(2) / `getegid`(2)](geteuid.md)
* [`getuid`(2) / `getgid`(2)](getuid.md)
* [`getresuid`(2) / `getresgid`(2)](getresuid.md)
* [`seteuid`(2) / `setegid`(2)](seteuid.md)
* [`setresuid`(2) / `setresgid`(2)](setresuid.md)

View file

@ -0,0 +1,71 @@
## Name
Overview of real, effective, and saved user and group IDs
## Description
Each process runs has a user ID and a group ID. By default, a new process inherits the user ID and group ID of its parent process.
Each file has permissions that control if it can be read, written, and executed by processes belonging to its owner, by processes belonging to other users in the owner's group, and by processes belonging to others.
In addition to the access permissions bits, executables may have the "Set User ID" and the "Set Group ID" bit set. When executables with these bits set are executed, they run with the user or group ID of the executable, instead of with the user and group ID of their parent process. These binaries are also called "SUID binaries" or "setuid binaries" (or "SGID binaries" or "setgid binaries" for the "Set Group ID" bit).
The motivation behind SUID binaries is that they allow users to do tasks that would normally require elevated permissions, without having to give users these permissions fully.
For example, `/usr/ping` has the Set User ID bit set and is owned by user root in group root. So if any process executes `/usr/ping`, it will run as root, which means it will be able to send network packets, even if the current process doesn't normally have network access.
For another example, many other Unix systems contain a utility `passwd` that changes the password of the current user. To store the password, it has to write to `/etc/shadow` -- but the current user is not supposed to have write access to `/etc/shadow` so that they cannot change passwords of other users. The solution is to make `passwd` a SUID binary. (SerenityOS currently doesn't have support for user passwords.)
SUID binaries mean that the effective user ID of a process and the real user ID of a process can be different. When a SUID binary is executed, it assumes the owner of the binary as effective user ID, and the user ID of the parent process that executed it as real user ID. The effective user ID is used for permission checks.
Since SUID binaries are able to bypass access checks, only carefully selected binaries should be made SUID. If, for example, `cp` was SUID root, everyone could overwrite every file using this `cp` binary.
In some instances, it is useful for a SUID binary to either temporarily or permanently drop its permissions and set the effective user ID to the real user ID.
To make this possible, each process has *three* user (and group) IDs: The (real) user ID, the *effective* user ID, and the *saved* user ID. When a process executes a normal binary, all three IDs are set to the parent process's user ID. However, when a process executes a SUID binary, the process runs with the paren process's ID as its real ID, but it takes its effective ID and saved ID from the binary. (Analogously for the group ID for SGID binaries.)
The function [`setresuid`(2)](../man2/getresuid.md) can change the real, effective, and saved user ID of a process -- but for non-root processes it is only valid to set each new ID to the current value of real, effective, or saved user ID. Since SUID binaries start with the binary's owner as effective and saved user ID and with the current user's ID as real user ID, this allows switching the effective user ID between the SUID owner's ID and the current user's ID.
Hence, to temporarily drop SUID privileges, set the effective ID to a less privileged user ID, and store the current effective user ID in the saved user ID so that it can be restored in a later call:
```c++
if (setresuid(-1, new_uid, geteuid()) < 0)
return OH_NO;
```
(Since the saved ID starts out as the file owner's ID for SUID binaries, this should in practice be the same as `seteuid(getuid())`, but it's easier to reason about.)
The process then has fewer permissions, but since the former effective ID is still stored in the saved ID, the process can restore its former permissions with:
```c++
uid_t ruid, euid, suid;
if (getresuid(&ruid, &euid, &suid) < 0)
return OH_NO;
if (setresuid(-1, suid, -1) < 0)
return OH_NO;
```
(Since SUID binaries are often owned by root who has user ID 0, this is often identical to `seteuid(0)` -- in particular, if a SUID root binary accepts user input in an unsafe way with temporarily dropped privileges, then if a user manages to take control of the binary with malicious input they can restore privileges with `seteuid(0)`.)
A process can permanently drop its SUID privileges by copying the real user ID into both effective and saved user ID. Then, it's impossible to set the effective ID to anything else (assuming the current user isn't the superuser). To permanently drop privileges:
```c++
if (setresuid(new_uid, new_uid, new_uid) < 0)
return OH_NO;
```
(On SerenityOS, this is usually the same as calling `setuid(new_uid)`, but easier to reason about.)
Changing group IDs is analogous. Since changing the user ID changes the permissions of a process, group privileges should be dropped before user privileges are dropped, and if they're dropped temporarily, user privileges should be restored before group privileges are restored.
For historical reasons, there are many functions for setting and getting these IDs. `setresuid()`, `setresgid()`, `getresuid()`, and `getresgid()` are the most flexible of these functions and they have the easiest to understand semantics.
## See also
* "Setuid Demystified", Proceedings of the 11th USENIX Security Symposium, August 2002, Pages 171190
* [`getresuid`(2) / `getresgid`(2)](../man2/getresuid.md)
* [`geteuid`(2) / `getegid`(2)](../man2/geteuid.md)
* [`getuid`(2) / `getgid`(2)](../man2/getuid.md)
* [`seteuid`(2) / `setegid`(2)](../man2/seteuid.md)
* [`setuid`(2) / `setgid`(2)](../man2/setuid.md)
* [`setresuid`(2) / `setresgid`(2)](../man2/setresuid.md)