Skip to content

Commit e2810d7

Browse files
committed
ALSA: usb-audio: Fix memory leak and corruption in mixer_us16x08.c
There are a few places leaking memory and doing double-free in mixer_us16x08.c. The driver allocates a usb_mixer_elem_info object at each add_new_ctl() call. This has to be freed via kctl->private_free, but currently this is done properly only for some controls. Also, the driver allocates three external objects (comp_store, eq_store, meter_store), and these are referred in elem->private_data (it's not kctl->private_data). And these have to be released, but there are none doing it. Moreover, these extra objects have to be released only once. Thus the release should be done only by the first kctl element that refers to it. For fixing these, we call either snd_usb_mixer_elem_free() (only for kctl->private_data) or elem_private_free() (for both kctl->private_data and elem->private_data) via kctl->private_free appropriately. Last but not least, snd_us16x08_controls_create() may return in the middle without releasing the allocated *_store objects due to an error. For fixing this, we shuffle the allocation code so that it's called just before its reference. Fixes: d2bb390 ("ALSA: usb-audio: Tascam US-16x08 DSP mixer quirk") Reported-by: Takashi Sakamoto <[email protected]> Reviewed-by: Takashi Sakamoto <[email protected]> Signed-off-by: Takashi Iwai <[email protected]>
1 parent 89b593c commit e2810d7

File tree

2 files changed

+39
-54
lines changed

2 files changed

+39
-54
lines changed

sound/usb/mixer_us16x08.c

Lines changed: 39 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,11 +1053,22 @@ static struct snd_us16x08_meter_store *snd_us16x08_create_meter_store(void)
10531053

10541054
}
10551055

1056+
/* release elem->private_free as well; called only once for each *_store */
1057+
static void elem_private_free(struct snd_kcontrol *kctl)
1058+
{
1059+
struct usb_mixer_elem_info *elem = kctl->private_data;
1060+
1061+
if (elem)
1062+
kfree(elem->private_data);
1063+
kfree(elem);
1064+
kctl->private_data = NULL;
1065+
}
1066+
10561067
static int add_new_ctl(struct usb_mixer_interface *mixer,
10571068
const struct snd_kcontrol_new *ncontrol,
10581069
int index, int val_type, int channels,
10591070
const char *name, const void *opt,
1060-
void (*freeer)(struct snd_kcontrol *kctl),
1071+
bool do_private_free,
10611072
struct usb_mixer_elem_info **elem_ret)
10621073
{
10631074
struct snd_kcontrol *kctl;
@@ -1085,7 +1096,10 @@ static int add_new_ctl(struct usb_mixer_interface *mixer,
10851096
return -ENOMEM;
10861097
}
10871098

1088-
kctl->private_free = freeer;
1099+
if (do_private_free)
1100+
kctl->private_free = elem_private_free;
1101+
else
1102+
kctl->private_free = snd_usb_mixer_elem_free;
10891103

10901104
strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
10911105

@@ -1109,87 +1123,76 @@ static struct snd_us16x08_control_params eq_controls[] = {
11091123
.type = USB_MIXER_BOOLEAN,
11101124
.num_channels = 16,
11111125
.name = "EQ Switch",
1112-
.freeer = snd_usb_mixer_elem_free
11131126
},
11141127
{ /* EQ low gain */
11151128
.kcontrol_new = &snd_us16x08_eq_gain_ctl,
11161129
.control_id = SND_US16X08_ID_EQLOWLEVEL,
11171130
.type = USB_MIXER_U8,
11181131
.num_channels = 16,
11191132
.name = "EQ Low Volume",
1120-
.freeer = snd_usb_mixer_elem_free
11211133
},
11221134
{ /* EQ low freq */
11231135
.kcontrol_new = &snd_us16x08_eq_low_freq_ctl,
11241136
.control_id = SND_US16X08_ID_EQLOWFREQ,
11251137
.type = USB_MIXER_U8,
11261138
.num_channels = 16,
11271139
.name = "EQ Low Frequence",
1128-
.freeer = NULL
11291140
},
11301141
{ /* EQ mid low gain */
11311142
.kcontrol_new = &snd_us16x08_eq_gain_ctl,
11321143
.control_id = SND_US16X08_ID_EQLOWMIDLEVEL,
11331144
.type = USB_MIXER_U8,
11341145
.num_channels = 16,
11351146
.name = "EQ MidLow Volume",
1136-
.freeer = snd_usb_mixer_elem_free
11371147
},
11381148
{ /* EQ mid low freq */
11391149
.kcontrol_new = &snd_us16x08_eq_mid_freq_ctl,
11401150
.control_id = SND_US16X08_ID_EQLOWMIDFREQ,
11411151
.type = USB_MIXER_U8,
11421152
.num_channels = 16,
11431153
.name = "EQ MidLow Frequence",
1144-
.freeer = NULL
11451154
},
11461155
{ /* EQ mid low Q */
11471156
.kcontrol_new = &snd_us16x08_eq_mid_width_ctl,
11481157
.control_id = SND_US16X08_ID_EQLOWMIDWIDTH,
11491158
.type = USB_MIXER_U8,
11501159
.num_channels = 16,
11511160
.name = "EQ MidQLow Q",
1152-
.freeer = NULL
11531161
},
11541162
{ /* EQ mid high gain */
11551163
.kcontrol_new = &snd_us16x08_eq_gain_ctl,
11561164
.control_id = SND_US16X08_ID_EQHIGHMIDLEVEL,
11571165
.type = USB_MIXER_U8,
11581166
.num_channels = 16,
11591167
.name = "EQ MidHigh Volume",
1160-
.freeer = snd_usb_mixer_elem_free
11611168
},
11621169
{ /* EQ mid high freq */
11631170
.kcontrol_new = &snd_us16x08_eq_mid_freq_ctl,
11641171
.control_id = SND_US16X08_ID_EQHIGHMIDFREQ,
11651172
.type = USB_MIXER_U8,
11661173
.num_channels = 16,
11671174
.name = "EQ MidHigh Frequence",
1168-
.freeer = NULL
11691175
},
11701176
{ /* EQ mid high Q */
11711177
.kcontrol_new = &snd_us16x08_eq_mid_width_ctl,
11721178
.control_id = SND_US16X08_ID_EQHIGHMIDWIDTH,
11731179
.type = USB_MIXER_U8,
11741180
.num_channels = 16,
11751181
.name = "EQ MidHigh Q",
1176-
.freeer = NULL
11771182
},
11781183
{ /* EQ high gain */
11791184
.kcontrol_new = &snd_us16x08_eq_gain_ctl,
11801185
.control_id = SND_US16X08_ID_EQHIGHLEVEL,
11811186
.type = USB_MIXER_U8,
11821187
.num_channels = 16,
11831188
.name = "EQ High Volume",
1184-
.freeer = snd_usb_mixer_elem_free
11851189
},
11861190
{ /* EQ low freq */
11871191
.kcontrol_new = &snd_us16x08_eq_high_freq_ctl,
11881192
.control_id = SND_US16X08_ID_EQHIGHFREQ,
11891193
.type = USB_MIXER_U8,
11901194
.num_channels = 16,
11911195
.name = "EQ High Frequence",
1192-
.freeer = NULL
11931196
},
11941197
};
11951198

@@ -1201,47 +1204,41 @@ static struct snd_us16x08_control_params comp_controls[] = {
12011204
.type = USB_MIXER_BOOLEAN,
12021205
.num_channels = 16,
12031206
.name = "Compressor Switch",
1204-
.freeer = snd_usb_mixer_elem_free
12051207
},
12061208
{ /* Comp threshold */
12071209
.kcontrol_new = &snd_us16x08_comp_threshold_ctl,
12081210
.control_id = SND_US16X08_ID_COMP_THRESHOLD,
12091211
.type = USB_MIXER_U8,
12101212
.num_channels = 16,
12111213
.name = "Compressor Threshold Volume",
1212-
.freeer = NULL
12131214
},
12141215
{ /* Comp ratio */
12151216
.kcontrol_new = &snd_us16x08_comp_ratio_ctl,
12161217
.control_id = SND_US16X08_ID_COMP_RATIO,
12171218
.type = USB_MIXER_U8,
12181219
.num_channels = 16,
12191220
.name = "Compressor Ratio",
1220-
.freeer = NULL
12211221
},
12221222
{ /* Comp attack */
12231223
.kcontrol_new = &snd_us16x08_comp_attack_ctl,
12241224
.control_id = SND_US16X08_ID_COMP_ATTACK,
12251225
.type = USB_MIXER_U8,
12261226
.num_channels = 16,
12271227
.name = "Compressor Attack",
1228-
.freeer = NULL
12291228
},
12301229
{ /* Comp release */
12311230
.kcontrol_new = &snd_us16x08_comp_release_ctl,
12321231
.control_id = SND_US16X08_ID_COMP_RELEASE,
12331232
.type = USB_MIXER_U8,
12341233
.num_channels = 16,
12351234
.name = "Compressor Release",
1236-
.freeer = NULL
12371235
},
12381236
{ /* Comp gain */
12391237
.kcontrol_new = &snd_us16x08_comp_gain_ctl,
12401238
.control_id = SND_US16X08_ID_COMP_GAIN,
12411239
.type = USB_MIXER_U8,
12421240
.num_channels = 16,
12431241
.name = "Compressor Volume",
1244-
.freeer = NULL
12451242
},
12461243
};
12471244

@@ -1253,7 +1250,6 @@ static struct snd_us16x08_control_params channel_controls[] = {
12531250
.type = USB_MIXER_BOOLEAN,
12541251
.num_channels = 16,
12551252
.name = "Phase Switch",
1256-
.freeer = snd_usb_mixer_elem_free,
12571253
.default_val = 0
12581254
},
12591255
{ /* Fader */
@@ -1262,7 +1258,6 @@ static struct snd_us16x08_control_params channel_controls[] = {
12621258
.type = USB_MIXER_U8,
12631259
.num_channels = 16,
12641260
.name = "Line Volume",
1265-
.freeer = NULL,
12661261
.default_val = 127
12671262
},
12681263
{ /* Mute */
@@ -1271,7 +1266,6 @@ static struct snd_us16x08_control_params channel_controls[] = {
12711266
.type = USB_MIXER_BOOLEAN,
12721267
.num_channels = 16,
12731268
.name = "Mute Switch",
1274-
.freeer = NULL,
12751269
.default_val = 0
12761270
},
12771271
{ /* Pan */
@@ -1280,7 +1274,6 @@ static struct snd_us16x08_control_params channel_controls[] = {
12801274
.type = USB_MIXER_U16,
12811275
.num_channels = 16,
12821276
.name = "Pan Left-Right Volume",
1283-
.freeer = NULL,
12841277
.default_val = 127
12851278
},
12861279
};
@@ -1293,7 +1286,6 @@ static struct snd_us16x08_control_params master_controls[] = {
12931286
.type = USB_MIXER_U8,
12941287
.num_channels = 16,
12951288
.name = "Master Volume",
1296-
.freeer = NULL,
12971289
.default_val = 127
12981290
},
12991291
{ /* Bypass */
@@ -1302,7 +1294,6 @@ static struct snd_us16x08_control_params master_controls[] = {
13021294
.type = USB_MIXER_BOOLEAN,
13031295
.num_channels = 16,
13041296
.name = "DSP Bypass Switch",
1305-
.freeer = NULL,
13061297
.default_val = 0
13071298
},
13081299
{ /* Buss out */
@@ -1311,7 +1302,6 @@ static struct snd_us16x08_control_params master_controls[] = {
13111302
.type = USB_MIXER_BOOLEAN,
13121303
.num_channels = 16,
13131304
.name = "Buss Out Switch",
1314-
.freeer = NULL,
13151305
.default_val = 0
13161306
},
13171307
{ /* Master mute */
@@ -1320,7 +1310,6 @@ static struct snd_us16x08_control_params master_controls[] = {
13201310
.type = USB_MIXER_BOOLEAN,
13211311
.num_channels = 16,
13221312
.name = "Master Mute Switch",
1323-
.freeer = NULL,
13241313
.default_val = 0
13251314
},
13261315

@@ -1338,30 +1327,10 @@ int snd_us16x08_controls_create(struct usb_mixer_interface *mixer)
13381327
/* just check for non-MIDI interface */
13391328
if (mixer->hostif->desc.bInterfaceNumber == 3) {
13401329

1341-
/* create compressor mixer elements */
1342-
comp_store = snd_us16x08_create_comp_store();
1343-
if (comp_store == NULL)
1344-
return -ENOMEM;
1345-
1346-
/* create eq store */
1347-
eq_store = snd_us16x08_create_eq_store();
1348-
if (eq_store == NULL) {
1349-
kfree(comp_store);
1350-
return -ENOMEM;
1351-
}
1352-
1353-
/* create meters store */
1354-
meter_store = snd_us16x08_create_meter_store();
1355-
if (meter_store == NULL) {
1356-
kfree(comp_store);
1357-
kfree(eq_store);
1358-
return -ENOMEM;
1359-
}
1360-
13611330
/* add routing control */
13621331
err = add_new_ctl(mixer, &snd_us16x08_route_ctl,
13631332
SND_US16X08_ID_ROUTE, USB_MIXER_U8, 8, "Line Out Route",
1364-
NULL, NULL, &elem);
1333+
NULL, false, &elem);
13651334
if (err < 0) {
13661335
usb_audio_dbg(mixer->chip,
13671336
"Failed to create route control, err:%d\n",
@@ -1372,6 +1341,11 @@ int snd_us16x08_controls_create(struct usb_mixer_interface *mixer)
13721341
elem->cache_val[i] = i < 2 ? i : i + 2;
13731342
elem->cached = 0xff;
13741343

1344+
/* create compressor mixer elements */
1345+
comp_store = snd_us16x08_create_comp_store();
1346+
if (!comp_store)
1347+
return -ENOMEM;
1348+
13751349
/* add master controls */
13761350
for (i = 0;
13771351
i < sizeof(master_controls)
@@ -1385,7 +1359,8 @@ int snd_us16x08_controls_create(struct usb_mixer_interface *mixer)
13851359
master_controls[i].num_channels,
13861360
master_controls[i].name,
13871361
comp_store,
1388-
master_controls[i].freeer, &elem);
1362+
i == 0, /* release comp_store only once */
1363+
&elem);
13891364
if (err < 0)
13901365
return err;
13911366
elem->cache_val[0] = master_controls[i].default_val;
@@ -1405,7 +1380,7 @@ int snd_us16x08_controls_create(struct usb_mixer_interface *mixer)
14051380
channel_controls[i].num_channels,
14061381
channel_controls[i].name,
14071382
comp_store,
1408-
channel_controls[i].freeer, &elem);
1383+
false, &elem);
14091384
if (err < 0)
14101385
return err;
14111386
for (j = 0; j < SND_US16X08_MAX_CHANNELS; j++) {
@@ -1415,6 +1390,11 @@ int snd_us16x08_controls_create(struct usb_mixer_interface *mixer)
14151390
elem->cached = 0xffff;
14161391
}
14171392

1393+
/* create eq store */
1394+
eq_store = snd_us16x08_create_eq_store();
1395+
if (!eq_store)
1396+
return -ENOMEM;
1397+
14181398
/* add EQ controls */
14191399
for (i = 0; i < sizeof(eq_controls) /
14201400
sizeof(control_params); i++) {
@@ -1426,7 +1406,8 @@ int snd_us16x08_controls_create(struct usb_mixer_interface *mixer)
14261406
eq_controls[i].num_channels,
14271407
eq_controls[i].name,
14281408
eq_store,
1429-
eq_controls[i].freeer, NULL);
1409+
i == 0, /* release eq_store only once */
1410+
NULL);
14301411
if (err < 0)
14311412
return err;
14321413
}
@@ -1444,18 +1425,23 @@ int snd_us16x08_controls_create(struct usb_mixer_interface *mixer)
14441425
comp_controls[i].num_channels,
14451426
comp_controls[i].name,
14461427
comp_store,
1447-
comp_controls[i].freeer, NULL);
1428+
false, NULL);
14481429
if (err < 0)
14491430
return err;
14501431
}
14511432

1433+
/* create meters store */
1434+
meter_store = snd_us16x08_create_meter_store();
1435+
if (!meter_store)
1436+
return -ENOMEM;
1437+
14521438
/* meter function 'get' must access to compressor store
14531439
* so place a reference here
14541440
*/
14551441
meter_store->comp_store = comp_store;
14561442
err = add_new_ctl(mixer, &snd_us16x08_meter_ctl,
14571443
SND_US16X08_ID_METER, USB_MIXER_U16, 0, "Level Meter",
1458-
(void *) meter_store, snd_usb_mixer_elem_free, NULL);
1444+
meter_store, true, NULL);
14591445
if (err < 0)
14601446
return err;
14611447
}

sound/usb/mixer_us16x08.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ struct snd_us16x08_control_params {
112112
int type;
113113
int num_channels;
114114
const char *name;
115-
void (*freeer)(struct snd_kcontrol *kctl);
116115
int default_val;
117116
};
118117

0 commit comments

Comments
 (0)