• Guillaume Nault's avatar
    ppp: lock ppp->flags in ppp_read() and ppp_poll() · edffc217
    Guillaume Nault authored
    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: default avatarGuillaume Nault <g.nault@alphalink.fr>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    edffc217
ppp_generic.c 71.8 KB