| From 7c5c7d06bd1f86d2c3ebe62be903a4ba42db4d2c Mon Sep 17 00:00:00 2001 |
| From: Liu Song <liu.song13@zte.com.cn> |
| Date: Thu, 10 Jul 2025 14:38:45 +0800 |
| Subject: PCI: endpoint: Avoid creating sub-groups asynchronously |
| |
| From: Liu Song <liu.song13@zte.com.cn> |
| |
| commit 7c5c7d06bd1f86d2c3ebe62be903a4ba42db4d2c upstream. |
| |
| The asynchronous creation of sub-groups by a delayed work could lead to a |
| NULL pointer dereference when the driver directory is removed before the |
| work completes. |
| |
| The crash can be easily reproduced with the following commands: |
| |
| # cd /sys/kernel/config/pci_ep/functions/pci_epf_test |
| # for i in {1..20}; do mkdir test && rmdir test; done |
| |
| BUG: kernel NULL pointer dereference, address: 0000000000000088 |
| ... |
| Call Trace: |
| configfs_register_group+0x3d/0x190 |
| pci_epf_cfs_work+0x41/0x110 |
| process_one_work+0x18f/0x350 |
| worker_thread+0x25a/0x3a0 |
| |
| Fix this issue by using configfs_add_default_group() API which does not |
| have the deadlock problem as configfs_register_group() and does not require |
| the delayed work handler. |
| |
| Fixes: e85a2d783762 ("PCI: endpoint: Add support in configfs to associate two EPCs with EPF") |
| Signed-off-by: Liu Song <liu.song13@zte.com.cn> |
| [mani: slightly reworded the description and added stable list] |
| Signed-off-by: Manivannan Sadhasivam <mani@kernel.org> |
| Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> |
| Cc: stable@kernel.org |
| Link: https://patch.msgid.link/20250710143845409gLM6JdlwPhlHG9iX3F6jK@zte.com.cn |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/pci/endpoint/pci-ep-cfs.c | 15 +++++---------- |
| 1 file changed, 5 insertions(+), 10 deletions(-) |
| |
| --- a/drivers/pci/endpoint/pci-ep-cfs.c |
| +++ b/drivers/pci/endpoint/pci-ep-cfs.c |
| @@ -23,7 +23,6 @@ struct pci_epf_group { |
| struct config_group group; |
| struct config_group primary_epc_group; |
| struct config_group secondary_epc_group; |
| - struct delayed_work cfs_work; |
| struct pci_epf *epf; |
| int index; |
| }; |
| @@ -103,7 +102,7 @@ static struct config_group |
| secondary_epc_group = &epf_group->secondary_epc_group; |
| config_group_init_type_name(secondary_epc_group, "secondary", |
| &pci_secondary_epc_type); |
| - configfs_register_group(&epf_group->group, secondary_epc_group); |
| + configfs_add_default_group(secondary_epc_group, &epf_group->group); |
| |
| return secondary_epc_group; |
| } |
| @@ -166,7 +165,7 @@ static struct config_group |
| |
| config_group_init_type_name(primary_epc_group, "primary", |
| &pci_primary_epc_type); |
| - configfs_register_group(&epf_group->group, primary_epc_group); |
| + configfs_add_default_group(primary_epc_group, &epf_group->group); |
| |
| return primary_epc_group; |
| } |
| @@ -570,15 +569,13 @@ static void pci_ep_cfs_add_type_group(st |
| return; |
| } |
| |
| - configfs_register_group(&epf_group->group, group); |
| + configfs_add_default_group(group, &epf_group->group); |
| } |
| |
| -static void pci_epf_cfs_work(struct work_struct *work) |
| +static void pci_epf_cfs_add_sub_groups(struct pci_epf_group *epf_group) |
| { |
| - struct pci_epf_group *epf_group; |
| struct config_group *group; |
| |
| - epf_group = container_of(work, struct pci_epf_group, cfs_work.work); |
| group = pci_ep_cfs_add_primary_group(epf_group); |
| if (IS_ERR(group)) { |
| pr_err("failed to create 'primary' EPC interface\n"); |
| @@ -637,9 +634,7 @@ static struct config_group *pci_epf_make |
| |
| kfree(epf_name); |
| |
| - INIT_DELAYED_WORK(&epf_group->cfs_work, pci_epf_cfs_work); |
| - queue_delayed_work(system_wq, &epf_group->cfs_work, |
| - msecs_to_jiffies(1)); |
| + pci_epf_cfs_add_sub_groups(epf_group); |
| |
| return &epf_group->group; |
| |