tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: locking against myself panic (cprng_strongreseed, filt_rndread)
> Date: Fri, 10 Nov 2017 13:58:51 +0100
> From: Edgar Fuß <ef%math.uni-bonn.de@localhost>
>
> Short: Your patch seems to work.
Pullup request submitted:
https://releng.netbsd.org/cgi-bin/req-6.cgi?show=1512
> Long: I don't quite understand the behaviour, but at least, it doesn't panic.
>
> I wrote a test programm (my first encounter with kqueue, so probably wrong)
> to exercise EVFILT_READ.
> I created a named pipe and it did approximately what I expected (on start,
> it hung in fiford, which I didn't expect).
> I wanted to test in on /dev/urandom, it read 512 bytes, then timed out
> (program wrote dots) and paniced (same traceback as originally) after
> about 15 of them.
> On /dev/random, it read 512 bytes, wrote dots and didn't panic (at least
> not for 20 seconds). On a second run on /dev/random, it read 512 bytes
> and paniced immediately after.
There are multiple compounding bugs here. Here's how it works:
1. - When you register an EVFILT_READ event for /dev/random, it draws
a PRNG seed from the entropy pool (`depleting it'), and records
that _if_ entropy is ever added to the pool then the waiter
should be notified.
- Same for /dev/urandom, except it doesn't draw a new seed if there
already was a per-CPU PRNG initialized.
(Note that the caller blocks if there already is entropy in the
pool -- the event only waits for _adding_ entropy to the pool.
This is an independent bug that was also fixed in netbsd-7.)
2. When someone later adds entropy to the pool (e.g., uvm fault, or
network packet arrival, or disk seek, or `echo htthththttthtthh >
/dev/random'), cprng_strong_reseed gets called.
3. cprng_strong_reseed does a locking dance with a pair of cyclic
mutexes (also gone in netbsd-7). If it wins the dance, it calls
cprng_strong_doreseed with c->reseed.mtx and c->mtx held.
4. cprng_strong_doreseed calls selnotify, which notifies all the
kqueue events by...
5. ...calling filt_rndread, which calls cprng_strong_ready, which
acquires c->mtx again --> panic.
The patch changes cprng_strong_ready so that it requires the caller to
hold c->mtx (which was necessary anyway for the caller to make
sensible decisions on the basis of invariants preserved by c->mtx),
and enables two ways to call filt_rndread:
- with c->mtx not held, indicated by having NOTE_SUBMIT clear, when
the waiter is registering the kevent and about to sleep; and
- with c->mtx held, indicated by having NOTE_SUBMIT set, when the
event happens.
(This kind of crazy NOTE_SUBMIT protocol turns out to be the standard
way to write kqueue filters. Go figure.)
> With the patch, it read behaved identically on the first run; on the second,
> it read about twenty 512-byte chunks and continued writing dots (if I
> remember correctly). In any case, I couldn't make it panic.
Right -- all of the _other_ bugs in netbsd-6 /dev/random are still
there. All that the patch changed is the instapanic on adding entropy
to the pool when someone is waiting with kqueue to read from
/dev/u?random.
Home |
Main Index |
Thread Index |
Old Index