]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.15-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 6 Mar 2023 11:32:04 +0000 (12:32 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 6 Mar 2023 11:32:04 +0000 (12:32 +0100)
added patches:
arm-dts-exynos-correct-hdmi-phy-compatible-in-exynos4.patch
btrfs-hold-block-group-refcount-during-async-discard.patch
ksmbd-do-not-allow-the-actual-frame-length-to-be-smaller-than-the-rfc1002-length.patch
ksmbd-fix-wrong-data-area-length-for-smb2-lock-request.patch
locking-rwsem-prevent-non-first-waiter-from-spinning-in-down_write-slowpath.patch

queue-5.15/arm-dts-exynos-correct-hdmi-phy-compatible-in-exynos4.patch [new file with mode: 0644]
queue-5.15/btrfs-hold-block-group-refcount-during-async-discard.patch [new file with mode: 0644]
queue-5.15/ksmbd-do-not-allow-the-actual-frame-length-to-be-smaller-than-the-rfc1002-length.patch [new file with mode: 0644]
queue-5.15/ksmbd-fix-wrong-data-area-length-for-smb2-lock-request.patch [new file with mode: 0644]
queue-5.15/locking-rwsem-prevent-non-first-waiter-from-spinning-in-down_write-slowpath.patch [new file with mode: 0644]
queue-5.15/series

diff --git a/queue-5.15/arm-dts-exynos-correct-hdmi-phy-compatible-in-exynos4.patch b/queue-5.15/arm-dts-exynos-correct-hdmi-phy-compatible-in-exynos4.patch
new file mode 100644 (file)
index 0000000..0f4f7b4
--- /dev/null
@@ -0,0 +1,31 @@
+From af1c89ddb74f170eccd5a57001d7317560b638ea Mon Sep 17 00:00:00 2001
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Date: Wed, 25 Jan 2023 10:45:05 +0100
+Subject: ARM: dts: exynos: correct HDMI phy compatible in Exynos4
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+commit af1c89ddb74f170eccd5a57001d7317560b638ea upstream.
+
+The HDMI phy compatible was missing vendor prefix.
+
+Fixes: ed80d4cab772 ("ARM: dts: add hdmi related nodes for exynos4 SoCs")
+Cc: <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20230125094513.155063-1-krzysztof.kozlowski@linaro.org
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm/boot/dts/exynos4.dtsi |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/exynos4.dtsi
++++ b/arch/arm/boot/dts/exynos4.dtsi
+@@ -605,7 +605,7 @@
+                       status = "disabled";
+                       hdmi_i2c_phy: hdmiphy@38 {
+-                              compatible = "exynos4210-hdmiphy";
++                              compatible = "samsung,exynos4210-hdmiphy";
+                               reg = <0x38>;
+                       };
+               };
diff --git a/queue-5.15/btrfs-hold-block-group-refcount-during-async-discard.patch b/queue-5.15/btrfs-hold-block-group-refcount-during-async-discard.patch
new file mode 100644 (file)
index 0000000..d07dddd
--- /dev/null
@@ -0,0 +1,153 @@
+From 2b5463fcbdfb24e898916bcae2b1359042d26963 Mon Sep 17 00:00:00 2001
+From: Boris Burkov <boris@bur.io>
+Date: Thu, 12 Jan 2023 16:05:11 -0800
+Subject: btrfs: hold block group refcount during async discard
+
+From: Boris Burkov <boris@bur.io>
+
+commit 2b5463fcbdfb24e898916bcae2b1359042d26963 upstream.
+
+Async discard does not acquire the block group reference count while it
+holds a reference on the discard list. This is generally OK, as the
+paths which destroy block groups tend to try to synchronize on
+cancelling async discard work. However, relying on cancelling work
+requires careful analysis to be sure it is safe from races with
+unpinning scheduling more work.
+
+While I am unable to find a race with unpinning in the current code for
+either the unused bgs or relocation paths, I believe we have one in an
+older version of auto relocation in a Meta internal build. This suggests
+that this is in fact an error prone model, and could be fragile to
+future changes to these bg deletion paths.
+
+To make this ownership more clear, add a refcount for async discard. If
+work is queued for a block group, its refcount should be incremented,
+and when work is completed or canceled, it should be decremented.
+
+CC: stable@vger.kernel.org # 5.15+
+Signed-off-by: Boris Burkov <boris@bur.io>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/discard.c |   41 ++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 38 insertions(+), 3 deletions(-)
+
+--- a/fs/btrfs/discard.c
++++ b/fs/btrfs/discard.c
+@@ -77,6 +77,7 @@ static struct list_head *get_discard_lis
+ static void __add_to_discard_list(struct btrfs_discard_ctl *discard_ctl,
+                                 struct btrfs_block_group *block_group)
+ {
++      lockdep_assert_held(&discard_ctl->lock);
+       if (!btrfs_run_discard_work(discard_ctl))
+               return;
+@@ -88,6 +89,8 @@ static void __add_to_discard_list(struct
+                                                     BTRFS_DISCARD_DELAY);
+               block_group->discard_state = BTRFS_DISCARD_RESET_CURSOR;
+       }
++      if (list_empty(&block_group->discard_list))
++              btrfs_get_block_group(block_group);
+       list_move_tail(&block_group->discard_list,
+                      get_discard_list(discard_ctl, block_group));
+@@ -107,8 +110,12 @@ static void add_to_discard_list(struct b
+ static void add_to_discard_unused_list(struct btrfs_discard_ctl *discard_ctl,
+                                      struct btrfs_block_group *block_group)
+ {
++      bool queued;
++
+       spin_lock(&discard_ctl->lock);
++      queued = !list_empty(&block_group->discard_list);
++
+       if (!btrfs_run_discard_work(discard_ctl)) {
+               spin_unlock(&discard_ctl->lock);
+               return;
+@@ -120,6 +127,8 @@ static void add_to_discard_unused_list(s
+       block_group->discard_eligible_time = (ktime_get_ns() +
+                                             BTRFS_DISCARD_UNUSED_DELAY);
+       block_group->discard_state = BTRFS_DISCARD_RESET_CURSOR;
++      if (!queued)
++              btrfs_get_block_group(block_group);
+       list_add_tail(&block_group->discard_list,
+                     &discard_ctl->discard_list[BTRFS_DISCARD_INDEX_UNUSED]);
+@@ -130,6 +139,7 @@ static bool remove_from_discard_list(str
+                                    struct btrfs_block_group *block_group)
+ {
+       bool running = false;
++      bool queued = false;
+       spin_lock(&discard_ctl->lock);
+@@ -139,7 +149,16 @@ static bool remove_from_discard_list(str
+       }
+       block_group->discard_eligible_time = 0;
++      queued = !list_empty(&block_group->discard_list);
+       list_del_init(&block_group->discard_list);
++      /*
++       * If the block group is currently running in the discard workfn, we
++       * don't want to deref it, since it's still being used by the workfn.
++       * The workfn will notice this case and deref the block group when it is
++       * finished.
++       */
++      if (queued && !running)
++              btrfs_put_block_group(block_group);
+       spin_unlock(&discard_ctl->lock);
+@@ -212,10 +231,12 @@ again:
+       if (block_group && now >= block_group->discard_eligible_time) {
+               if (block_group->discard_index == BTRFS_DISCARD_INDEX_UNUSED &&
+                   block_group->used != 0) {
+-                      if (btrfs_is_block_group_data_only(block_group))
++                      if (btrfs_is_block_group_data_only(block_group)) {
+                               __add_to_discard_list(discard_ctl, block_group);
+-                      else
++                      } else {
+                               list_del_init(&block_group->discard_list);
++                              btrfs_put_block_group(block_group);
++                      }
+                       goto again;
+               }
+               if (block_group->discard_state == BTRFS_DISCARD_RESET_CURSOR) {
+@@ -502,6 +523,15 @@ static void btrfs_discard_workfn(struct
+       spin_lock(&discard_ctl->lock);
+       discard_ctl->prev_discard = trimmed;
+       discard_ctl->prev_discard_time = now;
++      /*
++       * If the block group was removed from the discard list while it was
++       * running in this workfn, then we didn't deref it, since this function
++       * still owned that reference. But we set the discard_ctl->block_group
++       * back to NULL, so we can use that condition to know that now we need
++       * to deref the block_group.
++       */
++      if (discard_ctl->block_group == NULL)
++              btrfs_put_block_group(block_group);
+       discard_ctl->block_group = NULL;
+       __btrfs_discard_schedule_work(discard_ctl, now, false);
+       spin_unlock(&discard_ctl->lock);
+@@ -638,8 +668,12 @@ void btrfs_discard_punt_unused_bgs_list(
+       list_for_each_entry_safe(block_group, next, &fs_info->unused_bgs,
+                                bg_list) {
+               list_del_init(&block_group->bg_list);
+-              btrfs_put_block_group(block_group);
+               btrfs_discard_queue_work(&fs_info->discard_ctl, block_group);
++              /*
++               * This put is for the get done by btrfs_mark_bg_unused.
++               * Queueing discard incremented it for discard's reference.
++               */
++              btrfs_put_block_group(block_group);
+       }
+       spin_unlock(&fs_info->unused_bgs_lock);
+ }
+@@ -669,6 +703,7 @@ static void btrfs_discard_purge_list(str
+                       if (block_group->used == 0)
+                               btrfs_mark_bg_unused(block_group);
+                       spin_lock(&discard_ctl->lock);
++                      btrfs_put_block_group(block_group);
+               }
+       }
+       spin_unlock(&discard_ctl->lock);
diff --git a/queue-5.15/ksmbd-do-not-allow-the-actual-frame-length-to-be-smaller-than-the-rfc1002-length.patch b/queue-5.15/ksmbd-do-not-allow-the-actual-frame-length-to-be-smaller-than-the-rfc1002-length.patch
new file mode 100644 (file)
index 0000000..bf91df0
--- /dev/null
@@ -0,0 +1,58 @@
+From fb533473d1595fe79ecb528fda1de33552b07178 Mon Sep 17 00:00:00 2001
+From: Namjae Jeon <linkinjeon@kernel.org>
+Date: Sat, 11 Feb 2023 00:27:34 +0900
+Subject: ksmbd: do not allow the actual frame length to be smaller than the rfc1002 length
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+commit fb533473d1595fe79ecb528fda1de33552b07178 upstream.
+
+ksmbd allowed the actual frame length to be smaller than the rfc1002
+length. If allowed, it is possible to allocates a large amount of memory
+that can be limited by credit management and can eventually cause memory
+exhaustion problem. This patch do not allow it except SMB2 Negotiate
+request which will be validated when message handling proceeds.
+Also, Allow a message that padded to 8byte boundary.
+
+Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
+Cc: stable@vger.kernel.org
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ksmbd/smb2misc.c |   21 ++++++++++-----------
+ 1 file changed, 10 insertions(+), 11 deletions(-)
+
+--- a/fs/ksmbd/smb2misc.c
++++ b/fs/ksmbd/smb2misc.c
+@@ -414,20 +414,19 @@ int ksmbd_smb2_check_message(struct ksmb
+                       goto validate_credit;
+               /*
+-               * windows client also pad up to 8 bytes when compounding.
+-               * If pad is longer than eight bytes, log the server behavior
+-               * (once), since may indicate a problem but allow it and
+-               * continue since the frame is parseable.
++               * SMB2 NEGOTIATE request will be validated when message
++               * handling proceeds.
+                */
+-              if (clc_len < len) {
+-                      ksmbd_debug(SMB,
+-                                  "cli req padded more than expected. Length %d not %d for cmd:%d mid:%llu\n",
+-                                  len, clc_len, command,
+-                                  le64_to_cpu(hdr->MessageId));
++              if (command == SMB2_NEGOTIATE_HE)
+                       goto validate_credit;
+-              }
+-              ksmbd_debug(SMB,
++              /*
++               * Allow a message that padded to 8byte boundary.
++               */
++              if (clc_len < len && (len - clc_len) < 8)
++                      goto validate_credit;
++
++              pr_err_ratelimited(
+                           "cli req too short, len %d not %d. cmd:%d mid:%llu\n",
+                           len, clc_len, command,
+                           le64_to_cpu(hdr->MessageId));
diff --git a/queue-5.15/ksmbd-fix-wrong-data-area-length-for-smb2-lock-request.patch b/queue-5.15/ksmbd-fix-wrong-data-area-length-for-smb2-lock-request.patch
new file mode 100644 (file)
index 0000000..f085304
--- /dev/null
@@ -0,0 +1,47 @@
+From 8f8c43b125882ac14372f8dca0c8e50a59e78d79 Mon Sep 17 00:00:00 2001
+From: Namjae Jeon <linkinjeon@kernel.org>
+Date: Wed, 8 Feb 2023 09:50:46 +0900
+Subject: ksmbd: fix wrong data area length for smb2 lock request
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+commit 8f8c43b125882ac14372f8dca0c8e50a59e78d79 upstream.
+
+When turning debug mode on, The following error message from
+ksmbd_smb2_check_message() is coming.
+
+ksmbd: cli req padded more than expected. Length 112 not 88 for cmd:10 mid:14
+
+data area length calculation for smb2 lock request in smb2_get_data_area_len() is
+incorrect.
+
+Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
+Cc: stable@vger.kernel.org
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ksmbd/smb2misc.c |   10 +++-------
+ 1 file changed, 3 insertions(+), 7 deletions(-)
+
+--- a/fs/ksmbd/smb2misc.c
++++ b/fs/ksmbd/smb2misc.c
+@@ -150,15 +150,11 @@ static int smb2_get_data_area_len(unsign
+               break;
+       case SMB2_LOCK:
+       {
+-              int lock_count;
++              unsigned short lock_count;
+-              /*
+-               * smb2_lock request size is 48 included single
+-               * smb2_lock_element structure size.
+-               */
+-              lock_count = le16_to_cpu(((struct smb2_lock_req *)hdr)->LockCount) - 1;
++              lock_count = le16_to_cpu(((struct smb2_lock_req *)hdr)->LockCount);
+               if (lock_count > 0) {
+-                      *off = __SMB2_HEADER_STRUCTURE_SIZE + 48;
++                      *off = offsetof(struct smb2_lock_req, locks);
+                       *len = sizeof(struct smb2_lock_element) * lock_count;
+               }
+               break;
diff --git a/queue-5.15/locking-rwsem-prevent-non-first-waiter-from-spinning-in-down_write-slowpath.patch b/queue-5.15/locking-rwsem-prevent-non-first-waiter-from-spinning-in-down_write-slowpath.patch
new file mode 100644 (file)
index 0000000..bb92904
--- /dev/null
@@ -0,0 +1,99 @@
+From b613c7f31476c44316bfac1af7cac714b7d6bef9 Mon Sep 17 00:00:00 2001
+From: Waiman Long <longman@redhat.com>
+Date: Wed, 25 Jan 2023 19:36:25 -0500
+Subject: locking/rwsem: Prevent non-first waiter from spinning in down_write() slowpath
+
+From: Waiman Long <longman@redhat.com>
+
+commit b613c7f31476c44316bfac1af7cac714b7d6bef9 upstream.
+
+A non-first waiter can potentially spin in the for loop of
+rwsem_down_write_slowpath() without sleeping but fail to acquire the
+lock even if the rwsem is free if the following sequence happens:
+
+  Non-first RT waiter    First waiter      Lock holder
+  -------------------    ------------      -----------
+  Acquire wait_lock
+  rwsem_try_write_lock():
+    Set handoff bit if RT or
+      wait too long
+    Set waiter->handoff_set
+  Release wait_lock
+                         Acquire wait_lock
+                         Inherit waiter->handoff_set
+                         Release wait_lock
+                                          Clear owner
+                                           Release lock
+  if (waiter.handoff_set) {
+    rwsem_spin_on_owner(();
+    if (OWNER_NULL)
+      goto trylock_again;
+  }
+  trylock_again:
+  Acquire wait_lock
+  rwsem_try_write_lock():
+     if (first->handoff_set && (waiter != first))
+       return false;
+  Release wait_lock
+
+A non-first waiter cannot really acquire the rwsem even if it mistakenly
+believes that it can spin on OWNER_NULL value. If that waiter happens
+to be an RT task running on the same CPU as the first waiter, it can
+block the first waiter from acquiring the rwsem leading to live lock.
+Fix this problem by making sure that a non-first waiter cannot spin in
+the slowpath loop without sleeping.
+
+Fixes: d257cc8cb8d5 ("locking/rwsem: Make handoff bit handling more consistent")
+Signed-off-by: Waiman Long <longman@redhat.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Tested-by: Mukesh Ojha <quic_mojha@quicinc.com>
+Reviewed-by: Mukesh Ojha <quic_mojha@quicinc.com>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20230126003628.365092-2-longman@redhat.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/locking/rwsem.c |   19 +++++++++----------
+ 1 file changed, 9 insertions(+), 10 deletions(-)
+
+--- a/kernel/locking/rwsem.c
++++ b/kernel/locking/rwsem.c
+@@ -586,18 +586,16 @@ static inline bool rwsem_try_write_lock(
+                        */
+                       if (first->handoff_set && (waiter != first))
+                               return false;
+-
+-                      /*
+-                       * First waiter can inherit a previously set handoff
+-                       * bit and spin on rwsem if lock acquisition fails.
+-                       */
+-                      if (waiter == first)
+-                              waiter->handoff_set = true;
+               }
+               new = count;
+               if (count & RWSEM_LOCK_MASK) {
++                      /*
++                       * A waiter (first or not) can set the handoff bit
++                       * if it is an RT task or wait in the wait queue
++                       * for too long.
++                       */
+                       if (has_handoff || (!rt_task(waiter->task) &&
+                                           !time_after(jiffies, waiter->timeout)))
+                               return false;
+@@ -613,11 +611,12 @@ static inline bool rwsem_try_write_lock(
+       } while (!atomic_long_try_cmpxchg_acquire(&sem->count, &count, new));
+       /*
+-       * We have either acquired the lock with handoff bit cleared or
+-       * set the handoff bit.
++       * We have either acquired the lock with handoff bit cleared or set
++       * the handoff bit. Only the first waiter can have its handoff_set
++       * set here to enable optimistic spinning in slowpath loop.
+        */
+       if (new & RWSEM_FLAG_HANDOFF) {
+-              waiter->handoff_set = true;
++              first->handoff_set = true;
+               lockevent_inc(rwsem_wlock_handoff);
+               return false;
+       }
index 0f76f5d3fcdccc4af7c80a4acf4aa655de2541bf..7c9cd5b6c1ee00d76ca8da9616e9cc1f0da75d2c 100644 (file)
@@ -439,3 +439,8 @@ s390-discard-.interp-section.patch
 s390-kprobes-fix-irq-mask-clobbering-on-kprobe-reenter-from-post_handler.patch
 s390-kprobes-fix-current_kprobe-never-cleared-after-kprobes-reenter.patch
 cifs-fix-uninitialized-memory-read-in-smb3_qfs_tcon.patch
+btrfs-hold-block-group-refcount-during-async-discard.patch
+locking-rwsem-prevent-non-first-waiter-from-spinning-in-down_write-slowpath.patch
+ksmbd-fix-wrong-data-area-length-for-smb2-lock-request.patch
+ksmbd-do-not-allow-the-actual-frame-length-to-be-smaller-than-the-rfc1002-length.patch
+arm-dts-exynos-correct-hdmi-phy-compatible-in-exynos4.patch