Merge Official Source

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen
2025-08-29 15:16:20 +08:00
30 changed files with 473 additions and 47 deletions
+2 -2
View File
@@ -1,2 +1,2 @@
LINUX_VERSION-6.6 = .100
LINUX_KERNEL_HASH-6.6.100 = d6c0ec4d55b14814f55b62a0b23a2d95faf66877e48fbfb4b83523e4afdf97ba
LINUX_VERSION-6.6 = .102
LINUX_KERNEL_HASH-6.6.102 = 80d2feb7334c30bacbe1e7dafa9ea415efb2c0ea4f4740ecbd1467cf5d94de5c
@@ -0,0 +1,55 @@
From: Maharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
Date: Fri, 18 Jul 2025 11:38:35 +0530
Subject: [PATCH] wifi: mac80211: Add link iteration macro for link data
with rcu_dereference
Currently, the existing macro for_each_link_data() uses sdata_dereference()
which requires the wiphy lock. This lock cannot be used in atomic or RCU
read-side contexts, such as in the RX path.
Introduce a new macro, for_each_link_data_rcu(), that iterates over link of
sdata using rcu_dereference(), making it safe to use in RCU contexts. This
allows callers to access link data without requiring the wiphy lock.
The macro takes into account the vif.valid_links bitmap and ensures only
valid links are accessed safely. Callers are responsible for ensuring that
rcu_read_lock() is held when using this macro.
Signed-off-by: Maharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20250718060837.59371-3-maharaja.kennadyrajan@oss.qualcomm.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1211,6 +1211,30 @@ struct ieee80211_sub_if_data *vif_to_sda
if ((_link = wiphy_dereference((local)->hw.wiphy, \
___sdata->link[___link_id])))
+#define for_each_link_data(sdata, __link) \
+ /* outer loop just to define the variable ... */ \
+ for (struct ieee80211_sub_if_data *__sdata = (sdata); __sdata; \
+ __sdata = NULL /* always stop */) \
+ for (int __link_id = 0; \
+ __link_id < ARRAY_SIZE((__sdata)->link); __link_id++) \
+ if ((!(__sdata)->vif.valid_links || \
+ (__sdata)->vif.valid_links & BIT(__link_id)) && \
+ ((__link) = sdata_dereference((__sdata)->link[__link_id], \
+ (__sdata))))
+
+/*
+ * for_each_link_data_rcu should be used under RCU read lock.
+ */
+#define for_each_link_data_rcu(sdata, __link) \
+ /* outer loop just to define the variable ... */ \
+ for (struct ieee80211_sub_if_data *__sdata = (sdata); __sdata; \
+ __sdata = NULL /* always stop */) \
+ for (int __link_id = 0; \
+ __link_id < ARRAY_SIZE((__sdata)->link); __link_id++) \
+ if ((!(__sdata)->vif.valid_links || \
+ (__sdata)->vif.valid_links & BIT(__link_id)) && \
+ ((__link) = rcu_dereference((__sdata)->link[__link_id]))) \
+
static inline int
ieee80211_get_mbssid_beacon_len(struct cfg80211_mbssid_elems *elems,
struct cfg80211_rnr_elems *rnr_elems,
@@ -0,0 +1,77 @@
From: Maharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
Date: Fri, 18 Jul 2025 11:38:36 +0530
Subject: [PATCH] wifi: mac80211: extend beacon monitoring for MLO
Currently, reset beacon monitor (ieee80211_sta_reset_beacon_monitor())
timer is handled only for non-AP non-MLD STA and do not support non-AP MLD
STA. When the beacon loss occurs in non-AP MLD STA with the current
implementation, it is treated as a single link and the timer will reset
based on the timeout of the deflink, without checking all the links.
Check the CSA flags for all the links in the MLO and decide whether to
schedule the work queue for beacon loss. If any of the links has CSA
active, then beacon loss work is not scheduled.
Also, call the functions ieee80211_sta_reset_beacon_monitor() and
ieee80211_sta_reset_conn_monitor() from ieee80211_csa_switch_work() only
when all the links are CSA active.
Signed-off-by: Maharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20250718060837.59371-4-maharaja.kennadyrajan@oss.qualcomm.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2159,6 +2159,21 @@ static void ieee80211_csa_switch_work(st
}
}
+ /*
+ * It is not necessary to reset these timers if any link does not
+ * have an active CSA and that link still receives the beacons
+ * when other links have active CSA.
+ */
+ for_each_link_data(sdata, link) {
+ if (!link->conf->csa_active)
+ return;
+ }
+
+ /*
+ * Reset the beacon monitor and connection monitor timers when CSA
+ * is active for all links in MLO when channel switch occurs in all
+ * the links.
+ */
ieee80211_sta_reset_beacon_monitor(sdata);
ieee80211_sta_reset_conn_monitor(sdata);
}
@@ -7863,6 +7878,29 @@ void ieee80211_sta_work(struct ieee80211
}
}
+static bool
+ieee80211_is_csa_in_progress(struct ieee80211_sub_if_data *sdata)
+{
+ /*
+ * In MLO, check the CSA flags 'active' and 'waiting_bcn' for all
+ * the links.
+ */
+ struct ieee80211_link_data *link;
+ bool ret = true;
+
+ rcu_read_lock();
+ for_each_link_data_rcu(sdata, link) {
+ if (!(link->conf->csa_active &&
+ !link->u.mgd.csa.waiting_bcn)) {
+ ret = false;
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ return ret;
+}
+
static void ieee80211_sta_bcn_mon_timer(struct timer_list *t)
{
struct ieee80211_sub_if_data *sdata =
@@ -0,0 +1,141 @@
From: Maharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
Date: Fri, 18 Jul 2025 11:38:37 +0530
Subject: [PATCH] wifi: mac80211: extend connection monitoring for MLO
Currently, reset connection monitor (ieee80211_sta_reset_conn_monitor())
timer is handled only for non-AP non-MLD STA and do not support non-AP MLD
STA. The current implementation checks for the CSA active and update the
monitor timer with the timeout value of deflink and reset the timer based
on the deflink's timeout value else schedule the connection loss work when
the deflink is timed out and it won't work for the non-AP MLD STA.
Handle the reset connection monitor timer for non-AP MLD STA by updating
the monitor timer with the timeout value which is determined based on the
link that will expire last among all the links in MLO. If at least one link
has not timed out, the timer is updated accordingly with the latest timeout
value else schedule the connection loss work when all links have timed out.
Remove the MLO-related WARN_ON() checks in the beacon and connection
monitoring logic code paths as they support MLO now.
Signed-off-by: Maharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20250718060837.59371-5-maharaja.kennadyrajan@oss.qualcomm.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3831,9 +3831,6 @@ static void ieee80211_mgd_probe_ap_send(
lockdep_assert_wiphy(sdata->local->hw.wiphy);
- if (WARN_ON(ieee80211_vif_is_mld(&sdata->vif)))
- return;
-
/*
* Try sending broadcast probe requests for the last three
* probe requests after the first ones failed since some
@@ -3879,9 +3876,6 @@ static void ieee80211_mgd_probe_ap(struc
lockdep_assert_wiphy(sdata->local->hw.wiphy);
- if (WARN_ON_ONCE(ieee80211_vif_is_mld(&sdata->vif)))
- return;
-
if (!ieee80211_sdata_running(sdata))
return;
@@ -7921,36 +7915,73 @@ static void ieee80211_sta_bcn_mon_timer(
&sdata->u.mgd.beacon_connection_loss_work);
}
+static unsigned long
+ieee80211_latest_active_link_conn_timeout(struct ieee80211_sub_if_data *sdata)
+{
+ unsigned long latest_timeout = 0;
+ unsigned int link_id;
+ struct sta_info *sta;
+
+ rcu_read_lock();
+
+ sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr);
+ if (!sta)
+ goto out;
+
+ for (link_id = 0; link_id < ARRAY_SIZE(sta->link);
+ link_id++) {
+ struct link_sta_info *link_sta;
+ unsigned long timeout;
+
+ link_sta = rcu_dereference(sta->link[link_id]);
+ if (!link_sta)
+ continue;
+
+ timeout = link_sta->status_stats.last_ack;
+ if (time_before(timeout, link_sta->rx_stats.last_rx))
+ timeout = link_sta->rx_stats.last_rx;
+
+ timeout += IEEE80211_CONNECTION_IDLE_TIME;
+
+ /*
+ * latest_timeout holds the timeout of the link
+ * that will expire last among all links in an
+ * non-AP MLD STA. This ensures that the connection
+ * monitor timer is only reset if at least one link
+ * is still active, and it is scheduled to fire at
+ * the latest possible timeout.
+ */
+ if (time_is_after_jiffies(timeout) &&
+ time_after(timeout, latest_timeout))
+ latest_timeout = timeout;
+ }
+
+out:
+ rcu_read_unlock();
+
+ return latest_timeout;
+}
+
static void ieee80211_sta_conn_mon_timer(struct timer_list *t)
{
struct ieee80211_sub_if_data *sdata =
from_timer(sdata, t, u.mgd.conn_mon_timer);
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
- struct sta_info *sta;
- unsigned long timeout;
+ unsigned long latest_timeout;
- if (WARN_ON(ieee80211_vif_is_mld(&sdata->vif)))
+ if (ieee80211_is_csa_in_progress(sdata))
return;
- if (sdata->vif.bss_conf.csa_active &&
- !sdata->deflink.u.mgd.csa.waiting_bcn)
- return;
-
- sta = sta_info_get(sdata, sdata->vif.cfg.ap_addr);
- if (!sta)
- return;
-
- timeout = sta->deflink.status_stats.last_ack;
- if (time_before(sta->deflink.status_stats.last_ack, sta->deflink.rx_stats.last_rx))
- timeout = sta->deflink.rx_stats.last_rx;
- timeout += IEEE80211_CONNECTION_IDLE_TIME;
+ latest_timeout = ieee80211_latest_active_link_conn_timeout(sdata);
- /* If timeout is after now, then update timer to fire at
- * the later date, but do not actually probe at this time.
- */
- if (time_is_after_jiffies(timeout)) {
- mod_timer(&ifmgd->conn_mon_timer, round_jiffies_up(timeout));
+ /*
+ * If latest timeout is after now, then update timer to fire at
+ * the later date, but do not actually probe at this time.
+ */
+ if (latest_timeout) {
+ mod_timer(&ifmgd->conn_mon_timer,
+ round_jiffies_up(latest_timeout));
return;
}
@@ -0,0 +1,25 @@
From: Lorenzo Bianconi <lorenzo@kernel.org>
Date: Tue, 26 Aug 2025 13:54:31 +0200
Subject: [PATCH] wifi: mac80211: Make CONNECTION_MONITOR optional for MLO sta
Since commit '1bc892d76a6f ("wifi: mac80211: extend connection
monitoring for MLO")' mac80211 supports connection monitor for MLO
client interfaces. Remove the CONNECTION_MONITOR requirement in
ieee80211_register_hw routine.
Fixes: 1bc892d76a6f ("wifi: mac80211: extend connection monitoring for MLO")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1174,9 +1174,6 @@ int ieee80211_register_hw(struct ieee802
if (WARN_ON(!ieee80211_hw_check(hw, MFP_CAPABLE)))
return -EINVAL;
- if (WARN_ON(!ieee80211_hw_check(hw, CONNECTION_MONITOR)))
- return -EINVAL;
-
if (WARN_ON(ieee80211_hw_check(hw, NEED_DTIM_BEFORE_ASSOC)))
return -EINVAL;
+3 -3
View File
@@ -8,9 +8,9 @@ PKG_LICENSE_FILES:=
PKG_SOURCE_URL:=https://github.com/openwrt/mt76
PKG_SOURCE_PROTO:=git
PKG_SOURCE_DATE:=2025-08-13
PKG_SOURCE_VERSION:=903a7e0ace79dc9802b381fa05ecd2028122dd1b
PKG_MIRROR_HASH:=fcff7a90c8745091b8113e7833dc1f25e2767ff76da1f7adad27bde225c834df
PKG_SOURCE_DATE:=2025-08-27
PKG_SOURCE_VERSION:=de1df8b888bd1c99ee191f451af47b4fa9658e8c
PKG_MIRROR_HASH:=4ead68e97fc6472a682dae2f96f9dbb377f23c316511f625b85af15de46e9397
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_USE_NINJA:=0
@@ -33,7 +33,7 @@
{
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink);
@@ -1714,13 +1713,12 @@ out:
@@ -1687,13 +1686,12 @@ out:
rcu_read_unlock();
}
@@ -51,7 +51,7 @@
mt7996_link_rate_ctrl_update(&changed, sta);
ieee80211_queue_work(hw, &dev->rc_work);
@@ -2213,7 +2211,7 @@ const struct ieee80211_ops mt7996_ops =
@@ -2186,7 +2184,7 @@ const struct ieee80211_ops mt7996_ops =
.link_info_changed = mt7996_link_info_changed,
.sta_state = mt7996_sta_state,
.sta_pre_rcu_remove = mt76_sta_pre_rcu_remove,
@@ -62,7 +62,7 @@
.set_rts_threshold = mt7996_set_rts_threshold,
--- a/mac80211.c
+++ b/mac80211.c
@@ -1704,7 +1704,7 @@ s8 mt76_get_power_bound(struct mt76_phy
@@ -1745,7 +1745,7 @@ s8 mt76_get_power_bound(struct mt76_phy
EXPORT_SYMBOL_GPL(mt76_get_power_bound);
int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@ -73,7 +73,7 @@
int n_chains, delta;
--- a/mt76.h
+++ b/mt76.h
@@ -1520,7 +1520,7 @@ int mt76_get_min_avg_rssi(struct mt76_de
@@ -1521,7 +1521,7 @@ int mt76_get_min_avg_rssi(struct mt76_de
s8 mt76_get_power_bound(struct mt76_phy *phy, s8 txpower);
int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+3 -3
View File
@@ -11,9 +11,9 @@ PKG_NAME:=udebug
CMAKE_INSTALL:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/udebug.git
PKG_MIRROR_HASH:=578f795ef6ed0400efae8754891539e5b2922d8b164425e535b96da1b0a089c5
PKG_SOURCE_DATE:=2025-07-23
PKG_SOURCE_VERSION:=6ed8536142bbd4360b55a423723456a6a862c99b
PKG_MIRROR_HASH:=5e7b713aa1bff3b6480d4bd94d607b9cafed787b3d1cb27513883c83e56b0273
PKG_SOURCE_DATE:=2025-08-24
PKG_SOURCE_VERSION:=edeb4d6dc690acb476a47e6b11633b5632b08437
PKG_ABI_VERSION:=$(call abi_version_str,$(PKG_SOURCE_DATE))
PKG_LICENSE:=GPL-2.0
@@ -563,6 +563,7 @@ mac80211_hostapd_setup_bss() {
$hostapd_cfg
bssid=$macaddr
${default_macaddr:+#default_macaddr}
${random_macaddr:+#random_macaddr}
${dtim_period:+dtim_period=$dtim_period}
${max_listen_int:+max_listen_interval=$max_listen_int}
EOF
@@ -691,12 +692,14 @@ mac80211_prepare_vif() {
json_add_string _ifname "$ifname"
default_macaddr=
random_macaddr=
if [ -z "$macaddr" ]; then
macaddr="$(mac80211_generate_mac $phy)"
macidx="$(($macidx + 1))"
default_macaddr=1
elif [ "$macaddr" = 'random' ]; then
macaddr="$(macaddr_random)"
random_macaddr=1
fi
json_add_string _macaddr "$macaddr"
json_add_string _default_macaddr "$default_macaddr"
@@ -485,7 +485,9 @@ function iface_reload_config(name, phydev, config, old_config)
// try to preserve MAC address of this BSS by reassigning another
// BSS if necessary
if (cur_config.default_macaddr &&
if ((cur_config.default_macaddr || cur_config.random_macaddr) &&
cur_config.random_macaddr == prev_config.random_macaddr &&
cur_config.default_macaddr == prev_config.default_macaddr &&
!macaddr_list[prev_config.bssid]) {
macaddr_list[prev_config.bssid] = i;
cur_config.bssid = prev_config.bssid;
@@ -761,6 +763,8 @@ function iface_load_config(phy, radio, filename)
while ((line = rtrim(f.read("line"), "\n")) != null) {
if (line == "#default_macaddr")
bss.default_macaddr = true;
if (line == "#random_macaddr")
bss.random_macaddr = true;
let val = split(line, "=", 2);
if (!val[0])
@@ -579,7 +579,7 @@ SVN-Revision: 35130
goto next_ht;
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -273,7 +273,7 @@ INDIRECT_CALLABLE_SCOPE struct sk_buff *
@@ -275,7 +275,7 @@ INDIRECT_CALLABLE_SCOPE struct sk_buff *
continue;
iph2 = (struct ipv6hdr *)(p->data + off);
@@ -22,7 +22,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
struct vchiq_drvdata {
const unsigned int cache_line_size;
@@ -1825,6 +1826,7 @@ static int vchiq_probe(struct platform_d
@@ -1824,6 +1825,7 @@ static int vchiq_probe(struct platform_d
goto error_exit;
}
@@ -30,7 +30,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera");
bcm2835_audio = vchiq_register_child(pdev, "bcm2835_audio");
@@ -1840,6 +1842,7 @@ static void vchiq_remove(struct platform
@@ -1839,6 +1841,7 @@ static void vchiq_remove(struct platform
{
platform_device_unregister(bcm2835_audio);
platform_device_unregister(bcm2835_camera);
@@ -22,7 +22,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
static struct platform_device *vcsm_cma;
struct vchiq_drvdata {
@@ -1827,6 +1828,7 @@ static int vchiq_probe(struct platform_d
@@ -1826,6 +1827,7 @@ static int vchiq_probe(struct platform_d
}
vcsm_cma = vchiq_register_child(pdev, "vcsm-cma");
@@ -30,7 +30,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera");
bcm2835_audio = vchiq_register_child(pdev, "bcm2835_audio");
@@ -1842,6 +1844,7 @@ static void vchiq_remove(struct platform
@@ -1841,6 +1843,7 @@ static void vchiq_remove(struct platform
{
platform_device_unregister(bcm2835_audio);
platform_device_unregister(bcm2835_camera);
@@ -18,7 +18,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -1777,6 +1777,12 @@ vchiq_register_child(struct platform_dev
@@ -1776,6 +1776,12 @@ vchiq_register_child(struct platform_dev
child = NULL;
}
@@ -17,7 +17,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -1763,6 +1763,7 @@ vchiq_register_child(struct platform_dev
@@ -1762,6 +1762,7 @@ vchiq_register_child(struct platform_dev
{
struct platform_device_info pdevinfo;
struct platform_device *child;
@@ -25,7 +25,7 @@ Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org>
memset(&pdevinfo, 0, sizeof(pdevinfo));
@@ -1778,10 +1779,20 @@ vchiq_register_child(struct platform_dev
@@ -1777,10 +1778,20 @@ vchiq_register_child(struct platform_dev
}
/*
@@ -16,7 +16,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -1772,12 +1772,20 @@ vchiq_register_child(struct platform_dev
@@ -1771,12 +1771,20 @@ vchiq_register_child(struct platform_dev
pdevinfo.id = PLATFORM_DEVID_NONE;
pdevinfo.dma_mask = DMA_BIT_MASK(32);
@@ -21,7 +21,7 @@ Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
struct vchiq_drvdata {
const unsigned int cache_line_size;
@@ -1856,6 +1857,7 @@ static int vchiq_probe(struct platform_d
@@ -1855,6 +1856,7 @@ static int vchiq_probe(struct platform_d
bcm2835_codec = vchiq_register_child(pdev, "bcm2835-codec");
bcm2835_camera = vchiq_register_child(pdev, "bcm2835-camera");
bcm2835_audio = vchiq_register_child(pdev, "bcm2835_audio");
@@ -29,7 +29,7 @@ Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
return 0;
@@ -1867,6 +1869,7 @@ error_exit:
@@ -1866,6 +1868,7 @@ error_exit:
static void vchiq_remove(struct platform_device *pdev)
{
@@ -95,7 +95,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
#include <video/mipi_display.h>
@@ -1183,6 +1185,7 @@ static struct fbtft_platform_data *fbtft
@@ -1184,6 +1186,7 @@ static struct fbtft_platform_data *fbtft
* @display: Display properties
* @sdev: SPI device
* @pdev: Platform device
@@ -103,7 +103,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
*
* Allocates, initializes and registers a framebuffer
*
@@ -1192,12 +1195,15 @@ static struct fbtft_platform_data *fbtft
@@ -1193,12 +1196,15 @@ static struct fbtft_platform_data *fbtft
*/
int fbtft_probe_common(struct fbtft_display *display,
struct spi_device *sdev,
@@ -120,7 +120,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
int ret;
if (sdev)
@@ -1213,6 +1219,14 @@ int fbtft_probe_common(struct fbtft_disp
@@ -1214,6 +1220,14 @@ int fbtft_probe_common(struct fbtft_disp
pdata = fbtft_properties_read(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
@@ -22,7 +22,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
--- a/drivers/pps/pps.c
+++ b/drivers/pps/pps.c
@@ -249,12 +249,13 @@ static long pps_cdev_ioctl(struct file *
@@ -254,12 +254,13 @@ static long pps_cdev_ioctl(struct file *
static long pps_cdev_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -38,7 +38,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
struct pps_fdata_compat compat;
struct pps_fdata fdata;
int err;
@@ -289,6 +290,7 @@ static long pps_cdev_compat_ioctl(struct
@@ -296,6 +297,7 @@ static long pps_cdev_compat_ioctl(struct
return copy_to_user(uarg, &compat,
sizeof(struct pps_fdata_compat)) ? -EFAULT : 0;
}
@@ -223,7 +223,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
vchiq_log_info(vchiq_arm_log_level, "vchiq_init - done (slots %pK, phys %pad)",
vchiq_slot_zero, &slot_phys);
@@ -1755,6 +1823,7 @@ void vchiq_platform_conn_state_changed(s
@@ -1754,6 +1822,7 @@ void vchiq_platform_conn_state_changed(s
static const struct of_device_id vchiq_of_match[] = {
{ .compatible = "brcm,bcm2835-vchiq", .data = &bcm2835_drvdata },
{ .compatible = "brcm,bcm2836-vchiq", .data = &bcm2836_drvdata },
@@ -231,7 +231,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
{},
};
MODULE_DEVICE_TABLE(of, vchiq_of_match);
@@ -1787,22 +1856,8 @@ vchiq_register_child(struct platform_dev
@@ -1786,22 +1855,8 @@ vchiq_register_child(struct platform_dev
child->dev.of_node = np;
@@ -15,7 +15,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.com>
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -1856,8 +1856,18 @@ vchiq_register_child(struct platform_dev
@@ -1855,8 +1855,18 @@ vchiq_register_child(struct platform_dev
child->dev.of_node = np;
@@ -0,0 +1,121 @@
From: wangzijie <wangzijie1@honor.com>
To: <akpm@linux-foundation.org>, <brauner@kernel.org>,
<viro@zeniv.linux.org.uk>, <adobriyan@gmail.com>,
<rick.p.edgecombe@intel.com>, <ast@kernel.org>,
<k.shutemov@gmail.com>, <jirislaby@kernel.org>,
<linux-fsdevel@vger.kernel.org>
Cc: <polynomial-c@gmx.de>, <gregkh@linuxfoundation.org>,
<stable@vger.kernel.org>, <regressions@lists.linux.dev>,
wangzijie <wangzijie1@honor.com>
Subject: [PATCH v3] proc: fix missing pde_set_flags() for net proc files
Date: Thu, 21 Aug 2025 18:58:06 +0800 [thread overview]
Message-ID: <20250821105806.1453833-1-wangzijie1@honor.com> (raw)
To avoid potential UAF issues during module removal races, we use pde_set_flags()
to save proc_ops flags in PDE itself before proc_register(), and then use
pde_has_proc_*() helpers instead of directly dereferencing pde->proc_ops->*.
However, the pde_set_flags() call was missing when creating net related proc files.
This omission caused incorrect behavior which FMODE_LSEEK was being cleared
inappropriately in proc_reg_open() for net proc files. Lars reported it in this link[1].
Fix this by ensuring pde_set_flags() is called when register proc entry, and add
NULL check for proc_ops in pde_set_flags().
[1]: https://lore.kernel.org/all/20250815195616.64497967@chagall.paradoxon.rec/
Fixes: ff7ec8dc1b64 ("proc: use the same treatment to check proc_lseek as ones for proc_read_iter et.al")
Cc: stable@vger.kernel.org
Reported-by: Lars Wendler <polynomial-c@gmx.de>
Signed-off-by: wangzijie <wangzijie1@honor.com>
---
v3:
- followed by Christian's suggestion to stash pde->proc_ops in a local const variable
v2:
- followed by Jiri's suggestion to refractor code and reformat commit message
---
fs/proc/generic.c | 38 +++++++++++++++++++++-----------------
1 file changed, 21 insertions(+), 17 deletions(-)
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -362,6 +362,25 @@ static const struct inode_operations pro
.setattr = proc_notify_change,
};
+static void pde_set_flags(struct proc_dir_entry *pde)
+{
+ const struct proc_ops *proc_ops = pde->proc_ops;
+
+ if (!proc_ops)
+ return;
+
+ if (proc_ops->proc_flags & PROC_ENTRY_PERMANENT)
+ pde->flags |= PROC_ENTRY_PERMANENT;
+ if (proc_ops->proc_read_iter)
+ pde->flags |= PROC_ENTRY_proc_read_iter;
+#ifdef CONFIG_COMPAT
+ if (proc_ops->proc_compat_ioctl)
+ pde->flags |= PROC_ENTRY_proc_compat_ioctl;
+#endif
+ if (proc_ops->proc_lseek)
+ pde->flags |= PROC_ENTRY_proc_lseek;
+}
+
/* returns the registered entry, or frees dp and returns NULL on failure */
struct proc_dir_entry *proc_register(struct proc_dir_entry *dir,
struct proc_dir_entry *dp)
@@ -369,6 +388,8 @@ struct proc_dir_entry *proc_register(str
if (proc_alloc_inum(&dp->low_ino))
goto out_free_entry;
+ pde_set_flags(dp);
+
write_lock(&proc_subdir_lock);
dp->parent = dir;
if (pde_subdir_insert(dir, dp) == false) {
@@ -557,20 +578,6 @@ struct proc_dir_entry *proc_create_reg(c
return p;
}
-static void pde_set_flags(struct proc_dir_entry *pde)
-{
- if (pde->proc_ops->proc_flags & PROC_ENTRY_PERMANENT)
- pde->flags |= PROC_ENTRY_PERMANENT;
- if (pde->proc_ops->proc_read_iter)
- pde->flags |= PROC_ENTRY_proc_read_iter;
-#ifdef CONFIG_COMPAT
- if (pde->proc_ops->proc_compat_ioctl)
- pde->flags |= PROC_ENTRY_proc_compat_ioctl;
-#endif
- if (pde->proc_ops->proc_lseek)
- pde->flags |= PROC_ENTRY_proc_lseek;
-}
-
struct proc_dir_entry *proc_create_data(const char *name, umode_t mode,
struct proc_dir_entry *parent,
const struct proc_ops *proc_ops, void *data)
@@ -581,7 +588,6 @@ struct proc_dir_entry *proc_create_data(
if (!p)
return NULL;
p->proc_ops = proc_ops;
- pde_set_flags(p);
return proc_register(parent, p);
}
EXPORT_SYMBOL(proc_create_data);
@@ -632,7 +638,6 @@ struct proc_dir_entry *proc_create_seq_p
p->proc_ops = &proc_seq_ops;
p->seq_ops = ops;
p->state_size = state_size;
- pde_set_flags(p);
return proc_register(parent, p);
}
EXPORT_SYMBOL(proc_create_seq_private);
@@ -663,7 +668,6 @@ struct proc_dir_entry *proc_create_singl
return NULL;
p->proc_ops = &proc_single_ops;
p->single_show = show;
- pde_set_flags(p);
return proc_register(parent, p);
}
EXPORT_SYMBOL(proc_create_single_data);
@@ -42,7 +42,7 @@ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
* @adap: the adapter
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -1744,7 +1744,7 @@ static void rtw89_core_rx_to_mac80211(st
@@ -1749,7 +1749,7 @@ static void rtw89_core_rx_to_mac80211(st
struct napi_struct *napi = &rtwdev->napi;
/* In low power mode, napi isn't scheduled. Receive it to netif. */
@@ -137,7 +137,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/property.h>
@@ -3483,3 +3484,5 @@ static int __init regmap_initcall(void)
@@ -3485,3 +3486,5 @@ static int __init regmap_initcall(void)
return 0;
}
postcore_initcall(regmap_initcall);
@@ -60,7 +60,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
*/
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3098,6 +3098,10 @@ static inline int pskb_trim(struct sk_bu
@@ -3121,6 +3121,10 @@ static inline int pskb_trim(struct sk_bu
return (len < skb->len) ? __pskb_trim(skb, len) : 0;
}
@@ -71,7 +71,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/**
* pskb_trim_unique - remove end from a paged unique (not cloned) buffer
* @skb: buffer to alter
@@ -3263,16 +3267,6 @@ static inline struct sk_buff *dev_alloc_
@@ -3286,16 +3290,6 @@ static inline struct sk_buff *dev_alloc_
}
@@ -73,7 +73,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+MODULE_LICENSE("GPL");
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4486,6 +4486,7 @@ int wake_up_state(struct task_struct *p,
@@ -4485,6 +4485,7 @@ int wake_up_state(struct task_struct *p,
{
return try_to_wake_up(p, state, 0);
}
@@ -9,7 +9,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3065,7 +3065,7 @@ static inline int pskb_network_may_pull(
@@ -3088,7 +3088,7 @@ static inline int pskb_network_may_pull(
* NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8)
*/
#ifndef NET_SKB_PAD
@@ -185,7 +185,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
cfg->fc_flags |= RTF_REJECT;
if (rtm->rtm_type == RTN_LOCAL)
@@ -6341,6 +6372,8 @@ static int ip6_route_dev_notify(struct n
@@ -6349,6 +6380,8 @@ static int ip6_route_dev_notify(struct n
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
net->ipv6.ip6_prohibit_entry->dst.dev = dev;
net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
@@ -194,7 +194,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
#endif
@@ -6352,6 +6385,7 @@ static int ip6_route_dev_notify(struct n
@@ -6360,6 +6393,7 @@ static int ip6_route_dev_notify(struct n
in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
@@ -202,7 +202,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
#endif
}
@@ -6552,6 +6586,8 @@ static int __net_init ip6_route_net_init
@@ -6560,6 +6594,8 @@ static int __net_init ip6_route_net_init
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
net->ipv6.fib6_has_custom_rules = false;
@@ -211,7 +211,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
sizeof(*net->ipv6.ip6_prohibit_entry),
GFP_KERNEL);
@@ -6562,11 +6598,21 @@ static int __net_init ip6_route_net_init
@@ -6570,11 +6606,21 @@ static int __net_init ip6_route_net_init
ip6_template_metrics, true);
INIT_LIST_HEAD(&net->ipv6.ip6_prohibit_entry->dst.rt_uncached);
@@ -234,7 +234,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
ip6_template_metrics, true);
@@ -6593,6 +6639,8 @@ out:
@@ -6601,6 +6647,8 @@ out:
return ret;
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
@@ -243,7 +243,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
out_ip6_prohibit_entry:
kfree(net->ipv6.ip6_prohibit_entry);
out_ip6_null_entry:
@@ -6612,6 +6660,7 @@ static void __net_exit ip6_route_net_exi
@@ -6620,6 +6668,7 @@ static void __net_exit ip6_route_net_exi
kfree(net->ipv6.ip6_null_entry);
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
kfree(net->ipv6.ip6_prohibit_entry);
@@ -251,7 +251,7 @@ Signed-off-by: Jonas Gorski <jogo@openwrt.org>
kfree(net->ipv6.ip6_blk_hole_entry);
#endif
dst_entries_destroy(&net->ipv6.ip6_dst_ops);
@@ -6695,6 +6744,9 @@ void __init ip6_route_init_special_entri
@@ -6703,6 +6752,9 @@ void __init ip6_route_init_special_entri
init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
@@ -18,7 +18,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -8469,7 +8469,7 @@ static int nft_register_flowtable_net_ho
@@ -8449,7 +8449,7 @@ static int nft_register_flowtable_net_ho
err = flowtable->data.type->setup(&flowtable->data,
hook->ops.dev,
FLOW_BLOCK_BIND);
@@ -93,7 +93,7 @@ Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+#endif
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -4683,6 +4683,9 @@ enum skb_ext_id {
@@ -4706,6 +4706,9 @@ enum skb_ext_id {
#if IS_ENABLED(CONFIG_MCTP_FLOWS)
SKB_EXT_MCTP,
#endif