access() Security Hole

2019-01-28 09:07发布

问题:

I've been doing some shell writing and came across a recommendation for access() to check whether a file exists, can be read, etc. Seems super easy to implement and faster than stat(). When I started looking at the man page for it, I noticed that it is NOT recommended for use because it can lead to a security hole. The man page says this:

Using access() to check if a user is authorized to e.g. open a file before actually doing so using open(2) creates a security hole, because the user might exploit the short time interval between checking and opening the file to manipulate it.

Does anyone know how this can be exploited or if it pertains only to using open() after checking a file? I know that a lot of people say to use stat() instead, but access() is so easy to implement, especially for the shell that I used it for.

Thanks

回答1:

That is a TOCTOU race (Time of Check to Time of Update). A malicious user could substitute a file he has access to for a symlink to something he doesn't have access to between the access() and the open() calls. Use faccessat() or fstat(). In general, open a file once, and use f*() functions on it (e.g: fchown(), ...).



回答2:

One thing I can think of, although it seems weak - access() uses the real rather than effective uid and gid. This supposedly allows a setuid program (one which a regular user executes but which gains permissions of the owner) to check whether the invoking user can read the file, to prevent inadvertently giving that user access to a file that they should be unable to read, perhaps by using some symbolic link or hard link trickery. I can't find any evidence that this is possible, or that this isn't possible with stat(), but imagine this scenario:

user executes program
program is setuid, immediately gets all privs of root
program checks file1 to ensure that user has access
file1 is a hardlink to file2, which user has access to
user changes file1 to hardlink to file3 (/etc/shadow or something like that)
program reads file1 and does something to it (print, convert, whatever)
user now has access to a file they shouldn't


回答3:

The pattern seems to be calling access() or stat() to determine whether you can open a file, and then opening it if you have permission.

Instead, it's usually better just to go ahead and try to open it, and then check whether the attempt succeeded (and if not, why). This avoids the time interval between the check and the attempt to open the file.