-
Notifications
You must be signed in to change notification settings - Fork 293
unixpwd: fix reentrance of unixpwd_setpwd() and unixpwd_setspw() #6729
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
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a global lock around calls to these functions in the OCaml->C stubs (the OCaml runtime lock is never released).
Is the intention to call this function concurrently from different threads?
| fclose(spasswd_file); | ||
| fclose(tmp_file); | ||
| if (rc != ENOENT) { | ||
| ulckpwdf(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is still global, right?
What happens if 2 threads try to use lckpwdf? Do only one of them get it, do both of them get it?
Could it result in a bug where there are 2 callers to this function from 2 threads, the 1st one obtains the lock with lckpwdf(), the 2nd one (noop) acquires the lock again, and then the 1st one releases the lock with ulckpwdf(), leaving the 2nd thread to operate on the file without holding any locks, potentially corrupting it.
(If lckpwdf() relies on file-locks, then those only work per-process, and the application needs to do its own locking with mutexes, i.e. we're back to where we started, to having a global lock around this whole function)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If 2 threads can obtain the lock at the same time it would be a very weird lock.
Yes, Glibc uses a file descriptor and a file lock so 2 threads in the same process will obtain the lock. How these functions are classified as multithread-safe I don't know...
BTW, the lock (if implemented, in MUSL they are empty stubs) should be global system wide, so it could block other processes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About Ocaml lock, yes, it should be released in unixpwd/c/unixpwd_stubs.c.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, but then we need to introduce another mutex here (which could still be beneficial, because it'd allow other OCaml threads to keep running, while this one deals with the password database, which is probably quite rare)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although if the intention is just to get this to compile with Musl (#6729 (comment)), then keeping the OCaml runtime lock as is might be simpler (we don't gain any additional concurrency, and we don't risk introducing any concurrency bugs in our existing code either).
|
@edwintorok about the intent, in #6728 I proposed to replace But if OCaml runtime lock isn't released it might be overkill. Regarding
From glibc implementation, it should work against multiple threads in same process and against multiple processes (if all are using |
- prefer fgetpwent_r() over getpwent_r() to avoid ETC_PASSWD FILE to be shared against threads - prefer fgetspent_r() over getspent_r() to avoid ETC_SPASSWD FILE to be shared against threads - while here, unlink(2) tmp_name on error in unixpwd_setpwd() to avoid leaving temporary file on error Signed-off-by: Sebastien Marie <semarie@kapouay.eu.org>
Signed-off-by: Sebastien Marie <semarie@kapouay.eu.org>
cbfce18 to
2a73b82
Compare
|
This code is rarely used such that problems around concurrent access were unlikely to be noticed. I am happy to accept the improvements. |
I think the OCaml runtime lock would prevent concurrent accesses
Although if some libcs don't provide the thread-unsafe variants, then that is a good enough motive to switch to the more thread-safe ones, at least to keep things building, even if we don't release the OCaml runtime lock. |
|
I am switching this in PR in draft for now, as there is no rush to push it:
The purpose of this PR was specifically to address a (non-existent) thread safety issue, as my initial |
fgetpwent_r()overgetpwent_r()to avoid ETC_PASSWD FILE to be shared against threadsfgetspent_r()overgetspent_r()to avoid ETC_SPASSWD FILE to be shared against threadsunlink(2)tmp_name on error in unixpwd_setpwd() to avoid leaving temporary file on error