In the UNIX system, privileges, such as being able to change the system's notion of the current date, and access control, such as being able to read or write a particle file, are based on user and group IDs. when our programs need additional privileges or need to gain access to resources that they currently aren't allowed to access, they need to change their user or group ID to an ID that has the appropriate privilege or access. similarly, when our programs need to lower their privileges or prevent access to certain resources, they do so by changing either their user ID or group ID to an ID without the privilege or ability access to the resource.
In general, we try to use the least-privilege model when we design our applications. following this model, our programs shocould use the least privilege necessary to accomplish any given task. this vulnerability CES the likelihood that security can be compromised by a malicious user trying to trick our programs into using their privileges in unintended ways.
We can set the real user ID and valid tive user ID withSetuidFunction. Similarly, we can set the real group ID and the specified tive group ID withSetgidFunction.
# Include <unistd. h> Int setuid (uid_t UID ); Int setgid (gid_t GID ); |
Both return: 0 if OK, 1 on Error |
There are rules for who can change the IDs. Let's consider only the user ID for now. (everything we describe for the user ID also applies to the group ID .)
1. If the process has superuser privileges,SetuidFunction sets the real User ID, valid tive user ID, and saved set-user-ID to uid.
2. If the process does not have superuser privileges, but uid equals either the real User ID or the saved set-user-ID,SetuidSets only the valid user ID to uid. The real user ID and the saved set-user-ID are not changed.
3. If neither of these two conditions is true,ErrnoIs setEperm, And 1 is returned.
We can make a few statements about the three user IDs that the kernel maintains.
Only a superuser process can change the real User ID. Normally, the real User ID is set byLogin(1) program when we log in and never changes. BecauseLoginIs a superuser process, it sets all three user IDs when it CILSSetuid.
The specified tive user ID is set byExecFunctions only if the set-user-ID bit is set for the program file. If the set-user-ID bit is not set,ExecFunctions leave the specified tive user ID as its current value. We can callSetuidAt any time to set the valid user ID to either the real User ID or the saved set-user-id. Naturally, we can't set the valid user ID to any random value.
The saved set-user-ID is copied from the specified tive user IDExec. If the file's set-user-ID bit is set, this copy is saved afterExecStores the specified tive user ID from the file's user ID.
Figure 8.18 summarizes the varous ways these three user IDs can be changed.
Figure 8.18. ways to change the three user IDs
ID |
Exec |
Setuid(UID) |
Set-user-ID bit off |
Set-user-ID bit on |
Superuser |
Unprivileged user |
Real user ID |
Unchanged |
Unchanged |
Set to uid |
Unchanged |
Valid user ID |
Unchanged |
Set From User ID of program file |
Set to uid |
Set to uid |
Saved set-User ID |
Copied from valid tive user ID |
Copied from valid tive user ID |
Set to uid |
Unchanged |
Note that we can obtain only the current value of the real user ID and the valid user ID with the functionsGetuidAndGeteuidFrom section 8.2. We can't obtain the current value of the saved set-user-id.
Example
To see the utility of the saved set-user-ID feature, let's examine the operation of a program that uses it. We'll look atMan(1) program, which is used to display online manual pages.ManProgram can be installed either set-user-ID or set-group-ID to a specific user or group, usually one reservedManItself.ManProgram can be made to read and possibly overwrite files in locations that are chosen either through a configuration file (usually/Etc/man. configOr/Etc/manpath. config) Or using a command-line option.
TheManProgram might have to execute several other commands to process the files containing the manual page to be displayed. To prevent being tricked into running the wrong commands or overwriting the wrong files,ManCommand has to switch between two sets of privileges: those of the user runningManCommand and those of the user that ownsManExecutable file. The following steps take place.
Assuming thatManProgram file is owned by the user nameManAnd has its set-user-ID bit set, when weExecIt, we have
Real user id = our user ID
Valid tive user id =Man
Saved set-user-id =Man
TheManProgram accesses the required configuration
Files and manual pages. These files are owned by the user nameMan,
Because the valid tive user ID isMan, File access is allowed.
BeforeManRuns any command on our behalf, it CILS
Setuid (getuid ()). Because we are not a superuser process, this changes
Only the valid user ID. We have
Real user id = our user ID (unchanged)
Valid tive user id = our user ID
Saved set-user-id =Man(Unchanged)
NowManProcess is running with our user ID as its
Valid tive user ID. This means that we can access only the files to which we have
Normal access. We have no additional permissions. It can safely execute any
Filter on our behalf.
When the filter is done,ManCILS
Setuid (EUID), Where EUID is the numerical user ID for the user name
Man. (This was savedManBy callingGeteuid.) This
Call is allowed because the argumentSetuidEquals the saved
Set-user-id. (This is why we need the saved set-user-id.) Now we have
Real user id = our user ID (unchanged)
Valid tive user id =Man
Saved set-user-id =Man(Unchanged)
TheManProgram can now operate on its files, as its
Valid user ID isMan.
By using the saved set-user-ID in this fashion, we can use
Extra privileges granted to us by the Set-user-ID of the program file at
Beginning of the process and at the end of the process. In between, however, the process runs
Our normal permissions. If we weren't able to switch back to the saved
Set-user-ID at the end, we might be tempted to retain the extra permissions
Whole time we were running (which is asking for trouble ).
Let's look at what happens ifManSpawns a shell
US while it is running. (The shell is spawned usingForkAnd
Exec.) Because the real user ID and the valid tive user ID are both our
Normal user ID (Step 3), the shell has no extra permissions. The shell can't
Access the saved set-user-ID that is set to (User)ManWhile (command)ManIs
Running, because the saved set-user-ID for the shell is copied from
Valid user IDExec. So in the child process that does
Exec, All three user IDs are our normal user ID.
Our description of howManUsesSetuid
Function is not correct if the program is set-user-ID to root (as in centos, not In Debian), because a call
SetuidWith superuser privileges sets all three user IDs. For
Example to work as described, we needSetuidTo set only the valid tive
User ID.