--- /dev/null
+From b909df18ce2a998afef81d58bbd1a05dc0788c40 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Beno=C3=AEt=20Sevens?= <bsevens@google.com>
+Date: Wed, 20 Nov 2024 12:41:44 +0000
+Subject: ALSA: usb-audio: Fix potential out-of-bound accesses for Extigy and Mbox devices
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Benoît Sevens <bsevens@google.com>
+
+commit b909df18ce2a998afef81d58bbd1a05dc0788c40 upstream.
+
+A bogus device can provide a bNumConfigurations value that exceeds the
+initial value used in usb_get_configuration for allocating dev->config.
+
+This can lead to out-of-bounds accesses later, e.g. in
+usb_destroy_configuration.
+
+Signed-off-by: Benoît Sevens <bsevens@google.com>
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Cc: stable@kernel.org
+Link: https://patch.msgid.link/20241120124144.3814457-1-bsevens@google.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/usb/quirks.c | 27 +++++++++++++++++++++------
+ 1 file changed, 21 insertions(+), 6 deletions(-)
+
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -555,6 +555,7 @@ int snd_usb_create_quirk(struct snd_usb_
+ static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interface *intf)
+ {
+ struct usb_host_config *config = dev->actconfig;
++ struct usb_device_descriptor new_device_descriptor;
+ int err;
+
+ if (le16_to_cpu(get_cfg_desc(config)->wTotalLength) == EXTIGY_FIRMWARE_SIZE_OLD ||
+@@ -566,10 +567,14 @@ static int snd_usb_extigy_boot_quirk(str
+ if (err < 0)
+ dev_dbg(&dev->dev, "error sending boot message: %d\n", err);
+ err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
+- &dev->descriptor, sizeof(dev->descriptor));
+- config = dev->actconfig;
++ &new_device_descriptor, sizeof(new_device_descriptor));
+ if (err < 0)
+ dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err);
++ if (new_device_descriptor.bNumConfigurations > dev->descriptor.bNumConfigurations)
++ dev_dbg(&dev->dev, "error too large bNumConfigurations: %d\n",
++ new_device_descriptor.bNumConfigurations);
++ else
++ memcpy(&dev->descriptor, &new_device_descriptor, sizeof(dev->descriptor));
+ err = usb_reset_configuration(dev);
+ if (err < 0)
+ dev_dbg(&dev->dev, "error usb_reset_configuration: %d\n", err);
+@@ -901,6 +906,7 @@ static void mbox2_setup_48_24_magic(stru
+ static int snd_usb_mbox2_boot_quirk(struct usb_device *dev)
+ {
+ struct usb_host_config *config = dev->actconfig;
++ struct usb_device_descriptor new_device_descriptor;
+ int err;
+ u8 bootresponse[0x12];
+ int fwsize;
+@@ -936,10 +942,14 @@ static int snd_usb_mbox2_boot_quirk(stru
+ dev_dbg(&dev->dev, "device initialised!\n");
+
+ err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
+- &dev->descriptor, sizeof(dev->descriptor));
+- config = dev->actconfig;
++ &new_device_descriptor, sizeof(new_device_descriptor));
+ if (err < 0)
+ dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err);
++ if (new_device_descriptor.bNumConfigurations > dev->descriptor.bNumConfigurations)
++ dev_dbg(&dev->dev, "error too large bNumConfigurations: %d\n",
++ new_device_descriptor.bNumConfigurations);
++ else
++ memcpy(&dev->descriptor, &new_device_descriptor, sizeof(dev->descriptor));
+
+ err = usb_reset_configuration(dev);
+ if (err < 0)
+@@ -1253,6 +1263,7 @@ static void mbox3_setup_48_24_magic(stru
+ static int snd_usb_mbox3_boot_quirk(struct usb_device *dev)
+ {
+ struct usb_host_config *config = dev->actconfig;
++ struct usb_device_descriptor new_device_descriptor;
+ int err;
+ int descriptor_size;
+
+@@ -1266,10 +1277,14 @@ static int snd_usb_mbox3_boot_quirk(stru
+ dev_dbg(&dev->dev, "device initialised!\n");
+
+ err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
+- &dev->descriptor, sizeof(dev->descriptor));
+- config = dev->actconfig;
++ &new_device_descriptor, sizeof(new_device_descriptor));
+ if (err < 0)
+ dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err);
++ if (new_device_descriptor.bNumConfigurations > dev->descriptor.bNumConfigurations)
++ dev_dbg(&dev->dev, "error too large bNumConfigurations: %d\n",
++ new_device_descriptor.bNumConfigurations);
++ else
++ memcpy(&dev->descriptor, &new_device_descriptor, sizeof(dev->descriptor));
+
+ err = usb_reset_configuration(dev);
+ if (err < 0)
--- /dev/null
+From bb3868033a4cccff7be57e9145f2117cbdc91c11 Mon Sep 17 00:00:00 2001
+From: Filipe Manana <fdmanana@suse.com>
+Date: Fri, 14 Jun 2024 14:50:47 +0100
+Subject: btrfs: do not BUG_ON() when freeing tree block after error
+
+From: Filipe Manana <fdmanana@suse.com>
+
+commit bb3868033a4cccff7be57e9145f2117cbdc91c11 upstream.
+
+When freeing a tree block, at btrfs_free_tree_block(), if we fail to
+create a delayed reference we don't deal with the error and just do a
+BUG_ON(). The error most likely to happen is -ENOMEM, and we have a
+comment mentioning that only -ENOMEM can happen, but that is not true,
+because in case qgroups are enabled any error returned from
+btrfs_qgroup_trace_extent_post() (can be -EUCLEAN or anything returned
+from btrfs_search_slot() for example) can be propagated back to
+btrfs_free_tree_block().
+
+So stop doing a BUG_ON() and return the error to the callers and make
+them abort the transaction to prevent leaking space. Syzbot was
+triggering this, likely due to memory allocation failure injection.
+
+Reported-by: syzbot+a306f914b4d01b3958fe@syzkaller.appspotmail.com
+Link: https://lore.kernel.org/linux-btrfs/000000000000fcba1e05e998263c@google.com/
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[ Resolve minor conflicts ]
+Signed-off-by: Bin Lan <bin.lan.cn@windriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/ctree.c | 51 ++++++++++++++++++++++++++++++++++++---------
+ fs/btrfs/extent-tree.c | 22 +++++++++++--------
+ fs/btrfs/extent-tree.h | 8 +++----
+ fs/btrfs/free-space-tree.c | 10 ++++++--
+ fs/btrfs/ioctl.c | 6 ++++-
+ fs/btrfs/qgroup.c | 6 +++--
+ 6 files changed, 74 insertions(+), 29 deletions(-)
+
+--- a/fs/btrfs/ctree.c
++++ b/fs/btrfs/ctree.c
+@@ -617,10 +617,16 @@ static noinline int __btrfs_cow_block(st
+ atomic_inc(&cow->refs);
+ rcu_assign_pointer(root->node, cow);
+
+- btrfs_free_tree_block(trans, btrfs_root_id(root), buf,
+- parent_start, last_ref);
++ ret = btrfs_free_tree_block(trans, btrfs_root_id(root), buf,
++ parent_start, last_ref);
+ free_extent_buffer(buf);
+ add_root_to_dirty_list(root);
++ if (ret < 0) {
++ btrfs_tree_unlock(cow);
++ free_extent_buffer(cow);
++ btrfs_abort_transaction(trans, ret);
++ return ret;
++ }
+ } else {
+ WARN_ON(trans->transid != btrfs_header_generation(parent));
+ ret = btrfs_tree_mod_log_insert_key(parent, parent_slot,
+@@ -645,8 +651,14 @@ static noinline int __btrfs_cow_block(st
+ return ret;
+ }
+ }
+- btrfs_free_tree_block(trans, btrfs_root_id(root), buf,
+- parent_start, last_ref);
++ ret = btrfs_free_tree_block(trans, btrfs_root_id(root), buf,
++ parent_start, last_ref);
++ if (ret < 0) {
++ btrfs_tree_unlock(cow);
++ free_extent_buffer(cow);
++ btrfs_abort_transaction(trans, ret);
++ return ret;
++ }
+ }
+ if (unlock_orig)
+ btrfs_tree_unlock(buf);
+@@ -1121,9 +1133,13 @@ static noinline int balance_level(struct
+ free_extent_buffer(mid);
+
+ root_sub_used(root, mid->len);
+- btrfs_free_tree_block(trans, btrfs_root_id(root), mid, 0, 1);
++ ret = btrfs_free_tree_block(trans, btrfs_root_id(root), mid, 0, 1);
+ /* once for the root ptr */
+ free_extent_buffer_stale(mid);
++ if (ret < 0) {
++ btrfs_abort_transaction(trans, ret);
++ goto out;
++ }
+ return 0;
+ }
+ if (btrfs_header_nritems(mid) >
+@@ -1191,10 +1207,14 @@ static noinline int balance_level(struct
+ goto out;
+ }
+ root_sub_used(root, right->len);
+- btrfs_free_tree_block(trans, btrfs_root_id(root), right,
++ ret = btrfs_free_tree_block(trans, btrfs_root_id(root), right,
+ 0, 1);
+ free_extent_buffer_stale(right);
+ right = NULL;
++ if (ret < 0) {
++ btrfs_abort_transaction(trans, ret);
++ goto out;
++ }
+ } else {
+ struct btrfs_disk_key right_key;
+ btrfs_node_key(right, &right_key, 0);
+@@ -1249,9 +1269,13 @@ static noinline int balance_level(struct
+ goto out;
+ }
+ root_sub_used(root, mid->len);
+- btrfs_free_tree_block(trans, btrfs_root_id(root), mid, 0, 1);
++ ret = btrfs_free_tree_block(trans, btrfs_root_id(root), mid, 0, 1);
+ free_extent_buffer_stale(mid);
+ mid = NULL;
++ if (ret < 0) {
++ btrfs_abort_transaction(trans, ret);
++ goto out;
++ }
+ } else {
+ /* update the parent key to reflect our changes */
+ struct btrfs_disk_key mid_key;
+@@ -3022,7 +3046,11 @@ static noinline int insert_new_root(stru
+ old = root->node;
+ ret = btrfs_tree_mod_log_insert_root(root->node, c, false);
+ if (ret < 0) {
+- btrfs_free_tree_block(trans, btrfs_root_id(root), c, 0, 1);
++ int ret2;
++
++ ret2 = btrfs_free_tree_block(trans, btrfs_root_id(root), c, 0, 1);
++ if (ret2 < 0)
++ btrfs_abort_transaction(trans, ret2);
+ btrfs_tree_unlock(c);
+ free_extent_buffer(c);
+ return ret;
+@@ -4587,9 +4615,12 @@ static noinline int btrfs_del_leaf(struc
+ root_sub_used(root, leaf->len);
+
+ atomic_inc(&leaf->refs);
+- btrfs_free_tree_block(trans, btrfs_root_id(root), leaf, 0, 1);
++ ret = btrfs_free_tree_block(trans, btrfs_root_id(root), leaf, 0, 1);
+ free_extent_buffer_stale(leaf);
+- return 0;
++ if (ret < 0)
++ btrfs_abort_transaction(trans, ret);
++
++ return ret;
+ }
+ /*
+ * delete the item at the leaf level in path. If that empties
+--- a/fs/btrfs/extent-tree.c
++++ b/fs/btrfs/extent-tree.c
+@@ -3290,10 +3290,10 @@ out_delayed_unlock:
+ return 0;
+ }
+
+-void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
+- u64 root_id,
+- struct extent_buffer *buf,
+- u64 parent, int last_ref)
++int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
++ u64 root_id,
++ struct extent_buffer *buf,
++ u64 parent, int last_ref)
+ {
+ struct btrfs_fs_info *fs_info = trans->fs_info;
+ struct btrfs_ref generic_ref = { 0 };
+@@ -3307,7 +3307,8 @@ void btrfs_free_tree_block(struct btrfs_
+ if (root_id != BTRFS_TREE_LOG_OBJECTID) {
+ btrfs_ref_tree_mod(fs_info, &generic_ref);
+ ret = btrfs_add_delayed_tree_ref(trans, &generic_ref, NULL);
+- BUG_ON(ret); /* -ENOMEM */
++ if (ret < 0)
++ return ret;
+ }
+
+ if (last_ref && btrfs_header_generation(buf) == trans->transid) {
+@@ -3371,6 +3372,7 @@ out:
+ */
+ clear_bit(EXTENT_BUFFER_CORRUPT, &buf->bflags);
+ }
++ return 0;
+ }
+
+ /* Can return -ENOMEM */
+@@ -5474,7 +5476,7 @@ static noinline int walk_up_proc(struct
+ struct walk_control *wc)
+ {
+ struct btrfs_fs_info *fs_info = root->fs_info;
+- int ret;
++ int ret = 0;
+ int level = wc->level;
+ struct extent_buffer *eb = path->nodes[level];
+ u64 parent = 0;
+@@ -5565,12 +5567,14 @@ static noinline int walk_up_proc(struct
+ goto owner_mismatch;
+ }
+
+- btrfs_free_tree_block(trans, btrfs_root_id(root), eb, parent,
+- wc->refs[level] == 1);
++ ret = btrfs_free_tree_block(trans, btrfs_root_id(root), eb, parent,
++ wc->refs[level] == 1);
++ if (ret < 0)
++ btrfs_abort_transaction(trans, ret);
+ out:
+ wc->refs[level] = 0;
+ wc->flags[level] = 0;
+- return 0;
++ return ret;
+
+ owner_mismatch:
+ btrfs_err_rl(fs_info, "unexpected tree owner, have %llu expect %llu",
+--- a/fs/btrfs/extent-tree.h
++++ b/fs/btrfs/extent-tree.h
+@@ -114,10 +114,10 @@ struct extent_buffer *btrfs_alloc_tree_b
+ int level, u64 hint,
+ u64 empty_size,
+ enum btrfs_lock_nesting nest);
+-void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
+- u64 root_id,
+- struct extent_buffer *buf,
+- u64 parent, int last_ref);
++int btrfs_free_tree_block(struct btrfs_trans_handle *trans,
++ u64 root_id,
++ struct extent_buffer *buf,
++ u64 parent, int last_ref);
+ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 owner,
+ u64 offset, u64 ram_bytes,
+--- a/fs/btrfs/free-space-tree.c
++++ b/fs/btrfs/free-space-tree.c
+@@ -1289,10 +1289,14 @@ int btrfs_delete_free_space_tree(struct
+ btrfs_tree_lock(free_space_root->node);
+ btrfs_clear_buffer_dirty(trans, free_space_root->node);
+ btrfs_tree_unlock(free_space_root->node);
+- btrfs_free_tree_block(trans, btrfs_root_id(free_space_root),
+- free_space_root->node, 0, 1);
+-
++ ret = btrfs_free_tree_block(trans, btrfs_root_id(free_space_root),
++ free_space_root->node, 0, 1);
+ btrfs_put_root(free_space_root);
++ if (ret < 0) {
++ btrfs_abort_transaction(trans, ret);
++ btrfs_end_transaction(trans);
++ return ret;
++ }
+
+ return btrfs_commit_transaction(trans);
+
+--- a/fs/btrfs/ioctl.c
++++ b/fs/btrfs/ioctl.c
+@@ -707,6 +707,8 @@ static noinline int create_subvol(struct
+ ret = btrfs_insert_root(trans, fs_info->tree_root, &key,
+ root_item);
+ if (ret) {
++ int ret2;
++
+ /*
+ * Since we don't abort the transaction in this case, free the
+ * tree block so that we don't leak space and leave the
+@@ -717,7 +719,9 @@ static noinline int create_subvol(struct
+ btrfs_tree_lock(leaf);
+ btrfs_clear_buffer_dirty(trans, leaf);
+ btrfs_tree_unlock(leaf);
+- btrfs_free_tree_block(trans, objectid, leaf, 0, 1);
++ ret2 = btrfs_free_tree_block(trans, objectid, leaf, 0, 1);
++ if (ret2 < 0)
++ btrfs_abort_transaction(trans, ret2);
+ free_extent_buffer(leaf);
+ goto out;
+ }
+--- a/fs/btrfs/qgroup.c
++++ b/fs/btrfs/qgroup.c
+@@ -1320,9 +1320,11 @@ int btrfs_quota_disable(struct btrfs_fs_
+ btrfs_tree_lock(quota_root->node);
+ btrfs_clear_buffer_dirty(trans, quota_root->node);
+ btrfs_tree_unlock(quota_root->node);
+- btrfs_free_tree_block(trans, btrfs_root_id(quota_root),
+- quota_root->node, 0, 1);
++ ret = btrfs_free_tree_block(trans, btrfs_root_id(quota_root),
++ quota_root->node, 0, 1);
+
++ if (ret < 0)
++ btrfs_abort_transaction(trans, ret);
+
+ out:
+ btrfs_put_root(quota_root);