summaryrefslogtreecommitdiff
path: root/sound/core/seq/seq_clientmgr.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/seq/seq_clientmgr.c')
-rw-r--r--sound/core/seq/seq_clientmgr.c33
1 files changed, 28 insertions, 5 deletions
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 46a1ded7eb06..0c31b19dd948 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -441,6 +441,7 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count,
memcpy(&tmpev, &cell->event, aligned_size);
tmpev.data.ext.len &= ~SNDRV_SEQ_EXT_MASK;
+ tmpev.data.ext.ptr = NULL;
if (copy_to_user(buf, &tmpev, aligned_size)) {
err = -EFAULT;
break;
@@ -537,16 +538,38 @@ static int bounce_error_event(struct snd_seq_client *client,
/* set up quoted error */
memset(&bounce_ev, 0, sizeof(bounce_ev));
- bounce_ev.type = SNDRV_SEQ_EVENT_KERNEL_ERROR;
- bounce_ev.flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
+
+ if (client->type == USER_CLIENT) {
+ /*
+ * For user clients, send SNDRV_SEQ_EVENT_BOUNCE with the
+ * original event embedded as variable-length data. This
+ * avoids exposing data.quote.event (a kernel pointer) to
+ * userspace. The variable-length path in snd_seq_event_dup()
+ * copies the event data from data.ext.ptr into chained cells,
+ * and snd_seq_expand_var_event() copies only the data content
+ * -- never the pointer -- to userspace.
+ */
+ bounce_ev.type = SNDRV_SEQ_EVENT_BOUNCE;
+ bounce_ev.flags = SNDRV_SEQ_EVENT_LENGTH_VARIABLE;
+ bounce_ev.data.ext.len = sizeof(struct snd_seq_event);
+ bounce_ev.data.ext.ptr = (char *)event;
+ } else {
+ /*
+ * For kernel clients, quote the event pointer directly.
+ * Kernel consumers can safely dereference the pointer.
+ */
+ bounce_ev.type = SNDRV_SEQ_EVENT_KERNEL_ERROR;
+ bounce_ev.flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
+ bounce_ev.data.quote.origin = event->dest;
+ bounce_ev.data.quote.event = event;
+ bounce_ev.data.quote.value = -err; /* use positive value */
+ }
+
bounce_ev.queue = SNDRV_SEQ_QUEUE_DIRECT;
bounce_ev.source.client = SNDRV_SEQ_CLIENT_SYSTEM;
bounce_ev.source.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
bounce_ev.dest.client = client->number;
bounce_ev.dest.port = event->source.port;
- bounce_ev.data.quote.origin = event->dest;
- bounce_ev.data.quote.event = event;
- bounce_ev.data.quote.value = -err; /* use positive value */
result = snd_seq_deliver_single_event(NULL, &bounce_ev, atomic, hop + 1);
if (result < 0) {
client->event_lost++;