lkml.org 
[lkml]   [2022]   [May]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 4.19 09/38] ALSA: jack: Access input_dev under mutex
    Date
    From: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>

    [ Upstream commit 1b6a6fc5280e97559287b61eade2d4b363e836f2 ]

    It is possible when using ASoC that input_dev is unregistered while
    calling snd_jack_report, which causes NULL pointer dereference.
    In order to prevent this serialize access to input_dev using mutex lock.

    Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
    Reviewed-by: Cezary Rojewski <cezary.rojewski@intel.com>
    Link: https://lore.kernel.org/r/20220412091628.3056922-1-amadeuszx.slawinski@linux.intel.com
    Signed-off-by: Takashi Iwai <tiwai@suse.de>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    include/sound/jack.h | 1 +
    sound/core/jack.c | 34 +++++++++++++++++++++++++++-------
    2 files changed, 28 insertions(+), 7 deletions(-)

    diff --git a/include/sound/jack.h b/include/sound/jack.h
    index 1e84bfb553cf..4742f842b457 100644
    --- a/include/sound/jack.h
    +++ b/include/sound/jack.h
    @@ -77,6 +77,7 @@ struct snd_jack {
    const char *id;
    #ifdef CONFIG_SND_JACK_INPUT_DEV
    struct input_dev *input_dev;
    + struct mutex input_dev_lock;
    int registered;
    int type;
    char name[100];
    diff --git a/sound/core/jack.c b/sound/core/jack.c
    index acb531749efb..074b15fcb0ac 100644
    --- a/sound/core/jack.c
    +++ b/sound/core/jack.c
    @@ -48,8 +48,11 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
    #ifdef CONFIG_SND_JACK_INPUT_DEV
    struct snd_jack *jack = device->device_data;

    - if (!jack->input_dev)
    + mutex_lock(&jack->input_dev_lock);
    + if (!jack->input_dev) {
    + mutex_unlock(&jack->input_dev_lock);
    return 0;
    + }

    /* If the input device is registered with the input subsystem
    * then we need to use a different deallocator. */
    @@ -58,6 +61,7 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
    else
    input_free_device(jack->input_dev);
    jack->input_dev = NULL;
    + mutex_unlock(&jack->input_dev_lock);
    #endif /* CONFIG_SND_JACK_INPUT_DEV */
    return 0;
    }
    @@ -96,8 +100,11 @@ static int snd_jack_dev_register(struct snd_device *device)
    snprintf(jack->name, sizeof(jack->name), "%s %s",
    card->shortname, jack->id);

    - if (!jack->input_dev)
    + mutex_lock(&jack->input_dev_lock);
    + if (!jack->input_dev) {
    + mutex_unlock(&jack->input_dev_lock);
    return 0;
    + }

    jack->input_dev->name = jack->name;

    @@ -122,6 +129,7 @@ static int snd_jack_dev_register(struct snd_device *device)
    if (err == 0)
    jack->registered = 1;

    + mutex_unlock(&jack->input_dev_lock);
    return err;
    }
    #endif /* CONFIG_SND_JACK_INPUT_DEV */
    @@ -242,9 +250,11 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
    return -ENOMEM;
    }

    - /* don't creat input device for phantom jack */
    - if (!phantom_jack) {
    #ifdef CONFIG_SND_JACK_INPUT_DEV
    + mutex_init(&jack->input_dev_lock);
    +
    + /* don't create input device for phantom jack */
    + if (!phantom_jack) {
    int i;

    jack->input_dev = input_allocate_device();
    @@ -262,8 +272,8 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
    input_set_capability(jack->input_dev, EV_SW,
    jack_switch_types[i]);

    -#endif /* CONFIG_SND_JACK_INPUT_DEV */
    }
    +#endif /* CONFIG_SND_JACK_INPUT_DEV */

    err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);
    if (err < 0)
    @@ -303,10 +313,14 @@ EXPORT_SYMBOL(snd_jack_new);
    void snd_jack_set_parent(struct snd_jack *jack, struct device *parent)
    {
    WARN_ON(jack->registered);
    - if (!jack->input_dev)
    + mutex_lock(&jack->input_dev_lock);
    + if (!jack->input_dev) {
    + mutex_unlock(&jack->input_dev_lock);
    return;
    + }

    jack->input_dev->dev.parent = parent;
    + mutex_unlock(&jack->input_dev_lock);
    }
    EXPORT_SYMBOL(snd_jack_set_parent);

    @@ -354,6 +368,8 @@ EXPORT_SYMBOL(snd_jack_set_key);

    /**
    * snd_jack_report - Report the current status of a jack
    + * Note: This function uses mutexes and should be called from a
    + * context which can sleep (such as a workqueue).
    *
    * @jack: The jack to report status for
    * @status: The current status of the jack
    @@ -373,8 +389,11 @@ void snd_jack_report(struct snd_jack *jack, int status)
    status & jack_kctl->mask_bits);

    #ifdef CONFIG_SND_JACK_INPUT_DEV
    - if (!jack->input_dev)
    + mutex_lock(&jack->input_dev_lock);
    + if (!jack->input_dev) {
    + mutex_unlock(&jack->input_dev_lock);
    return;
    + }

    for (i = 0; i < ARRAY_SIZE(jack->key); i++) {
    int testbit = SND_JACK_BTN_0 >> i;
    @@ -393,6 +412,7 @@ void snd_jack_report(struct snd_jack *jack, int status)
    }

    input_sync(jack->input_dev);
    + mutex_unlock(&jack->input_dev_lock);
    #endif /* CONFIG_SND_JACK_INPUT_DEV */
    }
    EXPORT_SYMBOL(snd_jack_report);
    --
    2.35.1
    \
     
     \ /
      Last update: 2022-05-30 16:38    [W:4.258 / U:0.016 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site