FAILED: patch "[PATCH] btrfs: trim: fix underflow in trim length to prevent access" failed to apply to 5.4-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.4-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]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From c57dd1f2f6a7cd1bb61802344f59ccdc5278c983 Mon Sep 17 00:00:00 2001
From: Qu Wenruo <[email protected]>
Date: Fri, 31 Jul 2020 19:29:11 +0800
Subject: [PATCH] btrfs: trim: fix underflow in trim length to prevent access
beyond device boundary
[BUG]
The following script can lead to tons of beyond device boundary access:
mkfs.btrfs -f $dev -b 10G
mount $dev $mnt
trimfs $mnt
btrfs filesystem resize 1:-1G $mnt
trimfs $mnt
[CAUSE]
Since commit 929be17a9b49 ("btrfs: Switch btrfs_trim_free_extents to find_first_clear_extent_bit"), we try to avoid trimming ranges that's already trimmed.
So we check device->alloc_state by finding the first range which doesn't have CHUNK_TRIMMED and CHUNK_ALLOCATED not set.
But if we shrunk the device, that bits are not cleared, thus we could easily got a range starts beyond the shrunk device size.
This results the returned @start and @end are all beyond device size, then we call "end = min(end, device->total_bytes -1);" making @end smaller than device size.
Then finally we goes "len = end - start + 1", totally underflow the result, and lead to the beyond-device-boundary access.
[FIX]
This patch will fix the problem in two ways:
- Clear CHUNK_TRIMMED | CHUNK_ALLOCATED bits when shrinking device This is the root fix
- Add extra safety check when trimming free device extents We check and warn if the returned range is already beyond current device.
fs/btrfs/extent-io-tree.h +2 -0
@@ -34,6 +34,8 @@ struct io_failure_record;*/ #define CHUNK_ALLOCATED EXTENT_DIRTY#define CHUNK_TRIMMED EXTENT_DEFRAG +#define CHUNK_STATE_MASK (CHUNK_ALLOCATED | \ + CHUNK_TRIMMED)enum {IO_TREE_FS_PINNED_EXTENTS ,
fs/btrfs/extent-tree.c +14 -0
@@ -33,6 +33,7 @@#include "delalloc-space.h" #include "block-group.h" #include "discard.h" +#include "rcu-string.h" #undef SCRAMBLE_DELAYED_REFS
@@ -5668,6 +5669,19 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, u64 *trimmed) &start, &end, CHUNK_TRIMMED | CHUNK_ALLOCATED); +/* Check if there are any CHUNK_* bits left */ +if (start > device->total_bytes) { +WARN_ON (IS_ENABLED (CONFIG_BTRFS_DEBUG )); +btrfs_warn_in_rcu (fs_info, +"ignoring attempt to trim beyond device size: offset %llu length %llu device %s device size %llu" , + start, end - start +1 , +rcu_str_deref (device->name), + device->total_bytes); +mutex_unlock (&fs_info->chunk_mutex); + ret =0 ; +break ; + } +/* Ensure we skip the reserved area in the first 1M */ start =max_t (u64, start,SZ_1M );
fs/btrfs/volumes.c +4 -0
@@ -4720,6 +4720,10 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) }mutex_lock (&fs_info->chunk_mutex); +/* Clear all state bits beyond the shrunk device size */ +clear_extent_bits (&device->alloc_state, new_size, (u64)-1 , +CHUNK_STATE_MASK ); +btrfs_device_set_disk_total_bytes (device, new_size);if (list_empty (&device->post_commit_list)) list_add_tail(&device->post_commit_list,
Sudip Mukherjee
Reviewed-by Filipe MananaHi Greg,
Quoted 5 lines · On Wed, Aug 19, 2020 at 01:36:33PM +0200, [email protected] wrote:
The patch below does not apply to the 5.4-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]>.
Here is the backport.
--
Regards
Sudip
From 310079d12dd563fe3a065b6dfe66629e3b6611ee Mon Sep 17 00:00:00 2001
From: Qu Wenruo <[email protected]>
Date: Fri, 31 Jul 2020 19:29:11 +0800
Subject: [PATCH] btrfs: trim: fix underflow in trim length to prevent access beyond device boundary
commit c57dd1f2f6a7cd1bb61802344f59ccdc5278c983 upstream
[BUG]
The following script can lead to tons of beyond device boundary access:
mkfs.btrfs -f $dev -b 10G
mount $dev $mnt
trimfs $mnt
btrfs filesystem resize 1:-1G $mnt
trimfs $mnt
[CAUSE]
Since commit 929be17a9b49 ("btrfs: Switch btrfs_trim_free_extents to find_first_clear_extent_bit"), we try to avoid trimming ranges that's already trimmed.
So we check device->alloc_state by finding the first range which doesn't have CHUNK_TRIMMED and CHUNK_ALLOCATED not set.
But if we shrunk the device, that bits are not cleared, thus we could easily got a range starts beyond the shrunk device size.
This results the returned @start and @end are all beyond device size, then we call "end = min(end, device->total_bytes -1);" making @end smaller than device size.
Then finally we goes "len = end - start + 1", totally underflow the result, and lead to the beyond-device-boundary access.
[FIX]
This patch will fix the problem in two ways:
- Clear CHUNK_TRIMMED | CHUNK_ALLOCATED bits when shrinking device This is the root fix
- Add extra safety check when trimming free device extents We check and warn if the returned range is already beyond current device.
--- fs/btrfs/extent-tree.c | 14 ++++++++++++++ fs/btrfs/extent_io.h | 2 ++ fs/btrfs/volumes.c | 4 ++++ 3 files changed, 20 insertions(+)
fs/btrfs/extent-tree.c +14 -0
@@ -32,6 +32,7 @@#include "block-rsv.h" #include "delalloc-space.h" #include "block-group.h" +#include "rcu-string.h" #undef SCRAMBLE_DELAYED_REFS
@@ -5618,6 +5619,19 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, u64 *trimmed) &start, &end, CHUNK_TRIMMED | CHUNK_ALLOCATED); +/* Check if there are any CHUNK_* bits left */ +if (start > device->total_bytes) { +WARN_ON (IS_ENABLED (CONFIG_BTRFS_DEBUG )); +btrfs_warn_in_rcu (fs_info, +"ignoring attempt to trim beyond device size: offset %llu length %llu device %s device size %llu" , + start, end - start +1 , +rcu_str_deref (device->name), + device->total_bytes); +mutex_unlock (&fs_info->chunk_mutex); + ret =0 ; +break ; + } +/* Ensure we skip the reserved area in the first 1M */ start =max_t (u64, start,SZ_1M );
fs/btrfs/extent_io.h +2 -0
@@ -35,6 +35,8 @@*/ #define CHUNK_ALLOCATED EXTENT_DIRTY#define CHUNK_TRIMMED EXTENT_DEFRAG +#define CHUNK_STATE_MASK (CHUNK_ALLOCATED | \ + CHUNK_TRIMMED)/* * flags for bio submission. The high bits indicate the compression
fs/btrfs/volumes.c +4 -0
@@ -4908,6 +4908,10 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) }mutex_lock (&fs_info->chunk_mutex); +/* Clear all state bits beyond the shrunk device size */ +clear_extent_bits (&device->alloc_state, new_size, (u64)-1 , +CHUNK_STATE_MASK ); +btrfs_device_set_disk_total_bytes (device, new_size);if (list_empty (&device->post_commit_list)) list_add_tail(&device->post_commit_list,
Signature · 1 line
2.11.0
Greg KH
maintainerQuoted 10 lines · Sudip Mukherjee
Hi Greg,
Quoted 5 lines · On Wed, Aug 19, 2020 at 01:36:33PM +0200, [email protected] wrote:
The patch below does not apply to the 5.4-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]>.Here is the backport.
Now queued up, thanks.
greg k-h