* FAILED: patch "[PATCH] Bluetooth: hci_debugfs: Pin module for debugfs file operations" failed to apply to 5.15-stable tree
@ 2026-11-07 11:06 Sasha Levin
2026-11-10 15:50 ` [PATCH 5.15.y 1/2] Bluetooth: hci_core: Move all debugfs handling to hci_debugfs.c Sasha Levin
0 siblings, 1 reply; 3+ messages in thread
From: Sasha Levin @ 2026-11-07 11:06 UTC (permalink / raw)
To: dungvn2345, luiz.von.dentz; +Cc: stable
The patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x 2a3e2287877b1ee40ffb80b7d769b633866533f3
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '20261107060625-failed-5.15-2a3e2287877b@kernel.org' --subject-prefix 'PATCH 5.15.y' 'HEAD^..'
Thanks,
Sasha
------------------ original commit in Linus's tree ------------------
From 2a3e2287877b1ee40ffb80b7d769b633866533f3 Mon Sep 17 00:00:00 2001
From: Bui Viet Dung <dungvn2345@gmail.com>
Date: Thu, 8 Oct 2026 12:01:40 +0700
Subject: [PATCH] Bluetooth: hci_debugfs: Pin module for debugfs file
operations
An open debugfs file retains its file_operations pointer in the
debugfs proxy state. However, the file_operations defined in
hci_debugfs.c (use_debug_keys_fops, sc_only_mode_fops,
ssp_debug_mode_fops, force_bredr_smp_fops, force_static_address_fops,
force_no_mitm_fops, dut_mode_fops, vendor_diag_fops, and the
DEFINE_QUIRK_ATTRIBUTE macro) have no .owner set to THIS_MODULE.
As a result, full_proxy_open_regular() calls fops_get() which succeeds
without taking a reference to the bluetooth module. When a userspace
process opens any of these debugfs files, a subsequent controller removal
and module unload (rmmod bluetooth) can succeed while the file descriptor
remains open.
When the userspace process subsequently closes the descriptor,
full_proxy_release() accesses the already unmapped file_operations
structure, triggering a kernel oops in full_proxy_release():
BUG: unable to handle page fault for address: fffffbfff8056f03
#PF: supervisor read access in kernel mode
Oops: 0000 [#1] SMP KASAN NOPTI
RIP: 0010:full_proxy_release+0x8e/0x140
Call Trace:
<TASK>
__fput+0x39f/0xa60
fput_close_sync+0xff/0x200
__x64_sys_close+0x8c/0xf0
do_syscall_64+0x115/0x6a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
</TASK>
The issue was discovered via manual code audit of
net/bluetooth/hci_debugfs.c and verified on a Linux 7.3-rc6 test VM
with CONFIG_BT=m.
Set .owner = THIS_MODULE on all debugfs file_operations tables in
hci_debugfs.c so that debugfs keeps the module loaded until close has
finished.
Fixes: 0886aea6acd2 ("Bluetooth: Expose debug keys usage setting via debugfs")
Cc: stable@vger.kernel.org
Signed-off-by: Bui Viet Dung <dungvn2345@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
net/bluetooth/hci_debugfs.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c
index 2559fb6324d63..cd5ef398f2382 100644
--- a/net/bluetooth/hci_debugfs.c
+++ b/net/bluetooth/hci_debugfs.c
@@ -65,6 +65,7 @@ static ssize_t __name ## _write(struct file *file, \
} \
\
static const struct file_operations __name ## _fops = { \
+ .owner = THIS_MODULE, \
.open = simple_open, \
.read = __name ## _read, \
.write = __name ## _write, \
@@ -283,6 +284,7 @@ static ssize_t use_debug_keys_read(struct file *file, char __user *user_buf,
}
static const struct file_operations use_debug_keys_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = use_debug_keys_read,
.llseek = default_llseek,
@@ -301,6 +303,7 @@ static ssize_t sc_only_mode_read(struct file *file, char __user *user_buf,
}
static const struct file_operations sc_only_mode_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = sc_only_mode_read,
.llseek = default_llseek,
@@ -437,6 +440,7 @@ static ssize_t ssp_debug_mode_read(struct file *file, char __user *user_buf,
}
static const struct file_operations ssp_debug_mode_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = ssp_debug_mode_read,
.llseek = default_llseek,
@@ -529,6 +533,7 @@ static ssize_t force_bredr_smp_write(struct file *file,
}
static const struct file_operations force_bredr_smp_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = force_bredr_smp_read,
.write = force_bredr_smp_write,
@@ -778,6 +783,7 @@ static ssize_t force_static_address_write(struct file *file,
}
static const struct file_operations force_static_address_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = force_static_address_read,
.write = force_static_address_write,
@@ -1177,6 +1183,7 @@ static ssize_t force_no_mitm_write(struct file *file,
}
static const struct file_operations force_no_mitm_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = force_no_mitm_read,
.write = force_no_mitm_write,
@@ -1315,6 +1322,7 @@ static ssize_t dut_mode_write(struct file *file, const char __user *user_buf,
}
static const struct file_operations dut_mode_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = dut_mode_read,
.write = dut_mode_write,
@@ -1371,6 +1379,7 @@ static ssize_t vendor_diag_write(struct file *file, const char __user *user_buf,
}
static const struct file_operations vendor_diag_fops = {
+ .owner = THIS_MODULE,
.open = simple_open,
.read = vendor_diag_read,
.write = vendor_diag_write,
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH 5.15.y 1/2] Bluetooth: hci_core: Move all debugfs handling to hci_debugfs.c 2026-11-07 11:06 FAILED: patch "[PATCH] Bluetooth: hci_debugfs: Pin module for debugfs file operations" failed to apply to 5.15-stable tree Sasha Levin @ 2026-11-10 15:50 ` Sasha Levin 2026-11-10 15:50 ` [PATCH 5.15.y 2/2] Bluetooth: hci_debugfs: Pin module for debugfs file operations Sasha Levin 0 siblings, 1 reply; 3+ messages in thread From: Sasha Levin @ 2026-11-10 15:50 UTC (permalink / raw) To: stable; +Cc: Luiz Augusto von Dentz, Marcel Holtmann, Sasha Levin From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> [ Upstream commit 8331dc487fc55963e853b6858af716907717e181 ] This moves hci_debugfs_create_basic to hci_debugfs.c which is where all the others debugfs entries are handled. Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org> Stable-dep-of: 2a3e2287877b ("Bluetooth: hci_debugfs: Pin module for debugfs file operations") Signed-off-by: Sasha Levin <sashal@kernel.org> --- net/bluetooth/hci_core.c | 124 ------------------------------------ net/bluetooth/hci_debugfs.c | 123 +++++++++++++++++++++++++++++++++++ net/bluetooth/hci_debugfs.h | 5 ++ 3 files changed, 128 insertions(+), 124 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c31919623d1b4..170389a36bd9e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -61,130 +61,6 @@ DEFINE_MUTEX(hci_cb_list_lock); /* HCI ID Numbering */ static DEFINE_IDA(hci_index_ida); -/* ---- HCI debugfs entries ---- */ - -static ssize_t dut_mode_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct hci_dev *hdev = file->private_data; - char buf[3]; - - buf[0] = hci_dev_test_flag(hdev, HCI_DUT_MODE) ? 'Y' : 'N'; - buf[1] = '\n'; - buf[2] = '\0'; - return simple_read_from_buffer(user_buf, count, ppos, buf, 2); -} - -static ssize_t dut_mode_write(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct hci_dev *hdev = file->private_data; - struct sk_buff *skb; - bool enable; - int err; - - if (!test_bit(HCI_UP, &hdev->flags)) - return -ENETDOWN; - - err = kstrtobool_from_user(user_buf, count, &enable); - if (err) - return err; - - if (enable == hci_dev_test_flag(hdev, HCI_DUT_MODE)) - return -EALREADY; - - hci_req_sync_lock(hdev); - if (enable) - skb = __hci_cmd_sync(hdev, HCI_OP_ENABLE_DUT_MODE, 0, NULL, - HCI_CMD_TIMEOUT); - else - skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, - HCI_CMD_TIMEOUT); - hci_req_sync_unlock(hdev); - - if (IS_ERR(skb)) - return PTR_ERR(skb); - - kfree_skb(skb); - - hci_dev_change_flag(hdev, HCI_DUT_MODE); - - return count; -} - -static const struct file_operations dut_mode_fops = { - .open = simple_open, - .read = dut_mode_read, - .write = dut_mode_write, - .llseek = default_llseek, -}; - -static ssize_t vendor_diag_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct hci_dev *hdev = file->private_data; - char buf[3]; - - buf[0] = hci_dev_test_flag(hdev, HCI_VENDOR_DIAG) ? 'Y' : 'N'; - buf[1] = '\n'; - buf[2] = '\0'; - return simple_read_from_buffer(user_buf, count, ppos, buf, 2); -} - -static ssize_t vendor_diag_write(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct hci_dev *hdev = file->private_data; - bool enable; - int err; - - err = kstrtobool_from_user(user_buf, count, &enable); - if (err) - return err; - - /* When the diagnostic flags are not persistent and the transport - * is not active or in user channel operation, then there is no need - * for the vendor callback. Instead just store the desired value and - * the setting will be programmed when the controller gets powered on. - */ - if (test_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks) && - (!test_bit(HCI_RUNNING, &hdev->flags) || - hci_dev_test_flag(hdev, HCI_USER_CHANNEL))) - goto done; - - hci_req_sync_lock(hdev); - err = hdev->set_diag(hdev, enable); - hci_req_sync_unlock(hdev); - - if (err < 0) - return err; - -done: - if (enable) - hci_dev_set_flag(hdev, HCI_VENDOR_DIAG); - else - hci_dev_clear_flag(hdev, HCI_VENDOR_DIAG); - - return count; -} - -static const struct file_operations vendor_diag_fops = { - .open = simple_open, - .read = vendor_diag_read, - .write = vendor_diag_write, - .llseek = default_llseek, -}; - -static void hci_debugfs_create_basic(struct hci_dev *hdev) -{ - debugfs_create_file("dut_mode", 0644, hdev->debugfs, hdev, - &dut_mode_fops); - - if (hdev->set_diag) - debugfs_create_file("vendor_diag", 0644, hdev->debugfs, hdev, - &vendor_diag_fops); -} - static int hci_reset_req(struct hci_request *req, unsigned long opt) { BT_DBG("%s %ld", req->hdev->name, opt); diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c index b4ff99a4e5318..be805c87619c7 100644 --- a/net/bluetooth/hci_debugfs.c +++ b/net/bluetooth/hci_debugfs.c @@ -27,6 +27,7 @@ #include <net/bluetooth/hci_core.h> #include "smp.h" +#include "hci_request.h" #include "hci_debugfs.h" #define DEFINE_QUIRK_ATTRIBUTE(__name, __quirk) \ @@ -1270,3 +1271,125 @@ void hci_debugfs_create_conn(struct hci_conn *conn) snprintf(name, sizeof(name), "%u", conn->handle); conn->debugfs = debugfs_create_dir(name, hdev->debugfs); } + +static ssize_t dut_mode_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct hci_dev *hdev = file->private_data; + char buf[3]; + + buf[0] = hci_dev_test_flag(hdev, HCI_DUT_MODE) ? 'Y' : 'N'; + buf[1] = '\n'; + buf[2] = '\0'; + return simple_read_from_buffer(user_buf, count, ppos, buf, 2); +} + +static ssize_t dut_mode_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct hci_dev *hdev = file->private_data; + struct sk_buff *skb; + bool enable; + int err; + + if (!test_bit(HCI_UP, &hdev->flags)) + return -ENETDOWN; + + err = kstrtobool_from_user(user_buf, count, &enable); + if (err) + return err; + + if (enable == hci_dev_test_flag(hdev, HCI_DUT_MODE)) + return -EALREADY; + + hci_req_sync_lock(hdev); + if (enable) + skb = __hci_cmd_sync(hdev, HCI_OP_ENABLE_DUT_MODE, 0, NULL, + HCI_CMD_TIMEOUT); + else + skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, + HCI_CMD_TIMEOUT); + hci_req_sync_unlock(hdev); + + if (IS_ERR(skb)) + return PTR_ERR(skb); + + kfree_skb(skb); + + hci_dev_change_flag(hdev, HCI_DUT_MODE); + + return count; +} + +static const struct file_operations dut_mode_fops = { + .open = simple_open, + .read = dut_mode_read, + .write = dut_mode_write, + .llseek = default_llseek, +}; + +static ssize_t vendor_diag_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct hci_dev *hdev = file->private_data; + char buf[3]; + + buf[0] = hci_dev_test_flag(hdev, HCI_VENDOR_DIAG) ? 'Y' : 'N'; + buf[1] = '\n'; + buf[2] = '\0'; + return simple_read_from_buffer(user_buf, count, ppos, buf, 2); +} + +static ssize_t vendor_diag_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct hci_dev *hdev = file->private_data; + bool enable; + int err; + + err = kstrtobool_from_user(user_buf, count, &enable); + if (err) + return err; + + /* When the diagnostic flags are not persistent and the transport + * is not active or in user channel operation, then there is no need + * for the vendor callback. Instead just store the desired value and + * the setting will be programmed when the controller gets powered on. + */ + if (test_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks) && + (!test_bit(HCI_RUNNING, &hdev->flags) || + hci_dev_test_flag(hdev, HCI_USER_CHANNEL))) + goto done; + + hci_req_sync_lock(hdev); + err = hdev->set_diag(hdev, enable); + hci_req_sync_unlock(hdev); + + if (err < 0) + return err; + +done: + if (enable) + hci_dev_set_flag(hdev, HCI_VENDOR_DIAG); + else + hci_dev_clear_flag(hdev, HCI_VENDOR_DIAG); + + return count; +} + +static const struct file_operations vendor_diag_fops = { + .open = simple_open, + .read = vendor_diag_read, + .write = vendor_diag_write, + .llseek = default_llseek, +}; + +void hci_debugfs_create_basic(struct hci_dev *hdev) +{ + debugfs_create_file("dut_mode", 0644, hdev->debugfs, hdev, + &dut_mode_fops); + + if (hdev->set_diag) + debugfs_create_file("vendor_diag", 0644, hdev->debugfs, hdev, + &vendor_diag_fops); +} diff --git a/net/bluetooth/hci_debugfs.h b/net/bluetooth/hci_debugfs.h index 4444dc8cedc21..9a8a7c93bb12a 100644 --- a/net/bluetooth/hci_debugfs.h +++ b/net/bluetooth/hci_debugfs.h @@ -26,6 +26,7 @@ void hci_debugfs_create_common(struct hci_dev *hdev); void hci_debugfs_create_bredr(struct hci_dev *hdev); void hci_debugfs_create_le(struct hci_dev *hdev); void hci_debugfs_create_conn(struct hci_conn *conn); +void hci_debugfs_create_basic(struct hci_dev *hdev); #else @@ -45,4 +46,8 @@ static inline void hci_debugfs_create_conn(struct hci_conn *conn) { } +static inline void hci_debugfs_create_basic(struct hci_dev *hdev) +{ +} + #endif -- 2.53.0 ^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 5.15.y 2/2] Bluetooth: hci_debugfs: Pin module for debugfs file operations 2026-11-10 15:50 ` [PATCH 5.15.y 1/2] Bluetooth: hci_core: Move all debugfs handling to hci_debugfs.c Sasha Levin @ 2026-11-10 15:50 ` Sasha Levin 0 siblings, 0 replies; 3+ messages in thread From: Sasha Levin @ 2026-11-10 15:50 UTC (permalink / raw) To: stable; +Cc: Bui Viet Dung, Luiz Augusto von Dentz, Sasha Levin From: Bui Viet Dung <dungvn2345@gmail.com> [ Upstream commit 2a3e2287877b1ee40ffb80b7d769b633866533f3 ] An open debugfs file retains its file_operations pointer in the debugfs proxy state. However, the file_operations defined in hci_debugfs.c (use_debug_keys_fops, sc_only_mode_fops, ssp_debug_mode_fops, force_bredr_smp_fops, force_static_address_fops, force_no_mitm_fops, dut_mode_fops, vendor_diag_fops, and the DEFINE_QUIRK_ATTRIBUTE macro) have no .owner set to THIS_MODULE. As a result, full_proxy_open_regular() calls fops_get() which succeeds without taking a reference to the bluetooth module. When a userspace process opens any of these debugfs files, a subsequent controller removal and module unload (rmmod bluetooth) can succeed while the file descriptor remains open. When the userspace process subsequently closes the descriptor, full_proxy_release() accesses the already unmapped file_operations structure, triggering a kernel oops in full_proxy_release(): BUG: unable to handle page fault for address: fffffbfff8056f03 #PF: supervisor read access in kernel mode Oops: 0000 [#1] SMP KASAN NOPTI RIP: 0010:full_proxy_release+0x8e/0x140 Call Trace: <TASK> __fput+0x39f/0xa60 fput_close_sync+0xff/0x200 __x64_sys_close+0x8c/0xf0 do_syscall_64+0x115/0x6a0 entry_SYSCALL_64_after_hwframe+0x77/0x7f </TASK> The issue was discovered via manual code audit of net/bluetooth/hci_debugfs.c and verified on a Linux 7.3-rc6 test VM with CONFIG_BT=m. Set .owner = THIS_MODULE on all debugfs file_operations tables in hci_debugfs.c so that debugfs keeps the module loaded until close has finished. Fixes: 0886aea6acd2 ("Bluetooth: Expose debug keys usage setting via debugfs") Cc: stable@vger.kernel.org Signed-off-by: Bui Viet Dung <dungvn2345@gmail.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Signed-off-by: Sasha Levin <sashal@kernel.org> --- net/bluetooth/hci_debugfs.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c index be805c87619c7..770e026b1ebea 100644 --- a/net/bluetooth/hci_debugfs.c +++ b/net/bluetooth/hci_debugfs.c @@ -68,6 +68,7 @@ static ssize_t __name ## _write(struct file *file, \ } \ \ static const struct file_operations __name ## _fops = { \ + .owner = THIS_MODULE, \ .open = simple_open, \ .read = __name ## _read, \ .write = __name ## _write, \ @@ -286,6 +287,7 @@ static ssize_t use_debug_keys_read(struct file *file, char __user *user_buf, } static const struct file_operations use_debug_keys_fops = { + .owner = THIS_MODULE, .open = simple_open, .read = use_debug_keys_read, .llseek = default_llseek, @@ -304,6 +306,7 @@ static ssize_t sc_only_mode_read(struct file *file, char __user *user_buf, } static const struct file_operations sc_only_mode_fops = { + .owner = THIS_MODULE, .open = simple_open, .read = sc_only_mode_read, .llseek = default_llseek, @@ -440,6 +443,7 @@ static ssize_t ssp_debug_mode_read(struct file *file, char __user *user_buf, } static const struct file_operations ssp_debug_mode_fops = { + .owner = THIS_MODULE, .open = simple_open, .read = ssp_debug_mode_read, .llseek = default_llseek, @@ -532,6 +536,7 @@ static ssize_t force_bredr_smp_write(struct file *file, } static const struct file_operations force_bredr_smp_fops = { + .owner = THIS_MODULE, .open = simple_open, .read = force_bredr_smp_read, .write = force_bredr_smp_write, @@ -781,6 +786,7 @@ static ssize_t force_static_address_write(struct file *file, } static const struct file_operations force_static_address_fops = { + .owner = THIS_MODULE, .open = simple_open, .read = force_static_address_read, .write = force_static_address_write, @@ -1184,6 +1190,7 @@ static ssize_t force_no_mitm_write(struct file *file, } static const struct file_operations force_no_mitm_fops = { + .owner = THIS_MODULE, .open = simple_open, .read = force_no_mitm_read, .write = force_no_mitm_write, @@ -1322,6 +1329,7 @@ static ssize_t dut_mode_write(struct file *file, const char __user *user_buf, } static const struct file_operations dut_mode_fops = { + .owner = THIS_MODULE, .open = simple_open, .read = dut_mode_read, .write = dut_mode_write, @@ -1378,6 +1386,7 @@ static ssize_t vendor_diag_write(struct file *file, const char __user *user_buf, } static const struct file_operations vendor_diag_fops = { + .owner = THIS_MODULE, .open = simple_open, .read = vendor_diag_read, .write = vendor_diag_write, -- 2.53.0 ^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-11-10 15:50 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-11-07 11:06 FAILED: patch "[PATCH] Bluetooth: hci_debugfs: Pin module for debugfs file operations" failed to apply to 5.15-stable tree Sasha Levin 2026-11-10 15:50 ` [PATCH 5.15.y 1/2] Bluetooth: hci_core: Move all debugfs handling to hci_debugfs.c Sasha Levin 2026-11-10 15:50 ` [PATCH 5.15.y 2/2] Bluetooth: hci_debugfs: Pin module for debugfs file operations Sasha Levin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox