Issue 10824: urandom should not block (original) (raw)

Created on 2011-01-04 13:42 by nijel, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Messages (15)
msg125316 - (view) Author: Michal Čihař (nijel) * Date: 2011-01-04 13:42
Currently if /dev/urandom does not provide any data, unradom() call is just stuck infinitely waiting for data. I actually faced this issue when /dev/urandom was empty regular file (due to bug in pbuilder, but I don't think it matters how it did happen) and urandom() call just hang. I think it would be much saner in such case to throw an error and let user know that something it wrong than waiting infinitely.
msg125318 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-01-04 13:49
This would change semantics of the library call, though. I see two possible solutions: - do nothing and let users tackle the issue if necessary (e.g. by calling open() themselves and using select() on the resulting fd) - add an optional "blocking" parameter to os.urandom() that, if False, would return None when no data is available
msg125320 - (view) Author: Michal Čihař (nijel) * Date: 2011-01-04 13:59
Well in this particular case (/dev/urandom is regular file), it might make sense to simply raise NotImplementedError
msg125321 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-01-04 14:01
> Well in this particular case (/dev/urandom is regular file), it might > make sense to simply raise NotImplementedError IMO it would be quite fragile to try to detect regular files vs special files. I suppose you noticed the issue quite quickly anyway, since you had the blocking issue.
msg125322 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2011-01-04 14:06
Is it really necessary to do something about this? /dev/urandom being a regular file is clearly a bug in your system configuration, and I don't want to know what all the other programs will do that rely on it...
msg125323 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2011-01-04 14:10
From the documentation: "This function returns random bytes from an OS-specific randomness source." In your case, this problem shows up because of an OS misconfiguration : in that case, the behaviour is undefined (not much Python can do about it). Note that since /dev/urandom is used, with a properly configured system, this should never block (contrarily to /dev/random which might block until enough entropy has been gathered).
msg125324 - (view) Author: Michal Čihař (nijel) * Date: 2011-01-04 14:11
Yes, it was blocking, but deep in some program (which was actually called by dpkg postinst script), so it took some time to figure out. I don't think it's that fragile to figure out whether it is regular file using os.path.isfile. Indeed it was bug in a system, but actually this was only thing which got stuck because of it.
msg125325 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-01-04 14:13
> Note that since /dev/urandom is used, with a properly configured > system, this should never block Ok, suggesting closing then.
msg125362 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2011-01-04 21:08
I wonder why reading from /dev/urandom has a loop in the first place, though - isn't it guaranteed that you can read as many bytes as you want in one go? This goes back to #934711, and apparently, even the original patch had the loop - for reasons that got never questioned.
msg125365 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2011-01-04 21:40
Agreed that the original issue is invalid. So either the title should be changed so it can be used to address Martin's question, or it should be closed.
msg125368 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2011-01-04 21:54
Closing it. It seems that people feel more safe when urandom loops until it has enough data (see http://stackoverflow.com/questions/4598507/dev-urandom-maximum-size/4598534#4598534). I might still pursue this idea, but in a different issue.
msg125369 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2011-01-04 21:58
> Martin v. Löwis <martin@v.loewis.de> added the comment: > > I wonder why reading from /dev/urandom has a loop in the first place, though - isn't it guaranteed that you can read as many bytes as you want in one go? This goes back to #934711, and apparently, even the original patch had the loop - for reasons that got never questioned. > I found surprising that a read from /dev/urandom would be uninterruptible, so I digged a little, and found this mail from 1998: [patch] fix for urandom read(2) not interruptible http://marc.info/?l=bugtraq&m=91495921611500&w=2 "It's a bug in random.c that doesn' t check for signal pending inside the read(2) code, so you have no chance to kill the process via signals until the read(2) syscall is finished, and it could take a lot of time before return, if the buffer given to the read syscall is very big..." I've had a quick look at the source code, and indeed, read(2) from /dev/urandom can now be interrupted by a signal, so looping seems to be justified. > ---------- > nosy: +loewis > status: pending -> open > > _______________________________________ > Python tracker <report@bugs.python.org> > <http://bugs.python.org/issue10824> > _______________________________________ >
msg125376 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2011-01-04 22:37
> "It's a bug in random.c that doesn' t check for signal pending inside the > read(2) code, so you have no chance to kill the process via signals until > the read(2) syscall is finished, and it could take a lot of time before > return, if the buffer given to the read syscall is very big..." > > I've had a quick look at the source code, and indeed, read(2) from > /dev/urandom can now be interrupted by a signal, so looping seems to > be justified. No: if read(2) is interrupted, no data is returned, and exception is raised. So it won't loop in that case, but raise the exception out of urandom also (which is the right thing to do).
msg125519 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2011-01-06 08:18
> Martin v. Löwis <martin@v.loewis.de> added the comment: > >> "It's a bug in random.c that doesn' t check for signal pending inside the >> read(2) code, so you have no chance to kill the process via signals until >> the read(2) syscall is finished, and it could take a lot of time before >> return, if the buffer given to the read syscall is very big..." >> >> I've had a quick look at the source code, and indeed, read(2) from >> /dev/urandom can now be interrupted by a signal, so looping seems to >> be justified. > > No: if read(2) is interrupted, no data is returned, and exception is > raised. So it won't loop in that case, but raise the exception out of > urandom also (which is the right thing to do). > (Sorry for being a little off-topic, but since there's not dedicated thread) Try with this: dd if=/dev/urandom of=/dev/null bs=100M count=1 Then, in another terminal: pkill -USR1 -xn dd You'll see that read returns less that 100M bytes when interrupted. You can also try with the following python code: --- import os d = os.open('/dev/urandom', os.O_RDONLY) data = os.read(d, 1 << 28) os.close(d) print('read %d bytes' % len(data)) --- and in another terminal pkill -STOP -xn python then pkill -CONT -xn python Same thing, read returns less bytes than requested. Anyway, since /dev/urandom is not part of any standard (AFAIK), it's probably better to use the common idiom while len(data) < expected: read(expected - len(data)) So we're sure it won't break under some systems/conditions. Cheers > ---------- > > _______________________________________ > Python tracker <report@bugs.python.org> > <http://bugs.python.org/issue10824> > _______________________________________ >
msg125601 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2011-01-06 22:53
> You'll see that read returns less that 100M bytes when interrupted. I see. > while len(data) < expected: > read(expected - len(data)) > > So we're sure it won't break under some systems/conditions. I think this is not quite the idiom we should use if we want to deal with signals: if read() returns an empty string, we have hit end-of-file. If there is a signal before anything is read, we should catch the exception and continue reading (which the loop doesn't do, either). OTOH, if the signal was due to a user interrupt, we should raise an exception, anyway, IMO - even if we've read some data already.
History
Date User Action Args
2022-04-11 14:57:10 admin set github: 55033
2011-01-06 22:53:18 loewis set nosy:loewis, georg.brandl, nijel, pitrou, r.david.murray, neologixmessages: +
2011-01-06 08🔞41 neologix set nosy:loewis, georg.brandl, nijel, pitrou, r.david.murray, neologixmessages: +
2011-01-04 22:37:40 loewis set nosy:loewis, georg.brandl, nijel, pitrou, r.david.murray, neologixmessages: +
2011-01-04 21:58:17 neologix set nosy:loewis, georg.brandl, nijel, pitrou, r.david.murray, neologixmessages: +
2011-01-04 21:54:37 loewis set status: open -> closednosy:loewis, georg.brandl, nijel, pitrou, r.david.murray, neologixmessages: +
2011-01-04 21:40:37 r.david.murray set nosy: + r.david.murraymessages: +
2011-01-04 21:08:33 loewis set status: pending -> opennosy: + loewismessages: +
2011-01-04 14:13:16 pitrou set status: open -> pendingmessages: + resolution: not a bugnosy:georg.brandl, nijel, pitrou, neologix
2011-01-04 14:11:32 nijel set nosy:georg.brandl, nijel, pitrou, neologixmessages: +
2011-01-04 14:10:23 neologix set nosy: + neologixmessages: +
2011-01-04 14:06:34 georg.brandl set nosy: + georg.brandlmessages: +
2011-01-04 14:01:45 pitrou set messages: +
2011-01-04 13:59:38 nijel set messages: +
2011-01-04 13:49:42 pitrou set versions: + Python 3.3, - Python 2.7nosy: + pitroumessages: + type: behavior -> enhancement
2011-01-04 13:42:42 nijel create