mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
ALSA: virtio: Validate control metadata from the device
virtio-snd control handling trusts the device-provided control type and
value count returned by the device.
That metadata is then used directly to index g_v2a_type_map[] in
virtsnd_kctl_info(), and to size loops and memcpy() operations in
virtsnd_kctl_get() and virtsnd_kctl_put() against fixed-size
virtio_snd_ctl_value and snd_ctl_elem_value arrays.
A buggy or malicious device can therefore trigger out-of-bounds access by
advertising an invalid control type or an oversized value count.
Validate control type and count once in virtsnd_kctl_parse_cfg(), before
querying enumerated items or exposing the control to ALSA.
Fixes: d6568e3de4 ("ALSA: virtio: add support for audio controls")
Cc: stable@vger.kernel.org
Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
Link: https://patch.msgid.link/20260507-alsa-virtio-validate-kctl-info-v1-1-7404fb12ec37@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
0cf8217272
commit
c77a6cbb36
|
|
@ -18,6 +18,21 @@ static const snd_ctl_elem_type_t g_v2a_type_map[] = {
|
|||
[VIRTIO_SND_CTL_TYPE_IEC958] = SNDRV_CTL_ELEM_TYPE_IEC958
|
||||
};
|
||||
|
||||
/* Map for converting VirtIO types to maximum value counts. */
|
||||
static const unsigned int g_v2a_count_map[] = {
|
||||
[VIRTIO_SND_CTL_TYPE_BOOLEAN] =
|
||||
ARRAY_SIZE(((struct virtio_snd_ctl_value *)0)->value.integer),
|
||||
[VIRTIO_SND_CTL_TYPE_INTEGER] =
|
||||
ARRAY_SIZE(((struct virtio_snd_ctl_value *)0)->value.integer),
|
||||
[VIRTIO_SND_CTL_TYPE_INTEGER64] =
|
||||
ARRAY_SIZE(((struct virtio_snd_ctl_value *)0)->value.integer64),
|
||||
[VIRTIO_SND_CTL_TYPE_ENUMERATED] =
|
||||
ARRAY_SIZE(((struct virtio_snd_ctl_value *)0)->value.enumerated),
|
||||
[VIRTIO_SND_CTL_TYPE_BYTES] =
|
||||
ARRAY_SIZE(((struct virtio_snd_ctl_value *)0)->value.bytes),
|
||||
[VIRTIO_SND_CTL_TYPE_IEC958] = 1
|
||||
};
|
||||
|
||||
/* Map for converting VirtIO access rights to ALSA access rights. */
|
||||
static const unsigned int g_v2a_access_map[] = {
|
||||
[VIRTIO_SND_CTL_ACCESS_READ] = SNDRV_CTL_ELEM_ACCESS_READ,
|
||||
|
|
@ -36,6 +51,37 @@ static const unsigned int g_v2a_mask_map[] = {
|
|||
[VIRTIO_SND_CTL_EVT_MASK_TLV] = SNDRV_CTL_EVENT_MASK_TLV
|
||||
};
|
||||
|
||||
static int virtsnd_kctl_validate_info(struct virtio_snd *snd, u32 cid,
|
||||
struct virtio_snd_ctl_info *kinfo)
|
||||
{
|
||||
struct virtio_device *vdev = snd->vdev;
|
||||
unsigned int type = le32_to_cpu(kinfo->type);
|
||||
unsigned int count = le32_to_cpu(kinfo->count);
|
||||
|
||||
if (type >= ARRAY_SIZE(g_v2a_type_map)) {
|
||||
dev_err(&vdev->dev, "control #%u: unknown type %u\n",
|
||||
cid, type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (count > g_v2a_count_map[type] ||
|
||||
(type == VIRTIO_SND_CTL_TYPE_IEC958 && count != 1)) {
|
||||
dev_err(&vdev->dev, "control #%u: invalid count %u for type %u\n",
|
||||
cid, count, type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (type == VIRTIO_SND_CTL_TYPE_ENUMERATED &&
|
||||
!le32_to_cpu(kinfo->value.enumerated.items)) {
|
||||
dev_err(&vdev->dev,
|
||||
"control #%u: no items for enumerated control\n",
|
||||
cid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* virtsnd_kctl_info() - Returns information about the control.
|
||||
* @kcontrol: ALSA control element.
|
||||
|
|
@ -385,6 +431,10 @@ int virtsnd_kctl_parse_cfg(struct virtio_snd *snd)
|
|||
struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[i];
|
||||
unsigned int type = le32_to_cpu(kinfo->type);
|
||||
|
||||
rc = virtsnd_kctl_validate_info(snd, i, kinfo);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (type == VIRTIO_SND_CTL_TYPE_ENUMERATED) {
|
||||
rc = virtsnd_kctl_get_enum_items(snd, i);
|
||||
if (rc)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user