From: Greg Kroah-Hartman Date: Thu, 11 Jun 2020 11:22:02 +0000 (+0200) Subject: 4.19-stable patches X-Git-Tag: v5.4.47~136 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3ea49b57b18054f51d4c9132c24160512198cbd7;p=thirdparty%2Fkernel%2Fstable-queue.git 4.19-stable patches added patches: arch-openrisc-fix-issues-with-access_ok.patch btrfs-detect-unbalanced-tree-with-empty-leaf-before-crashing-btree-operations.patch btrfs-merge-btrfs_find_device-and-find_device.patch fix-acccess_ok-on-alpha-and-sh.patch lib-reduce-user_access_begin-boundaries-in-strncpy_from_user-and-strnlen_user.patch make-user_access_begin-do-access_ok.patch x86-uaccess-inhibit-speculation-past-access_ok-in-user_access_begin.patch --- diff --git a/queue-4.19/arch-openrisc-fix-issues-with-access_ok.patch b/queue-4.19/arch-openrisc-fix-issues-with-access_ok.patch new file mode 100644 index 00000000000..5b78f5db393 --- /dev/null +++ b/queue-4.19/arch-openrisc-fix-issues-with-access_ok.patch @@ -0,0 +1,46 @@ +From 9cb2feb4d21d97386eb25c7b67e2793efcc1e70a Mon Sep 17 00:00:00 2001 +From: Stafford Horne +Date: Tue, 8 Jan 2019 22:15:15 +0900 +Subject: arch/openrisc: Fix issues with access_ok() + +From: Stafford Horne + +commit 9cb2feb4d21d97386eb25c7b67e2793efcc1e70a upstream. + +The commit 594cc251fdd0 ("make 'user_access_begin()' do 'access_ok()'") +exposed incorrect implementations of access_ok() macro in several +architectures. This change fixes 2 issues found in OpenRISC. + +OpenRISC was not properly using parenthesis for arguments and also using +arguments twice. This patch fixes those 2 issues. + +I test booted this patch with v5.0-rc1 on qemu and it's working fine. + +Cc: Guenter Roeck +Cc: Linus Torvalds +Reported-by: Linus Torvalds +Signed-off-by: Stafford Horne +Signed-off-by: Linus Torvalds +Signed-off-by: Miles Chen +Signed-off-by: Greg Kroah-Hartman +--- + arch/openrisc/include/asm/uaccess.h | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/arch/openrisc/include/asm/uaccess.h ++++ b/arch/openrisc/include/asm/uaccess.h +@@ -58,8 +58,12 @@ + /* Ensure that addr is below task's addr_limit */ + #define __addr_ok(addr) ((unsigned long) addr < get_fs()) + +-#define access_ok(type, addr, size) \ +- __range_ok((unsigned long)addr, (unsigned long)size) ++#define access_ok(type, addr, size) \ ++({ \ ++ unsigned long __ao_addr = (unsigned long)(addr); \ ++ unsigned long __ao_size = (unsigned long)(size); \ ++ __range_ok(__ao_addr, __ao_size); \ ++}) + + /* + * These are the main single-value transfer routines. They automatically diff --git a/queue-4.19/btrfs-detect-unbalanced-tree-with-empty-leaf-before-crashing-btree-operations.patch b/queue-4.19/btrfs-detect-unbalanced-tree-with-empty-leaf-before-crashing-btree-operations.patch new file mode 100644 index 00000000000..94886f5099d --- /dev/null +++ b/queue-4.19/btrfs-detect-unbalanced-tree-with-empty-leaf-before-crashing-btree-operations.patch @@ -0,0 +1,124 @@ +From 62fdaa52a3d00a875da771719b6dc537ca79fce1 Mon Sep 17 00:00:00 2001 +From: Qu Wenruo +Date: Thu, 22 Aug 2019 10:14:15 +0800 +Subject: btrfs: Detect unbalanced tree with empty leaf before crashing btree operations + +From: Qu Wenruo + +commit 62fdaa52a3d00a875da771719b6dc537ca79fce1 upstream. + +[BUG] +With crafted image, btrfs will panic at btree operations: + + kernel BUG at fs/btrfs/ctree.c:3894! + invalid opcode: 0000 [#1] SMP PTI + CPU: 0 PID: 1138 Comm: btrfs-transacti Not tainted 5.0.0-rc8+ #9 + RIP: 0010:__push_leaf_left+0x6b6/0x6e0 + RSP: 0018:ffffc0bd4128b990 EFLAGS: 00010246 + RAX: 0000000000000000 RBX: ffffa0a4ab8f0e38 RCX: 0000000000000000 + RDX: ffffa0a280000000 RSI: 0000000000000000 RDI: ffffa0a4b3814000 + RBP: ffffc0bd4128ba38 R08: 0000000000001000 R09: ffffc0bd4128b948 + R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000240 + R13: ffffa0a4b556fb60 R14: ffffa0a4ab8f0af0 R15: ffffa0a4ab8f0af0 + FS: 0000000000000000(0000) GS:ffffa0a4b7a00000(0000) knlGS:0000000000000000 + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + CR2: 00007f2461c80020 CR3: 000000022b32a006 CR4: 00000000000206f0 + Call Trace: + ? _cond_resched+0x1a/0x50 + push_leaf_left+0x179/0x190 + btrfs_del_items+0x316/0x470 + btrfs_del_csums+0x215/0x3a0 + __btrfs_free_extent.isra.72+0x5a7/0xbe0 + __btrfs_run_delayed_refs+0x539/0x1120 + btrfs_run_delayed_refs+0xdb/0x1b0 + btrfs_commit_transaction+0x52/0x950 + ? start_transaction+0x94/0x450 + transaction_kthread+0x163/0x190 + kthread+0x105/0x140 + ? btrfs_cleanup_transaction+0x560/0x560 + ? kthread_destroy_worker+0x50/0x50 + ret_from_fork+0x35/0x40 + Modules linked in: + ---[ end trace c2425e6e89b5558f ]--- + +[CAUSE] +The offending csum tree looks like this: + + checksum tree key (CSUM_TREE ROOT_ITEM 0) + node 29741056 level 1 items 14 free 107 generation 19 owner CSUM_TREE + ... + key (EXTENT_CSUM EXTENT_CSUM 85975040) block 29630464 gen 17 + key (EXTENT_CSUM EXTENT_CSUM 89911296) block 29642752 gen 17 <<< + key (EXTENT_CSUM EXTENT_CSUM 92274688) block 29646848 gen 17 + ... + + leaf 29630464 items 6 free space 1 generation 17 owner CSUM_TREE + item 0 key (EXTENT_CSUM EXTENT_CSUM 85975040) itemoff 3987 itemsize 8 + range start 85975040 end 85983232 length 8192 + ... + leaf 29642752 items 0 free space 3995 generation 17 owner 0 + ^ empty leaf invalid owner ^ + + leaf 29646848 items 1 free space 602 generation 17 owner CSUM_TREE + item 0 key (EXTENT_CSUM EXTENT_CSUM 92274688) itemoff 627 itemsize 3368 + range start 92274688 end 95723520 length 3448832 + +So we have a corrupted csum tree where one tree leaf is completely +empty, causing unbalanced btree, thus leading to unexpected btree +balance error. + +[FIX] +For this particular case, we handle it in two directions to catch it: +- Check if the tree block is empty through btrfs_verify_level_key() + So that invalid tree blocks won't be read out through + btrfs_search_slot() and its variants. + +- Check 0 tree owner in tree checker + NO tree is using 0 as its tree owner, detect it and reject at tree + block read time. + +Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=202821 +Reviewed-by: Nikolay Borisov +Signed-off-by: Qu Wenruo +Signed-off-by: David Sterba +Signed-off-by: Vikash Bansal +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/disk-io.c | 10 ++++++++++ + fs/btrfs/tree-checker.c | 6 ++++++ + 2 files changed, 16 insertions(+) + +--- a/fs/btrfs/disk-io.c ++++ b/fs/btrfs/disk-io.c +@@ -438,6 +438,16 @@ int btrfs_verify_level_key(struct btrfs_ + */ + if (btrfs_header_generation(eb) > fs_info->last_trans_committed) + return 0; ++ ++ /* We have @first_key, so this @eb must have at least one item */ ++ if (btrfs_header_nritems(eb) == 0) { ++ btrfs_err(fs_info, ++ "invalid tree nritems, bytenr=%llu nritems=0 expect >0", ++ eb->start); ++ WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG)); ++ return -EUCLEAN; ++ } ++ + if (found_level) + btrfs_node_key_to_cpu(eb, &found_key, 0); + else +--- a/fs/btrfs/tree-checker.c ++++ b/fs/btrfs/tree-checker.c +@@ -169,6 +169,12 @@ static int check_extent_data_item(struct + btrfs_file_extent_ram_bytes(leaf, fi)); + return -EUCLEAN; + } ++ /* Unknown tree */ ++ if (owner == 0) { ++ generic_err(leaf, 0, ++ "invalid owner, root 0 is not defined"); ++ return -EUCLEAN; ++ } + return 0; + } + diff --git a/queue-4.19/btrfs-merge-btrfs_find_device-and-find_device.patch b/queue-4.19/btrfs-merge-btrfs_find_device-and-find_device.patch new file mode 100644 index 00000000000..54001626e43 --- /dev/null +++ b/queue-4.19/btrfs-merge-btrfs_find_device-and-find_device.patch @@ -0,0 +1,271 @@ +From 09ba3bc9dd150457c506e4661380a6183af651c1 Mon Sep 17 00:00:00 2001 +From: Anand Jain +Date: Sat, 19 Jan 2019 14:48:55 +0800 +Subject: btrfs: merge btrfs_find_device and find_device + +From: Anand Jain + +commit 09ba3bc9dd150457c506e4661380a6183af651c1 upstream. + +Both btrfs_find_device() and find_device() does the same thing except +that the latter does not take the seed device onto account in the device +scanning context. We can merge them. + +Signed-off-by: Anand Jain +Reviewed-by: David Sterba +Signed-off-by: David Sterba +[4.19.y backport notes: +Vikash : - To apply this patch, a portion of commit e4319cd9cace + was used to change the first argument of function + "btrfs_find_device" from "struct btrfs_fs_info" to + "struct btrfs_fs_devices". +Signed-off-by: Vikash Bansal +Signed-off-by: Greg Kroah-Hartman +--- + fs/btrfs/dev-replace.c | 8 ++-- + fs/btrfs/ioctl.c | 5 +- + fs/btrfs/scrub.c | 4 +- + fs/btrfs/volumes.c | 84 ++++++++++++++++++++++++------------------------- + fs/btrfs/volumes.h | 4 +- + 5 files changed, 53 insertions(+), 52 deletions(-) + +--- a/fs/btrfs/dev-replace.c ++++ b/fs/btrfs/dev-replace.c +@@ -112,11 +112,11 @@ no_valid_dev_replace_entry_found: + break; + case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: + case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: +- dev_replace->srcdev = btrfs_find_device(fs_info, src_devid, +- NULL, NULL); +- dev_replace->tgtdev = btrfs_find_device(fs_info, ++ dev_replace->srcdev = btrfs_find_device(fs_info->fs_devices, ++ src_devid, NULL, NULL, true); ++ dev_replace->tgtdev = btrfs_find_device(fs_info->fs_devices, + BTRFS_DEV_REPLACE_DEVID, +- NULL, NULL); ++ NULL, NULL, true); + /* + * allow 'btrfs dev replace_cancel' if src/tgt device is + * missing +--- a/fs/btrfs/ioctl.c ++++ b/fs/btrfs/ioctl.c +@@ -1642,7 +1642,7 @@ static noinline int btrfs_ioctl_resize(s + btrfs_info(fs_info, "resizing devid %llu", devid); + } + +- device = btrfs_find_device(fs_info, devid, NULL, NULL); ++ device = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL, true); + if (!device) { + btrfs_info(fs_info, "resizer unable to find device %llu", + devid); +@@ -3178,7 +3178,8 @@ static long btrfs_ioctl_dev_info(struct + s_uuid = di_args->uuid; + + rcu_read_lock(); +- dev = btrfs_find_device(fs_info, di_args->devid, s_uuid, NULL); ++ dev = btrfs_find_device(fs_info->fs_devices, di_args->devid, s_uuid, ++ NULL, true); + + if (!dev) { + ret = -ENODEV; +--- a/fs/btrfs/scrub.c ++++ b/fs/btrfs/scrub.c +@@ -3835,7 +3835,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info + return PTR_ERR(sctx); + + mutex_lock(&fs_info->fs_devices->device_list_mutex); +- dev = btrfs_find_device(fs_info, devid, NULL, NULL); ++ dev = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL, true); + if (!dev || (test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state) && + !is_dev_replace)) { + mutex_unlock(&fs_info->fs_devices->device_list_mutex); +@@ -4019,7 +4019,7 @@ int btrfs_scrub_progress(struct btrfs_fs + struct scrub_ctx *sctx = NULL; + + mutex_lock(&fs_info->fs_devices->device_list_mutex); +- dev = btrfs_find_device(fs_info, devid, NULL, NULL); ++ dev = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL, true); + if (dev) + sctx = dev->scrub_ctx; + if (sctx) +--- a/fs/btrfs/volumes.c ++++ b/fs/btrfs/volumes.c +@@ -347,27 +347,6 @@ static struct btrfs_device *__alloc_devi + return dev; + } + +-/* +- * Find a device specified by @devid or @uuid in the list of @fs_devices, or +- * return NULL. +- * +- * If devid and uuid are both specified, the match must be exact, otherwise +- * only devid is used. +- */ +-static struct btrfs_device *find_device(struct btrfs_fs_devices *fs_devices, +- u64 devid, const u8 *uuid) +-{ +- struct btrfs_device *dev; +- +- list_for_each_entry(dev, &fs_devices->devices, dev_list) { +- if (dev->devid == devid && +- (!uuid || !memcmp(dev->uuid, uuid, BTRFS_UUID_SIZE))) { +- return dev; +- } +- } +- return NULL; +-} +- + static noinline struct btrfs_fs_devices *find_fsid(u8 *fsid) + { + struct btrfs_fs_devices *fs_devices; +@@ -772,8 +751,8 @@ static noinline struct btrfs_device *dev + device = NULL; + } else { + mutex_lock(&fs_devices->device_list_mutex); +- device = find_device(fs_devices, devid, +- disk_super->dev_item.uuid); ++ device = btrfs_find_device(fs_devices, devid, ++ disk_super->dev_item.uuid, NULL, false); + } + + if (!device) { +@@ -2144,7 +2123,8 @@ static int btrfs_find_device_by_path(str + disk_super = (struct btrfs_super_block *)bh->b_data; + devid = btrfs_stack_device_id(&disk_super->dev_item); + dev_uuid = disk_super->dev_item.uuid; +- *device = btrfs_find_device(fs_info, devid, dev_uuid, disk_super->fsid); ++ *device = btrfs_find_device(fs_info->fs_devices, devid, dev_uuid, ++ disk_super->fsid, true); + brelse(bh); + if (!*device) + ret = -ENOENT; +@@ -2190,7 +2170,8 @@ int btrfs_find_device_by_devspec(struct + + if (devid) { + ret = 0; +- *device = btrfs_find_device(fs_info, devid, NULL, NULL); ++ *device = btrfs_find_device(fs_info->fs_devices, devid, ++ NULL, NULL, true); + if (!*device) + ret = -ENOENT; + } else { +@@ -2322,7 +2303,8 @@ next_slot: + BTRFS_UUID_SIZE); + read_extent_buffer(leaf, fs_uuid, btrfs_device_fsid(dev_item), + BTRFS_FSID_SIZE); +- device = btrfs_find_device(fs_info, devid, dev_uuid, fs_uuid); ++ device = btrfs_find_device(fs_info->fs_devices, devid, dev_uuid, ++ fs_uuid, true); + BUG_ON(!device); /* Logic error */ + + if (device->fs_devices->seeding) { +@@ -6254,21 +6236,36 @@ blk_status_t btrfs_map_bio(struct btrfs_ + return BLK_STS_OK; + } + +-struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid, +- u8 *uuid, u8 *fsid) ++/* ++ * Find a device specified by @devid or @uuid in the list of @fs_devices, or ++ * return NULL. ++ * ++ * If devid and uuid are both specified, the match must be exact, otherwise ++ * only devid is used. ++ * ++ * If @seed is true, traverse through the seed devices. ++ */ ++struct btrfs_device *btrfs_find_device(struct btrfs_fs_devices *fs_devices, ++ u64 devid, u8 *uuid, u8 *fsid, ++ bool seed) + { + struct btrfs_device *device; +- struct btrfs_fs_devices *cur_devices; + +- cur_devices = fs_info->fs_devices; +- while (cur_devices) { ++ while (fs_devices) { + if (!fsid || +- !memcmp(cur_devices->fsid, fsid, BTRFS_FSID_SIZE)) { +- device = find_device(cur_devices, devid, uuid); +- if (device) +- return device; ++ !memcmp(fs_devices->fsid, fsid, BTRFS_FSID_SIZE)) { ++ list_for_each_entry(device, &fs_devices->devices, ++ dev_list) { ++ if (device->devid == devid && ++ (!uuid || memcmp(device->uuid, uuid, ++ BTRFS_UUID_SIZE) == 0)) ++ return device; ++ } + } +- cur_devices = cur_devices->seed; ++ if (seed) ++ fs_devices = fs_devices->seed; ++ else ++ return NULL; + } + return NULL; + } +@@ -6513,8 +6510,8 @@ static int read_one_chunk(struct btrfs_f + read_extent_buffer(leaf, uuid, (unsigned long) + btrfs_stripe_dev_uuid_nr(chunk, i), + BTRFS_UUID_SIZE); +- map->stripes[i].dev = btrfs_find_device(fs_info, devid, +- uuid, NULL); ++ map->stripes[i].dev = btrfs_find_device(fs_info->fs_devices, ++ devid, uuid, NULL, true); + if (!map->stripes[i].dev && + !btrfs_test_opt(fs_info, DEGRADED)) { + free_extent_map(em); +@@ -6653,7 +6650,8 @@ static int read_one_dev(struct btrfs_fs_ + return PTR_ERR(fs_devices); + } + +- device = btrfs_find_device(fs_info, devid, dev_uuid, fs_uuid); ++ device = btrfs_find_device(fs_info->fs_devices, devid, dev_uuid, ++ fs_uuid, true); + if (!device) { + if (!btrfs_test_opt(fs_info, DEGRADED)) { + btrfs_report_missing_device(fs_info, devid, +@@ -7243,7 +7241,8 @@ int btrfs_get_dev_stats(struct btrfs_fs_ + int i; + + mutex_lock(&fs_devices->device_list_mutex); +- dev = btrfs_find_device(fs_info, stats->devid, NULL, NULL); ++ dev = btrfs_find_device(fs_info->fs_devices, stats->devid, ++ NULL, NULL, true); + mutex_unlock(&fs_devices->device_list_mutex); + + if (!dev) { +@@ -7460,7 +7459,7 @@ static int verify_one_dev_extent(struct + } + + /* Make sure no dev extent is beyond device bondary */ +- dev = btrfs_find_device(fs_info, devid, NULL, NULL); ++ dev = btrfs_find_device(fs_info->fs_devices, devid, NULL, NULL, true); + if (!dev) { + btrfs_err(fs_info, "failed to find devid %llu", devid); + ret = -EUCLEAN; +@@ -7469,7 +7468,8 @@ static int verify_one_dev_extent(struct + + /* It's possible this device is a dummy for seed device */ + if (dev->disk_total_bytes == 0) { +- dev = find_device(fs_info->fs_devices->seed, devid, NULL); ++ dev = btrfs_find_device(fs_info->fs_devices->seed, devid, ++ NULL, NULL, false); + if (!dev) { + btrfs_err(fs_info, "failed to find seed devid %llu", + devid); +--- a/fs/btrfs/volumes.h ++++ b/fs/btrfs/volumes.h +@@ -430,8 +430,8 @@ void __exit btrfs_cleanup_fs_uuids(void) + int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len); + int btrfs_grow_device(struct btrfs_trans_handle *trans, + struct btrfs_device *device, u64 new_size); +-struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid, +- u8 *uuid, u8 *fsid); ++struct btrfs_device *btrfs_find_device(struct btrfs_fs_devices *fs_devices, ++ u64 devid, u8 *uuid, u8 *fsid, bool seed); + int btrfs_shrink_device(struct btrfs_device *device, u64 new_size); + int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *path); + int btrfs_balance(struct btrfs_fs_info *fs_info, diff --git a/queue-4.19/fix-acccess_ok-on-alpha-and-sh.patch b/queue-4.19/fix-acccess_ok-on-alpha-and-sh.patch new file mode 100644 index 00000000000..d1f43285406 --- /dev/null +++ b/queue-4.19/fix-acccess_ok-on-alpha-and-sh.patch @@ -0,0 +1,126 @@ +From 94bd8a05cd4de344a9a57e52ef7d99550251984f Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Sun, 6 Jan 2019 11:15:04 -0800 +Subject: Fix 'acccess_ok()' on alpha and SH + +From: Linus Torvalds + +commit 94bd8a05cd4de344a9a57e52ef7d99550251984f upstream. + +Commit 594cc251fdd0 ("make 'user_access_begin()' do 'access_ok()'") +broke both alpha and SH booting in qemu, as noticed by Guenter Roeck. + +It turns out that the bug wasn't actually in that commit itself (which +would have been surprising: it was mostly a no-op), but in how the +addition of access_ok() to the strncpy_from_user() and strnlen_user() +functions now triggered the case where those functions would test the +access of the very last byte of the user address space. + +The string functions actually did that user range test before too, but +they did it manually by just comparing against user_addr_max(). But +with user_access_begin() doing the check (using "access_ok()"), it now +exposed problems in the architecture implementations of that function. + +For example, on alpha, the access_ok() helper macro looked like this: + + #define __access_ok(addr, size) \ + ((get_fs().seg & (addr | size | (addr+size))) == 0) + +and what it basically tests is of any of the high bits get set (the +USER_DS masking value is 0xfffffc0000000000). + +And that's completely wrong for the "addr+size" check. Because it's +off-by-one for the case where we check to the very end of the user +address space, which is exactly what the strn*_user() functions do. + +Why? Because "addr+size" will be exactly the size of the address space, +so trying to access the last byte of the user address space will fail +the __access_ok() check, even though it shouldn't. As a result, the +user string accessor functions failed consistently - because they +literally don't know how long the string is going to be, and the max +access is going to be that last byte of the user address space. + +Side note: that alpha macro is buggy for another reason too - it re-uses +the arguments twice. + +And SH has another version of almost the exact same bug: + + #define __addr_ok(addr) \ + ((unsigned long __force)(addr) < current_thread_info()->addr_limit.seg) + +so far so good: yes, a user address must be below the limit. But then: + + #define __access_ok(addr, size) \ + (__addr_ok((addr) + (size))) + +is wrong with the exact same off-by-one case: the case when "addr+size" +is exactly _equal_ to the limit is actually perfectly fine (think "one +byte access at the last address of the user address space") + +The SH version is actually seriously buggy in another way: it doesn't +actually check for overflow, even though it did copy the _comment_ that +talks about overflow. + +So it turns out that both SH and alpha actually have completely buggy +implementations of access_ok(), but they happened to work in practice +(although the SH overflow one is a serious serious security bug, not +that anybody likely cares about SH security). + +This fixes the problems by using a similar macro on both alpha and SH. +It isn't trying to be clever, the end address is based on this logic: + + unsigned long __ao_end = __ao_a + __ao_b - !!__ao_b; + +which basically says "add start and length, and then subtract one unless +the length was zero". We can't subtract one for a zero length, or we'd +just hit an underflow instead. + +For a lot of access_ok() users the length is a constant, so this isn't +actually as expensive as it initially looks. + +Reported-and-tested-by: Guenter Roeck +Cc: Matt Turner +Cc: Yoshinori Sato +Signed-off-by: Linus Torvalds +Signed-off-by: Miles Chen +Signed-off-by: Greg Kroah-Hartman +--- + arch/alpha/include/asm/uaccess.h | 8 +++++--- + arch/sh/include/asm/uaccess.h | 7 +++++-- + 2 files changed, 10 insertions(+), 5 deletions(-) + +--- a/arch/alpha/include/asm/uaccess.h ++++ b/arch/alpha/include/asm/uaccess.h +@@ -30,11 +30,13 @@ + * Address valid if: + * - "addr" doesn't have any high-bits set + * - AND "size" doesn't have any high-bits set +- * - AND "addr+size" doesn't have any high-bits set ++ * - AND "addr+size-(size != 0)" doesn't have any high-bits set + * - OR we are in kernel mode. + */ +-#define __access_ok(addr, size) \ +- ((get_fs().seg & (addr | size | (addr+size))) == 0) ++#define __access_ok(addr, size) ({ \ ++ unsigned long __ao_a = (addr), __ao_b = (size); \ ++ unsigned long __ao_end = __ao_a + __ao_b - !!__ao_b; \ ++ (get_fs().seg & (__ao_a | __ao_b | __ao_end)) == 0; }) + + #define access_ok(type, addr, size) \ + ({ \ +--- a/arch/sh/include/asm/uaccess.h ++++ b/arch/sh/include/asm/uaccess.h +@@ -16,8 +16,11 @@ + * sum := addr + size; carry? --> flag = true; + * if (sum >= addr_limit) flag = true; + */ +-#define __access_ok(addr, size) \ +- (__addr_ok((addr) + (size))) ++#define __access_ok(addr, size) ({ \ ++ unsigned long __ao_a = (addr), __ao_b = (size); \ ++ unsigned long __ao_end = __ao_a + __ao_b - !!__ao_b; \ ++ __ao_end >= __ao_a && __addr_ok(__ao_end); }) ++ + #define access_ok(type, addr, size) \ + (__chk_user_ptr(addr), \ + __access_ok((unsigned long __force)(addr), (size))) diff --git a/queue-4.19/lib-reduce-user_access_begin-boundaries-in-strncpy_from_user-and-strnlen_user.patch b/queue-4.19/lib-reduce-user_access_begin-boundaries-in-strncpy_from_user-and-strnlen_user.patch new file mode 100644 index 00000000000..218b95dd5d5 --- /dev/null +++ b/queue-4.19/lib-reduce-user_access_begin-boundaries-in-strncpy_from_user-and-strnlen_user.patch @@ -0,0 +1,89 @@ +From ab10ae1c3bef56c29bac61e1201c752221b87b41 Mon Sep 17 00:00:00 2001 +From: Christophe Leroy +Date: Thu, 23 Jan 2020 08:34:18 +0000 +Subject: lib: Reduce user_access_begin() boundaries in strncpy_from_user() and strnlen_user() + +From: Christophe Leroy + +commit ab10ae1c3bef56c29bac61e1201c752221b87b41 upstream. + +The range passed to user_access_begin() by strncpy_from_user() and +strnlen_user() starts at 'src' and goes up to the limit of userspace +although reads will be limited by the 'count' param. + +On 32 bits powerpc (book3s/32) access has to be granted for each +256Mbytes segment and the cost increases with the number of segments to +unlock. + +Limit the range with 'count' param. + +Fixes: 594cc251fdd0 ("make 'user_access_begin()' do 'access_ok()'") +Signed-off-by: Christophe Leroy +Signed-off-by: Linus Torvalds +Signed-off-by: Miles Chen +Signed-off-by: Greg Kroah-Hartman +--- + lib/strncpy_from_user.c | 14 +++++++------- + lib/strnlen_user.c | 14 +++++++------- + 2 files changed, 14 insertions(+), 14 deletions(-) + +--- a/lib/strncpy_from_user.c ++++ b/lib/strncpy_from_user.c +@@ -29,13 +29,6 @@ static inline long do_strncpy_from_user( + const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; + unsigned long res = 0; + +- /* +- * Truncate 'max' to the user-specified limit, so that +- * we only have one limit we need to check in the loop +- */ +- if (max > count) +- max = count; +- + if (IS_UNALIGNED(src, dst)) + goto byte_at_a_time; + +@@ -113,6 +106,13 @@ long strncpy_from_user(char *dst, const + unsigned long max = max_addr - src_addr; + long retval; + ++ /* ++ * Truncate 'max' to the user-specified limit, so that ++ * we only have one limit we need to check in the loop ++ */ ++ if (max > count) ++ max = count; ++ + kasan_check_write(dst, count); + check_object_size(dst, count, false); + if (user_access_begin(VERIFY_READ, src, max)) { +--- a/lib/strnlen_user.c ++++ b/lib/strnlen_user.c +@@ -32,13 +32,6 @@ static inline long do_strnlen_user(const + unsigned long c; + + /* +- * Truncate 'max' to the user-specified limit, so that +- * we only have one limit we need to check in the loop +- */ +- if (max > count) +- max = count; +- +- /* + * Do everything aligned. But that means that we + * need to also expand the maximum.. + */ +@@ -114,6 +107,13 @@ long strnlen_user(const char __user *str + unsigned long max = max_addr - src_addr; + long retval; + ++ /* ++ * Truncate 'max' to the user-specified limit, so that ++ * we only have one limit we need to check in the loop ++ */ ++ if (max > count) ++ max = count; ++ + if (user_access_begin(VERIFY_READ, str, max)) { + retval = do_strnlen_user(str, count, max); + user_access_end(); diff --git a/queue-4.19/make-user_access_begin-do-access_ok.patch b/queue-4.19/make-user_access_begin-do-access_ok.patch new file mode 100644 index 00000000000..8d306f8d0c2 --- /dev/null +++ b/queue-4.19/make-user_access_begin-do-access_ok.patch @@ -0,0 +1,193 @@ +From 594cc251fdd0d231d342d88b2fdff4bc42fb0690 Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Fri, 4 Jan 2019 12:56:09 -0800 +Subject: make 'user_access_begin()' do 'access_ok()' + +From: Linus Torvalds + +commit 594cc251fdd0d231d342d88b2fdff4bc42fb0690 upstream. + +Originally, the rule used to be that you'd have to do access_ok() +separately, and then user_access_begin() before actually doing the +direct (optimized) user access. + +But experience has shown that people then decide not to do access_ok() +at all, and instead rely on it being implied by other operations or +similar. Which makes it very hard to verify that the access has +actually been range-checked. + +If you use the unsafe direct user accesses, hardware features (either +SMAP - Supervisor Mode Access Protection - on x86, or PAN - Privileged +Access Never - on ARM) do force you to use user_access_begin(). But +nothing really forces the range check. + +By putting the range check into user_access_begin(), we actually force +people to do the right thing (tm), and the range check vill be visible +near the actual accesses. We have way too long a history of people +trying to avoid them. + +Signed-off-by: Linus Torvalds +Signed-off-by: Miles Chen +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/include/asm/uaccess.h | 12 +++++++++++- + drivers/gpu/drm/i915/i915_gem_execbuffer.c | 16 ++++++++++++++-- + include/linux/uaccess.h | 2 +- + kernel/compat.c | 6 ++---- + kernel/exit.c | 6 ++---- + lib/strncpy_from_user.c | 9 +++++---- + lib/strnlen_user.c | 9 +++++---- + 7 files changed, 40 insertions(+), 20 deletions(-) + +--- a/arch/x86/include/asm/uaccess.h ++++ b/arch/x86/include/asm/uaccess.h +@@ -711,7 +711,17 @@ extern struct movsl_mask { + * checking before using them, but you have to surround them with the + * user_access_begin/end() pair. + */ +-#define user_access_begin() __uaccess_begin() ++static __must_check inline bool user_access_begin(int type, ++ const void __user *ptr, ++ size_t len) ++{ ++ if (unlikely(!access_ok(type, ptr, len))) ++ return 0; ++ __uaccess_begin(); ++ return 1; ++} ++ ++#define user_access_begin(a, b, c) user_access_begin(a, b, c) + #define user_access_end() __uaccess_end() + + #define unsafe_put_user(x, ptr, err_label) \ +--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c ++++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c +@@ -1604,7 +1604,9 @@ static int eb_copy_relocations(const str + * happened we would make the mistake of assuming that the + * relocations were valid. + */ +- user_access_begin(); ++ if (!user_access_begin(VERIFY_WRITE, urelocs, size)) ++ goto end_user; ++ + for (copied = 0; copied < nreloc; copied++) + unsafe_put_user(-1, + &urelocs[copied].presumed_offset, +@@ -2649,7 +2651,17 @@ i915_gem_execbuffer2_ioctl(struct drm_de + unsigned int i; + + /* Copy the new buffer offsets back to the user's exec list. */ +- user_access_begin(); ++ /* ++ * Note: count * sizeof(*user_exec_list) does not overflow, ++ * because we checked 'count' in check_buffer_count(). ++ * ++ * And this range already got effectively checked earlier ++ * when we did the "copy_from_user()" above. ++ */ ++ if (!user_access_begin(VERIFY_WRITE, user_exec_list, ++ count * sizeof(*user_exec_list))) ++ goto end_user; ++ + for (i = 0; i < args->buffer_count; i++) { + if (!(exec2_list[i].offset & UPDATE)) + continue; +--- a/include/linux/uaccess.h ++++ b/include/linux/uaccess.h +@@ -267,7 +267,7 @@ extern long strncpy_from_unsafe(char *ds + probe_kernel_read(&retval, addr, sizeof(retval)) + + #ifndef user_access_begin +-#define user_access_begin() do { } while (0) ++#define user_access_begin(type, ptr, len) access_ok(type, ptr, len) + #define user_access_end() do { } while (0) + #define unsafe_get_user(x, ptr, err) do { if (unlikely(__get_user(x, ptr))) goto err; } while (0) + #define unsafe_put_user(x, ptr, err) do { if (unlikely(__put_user(x, ptr))) goto err; } while (0) +--- a/kernel/compat.c ++++ b/kernel/compat.c +@@ -354,10 +354,9 @@ long compat_get_bitmap(unsigned long *ma + bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG); + nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); + +- if (!access_ok(VERIFY_READ, umask, bitmap_size / 8)) ++ if (!user_access_begin(VERIFY_READ, umask, bitmap_size / 8)) + return -EFAULT; + +- user_access_begin(); + while (nr_compat_longs > 1) { + compat_ulong_t l1, l2; + unsafe_get_user(l1, umask++, Efault); +@@ -384,10 +383,9 @@ long compat_put_bitmap(compat_ulong_t __ + bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG); + nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); + +- if (!access_ok(VERIFY_WRITE, umask, bitmap_size / 8)) ++ if (!user_access_begin(VERIFY_WRITE, umask, bitmap_size / 8)) + return -EFAULT; + +- user_access_begin(); + while (nr_compat_longs > 1) { + unsigned long m = *mask++; + unsafe_put_user((compat_ulong_t)m, umask++, Efault); +--- a/kernel/exit.c ++++ b/kernel/exit.c +@@ -1617,10 +1617,9 @@ SYSCALL_DEFINE5(waitid, int, which, pid_ + if (!infop) + return err; + +- if (!access_ok(VERIFY_WRITE, infop, sizeof(*infop))) ++ if (!user_access_begin(VERIFY_WRITE, infop, sizeof(*infop))) + return -EFAULT; + +- user_access_begin(); + unsafe_put_user(signo, &infop->si_signo, Efault); + unsafe_put_user(0, &infop->si_errno, Efault); + unsafe_put_user(info.cause, &infop->si_code, Efault); +@@ -1745,10 +1744,9 @@ COMPAT_SYSCALL_DEFINE5(waitid, + if (!infop) + return err; + +- if (!access_ok(VERIFY_WRITE, infop, sizeof(*infop))) ++ if (!user_access_begin(VERIFY_WRITE, infop, sizeof(*infop))) + return -EFAULT; + +- user_access_begin(); + unsafe_put_user(signo, &infop->si_signo, Efault); + unsafe_put_user(0, &infop->si_errno, Efault); + unsafe_put_user(info.cause, &infop->si_code, Efault); +--- a/lib/strncpy_from_user.c ++++ b/lib/strncpy_from_user.c +@@ -115,10 +115,11 @@ long strncpy_from_user(char *dst, const + + kasan_check_write(dst, count); + check_object_size(dst, count, false); +- user_access_begin(); +- retval = do_strncpy_from_user(dst, src, count, max); +- user_access_end(); +- return retval; ++ if (user_access_begin(VERIFY_READ, src, max)) { ++ retval = do_strncpy_from_user(dst, src, count, max); ++ user_access_end(); ++ return retval; ++ } + } + return -EFAULT; + } +--- a/lib/strnlen_user.c ++++ b/lib/strnlen_user.c +@@ -114,10 +114,11 @@ long strnlen_user(const char __user *str + unsigned long max = max_addr - src_addr; + long retval; + +- user_access_begin(); +- retval = do_strnlen_user(str, count, max); +- user_access_end(); +- return retval; ++ if (user_access_begin(VERIFY_READ, str, max)) { ++ retval = do_strnlen_user(str, count, max); ++ user_access_end(); ++ return retval; ++ } + } + return 0; + } diff --git a/queue-4.19/series b/queue-4.19/series index ca379f79267..fc3193b2e9a 100644 --- a/queue-4.19/series +++ b/queue-4.19/series @@ -4,3 +4,10 @@ bridge-avoid-infinite-loop-when-suppressing-ns-messages-with-invalid-options.pat vxlan-avoid-infinite-loop-when-suppressing-ns-messages-with-invalid-options.patch tun-correct-header-offsets-in-napi-frags-mode.patch selftests-bpf-fix-use-of-undeclared-ret_if-macro.patch +make-user_access_begin-do-access_ok.patch +fix-acccess_ok-on-alpha-and-sh.patch +arch-openrisc-fix-issues-with-access_ok.patch +x86-uaccess-inhibit-speculation-past-access_ok-in-user_access_begin.patch +lib-reduce-user_access_begin-boundaries-in-strncpy_from_user-and-strnlen_user.patch +btrfs-merge-btrfs_find_device-and-find_device.patch +btrfs-detect-unbalanced-tree-with-empty-leaf-before-crashing-btree-operations.patch diff --git a/queue-4.19/x86-uaccess-inhibit-speculation-past-access_ok-in-user_access_begin.patch b/queue-4.19/x86-uaccess-inhibit-speculation-past-access_ok-in-user_access_begin.patch new file mode 100644 index 00000000000..f49dc15abb1 --- /dev/null +++ b/queue-4.19/x86-uaccess-inhibit-speculation-past-access_ok-in-user_access_begin.patch @@ -0,0 +1,45 @@ +From 6e693b3ffecb0b478c7050b44a4842854154f715 Mon Sep 17 00:00:00 2001 +From: Will Deacon +Date: Sat, 19 Jan 2019 21:56:05 +0000 +Subject: x86: uaccess: Inhibit speculation past access_ok() in user_access_begin() + +From: Will Deacon + +commit 6e693b3ffecb0b478c7050b44a4842854154f715 upstream. + +Commit 594cc251fdd0 ("make 'user_access_begin()' do 'access_ok()'") +makes the access_ok() check part of the user_access_begin() preceding a +series of 'unsafe' accesses. This has the desirable effect of ensuring +that all 'unsafe' accesses have been range-checked, without having to +pick through all of the callsites to verify whether the appropriate +checking has been made. + +However, the consolidated range check does not inhibit speculation, so +it is still up to the caller to ensure that they are not susceptible to +any speculative side-channel attacks for user addresses that ultimately +fail the access_ok() check. + +This is an oversight, so use __uaccess_begin_nospec() to ensure that +speculation is inhibited until the access_ok() check has passed. + +Reported-by: Julien Thierry +Signed-off-by: Will Deacon +Signed-off-by: Linus Torvalds +Cc: Miles Chen +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/include/asm/uaccess.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/x86/include/asm/uaccess.h ++++ b/arch/x86/include/asm/uaccess.h +@@ -717,7 +717,7 @@ static __must_check inline bool user_acc + { + if (unlikely(!access_ok(type, ptr, len))) + return 0; +- __uaccess_begin(); ++ __uaccess_begin_nospec(); + return 1; + } +