FAILED: patch "[PATCH] btrfs: fix transaction abort on set received ioctl due to" failed to apply to 6.1-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.1-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 <[email protected]>.
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.1.y
git checkout FETCH_HEAD
git cherry-pick -x 87f2c46003fce4d739138aab4af1942b1afdadac
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026031751-vitally-omega-64ea@gregkh' --subject-prefix 'PATCH 6.1.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 87f2c46003fce4d739138aab4af1942b1afdadac Mon Sep 17 00:00:00 2001
From: Filipe Manana <[email protected]>
Date: Thu, 26 Feb 2026 23:41:07 +0000
Subject: [PATCH] btrfs: fix transaction abort on set received ioctl due to
item overflow
If the set received ioctl fails due to an item overflow when attempting to add the BTRFS_UUID_KEY_RECEIVED_SUBVOL we have to abort the transaction since we did some metadata updates before.
This means that if a user calls this ioctl with the same received UUID field for a lot of subvolumes, we will hit the overflow, trigger the transaction abort and turn the filesystem into RO mode. A malicious user could exploit this, and this ioctl does not even requires that a user has admin privileges (CAP_SYS_ADMIN), only that he/she owns the subvolume.
Fix this by doing an early check for item overflow before starting a transaction. This is also race safe because we are holding the subvol_sem semaphore in exclusive (write) mode.
A test case for fstests will follow soon.
fs/btrfs/ioctl.c +19 -2
@@ -3929,6 +3929,25 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file, goto out; } + received_uuid_changed =memcmp (root_item->received_uuid, sa->uuid, +BTRFS_UUID_SIZE ); + +/* +* Before we attempt to add the new received uuid, check if we have room +* for it in case there's already an item. If the size of the existing +* item plus this root's ID (u64) exceeds the maximum item size, we can +* return here without the need to abort a transaction. If we don't do +* this check, the btrfs_uuid_tree_add() call below would fail with +* -EOVERFLOW and result in a transaction abort. Malicious users could +* exploit this to turn the fs into RO mode. +*/ +if (received_uuid_changed && !btrfs_is_empty_uuid (sa->uuid)) { + ret =btrfs_uuid_tree_check_overflow (fs_info, sa->uuid, +BTRFS_UUID_KEY_RECEIVED_SUBVOL ); +if (ret <0 ) + goto out; + } +/* * 1 - root item * 2 - uuid items (received uuid + subvol uuid)
@@ -3944,8 +3963,6 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file, sa->rtime.sec = ct.tv_sec; sa->rtime.nsec = ct.tv_nsec; - received_uuid_changed =memcmp (root_item->received_uuid, sa->uuid, -BTRFS_UUID_SIZE );if (received_uuid_changed && !btrfs_is_empty_uuid (root_item->received_uuid)) { ret = btrfs_uuid_tree_remove(trans, root_item->received_uuid,
fs/btrfs/uuid-tree.c +38 -0
@@ -199,6 +199,44 @@ int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, const u8 *uuid, u8return 0 ; } +/* +* Check if we can add one root ID to a UUID key. +* If the key does not yet exists, we can, otherwise only if extended item does +* not exceeds the maximum item size permitted by the leaf size. +* +* Returns 0 on success, negative value on error. +*/ +int btrfs_uuid_tree_check_overflow (struct btrfs_fs_info *fs_info, +const u8 *uuid,u8 type) +{ +BTRFS_PATH_AUTO_FREE (path); +int ret; +u32 item_size; +struct btrfs_key key; + +if (WARN_ON_ONCE (!fs_info->uuid_root)) +return -EINVAL ; + + path =btrfs_alloc_path (); +if (!path) +return -ENOMEM ; + +btrfs_uuid_to_key (uuid, type, &key); + ret =btrfs_search_slot (NULL , fs_info->uuid_root, &key, path,0 ,0 ); +if (ret <0 ) +return ret; +if (ret >0 ) +return 0 ; + + item_size =btrfs_item_size (path->nodes[0 ], path->slots[0 ]); + +if (sizeof (struct btrfs_item ) + item_size +sizeof (u64) > +BTRFS_LEAF_DATA_SIZE (fs_info)) +return -EOVERFLOW ; + +return 0 ; +} +static int btrfs_uuid_iter_rem (struct btrfs_root *uuid_root,u8 *uuid,u8 type,u64 subid) {
fs/btrfs/uuid-tree.h +2 -0
@@ -12,6 +12,8 @@ int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, const u8 *uuid, u8 typ u64 subid);int btrfs_uuid_tree_remove (struct btrfs_trans_handle *trans,const u8 *uuid,u8 type,u64 subid); +int btrfs_uuid_tree_check_overflow (struct btrfs_fs_info *fs_info, +const u8 *uuid,u8 type);int btrfs_uuid_tree_iterate (struct btrfs_fs_info *fs_info);int btrfs_create_uuid_tree (struct btrfs_fs_info *fs_info);int btrfs_uuid_scan_kthread (void *data);
Sasha Levin
maintainerPATCH 1/1 btrfs: fix transaction abort on set received ioctl due to item overflow
From: Filipe Manana <[email protected]>
[ Upstream commit 87f2c46003fce4d739138aab4af1942b1afdadac ]
If the set received ioctl fails due to an item overflow when attempting to add the BTRFS_UUID_KEY_RECEIVED_SUBVOL we have to abort the transaction since we did some metadata updates before.
This means that if a user calls this ioctl with the same received UUID field for a lot of subvolumes, we will hit the overflow, trigger the transaction abort and turn the filesystem into RO mode. A malicious user could exploit this, and this ioctl does not even requires that a user has admin privileges (CAP_SYS_ADMIN), only that he/she owns the subvolume.
Fix this by doing an early check for item overflow before starting a transaction. This is also race safe because we are holding the subvol_sem semaphore in exclusive (write) mode.
A test case for fstests will follow soon.
--- fs/btrfs/ctree.h | 2 ++ fs/btrfs/ioctl.c | 21 ++++++++++++++++++-- fs/btrfs/uuid-tree.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 2 deletions(-)
fs/btrfs/ctree.h +2 -0
@@ -3215,6 +3215,8 @@ int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, u8 *uuid, u8 type, u64 subid);int btrfs_uuid_tree_remove (struct btrfs_trans_handle *trans,u8 *uuid,u8 type,u64 subid); +int btrfs_uuid_tree_check_overflow (struct btrfs_fs_info *fs_info, +u8 *uuid,u8 type);int btrfs_uuid_tree_iterate (struct btrfs_fs_info *fs_info);/* dir-item.c */
fs/btrfs/ioctl.c +19 -2
@@ -4883,6 +4883,25 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file, goto out; } + received_uuid_changed =memcmp (root_item->received_uuid, sa->uuid, +BTRFS_UUID_SIZE ); + +/* +* Before we attempt to add the new received uuid, check if we have room +* for it in case there's already an item. If the size of the existing +* item plus this root's ID (u64) exceeds the maximum item size, we can +* return here without the need to abort a transaction. If we don't do +* this check, the btrfs_uuid_tree_add() call below would fail with +* -EOVERFLOW and result in a transaction abort. Malicious users could +* exploit this to turn the fs into RO mode. +*/ +if (received_uuid_changed && !btrfs_is_empty_uuid (sa->uuid)) { + ret =btrfs_uuid_tree_check_overflow (fs_info, sa->uuid, +BTRFS_UUID_KEY_RECEIVED_SUBVOL ); +if (ret <0 ) + goto out; + } +/* * 1 - root item * 2 - uuid items (received uuid + subvol uuid)
@@ -4898,8 +4917,6 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file, sa->rtime.sec = ct.tv_sec; sa->rtime.nsec = ct.tv_nsec; - received_uuid_changed =memcmp (root_item->received_uuid, sa->uuid, -BTRFS_UUID_SIZE );if (received_uuid_changed && !btrfs_is_empty_uuid (root_item->received_uuid)) { ret = btrfs_uuid_tree_remove(trans, root_item->received_uuid,
fs/btrfs/uuid-tree.c +46 -0
52 lines not on this page · raw message
Signature · 1 line
2.51.0