aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
authorCássio Gabriel <cassiogabrielcontato@gmail.com>2026-05-07 11:28:30 -0300
committerTakashi Iwai <tiwai@suse.de>2026-05-15 11:21:20 +0200
commitc77a6cbb36ff8cbc1f084d94f8dcda5250935271 (patch)
tree8589a63bd9f37b4a1655b2474d986521f588d550 /sound
parent0cf821727205109ff2119d2bbd45fef8239f7e2c (diff)
downloadlinux-next-history-c77a6cbb36ff8cbc1f084d94f8dcda5250935271.tar.gz
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: d6568e3de42d ("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>
Diffstat (limited to 'sound')
-rw-r--r--sound/virtio/virtio_kctl.c50
1 files changed, 50 insertions, 0 deletions
diff --git a/sound/virtio/virtio_kctl.c b/sound/virtio/virtio_kctl.c
index ffb903d56297a..45f7b6a5b3080 100644
--- a/sound/virtio/virtio_kctl.c
+++ b/sound/virtio/virtio_kctl.c
@@ -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)