From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793802757; b=O953rQWpPWVHZEEkso3elpVQ/Q7wZdcL0sY7+KJHawTLHzndRhWyk2oDKthyUcxqCEHk ySVELEG/aAUolqPTt/U7T43U9EieDSFXvg2aso0nC5fOGtVJEpMxJlKClmMrWdYCLnXQG yWSgpNOQuEu2zOt1oIbEsSMJjACu57GHo8FvtEdKWiqR+yh7dqQlRchruHsZDHIxZqPor r6PZPZTPm0nrxp9EWu0fWsjoCb0Wx2OxlHjlErer1miSQGa4FYjKHJu+Wfh/76I3x6mt7 7S640SJ4Ih2jguC3tsSF2wb3mrLFz68syU/xB+7rhC1ESOgYcKbGmXHi/mJuAn9gxBQ== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793802757; h=Received:DKIM-Signature:Subject:To:Cc:From:Date:Message-ID: MIME-Version:Content-Type:Content-Transfer-Encoding; bh=ID2kUMndXIo1xjH44ZfqohE0V8EPk266zWvrP99Pp7k=; b=YivnBR7NkGcpAE2OeT1+fVOJNnUGICvuGCxUWcz6qwxfyspAlYbfu5iChO3u/I2z7wEF nBS8Fh90CXPa53nxnskpFX2oDZG2vuKpBJM+Zeg82iadnul4Fa5G/d3mdjLbYvthCN8F8 d7vqKNq16uIb8KyxjnDnQenVwdrV9I7raXQ4ceKQMxLO0tQLijeQ3W4gxr/Yja4mCT6TK FYw282HWQZLtgZx6qnhQF4GKQoinl+kxHJVZ1Tx4j+uR5HmRbMLMcMRI+5d721jl8asjx WapMTWX0wnFNRMqF7oFJlUgqPxQEevdxVKNUOqfWyM6EgsVg9u845Ra/z1b0WbacQdw== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=ZEGzNGT5; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B7450606A31B for ; Wed, 4 Nov 2026 14:32:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key, unprotected) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=ZEGzNGT5 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 177121F000C1; Wed, 4 Nov 2026 14:32:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1793802756; bh=ID2kUMndXIo1xjH44ZfqohE0V8EPk266zWvrP99Pp7k=; h=Subject:To:Cc:From:Date; b=ZEGzNGT5RuYEnCnjGpvitx+LYNiNZwFMXITjd4K62BuXG17ZqG7jzGK+ggwn8lF3E HqUMQylxxfD7a+ElIM7J5pBrYTcf7uBgh4y01zjCUxp4ZUF+GIvRXbN5RO1f+1C+I1 fx1IRXYT/QT/vw4VU1A77sLeGexlWSxV5mVOieEo= Subject: FAILED: patch "[PATCH] media: rc: Add missing locking for keymap" failed to apply to 6.12-stable tree To: sean@mess.org,hverkuil+cisco@kernel.org Cc: From: Date: Wed, 04 Nov 2026 15:32:25 +0100 Message-ID: <2026110425-mowing-scuff-ddb6@gregkh> X-Mailing-List: stable@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=ANSI_X3.4-1968 Content-Transfer-Encoding: 8bit The patch below does not apply to the 6.12-stable tree. If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to . To reproduce the conflict and resubmit, you may use the following commands: git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y git checkout FETCH_HEAD git cherry-pick -x ab9567336171e46ce9e03ee126902b3fd7901baa # git commit -s git send-email --to '' --in-reply-to '2026110425-mowing-scuff-ddb6@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..' Possible dependencies: thanks, greg k-h ------------------ original commit in Linus's tree ------------------ >From ab9567336171e46ce9e03ee126902b3fd7901baa Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 12 Aug 2026 14:03:10 +0100 Subject: [PATCH] media: rc: Add missing locking for keymap When the rc_map for an rc_dev gets updated, locking is required but is missing in places. A concurrent scancode lookup and a call to rc_{register,unregistered}_device() could result in a use-after-free; this could happen if IR is decoded during those function calls. Add lockdep assertions where locks are required. ir_free_table() should only be called for non-TX devices else we will use a spinlock without iniitializing it. Fixes: dccc0c3ddf8f ("media: rc: fix race between unregister and urb/irq callbacks") Signed-off-by: Sean Young Cc: stable@vger.kernel.org Acked-by: Hans Verkuil diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 53e39b7a489a..67d86b8ea5e0 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -104,7 +104,6 @@ static struct rc_map_list *seek_rc_map(const char *name) struct rc_map *rc_map_get(const char *name) { - struct rc_map_list *map; map = seek_rc_map(name); @@ -201,7 +200,7 @@ static int scancode_to_u64(const struct input_keymap_entry *ke, u64 *scancode) * ir_create_table() - initializes a scancode table * @dev: the rc_dev device * @rc_map: the rc_map to initialize - * @name: name to assign to the table + * @map_name: name to assign to the table * @rc_proto: ir type to assign to the new table * @size: initial size of the table * @@ -211,23 +210,31 @@ static int scancode_to_u64(const struct input_keymap_entry *ke, u64 *scancode) * return: zero on success or a negative error code */ static int ir_create_table(struct rc_dev *dev, struct rc_map *rc_map, - const char *name, u64 rc_proto, size_t size) + const char *map_name, u64 rc_proto, size_t size) { + struct rc_map_table *scan; unsigned int alloc; - rc_map->name = kstrdup(name, GFP_KERNEL); - if (!rc_map->name) + char *name; + + name = kstrdup(map_name, GFP_KERNEL); + if (!name) return -ENOMEM; + alloc = roundup_pow_of_two(size); - rc_map->rc_proto = rc_proto; - rc_map->len = 0; - rc_map->size = alloc; - rc_map->scan = kmalloc_objs(struct rc_map_table, alloc, GFP_KERNEL); - if (!rc_map->scan) { - kfree(rc_map->name); - rc_map->name = NULL; + scan = kmalloc_objs(struct rc_map_table, alloc, GFP_KERNEL); + if (!scan) { + kfree(name); return -ENOMEM; } + scoped_guard(spinlock_irqsave, &rc_map->lock) { + rc_map->name = name; + rc_map->scan = scan; + rc_map->rc_proto = rc_proto; + rc_map->len = 0; + rc_map->size = alloc; + } + dev_dbg(&dev->dev, "Allocated space for %u keycode entries (%zu bytes)\n", alloc, alloc * sizeof(struct rc_map_table)); return 0; @@ -237,16 +244,26 @@ static int ir_create_table(struct rc_dev *dev, struct rc_map *rc_map, * ir_free_table() - frees memory allocated by a scancode table * @rc_map: the table whose mappings need to be freed * - * This routine will free memory alloctaed for key mappings used by given + * This routine will free memory allocated for key mappings used by given * scancode table. */ static void ir_free_table(struct rc_map *rc_map) { - rc_map->size = 0; - kfree(rc_map->name); - rc_map->name = NULL; - kfree(rc_map->scan); - rc_map->scan = NULL; + struct rc_map_table *scan; + const char *name; + + scoped_guard(spinlock_irqsave, &rc_map->lock) { + name = rc_map->name; + scan = rc_map->scan; + + rc_map->size = 0; + rc_map->len = 0; + rc_map->name = NULL; + rc_map->scan = NULL; + } + + kfree(name); + kfree(scan); } /** @@ -266,6 +283,8 @@ static int ir_resize_table(struct rc_dev *dev, struct rc_map *rc_map, unsigned int newsize = rc_map->size; struct rc_map_table *newscan; + lockdep_assert_held(&rc_map->lock); + if (rc_map->size == rc_map->len) { /* All entries in use -> grow keytable */ if (newsize >= IR_TAB_MAX_ENTRIES) @@ -317,6 +336,8 @@ static unsigned int ir_update_mapping(struct rc_dev *dev, int old_keycode = rc_map->scan[index].keycode; int i; + lockdep_assert_held(&rc_map->lock); + /* Did the user wish to remove the mapping? */ if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) { dev_dbg(&dev->dev, "#%d: Deleting scan 0x%04llx\n", @@ -372,6 +393,8 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev, { unsigned int i; + lockdep_assert_held(&rc_map->lock); + /* * Unfortunately, some hardware-based IR decoders don't provide * all bits for the complete IR code. In general, they provide only @@ -396,7 +419,7 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev, /* No previous mapping found, we might need to grow the table */ if (rc_map->size == rc_map->len) { if (!resize || ir_resize_table(dev, rc_map, GFP_ATOMIC)) - return -1U; + return UINT_MAX; } /* i is the proper index to insert our new keycode */ @@ -478,16 +501,18 @@ static int ir_setkeytable(struct rc_dev *dev, const struct rc_map *from) if (rc) return rc; - for (i = 0; i < from->size; i++) { - index = ir_establish_scancode(dev, rc_map, - from->scan[i].scancode, false); - if (index >= rc_map->len) { - rc = -ENOMEM; - break; - } + scoped_guard(spinlock_irqsave, &rc_map->lock) { + for (i = 0; i < from->size; i++) { + index = ir_establish_scancode(dev, rc_map, + from->scan[i].scancode, false); + if (index >= rc_map->len) { + rc = -ENOMEM; + break; + } - ir_update_mapping(dev, rc_map, index, - from->scan[i].keycode); + ir_update_mapping(dev, rc_map, index, + from->scan[i].keycode); + } } if (rc) @@ -523,6 +548,8 @@ static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map, { struct rc_map_table *res; + lockdep_assert_held(&rc_map->lock); + res = bsearch(&scancode, rc_map->scan, rc_map->len, sizeof(struct rc_map_table), rc_map_cmp); if (!res) @@ -1989,7 +2016,8 @@ out_rx_free: scoped_guard(mutex, &dev->lock) dev->registered = false; out_free_table: - ir_free_table(&dev->rc_map); + if (dev->driver_type != RC_DRIVER_IR_RAW_TX) + ir_free_table(&dev->rc_map); out_raw: ida_free(&rc_ida, minor); return rc;