aboutsummarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorScott B2022-02-08 21:05:52 -0800
committerScott B2022-02-11 01:16:12 -0800
commit5dac791642c88b593c71bfd50c7bf568aa6e5f83 (patch)
tree8eaf40b955e97e4266a1573ddb59deb9f1f23426
parentae87b0aaaefeea375d839d76e9e063b649285c0e (diff)
downloadaur-5dac791642c88b593c71bfd50c7bf568aa6e5f83.tar.gz
hotfix: patch iwlwifi/bt boot deadlocks
-rw-r--r--.SRCINFO4
-rw-r--r--Bluetooth-fix-deadlock-for-RFCOMM-sk-state-change.patch231
-rw-r--r--PKGBUILD6
-rw-r--r--iwlwifi-fix-use-after-free.patch48
4 files changed, 289 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
index bf4741ed40c5..7ebe65aef309 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -21,8 +21,10 @@ pkgbase = linux-xanmod-rog
source = https://github.com/xanmod/linux/releases/download/5.16.7-xanmod1/patch-5.16.7-xanmod1.xz
source = choose-gcc-optimization.sh
source = https://cdn.kernel.org/pub/linux/kernel/v5.x/incr/patch-5.16.7-8.xz
+ source = iwlwifi-fix-use-after-free.patch
source = Bluetooth-btintel-Fix-bdaddress-comparison-with-garb.patch
source = Bluetooth-Read-codec-capabilities-only-if-supported.patch
+ source = Bluetooth-fix-deadlock-for-RFCOMM-sk-state-change.patch
source = udp-ipv6-optimisations-v2-net-next.patch
source = af_unix-Replace-unix_table_lock-with-per-hash-locks.patch
source = CONFIG_RCU_FAST_NO_HZ-removal-for-v5.17.patch
@@ -48,8 +50,10 @@ pkgbase = linux-xanmod-rog
sha256sums = 834dd6603ec3fb0a72e3a1a97669a7198cd6921c4f355b155b3d587a8f0fcea4
sha256sums = 278118011d7a2eeca9971ac97b31bf0c55ab55e99c662ab9ae4717b55819c9a2
sha256sums = bb915d4f4291cbc7893a9f61fb5e1d90d9a6b368306710ef732795365b8b0108
+ sha256sums = 7b6825a43b4173750768a1a50bfd38dcbd326aec6d56cc886490d97e323b7ce9
sha256sums = 241f01f06849fcec462d72355ca3ab6bd34931731dec89876d785912ac532398
sha256sums = dd01bd3f774c3a9af42b6d89f534f39c4a5f200db32cd6d4b72a29325645100e
+ sha256sums = a9647897e59b04cb883dcf649b3108e9397d5a6c672bc545ea0c6bb7bb30d5a9
sha256sums = 56f8f93a38ed7236c2504c79645a33123ee7bdf3c0cbb97dfd90600df06be7dd
sha256sums = eac568d7f2b369a8a2b685fae236388c3516938000d4d6b2116b5874c4f93430
sha256sums = e74649fb883f2c8c3703c730e45119fca7126dc0599d6bc814de6dcf5a07e7cb
diff --git a/Bluetooth-fix-deadlock-for-RFCOMM-sk-state-change.patch b/Bluetooth-fix-deadlock-for-RFCOMM-sk-state-change.patch
new file mode 100644
index 000000000000..b7b8a460d2d5
--- /dev/null
+++ b/Bluetooth-fix-deadlock-for-RFCOMM-sk-state-change.patch
@@ -0,0 +1,231 @@
+From a3522be2facbca017e2ce12b7899bef3775e26c0 Mon Sep 17 00:00:00 2001
+From: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
+Date: Mon, 4 Oct 2021 14:07:34 -0400
+Subject: [PATCH] Bluetooth: fix deadlock for RFCOMM sk state change
+
+Syzbot reports the following task hang [1]:
+
+INFO: task syz-executor255:8499 blocked for more than 143 seconds.
+ Not tainted 5.14.0-rc7-syzkaller #0
+
+Call Trace:
+ context_switch kernel/sched/core.c:4681 [inline]
+ __schedule+0x93a/0x26f0 kernel/sched/core.c:5938
+ schedule+0xd3/0x270 kernel/sched/core.c:6017
+ __lock_sock+0x13d/0x260 net/core/sock.c:2644
+ lock_sock_nested+0xf6/0x120 net/core/sock.c:3185
+ lock_sock include/net/sock.h:1612 [inline]
+ rfcomm_sk_state_change+0xb4/0x390 net/bluetooth/rfcomm/sock.c:73
+ __rfcomm_dlc_close+0x1b6/0x8a0 net/bluetooth/rfcomm/core.c:489
+ rfcomm_dlc_close+0x1ea/0x240 net/bluetooth/rfcomm/core.c:520
+ __rfcomm_sock_close+0xac/0x260 net/bluetooth/rfcomm/sock.c:220
+ rfcomm_sock_shutdown+0xe9/0x210 net/bluetooth/rfcomm/sock.c:931
+ rfcomm_sock_release+0x5f/0x140 net/bluetooth/rfcomm/sock.c:951
+ __sock_release+0xcd/0x280 net/socket.c:649
+ sock_close+0x18/0x20 net/socket.c:1314
+ __fput+0x288/0x920 fs/file_table.c:280
+ task_work_run+0xdd/0x1a0 kernel/task_work.c:164
+ exit_task_work include/linux/task_work.h:32 [inline]
+ do_exit+0xbd4/0x2a60 kernel/exit.c:825
+ do_group_exit+0x125/0x310 kernel/exit.c:922
+ get_signal+0x47f/0x2160 kernel/signal.c:2808
+ arch_do_signal_or_restart+0x2a9/0x1c40 arch/x86/kernel/signal.c:865
+ handle_signal_work kernel/entry/common.c:148 [inline]
+ exit_to_user_mode_loop kernel/entry/common.c:172 [inline]
+ exit_to_user_mode_prepare+0x17d/0x290 kernel/entry/common.c:209
+ __syscall_exit_to_user_mode_work kernel/entry/common.c:291 [inline]
+ syscall_exit_to_user_mode+0x19/0x60 kernel/entry/common.c:302
+ do_syscall_64+0x42/0xb0 arch/x86/entry/common.c:86
+ entry_SYSCALL_64_after_hwframe+0x44/0xae
+
+Showing all locks held in the system:
+1 lock held by khungtaskd/1653:
+ #0: ffffffff8b97c280 (rcu_read_lock){....}-{1:2}, at:
+ debug_show_all_locks+0x53/0x260 kernel/locking/lockdep.c:6446
+1 lock held by krfcommd/4781:
+ #0: ffffffff8d306528 (rfcomm_mutex){+.+.}-{3:3}, at:
+ rfcomm_process_sessions net/bluetooth/rfcomm/core.c:1979 [inline]
+ #0: ffffffff8d306528 (rfcomm_mutex){+.+.}-{3:3}, at:
+ rfcomm_run+0x2ed/0x4a20 net/bluetooth/rfcomm/core.c:2086
+2 locks held by in:imklog/8206:
+ #0: ffff8880182ce5f0 (&f->f_pos_lock){+.+.}-{3:3}, at:
+ __fdget_pos+0xe9/0x100 fs/file.c:974
+ #1: ffff8880b9c51a58 (&rq->__lock){-.-.}-{2:2}, at:
+ raw_spin_rq_lock_nested kernel/sched/core.c:460 [inline]
+ #1: ffff8880b9c51a58 (&rq->__lock){-.-.}-{2:2}, at: raw_spin_rq_lock
+ kernel/sched/sched.h:1307 [inline]
+ #1: ffff8880b9c51a58 (&rq->__lock){-.-.}-{2:2}, at: rq_lock
+ kernel/sched/sched.h:1610 [inline]
+ #1: ffff8880b9c51a58 (&rq->__lock){-.-.}-{2:2}, at:
+ __schedule+0x233/0x26f0 kernel/sched/core.c:5852
+4 locks held by syz-executor255/8499:
+ #0: ffff888039a83690 (&sb->s_type->i_mutex_key#13){+.+.}-{3:3}, at:
+ inode_lock include/linux/fs.h:774 [inline]
+ #0: ffff888039a83690 (&sb->s_type->i_mutex_key#13){+.+.}-{3:3}, at:
+ __sock_release+0x86/0x280 net/socket.c:648
+ #1:
+ ffff88802fa31120 (sk_lock-AF_BLUETOOTH-BTPROTO_RFCOMM){+.+.}-{0:0},
+ at: lock_sock include/net/sock.h:1612 [inline]
+ #1:
+ ffff88802fa31120 (sk_lock-AF_BLUETOOTH-BTPROTO_RFCOMM){+.+.}-{0:0},
+ at: rfcomm_sock_shutdown+0x54/0x210 net/bluetooth/rfcomm/sock.c:928
+ #2: ffffffff8d306528 (rfcomm_mutex){+.+.}-{3:3}, at:
+ rfcomm_dlc_close+0x34/0x240 net/bluetooth/rfcomm/core.c:507
+ #3: ffff888141bd6d28 (&d->lock){+.+.}-{3:3}, at:
+ __rfcomm_dlc_close+0x162/0x8a0 net/bluetooth/rfcomm/core.c:487
+==================================================================
+
+The task hangs because of a deadlock that occurs when lock_sock() is
+called in rfcomm_sk_state_change(). One such call stack is:
+
+ rfcomm_sock_shutdown():
+ lock_sock();
+ __rfcomm_sock_close():
+ rfcomm_dlc_close():
+ __rfcomm_dlc_close():
+ rfcomm_dlc_lock();
+ rfcomm_sk_state_change():
+ lock_sock();
+
+lock_sock() has to be called when the sk state is changed because the
+lock is not always held when rfcomm_sk_state_change() is
+called. However, besides the recursive deadlock, there is also an
+issue of a lock hierarchy inversion between rfcomm_dlc_lock() and
+lock_sock() if the socket is locked in rfcomm_sk_state_change().
+
+To avoid these issues, we can instead schedule the sk state change in
+the global workqueue. This is already the implicit assumption about
+how sk state changes happen. For example, in rfcomm_sock_shutdown(),
+the call to __rfcomm_sock_close() is followed by
+bt_sock_wait_state().
+
+Additionally, the call to rfcomm_sock_kill() inside
+rfcomm_sk_state_change() should be removed. The socket shouldn't be
+killed here because only rfcomm_sock_release() calls sock_orphan(),
+which it already follows up with a call to rfcomm_sock_kill().
+
+Fixes: b7ce436a5d79 ("Bluetooth: switch to lock_sock in RFCOMM")
+Link: https://syzkaller.appspot.com/bug?extid=7d51f807c81b190a127d [1]
+Reported-by: syzbot+7d51f807c81b190a127d@syzkaller.appspotmail.com
+Tested-by: syzbot+7d51f807c81b190a127d@syzkaller.appspotmail.com
+Signed-off-by: Desmond Cheong Zhi Xi <desmondcheongzx@gmail.com>
+Cc: Hillf Danton <hdanton@sina.com>
+---
+ include/net/bluetooth/rfcomm.h | 3 +++
+ net/bluetooth/rfcomm/core.c | 2 ++
+ net/bluetooth/rfcomm/sock.c | 34 ++++++++++++++++++++++------------
+ 3 files changed, 27 insertions(+), 12 deletions(-)
+
+diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
+index 99d26879b02a..a92799fc5e74 100644
+--- a/include/net/bluetooth/rfcomm.h
++++ b/include/net/bluetooth/rfcomm.h
+@@ -171,6 +171,7 @@ struct rfcomm_dlc {
+ struct rfcomm_session *session;
+ struct sk_buff_head tx_queue;
+ struct timer_list timer;
++ struct work_struct state_change_work;
+
+ struct mutex lock;
+ unsigned long state;
+@@ -186,6 +187,7 @@ struct rfcomm_dlc {
+ u8 sec_level;
+ u8 role_switch;
+ u32 defer_setup;
++ int err;
+
+ uint mtu;
+ uint cfc;
+@@ -310,6 +312,7 @@ struct rfcomm_pinfo {
+ u8 role_switch;
+ };
+
++void __rfcomm_sk_state_change(struct work_struct *work);
+ int rfcomm_init_sockets(void);
+ void rfcomm_cleanup_sockets(void);
+
+diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
+index 7324764384b6..c6494e85cd68 100644
+--- a/net/bluetooth/rfcomm/core.c
++++ b/net/bluetooth/rfcomm/core.c
+@@ -289,6 +289,7 @@ static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d)
+ d->flags = 0;
+ d->mscex = 0;
+ d->sec_level = BT_SECURITY_LOW;
++ d->err = 0;
+ d->mtu = RFCOMM_DEFAULT_MTU;
+ d->v24_sig = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV;
+
+@@ -306,6 +307,7 @@ struct rfcomm_dlc *rfcomm_dlc_alloc(gfp_t prio)
+ timer_setup(&d->timer, rfcomm_dlc_timeout, 0);
+
+ skb_queue_head_init(&d->tx_queue);
++ INIT_WORK(&d->state_change_work, __rfcomm_sk_state_change);
+ mutex_init(&d->lock);
+ refcount_set(&d->refcnt, 1);
+
+diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
+index 4bf4ea6cbb5e..4850dafbaa05 100644
+--- a/net/bluetooth/rfcomm/sock.c
++++ b/net/bluetooth/rfcomm/sock.c
+@@ -61,19 +61,22 @@ static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb)
+ rfcomm_dlc_throttle(d);
+ }
+
+-static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
++void __rfcomm_sk_state_change(struct work_struct *work)
+ {
++ struct rfcomm_dlc *d = container_of(work, struct rfcomm_dlc,
++ state_change_work);
+ struct sock *sk = d->owner, *parent;
+
+ if (!sk)
+ return;
+
+- BT_DBG("dlc %p state %ld err %d", d, d->state, err);
+-
+ lock_sock(sk);
++ rfcomm_dlc_lock(d);
+
+- if (err)
+- sk->sk_err = err;
++ BT_DBG("dlc %p state %ld err %d", d, d->state, d->err);
++
++ if (d->err)
++ sk->sk_err = d->err;
+
+ sk->sk_state = d->state;
+
+@@ -91,15 +94,22 @@ static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
+ sk->sk_state_change(sk);
+ }
+
++ rfcomm_dlc_unlock(d);
+ release_sock(sk);
++ sock_put(sk);
++}
+
+- if (parent && sock_flag(sk, SOCK_ZAPPED)) {
+- /* We have to drop DLC lock here, otherwise
+- * rfcomm_sock_destruct() will dead lock. */
+- rfcomm_dlc_unlock(d);
+- rfcomm_sock_kill(sk);
+- rfcomm_dlc_lock(d);
+- }
++static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
++{
++ struct sock *sk = d->owner;
++
++ if (!sk)
++ return;
++
++ d->err = err;
++ sock_hold(sk);
++ if (!schedule_work(&d->state_change_work))
++ sock_put(sk);
+ }
+
+ /* ---- Socket functions ---- */
+--
+2.35.1
+
diff --git a/PKGBUILD b/PKGBUILD
index f98464615f9a..42a80bb41518 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -106,9 +106,13 @@ source=("https://cdn.kernel.org/pub/linux/kernel/v${_branch}/linux-${_major}.tar
"https://cdn.kernel.org/pub/linux/kernel/v5.x/incr/patch-5.16.7-8.xz"
#"Linux-5.16.8-rc2.patch"
+ # hotfix: address iwlwifi crash at boot on some hardware
+ "iwlwifi-fix-use-after-free.patch"
+
# Arch: misc hotfixes
"Bluetooth-btintel-Fix-bdaddress-comparison-with-garb.patch"
"Bluetooth-Read-codec-capabilities-only-if-supported.patch"
+ "Bluetooth-fix-deadlock-for-RFCOMM-sk-state-change.patch"
# amd-pstate included in Xanmod
# multigenerational lru included in Xanmod
@@ -168,8 +172,10 @@ sha256sums=('027d7e8988bb69ac12ee92406c3be1fe13f990b1ca2249e226225cd1573308bb'
'834dd6603ec3fb0a72e3a1a97669a7198cd6921c4f355b155b3d587a8f0fcea4'
'278118011d7a2eeca9971ac97b31bf0c55ab55e99c662ab9ae4717b55819c9a2'
'bb915d4f4291cbc7893a9f61fb5e1d90d9a6b368306710ef732795365b8b0108'
+ '7b6825a43b4173750768a1a50bfd38dcbd326aec6d56cc886490d97e323b7ce9'
'241f01f06849fcec462d72355ca3ab6bd34931731dec89876d785912ac532398'
'dd01bd3f774c3a9af42b6d89f534f39c4a5f200db32cd6d4b72a29325645100e'
+ 'a9647897e59b04cb883dcf649b3108e9397d5a6c672bc545ea0c6bb7bb30d5a9'
'56f8f93a38ed7236c2504c79645a33123ee7bdf3c0cbb97dfd90600df06be7dd'
'eac568d7f2b369a8a2b685fae236388c3516938000d4d6b2116b5874c4f93430'
'e74649fb883f2c8c3703c730e45119fca7126dc0599d6bc814de6dcf5a07e7cb'
diff --git a/iwlwifi-fix-use-after-free.patch b/iwlwifi-fix-use-after-free.patch
new file mode 100644
index 000000000000..e81044c9c2f2
--- /dev/null
+++ b/iwlwifi-fix-use-after-free.patch
@@ -0,0 +1,48 @@
+From: Johannes Berg <johannes@sipsolutions.net>
+Subject: [PATCH] iwlwifi: fix use-after-free
+Date: Tue, 8 Feb 2022 11:47:30 +0100
+Content-Type: text/plain; charset=UTF-8
+Message-Id: <20220208114728.e6b514cf4c85.Iffb575ca2a623d7859b542c33b2a507d01554251@changeid>
+List-ID: <stable.vger.kernel.org>
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+If no firmware was present at all (or, presumably, all of the
+firmware files failed to parse), we end up unbinding by calling
+device_release_driver(), which calls remove(), which then in
+iwlwifi calls iwl_drv_stop(), freeing the 'drv' struct. However
+the new code I added will still erroneously access it after it
+was freed.
+
+Set 'failure=false' in this case to avoid the access, all data
+was already freed anyway.
+
+Cc: stable@vger.kernel.org
+Reported-by: Stefan Agner <stefan@agner.ch>
+Reported-by: Wolfgang Walter <linux@stwm.de>
+Reported-by: Jason Self <jason@bluehome.net>
+Reported-by: Dominik Behr <dominik@dominikbehr.com>
+Reported-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
+Fixes: ab07506b0454 ("iwlwifi: fix leaks/bad data after failed firmware load")
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+ drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+index 83e3b731ad29..6651e78b39ec 100644
+--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
++++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+@@ -1707,6 +1707,8 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
+ out_unbind:
+ complete(&drv->request_firmware_complete);
+ device_release_driver(drv->trans->dev);
++ /* drv has just been freed by the release */
++ failure = false;
+ free:
+ if (failure)
+ iwl_dealloc_ucode(drv);
+--
+2.34.1
+
+