Skip to content

Commit

Permalink
ASoC: dapm: Fix kcontrol path list corruption
Browse files Browse the repository at this point in the history
When calling krealloc for the kcontrol data the items in the path list that
point back to the head of the list will now point to freed memory, which causes
the list to become corrupted. To fix this, instead of resizing the whole data
struct, only resize the widget list.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Mark Brown <broonie@linaro.org>
  • Loading branch information
Lars-Peter Clausen authored and Mark Brown committed Aug 1, 2013
1 parent 9356e9d commit 2c75bdf
Showing 1 changed file with 21 additions and 17 deletions.
38 changes: 21 additions & 17 deletions sound/soc/soc-dapm.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,24 +177,22 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
struct dapm_kcontrol_data {
unsigned int value;
struct list_head paths;
struct snd_soc_dapm_widget_list wlist;
struct snd_soc_dapm_widget_list *wlist;
};

static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
struct snd_kcontrol *kcontrol)
{
struct dapm_kcontrol_data *data;

data = kzalloc(sizeof(*data) + sizeof(widget), GFP_KERNEL);
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
dev_err(widget->dapm->dev,
"ASoC: can't allocate kcontrol data for %s\n",
widget->name);
return -ENOMEM;
}

data->wlist.widgets[0] = widget;
data->wlist.num_widgets = 1;
INIT_LIST_HEAD(&data->paths);

kcontrol->private_data = data;
Expand All @@ -205,6 +203,7 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
{
struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
kfree(data->wlist);
kfree(data);
}

Expand All @@ -213,25 +212,30 @@ static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
{
struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);

return &data->wlist;
return data->wlist;
}

static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_widget *widget)
{
struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
struct dapm_kcontrol_data *new_data;
unsigned int n = data->wlist.num_widgets + 1;
struct snd_soc_dapm_widget_list *new_wlist;
unsigned int n;

if (data->wlist)
n = data->wlist->num_widgets + 1;
else
n = 1;

new_data = krealloc(data, sizeof(*data) + sizeof(widget) * n,
GFP_KERNEL);
if (!new_data)
new_wlist = krealloc(data->wlist,
sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL);
if (!new_wlist)
return -ENOMEM;

new_data->wlist.widgets[n - 1] = widget;
new_data->wlist.num_widgets = n;
new_wlist->widgets[n - 1] = widget;
new_wlist->num_widgets = n;

kcontrol->private_data = new_data;
data->wlist = new_wlist;

return 0;
}
Expand Down Expand Up @@ -689,12 +693,12 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
w->name, name, ret);
return ret;
}
} else {
ret = dapm_kcontrol_add_widget(kcontrol, w);
if (ret)
return ret;
}

ret = dapm_kcontrol_add_widget(kcontrol, w);
if (ret)
return ret;

w->kcontrols[kci] = kcontrol;
dapm_kcontrol_add_path(kcontrol, path);

Expand Down

0 comments on commit 2c75bdf

Please sign in to comment.