jhrozek
jhrozek

Reputation: 59

Why does access(2) check for real and not effective UID?

I noticed the hard way that the access(2) system call uses the real and not effective user ID for the access control check. While this is in line with what the access(2) man page says on Linux, it still makes little sense to me...

For example, a setuid root program would run under the effective UID of root and real UID of whoever ran the program..now, the program would be able to open /etc/shadow with open(2), but the call access("/etc/shadow", R_OK); would fail with EACCESS

Can anyone educate my on why access(2) works the way it does?

Upvotes: 4

Views: 1729

Answers (2)

Kenster
Kenster

Reputation: 25439

The simplest answer is that access() works the way the standard says it should:

The access() function shall check the file named by the pathname pointed to by the path argument for accessibility according to the bit pattern contained in amode, using the real user ID in place of the effective user ID and the real group ID in place of the effective group ID.

The standard also describes a different function faccessat() which has an option to use the effective UID:

AT_EACCESS
The checks for accessibility are performed using the effective user and group IDs instead of the real user and group ID as required in a call to access().

There is also a nonstandard function eaccess() or euidaccess() which you'll find on some systems, which checks using the EUID. The standard talks a bit about this function and why it's not part of the standard.

As for why access() was original designed the way it was, consider that typical programs don't actually need access() very often. If you want to know if you can open a file, it's probably because you're about to open it. So just try to open it and see if it works. It's rare to need to test whether you can do something without actually doing it.

The rationale on the standards page hints at the original purpose for access():

The superuser has complete access to all files on a system. As a consequence, programs started by the superuser and switched to the effective user ID with lesser privileges cannot use access() to test their file access permissions.

The original purpose of access() was for a setuid program to test whether the user could perform an action without considering the program's elevated access. That permits a setuid program to limit the scope of what it does without relinquishing its elevated status.

Upvotes: 4

John Bollinger
John Bollinger

Reputation: 181008

Per the Linux man page, "This allows set-user-ID programs to easily determine the invoking user’s authority."

I suppose this is actually the crux of the function. Any program can just attempt the desired type of access and handle failure if it happens. Most do. You need to check access separately only if you care whether the answer differs from what you would get from the "try and see" approach.

Upvotes: 0

Related Questions