Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH v1 08/12] nfc: Unify style of of_device_id arrays
From: Ian Ray @ 2026-07-07 17:13 UTC (permalink / raw)
  To: Uwe Kleine-König (The Capable Hub)
  Cc: David Heidelberg, Krzysztof Kozlowski, Mark Greer, Carl Lee,
	Jakub Kicinski, Paolo Abeni, Pengpeng Hou, Kees Cook,
	Simon Horman, Tomasz Unger, oe-linux-nfc, linux-kernel,
	linux-wireless
In-Reply-To: <583375dcd834f5edf6241b09cdd75ad4f32af668.1783091699.git.u.kleine-koenig@baylibre.com>

On Fri, Jul 03, 2026 at 05:46:22PM +0200, Uwe Kleine-König (The Capable Hub) wrote:
> The most common style treewide is:
> 
>  - A single space in the list terminator and no trailing ,
>  - No comma after a named initializers iff the closing } is on the same
>    line
> 
> Adapt the of_device_id arrays accordingly.
> 
> Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>

Reviewed-by: Ian Ray <ian.ray@gehealthcare.com>

> ---
>  drivers/nfc/nfcmrvl/i2c.c  | 4 ++--
>  drivers/nfc/nfcmrvl/spi.c  | 4 ++--
>  drivers/nfc/nxp-nci/i2c.c  | 4 ++--
>  drivers/nfc/pn533/i2c.c    | 8 ++++----
>  drivers/nfc/pn533/uart.c   | 4 ++--
>  drivers/nfc/pn544/i2c.c    | 4 ++--
>  drivers/nfc/s3fwrn5/i2c.c  | 4 ++--
>  drivers/nfc/s3fwrn5/uart.c | 4 ++--
>  drivers/nfc/st-nci/i2c.c   | 8 ++++----
>  drivers/nfc/st-nci/spi.c   | 4 ++--
>  drivers/nfc/st21nfca/i2c.c | 6 +++---
>  drivers/nfc/st95hf/core.c  | 2 +-
>  drivers/nfc/trf7970a.c     | 5 ++---
>  13 files changed, 30 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/nfc/nfcmrvl/i2c.c b/drivers/nfc/nfcmrvl/i2c.c
> index 687d2979b881..068c5d278a35 100644
> --- a/drivers/nfc/nfcmrvl/i2c.c
> +++ b/drivers/nfc/nfcmrvl/i2c.c
> @@ -246,8 +246,8 @@ static void nfcmrvl_i2c_remove(struct i2c_client *client)
> 
> 
>  static const struct of_device_id of_nfcmrvl_i2c_match[] = {
> -       { .compatible = "marvell,nfc-i2c", },
> -       {},
> +       { .compatible = "marvell,nfc-i2c" },
> +       { }
>  };
>  MODULE_DEVICE_TABLE(of, of_nfcmrvl_i2c_match);
> 
> diff --git a/drivers/nfc/nfcmrvl/spi.c b/drivers/nfc/nfcmrvl/spi.c
> index 8dd71fed8493..34842ecc4a05 100644
> --- a/drivers/nfc/nfcmrvl/spi.c
> +++ b/drivers/nfc/nfcmrvl/spi.c
> @@ -182,8 +182,8 @@ static void nfcmrvl_spi_remove(struct spi_device *spi)
>  }
> 
>  static const struct of_device_id of_nfcmrvl_spi_match[] = {
> -       { .compatible = "marvell,nfc-spi", },
> -       {},
> +       { .compatible = "marvell,nfc-spi" },
> +       { }
>  };
>  MODULE_DEVICE_TABLE(of, of_nfcmrvl_spi_match);
> 
> diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c
> index 39b43f8f3bf0..d424452934ec 100644
> --- a/drivers/nfc/nxp-nci/i2c.c
> +++ b/drivers/nfc/nxp-nci/i2c.c
> @@ -355,8 +355,8 @@ static const struct i2c_device_id nxp_nci_i2c_id_table[] = {
>  MODULE_DEVICE_TABLE(i2c, nxp_nci_i2c_id_table);
> 
>  static const struct of_device_id of_nxp_nci_i2c_match[] = {
> -       { .compatible = "nxp,nxp-nci-i2c", },
> -       {}
> +       { .compatible = "nxp,nxp-nci-i2c" },
> +       { }
>  };
>  MODULE_DEVICE_TABLE(of, of_nxp_nci_i2c_match);
> 
> diff --git a/drivers/nfc/pn533/i2c.c b/drivers/nfc/pn533/i2c.c
> index 2128083f0297..66d201c14a40 100644
> --- a/drivers/nfc/pn533/i2c.c
> +++ b/drivers/nfc/pn533/i2c.c
> @@ -237,14 +237,14 @@ static void pn533_i2c_remove(struct i2c_client *client)
>  }
> 
>  static const struct of_device_id of_pn533_i2c_match[] = {
> -       { .compatible = "nxp,pn532", },
> +       { .compatible = "nxp,pn532" },
>         /*
>          * NOTE: The use of the compatibles with the trailing "...-i2c" is
>          * deprecated and will be removed.
>          */
> -       { .compatible = "nxp,pn533-i2c", },
> -       { .compatible = "nxp,pn532-i2c", },
> -       {},
> +       { .compatible = "nxp,pn533-i2c" },
> +       { .compatible = "nxp,pn532-i2c" },
> +       { }
>  };
>  MODULE_DEVICE_TABLE(of, of_pn533_i2c_match);
> 
> diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c
> index e0d67cd2ac9b..83c1ccda0af6 100644
> --- a/drivers/nfc/pn533/uart.c
> +++ b/drivers/nfc/pn533/uart.c
> @@ -238,8 +238,8 @@ static const struct serdev_device_ops pn532_serdev_ops = {
>  };
> 
>  static const struct of_device_id pn532_uart_of_match[] = {
> -       { .compatible = "nxp,pn532", },
> -       {},
> +       { .compatible = "nxp,pn532" },
> +       { }
>  };
>  MODULE_DEVICE_TABLE(of, pn532_uart_of_match);
> 
> diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c
> index 50907a1974cd..7fde3aefae70 100644
> --- a/drivers/nfc/pn544/i2c.c
> +++ b/drivers/nfc/pn544/i2c.c
> @@ -938,8 +938,8 @@ static void pn544_hci_i2c_remove(struct i2c_client *client)
>  }
> 
>  static const struct of_device_id of_pn544_i2c_match[] = {
> -       { .compatible = "nxp,pn544-i2c", },
> -       {},
> +       { .compatible = "nxp,pn544-i2c" },
> +       { }
>  };
>  MODULE_DEVICE_TABLE(of, of_pn544_i2c_match);
> 
> diff --git a/drivers/nfc/s3fwrn5/i2c.c b/drivers/nfc/s3fwrn5/i2c.c
> index 499301a6fa3f..4ba762611711 100644
> --- a/drivers/nfc/s3fwrn5/i2c.c
> +++ b/drivers/nfc/s3fwrn5/i2c.c
> @@ -211,8 +211,8 @@ static const struct i2c_device_id s3fwrn5_i2c_id_table[] = {
>  MODULE_DEVICE_TABLE(i2c, s3fwrn5_i2c_id_table);
> 
>  static const struct of_device_id of_s3fwrn5_i2c_match[] = {
> -       { .compatible = "samsung,s3fwrn5-i2c", },
> -       {}
> +       { .compatible = "samsung,s3fwrn5-i2c" },
> +       { }
>  };
>  MODULE_DEVICE_TABLE(of, of_s3fwrn5_i2c_match);
> 
> diff --git a/drivers/nfc/s3fwrn5/uart.c b/drivers/nfc/s3fwrn5/uart.c
> index e17c599a2da5..8f142a255101 100644
> --- a/drivers/nfc/s3fwrn5/uart.c
> +++ b/drivers/nfc/s3fwrn5/uart.c
> @@ -85,8 +85,8 @@ static const struct serdev_device_ops s3fwrn82_serdev_ops = {
>  };
> 
>  static const struct of_device_id s3fwrn82_uart_of_match[] = {
> -       { .compatible = "samsung,s3fwrn82", },
> -       {},
> +       { .compatible = "samsung,s3fwrn82" },
> +       { }
>  };
>  MODULE_DEVICE_TABLE(of, s3fwrn82_uart_of_match);
> 
> diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c
> index ceb7d7450e47..152c20b6bb01 100644
> --- a/drivers/nfc/st-nci/i2c.c
> +++ b/drivers/nfc/st-nci/i2c.c
> @@ -270,10 +270,10 @@ static const struct acpi_device_id st_nci_i2c_acpi_match[] = {
>  MODULE_DEVICE_TABLE(acpi, st_nci_i2c_acpi_match);
> 
>  static const struct of_device_id of_st_nci_i2c_match[] = {
> -       { .compatible = "st,st21nfcb-i2c", },
> -       { .compatible = "st,st21nfcb_i2c", },
> -       { .compatible = "st,st21nfcc-i2c", },
> -       {}
> +       { .compatible = "st,st21nfcb-i2c" },
> +       { .compatible = "st,st21nfcb_i2c" },
> +       { .compatible = "st,st21nfcc-i2c" },
> +       { }
>  };
>  MODULE_DEVICE_TABLE(of, of_st_nci_i2c_match);
> 
> diff --git a/drivers/nfc/st-nci/spi.c b/drivers/nfc/st-nci/spi.c
> index 8632cc0cb305..5e0b94050f90 100644
> --- a/drivers/nfc/st-nci/spi.c
> +++ b/drivers/nfc/st-nci/spi.c
> @@ -284,8 +284,8 @@ static const struct acpi_device_id st_nci_spi_acpi_match[] = {
>  MODULE_DEVICE_TABLE(acpi, st_nci_spi_acpi_match);
> 
>  static const struct of_device_id of_st_nci_spi_match[] = {
> -       { .compatible = "st,st21nfcb-spi", },
> -       {}
> +       { .compatible = "st,st21nfcb-spi" },
> +       { }
>  };
>  MODULE_DEVICE_TABLE(of, of_st_nci_spi_match);
> 
> diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c
> index 4e70f591af55..a4c93ff7c5b0 100644
> --- a/drivers/nfc/st21nfca/i2c.c
> +++ b/drivers/nfc/st21nfca/i2c.c
> @@ -584,9 +584,9 @@ static const struct acpi_device_id st21nfca_hci_i2c_acpi_match[] = {
>  MODULE_DEVICE_TABLE(acpi, st21nfca_hci_i2c_acpi_match);
> 
>  static const struct of_device_id of_st21nfca_i2c_match[] = {
> -       { .compatible = "st,st21nfca-i2c", },
> -       { .compatible = "st,st21nfca_i2c", },
> -       {}
> +       { .compatible = "st,st21nfca-i2c" },
> +       { .compatible = "st,st21nfca_i2c" },
> +       { }
>  };
>  MODULE_DEVICE_TABLE(of, of_st21nfca_i2c_match);
> 
> diff --git a/drivers/nfc/st95hf/core.c b/drivers/nfc/st95hf/core.c
> index 1ecd47c6518e..265ab10bbb61 100644
> --- a/drivers/nfc/st95hf/core.c
> +++ b/drivers/nfc/st95hf/core.c
> @@ -1056,7 +1056,7 @@ MODULE_DEVICE_TABLE(spi, st95hf_id);
> 
>  static const struct of_device_id st95hf_spi_of_match[] = {
>         { .compatible = "st,st95hf" },
> -       {},
> +       { }
>  };
>  MODULE_DEVICE_TABLE(of, st95hf_spi_of_match);
> 
> diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c
> index bc01b46f461c..3802081fb8ee 100644
> --- a/drivers/nfc/trf7970a.c
> +++ b/drivers/nfc/trf7970a.c
> @@ -2304,10 +2304,9 @@ static const struct dev_pm_ops trf7970a_pm_ops = {
>  };
> 
>  static const struct of_device_id trf7970a_of_match[] = {
> -       {.compatible = "ti,trf7970a",},
> -       {},
> +       { .compatible = "ti,trf7970a" },
> +       { }
>  };
> -
>  MODULE_DEVICE_TABLE(of, trf7970a_of_match);
> 
>  static const struct spi_device_id trf7970a_id_table[] = {
> --
> 2.55.0.11.g153666a7d9bb
> 

^ permalink raw reply

* Re: [PATCH] wifi: cfg80211: reinit wiphy work entries on runaway drain
From: Ben Greear @ 2026-07-07 16:03 UTC (permalink / raw)
  To: Cen Zhang; +Cc: Johannes Berg, linux-wireless, baijiaju1990
In-Reply-To: <CAFRLqsXHZ75ktX0gb3HbJHyPLHa_iFr=qA8Z-G0Lz1ZEfLQKjQ@mail.gmail.com>

On 7/7/26 08:47, Cen Zhang wrote:
> Hi Ben,
> 
> Thanks for your review and comments.
> 
>> Even this likely leaves the system in a bad state since requested work
>> items would be skipped.  Probably should also increase runaway_limit quite
>> a bit as well (that has worked OK for me), maybe remove it entirely.
> 
> Fair. Hitting the guard still means pending work gets skipped; this patch only
> avoids leaving those work entries with stale list links after the
> existing drop path.
> 
> I was hesitant to remove the guard in the same change, because the
> flush-all paths run under the wiphy mutex, and a work item that keeps
> requeueing itself could otherwise keep flush, suspend, or unregister
> stuck there. Raising the limit sounds less risky, but I would want a
> concrete reason for the new value rather than picking one arbitrarily..

Yeah, you have a good point.  I'm not sure of a proper solution.  I set my limit to 200
and was no longer able to reproduce warning splats.

Your patch may certainly be an improvement.

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com



^ permalink raw reply

* Re: [PATCH] wifi: cfg80211: reinit wiphy work entries on runaway drain
From: Cen Zhang @ 2026-07-07 15:47 UTC (permalink / raw)
  To: Ben Greear; +Cc: Johannes Berg, linux-wireless, baijiaju1990
In-Reply-To: <d39f212a-5161-4d00-bc38-bcdc5fee2658@candelatech.com>

Hi Ben,

Thanks for your review and comments.

> Even this likely leaves the system in a bad state since requested work
> items would be skipped.  Probably should also increase runaway_limit quite
> a bit as well (that has worked OK for me), maybe remove it entirely.

Fair. Hitting the guard still means pending work gets skipped; this patch only
avoids leaving those work entries with stale list links after the
existing drop path.

I was hesitant to remove the guard in the same change, because the
flush-all paths run under the wiphy mutex, and a work item that keeps
requeueing itself could otherwise keep flush, suspend, or unregister
stuck there. Raising the limit sounds less risky, but I would want a
concrete reason for the new value rather than picking one arbitrarily..

Best Regards,
Cen Zhang

^ permalink raw reply

* [Bug 221733] iwlegacy: iwl4965: kernel oops
From: Martin-Éric Racine @ 2026-07-07 15:17 UTC (permalink / raw)
  To: linux-wireless, Stanislaw Gruszka, Stanislaw Gruszka

Greetings,

As instructed via the kernel.org Bugzilla, I'm hereby contacting the
mailing list since Intel pointed out that they no longer maintain the
iwl4965 driver themselves and instead inquire on the mailing list.

Martin-Éric

^ permalink raw reply

* Re: [PATCH] wifi: cfg80211: reinit wiphy work entries on runaway drain
From: Ben Greear @ 2026-07-07 14:38 UTC (permalink / raw)
  To: Cen Zhang, Johannes Berg; +Cc: linux-wireless, baijiaju1990
In-Reply-To: <20260707134925.106972-1-zzzccc427@gmail.com>

On 7/7/26 06:49, Cen Zhang wrote:
> cfg80211_process_wiphy_works() has a runaway guard for the process-all
> case. When the guard fires, it drops the remaining queued work by
> reinitializing rdev->wiphy_work_list.

Even this likely leaves the system in a bad state since requested work
items would be skipped.  Probably should also increase runaway_limit quite
a bit as well (that has worked OK for me), maybe remove it entirely.

Thanks,
Ben

> 
> That only resets the list head. The queued struct wiphy_work entries are
> embedded in their owners, and their entry fields still point at the old
> list neighbors. Later queue or cancel checks can then see a work item as
> listed even though the rdev list has been cleared.
> 
> Drain the remaining list with list_del_init() under wiphy_work_lock
> instead of reinitializing only the head. This keeps the existing WARN and
> drop behavior while leaving each work item in the same state as normal
> wiphy work removal.
> 
> Fixes: a3ee4dc84c4e ("wifi: cfg80211: add a work abstraction with special semantics")
> Assisted-by: Codex:gpt-5.5
> Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
> ---
>   net/wireless/core.c | 10 ++++++++--
>   1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/net/wireless/core.c b/net/wireless/core.c
> index 3dcf63b04c41..a7e011ed455d 100644
> --- a/net/wireless/core.c
> +++ b/net/wireless/core.c
> @@ -1278,8 +1278,14 @@ void cfg80211_process_wiphy_works(struct cfg80211_registered_device *rdev,
>   		if (wk == end)
>   			break;
>   
> -		if (WARN_ON(--runaway_limit == 0))
> -			INIT_LIST_HEAD(&rdev->wiphy_work_list);
> +		if (WARN_ON(--runaway_limit == 0)) {
> +			while (!list_empty(&rdev->wiphy_work_list)) {
> +				wk = list_first_entry(&rdev->wiphy_work_list,
> +						      struct wiphy_work,
> +						      entry);
> +				list_del_init(&wk->entry);
> +			}
> +		}
>   	}
>   	spin_unlock_irqrestore(&rdev->wiphy_work_lock, flags);
>   }

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com


^ permalink raw reply

* Re: [PATCH 0/4] drivers/net: replace __get_free_pages() with kmalloc()
From: Simon Horman @ 2026-07-07 14:46 UTC (permalink / raw)
  To: Mike Rapoport (Microsoft)
  Cc: Johannes Berg, Brian Norris, Francesco Dolcini, Jakub Kicinski,
	b43-dev, libertas-dev, linux-kernel, linux-mm, linux-wireless,
	netdev
In-Reply-To: <20260701-b4-drivers-wireless-v1-0-60264cdf2efe@kernel.org>

On Wed, Jul 01, 2026 at 04:59:09PM +0300, Mike Rapoport (Microsoft) wrote:
> This is a (small) part of larger work of replacing page allocator calls
> with kmalloc.
> 
> My initial intention a few month ago was to remove ugly casts [1], but then
> willy pointed out that Linus objected to something like this [2] and it
> looks like more than a decade old technical debt.
> 
> Largely, anything that doesn't need struct page (or a memdesc in the
> future) should just use kmalloc() or kvmalloc() to allocate memory.
> kmalloc() guarantees alignment, physical contiguity and working
> virt_to_phys() and beside nicer API that returns void * on alloc and
> doesn't require to know the allocation size on free, kmalloc() provides
> better debugging capabilities than page allocator.
> 
> Another thing is that touching these allocation sites gives the reviewers
> opportunity to see if a PAGE_SIZE buffer is actually needed or maybe
> another size is appropriate.
> 
> For larger allocations that don't need physically contiguous memory
> kvmalloc() can be a better option that __get_free_pages() because under
> memory pressure it's is easier to allocate several order-0 pages than a
> physically contiguous chunk with the same number of pages.
> 
> And last, but not least, removing needless calls to page allocator should
> help with memdesc (aka project folio) conversion. There will be way less
> places to audit to see if the user was actually using struct page.
> 
> Also in git:
> https://git.kernel.org/pub/scm/linux/kernel/git/rppt/linux.git gfp-to-kmalloc/drivers-net-wireless
> 
> [1] https://lore.kernel.org/all/20251018093002.3660549-1-rppt@kernel.org/
> [2] https://lore.kernel.org/all/CA+55aFwp4iy4rtX2gE2WjBGFL=NxMVnoFeHqYa2j1dYOMMGqxg@mail.gmail.com/
> 
> ---
> Changes in v2:
> - split out wireless drivers from a larger set 
> - use kzalloc() instead of kmalloc() + memset in b43legacy
> 
> v1: https://patch.msgid.link/20260630-b4-drivers-net-v1-0-672162a91f37@kernel.org

For the series:

Reviewed-by: Simon Horman <horms@kernel.org>


^ permalink raw reply

* [PATCH] wifi: cfg80211: reinit wiphy work entries on runaway drain
From: Cen Zhang @ 2026-07-07 13:49 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, baijiaju1990, zzzccc427

cfg80211_process_wiphy_works() has a runaway guard for the process-all
case. When the guard fires, it drops the remaining queued work by
reinitializing rdev->wiphy_work_list.

That only resets the list head. The queued struct wiphy_work entries are
embedded in their owners, and their entry fields still point at the old
list neighbors. Later queue or cancel checks can then see a work item as
listed even though the rdev list has been cleared.

Drain the remaining list with list_del_init() under wiphy_work_lock
instead of reinitializing only the head. This keeps the existing WARN and
drop behavior while leaving each work item in the same state as normal
wiphy work removal.

Fixes: a3ee4dc84c4e ("wifi: cfg80211: add a work abstraction with special semantics")
Assisted-by: Codex:gpt-5.5
Signed-off-by: Cen Zhang <zzzccc427@gmail.com>
---
 net/wireless/core.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/net/wireless/core.c b/net/wireless/core.c
index 3dcf63b04c41..a7e011ed455d 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1278,8 +1278,14 @@ void cfg80211_process_wiphy_works(struct cfg80211_registered_device *rdev,
 		if (wk == end)
 			break;
 
-		if (WARN_ON(--runaway_limit == 0))
-			INIT_LIST_HEAD(&rdev->wiphy_work_list);
+		if (WARN_ON(--runaway_limit == 0)) {
+			while (!list_empty(&rdev->wiphy_work_list)) {
+				wk = list_first_entry(&rdev->wiphy_work_list,
+						      struct wiphy_work,
+						      entry);
+				list_del_init(&wk->entry);
+			}
+		}
 	}
 	spin_unlock_irqrestore(&rdev->wiphy_work_lock, flags);
 }
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH] wifi: mac80211: only accept IBSS channel switch from our own BSSID
From: Yingjie Cao @ 2026-07-07 13:43 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Nathan Howard, linux-wireless, linux-kernel
In-Reply-To: <b7dab24792025a5a95b719ef7d508fb109859ec1.camel@sipsolutions.net>

Hi Johannes,

Thank you for the feedback, and sorry for the delayed follow-up.

I did use AI assistance while preparing this patch, and I should have
been more careful and responsible before submitting it. In particular, I
agree that the commit message overstated the security impact, and that
adding Cc: stable was not appropriate for this submission.

I am currently learning the kernel patch submission process and the IBSS
code paths involved here. Going forward, I will make sure any future
submissions are reviewed and verified by me personally before sending,
and I will include the proper Assisted-by tag when AI tools materially
contribute to the work.

For this patch, I will drop it until I have a fuller understanding of
the code involved.

Thanks,
Yingjie

^ permalink raw reply

* Re: [PATCH v2 7/7] usb: fix UAF when probe runs concurrent to dyn ID removal
From: Danilo Krummrich @ 2026-07-07 13:41 UTC (permalink / raw)
  To: Gary Guo
  Cc: Greg Kroah-Hartman, Rafael J. Wysocki,
	Toke Høiland-Jørgensen, Johan Hovold,
	Mauro Carvalho Chehab, Petko Manolov, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Chas Williams, Alan Stern, linux-usb, driver-core, linux-wireless,
	linux-media, linux-atm-general, netdev, usb-storage, linux-kernel
In-Reply-To: <20260707-usb_dyn_id_uaf-v2-7-632dcf3adfba@garyguo.net>

On 7/7/26 2:26 PM, Gary Guo wrote:
> Dynamic IDs are only guaranteed to be valid when usb_dynids_lock is held,
> as remove_id_store can free the node. Thus, make a copy in
> usb_probe_interface. Clarify the documentation that the id parameter is
> only valid during the probe.
> 
> USB serial has the same pattern, but it does not need fixing as the IDs
> cannot be removed via sysfs.
> 
> Fixes: 0c7a2b72746a ("USB: add remove_id sysfs attr for usb drivers")
> Signed-off-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Danilo Krummrich <dakr@kernel.org>

^ permalink raw reply

* [PATCH v2 3/7] usb: serial: spcp8x5: don't store usb_device_id
From: Gary Guo @ 2026-07-07 12:26 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
	Toke Høiland-Jørgensen, Johan Hovold,
	Mauro Carvalho Chehab, Petko Manolov, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Chas Williams, Alan Stern
  Cc: linux-usb, driver-core, linux-wireless, linux-media,
	linux-atm-general, netdev, usb-storage, linux-kernel, Gary Guo,
	Manuel Ebner
In-Reply-To: <20260707-usb_dyn_id_uaf-v2-0-632dcf3adfba@garyguo.net>

USB probe functions should not keep usb_device_id for longer than probe due
to presence of dynamic ID removal. USB serial does not support ID removal,
however in this case only driver_data is ever needed, there is no reason
keeping the usb_device_id in the first place, so convert it as well.

Reviewed-by: Manuel Ebner <manuelebner@mailbox.org>
Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Gary Guo <gary@garyguo.net>
---
 drivers/usb/serial/spcp8x5.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index c11d64bf08fb..0e7715a02df4 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -133,14 +133,14 @@ struct spcp8x5_private {
 static int spcp8x5_probe(struct usb_serial *serial,
 						const struct usb_device_id *id)
 {
-	usb_set_serial_data(serial, (void *)id);
+	usb_set_serial_data(serial, (void *)id->driver_info);
 
 	return 0;
 }
 
 static int spcp8x5_port_probe(struct usb_serial_port *port)
 {
-	const struct usb_device_id *id = usb_get_serial_data(port->serial);
+	unsigned int quirks = (unsigned int)(unsigned long)usb_get_serial_data(port->serial);
 	struct spcp8x5_private *priv;
 
 	priv = kzalloc_obj(*priv);
@@ -148,7 +148,7 @@ static int spcp8x5_port_probe(struct usb_serial_port *port)
 		return -ENOMEM;
 
 	spin_lock_init(&priv->lock);
-	priv->quirks = id->driver_info;
+	priv->quirks = quirks;
 
 	usb_set_serial_port_data(port, priv);
 

-- 
2.54.0


^ permalink raw reply related

* [PATCH v2 7/7] usb: fix UAF when probe runs concurrent to dyn ID removal
From: Gary Guo @ 2026-07-07 12:26 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
	Toke Høiland-Jørgensen, Johan Hovold,
	Mauro Carvalho Chehab, Petko Manolov, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Chas Williams, Alan Stern
  Cc: linux-usb, driver-core, linux-wireless, linux-media,
	linux-atm-general, netdev, usb-storage, linux-kernel, Gary Guo
In-Reply-To: <20260707-usb_dyn_id_uaf-v2-0-632dcf3adfba@garyguo.net>

Dynamic IDs are only guaranteed to be valid when usb_dynids_lock is held,
as remove_id_store can free the node. Thus, make a copy in
usb_probe_interface. Clarify the documentation that the id parameter is
only valid during the probe.

USB serial has the same pattern, but it does not need fixing as the IDs
cannot be removed via sysfs.

Fixes: 0c7a2b72746a ("USB: add remove_id sysfs attr for usb drivers")
Signed-off-by: Gary Guo <gary@garyguo.net>
---
 drivers/usb/core/driver.c | 12 ++++++++----
 include/linux/usb.h       |  3 ++-
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index f63004417058..7f33fe5ba03b 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -228,14 +228,16 @@ static void usb_free_dynids(struct usb_driver *usb_drv)
 }
 
 static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *intf,
-							const struct usb_driver *drv)
+							const struct usb_driver *drv,
+							struct usb_device_id *id_copy)
 {
 	struct usb_dynid *dynid;
 
 	guard(mutex)(&usb_dynids_lock);
 	list_for_each_entry(dynid, &drv->dynids.list, node) {
 		if (usb_match_one_id(intf, &dynid->id)) {
-			return &dynid->id;
+			*id_copy = dynid->id;
+			return id_copy;
 		}
 	}
 	return NULL;
@@ -321,6 +323,7 @@ static int usb_probe_interface(struct device *dev)
 	struct usb_interface *intf = to_usb_interface(dev);
 	struct usb_device *udev = interface_to_usbdev(intf);
 	const struct usb_device_id *id;
+	struct usb_device_id id_copy;
 	int error = -ENODEV;
 	int lpm_disable_error = -ENODEV;
 
@@ -340,7 +343,7 @@ static int usb_probe_interface(struct device *dev)
 		return error;
 	}
 
-	id = usb_match_dynamic_id(intf, driver);
+	id = usb_match_dynamic_id(intf, driver, &id_copy);
 	if (!id)
 		id = usb_match_id(intf, driver->id_table);
 	if (!id)
@@ -892,6 +895,7 @@ static int usb_device_match(struct device *dev, const struct device_driver *drv)
 		struct usb_interface *intf;
 		const struct usb_driver *usb_drv;
 		const struct usb_device_id *id;
+		struct usb_device_id id_copy;
 
 		/* device drivers never match interfaces */
 		if (is_usb_device_driver(drv))
@@ -904,7 +908,7 @@ static int usb_device_match(struct device *dev, const struct device_driver *drv)
 		if (id)
 			return 1;
 
-		id = usb_match_dynamic_id(intf, usb_drv);
+		id = usb_match_dynamic_id(intf, usb_drv, &id_copy);
 		if (id)
 			return 1;
 	}
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 1da4ad1610bc..49ab8dbb885f 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1185,7 +1185,8 @@ extern ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf);
  *	interface.  It may also use usb_set_interface() to specify the
  *	appropriate altsetting.  If unwilling to manage the interface,
  *	return -ENODEV, if genuine IO errors occurred, an appropriate
- *	negative errno value.
+ *	negative errno value.  The usb_device_id parameter is only valid during
+ *	probe.
  * @disconnect: Called when the interface is no longer accessible, usually
  *	because its device has been (or is being) disconnected or the
  *	driver module is being unloaded.

