Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: usb-audio: Add input value sanity checks for standard types

For an invalid input value that is out of the given range, currently
USB-audio driver corrects the value silently and accepts without
errors. This is no wrong behavior, per se, but the recent kselftest
rather wants to have an error in such a case, hence a different
behavior is expected now.

This patch adds a sanity check at each control put for the standard
mixer types and returns an error if an invalid value is given.

Note that this covers only the standard mixer types. The mixer quirks
that have own control callbacks would need different coverage.

Link: https://patch.msgid.link/20240806124651.28203-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>

+28 -8
+27 -8
sound/usb/mixer.c
··· 1377 1377 1378 1378 #define get_min_max(cval, def) get_min_max_with_quirks(cval, def, NULL) 1379 1379 1380 + /* get the max value advertised via control API */ 1381 + static int get_max_exposed(struct usb_mixer_elem_info *cval) 1382 + { 1383 + if (!cval->max_exposed) { 1384 + if (cval->res) 1385 + cval->max_exposed = 1386 + DIV_ROUND_UP(cval->max - cval->min, cval->res); 1387 + else 1388 + cval->max_exposed = cval->max - cval->min; 1389 + } 1390 + return cval->max_exposed; 1391 + } 1392 + 1380 1393 /* get a feature/mixer unit info */ 1381 1394 static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, 1382 1395 struct snd_ctl_elem_info *uinfo) ··· 1402 1389 else 1403 1390 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 1404 1391 uinfo->count = cval->channels; 1405 - if (cval->val_type == USB_MIXER_BOOLEAN || 1406 - cval->val_type == USB_MIXER_INV_BOOLEAN) { 1407 - uinfo->value.integer.min = 0; 1408 - uinfo->value.integer.max = 1; 1409 - } else { 1392 + if (cval->val_type != USB_MIXER_BOOLEAN && 1393 + cval->val_type != USB_MIXER_INV_BOOLEAN) { 1410 1394 if (!cval->initialized) { 1411 1395 get_min_max_with_quirks(cval, 0, kcontrol); 1412 1396 if (cval->initialized && cval->dBmin >= cval->dBmax) { ··· 1415 1405 &kcontrol->id); 1416 1406 } 1417 1407 } 1418 - uinfo->value.integer.min = 0; 1419 - uinfo->value.integer.max = 1420 - DIV_ROUND_UP(cval->max - cval->min, cval->res); 1421 1408 } 1409 + 1410 + uinfo->value.integer.min = 0; 1411 + uinfo->value.integer.max = get_max_exposed(cval); 1422 1412 return 0; 1423 1413 } 1424 1414 ··· 1459 1449 struct snd_ctl_elem_value *ucontrol) 1460 1450 { 1461 1451 struct usb_mixer_elem_info *cval = kcontrol->private_data; 1452 + int max_val = get_max_exposed(cval); 1462 1453 int c, cnt, val, oval, err; 1463 1454 int changed = 0; 1464 1455 ··· 1472 1461 if (err < 0) 1473 1462 return filter_error(cval, err); 1474 1463 val = ucontrol->value.integer.value[cnt]; 1464 + if (val < 0 || val > max_val) 1465 + return -EINVAL; 1475 1466 val = get_abs_value(cval, val); 1476 1467 if (oval != val) { 1477 1468 snd_usb_set_cur_mix_value(cval, c + 1, cnt, val); ··· 1487 1474 if (err < 0) 1488 1475 return filter_error(cval, err); 1489 1476 val = ucontrol->value.integer.value[0]; 1477 + if (val < 0 || val > max_val) 1478 + return -EINVAL; 1490 1479 val = get_abs_value(cval, val); 1491 1480 if (val != oval) { 1492 1481 snd_usb_set_cur_mix_value(cval, 0, 0, val); ··· 2352 2337 if (err < 0) 2353 2338 return filter_error(cval, err); 2354 2339 val = ucontrol->value.integer.value[0]; 2340 + if (val < 0 || val > get_max_exposed(cval)) 2341 + return -EINVAL; 2355 2342 val = get_abs_value(cval, val); 2356 2343 if (val != oval) { 2357 2344 set_cur_ctl_value(cval, cval->control << 8, val); ··· 2716 2699 if (err < 0) 2717 2700 return filter_error(cval, err); 2718 2701 val = ucontrol->value.enumerated.item[0]; 2702 + if (val < 0 || val >= cval->max) /* here cval->max = # elements */ 2703 + return -EINVAL; 2719 2704 val = get_abs_value(cval, val); 2720 2705 if (val != oval) { 2721 2706 set_cur_ctl_value(cval, cval->control << 8, val);
+1
sound/usb/mixer.h
··· 88 88 int channels; 89 89 int val_type; 90 90 int min, max, res; 91 + int max_exposed; /* control API exposes the value in 0..max_exposed */ 91 92 int dBmin, dBmax; 92 93 int cached; 93 94 int cache_val[MAX_CHANNELS];