ppp: lock ppp->flags in ppp_read() and ppp_poll()
authorGuillaume Nault <g.nault@alphalink.fr>
Fri, 26 Feb 2016 17:45:34 +0000 (18:45 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 1 Mar 2016 21:15:07 +0000 (16:15 -0500)
commitedffc2178d4ba10a61e150b42ef5e7d797714eb3
treeffea2b44f6560408081be5f8d26fbce1f10f1eda
parenta7f4b98896f6aede26431a3017d32d722fcec5cb
ppp: lock ppp->flags in ppp_read() and ppp_poll()

ppp_read() and ppp_poll() can be called concurrently with ppp_ioctl().
In this case, ppp_ioctl() might call ppp_ccp_closed(), which may update
ppp->flags while ppp_read() or ppp_poll() is reading it.
The update done by ppp_ccp_closed() isn't atomic due to the bit mask
operation ('ppp->flags &= ~(SC_CCP_OPEN | SC_CCP_UP)'), so concurrent
readers might get transient values.
Reading incorrect ppp->flags may disturb the 'ppp->flags & SC_LOOP_TRAFFIC'
test in ppp_read() and ppp_poll(), which in turn can lead to improper
decision on whether the PPP unit file is ready for reading or not.

Since ppp_ccp_closed() is protected by the Rx and Tx locks (with
ppp_lock()), taking the Rx lock is enough for ppp_read() and ppp_poll()
to guarantee that ppp_ccp_closed() won't update ppp->flags
concurrently.

The same reasoning applies to ppp->n_channels. The 'n_channels' field
can also be written to concurrently by ppp_ioctl() (through
ppp_connect_channel() or ppp_disconnect_channel()). These writes aren't
atomic (simple increment/decrement), but are protected by both the Rx
and Tx locks (like in the ppp->flags case). So holding the Rx lock
before reading ppp->n_channels also prevents concurrent writes.

Signed-off-by: Guillaume Nault <g.nault@alphalink.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ppp/ppp_generic.c