-
-
Notifications
You must be signed in to change notification settings - Fork 99
File handle leak fix (50c0e0a/ec67b14 commits) seems to have introduced deadlock #23
Comments
tanyev notifications@github.com wrote:
I had that problem too, and found and fixed it. The problem is in --- /tmp/magic.c 2014-11-25 15:38:49.887510095 -0800 /*
Dave Olson |
I like the idea of falling back to seeding from your change @daveolson53, but why not also use whatever bits had been read from /dev/urandom in the seeding? In truth, I'm not sure ec67b14 is the best way to address the leaked FD. Prior to that change, the code treated 'rfd' as a long-lived source of entropy -- it could always go back to that pool to grab more bits, at least that appears to be the goal from the 117013b change. From a security perspective, pulling bits from '/dev/urandom' will provide more entropy than using srandom/random. If the goal is simply to ensure that 'rfd' is closed when the process shuts down, then why not use atexit(3) when the fd is successfully opened. Starting with the version of magic.c in commit 117013b, that change would look something like this: /* ... add a new function to magic.c .... */
/*
* magic_cleanup - if /dev/urandom was used as entropy (via rfd), then make
* sure it is closed at process end
*/
void
magic_cleanup()
{
/* arguably, this could be asserted based on how this callback is set up. */
if (rfd > -1) {
close(rfd);
rfd = -1;
}
}
/* ... snip .... */
void
magic_init()
{
struct stat statbuf;
long seed;
struct timeval t;
if (magic_inited)
return;
magic_inited = 1;
/*
try using /dev/urandom
also check that it's a character device
If it doesn't exist, fallback to other method
*/
if (!lstat("/dev/urandom", &statbuf) && S_ISCHR(statbuf.st_mode)) {
rfd = open("/dev/urandom", O_RDONLY);
if (rfd >= 0) {
if (0 == atexit(&magic_cleanup)) {
return;
}
else {
/* if the atexit() fails due to error, fallback to srandom */
close(rfd);
rfd = -1;
}
}
}
/* ... more code here .... */ (Disclaimer: I haven't tested this, but I'd be happy to and create a patch for this is people think it'd be useful.) Cheers. |
benschumacher notifications@github.com wrote:
I thought of that, but I'd have had to add code to save them. For
Sure, but really, does it matter much?
The issue for my use (and I think the original poster), is that the The atexit() doesn't help, because this is the login process, the Dave Olson |
Alright. I think I'm caught up. In that case, I would propose adjusting the behavior a bit to this flow:
If there is an error in the above flow anywhere in the above steps, then fallback to seeding PRNG using the existing mechanism, and then generate a new random after seeding PRNG. In no circumstance should we return the seed material to the application-layer, which may use it as the session identifier in the cleartext header of the TACACS+ protocol. |
Note that the whole |
Could you please test how it works with the latest commit? |
I re-created the original test and the deadlock is gone. I noticed that the file descriptors in use seem to have moved around (see below). I wonder if if a 'close(rfd);' after line 54 is in order? Once a seed has been obtained, rfd serves no other purpose and closing it would achieve the "spirit" of ec67b14. Here is the strace starting with the open_session sequence that deadlocked before:
|
Ah, correct - just fixed it! |
I have been developing a prototype using pam_tacplus (1.3.9 tag) authenticating against a tac_plus server. I was experimenting with multiple servers and was passing the 'debug' option to pam_tacplus.so. During pam_sm_open_session() my test program (a modified pamtest.py from python-pam package) locked up. The deadlock was reproducible. Here is an strace leading to the deadlock:
As you can see from the last few lines, some code is trying to read from the syslog file descriptor. I captured a stack trace with gdb.
The top two stack frames lead me to line 81 of magic.c:
Obviously preventing the leak is important, especially for long running applications. But multiple calls to magic() in the life of an application is also a valid use case. Not being steeped in pam_tacplus, my naive solution would be to also reset rfd and magic_inited when closing rfd.
The text was updated successfully, but these errors were encountered: