lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260122111249.67319-1-mstrozek@opensource.cirrus.com>
Date: Thu, 22 Jan 2026 11:12:47 +0000
From: Maciej Strozek <mstrozek@...nsource.cirrus.com>
To: Jaroslav Kysela <perex@...ex.cz>, Takashi Iwai <tiwai@...e.com>
Cc: linux-kernel@...r.kernel.org, linux-sound@...r.kernel.org,
        patches@...nsource.cirrus.com, alsa-devel@...a-project.org,
        Maciej Strozek <mstrozek@...nsource.cirrus.com>
Subject: [PATCH v2] ALSA: control: add ioctl to retrieve full card components

The fixed-size components field in SNDRV_CTL_IOCTL_CARD_INFO can be too
small on systems with many audio devices.

Keep the existing struct snd_ctl_card_info ABI intact and add a new ioctl
to retrieve the full components string.

When the legacy components field is truncated, append '>' to indicate
that the full string is available via the new ioctl.

Link: https://github.com/alsa-project/alsa-lib/pull/494
Link: https://github.com/alsa-project/alsa-utils/pull/318
Suggested-by: Jaroslav Kysela <perex@...ex.cz>
Suggested-by: Takashi Iwai <tiwai@...e.com>
Signed-off-by: Maciej Strozek <mstrozek@...nsource.cirrus.com>
---
Changes for v2:
 - do not modify existing card->components field
 - add a new ioctl and struct to keep the full components string
 - handle the split/trim in snd_ctl_card_info()
---
 include/sound/core.h        |  4 +++-
 include/uapi/sound/asound.h | 15 ++++++++++++++-
 sound/core/control.c        | 34 +++++++++++++++++++++++++++++++++-
 sound/core/control_compat.c |  3 ++-
 sound/core/init.c           | 14 +++++++-------
 5 files changed, 59 insertions(+), 11 deletions(-)

diff --git a/include/sound/core.h b/include/sound/core.h
index 64327e971122..0b16e2cb3f53 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -15,6 +15,7 @@
 #include <linux/stringify.h>
 #include <linux/printk.h>
 #include <linux/xarray.h>
+#include <uapi/sound/asound.h>		/* SNDRV_CTL_COMPONENTS_LEN */

 /* number of supported soundcards */
 #ifdef CONFIG_SND_DYNAMIC_MINORS
@@ -88,7 +89,8 @@ struct snd_card {
 	char irq_descr[32];		/* Interrupt description */
 	char mixername[80];		/* mixer name */
 	char components[128];		/* card components delimited with
-								space */
+								space, truncated to 127 chars */
+	char components_extended[SNDRV_CTL_COMPONENTS_LEN];	/* full card components string */
 	struct module *module;		/* top-level module */

 	void *private_data;		/* private data for soundcard */
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index d3ce75ba938a..5645ea8bb8a4 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -1058,7 +1058,7 @@ struct snd_timer_tread {
  *                                                                          *
  ****************************************************************************/

-#define SNDRV_CTL_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 9)
+#define SNDRV_CTL_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 10)

 struct snd_ctl_card_info {
 	int card;			/* card number */
@@ -1072,6 +1072,18 @@ struct snd_ctl_card_info {
 	unsigned char components[128];	/* card components / fine identification, delimited with one space (AC97 etc..) */
 };

+/*
+ * Card components can exceed the fixed 128 bytes in snd_ctl_card_info.
+ * Use SNDRV_CTL_IOCTL_CARD_COMPONENTS to retrieve the full string.
+ */
+#define SNDRV_CTL_COMPONENTS_LEN	512
+
+struct snd_ctl_card_components {
+	int card;			/* card number */
+	unsigned int length;		/* returned length of components string */
+	unsigned char components[SNDRV_CTL_COMPONENTS_LEN];
+};
+
 typedef int __bitwise snd_ctl_elem_type_t;
 #define	SNDRV_CTL_ELEM_TYPE_NONE	((__force snd_ctl_elem_type_t) 0) /* invalid */
 #define	SNDRV_CTL_ELEM_TYPE_BOOLEAN	((__force snd_ctl_elem_type_t) 1) /* boolean type */
@@ -1198,6 +1210,7 @@ struct snd_ctl_tlv {

 #define SNDRV_CTL_IOCTL_PVERSION	_IOR('U', 0x00, int)
 #define SNDRV_CTL_IOCTL_CARD_INFO	_IOR('U', 0x01, struct snd_ctl_card_info)
+#define SNDRV_CTL_IOCTL_CARD_COMPONENTS	_IOWR('U', 0x02, struct snd_ctl_card_components)
 #define SNDRV_CTL_IOCTL_ELEM_LIST	_IOWR('U', 0x10, struct snd_ctl_elem_list)
 #define SNDRV_CTL_IOCTL_ELEM_INFO	_IOWR('U', 0x11, struct snd_ctl_elem_info)
 #define SNDRV_CTL_IOCTL_ELEM_READ	_IOWR('U', 0x12, struct snd_ctl_elem_value)
diff --git a/sound/core/control.c b/sound/core/control.c
index 9c3fd5113a61..0f0d9828aeb1 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -868,10 +868,14 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
 			     unsigned int cmd, void __user *arg)
 {
 	struct snd_ctl_card_info *info __free(kfree) = NULL;
+	ssize_t n;

 	info = kzalloc(sizeof(*info), GFP_KERNEL);
 	if (! info)
 		return -ENOMEM;
+
+	static_assert(sizeof(info->components) >= 2);
+
 	scoped_guard(rwsem_read, &snd_ioctl_rwsem) {
 		info->card = card->number;
 		strscpy(info->id, card->id, sizeof(info->id));
@@ -879,13 +883,39 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
 		strscpy(info->name, card->shortname, sizeof(info->name));
 		strscpy(info->longname, card->longname, sizeof(info->longname));
 		strscpy(info->mixername, card->mixername, sizeof(info->mixername));
-		strscpy(info->components, card->components, sizeof(info->components));
+		n = strscpy(info->components, card->components_extended,
+			    sizeof(info->components));
+		if (n < 0) {
+			info->components[sizeof(info->components) - 2] = '>';
+			info->components[sizeof(info->components) - 1] = '\0';
+		}
 	}
 	if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info)))
 		return -EFAULT;
 	return 0;
 }

+static int snd_ctl_card_components(struct snd_card *card, void __user *arg)
+{
+	struct snd_ctl_card_components *info __free(kfree) = NULL;
+	int copied;
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	scoped_guard(rwsem_read, &snd_ioctl_rwsem) {
+		info->card = card->number;
+		copied = strscpy(info->components, card->components_extended,
+				 sizeof(info->components));
+		info->length = copied;
+	}
+
+	if (copy_to_user(arg, info, sizeof(*info)))
+		return -EFAULT;
+	return 0;
+}
+
 static int snd_ctl_elem_list(struct snd_card *card,
 			     struct snd_ctl_elem_list *list)
 {
@@ -1914,6 +1944,8 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
 		return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0;
 	case SNDRV_CTL_IOCTL_CARD_INFO:
 		return snd_ctl_card_info(card, ctl, cmd, argp);
+	case SNDRV_CTL_IOCTL_CARD_COMPONENTS:
+		return snd_ctl_card_components(card, argp);
 	case SNDRV_CTL_IOCTL_ELEM_LIST:
 		return snd_ctl_elem_list_user(card, argp);
 	case SNDRV_CTL_IOCTL_ELEM_INFO:
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index 6459809ed364..edb7b28d8177 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -416,7 +416,7 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file,
 		break;
 	}
 	return snd_ctl_elem_add(file, data, replace);
-}
+}

 enum {
 	SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct snd_ctl_elem_list32),
@@ -445,6 +445,7 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
 	switch (cmd) {
 	case SNDRV_CTL_IOCTL_PVERSION:
 	case SNDRV_CTL_IOCTL_CARD_INFO:
+	case SNDRV_CTL_IOCTL_CARD_COMPONENTS:
 	case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
 	case SNDRV_CTL_IOCTL_POWER:
 	case SNDRV_CTL_IOCTL_POWER_STATE:
diff --git a/sound/core/init.c b/sound/core/init.c
index c372b3228785..3ec2f08ba765 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -714,7 +714,7 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
 	int len, loops;
 	bool is_default = false;
 	char *id;
-
+
 	copy_valid_id_string(card, src, nid);
 	id = card->id;

@@ -1023,24 +1023,24 @@ int __init snd_card_info_init(void)
  *
  *  Return: Zero otherwise a negative error code.
  */
-
+
 int snd_component_add(struct snd_card *card, const char *component)
 {
 	char *ptr;
 	int len = strlen(component);

-	ptr = strstr(card->components, component);
+	ptr = strstr(card->components_extended, component);
 	if (ptr != NULL) {
 		if (ptr[len] == '\0' || ptr[len] == ' ')	/* already there */
 			return 1;
 	}
-	if (strlen(card->components) + 1 + len + 1 > sizeof(card->components)) {
+	if (strlen(card->components_extended) + 1 + len + 1 > sizeof(card->components_extended)) {
 		snd_BUG();
 		return -ENOMEM;
 	}
-	if (card->components[0] != '\0')
-		strcat(card->components, " ");
-	strcat(card->components, component);
+	if (card->components_extended[0] != '\0')
+		strcat(card->components_extended, " ");
+	strcat(card->components_extended, component);
 	return 0;
 }
 EXPORT_SYMBOL(snd_component_add);
--
2.48.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