]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 11 Jun 2020 11:22:02 +0000 (13:22 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 11 Jun 2020 11:22:02 +0000 (13:22 +0200)
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

queue-4.19/arch-openrisc-fix-issues-with-access_ok.patch [new file with mode: 0644]
queue-4.19/btrfs-detect-unbalanced-tree-with-empty-leaf-before-crashing-btree-operations.patch [new file with mode: 0644]
queue-4.19/btrfs-merge-btrfs_find_device-and-find_device.patch [new file with mode: 0644]
queue-4.19/fix-acccess_ok-on-alpha-and-sh.patch [new file with mode: 0644]
queue-4.19/lib-reduce-user_access_begin-boundaries-in-strncpy_from_user-and-strnlen_user.patch [new file with mode: 0644]
queue-4.19/make-user_access_begin-do-access_ok.patch [new file with mode: 0644]
queue-4.19/series
queue-4.19/x86-uaccess-inhibit-speculation-past-access_ok-in-user_access_begin.patch [new file with mode: 0644]

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 (file)
index 0000000..5b78f5d
--- /dev/null
@@ -0,0 +1,46 @@
+From 9cb2feb4d21d97386eb25c7b67e2793efcc1e70a Mon Sep 17 00:00:00 2001
+From: Stafford Horne <shorne@gmail.com>
+Date: Tue, 8 Jan 2019 22:15:15 +0900
+Subject: arch/openrisc: Fix issues with access_ok()
+
+From: Stafford Horne <shorne@gmail.com>
+
+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 <linux@roeck-us.net>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Stafford Horne <shorne@gmail.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Miles Chen <miles.chen@mediatek.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..94886f5
--- /dev/null
@@ -0,0 +1,124 @@
+From 62fdaa52a3d00a875da771719b6dc537ca79fce1 Mon Sep 17 00:00:00 2001
+From: Qu Wenruo <wqu@suse.com>
+Date: Thu, 22 Aug 2019 10:14:15 +0800
+Subject: btrfs: Detect unbalanced tree with empty leaf before crashing btree operations
+
+From: Qu Wenruo <wqu@suse.com>
+
+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 <nborisov@suse.com>
+Signed-off-by: Qu Wenruo <wqu@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Vikash Bansal <bvikas@vmware.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..5400162
--- /dev/null
@@ -0,0 +1,271 @@
+From 09ba3bc9dd150457c506e4661380a6183af651c1 Mon Sep 17 00:00:00 2001
+From: Anand Jain <anand.jain@oracle.com>
+Date: Sat, 19 Jan 2019 14:48:55 +0800
+Subject: btrfs: merge btrfs_find_device and find_device
+
+From: Anand Jain <anand.jain@oracle.com>
+
+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 <anand.jain@oracle.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+[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 <bvikas@vmware.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..d1f4328
--- /dev/null
@@ -0,0 +1,126 @@
+From 94bd8a05cd4de344a9a57e52ef7d99550251984f Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Sun, 6 Jan 2019 11:15:04 -0800
+Subject: Fix 'acccess_ok()' on alpha and SH
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+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 <linux@roeck-us.net>
+Cc: Matt Turner <mattst88@gmail.com>
+Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Miles Chen <miles.chen@mediatek.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..218b95d
--- /dev/null
@@ -0,0 +1,89 @@
+From ab10ae1c3bef56c29bac61e1201c752221b87b41 Mon Sep 17 00:00:00 2001
+From: Christophe Leroy <christophe.leroy@c-s.fr>
+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 <christophe.leroy@c-s.fr>
+
+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 <christophe.leroy@c-s.fr>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Miles Chen <miles.chen@mediatek.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..8d306f8
--- /dev/null
@@ -0,0 +1,193 @@
+From 594cc251fdd0d231d342d88b2fdff4bc42fb0690 Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Fri, 4 Jan 2019 12:56:09 -0800
+Subject: make 'user_access_begin()' do 'access_ok()'
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+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 <torvalds@linux-foundation.org>
+Signed-off-by: Miles Chen <miles.chen@mediatek.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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;
+ }
index ca379f79267882f00a0b3c6046d4089dc6dd1f09..fc3193b2e9af3e424aa8eb5b8d6ce2f79440093f 100644 (file)
@@ -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 (file)
index 0000000..f49dc15
--- /dev/null
@@ -0,0 +1,45 @@
+From 6e693b3ffecb0b478c7050b44a4842854154f715 Mon Sep 17 00:00:00 2001
+From: Will Deacon <will@kernel.org>
+Date: Sat, 19 Jan 2019 21:56:05 +0000
+Subject: x86: uaccess: Inhibit speculation past access_ok() in user_access_begin()
+
+From: Will Deacon <will.deacon@arm.com>
+
+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 <julien.thierry@arm.com>
+Signed-off-by: Will Deacon <will.deacon@arm.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Miles Chen <miles.chen@mediatek.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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;
+ }