NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/47538: races in uatp(4)



>Number:         47538
>Category:       kern
>Synopsis:       races in uatp(4)
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Feb 06 21:05:00 +0000 2013
>Originator:     Taylor R Campbell <campbell+netbsd%mumble.net@localhost>
>Release:        NetBSD-current
>Organization:
>Environment:
>Description:

        uatp_detach does nothing to ensure the callout is stopped
        before destroying it or to ensure that uatp_intr will not run
        before clobbering the softc structure.  sc_status, sc_input,
        sc_input_index, and sc_input_size are not protected by any
        mutex.  Also, geyser34_enable_raw_mode has a window between the
        UR_GET_REPORT and UR_SET_REPORT requests with nothing to
        prevent intervening updates to the report.  It's not clear that
        this is a problem, but it makes me nervous.

        The hardware should perhaps be reset when enabling the uhidev,
        not just when attaching the device -- that might help to fix
        the interrupt storms I have seen when starting X which the
        heuristic in uatp_intr doesn't detect.

>How-To-Repeat:

        Code inspection.

>Fix:

        Coming!

        I think that it should suffice to

        (a) extend sc_tap_mutex to cover all the mutable fields (and
        rename it to sc_lock), and

        (b) add some logic to uatp_detach to wait for the callout to
        stop running.

        In particular, I believe calling uhidev_close is enough to
        block further uatp_intr, so it is not necessary to add any
        logic to uatp_intr to check for sc_status & ENABLED.

        Eliminating the window in geyser34_enable_raw_mode might be
        best done with an additional flag in sc_status, say RESETTING,
        and an associated condvar:

static int
uatp_enter(struct uatp_softc *sc)
{
        int error;

        mutex_enter(&sc->sc_lock);
        while (ISSET(sc->sc_status, UATP_RESETTING)) {
                error = cv_timedwait_sig(&sc->sc_cv, &sc->sc_lock,
                    mstohz(1000));
                if (error)
                        return error;
        }

        return 0;
}

static void
uatp_exit(struct uatp_softc *sc)
{

        mutex_exit(&sc->sc_lock);
}

static void
geyser34_enable_raw_mode(struct uatp_softc *sc)
{

        if (uatp_enter(sc) != 0)
                return;
        sc->sc_status |= UATP_RESETTING;
        uatp_exit(sc);

        ...do the USB requests...

out:    mutex_enter(&sc->sc_lock);
        sc->sc_status &=~ UATP_RESETTING;
        cv_broadcast(&sc->sc_cv);
        mutex_exit(&sc->sc_lock);
}



Home | Main Index | Thread Index | Old Index