-- 
2.54.0


^ permalink raw reply related

* [PATCH v2 2/7] usb: usbtmc: don't store usb_device_id
From: Gary Guo @ 2026-07-07 12:26 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
	Toke Høiland-Jørgensen, Johan Hovold,
	Mauro Carvalho Chehab, Petko Manolov, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Chas Williams, Alan Stern
  Cc: linux-usb, driver-core, linux-wireless, linux-media,
	linux-atm-general, netdev, usb-storage, linux-kernel, Gary Guo,
	Manuel Ebner
In-Reply-To: <20260707-usb_dyn_id_uaf-v2-0-632dcf3adfba@garyguo.net>

usb_device_id is not guaranteed to live longer than probe due to presence
of dynamic ID. This stored ID is unused so remove it.

Reviewed-by: Manuel Ebner <manuelebner@mailbox.org>
Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Gary Guo <gary@garyguo.net>
---
 drivers/usb/class/usbtmc.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index af9ae55dae14..51cd9320a736 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -71,7 +71,6 @@ struct usbtmc_dev_capabilities {
  * allocated for each USBTMC device in the driver's probe function.
  */
 struct usbtmc_device_data {
-	const struct usb_device_id *id;
 	struct usb_device *usb_dev;
 	struct usb_interface *intf;
 	struct list_head file_list;
@@ -2394,7 +2393,6 @@ static int usbtmc_probe(struct usb_interface *intf,
 		return -ENOMEM;
 
 	data->intf = intf;
-	data->id = id;
 	data->usb_dev = usb_get_dev(interface_to_usbdev(intf));
 	usb_set_intfdata(intf, data);
 	kref_init(&data->kref);

-- 
2.54.0


^ permalink raw reply related

* [PATCH v2 6/7] usb: xusbatm: don't rely on id table pointer arithmetic
From: Gary Guo @ 2026-07-07 12:26 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
	Toke Høiland-Jørgensen, Johan Hovold,
	Mauro Carvalho Chehab, Petko Manolov, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Chas Williams, Alan Stern
  Cc: linux-usb, driver-core, linux-wireless, linux-media,
	linux-atm-general, netdev, usb-storage, linux-kernel, Gary Guo
In-Reply-To: <20260707-usb_dyn_id_uaf-v2-0-632dcf3adfba@garyguo.net>

The current code is broken when dynamic ID is involved; in such cases
usb_device_id parameter of probe lives on the heap and the pointer
arithmetic will get an index that is wildly out of bound. xusbatm
initialize the USB device IDs dynamically so it can just use driver_info
too.

Even with conversion, xusbatm still cannot support dynamic IDs, so also set
no_dynamic_id.

Signed-off-by: Gary Guo <gary@garyguo.net>
---
 drivers/usb/atm/xusbatm.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c
index 0befbf63d1cc..5c1e1f521555 100644
--- a/drivers/usb/atm/xusbatm.c
+++ b/drivers/usb/atm/xusbatm.c
@@ -79,7 +79,7 @@ static int xusbatm_bind(struct usbatm_data *usbatm,
 			struct usb_interface *intf, const struct usb_device_id *id)
 {
 	struct usb_device *usb_dev = interface_to_usbdev(intf);
-	int drv_ix = id - xusbatm_usb_ids;
+	int drv_ix = id->driver_info;
 	int rx_alt = rx_altsetting[drv_ix];
 	int tx_alt = tx_altsetting[drv_ix];
 	struct usb_interface *rx_intf = xusbatm_find_intf(usb_dev, rx_alt, rx_endpoint[drv_ix]);
@@ -168,7 +168,8 @@ static struct usb_driver xusbatm_usb_driver = {
 	.name		= xusbatm_driver_name,
 	.probe		= xusbatm_usb_probe,
 	.disconnect	= usbatm_usb_disconnect,
-	.id_table	= xusbatm_usb_ids
+	.id_table	= xusbatm_usb_ids,
+	.no_dynamic_id	= 1,
 };
 
 static int __init xusbatm_init(void)
@@ -190,6 +191,7 @@ static int __init xusbatm_init(void)
 		xusbatm_usb_ids[i].match_flags	= USB_DEVICE_ID_MATCH_DEVICE;
 		xusbatm_usb_ids[i].idVendor	= vendor[i];
 		xusbatm_usb_ids[i].idProduct	= product[i];
+		xusbatm_usb_ids[i].driver_info	= i;
 
 		xusbatm_drivers[i].driver_name	= xusbatm_driver_name;
 		xusbatm_drivers[i].bind		= xusbatm_bind;

-- 
2.54.0


^ permalink raw reply related

* [PATCH v2 0/7] usb: fix UAF related to dynamic ID
From: Gary Guo @ 2026-07-07 12:26 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
	Toke Høiland-Jørgensen, Johan Hovold,
	Mauro Carvalho Chehab, Petko Manolov, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Chas Williams, Alan Stern
  Cc: linux-usb, driver-core, linux-wireless, linux-media,
	linux-atm-general, netdev, usb-storage, linux-kernel, Gary Guo,
	Manuel Ebner

This is the USB version of the dynamic ID UAF fix similar to that of PCI
[1]. usb_match_dynamic_id returns a pointer to field of usb_dynid, which
can be freed when dynamic ID is removed via sysfs. It can be triggered with
the following sequence:

    echo <vid> <pid> > /sys/bus/usb/drivers/<name>/new_id
    <probe start>
    echo <vid> <pid> > /sys/bus/usb/drivers/<name>/remove_id
    <probe use ID>

Fix it by making a stack copy of the ID. This does mean that the lifetime
of ID is scoped to probe (which is already the case but never spelled out
explicitly). Drivers use these device IDs creatively, so this series also
fix these drivers.

The following coccinelle script is used to find all cases that are deemed
suspicious. Only useful case for IDs should be access its fields, or
forwarding (without type cast) to functions that do so.

@usage@
identifier fn, id;
position p;
@@
  fn(..., struct usb_device_id *id, ...)
  {
    ...
    id@p
    ...
  }

// Due to cocci isomorphism this needs to be explicit
@bad@
identifier fn, id;
type T;
position usage.p;
@@
  fn(..., struct usb_device_id *id, ...)
  {
    ...
    (T*)id@p
    ...
  }

// Good use cases
@good@
identifier fn, id, fld;
expression E;
position usage.p;
@@
  fn(..., struct usb_device_id *id, ...)
  {
    ...
(
    id@p->fld
|
    E(..., id@p, ...)
|
// Redundant checks, but ignore
    !id@p
|
// Redundant checks, but ignore
    id ? ... : ...
)
    ...
  }

@script:python depends on usage && (bad || !good)@
p << usage.p;
@@
coccilib.report.print_report(p[0], "suspicious use of device ID")

There're 3 drivers that store usb_device_id, and they're converted to just
use driver_info instead. The other fields of usb_device_id can be easily
retrieved from usb_device via descriptor.id{Vendor,Product}.

There're also a few users that rely on pointer arithmetics. Pegaus and
xusbatm are converted to use driver_info. All unusal USB mass storage
drivers rely on pointer arithemtic to index into a side table, because USB
storage subsystem is using the driver_data for flags. Luckily all these
drivers set no_dynamic_id. Ideally these could be fixed too but their
maintainers probably have a better idea of how.

Link: https://lore.kernel.org/driver-core/20260706-pci_id_fix-v3-0-2d48fc025acc@garyguo.net [1]

Signed-off-by: Gary Guo <gary@garyguo.net>
---
Changes in v2:
- Add le16_to_cpu in ath9k patch.
- Fix AS102 which relies on address comparison. (Sashiko)
- Fix pegasus, xusbatm which relies on pointer arithmetic.
- usb_device_id from static ID table is now not copied. This ensures that
  USB mass storage subsystem can still perform pointer arithmetic. This
  also addresses Danilo's review feedback.
- Link to v1: https://patch.msgid.link/20260630-usb_dyn_id_uaf-v1-0-160a02be5ac2@garyguo.net

---
Gary Guo (7):
      wifi: ath9k_htc: don't store usb_device_id
      usb: usbtmc: don't store usb_device_id
      usb: serial: spcp8x5: don't store usb_device_id
      media: as102: do not rely on id table address comparison
      net: usb: pegasus: don't rely on id table pointer arithmetic
      usb: xusbatm: don't rely on id table pointer arithmetic
      usb: fix UAF when probe runs concurrent to dyn ID removal

 drivers/media/usb/as102/as102_usb_drv.c  | 73 +++++++++++++-------------------
 drivers/net/usb/pegasus.c                | 54 ++++++++++-------------
 drivers/net/usb/pegasus.h                |  3 --
 drivers/net/wireless/ath/ath9k/hif_usb.c | 12 +++---
 drivers/net/wireless/ath/ath9k/hif_usb.h |  2 +-
 drivers/usb/atm/xusbatm.c                |  6 ++-
 drivers/usb/class/usbtmc.c               |  2 -
 drivers/usb/core/driver.c                | 12 ++++--
 drivers/usb/serial/spcp8x5.c             |  6 +--
 include/linux/usb.h                      |  3 +-
 10 files changed, 76 insertions(+), 97 deletions(-)
---
base-commit: 2b763db0c2763d6bf73d7d3e69665222d1f377cf
change-id: 20260629-usb_dyn_id_uaf-9d5f415387d4

Best regards,
--  
Gary Guo <gary@garyguo.net>


^ permalink raw reply

* [PATCH v2 5/7] net: usb: pegasus: don't rely on id table pointer arithmetic
From: Gary Guo @ 2026-07-07 12:26 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
	Toke Høiland-Jørgensen, Johan Hovold,
	Mauro Carvalho Chehab, Petko Manolov, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Chas Williams, Alan Stern
  Cc: linux-usb, driver-core, linux-wireless, linux-media,
	linux-atm-general, netdev, usb-storage, linux-kernel, Gary Guo
In-Reply-To: <20260707-usb_dyn_id_uaf-v2-0-632dcf3adfba@garyguo.net>

The current code is broken when dynamic ID is involved; in such cases
usb_device_id parameter of probe lives on the heap and the pointer
arithmetic will get an index that is wildly out of bound. Instead of
keeping a side table for additional information, use driver_info field of
the usb_device_id.

The dynamic ID parsing code needs to be updated for this; convert it to
just write to the reserved entry for dynamic ID and remove the weird loop.

Signed-off-by: Gary Guo <gary@garyguo.net>
---
 drivers/net/usb/pegasus.c | 54 +++++++++++++++++++----------------------------
 drivers/net/usb/pegasus.h |  3 ---
 2 files changed, 22 insertions(+), 35 deletions(-)

diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 8700eeb8e22d..aba1a640fc26 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -43,21 +43,12 @@ static bool loopback;
 static bool mii_mode;
 static char *devid;
 
-static struct usb_eth_dev usb_dev_id[] = {
-#define	PEGASUS_DEV(pn, vid, pid, flags)	\
-	{.name = pn, .vendor = vid, .device = pid, .private = flags},
-#define PEGASUS_DEV_CLASS(pn, vid, pid, dclass, flags) \
-	PEGASUS_DEV(pn, vid, pid, flags)
-#include "pegasus.h"
-#undef	PEGASUS_DEV
-#undef	PEGASUS_DEV_CLASS
-	{NULL, 0, 0, 0},
-	{NULL, 0, 0, 0}
-};
+static struct usb_eth_dev dynamic_id_info = {};
 
 static struct usb_device_id pegasus_ids[] = {
 #define	PEGASUS_DEV(pn, vid, pid, flags) \
-	{.match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = vid, .idProduct = pid},
+	{.match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = vid, .idProduct = pid, \
+	 .driver_info = (kernel_ulong_t)&(const struct usb_eth_dev) {.name = pn, .private = flags}},
 /*
  * The Belkin F8T012xx1 bluetooth adaptor has the same vendor and product
  * IDs as the Belkin F5D5050, so we need to teach the pegasus driver to
@@ -66,7 +57,8 @@ static struct usb_device_id pegasus_ids[] = {
  */
 #define PEGASUS_DEV_CLASS(pn, vid, pid, dclass, flags) \
 	{.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_CLASS), \
-	.idVendor = vid, .idProduct = pid, .bDeviceClass = dclass},
+	.idVendor = vid, .idProduct = pid, .bDeviceClass = dclass, \
+	.driver_info = (kernel_ulong_t)&(const struct usb_eth_dev) {.name = pn, .private = flags}},
 #include "pegasus.h"
 #undef	PEGASUS_DEV
 #undef	PEGASUS_DEV_CLASS
@@ -402,12 +394,12 @@ static inline int reset_mac(pegasus_t *pegasus)
 	if (i == REG_TIMEOUT)
 		return -ETIMEDOUT;
 
-	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
-	    usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
+	if (le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_LINKSYS ||
+	    le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_DLINK) {
 		set_register(pegasus, Gpio0, 0x24);
 		set_register(pegasus, Gpio0, 0x26);
 	}
-	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) {
+	if (le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_ELCON) {
 		__u16 auxmode;
 		ret = read_mii_word(pegasus, 3, 0x1b, &auxmode);
 		if (ret < 0)
@@ -445,9 +437,9 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
 	memcpy(pegasus->eth_regs, data, sizeof(data));
 	ret = set_registers(pegasus, EthCtrl0, 3, data);
 
-	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
-	    usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS2 ||
-	    usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {
+	if (le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_LINKSYS ||
+	    le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_LINKSYS2 ||
+	    le16_to_cpu(pegasus->usb->descriptor.idVendor) == VENDOR_DLINK) {
 		u16 auxmode;
 		ret = read_mii_word(pegasus, 0, 0x1b, &auxmode);
 		if (ret < 0)
@@ -1153,7 +1145,7 @@ static int pegasus_probe(struct usb_interface *intf,
 	struct usb_device *dev = interface_to_usbdev(intf);
 	struct net_device *net;
 	pegasus_t *pegasus;
-	int dev_index = id - pegasus_ids;
+	const struct usb_eth_dev *info = (const struct usb_eth_dev *)id->driver_info;
 	int res = -ENOMEM;
 	static const u8 bulk_ep_addr[] = {
 		PEGASUS_USB_EP_BULK_IN | USB_DIR_IN,
@@ -1178,7 +1170,6 @@ static int pegasus_probe(struct usb_interface *intf,
 		goto out;
 
 	pegasus = netdev_priv(net);
-	pegasus->dev_index = dev_index;
 	pegasus->intf = intf;
 
 	res = alloc_urbs(pegasus);
@@ -1206,7 +1197,7 @@ static int pegasus_probe(struct usb_interface *intf,
 	pegasus->msg_enable = netif_msg_init(msg_level, NETIF_MSG_DRV
 				| NETIF_MSG_PROBE | NETIF_MSG_LINK);
 
-	pegasus->features = usb_dev_id[dev_index].private;
+	pegasus->features = info ? info->private : DEFAULT_GPIO_RESET;
 	res = get_interrupt_interval(pegasus);
 	if (res)
 		goto out2;
@@ -1235,7 +1226,7 @@ static int pegasus_probe(struct usb_interface *intf,
 	queue_delayed_work(system_long_wq, &pegasus->carrier_check,
 			   CARRIER_CHECK_DELAY);
 	dev_info(&intf->dev, "%s, %s, %pM\n", net->name,
-		 usb_dev_id[dev_index].name, net->dev_addr);
+		 info ? info->name : "(unknown)", net->dev_addr);
 	return 0;
 
 out3:
@@ -1325,8 +1316,9 @@ static struct usb_driver pegasus_driver = {
 
 static void __init parse_id(char *id)
 {
-	unsigned int vendor_id = 0, device_id = 0, flags = 0, i = 0;
+	unsigned int vendor_id = 0, device_id = 0, flags = 0;
 	char *token, *name = NULL;
+	int dyn_id_index = ARRAY_SIZE(pegasus_ids) - 2;
 
 	token = strsep(&id, ":");
 	if (token)
@@ -1348,14 +1340,12 @@ static void __init parse_id(char *id)
 	if (device_id > 0x10000 || device_id == 0)
 		return;
 
-	for (i = 0; usb_dev_id[i].name; i++);
-	usb_dev_id[i].name = name;
-	usb_dev_id[i].vendor = vendor_id;
-	usb_dev_id[i].device = device_id;
-	usb_dev_id[i].private = flags;
-	pegasus_ids[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
-	pegasus_ids[i].idVendor = vendor_id;
-	pegasus_ids[i].idProduct = device_id;
+	dynamic_id_info.name = name;
+	dynamic_id_info.private = flags;
+	pegasus_ids[dyn_id_index].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
+	pegasus_ids[dyn_id_index].idVendor = vendor_id;
+	pegasus_ids[dyn_id_index].idProduct = device_id;
+	pegasus_ids[dyn_id_index].driver_info = (kernel_ulong_t)&dynamic_id_info;
 }
 
 static int __init pegasus_init(void)
diff --git a/drivers/net/usb/pegasus.h b/drivers/net/usb/pegasus.h
index a05b143155ba..ccdedcef52e7 100644
--- a/drivers/net/usb/pegasus.h
+++ b/drivers/net/usb/pegasus.h
@@ -85,7 +85,6 @@ typedef struct pegasus {
 	unsigned		features;
 	u32			msg_enable;
 	u32			wolopts;
-	int			dev_index;
 	int			intr_interval;
 	struct tasklet_struct	rx_tl;
 	struct delayed_work	carrier_check;
@@ -102,8 +101,6 @@ typedef struct pegasus {
 
 struct usb_eth_dev {
 	char	*name;
-	__u16	vendor;
-	__u16	device;
 	__u32	private; /* LSB is gpio reset value */
 };
 

-- 
2.54.0


^ permalink raw reply related

* [PATCH v2 4/7] media: as102: do not rely on id table address comparison
From: Gary Guo @ 2026-07-07 12:26 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
	Toke Høiland-Jørgensen, Johan Hovold,
	Mauro Carvalho Chehab, Petko Manolov, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Chas Williams, Alan Stern
  Cc: linux-usb, driver-core, linux-wireless, linux-media,
	linux-atm-general, netdev, usb-storage, linux-kernel, Gary Guo
In-Reply-To: <20260707-usb_dyn_id_uaf-v2-0-632dcf3adfba@garyguo.net>

The driver info should be retrieved using the driver_info field, not by
address comparison.

Signed-off-by: Gary Guo <gary@garyguo.net>
---
 drivers/media/usb/as102/as102_usb_drv.c | 73 ++++++++++++++-------------------
 1 file changed, 30 insertions(+), 43 deletions(-)

diff --git a/drivers/media/usb/as102/as102_usb_drv.c b/drivers/media/usb/as102/as102_usb_drv.c
index a11024451ceb..be2f8be560fa 100644
--- a/drivers/media/usb/as102/as102_usb_drv.c
+++ b/drivers/media/usb/as102/as102_usb_drv.c
@@ -24,35 +24,33 @@ static void as102_usb_stop_stream(struct as102_dev_t *dev);
 static int as102_open(struct inode *inode, struct file *file);
 static int as102_release(struct inode *inode, struct file *file);
 
-static const struct usb_device_id as102_usb_id_table[] = {
-	{ USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001) },
-	{ USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) },
-	{ USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) },
-	{ USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID) },
-	{ USB_DEVICE(SKY_IT_DIGITAL_KEY_USB_VID, SKY_IT_DIGITAL_KEY_USB_PID) },
-	{ } /* Terminating entry */
+struct as102_dev_info {
+	const char *name;
+	/*
+	 * eLNA configuration: devices built on the reference design work best
+	 * with 0xA0, while custom designs seem to require 0xC0
+	 */
+	uint8_t elna_cfg;
 };
 
-/* Note that this table must always have the same number of entries as the
-   as102_usb_id_table struct */
-static const char * const as102_device_names[] = {
-	AS102_REFERENCE_DESIGN,
-	AS102_PCTV_74E,
-	AS102_ELGATO_EYETV_DTT_NAME,
-	AS102_NBOX_DVBT_DONGLE_NAME,
-	AS102_SKY_IT_DIGITAL_KEY_NAME,
-	NULL /* Terminating entry */
-};
+#define DRIVER_INFO(dev_name, dev_elna_cfg) \
+	.driver_info = (kernel_ulong_t)&(const struct as102_dev_info){ \
+		.name = (dev_name), \
+		.elna_cfg = (dev_elna_cfg), \
+	}
 
-/* eLNA configuration: devices built on the reference design work best
-   with 0xA0, while custom designs seem to require 0xC0 */
-static uint8_t const as102_elna_cfg[] = {
-	0xA0,
-	0xC0,
-	0xC0,
-	0xA0,
-	0xA0,
-	0x00 /* Terminating entry */
+static const struct usb_device_id as102_usb_id_table[] = {
+	{ USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001),
+	  DRIVER_INFO(AS102_REFERENCE_DESIGN, 0xA0) },
+	{ USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID),
+	  DRIVER_INFO(AS102_PCTV_74E, 0xC0) },
+	{ USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID),
+	  DRIVER_INFO(AS102_ELGATO_EYETV_DTT_NAME, 0xC0) },
+	{ USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID),
+	  DRIVER_INFO(AS102_NBOX_DVBT_DONGLE_NAME, 0xA0) },
+	{ USB_DEVICE(SKY_IT_DIGITAL_KEY_USB_VID, SKY_IT_DIGITAL_KEY_USB_PID),
+	  DRIVER_INFO(AS102_SKY_IT_DIGITAL_KEY_NAME, 0xA0) },
+	{ } /* Terminating entry */
 };
 
 struct usb_driver as102_usb_driver = {
@@ -336,29 +334,18 @@ static int as102_usb_probe(struct usb_interface *intf,
 {
 	int ret;
 	struct as102_dev_t *as102_dev;
-	int i;
-
-	/* This should never actually happen */
-	if (ARRAY_SIZE(as102_usb_id_table) !=
-	    (sizeof(as102_device_names) / sizeof(const char *))) {
-		pr_err("Device names table invalid size");
-		return -EINVAL;
-	}
+	const struct as102_dev_info *info = (const struct as102_dev_info *)id->driver_info;
 
 	as102_dev = kzalloc_obj(struct as102_dev_t);
 	if (as102_dev == NULL)
 		return -ENOMEM;
 
-	/* Assign the user-friendly device name */
-	for (i = 0; i < ARRAY_SIZE(as102_usb_id_table); i++) {
-		if (id == &as102_usb_id_table[i]) {
-			as102_dev->name = as102_device_names[i];
-			as102_dev->elna_cfg = as102_elna_cfg[i];
-		}
-	}
-
-	if (as102_dev->name == NULL)
+	if (info) {
+		as102_dev->name = info->name;
+		as102_dev->elna_cfg = info->elna_cfg;
+	} else {
 		as102_dev->name = "Unknown AS102 device";
+	}
 
 	/* set private callback functions */
 	as102_dev->bus_adap.ops = &as102_priv_ops;

-- 
2.54.0


^ permalink raw reply related

* [PATCH v2 1/7] wifi: ath9k_htc: don't store usb_device_id
From: Gary Guo @ 2026-07-07 12:26 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
	Toke Høiland-Jørgensen, Johan Hovold,
	Mauro Carvalho Chehab, Petko Manolov, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Chas Williams, Alan Stern
  Cc: linux-usb, driver-core, linux-wireless, linux-media,
	linux-atm-general, netdev, usb-storage, linux-kernel, Gary Guo
In-Reply-To: <20260707-usb_dyn_id_uaf-v2-0-632dcf3adfba@garyguo.net>

usb_device_id is not guaranteed to live longer than probe due to presence
of dynamic ID. All information apart from driver_data can be easily
retrieved from usb_device, so just store driver_data.

Signed-off-by: Gary Guo <gary@garyguo.net>
---
 drivers/net/wireless/ath/ath9k/hif_usb.c | 12 ++++++------
 drivers/net/wireless/ath/ath9k/hif_usb.h |  2 +-
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 47f904e7e652..d3491ff08e6e 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -1087,7 +1087,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
 	}
 	kfree(buf);
 
-	if (IS_AR7010_DEVICE(hif_dev->usb_device_id->driver_info))
+	if (IS_AR7010_DEVICE(hif_dev->id_info))
 		firm_offset = AR7010_FIRMWARE_TEXT;
 	else
 		firm_offset = AR9271_FIRMWARE_TEXT;
@@ -1182,7 +1182,7 @@ static int ath9k_hif_request_firmware(struct hif_device_usb *hif_dev,
 	if (MAJOR_VERSION_REQ == 1 && hif_dev->fw_minor_index == 3) {
 		const char *filename;
 
-		if (IS_AR7010_DEVICE(hif_dev->usb_device_id->driver_info))
+		if (IS_AR7010_DEVICE(hif_dev->id_info))
 			filename = FIRMWARE_AR7010_1_1;
 		else
 			filename = FIRMWARE_AR9271;
@@ -1198,7 +1198,7 @@ static int ath9k_hif_request_firmware(struct hif_device_usb *hif_dev,
 
 		return -ENOENT;
 	} else {
-		if (IS_AR7010_DEVICE(hif_dev->usb_device_id->driver_info))
+		if (IS_AR7010_DEVICE(hif_dev->id_info))
 			chip = "7010";
 		else
 			chip = "9271";
@@ -1255,9 +1255,9 @@ static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context)
 
 	ret = ath9k_htc_hw_init(hif_dev->htc_handle,
 				&hif_dev->interface->dev,
-				hif_dev->usb_device_id->idProduct,
+				le16_to_cpu(hif_dev->udev->descriptor.idProduct),
 				hif_dev->udev->product,
-				hif_dev->usb_device_id->driver_info);
+				hif_dev->id_info);
 	if (ret) {
 		ret = -EINVAL;
 		goto err_htc_hw_init;
@@ -1369,7 +1369,7 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
 
 	hif_dev->udev = udev;
 	hif_dev->interface = interface;
-	hif_dev->usb_device_id = id;
+	hif_dev->id_info = id->driver_info;
 #ifdef CONFIG_PM
 	udev->reset_resume = 1;
 #endif
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index dc0b0fa5c325..b3e7b0fb54b8 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -115,7 +115,7 @@ struct cmd_buf {
 struct hif_device_usb {
 	struct usb_device *udev;
 	struct usb_interface *interface;
-	const struct usb_device_id *usb_device_id;
+	int id_info;
 	const void *fw_data;
 	size_t fw_size;
 	struct completion fw_done;

-- 
2.54.0


^ permalink raw reply related

* [PATCH v3] wifi: cfg80211: bound element ID read when checking non-inheritance
From: HE WEI (ギカク) @ 2026-07-07 11:59 UTC (permalink / raw)
  To: Johannes Berg
  Cc: linux-wireless, linux-kernel, Sara Sharon, Luca Coelho,
	HE WEI (ギカク)
In-Reply-To: <20260626144543.5034-1-skyexpoc@gmail.com>

cfg80211_is_element_inherited() reads the first data octet of the
candidate element (id = elem->data[0]) to look it up in an extension
non-inheritance list. It does so after testing elem->id, but without
verifying that the element actually has a data octet. A zero-length
extension element (WLAN_EID_EXTENSION with length 0) therefore makes it
read one octet past the end of the element.

_ieee802_11_parse_elems_full() runs this check for every element of a
frame once a non-inheritance context exists -- e.g. while parsing a
per-STA profile of a Multi-Link element in a (re)association response,
or a non-transmitted BSS profile -- so a crafted frame from an AP can
trigger a one-octet slab-out-of-bounds read during element parsing:

  BUG: KASAN: slab-out-of-bounds in cfg80211_is_element_inherited
  Read of size 1 ... in net/wireless/scan.c

Return early (treat the element as inherited) when an extension element
carries no data, mirroring the existing handling of empty ID lists.

The bug was found by fuzzing ieee802_11_parse_elems_full() under KASAN.

Fixes: f7dacfb11475 ("cfg80211: support non-inheritance element")
Signed-off-by: HE WEI (ギカク) <skyexpoc@gmail.com>
---
Changes in v3:
- Move the version changelog below the --- line and trim the Fixes
  commit id to 12 characters (checkpatch).

Changes in v2:
- Correct the Fixes tag. The unchecked elem->data[0] read was
  introduced in 2019 by f7dacfb11475 ("cfg80211: support
  non-inheritance element") -- the commit that added
  cfg80211_is_element_inherited() -- not by dfd9aa3e7a45, which only
  rewrote the sibling cfg80211_gen_new_ie() and never touched this
  function.

 net/wireless/scan.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 05b7dc6b7..0a44856b1 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -205,7 +205,7 @@ bool cfg80211_is_element_inherited(const struct element *elem,
 		return true;

 	if (elem->id == WLAN_EID_EXTENSION) {
-		if (!ext_id_len)
+		if (!ext_id_len || !elem->datalen)
 			return true;
 		loop_len = ext_id_len;
 		list = &non_inherit_elem->data[3 + id_len];
--
2.43.0

^ permalink raw reply related

* Re: [PATCH v2] wifi: brcmfmac: cyw: fix heap overflow on a short auth frame
From: Johannes Berg @ 2026-07-07 11:53 UTC (permalink / raw)
  To: Arend van Spriel, Maoyi Xie
  Cc: linux-wireless, brcm80211, brcm80211-dev-list.pdl, linux-kernel
In-Reply-To: <996adbdb-9531-49e1-8cae-5fcb7b914d19@broadcom.com>

On Tue, 2026-07-07 at 13:40 +0200, Arend van Spriel wrote:
> 
> Actually v1 was already applied to the wireless tree.

Yeah, I thought the Link: was fine - I (only) add links to the patch
submission itself for tracking (Linus isn't super happy about accepts it
now), but the link given was to a report/further discussion, so that
seemed OK.

johannes

^ permalink raw reply

* Re: [PATCH v2] wifi: brcmfmac: cyw: fix heap overflow on a short auth frame
From: Arend van Spriel @ 2026-07-07 11:40 UTC (permalink / raw)
  To: Maoyi Xie; +Cc: linux-wireless, brcm80211, brcm80211-dev-list.pdl, linux-kernel
In-Reply-To: <77dfa2f3-296f-470b-8d21-0f10a56a2a4a@broadcom.com>

On 07/07/2026 13:32, Arend van Spriel wrote:
> On 07/07/2026 08:31, Maoyi Xie wrote:
>> brcmf_notify_auth_frame_rx() takes the frame length from the firmware
>> event and copies the frame body with the management header offset
>> subtracted:
>>
>>     u32 mgmt_frame_len = e->datalen - sizeof(struct brcmf_rx_mgmt_data);
>>     ...
>>     memcpy(&mgmt_frame->u, frame,
>>            mgmt_frame_len - offsetof(struct ieee80211_mgmt, u));
>>
>> The only length check is e->datalen >= sizeof(*rxframe), so 
>> mgmt_frame_len
>> can be anything from 0 up. offsetof(struct ieee80211_mgmt, u) is 24. When
>> mgmt_frame_len is below that, the subtraction wraps as an unsigned 
>> value to
>> a huge length. The memcpy then runs far past the kzalloc'd buffer. A
>> malicious or malfunctioning AP can make the frame short during the
>> external SAE auth exchange, so this is a remotely triggered heap 
>> overflow.
>>
>> Reject frames shorter than the management header offset before the copy.
>>
>> Fixes: 66f909308a7c ("wifi: brcmfmac: cyw: support external SAE 
>> authentication in station mode")
>> Cc: stable@vger.kernel.org
>> Co-developed-by: Kaixuan Li <kaixuan.li@ntu.edu.sg>
>> Signed-off-by: Kaixuan Li <kaixuan.li@ntu.edu.sg>
>> Signed-off-by: Maoyi Xie <maoyixie.tju@gmail.com>
>> Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
> 
> Thanks. Nothing to add here.

Actually v1 was already applied to the wireless tree.

>> ---
>> v2: drop the Link: tag (Arend), add Arend's Acked-by.
>>
>> v1: https://lore.kernel.org/r/20260627131313.3878893-1- 
>> maoyixie.tju@gmail.com
>>   drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c | 6 ++++++
>>   1 file changed, 6 insertions(+)


^ permalink raw reply

* Re: [PATCH v2] wifi: brcmfmac: cyw: fix heap overflow on a short auth frame
From: Arend van Spriel @ 2026-07-07 11:32 UTC (permalink / raw)
  To: Maoyi Xie; +Cc: linux-wireless, brcm80211, brcm80211-dev-list.pdl, linux-kernel
In-Reply-To: <20260707063155.3099999-1-maoyixie.tju@gmail.com>

On 07/07/2026 08:31, Maoyi Xie wrote:
> brcmf_notify_auth_frame_rx() takes the frame length from the firmware
> event and copies the frame body with the management header offset
> subtracted:
> 
> 	u32 mgmt_frame_len = e->datalen - sizeof(struct brcmf_rx_mgmt_data);
> 	...
> 	memcpy(&mgmt_frame->u, frame,
> 	       mgmt_frame_len - offsetof(struct ieee80211_mgmt, u));
> 
> The only length check is e->datalen >= sizeof(*rxframe), so mgmt_frame_len
> can be anything from 0 up. offsetof(struct ieee80211_mgmt, u) is 24. When
> mgmt_frame_len is below that, the subtraction wraps as an unsigned value to
> a huge length. The memcpy then runs far past the kzalloc'd buffer. A
> malicious or malfunctioning AP can make the frame short during the
> external SAE auth exchange, so this is a remotely triggered heap overflow.
> 
> Reject frames shorter than the management header offset before the copy.
> 
> Fixes: 66f909308a7c ("wifi: brcmfmac: cyw: support external SAE authentication in station mode")
> Cc: stable@vger.kernel.org
> Co-developed-by: Kaixuan Li <kaixuan.li@ntu.edu.sg>
> Signed-off-by: Kaixuan Li <kaixuan.li@ntu.edu.sg>
> Signed-off-by: Maoyi Xie <maoyixie.tju@gmail.com>
> Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>

Thanks. Nothing to add here.

> ---
> v2: drop the Link: tag (Arend), add Arend's Acked-by.
> 
> v1: https://lore.kernel.org/r/20260627131313.3878893-1-maoyixie.tju@gmail.com
>   drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c | 6 ++++++
>   1 file changed, 6 insertions(+)

^ permalink raw reply

* [PATCH iwlwifi-next] wifi: iwlwifi: transport: Change system_unbound_wq with system_dfl_wq
From: Marco Crivellari @ 2026-07-07 10:23 UTC (permalink / raw)
  To: linux-kernel, linux-wireless
  Cc: Tejun Heo, Lai Jiangshan, Frederic Weisbecker,
	Sebastian Andrzej Siewior, Marco Crivellari, Michal Hocko,
	Miri Korenblit

system_wq (per-CPU) and system_unbound_wq (unbound) are the older
workqueue name, replaced by system_{percpu|dfl}_wq.
The new workqueues have been introduced by:

  128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq")

Usage of older workqueues will now trigger a pr_warn_once() because they are
marked as deprecated as per commit:

  64d8eae3f895 ("workqueue: Add warnings and fallback if system_{unbound}_wq is used")

So change the used workqueue with the newer, keeping the same behavior.

Suggested-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
---
 drivers/net/wireless/intel/iwlwifi/iwl-trans.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
index 73aae1125042..9343b6230e1a 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
@@ -236,7 +236,7 @@ static void iwl_trans_restart_wk(struct work_struct *wk)
 	mode = iwl_trans_determine_restart_mode(trans);
 	if (mode == IWL_RESET_MODE_BACKOFF) {
 		IWL_ERR(trans, "Too many device errors - delay next reset\n");
-		queue_delayed_work(system_unbound_wq, &trans->restart.wk,
+		queue_delayed_work(system_dfl_wq, &trans->restart.wk,
 				   IWL_TRANS_RESET_DELAY);
 		return;
 	}
-- 
2.54.0


^ permalink raw reply related

* [PATCH v2] wifi: cfg80211: bound element ID read when checking non-inheritance
From: HE WEI (ギカク) @ 2026-07-07  9:48 UTC (permalink / raw)
  To: Johannes Berg
  Cc: linux-wireless, linux-kernel, HE WEI (ギカク)
In-Reply-To: <20260626144543.5034-1-skyexpoc@gmail.com>

cfg80211_is_element_inherited() reads the first data octet of the
candidate element (id = elem->data[0]) to look it up in an extension
non-inheritance list. It does so after testing elem->id, but without
verifying that the element actually has a data octet. A zero-length
extension element (WLAN_EID_EXTENSION with length 0) therefore makes it
read one octet past the end of the element.

_ieee802_11_parse_elems_full() runs this check for every element of a
frame once a non-inheritance context exists -- e.g. while parsing a
per-STA profile of a Multi-Link element in a (re)association response,
or a non-transmitted BSS profile -- so a crafted frame from an AP can
trigger a one-octet slab-out-of-bounds read during element parsing:

  BUG: KASAN: slab-out-of-bounds in cfg80211_is_element_inherited
  Read of size 1 ... in net/wireless/scan.c

Return early (treat the element as inherited) when an extension element
carries no data, mirroring the existing handling of empty ID lists.

The bug was found by fuzzing ieee802_11_parse_elems_full() under KASAN.

Changes in v2:
- Fixed the Fixes tag to point to the correct commit f7dacfb11475b
  ("cfg80211: support non-inheritance element")
- The bug was introduced in the original implementation in 2019, not in
  commit dfd9aa3e7a45

Fixes: f7dacfb11475b ("cfg80211: support non-inheritance element")
Signed-off-by: HE WEI (ギカク) <skyexpoc@gmail.com>
---
 net/wireless/scan.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 05b7dc6b7..0a44856b1 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -205,7 +205,7 @@ bool cfg80211_is_element_inherited(const struct element *elem,
 		return true;
 
 	if (elem->id == WLAN_EID_EXTENSION) {
-		if (!ext_id_len)
+		if (!ext_id_len || !elem->datalen)
 			return true;
 		loop_len = ext_id_len;
 		list = &non_inherit_elem->data[3 + id_len];
-- 
2.43.0

^ permalink raw reply related

* Re: [PATCH] wifi: cfg80211: bound element ID read when checking non-inheritance
From: HE WEI(ギカク) @ 2026-07-07  9:22 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, linux-kernel
In-Reply-To: <b4129a5d4d11080726c460955579851198c879f5.camel@sipsolutions.net>

Hi Johannes,

I'm sorry, that was my oversight. After reconfirmation, I found that
cfg80211_is_element_inherited() was introduced in commit f7dacfb11475b
("cfg80211: support non-inheritance element"), not dfd9aa3e7a45.

The bug existed from the initial implementation of this function in 2019.
I will send v2 with the correct Fixes tag.

Thank you for catching this!

Best regards,
HE WEI(ギカク)

Johannes Berg <johannes@sipsolutions.net> 于2026年7月6日周一 20:44写道:
>
> On Fri, 2026-06-26 at 23:45 +0900, HE WEI (ギカク) wrote:
>
> >
> > Fixes: dfd9aa3e7a45 ("wifi: cfg80211: rewrite merging of inherited elements")
>
> This doesn't seem right at all?
>
> johannes

^ permalink raw reply

* [PATCH rtw-next 15/15] wifi: rtw89: set needed firmware elements for early chips transition
From: Ping-Ke Shih @ 2026-07-07  9:10 UTC (permalink / raw)
  To: linux-wireless; +Cc: gary.chang, echuang
In-Reply-To: <20260707091056.42771-1-pkshih@realtek.com>

The early chips including RTL8852A, RTL8851B, RTL8852B and RTL8852C have
driver built-in tables, which are not preferred. New firmware is prepared
with corresponding tables in firmware elements, so we can start to
transition. After this patch, old firmware is still usable, but add a
prompt text for users to update firmware.

Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtw89/fw.c       | 10 +++++++
 drivers/net/wireless/realtek/rtw89/fw.h       | 27 ++++++++++++++++---
 drivers/net/wireless/realtek/rtw89/rtw8851b.c |  3 ++-
 drivers/net/wireless/realtek/rtw89/rtw8852a.c |  3 ++-
 drivers/net/wireless/realtek/rtw89/rtw8852b.c |  3 ++-
 drivers/net/wireless/realtek/rtw89/rtw8852c.c |  3 ++-
 6 files changed, 41 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index 9d98805835d6..6b293611d5a8 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -1562,6 +1562,7 @@ int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev)
 	u32 unrecognized_elements = chip->needed_fw_elms;
 	const struct rtw89_fw_element_handler *handler;
 	const struct rtw89_fw_element_hdr *hdr;
+	bool transition;
 	u32 elm_size;
 	u32 elem_id;
 	u32 offset;
@@ -1569,6 +1570,9 @@ int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev)
 
 	BUILD_BUG_ON(sizeof(chip->needed_fw_elms) * 8 < RTW89_FW_ELEMENT_ID_NUM);
 
+	transition = !!((chip->needed_fw_elms & BIT(__RTW89_FW_ELEMENT_ID_INTL_TRANSITION)));
+	unrecognized_elements &= ~BIT(__RTW89_FW_ELEMENT_ID_INTL_TRANSITION);
+
 	offset = rtw89_mfw_get_size(rtwdev);
 	offset = ALIGN(offset, RTW89_FW_ELEMENT_ALIGN);
 	if (offset == 0)
@@ -1608,6 +1612,12 @@ int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev)
 	}
 
 	if (unrecognized_elements) {
+		if (transition) {
+			rtw89_info(rtwdev, "NOTE: This firmware is going to be obsolete!\n"
+				   "Please download the latest firmware from https://gitlab.com/kernel-firmware/linux-firmware.git\n");
+			return 0;
+		}
+
 		rtw89_err(rtwdev, "Firmware elements 0x%08x are unrecognized\n",
 			  unrecognized_elements);
 		return -ENOENT;
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index 71e8554a7af7..e4c81b893780 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -4346,31 +4346,50 @@ enum rtw89_fw_element_id {
 	RTW89_FW_ELEMENT_ID_DIAG_MAC = 28,
 	RTW89_FW_ELEMENT_ID_TX_COMP = 29,
 
+	__RTW89_FW_ELEMENT_ID_INTL_TRANSITION,
 	RTW89_FW_ELEMENT_ID_NUM,
 };
 
+#define BITS_OF_RTW89_TXPWR_FW_ELEMENTS_TX_SHAPE \
+	(BIT(RTW89_FW_ELEMENT_ID_TX_SHAPE_LMT) | \
+	 BIT(RTW89_FW_ELEMENT_ID_TX_SHAPE_LMT_RU))
+
 #define BITS_OF_RTW89_TXPWR_FW_ELEMENTS_NO_6GHZ \
 	(BIT(RTW89_FW_ELEMENT_ID_TXPWR_BYRATE) | \
 	 BIT(RTW89_FW_ELEMENT_ID_TXPWR_LMT_2GHZ) | \
 	 BIT(RTW89_FW_ELEMENT_ID_TXPWR_LMT_5GHZ) | \
 	 BIT(RTW89_FW_ELEMENT_ID_TXPWR_LMT_RU_2GHZ) | \
 	 BIT(RTW89_FW_ELEMENT_ID_TXPWR_LMT_RU_5GHZ) | \
-	 BIT(RTW89_FW_ELEMENT_ID_TX_SHAPE_LMT) | \
-	 BIT(RTW89_FW_ELEMENT_ID_TX_SHAPE_LMT_RU))
+	 BITS_OF_RTW89_TXPWR_FW_ELEMENTS_TX_SHAPE)
 
 #define BITS_OF_RTW89_TXPWR_FW_ELEMENTS \
 	(BITS_OF_RTW89_TXPWR_FW_ELEMENTS_NO_6GHZ | \
 	 BIT(RTW89_FW_ELEMENT_ID_TXPWR_LMT_6GHZ) | \
 	 BIT(RTW89_FW_ELEMENT_ID_TXPWR_LMT_RU_6GHZ))
 
-#define RTW89_AX_GEN_DEF_NEEDED_FW_ELEMENTS_NO_6GHZ \
+#define RTW89_AX_GEN_DEF_NEEDED_FW_ELEMENTS_BASE \
 	(BIT(RTW89_FW_ELEMENT_ID_BB_REG) | \
 	 BIT(RTW89_FW_ELEMENT_ID_RADIO_A) | \
 	 BIT(RTW89_FW_ELEMENT_ID_RADIO_B) | \
 	 BIT(RTW89_FW_ELEMENT_ID_RF_NCTL) | \
-	 BIT(RTW89_FW_ELEMENT_ID_TXPWR_TRK) | \
+	 BIT(RTW89_FW_ELEMENT_ID_TXPWR_TRK))
+
+#define RTW89_AX_GEN_DEF_NEEDED_FW_ELEMENTS_NO_6GHZ \
+	(RTW89_AX_GEN_DEF_NEEDED_FW_ELEMENTS_BASE | \
 	 BITS_OF_RTW89_TXPWR_FW_ELEMENTS_NO_6GHZ)
 
+#define RTW89_AX_GEN_DEF_NEEDED_FW_ELEMENTS \
+	(RTW89_AX_GEN_DEF_NEEDED_FW_ELEMENTS_BASE | \
+	 BITS_OF_RTW89_TXPWR_FW_ELEMENTS)
+
+#define RTW89_AX_GEN_DEF_NEEDED_FW_ELEMENTS_RTL8852A \
+	(RTW89_AX_GEN_DEF_NEEDED_FW_ELEMENTS_NO_6GHZ & \
+	 ~BITS_OF_RTW89_TXPWR_FW_ELEMENTS_TX_SHAPE)
+
+#define RTW89_AX_GEN_DEF_NEEDED_FW_ELEMENTS_RTL8851B \
+	(RTW89_AX_GEN_DEF_NEEDED_FW_ELEMENTS_NO_6GHZ & \
+	 ~BIT(RTW89_FW_ELEMENT_ID_RADIO_B))
+
 #define RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS_BASE \
 	(BIT(RTW89_FW_ELEMENT_ID_BB_REG) | \
 	 BIT(RTW89_FW_ELEMENT_ID_RADIO_A) | \
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
index d0c262c3dffe..818cf82861d9 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
@@ -2637,7 +2637,8 @@ const struct rtw89_chip_info rtw8851b_chip_info = {
 	},
 	.try_ce_fw		= true,
 	.bbmcu_nr		= 0,
-	.needed_fw_elms		= 0,
+	.needed_fw_elms		= RTW89_AX_GEN_DEF_NEEDED_FW_ELEMENTS_RTL8851B |
+				  BIT(__RTW89_FW_ELEMENT_ID_INTL_TRANSITION),
 	.fw_blacklist		= NULL,
 	.fifo_size		= 196608,
 	.small_fifo_size	= true,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
index 61b6b76c5bdb..08821af48f02 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
@@ -2374,7 +2374,8 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
 	},
 	.try_ce_fw		= false,
 	.bbmcu_nr		= 0,
-	.needed_fw_elms		= 0,
+	.needed_fw_elms		= RTW89_AX_GEN_DEF_NEEDED_FW_ELEMENTS_RTL8852A |
+				  BIT(__RTW89_FW_ELEMENT_ID_INTL_TRANSITION),
 	.fw_blacklist		= NULL,
 	.fifo_size		= 458752,
 	.small_fifo_size	= false,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
index a8638024b54a..5904127cc836 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
@@ -968,7 +968,8 @@ const struct rtw89_chip_info rtw8852b_chip_info = {
 	},
 	.try_ce_fw		= true,
 	.bbmcu_nr		= 0,
-	.needed_fw_elms		= 0,
+	.needed_fw_elms		= RTW89_AX_GEN_DEF_NEEDED_FW_ELEMENTS_NO_6GHZ |
+				  BIT(__RTW89_FW_ELEMENT_ID_INTL_TRANSITION),
 	.fw_blacklist		= &rtw89_fw_blacklist_default,
 	.fifo_size		= 196608,
 	.small_fifo_size	= true,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 52986b982ecd..35cbb59b3e56 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -3173,7 +3173,8 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
 	},
 	.try_ce_fw		= false,
 	.bbmcu_nr		= 0,
-	.needed_fw_elms		= 0,
+	.needed_fw_elms		= RTW89_AX_GEN_DEF_NEEDED_FW_ELEMENTS |
+				  BIT(__RTW89_FW_ELEMENT_ID_INTL_TRANSITION),
 	.fw_blacklist		= &rtw89_fw_blacklist_default,
 	.fifo_size		= 458752,
 	.small_fifo_size	= false,
-- 
2.25.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox