• Rafael J. Wysocki's avatar
    PM / Sleep: Mitigate race between the freezer and request_firmware() · 247bc037
    Rafael J. Wysocki authored
    There is a race condition between the freezer and request_firmware()
    such that if request_firmware() is run on one CPU and
    freeze_processes() is run on another CPU and usermodehelper_disable()
    called by it succeeds to grab umhelper_sem for writing before
    usermodehelper_read_trylock() called from request_firmware()
    acquires it for reading, the request_firmware() will fail and
    trigger a WARN_ON() complaining that it was called at a wrong time.
    However, in fact, it wasn't called at a wrong time and
    freeze_processes() simply happened to be executed simultaneously.
    
    To avoid this race, at least in some cases, modify
    usermodehelper_read_trylock() so that it doesn't fail if the
    freezing of tasks has just started and hasn't been completed yet.
    Instead, during the freezing of tasks, it will try to freeze the
    task that has called it so that it can wait until user space is
    thawed without triggering the scary warning.
    
    For this purpose, change usermodehelper_disabled so that it can
    take three different values, UMH_ENABLED (0), UMH_FREEZING and
    UMH_DISABLED.  The first one means that usermode helpers are
    enabled, the last one means "hard disable" (i.e. the system is not
    ready for usermode helpers to be used) and the second one
    is reserved for the freezer.  Namely, when freeze_processes() is
    started, it sets usermodehelper_disabled to UMH_FREEZING which
    tells usermodehelper_read_trylock() that it shouldn't fail just
    yet and should call try_to_freeze() if woken up and cannot
    return immediately.  This way all freezable tasks that happen
    to call request_firmware() right before freeze_processes() is
    started and lose the race for umhelper_sem with it will be
    frozen and will sleep until thaw_processes() unsets
    usermodehelper_disabled.  [For the non-freezable callers of
    request_firmware() the race for umhelper_sem against
    freeze_processes() is unfortunately unavoidable.]
    Reported-by: default avatarStephen Boyd <sboyd@codeaurora.org>
    Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
    Acked-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    Cc: stable@vger.kernel.org
    247bc037
process.c 4.69 KB