Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix (highly unlikely) race condition in readLink #1645

Merged
merged 1 commit into from Nov 20, 2017

Conversation

twhitehead
Copy link
Contributor

Used to determine symlink size with stat and value with readlink. This could technically result in garbage if symlink changed between calls. Also gets around the broken stat implementation in our network filesystem (returns size + 1 giving a byte of garbage).

Used to determine symlink size with stat and value with readlink.
This could technically result in garbage if symlink changed between
calls.  Also gets around the broken stat implementation in our
network filesystem (returns size + 1 giving a byte of garbage).
@copumpkin
Copy link
Member

Isn't this case the motivation for readlinkat?

@twhitehead
Copy link
Contributor Author

I'm not sure I understand what you are meaning?

From reading the man page of readlinkat it seems it's difference is that you can provide a directory file descriptor from which to interpreted a passed relative path from instead of a implicitly relative to the processes working directory.

The race condition I was referring to was that, in the original code, the length of the symlink was determined by a call to stat while the contents of the symlink was determined by a later call to readlink. This can go wrong as things can technically change between the two calls.

The value used for the length of the returned symlink should be the value that readlink returns, as it is the one that also provides the symlink contents, not the earlier stat value.

Cheers! -Tyson

PS: My motivation for this change isn't so much that I'm worried about this race condition, although it should be fixed as it is technically wrong and can be, but that the stat call on our (vendor supplied) filesystem is broken and returns the length +1 which screws up the current code.

@copumpkin
Copy link
Member

Oh, I see, sorry. Ignore me!

@dezgeg
Copy link
Contributor

dezgeg commented Nov 3, 2017

Since we're allocating the temporary value on the stack anyway, I would just directly allocate a PATH_MAX sized buffer.

@twhitehead
Copy link
Contributor Author

Apparently PATH_MAX is a bit of a dubious thing

http://www.gnu.org/software/libc/manual/html_node/Limits-for-Files.html

and isn't even defined on some OSs.

@orivej
Copy link
Contributor

orivej commented Nov 3, 2017

Golang implements readlink as in this PR: https://sourcegraph.com/github.com/golang/go@go1.9.2/-/blob/src/os/file_posix.go#L16-29

@twhitehead
Copy link
Contributor Author

@orivej Interesting. Looks exactly like what I did except they start with a length of 128 and do 2x on failure while I started with 1024 (PATH_MAX/4) and do 1.5x on failure.

Perhaps picking a value like 128 is better though as on some systems PATH_MAX is not defined.

According to git blame, the code originally just used the stat size, but was later amended to use max(stat size,PATH_MAX) as links in /proc returned a stat size of 0.

@edolstra edolstra merged commit 72804dc into NixOS:master Nov 20, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants