forked from mirrors/linux
		
	random: fix accounting race condition with lockless irq entropy_count update
Commit902c098a36("random: use lockless techniques in the interrupt path") turned IRQ path from being spinlock protected into lockless cmpxchg-retry update. That commit removed r->lock serialization between crediting entropy bits from IRQ context and accounting when extracting entropy on userspace read path, but didn't turn the r->entropy_count reads/updates in account() to use cmpxchg as well. It has been observed, that under certain circumstances this leads to read() on /dev/urandom to return 0 (EOF), as r->entropy_count gets corrupted and becomes negative, which in turn results in propagating 0 all the way from account() to the actual read() call. Convert the accounting code to be the proper lockless counterpart of what has been partially done by902c098a36. Signed-off-by: Jiri Kosina <jkosina@suse.cz> Cc: Theodore Ts'o <tytso@mit.edu> Cc: Greg KH <greg@kroah.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									1e7e2e05c1
								
							
						
					
					
						commit
						10b3a32d29
					
				
					 1 changed files with 15 additions and 7 deletions
				
			
		| 
						 | 
				
			
			@ -865,16 +865,24 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
 | 
			
		|||
	if (r->entropy_count / 8 < min + reserved) {
 | 
			
		||||
		nbytes = 0;
 | 
			
		||||
	} else {
 | 
			
		||||
		int entropy_count, orig;
 | 
			
		||||
retry:
 | 
			
		||||
		entropy_count = orig = ACCESS_ONCE(r->entropy_count);
 | 
			
		||||
		/* If limited, never pull more than available */
 | 
			
		||||
		if (r->limit && nbytes + reserved >= r->entropy_count / 8)
 | 
			
		||||
			nbytes = r->entropy_count/8 - reserved;
 | 
			
		||||
		if (r->limit && nbytes + reserved >= entropy_count / 8)
 | 
			
		||||
			nbytes = entropy_count/8 - reserved;
 | 
			
		||||
 | 
			
		||||
		if (r->entropy_count / 8 >= nbytes + reserved)
 | 
			
		||||
			r->entropy_count -= nbytes*8;
 | 
			
		||||
		else
 | 
			
		||||
			r->entropy_count = reserved;
 | 
			
		||||
		if (entropy_count / 8 >= nbytes + reserved) {
 | 
			
		||||
			entropy_count -= nbytes*8;
 | 
			
		||||
			if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
 | 
			
		||||
				goto retry;
 | 
			
		||||
		} else {
 | 
			
		||||
			entropy_count = reserved;
 | 
			
		||||
			if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
 | 
			
		||||
				goto retry;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (r->entropy_count < random_write_wakeup_thresh)
 | 
			
		||||
		if (entropy_count < random_write_wakeup_thresh)
 | 
			
		||||
			wakeup_write = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue