6.12.110-rc1 review
Subsystems (7)
Greg Kroah-Hartman
maintainerPATCH 1159/1376 hwmon: (coretemp) Fix core_data leak on CPUs without PTS
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Szymon Wilczek <[email protected]>
[ Upstream commit 0cd8450c257faa0cece0e0c43d3b55d1a389acc7 ]
pdata->core_data is allocated in init_temp_data() when the first core temp_data of a package is created, but it is only released from destroy_temp_data(), and only in the branch that handles the package temp_data.
Package temp_data is created solely when the CPU supports X86_FEATURE_PTS. On a CPU without it, coretemp_cpu_online() never calls coretemp_add_core() with pkg_flag set, so pdata->pkg_data stays NULL. coretemp_cpu_offline() then skips the removal of the package interface, destroy_temp_data() is never called for package data, and the array is still allocated when coretemp_device_remove() frees the platform data that pointed at it.
Release the array in coretemp_device_remove(). destroy_temp_data() sets pdata->core_data to NULL when it frees it, so the added kfree() is a no-op on CPUs that do have PTS.
Tested on an Intel Core i5-1135G7. The driver was instrumented to log every allocation and release of pdata->core_data, and the PTS check in coretemp_cpu_online() was patched out to emulate a CPU without package thermal support. Without this change the array was allocated and never released, and coretemp_device_remove() still saw a non-NULL pointer. With it the array is released and the pointer accounting balances. On an unmodified build the release still happens via the package temp_data and the added kfree() sees NULL, with no slab warnings over repeated module load and unload cycles.
--- drivers/hwmon/coretemp.c | 1 + 1 file changed, 1 insertion(+)
drivers/hwmon/coretemp.c +1 -0
@@ -656,6 +656,7 @@ static void coretemp_device_remove(int zoneid)struct platform_data *pdata =platform_get_drvdata (pdev);ida_destroy (&pdata->ida); +kfree (pdata->core_data);kfree (pdata);platform_device_unregister (pdev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1160/1376 hwmon: (emc1403) Rely on subsystem locking
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit 61e9b50ffa2390a2927051d335b2ba04b8f791ce ]
Attribute access is now serialized in the hardware monitoring core, so locking in the driver code is no longer necessary. Drop it.
Stable-dep-of: 75f2c0b36907 ("hwmon: (emc1403) Drop hysteresis for low limit temperature")
--- drivers/hwmon/emc1403.c | 46 +++++++++-------------------------------- 1 file changed, 10 insertions(+), 36 deletions(-)
drivers/hwmon/emc1403.c +10 -36
@@ -17,7 +17,6 @@#include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/sysfs.h> -#include <linux/mutex.h> #include <linux/regmap.h> #include <linux/util_macros.h>
@@ -30,7 +29,6 @@ enum emc1403_chip { emc1402, emc1403, emc1404, emc1428 };struct thermal_data {enum emc1403_chip chip;struct regmap *regmap; -struct mutex mutex; };static ssize_t power_state_show (struct device *dev,struct device_attribute *attr,char *buf)
@@ -268,8 +266,8 @@ static s8 emc1403_temp_regs_low[][4] = { }, }; -static int __emc1403_get_temp (struct thermal_data *data,int channel, -enum emc1403_reg_map map,long *val) +static int emc1403_get_temp (struct thermal_data *data,int channel, +enum emc1403_reg_map map,long *val) {unsigned int regvalh;unsigned int regvall =0 ;
@@ -295,38 +293,23 @@ static int __emc1403_get_temp(struct thermal_data *data, int channel,return 0 ; } -static int emc1403_get_temp (struct thermal_data *data,int channel, -enum emc1403_reg_map map,long *val) -{ -int ret; - -mutex_lock (&data->mutex); - ret =__emc1403_get_temp (data, channel, map, val); -mutex_unlock (&data->mutex); - -return ret; -} -static int emc1403_get_hyst (struct thermal_data *data,int channel,enum emc1403_reg_map map,long *val) {int hyst, ret;long limit; -mutex_lock (&data->mutex); - ret =__emc1403_get_temp (data, channel, map, &limit); + ret =emc1403_get_temp (data, channel, map, &limit);if (ret <0 ) - goto unlock; +return ret; ret =regmap_read (data->regmap,0x21 , &hyst);if (ret <0 ) - goto unlock; +return ret;if (map == temp_min) *val = limit + hyst *1000 ;else *val = limit - hyst *1000 ; -unlock: -mutex_unlock (&data->mutex); -return ret; +return 0 ; }static int emc1403_temp_read (struct thermal_data *data,u32 attr,int channel,long *val)
@@ -451,20 +434,16 @@ static int emc1403_set_hyst(struct thermal_data *data, long val)else val =clamp_val (val,0 ,255000 ); -mutex_lock (&data->mutex); - ret =__emc1403_get_temp (data,0 , temp_crit, &limit); + ret =emc1403_get_temp (data,0 , temp_crit, &limit);if (ret <0 ) - goto unlock; +return ret; hyst = limit - val;if (data->chip == emc1428) hyst =clamp_val (DIV_ROUND_CLOSEST (hyst,1000 ),0 ,127 );else hyst =clamp_val (DIV_ROUND_CLOSEST (hyst,1000 ),0 ,255 ); - ret =regmap_write (data->regmap,0x21 , hyst); -unlock: -mutex_unlock (&data->mutex); -return ret; +return regmap_write (data->regmap,0x21 , hyst); } static int emc1403_set_temp(struct thermal_data *data, int channel,
@@ -478,7 +457,6 @@ static int emc1403_set_temp(struct thermal_data *data, int channel, regh = emc1403_temp_regs[channel][map]; regl = emc1403_temp_regs_low[channel][map]; -mutex_lock (&data->mutex);if (regl >=0 ) {if (data->chip == emc1428) val =clamp_val (val,-128000 ,127875 );
@@ -487,7 +465,7 @@ static int emc1403_set_temp(struct thermal_data *data, int channel, regval =DIV_ROUND_CLOSEST (val,125 ); ret =regmap_write (data->regmap, regh, (regval >>3 ) &0xff );if (ret <0 ) - goto unlock; +return ret; ret =regmap_write (data->regmap, regl, (regval &0x07 ) <<5 ); }else {if (data->chip == emc1428)
@@ -497,8 +475,6 @@ static int emc1403_set_temp(struct thermal_data *data, int channel, regval =DIV_ROUND_CLOSEST (val,1000 ); ret =regmap_write (data->regmap, regh, regval); } -unlock: -mutex_unlock (&data->mutex);return ret; }
@@ -695,8 +671,6 @@ static int emc1403_probe(struct i2c_client *client)if (IS_ERR (data->regmap))return PTR_ERR (data->regmap); -mutex_init (&data->mutex); - hwmon_dev = devm_hwmon_device_register_with_info(&client->dev, client->name, data, &emc1403_chip_info,
Signature · 1 line
2.53.0
Re: [PATCH 6.12 1160/1376] hwmon: (emc1403) Rely on subsystem locking
Quoted 6 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
Quoted 8 lines
[ Upstream commit
61e9b50ffa2390a2927051d335b2ba04b8f791ce]Attribute access is now serialized in the hardware monitoring core, so locking in the driver code is no longer necessary. Drop it.
Signed-off-by Guenter Roeck <[email protected]>Stable-dep-of:
75f2c0b36907("hwmon: (emc1403) Drop hysteresis for low limit temperature")Signed-off-by Sasha Levin <[email protected]>
Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
Upstream hwmon core after 3ad2a7b9b15d:
struct mutex lock;
guard(mutex)(&hwdev->lock);
ret = hattr->ops->read(dev, hattr->type, hattr->attr,
hattr->index, &val);Downstream 6.12.y hwmon core:
ret = hattr->ops->read(dev, hattr->type, hattr->attr,
hattr->index, &val);The downstream core invokes the complete callback without its own lock.
The patch removes the EMC1403 mutex on the premise that hwmon core serializes callbacks. This 6.12 hwmon core has no such mutex and invokes read and write operations unlocked. Regmap locking covers only each individual transfer, not the driver's multi-read or multi-write transactions, so concurrent callbacks can interleave threshold and temperature operations.
I think 6.12.y misses 3ad2a7b9b15d5072139a20be84adb36776eb6c9b, "hwmon:
Serialize accesses in hwmon core".
Quoted 137 lines
--- drivers/hwmon/emc1403.c | 46 +++++++++-------------------------------- 1 file changed, 10 insertions(+), 36 deletions(-)drivers/hwmon/emc1403.c +10
-36@@ -17,7 +17,6 @@#include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/sysfs.h> -#include <linux/mutex.h> #include <linux/regmap.h> #include <linux/util_macros.h> @@ -30,7 +29,6 @@ enum emc1403_chip { emc1402, emc1403, emc1404, emc1428 };struct thermal_data {enum emc1403_chip chip;struct regmap *regmap; -struct mutex mutex; };static ssize_t power_state_show (struct device *dev,struct device_attribute *attr,char *buf)@@ -268,8 +266,8 @@ static s8 emc1403_temp_regs_low[][4] = { }, }; -static int __emc1403_get_temp (struct thermal_data *data,int channel, -enum emc1403_reg_map map,long *val) +static int emc1403_get_temp (struct thermal_data *data,int channel, +enum emc1403_reg_map map,long *val) {unsigned int regvalh;unsigned int regvall =0 ;@@ -295,38 +293,23 @@ static int __emc1403_get_temp(struct thermal_data *data, int channel,return 0 ; } -static int emc1403_get_temp (struct thermal_data *data,int channel, -enum emc1403_reg_map map,long *val) -{ -int ret; - -mutex_lock (&data->mutex); - ret =__emc1403_get_temp (data, channel, map, val); -mutex_unlock (&data->mutex); - -return ret; -} -static int emc1403_get_hyst (struct thermal_data *data,int channel,enum emc1403_reg_map map,long *val) {int hyst, ret;long limit; -mutex_lock (&data->mutex); - ret =__emc1403_get_temp (data, channel, map, &limit); + ret =emc1403_get_temp (data, channel, map, &limit);if (ret <0 ) - goto unlock; +return ret; ret =regmap_read (data->regmap,0x21 , &hyst);if (ret <0 ) - goto unlock; +return ret;if (map == temp_min) *val = limit + hyst *1000 ;else *val = limit - hyst *1000 ; -unlock: -mutex_unlock (&data->mutex); -return ret; +return 0 ; }static int emc1403_temp_read (struct thermal_data *data,u32 attr,int channel,long *val)@@ -451,20 +434,16 @@ static int emc1403_set_hyst(struct thermal_data *data, long val)else val =clamp_val (val,0 ,255000 ); -mutex_lock (&data->mutex); - ret =__emc1403_get_temp (data,0 , temp_crit, &limit); + ret =emc1403_get_temp (data,0 , temp_crit, &limit);if (ret <0 ) - goto unlock; +return ret; hyst = limit - val;if (data->chip == emc1428) hyst =clamp_val (DIV_ROUND_CLOSEST (hyst,1000 ),0 ,127 );else hyst =clamp_val (DIV_ROUND_CLOSEST (hyst,1000 ),0 ,255 ); - ret =regmap_write (data->regmap,0x21 , hyst); -unlock: -mutex_unlock (&data->mutex); -return ret; +return regmap_write (data->regmap,0x21 , hyst); } static int emc1403_set_temp(struct thermal_data *data, int channel,@@ -478,7 +457,6 @@ static int emc1403_set_temp(struct thermal_data *data, int channel, regh = emc1403_temp_regs[channel][map]; regl = emc1403_temp_regs_low[channel][map]; -mutex_lock (&data->mutex);if (regl >=0 ) {if (data->chip == emc1428) val =clamp_val (val,-128000 ,127875 );@@ -487,7 +465,7 @@ static int emc1403_set_temp(struct thermal_data *data, int channel, regval =DIV_ROUND_CLOSEST (val,125 ); ret =regmap_write (data->regmap, regh, (regval >>3 ) &0xff );if (ret <0 ) - goto unlock; +return ret; ret =regmap_write (data->regmap, regl, (regval &0x07 ) <<5 ); }else {if (data->chip == emc1428)@@ -497,8 +475,6 @@ static int emc1403_set_temp(struct thermal_data *data, int channel, regval =DIV_ROUND_CLOSEST (val,1000 ); ret =regmap_write (data->regmap, regh, regval); } -unlock: -mutex_unlock (&data->mutex);return ret; }@@ -695,8 +671,6 @@ static int emc1403_probe(struct i2c_client *client)if (IS_ERR (data->regmap))return PTR_ERR (data->regmap); -mutex_init (&data->mutex); - hwmon_dev = devm_hwmon_device_register_with_info(&client->dev, client->name, data, &emc1403_chip_info,
Re: [PATCH 6.12 1160/1376] hwmon: (emc1403) Rely on subsystem locking
Quoted 44 lines · Harshit Mogalapalli
Quoted 6 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
Quoted 8 lines
[ Upstream commit
61e9b50ffa2390a2927051d335b2ba04b8f791ce]Attribute access is now serialized in the hardware monitoring core, so locking in the driver code is no longer necessary. Drop it.
Signed-off-by Guenter Roeck <[email protected]>Stable-dep-of:
75f2c0b36907("hwmon: (emc1403) Drop hysteresis for low limit temperature")Signed-off-by Sasha Levin <[email protected]>Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
Upstream hwmon core after
3ad2a7b9b15d:struct mutex lock; guard(mutex)(&hwdev->lock);
ret =hattr->ops->read(dev, hattr->type, hattr->attr, hattr->index, &val);Downstream 6.12.y hwmon core:
ret =
hattr->ops->read(dev, hattr->type, hattr->attr, hattr->index, &val);The downstream core invokes the complete callback without its own lock.
The patch removes the EMC1403 mutex on the premise that hwmon core serializes callbacks. This 6.12 hwmon core has no such mutex and invokes read and write operations unlocked. Regmap locking covers only each individual transfer, not the driver's multi-read or multi-write transactions, so concurrent callbacks can interleave threshold and temperature operations.
Quoted 3 lines
I think 6.12.y misses
3ad2a7b9b15d5072139a20be84adb36776eb6c9b, "hwmon:
Serialize accesses in hwmon core".
Guess I didn't pay close enough attention. Neither this patch nor similar patches nor 3ad2a7b9b15d507 were bug fixes and should not be / have been backported, not even as prerequisites of other patches.
I think we are at a point where the automatic backports are way too aggressive. Greg, please stop autoselecting hwmon and watchdog patches for backports, and only pick patches with explicit Cc: stable going forward.
Thanks,
Guenter
Greg Kroah-Hartman
maintainerRe: [PATCH 6.12 1160/1376] hwmon: (emc1403) Rely on subsystem locking
Quoted 48 lines · Guenter Roeck
Quoted 44 lines · Harshit Mogalapalli
Quoted 6 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
Quoted 8 lines
[ Upstream commit
61e9b50ffa2390a2927051d335b2ba04b8f791ce]Attribute access is now serialized in the hardware monitoring core, so locking in the driver code is no longer necessary. Drop it.
Signed-off-by Guenter Roeck <[email protected]>Stable-dep-of:
75f2c0b36907("hwmon: (emc1403) Drop hysteresis for low limit temperature")Signed-off-by Sasha Levin <[email protected]>Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
Upstream hwmon core after
3ad2a7b9b15d:struct mutex lock; guard(mutex)(&hwdev->lock);
ret =hattr->ops->read(dev, hattr->type, hattr->attr, hattr->index, &val);Downstream 6.12.y hwmon core:
ret =
hattr->ops->read(dev, hattr->type, hattr->attr, hattr->index, &val);The downstream core invokes the complete callback without its own lock.
The patch removes the EMC1403 mutex on the premise that hwmon core serializes callbacks. This 6.12 hwmon core has no such mutex and invokes read and write operations unlocked. Regmap locking covers only each individual transfer, not the driver's multi-read or multi-write transactions, so concurrent callbacks can interleave threshold and temperature operations.
Quoted 3 lines
I think 6.12.y misses
3ad2a7b9b15d5072139a20be84adb36776eb6c9b, "hwmon:
Serialize accesses in hwmon core".
Quoted 7 lines
Guess I didn't pay close enough attention. Neither this patch nor similar patches nor
3ad2a7b9b15d507were bug fixes and should not be / have been backported, not even as prerequisites of other patches.I think we are at a point where the automatic backports are way too aggressive. Greg, please stop autoselecting hwmon and watchdog patches for backports, and only pick patches with explicit Cc: stable going forward.
Not a problem, here's the patch I've applied to our stable-queue.git:
ignore_list +4 -0
@@ -46,3 +46,7 @@ drivers/input/* # nolibc tools/include/nolibc/* tools/testing/selftests/nolibc/* + +# hwmon and watchdog +drivers/hwmon/* +drivers/watchdog/*
Sasha Levin
maintainerRe: [PATCH 6.12 1160/1376] hwmon: (emc1403) Rely on subsystem locking
In reply to Guenter RoeckQuoted 3 lines
I think we are at a point where the automatic backports are way too aggressive. Greg, please stop autoselecting hwmon and watchdog patches for backports, and only pick patches with explicit Cc: stable going forward.
Ack. I'll add it to my lists.
Signature · 2 lines
Thanks, Sasha
Sasha Levin
maintainerRe: [PATCH 6.12 1160/1376] hwmon: (emc1403) Rely on subsystem locking
In reply to Guenter RoeckQuoted 3 lines
Guess I didn't pay close enough attention. Neither this patch nor similar patches nor
3ad2a7b9b15d507were bug fixes and should not be / have been backported, not even as prerequisites of other patches.
Both are reverted now, on 6.12 and on 6.6: the locking change and the hysteresis fix that was stacked on top of it. 6.6 carried the identical pair, so it got the same treatment.
Reverting the hysteresis change also re-adds the temp*_min_hyst attributes on those two trees.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 1161/1376 hwmon: (emc1403) Drop hysteresis for low limit temperature
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marius Cristea <[email protected]>
[ Upstream commit 75f2c0b3690702c90863c2e138cb5520670845ea ]
Remove the hysteresis for low temperature limit, in hardware the hysteresis is applied only to the maxim limit and the critical limit temperature.
--- Documentation/hwmon/emc1403.rst | 8 ++++---- drivers/hwmon/emc1403.c | 27 +++++++++++---------------- 2 files changed, 15 insertions(+), 20 deletions(-)
Documentation/hwmon/emc1403.rst +4 -4
@@ -71,10 +71,10 @@ and EMC14x8 support eight sensors (one internal, seven external). The chips implement three limits for each sensor: low (tempX_min), high (tempX_max) and critical (tempX_crit.) The chips also implement an -hysteresis mechanism which applies to all limits. The relative difference -is stored in a single register on the chip, which means that the relative -difference between the limit and its hysteresis is always the same for -all three limits. +hysteresis mechanism which applies to high and critical limits. The relative +difference is stored in a single register on the chip, which means that the +relative difference between the limit and its hysteresis is always the same +for high and critical limits. This implementation detail implies the following:
drivers/hwmon/emc1403.c +11 -16
@@ -305,10 +305,9 @@ static int emc1403_get_hyst(struct thermal_data *data, int channel, ret =regmap_read (data->regmap,0x21 , &hyst);if (ret <0 )return ret; -if (map == temp_min) - *val = limit + hyst *1000 ; -else - *val = limit - hyst *1000 ; + + *val = limit - hyst *1000 ; +return 0 ; }
@@ -324,9 +323,6 @@ static int emc1403_temp_read(struct thermal_data *data, u32 attr, int channel, lcase hwmon_temp_input: ret =emc1403_get_temp (data, channel, ema1403_temp_map[attr], val);break ; -case hwmon_temp_min_hyst: - ret =emc1403_get_hyst (data, channel, temp_min, val); -break ;case hwmon_temp_max_hyst: ret =emc1403_get_hyst (data, channel, temp_max, val);break ;
@@ -548,7 +544,6 @@ static umode_t emc1403_temp_is_visible(const void *_data, u32 attr, int channel)case hwmon_temp_max_alarm:case hwmon_temp_crit_alarm:case hwmon_temp_fault: -case hwmon_temp_min_hyst:case hwmon_temp_max_hyst:return 0444 ;case hwmon_temp_min:
@@ -591,35 +586,35 @@ static const struct hwmon_channel_info * const emc1403_info[] = {HWMON_CHANNEL_INFO (chip,HWMON_C_UPDATE_INTERVAL ),HWMON_CHANNEL_INFO (temp,HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | -HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT |HWMON_T_MAX_HYST |HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM |HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM ,HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | -HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT |HWMON_T_MAX_HYST |HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM |HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM |HWMON_T_FAULT ,HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | -HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT |HWMON_T_MAX_HYST |HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM |HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM |HWMON_T_FAULT ,HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | -HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT |HWMON_T_MAX_HYST |HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM |HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM |HWMON_T_FAULT ,HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | -HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT |HWMON_T_MAX_HYST |HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM |HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM |HWMON_T_FAULT ,HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | -HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT |HWMON_T_MAX_HYST |HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM |HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM |HWMON_T_FAULT ,HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | -HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT |HWMON_T_MAX_HYST |HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM |HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM |HWMON_T_FAULT ,HWMON_T_INPUT |HWMON_T_MIN |HWMON_T_MAX | -HWMON_T_CRIT |HWMON_T_MIN_HYST |HWMON_T_MAX_HYST | +HWMON_T_CRIT |HWMON_T_MAX_HYST |HWMON_T_CRIT_HYST |HWMON_T_MIN_ALARM |HWMON_T_MAX_ALARM |HWMON_T_CRIT_ALARM |HWMON_T_FAULT ),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1162/1376 ksmbd: Do not skip lock checks for single-byte ranges
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit d40c24634fe077a0dc91fd11fccf44ce12b454d5 ]
check_lock_range() uses inclusive ranges. Its callers pass the end offset as start + length - 1, so start == end represents a valid single-byte range rather than an empty range.
The start == end shortcut therefore skips mandatory byte-range lock checks for one-byte reads, writes, copychunk operations and one-byte truncate ranges. A conflicting lock covering that byte is not checked and the operation is allowed to proceed.
Remove the shortcut. The truncate size == inode->i_size case is already handled by only calling check_lock_range() when the new size differs from the current file size.
--- fs/smb/server/vfs.c | 3 --- 1 file changed, 3 deletions(-)
fs/smb/server/vfs.c +0 -3
@@ -329,9 +329,6 @@ static int check_lock_range(struct file *filp, loff_t start, loff_t end,struct file_lock_context *ctx =locks_inode_context (file_inode (filp));int error =0 ; -if (start == end) -return 0 ; -if (!ctx ||list_empty_careful (&ctx->flc_posix))return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1163/1376 smb: server: fix leak of ksmbd_ipc_login_request_ext() returned buffer
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Enzo Matsumiya <[email protected]>
[ Upstream commit 1c3ebf832d010c08afe1359215d4121cb1ed2de5 ]
Free it unconditionally after ksmbd_alloc_user() calls.
kmemleak splat:
unreferenced object 0xffff888103b83540 (size 192):
comm "pool-0", pid 16970, jiffies 4377290937
hex dump (first 32 bytes):
00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace (crc 408ccc66):
__kvmalloc_node_noprof+0x730/0x920
handle_generic_event+0xec/0x1a0 [ksmbd]
genl_family_rcv_msg_doit+0xe0/0x130
genl_rcv_msg+0x181/0x290
netlink_rcv_skb+0x4f/0x100
genl_rcv+0x28/0x40
netlink_unicast+0x1e6/0x2c0
netlink_sendmsg+0x20a/0x450
____sys_sendmsg+0x2e8/0x310
___sys_sendmsg+0x78/0xc0
__sys_sendmsg+0x63/0xc0
do_syscall_64+0xa1/0x670
entry_SYSCALL_64_after_hwframe+0x76/0x7e--- fs/smb/server/auth.c | 1 + fs/smb/server/mgmt/user_config.c | 1 + 2 files changed, 2 insertions(+)
fs/smb/server/auth.c +1 -0
@@ -547,6 +547,7 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob, resp_ext =ksmbd_ipc_login_request_ext (resp->login_response.account); user =ksmbd_alloc_user (&resp->login_response, resp_ext); +kvfree (resp_ext);if (!user) {ksmbd_debug (AUTH ,"login failure\n" ); retval = -ENOMEM ;
fs/smb/server/mgmt/user_config.c +1 -0
@@ -26,6 +26,7 @@ struct ksmbd_user *ksmbd_login_user(const char *account) resp_ext =ksmbd_ipc_login_request_ext (account); user =ksmbd_alloc_user (resp, resp_ext); +kvfree (resp_ext); out:kvfree (resp);return user;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1164/1376 ksmbd: validate ipc response length before dereferencing its fields
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yunseong Kim <[email protected]>
[ Upstream commit e9b33376bd07bca4175f7bcc2d6034ef250f8181 ]
ipc_validate_msg() computes the expected message size by reading length fields out of the response buffer supplied by the userspace ksmbd daemon (payload_sz, session_key_len, ngroups, ...). Those fields are read before the buffer is verified to be large enough to contain the struct they belong to, so a short response makes the read land past the end of the allocation.
handle_response() sizes entry->response purely from the netlink attribute length (nla_len()) and only guards the leading handle read, so the daemon can install a response as small as the kmalloc-8 object seen below. When ipc_msg_send_request() then calls ipc_validate_msg() for a KSMBD_EVENT_RPC_REQUEST, the cast to struct ksmbd_rpc_command reads resp->payload_sz at offset 8 of an 8-byte allocation:
[ 3697.841381] ================================================================== [ 3697.844099] BUG: KASAN: slab-out-of-bounds in ipc_msg_send_request+0x763/0x800 [ 3697.846604] Read of size 4 at addr ffff888105f95910 by task kworker/4:3/20682 [ 3697.849061] [ 3697.849801] CPU: 4 UID: 0 PID: 20682 Comm: kworker/4:3 Not tainted 7.2.0-rc3-next-20260717-virtme #117 PREEMPT(lazy) [ 3697.850077] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014 [ 3697.850303] Workqueue: ksmbd-io handle_ksmbd_work [ 3697.850592] Call Trace: [ 3697.850794] <TASK> [ 3697.850952] __dump_stack+0x21/0x60 [ 3697.851239] dump_stack_lvl+0xc2/0x100 [ 3697.851528] print_address_description+0x77/0x200 [ 3697.851816] ? ipc_msg_send_request+0x763/0x800 [ 3697.852024] print_report+0x58/0x70 [ 3697.852316] kasan_report+0x117/0x150 [ 3697.852585] ? down_write+0x146/0x1f0 [ 3697.852809] ? ipc_msg_send_request+0x763/0x800 [ 3697.853082] ipc_msg_send_request+0x763/0x800 [ 3697.853385] ? __pfx_ipc_msg_send_request+0x10/0x10 [ 3697.853604] ? kasan_unpoison+0x48/0x70 [ 3697.853936] ? __pfx___up_read+0x10/0x10 [ 3697.854221] ksmbd_rpc_ioctl+0x380/0x520 [ 3697.854542] ? __pfx_ksmbd_rpc_ioctl+0x10/0x10 [ 3697.854757] ? kasan_unpoison+0x48/0x70 [ 3697.854962] ? copy_from_kernel_nofault+0x32c/0x4e0 [ 3697.855166] ? kasan_unpoison+0x48/0x70 [ 3697.855416] fsctl_pipe_transceive+0x139/0x7a0 [ 3697.855705] ? __pfx_copy_from_kernel_nofault+0x10/0x10 [ 3697.855937] ? __pfx_fsctl_pipe_transceive+0x10/0x10 [ 3697.856388] ? __sanitizer_cov_trace_switch+0x7b/0x140 [ 3697.856620] smb2_ioctl+0x1141/0x3420 [ 3697.856994] ? __pfx_smb2_ioctl+0x10/0x10 [ 3697.857182] ? get_smb2_cmd_val+0xe3/0x1c0 [ 3697.857655] handle_ksmbd_work+0x9ad/0x15e0 [ 3697.858034] ? __pfx_handle_ksmbd_work+0x10/0x10 [ 3697.858251] ? lock_release+0xf7/0x360 [ 3697.858466] ? process_scheduled_works+0x954/0x1600 [ 3697.858698] ? process_scheduled_works+0x954/0x1600 [ 3697.858905] process_scheduled_works+0xc22/0x1600 [ 3697.859368] ? __pfx_process_scheduled_works+0x10/0x10 [ 3697.859637] ? __pfx_assign_work+0x10/0x10 [ 3697.859896] ? lock_is_held_type+0x7b/0x110 [ 3697.860146] worker_thread+0x975/0xee0 [ 3697.860524] ? __pfx_do_raw_spin_lock+0x10/0x10 [ 3697.860830] ? __kthread_parkme+0x21e/0x260 [ 3697.861105] kthread+0x3a6/0x490 [ 3697.861423] ? __pfx_worker_thread+0x10/0x10 [ 3697.861643] ? __pfx_kthread+0x10/0x10 [ 3697.861878] ret_from_fork+0x55a/0xa20 [ 3697.862194] ? __pfx_ret_from_fork+0x10/0x10 [ 3697.862480] ? __pfx_kthread+0x10/0x10 [ 3697.862714] ret_from_fork_asm+0x1a/0x30 [ 3697.862965] </TASK> [ 3697.863039] [ 3697.938882] Allocated by task 20761: [ 3697.940257] kasan_save_track+0x3e/0x80 [ 3697.941782] __kasan_kmalloc+0x72/0x90 [ 3697.943228] __kvmalloc_node_noprof+0x3e9/0x6a0 [ 3697.944948] handle_generic_event+0x59b/0x750 [ 3697.946592] genl_family_rcv_msg_doit+0x3d6/0x560 [ 3697.946977] genl_rcv_msg+0x67c/0x900 [ 3697.947224] netlink_rcv_skb+0x286/0x580 [ 3697.947488] genl_rcv+0x2d/0x80 [ 3697.947706] netlink_unicast+0x937/0xb70 [ 3697.947993] netlink_sendmsg+0x977/0xc10 [ 3697.948268] __sock_sendmsg+0x264/0x2d0 [ 3697.948536] __sys_sendto+0x4de/0x690 [ 3697.948789] __x64_sys_sendto+0x173/0x380 [ 3697.949069] do_syscall_64+0x13d/0x420 [ 3697.949328] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 3697.949662] [ 3697.949779] The buggy address belongs to the object at ffff888105f95908 [ 3697.949779] which belongs to the cache kmalloc-8 of size 8 [ 3697.950550] The buggy address is located 0 bytes to the right of [ 3697.950550] allocated 8-byte region [ffff888105f95908, ffff888105f95910) [ 3697.951455] [ 3697.951574] The buggy address belongs to the physical page: [ 3697.951958] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0xffff888105f951b8 pfn:0x105f95 [ 3697.952571] flags: 0x100000000000200(workingset|node=0|zone=2) [ 3697.952973] page_type: f5(slab) [ 3697.953198] raw: 0100000000000200 ffff888100042640 ffffea0004063610 ffff888100040588 [ 3697.953707] raw: ffff888105f951b8 00000000001c000e 00000000f5000000 0000000000000000 [ 3697.954240] page dumped because: kasan: bad access detected [ 3697.954616] [ 3697.954734] Memory state around the buggy address: [ 3697.955063] ffff888105f95800: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fa [ 3697.955534] ffff888105f95880: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 3697.956006] >ffff888105f95900: fc 00 fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 3697.956477] ^ [ 3697.956728] ffff888105f95980: fc fc fc fa fc fc fc fc fc fc fc fc fc fc fc fc [ 3697.957202] ffff888105f95a00: fc fc fc fc fc fa fc fc fc fc fc fc fc fc fc fc [ 3697.957671] ==================================================================
The final "entry->msg_sz != msg_sz" comparison cannot help: the offending read has already happened by the time it runs. Every case in the switch shares this pattern.
Floor entry->msg_sz against the base struct of each event type before dereferencing any of its length fields. On failure ipc_msg_send_request() already frees the response and returns NULL, so callers stay safe.
The malformed message originates from the ksmbd.mountd daemon over genl netlink rather than a remote SMB client, so triggering it requires a buggy or compromised daemon; it is still an out-of-bounds read the validator is meant to prevent.
--- fs/smb/server/transport_ipc.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
fs/smb/server/transport_ipc.c +12 -0
@@ -498,6 +498,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) {struct ksmbd_rpc_command *resp = entry->response; +if (entry->msg_sz <sizeof (struct ksmbd_rpc_command )) +return -EINVAL ; +if (check_add_overflow (sizeof (struct ksmbd_rpc_command ), resp->payload_sz, &msg_sz))return -EINVAL ;
@@ -507,6 +510,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) {struct ksmbd_spnego_authen_response *resp = entry->response; +if (entry->msg_sz <sizeof (struct ksmbd_spnego_authen_response )) +return -EINVAL ; + msg_sz =sizeof (struct ksmbd_spnego_authen_response ) + resp->session_key_len + resp->spnego_blob_len;break ;
@@ -515,6 +521,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) {struct ksmbd_share_config_response *resp = entry->response; +if (entry->msg_sz <sizeof (struct ksmbd_share_config_response )) +return -EINVAL ; +if (resp->payload_sz) {if (resp->payload_sz < resp->veto_list_sz)return -EINVAL ;
@@ -529,6 +538,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) {struct ksmbd_login_response_ext *resp = entry->response; +if (entry->msg_sz <sizeof (struct ksmbd_login_response_ext )) +return -EINVAL ; +if (resp->ngroups) {if (resp->ngroups <0 || resp->ngroups >NGROUPS_MAX ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1165/1376 ksmbd: do not advertise unimplemented CA support
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit eebdd3f1157e35a50df5ff2d3d9a305901df3254 ]
ksmbd durable handles are currently in-memory state. There is no persistent open recovery, cluster ownership epoch, fencing, or failover implementation behind the continuous-availability share flag.
Do not advertise SMB2 persistent-handle or continuous-availability capabilities until those guarantees exist. A client requesting DH2Q then falls back to the existing durable V2 behavior rather than being promised a persistent handle that cannot survive a server failure.
Stable-dep-of: 06c7b1d731bc ("ksmbd: free preauth sessions on connection teardown")
--- fs/smb/server/smb2ops.c | 9 +++++---- fs/smb/server/smb2pdu.c | 11 +++++------ 2 files changed, 10 insertions(+), 10 deletions(-)
fs/smb/server/smb2ops.c +5 -4
@@ -262,8 +262,10 @@ void init_smb3_02_server(struct ksmbd_conn *conn)if (server_conf.flags &KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL ) conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_MULTI_CHANNEL ; -if (server_conf.flags &KSMBD_GLOBAL_FLAG_DURABLE_HANDLE ) - conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_PERSISTENT_HANDLES ; +/* +* Durable handles are in-memory only. Do not advertise persistent +* handles until CA recovery and fencing are implemented. +*/ }/**
@@ -286,8 +288,7 @@ int init_smb3_11_server(struct ksmbd_conn *conn)if (server_conf.flags &KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL ) conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_MULTI_CHANNEL ; -if (server_conf.flags &KSMBD_GLOBAL_FLAG_DURABLE_HANDLE ) - conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_PERSISTENT_HANDLES ; +/* See init_smb3_02_server(): persistent handles require CA recovery. */ INIT_LIST_HEAD (&conn->preauth_sess_table);return 0 ;
fs/smb/server/smb2pdu.c +5 -6
@@ -2056,12 +2056,11 @@ int smb2_tree_connect(struct ksmbd_work *work)write_unlock (&sess->tree_conns_lock); rsp->StructureSize =cpu_to_le16 (16 ); out_err1: -if (server_conf.flags &KSMBD_GLOBAL_FLAG_DURABLE_HANDLE && share && -test_share_config_flag (share, -KSMBD_SHARE_FLAG_CONTINUOUS_AVAILABILITY )) - rsp->Capabilities =SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY ; -else - rsp->Capabilities =0 ; +/* +* A configured CA share is not continuously available until persistent +* open recovery, ownership fencing, and failover are implemented. +*/ + rsp->Capabilities =0 ; rsp->Reserved =0 ;/* default manual caching */ rsp->ShareFlags =SMB2_SHAREFLAG_MANUAL_CACHING ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1166/1376 ksmbd: free preauth sessions on connection teardown
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit 06c7b1d731bc105a8644f1b70165ba8b9416cbab ]
SMB3.1.1 multichannel binding preserves the preauthentication hash in a preauth_session between the NTLM negotiate and authenticate requests. The binding NTLM negotiate allocates this object and returns STATUS_MORE_PROCESSING_REQUIRED. If the client disconnects before it sends the authenticate request, neither the authenticate nor error cleanup paths free the object.
Release any remaining preauthentication sessions when tearing down the connection. Initialize the list when allocating the connection so that this cleanup is safe regardless of the negotiated dialect.
--- fs/smb/server/connection.c | 3 +++ fs/smb/server/mgmt/user_session.c | 11 +++++++++++ fs/smb/server/mgmt/user_session.h | 1 + fs/smb/server/smb2ops.c | 2 -- 4 files changed, 15 insertions(+), 2 deletions(-)
fs/smb/server/connection.c +3 -0
@@ -11,6 +11,7 @@#include "server.h" #include "smb_common.h" #include "mgmt/ksmbd_ida.h" +#include "mgmt/user_session.h" #include "connection.h" #include "transport_tcp.h" #include "transport_rdma.h"
@@ -123,6 +124,7 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)kvfree (conn->request_buf);kfree (conn->preauth_info);kfree (conn->mechToken); +ksmbd_preauth_session_destroy (conn);ksmbd_conn_put (conn); }
@@ -161,6 +163,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)init_waitqueue_head (&conn->r_count_q);INIT_LIST_HEAD (&conn->requests);INIT_LIST_HEAD (&conn->async_requests); +INIT_LIST_HEAD (&conn->preauth_sess_table);spin_lock_init (&conn->request_lock);spin_lock_init (&conn->credits_lock);ida_init (&conn->async_ida);
fs/smb/server/mgmt/user_session.c +11 -0
@@ -374,6 +374,17 @@ struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,return sess; } +void ksmbd_preauth_session_destroy (struct ksmbd_conn *conn) +{ +struct preauth_session *sess, *tmp; + +list_for_each_entry_safe (sess, tmp, &conn->preauth_sess_table, + preauth_entry) { +list_del (&sess->preauth_entry); +kfree (sess); + } +} +void destroy_previous_session (struct ksmbd_conn *conn,struct ksmbd_user *user,u64 id) {
fs/smb/server/mgmt/user_session.h +1 -0
@@ -101,6 +101,7 @@ void destroy_previous_session(struct ksmbd_conn *conn, struct ksmbd_user *user, u64 id);struct preauth_session *ksmbd_preauth_session_alloc (struct ksmbd_conn *conn,u64 sess_id); +void ksmbd_preauth_session_destroy (struct ksmbd_conn *conn);struct preauth_session *ksmbd_preauth_session_lookup (struct ksmbd_conn *conn,unsigned long long id);
fs/smb/server/smb2ops.c +0 -2
@@ -289,8 +289,6 @@ int init_smb3_11_server(struct ksmbd_conn *conn) conn->vals->req_capabilities |=SMB2_GLOBAL_CAP_MULTI_CHANNEL ;/* See init_smb3_02_server(): persistent handles require CA recovery. */ - -INIT_LIST_HEAD (&conn->preauth_sess_table);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1167/1376 smb/server: fix null-ptr-deref in ksmbd_ipc_tree_connect_request()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: ZhangGuoDong <[email protected]>
[ Upstream commit d2ccf905f47d2344270749f4dfa905afcd3edeb0 ]
See the procedure below:
ksmbd_tree_conn_connect
ksmbd_share_config_get
share->name = kstrdup() // fail
if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) // false
// do not check `share->name`
ksmbd_ipc_tree_connect_request
strlen(share->name) // null-ptr-deref--- fs/smb/server/mgmt/share_config.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
fs/smb/server/mgmt/share_config.c +6 -1
@@ -158,6 +158,11 @@ static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work,atomic_set (&share->refcount,1 );INIT_LIST_HEAD (&share->veto_list); share->name =kstrdup (name,KSMBD_DEFAULT_GFP ); +if (!share->name) { +kill_share (share); + share =NULL ; + goto out; + }if (!test_share_config_flag (share,KSMBD_SHARE_FLAG_PIPE )) {int path_len =PATH_MAX ;
@@ -199,7 +204,7 @@ static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work, share->path =NULL ; } } -if (ret || !share->name) { +if (ret) {kill_share (share); share =NULL ; goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1168/1376 smb/server: fix invalid pointer dereference in ksmbd_stop_durable_scavenger()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: ZhangGuoDong <[email protected]>
[ Upstream commit bef46b604732d83f8da29f782868de4d25bf972c ]
See the procedure below:
ksmbd_launch_ksmbd_durable_scavenger
durable_scavenger_running = true
server_conf.dh_task = kthread_run() // fail, dh_task is an ERR_PTR()
server_ctrl_handle_reset
ksmbd_stop_durable_scavenger kthread_stop(server_conf.dh_task) // invalid pointer
--- fs/smb/server/vfs_cache.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
fs/smb/server/vfs_cache.c +4 -1
@@ -1103,9 +1103,12 @@ void ksmbd_launch_ksmbd_durable_scavenger(void) server_conf.dh_task =kthread_run (ksmbd_durable_scavenger, (void *)NULL ,"ksmbd-durable-scavenger" ); -if (IS_ERR (server_conf.dh_task)) +if (IS_ERR (server_conf.dh_task)) {pr_err ("cannot start conn thread, err : %ld\n" ,PTR_ERR (server_conf.dh_task)); + server_conf.dh_task =NULL ; + durable_scavenger_running = false; + }mutex_unlock (&durable_scavenger_lock); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1169/1376 smb/server: preserve error status in smb2_handle_negotiate()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: ZhangGuoDong <[email protected]>
[ Upstream commit 73541bd2bab77e7e8e89b1edb5d342f4190dd4d0 ]
smb2_handle_negotiate() records specific failures such as STATUS_INVALID_PARAMETER or STATUS_NOT_SUPPORTED.
--- fs/smb/server/smb2pdu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/smb/server/smb2pdu.c +2 -2
@@ -1169,7 +1169,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work) KSMBD_DEFAULT_GFP);if (!conn->preauth_info) { rc = -ENOMEM ; - rsp->hdr.Status =STATUS_INVALID_PARAMETER ; + rsp->hdr.Status =STATUS_INSUFFICIENT_RESOURCES ; goto err_out; }
@@ -1266,7 +1266,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work)ksmbd_conn_set_need_setup (conn); err_out: -if (rc) +if (rc && rsp->hdr.Status ==STATUS_SUCCESS ) rsp->hdr.Status =STATUS_INSUFFICIENT_RESOURCES ;if (!rc)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1170/1376 lwt_bpf: Restore reserved headroom after xmit program
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junseo Lim <[email protected]>
[ Upstream commit 5fe7007aed9ad069b2bd77e5d0c875c64f5c0269 ]
ip_finish_output2() expands an skb to LL_RESERVED_SPACE(dev) before LWT xmit. An LWT_XMIT BPF program can then modify the skb head and still return BPF_OK, so bpf_xmit() rechecks the remaining headroom before the skb continues to neighbour output.
That recheck uses dst->dev->hard_header_len. This is not enough for the neighbour cached-header path: neigh_hh_output() copies the cached hardware header using the aligned hh_cache size, HH_DATA_MOD for short headers or HH_DATA_ALIGN(hh_len) otherwise.
On Ethernet, hard_header_len is 14 but the cached copy needs 16 bytes. If an LWT_XMIT BPF program calls bpf_skb_change_head(skb, 1, 0), the skb can still have 15 bytes of headroom after the program. The existing check accepts that, after which neigh_hh_output() hits its headroom warning and drops the skb.
Use LL_RESERVED_SPACE(dst->dev) in the post-BPF headroom check to match the reservation made before LWT xmit.
--- net/core/lwt_bpf.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
net/core/lwt_bpf.c +9 -6
@@ -160,10 +160,10 @@ static int bpf_output(struct net *net, struct sock *sk, struct sk_buff *skb)return dst->lwtstate->orig_output (net, sk, skb); } -static int xmit_check_hhlen (struct sk_buff *skb,int hh_len) +static int xmit_check_headroom (struct sk_buff *skb,int hroom) { -if (skb_headroom (skb) < hh_len) { -int nhead =HH_DATA_ALIGN (hh_len -skb_headroom (skb)); +if (skb_headroom (skb) < hroom) { +int nhead = hroom -skb_headroom (skb);if (pskb_expand_head (skb, nhead,0 ,GFP_ATOMIC ))return -ENOMEM ;
@@ -275,7 +275,7 @@ static int bpf_xmit(struct sk_buff *skb) bpf =bpf_lwt_lwtunnel (dst->lwtstate);if (bpf->xmit.prog) { -int hh_len = dst->dev->hard_header_len; +int hroom =LL_RESERVED_SPACE (dst->dev);__be16 proto = skb->protocol;int ret;
@@ -291,9 +291,12 @@ static int bpf_xmit(struct sk_buff *skb)return -EINVAL ; }/* If the header was expanded, headroom might be too -* small for L2 header to come, expand as needed. +* small for the L2 header to come, expand as needed. +* neigh_hh_output() copies the cached header in +* HH_DATA_MOD aligned chunks, so match the reservation +* made before LWT xmit. */ - ret =xmit_check_hhlen (skb, hh_len); + ret =xmit_check_headroom (skb, hroom);if (unlikely (ret))return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1171/1376 erofs: convert z_erofs_bind_cache() to folios
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gao Xiang <[email protected]>
[ Upstream commit e180b8c4c23beb876927a999c49c18b361fa7975 ]
The managed cache uses a pseudo inode to keep (necessary) compressed data.
Currently, it still uses zero-order folios, so this is just a trivial conversion, except that the use of the pagepool is temporarily dropped.
Drop some obsoleted comments too.
Stable-dep-of: 988c3c186c73 ("erofs: fix unused pcluster_pools for higher page sizes")
--- fs/erofs/compress.h | 23 +------------------- fs/erofs/zdata.c | 51 ++++++++++++++++++--------------------------- 2 files changed, 21 insertions(+), 53 deletions(-)
fs/erofs/compress.h +1 -22
@@ -30,29 +30,8 @@ struct z_erofs_decompressor {char *name; }; -/* some special page->private (unsigned long, see below) */ #define Z_EROFS_SHORTLIVED_PAGE (-1UL << 2) -#define Z_EROFS_PREALLOCATED_PAGE (-2UL << 2) - -/* -* For all pages in a pcluster, page->private should be one of -* Type Last 2bits page->private -* short-lived page 00 Z_EROFS_SHORTLIVED_PAGE -* preallocated page (tryalloc) 00 Z_EROFS_PREALLOCATED_PAGE -* cached/managed page 00 pointer to z_erofs_pcluster -* online page (file-backed, 01/10/11 sub-index << 2 | count -* some pages can be used for inplace I/O) -* -* page->mapping should be one of -* Type page->mapping -* short-lived page NULL -* preallocated page NULL -* cached/managed page non-NULL or NULL (invalidated/truncated page) -* online page non-NULL -* -* For all managed pages, PG_private should be set with 1 extra refcount, -* which is used for page reclaim / migration. -*/ +#define Z_EROFS_PREALLOCATED_FOLIO ((void *)(-2UL << 2))/* * Currently, short-lived pages are pages directly from buddy system
fs/erofs/zdata.c +20 -31
92 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1172/1376 erofs: support unaligned encoded data
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gao Xiang <[email protected]>
[ Upstream commit 7361d1e3763baaf7b9349c576137851458ad38d1 ]
We're almost there. It's straight-forward to adapt the current decompression subsystem to support unaligned encoded (compressed) data.
Note that unaligned data is not encouraged because of worse I/O and caching efficiency unless the corresponding compressor doesn't support fixed-sized output compression natively like Zstd.
Stable-dep-of: 988c3c186c73 ("erofs: fix unused pcluster_pools for higher page sizes")
--- fs/erofs/decompressor.c | 2 +- fs/erofs/zdata.c | 92 ++++++++++++++++++++--------------------- 2 files changed, 46 insertions(+), 48 deletions(-)
fs/erofs/decompressor.c +1 -1
@@ -326,7 +326,7 @@ static int z_erofs_transform_plain(struct z_erofs_decompress_req *rq, rq->outputsize -= cur; } -for (; rq->outputsize; rq->pageofs_in =0 , cur +=PAGE_SIZE , ni++) { +for (; rq->outputsize; rq->pageofs_in =0 , cur += insz, ni++) { insz =min (PAGE_SIZE - rq->pageofs_in, rq->outputsize); rq->outputsize -= insz;if (!rq->in[ni])
fs/erofs/zdata.c +45 -47
248 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1173/1376 erofs: fix unused pcluster_pools for higher page sizes
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ojaswin Mujoo <[email protected]>
[ Upstream commit 988c3c186c730590a71df8adc1424c5578ef8bae ]
pcluster_pool[] hardcodes {1,4,16,64,128,Z_EROFS_PCLUSTER_MAX_PAGES+1}, but the assumption of Z_EROFS_PCLUSTER_MAX_PAGES == 256 is only right for 4k page sizes. For higher page sizes like 16k or 64k, This results in us ending up with clusters bigger than what we will ever use, since we only support upto 1MB of compressed data. For example, on 64k page size we will only ever use clusters with nrpages= 1, 4 and 17.
This patch fixes the allocation for such higher pages sizes by adding some compile time checks.
Below are the clusters created right after boot on a 64KB page size machine
$cat /proc/slabinfo | grep pcluster | cut -d" " -f1:
Before the patch:
erofs_pcluster-1
erofs_pcluster-4
erofs_pcluster-16
erofs_pcluster-17
erofs_pcluster-64
erofs_pcluster-128
After the patch:
erofs_pcluster-1
erofs_pcluster-4
erofs_pcluster-17
--- fs/erofs/zdata.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
fs/erofs/zdata.c +11 -1
@@ -128,7 +128,17 @@ struct z_erofs_pcluster_slab {#define _PCLP (n) { .maxpages = n }static struct z_erofs_pcluster_slab pcluster_pool[]__read_mostly = { -_PCLP (1 ),_PCLP (4 ),_PCLP (16 ),_PCLP (64 ),_PCLP (128 ), +_PCLP (1 ), +_PCLP (4 ), +#if Z_EROFS_PCLUSTER_MAX_PAGES > 16 +_PCLP (16 ), +#endif +#if Z_EROFS_PCLUSTER_MAX_PAGES > 64 +_PCLP (64 ), +#endif +#if Z_EROFS_PCLUSTER_MAX_PAGES > 128 +_PCLP (128 ), +#endif_PCLP (Z_EROFS_PCLUSTER_MAX_PAGES +1 ) };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1174/1376 bpf: Disallow bpf_{g,s}etsockopt() in cgroup UNIX getname hooks
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junseo Lim <[email protected]>
[ Upstream commit 84473a7e1813a2da7b759ab1d098a84998c8d3f5 ]
_bpf_setsockopt() and _bpf_getsockopt() call sock_owned_by_me() for full sockets, so these helpers expect the socket lock to be held.
BPF_CGROUP_UNIX_GETPEERNAME and BPF_CGROUP_UNIX_GETSOCKNAME run BPF programs without acquiring the socket lock. A program attached to either hook can therefore trigger the sock_owned_by_me() warning by calling bpf_setsockopt() or bpf_getsockopt().
Disallow bpf_setsockopt() and bpf_getsockopt() for CGROUP_UNIX_GETPEERNAME and CGROUP_UNIX_GETSOCKNAME.
--- net/core/filter.c | 4 ---- 1 file changed, 4 deletions(-)
net/core/filter.c +0 -4
@@ -8128,10 +8128,8 @@ sock_addr_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)case BPF_CGROUP_UNIX_SENDMSG :case BPF_CGROUP_INET4_GETPEERNAME :case BPF_CGROUP_INET6_GETPEERNAME : -case BPF_CGROUP_UNIX_GETPEERNAME :case BPF_CGROUP_INET4_GETSOCKNAME :case BPF_CGROUP_INET6_GETSOCKNAME : -case BPF_CGROUP_UNIX_GETSOCKNAME :return &bpf_sock_addr_setsockopt_proto;default :return NULL ;
@@ -8151,10 +8149,8 @@ sock_addr_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)case BPF_CGROUP_UNIX_SENDMSG :case BPF_CGROUP_INET4_GETPEERNAME :case BPF_CGROUP_INET6_GETPEERNAME : -case BPF_CGROUP_UNIX_GETPEERNAME :case BPF_CGROUP_INET4_GETSOCKNAME :case BPF_CGROUP_INET6_GETSOCKNAME : -case BPF_CGROUP_UNIX_GETSOCKNAME :return &bpf_sock_addr_getsockopt_proto;default :return NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1175/1376 m68k: nfcon: Do not call console_is_registered() in nfcon_device()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andreas Schwab <[email protected]>
[ Upstream commit 2f8e3cad53b5c36ab0ed5d3195bfc55c59ea61a5 ]
Since 7c2af0f634f1 ("tty: tty_io: use console_list_lock for list synchronization") show_cons_active() calls the .device() method under the console_list_lock, but console_is_registered() tries to acquire console_list_lock as well, causing a deadlock. It should not be necessary to check console_is_registered() here since the function should not be called in the fist place when the console is not registered.
--- arch/m68k/emu/nfcon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/m68k/emu/nfcon.c +1 -1
@@ -49,7 +49,7 @@ static void nfcon_write(struct console *con, const char *str,static struct tty_driver *nfcon_device (struct console *con,int *index) { *index =0 ; -return console_is_registered (con) ? nfcon_tty_driver :NULL ; +return nfcon_tty_driver; }static struct console nf_console = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1176/1376 bpf: Reject negative optlen in cgroup getsockopt hook
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junseo Lim <[email protected]>
[ Upstream commit 1b5aacd5b2419b0790e955e466d389a61c79b4b1 ]
A cgroup getsockopt BPF program can shrink ctx->optlen after the kernel getsockopt handler has run. The kernel-buffer variant, used by TCP_ZEROCOPY_RECEIVE, only rejects values larger than the original length.
If BPF writes a negative optlen, that value is accepted and propagated back to the TCP getsockopt code. It can then be passed to copy_to_sockptr() as a size_t and trigger the hardened usercopy bytes > INT_MAX warning.
Reject negative ctx.optlen in __cgroup_bpf_run_filter_getsockopt_kern(), matching the lower-bound validation already present in the sockptr-based getsockopt hook.
--- kernel/bpf/cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/bpf/cgroup.c +1 -1
@@ -2214,7 +2214,7 @@ int __cgroup_bpf_run_filter_getsockopt_kern(struct sock *sk, int level,if (ret <0 )return ret; -if (ctx.optlen > *optlen) +if (ctx.optlen > *optlen || ctx.optlen <0 )return -EFAULT ;/* BPF programs can shrink the buffer, export the modifications.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1177/1376 ksmbd: disconnect on SMB3 decryption failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
[ Upstream commit 12a6680ce59bcd431730c9f049caddb017964c64 ]
MS-SMB2 requires the server to disconnect a connection when an encrypted transform cannot be associated with a session or fails authenticated decryption. This includes an encrypted request that still carries a SessionId invalidated through PreviousSessionId.
Move the connection to EXITING and shut down its transport when decrypt_req() fails. Add the missing TCP shutdown callback so a receive blocked in kernel_recvmsg() is released; SMB Direct already provides the corresponding callback.
Plaintext requests using an invalidated SessionId do not take this path and continue to receive STATUS_USER_SESSION_DELETED.
--- fs/smb/server/connection.c | 16 ++++++++++++++++ fs/smb/server/connection.h | 1 + fs/smb/server/server.c | 4 +++- fs/smb/server/transport_tcp.c | 6 ++++++ 4 files changed, 26 insertions(+), 1 deletion(-)
fs/smb/server/connection.c +16 -0
@@ -255,6 +255,22 @@ void ksmbd_all_conn_set_status(u64 sess_id, u32 status)up_read (&conn_list_lock); } +void ksmbd_conn_abort (struct ksmbd_conn *conn) +{ +bool shutdown = false; + +spin_lock (&conn->request_lock); +if (!ksmbd_conn_exiting (conn) && !ksmbd_conn_releasing (conn)) { +ksmbd_conn_set_exiting (conn); + shutdown = true; + } +spin_unlock (&conn->request_lock); +wake_up_all (&conn->req_running_q); + +if (shutdown && conn->transport->ops->shutdown) + conn->transport->ops->shutdown (conn->transport); +} +void ksmbd_conn_wait_idle (struct ksmbd_conn *conn) {wait_event (conn->req_running_q,atomic_read (&conn->req_running) <2 );
fs/smb/server/connection.h +1 -0
@@ -166,6 +166,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void);void ksmbd_conn_free (struct ksmbd_conn *conn);struct ksmbd_conn *ksmbd_conn_get (struct ksmbd_conn *conn);void ksmbd_conn_put (struct ksmbd_conn *conn); +void ksmbd_conn_abort (struct ksmbd_conn *conn);int ksmbd_conn_wq_init (void );void ksmbd_conn_wq_destroy (void );bool ksmbd_conn_lookup_dialect (struct ksmbd_conn *c);
fs/smb/server/server.c +3 -1
@@ -170,8 +170,10 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,if (conn->ops->is_transform_hdr && conn->ops->is_transform_hdr (work->request_buf)) { rc = conn->ops->decrypt_req (work); -if (rc <0 ) +if (rc <0 ) { +ksmbd_conn_abort (conn);return ; + } work->encrypted = true; }
fs/smb/server/transport_tcp.c +6 -0
@@ -467,6 +467,11 @@ static void ksmbd_tcp_disconnect(struct ksmbd_transport *t)atomic_dec (&active_num_conn); } +static void ksmbd_tcp_shutdown (struct ksmbd_transport *t) +{ +kernel_sock_shutdown (TCP_TRANS (t)->sock,SHUT_RDWR ); +} +static void tcp_destroy_socket (struct socket *ksmbd_socket) {int ret;
@@ -722,5 +727,6 @@ static const struct ksmbd_transport_ops ksmbd_tcp_transport_ops = { .read = ksmbd_tcp_read, .writev = ksmbd_tcp_writev, .disconnect = ksmbd_tcp_disconnect, + .shutdown = ksmbd_tcp_shutdown, .free_transport = ksmbd_tcp_free_transport, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1178/1376 ksmbd: bound smb_check_perm_dacl() ACE walks by DACL size
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hang Nan <[email protected]>
[ Upstream commit 79decd88dd3f0d42e7fb0689b1a7853bfa302459 ]
smb_check_perm_dacl() validates that the DACL fits inside the NT security descriptor, but then bounds its two ACE walks by the remaining NTSD length (acl_size) rather than the DACL's declared size (pdacl_size).
When pdacl->size is smaller than the trailing NTSD buffer, bytes after the declared DACL boundary - still inside the stored security descriptor - are parsed as ACEs during access checks. A crafted DACL can place an access-granting ACE beyond pdacl->size, and the current code accepts it during SMB2_CREATE access validation, while parse_dacl() and smb_inherit_dacl() stop at pdacl_size.
Bound both ACE walks by pdacl_size to match the DACL boundary semantics used elsewhere in the server.
Validation:
- semantic KUnit harness shows the post-boundary ACE is selected before the fix and rejected (EACCES) after it
- linux master (7.2-rc6), x86_64
--- fs/smb/server/smbacl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/smb/server/smbacl.c +2 -2
@@ -1471,7 +1471,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,DELETE ; ace = (struct smb_ace *)((char *)pdacl +sizeof (struct smb_acl )); - aces_size = acl_size -sizeof (struct smb_acl ); + aces_size = pdacl_size -sizeof (struct smb_acl );for (i =0 ; i <le16_to_cpu (pdacl->num_aces); i++) {if (aces_size < offsetof(struct smb_ace , sid) +CIFS_SID_BASE_SIZE )
@@ -1495,7 +1495,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,id_to_sid (uid, sid_type, &sid); ace = (struct smb_ace *)((char *)pdacl +sizeof (struct smb_acl )); - aces_size = acl_size -sizeof (struct smb_acl ); + aces_size = pdacl_size -sizeof (struct smb_acl );for (i =0 ; i <le16_to_cpu (pdacl->num_aces); i++) {if (aces_size < offsetof(struct smb_ace , sid) +CIFS_SID_BASE_SIZE )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1179/1376 smb/server: fix session leak in ksmbd_session_register()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ze Tan <[email protected]>
[ Upstream commit 99b25b046e47e4904373cfeb445c5483f1633d88 ]
See the procedure below:
smb2_sess_setup
ksmbd_smb2_session_create
__session_create
atomic_set(&sess->refcnt, 2)
hash_add(sessions_table, &sess->hlist, sess->id)
ksmbd_session_register
xa_store(&conn->sessions, sess->id, sess) // fail
ksmbd_user_session_put
atomic_dec(&sess->refcnt) // refcnt is 1, session is not freedRemove the session from sessions_table and drop its table reference if xa_store() fails.
--- fs/smb/server/mgmt/user_session.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
fs/smb/server/mgmt/user_session.c +12 -1
@@ -212,10 +212,21 @@ static void ksmbd_expire_session(struct ksmbd_conn *conn)int ksmbd_session_register (struct ksmbd_conn *conn,struct ksmbd_session *sess) { +int ret; + sess->dialect = conn->dialect;memcpy (sess->ClientGUID, conn->ClientGUID,SMB2_CLIENT_GUID_SIZE );ksmbd_expire_session (conn); -return xa_err (xa_store (&conn->sessions, sess->id, sess,KSMBD_DEFAULT_GFP )); + ret =xa_err (xa_store (&conn->sessions, sess->id, sess, +KSMBD_DEFAULT_GFP )); +if (ret) { +down_write (&sessions_table_lock); +hash_del (&sess->hlist); +up_write (&sessions_table_lock); +ksmbd_user_session_put (sess); + } + +return ret; }static int ksmbd_chann_del (struct ksmbd_conn *conn,struct ksmbd_session *sess)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1180/1376 nfs: replace atomic bitops sequence with clear_and_wake_up_bit helper
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaud Bonnet <[email protected]>
[ Upstream commit 61461050da42401b484d03e0fdac02878d235fe6 ]
Commit 8236b0ae31c83 ("bdi: wake up concurrent wb_shutdown() callers.") introduces the clear_and_wake_up_bit() helper as a wrapper for the common clear -> barrier -> wake up bitops sequence.
Use the helper in nfs_clear_invalid_mapping as inode.c already relies on functions from <linux/wait_bit.h> and to homogenize with other subsystems.
--- fs/nfs/inode.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
fs/nfs/inode.c +1 -3
@@ -1504,9 +1504,7 @@ int nfs_clear_invalid_mapping(struct address_space *mapping) ret =nfs_invalidate_mapping (inode, mapping);trace_nfs_invalidate_mapping_exit (inode, ret); -clear_bit_unlock (NFS_INO_INVALIDATING , bitlock); -smp_mb__after_atomic (); -wake_up_bit (bitlock,NFS_INO_INVALIDATING ); +clear_and_wake_up_bit (NFS_INO_INVALIDATING , bitlock); out:return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1181/1376 nfs: refactor pNFS functions using clear_and_wake_up_bit
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaud Bonnet <[email protected]>
[ Upstream commit 187bfc974eefa9e5d88a0b4ee9d08ae8fe485df4 ]
Commit 8236b0ae31c83 ("bdi: wake up concurrent wb_shutdown() callers.") introduces the clear_and_wake_up_bit() helper as a wrapper for the common clear -> barrier -> wake up bitops sequence.
The file pnfs.c has several helpers with identical contents. Thus they are replaced with the more recent clean_and_wake_up_bit() global helper which describes accurately its effects at the call and still specifies the cleared bit. This also homogenizes the code with other subsystems.
Since the helpers are no longer used after this, they can be safely removed.
--- fs/nfs/pnfs.c | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-)
fs/nfs/pnfs.c +10 -25
@@ -2088,15 +2088,6 @@ static bool pnfs_is_first_layoutget(struct pnfs_layout_hdr *lo)return test_bit (NFS_LAYOUT_FIRST_LAYOUTGET , &lo->plh_flags); } -static void pnfs_clear_first_layoutget (struct pnfs_layout_hdr *lo) -{ -unsigned long *bitlock = &lo->plh_flags; - -clear_bit_unlock (NFS_LAYOUT_FIRST_LAYOUTGET , bitlock); -smp_mb__after_atomic (); -wake_up_bit (bitlock,NFS_LAYOUT_FIRST_LAYOUTGET ); -} -static void _add_to_server_list (struct pnfs_layout_hdr *lo,struct nfs_server *server) {
@@ -2272,7 +2263,8 @@ pnfs_update_layout(struct inode *ino, iomode, lo, lseg, PNFS_UPDATE_LAYOUT_INVALID_OPEN);nfs4_schedule_stateid_recovery (server, ctx->state); -pnfs_clear_first_layoutget (lo); +clear_and_wake_up_bit (NFS_LAYOUT_FIRST_LAYOUTGET , + &lo->plh_flags);pnfs_put_layout_hdr (lo); goto lookup_again; }
@@ -2341,7 +2333,8 @@ pnfs_update_layout(struct inode *ino,if (!exception.retry) goto out_put_layout_hdr;if (first) -pnfs_clear_first_layoutget (lo); +clear_and_wake_up_bit (NFS_LAYOUT_FIRST_LAYOUTGET , + &lo->plh_flags);trace_pnfs_update_layout (ino, pos, count, iomode, lo, lseg,PNFS_UPDATE_LAYOUT_RETRY );pnfs_put_layout_hdr (lo);
@@ -2353,7 +2346,7 @@ pnfs_update_layout(struct inode *ino, out_put_layout_hdr:if (first) -pnfs_clear_first_layoutget (lo); +clear_and_wake_up_bit (NFS_LAYOUT_FIRST_LAYOUTGET , &lo->plh_flags);trace_pnfs_update_layout (ino, pos, count, iomode, lo, lseg,PNFS_UPDATE_LAYOUT_EXIT );pnfs_put_layout_hdr (lo);
@@ -2445,7 +2438,7 @@ static void _lgopen_prepare_attached(struct nfs4_opendata *data, lgp =pnfs_alloc_init_layoutget_args (ino, ctx, ¤t_stateid, &rng,nfs_io_gfp_mask ());if (!lgp) { -pnfs_clear_first_layoutget (lo); +clear_and_wake_up_bit (NFS_LAYOUT_FIRST_LAYOUTGET , &lo->plh_flags);nfs_layoutget_end (lo);pnfs_put_layout_hdr (lo);return ;
@@ -2549,7 +2542,8 @@ void nfs4_lgopen_release(struct nfs4_layoutget *lgp) {if (lgp !=NULL ) {if (lgp->lo) { -pnfs_clear_first_layoutget (lgp->lo); +clear_and_wake_up_bit (NFS_LAYOUT_FIRST_LAYOUTGET , + &lgp->lo->plh_flags);nfs_layoutget_end (lgp->lo); }pnfs_layoutget_free (lgp);
@@ -3262,15 +3256,6 @@ pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) }EXPORT_SYMBOL_GPL (pnfs_generic_pg_readpages); -static void pnfs_clear_layoutcommitting (struct inode *inode) -{ -unsigned long *bitlock = &NFS_I (inode)->flags; - -clear_bit_unlock (NFS_INO_LAYOUTCOMMITTING , bitlock); -smp_mb__after_atomic (); -wake_up_bit (bitlock,NFS_INO_LAYOUTCOMMITTING ); -} -/* * There can be multiple RW segments. */
@@ -3295,7 +3280,7 @@ static void pnfs_list_write_lseg_done(struct inode *inode, struct list_head *lispnfs_put_lseg (lseg); } -pnfs_clear_layoutcommitting (inode); +clear_and_wake_up_bit (NFS_INO_LAYOUTCOMMITTING , &NFS_I (inode)->flags); }void pnfs_set_lo_fail (struct pnfs_layout_segment *lseg)
@@ -3435,7 +3420,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)spin_unlock (&inode->i_lock);kfree (data); clear_layoutcommitting: -pnfs_clear_layoutcommitting (inode); +clear_and_wake_up_bit (NFS_INO_LAYOUTCOMMITTING , &NFS_I (inode)->flags); goto out; }EXPORT_SYMBOL_GPL (pnfs_layoutcommit_inode);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1182/1376 NFSv4: remove callback IDR entry on client allocation failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit d05c2007b3d84ccba11dc6e9cb3202768cc72f14 ]
nfs4_alloc_client() allocates an NFSv4.0 callback identifier before it finishes setting up the client. If any later initialization step fails, the error path frees the nfs_client directly with nfs_free_client(). That bypasses nfs_put_client(), which is where the callback IDR entry is removed during normal teardown.
A failed allocation can therefore leave cb_ident_idr pointing at a freed nfs_client. A later NFSv4.0 callback lookup by cb_ident would find the stale pointer and take a reference to it.
Make the callback IDR removal helper callable by the allocation failure path, and remove the callback identifier before freeing the client.
This was found by a local static-analysis checker for publish-before-free lifetime bugs and confirmed by manual inspection.
--- fs/nfs/client.c | 14 +++++++++++++- fs/nfs/internal.h | 1 + fs/nfs/nfs4client.c | 1 + 3 files changed, 15 insertions(+), 1 deletion(-)
fs/nfs/client.c +13 -1
@@ -211,9 +211,21 @@ static void nfs_cb_idr_remove_locked(struct nfs_client *clp) {struct nfs_net *nn =net_generic (clp->cl_net, nfs_net_id); -if (clp->cl_cb_ident) +if (clp->cl_cb_ident) {idr_remove (&nn->cb_ident_idr, clp->cl_cb_ident); + clp->cl_cb_ident =0 ; + } +} + +void nfs_cb_idr_remove (struct nfs_client *clp) +{ +struct nfs_net *nn =net_generic (clp->cl_net, nfs_net_id); + +spin_lock (&nn->nfs_client_lock); +nfs_cb_idr_remove_locked (clp); +spin_unlock (&nn->nfs_client_lock); } +EXPORT_SYMBOL_GPL (nfs_cb_idr_remove);static void pnfs_init_server (struct nfs_server *server) {
fs/nfs/internal.h +1 -0
@@ -226,6 +226,7 @@ void nfs_server_copy_userdata(struct nfs_server *, struct nfs_server *);extern void nfs_put_client (struct nfs_client *);extern void nfs_free_client (struct nfs_client *); +void nfs_cb_idr_remove (struct nfs_client *clp);extern struct nfs_client *nfs4_find_client_ident (struct net *,int );extern struct nfs_client * nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
fs/nfs/nfs4client.c +1 -0
@@ -270,6 +270,7 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)return clp; error: +nfs_cb_idr_remove (clp);nfs_free_client (clp);return ERR_PTR (err); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1183/1376 pnfs/blocklayout: Fix device leaks on parse failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: ZhangGuoDong <[email protected]>
[ Upstream commit c056f817e4200fb18079d5052c273a22f191ff0a ]
bl_parse_concat() and bl_parse_stripe() allocate a child device array and then parse each child in turn. If parsing a child fails, the failed child is not counted in nr_children and the parent may be left with a children array that bl_free_device() will not release when nr_children is zero.
Release the failed child and the already parsed children before returning the error. Also make bl_free_device() release the child array whenever the children pointer is set, so that partially initialised concat or stripe devices are cleaned up correctly.
bl_parse_scsi() can also fail after assigning d->bdev_file and dropping the file reference. Clear the pointer after fput() so that an outer cleanup path does not put it again.
--- fs/nfs/blocklayout/dev.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-)
fs/nfs/blocklayout/dev.c +15 -6
@@ -85,15 +85,17 @@ bl_free_device(struct pnfs_block_dev *dev) {bl_unregister_dev (dev); -if (dev->nr_children) { +if (dev->children) {int i;for (i =0 ; i < dev->nr_children; i++)bl_free_device (&dev->children[i]);kfree (dev->children); - }else { -if (dev->bdev_file) -fput (dev->bdev_file); + dev->children =NULL ; + dev->nr_children =0 ; + }else if (dev->bdev_file) { +fput (dev->bdev_file); + dev->bdev_file =NULL ; } }
@@ -434,6 +436,7 @@ bl_parse_scsi(struct nfs_server *server, struct pnfs_block_dev *d, out_blkdev_put:fput (d->bdev_file); + d->bdev_file =NULL ;return error; }
@@ -469,8 +472,11 @@ bl_parse_concat(struct nfs_server *server, struct pnfs_block_dev *d,for (i =0 ; i < v->concat.volumes_count; i++) { ret =bl_parse_deviceid (server, &d->children[i], volumes, v->concat.volumes[i], gfp_mask); -if (ret) +if (ret) { +bl_free_device (&d->children[i]); +bl_free_device (d);return ret; + } d->nr_children++; d->children[i].start += len;
@@ -498,8 +504,11 @@ bl_parse_stripe(struct nfs_server *server, struct pnfs_block_dev *d,for (i =0 ; i < v->stripe.volumes_count; i++) { ret =bl_parse_deviceid (server, &d->children[i], volumes, v->stripe.volumes[i], gfp_mask); -if (ret) +if (ret) { +bl_free_device (&d->children[i]); +bl_free_device (d);return ret; + } d->nr_children++; len += d->children[i].len;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1184/1376 NFSv4: Fix incorrect argument passed to nfs4_delete_lease() in nfs4_add_lease()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhansong Gao <[email protected]>
[ Upstream commit 468e458ffde907ba19acd2102ca1fbb8f6fbede2 ]
When nfs4_add_lease() races with a delegation return, it calls nfs4_delete_lease() to clean up. Previously, it passed priv, which can legitimately be NULL. Passing a NULL priv eventually leads to a NULL pointer dereference in generic_setlease().
--- fs/nfs/nfs4proc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/nfs/nfs4proc.c +3 -1
@@ -7812,6 +7812,7 @@ static int nfs4_add_lease(struct file *file, int arg, struct file_lease **lease, {struct inode *inode =file_inode (file);fmode_t type = arg ==F_RDLCK ?FMODE_READ :FMODE_WRITE ; +fl_owner_t owner = (*lease)->c.flc_owner;int ret;/* No delegation, no lease */
@@ -7821,7 +7822,8 @@ static int nfs4_add_lease(struct file *file, int arg, struct file_lease **lease,if (ret ||nfs4_have_delegation (inode, type,0 ))return ret;/* We raced with a delegation return */ -nfs4_delete_lease (file, priv); +dprintk ("%s: raced with a delegation return\n" , __func__); +nfs4_delete_lease (file, &owner);return -EAGAIN ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1185/1376 nfs: fix ENXIO on O_CREAT open of existing symlink over NFSv3
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Nemanov <[email protected]>
[ Upstream commit 10f307e525a1783570a39eb9ac146d45f4f16b3e ]
When open(2) is called with O_CREAT on a path that already exists as a symlink, over an NFSv3 mount with a cold dcache, the kernel returns ENXIO instead of following the symlink to its target.
Reproducer script (MNT is an NFSv3 mount, kernel is 7.1-rc6):
MNT=/mnt/export
ln -sf /tmp/target $MNT/mylink
echo 3 | sudo tee /proc/sys/vm/drop_caches # cold dcache
python3 - <<'EOF'
import os
fd = os.open('/mnt/export/mylink', os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0o666) os.close(fd)
EOF
Expected: success (follow symlink, open target) Actual: OSError: [Errno 6] No such device or address
The bug does not trigger when the dcache is warm (e.g. after a prior stat(2)), because lookup_open() then finds a positive dentry and skips atomic_open entirely, leaving symlink resolution to the VFS.
Root cause:nfs_atomic_open_v23(), registered as inode->i_op->atomic_open for NFSv3, handles O_CREAT by sending a CREATE UNCHECKED RPC. As implemented in nfsd3_create_file() (fs/nfsd/nfs3proc.c) and as required by RFC 1813 (3.3.8), when the name already exists as a non-regular file the server returns NFS3_OK with the existing object's file handle rather than NFS3ERR_EXIST causing nfs_do_create() to return 0 with the dentry now pointing to a symlink.
The code then unconditionally calls finish_open(), which dispatches through inode->i_fop->open(). Symlink inodes never have i_fop set — the VFS initialises it to &no_open_fops because POSIX requires open(2) to follow symlinks, never open them directly. no_open() returns -ENXIO.
Fix:
After nfs_do_create() succeeds, verify the returned inode is a regular file before calling finish_open(). If the object is not regular, return finish_no_open(file, NULL) so the VFS follows the symlink through the normal open path. NULL is passed because nfs_do_create() instantiates the inode on the dentry already owned by the caller; passing dentry back would cause atomic_open() to dput() it a second time. !S_ISREG() is used rather than S_ISLNK() to cover any other non-regular types a server might return.
Changes in v2:
- Pass NULL to finish_no_open() per Trond's feedback.
--- fs/nfs/dir.c | 7 +++++++ 1 file changed, 7 insertions(+)
fs/nfs/dir.c +7 -0
@@ -2287,6 +2287,13 @@ int nfs_atomic_open_v23(struct inode *dir, struct dentry *dentry,if (open_flags &O_CREAT ) { error =nfs_do_create (dir, dentry, mode, open_flags);if (!error) { +/* With UNCHECKED mode, a server may return NFS3_OK for +* a pre-existing non-regular file (e.g. a symlink). +* Let the VFS handle it; calling finish_open() would +* hit no_open() and return -ENXIO. +*/ +if (!d_is_reg (dentry)) +return finish_no_open (file,NULL ); file->f_mode |=FMODE_CREATED ;return finish_open (file, dentry,NULL ); }else if (error != -EEXIST || open_flags &O_EXCL )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1186/1376 clk: devres: fix cleanup in devm_clk_get_optional_enabled_with_rate()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Onur Özkan <[email protected]>
[ Upstream commit 0d4d262c1664365e17e0a5ba2ab79f4db484b44e ]
devm_clk_get_optional_enabled_with_rate() registers its cleanup action before setting the clock rate. If setting the rate fails, it attempts to disable and unprepare a clock that was never enabled. This issue was spotted while reviewing "rust: clk: add devres-managed clks" [1].
Register the cleanup action only after successfully preparing and enabling the clock.
[1]: https://lore.kernel.org/rust-for-linux/[email protected]
--- drivers/clk/clk-devres.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/clk/clk-devres.c +10 -2
@@ -99,6 +99,11 @@ struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id) }EXPORT_SYMBOL_GPL (devm_clk_get_optional_enabled); +static void devm_clk_disable_unprepare (void *data) +{ +clk_disable_unprepare (data); +} +struct clk *devm_clk_get_optional_enabled_with_rate (struct device *dev,const char *id,unsigned long rate)
@@ -106,8 +111,7 @@ struct clk *devm_clk_get_optional_enabled_with_rate(struct device *dev,struct clk *clk;int ret; - clk =__devm_clk_get (dev, id, clk_get_optional,NULL , - clk_disable_unprepare); + clk =devm_clk_get_optional (dev, id);if (IS_ERR (clk))return ERR_CAST (clk);
@@ -119,6 +123,10 @@ struct clk *devm_clk_get_optional_enabled_with_rate(struct device *dev,if (ret) goto out_put_clk; + ret =devm_add_action_or_reset (dev, devm_clk_disable_unprepare, clk); +if (ret) + goto out_put_clk; +return clk; out_put_clk:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1187/1376 clk: ti: use kcalloc() instead of kzalloc()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ethan Carter Edwards <[email protected]>
[ Upstream commit de517118c5d3482411fd88141093fa838bc0af77 ]
Use 2-factor multiplication argument form kcalloc() instead of kzalloc().
Stable-dep-of: 667f420c09f1 ("clk: ti: mux: resolve parent clocks by DT index, not by name")
--- drivers/clk/ti/mux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/ti/mux.c +1 -1
@@ -180,7 +180,7 @@ static void of_mux_clk_setup(struct device_node *node)pr_err ("mux-clock %pOFn must have parents\n" , node);return ; } - parent_names =kzalloc ((sizeof (char *) * num_parents),GFP_KERNEL ); + parent_names =kcalloc (num_parents,sizeof (char *),GFP_KERNEL );if (!parent_names) goto cleanup;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1188/1376 clk: ti: mux: resolve parent clocks by DT index, not by name
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mathieu Dubois-Briand <[email protected]>
[ Upstream commit 667f420c09f1417c9f07798e32432c901915209d ]
Resolve parent clocks by their index into the device tree "clocks" property rather than matching names as strings. Name-based matching is fragile because a clock's "clock-output-names" value in its provider node can differ from the name used to reference it in a consumer node, and because names must be globally unique across all clock providers.
On AM335x, this caused broken clock trees where some clocks failed to enable because their parents could not be found.
Replace of_clk_parent_fill() with a clk_parent_data array that sets .index to the array position.
--- drivers/clk/ti/mux.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-)
drivers/clk/ti/mux.c +11 -9
@@ -119,7 +119,7 @@ const struct clk_ops ti_clk_mux_ops = { };static struct clk *_register_mux (struct device_node *node,const char *name, -const char *const *parent_names, +const struct clk_parent_data *parent_data,u8 num_parents,unsigned long flags,struct clk_omap_reg *reg,u8 shift,u32 mask,s8 latch,u8 clk_mux_flags,u32 *table)
@@ -136,7 +136,7 @@ static struct clk *_register_mux(struct device_node *node, const char *name, init.name = name; init.ops = &ti_clk_mux_ops; init.flags = flags; - init.parent_names = parent_names; + init.parent_data = parent_data; init.num_parents = num_parents;/* struct clk_mux assignments */
@@ -167,24 +167,26 @@ static void of_mux_clk_setup(struct device_node *node)struct clk *clk;struct clk_omap_reg reg;unsigned int num_parents; -const char **parent_names; +struct clk_parent_data *parent_data;const char *name;u8 clk_mux_flags =0 ;u32 mask =0 ;u32 shift =0 ;s32 latch = -EINVAL ;u32 flags =CLK_SET_RATE_NO_REPARENT ; +int i; num_parents =of_clk_get_parent_count (node);if (num_parents <2 ) {pr_err ("mux-clock %pOFn must have parents\n" , node);return ; } - parent_names =kcalloc (num_parents,sizeof (char *),GFP_KERNEL ); -if (!parent_names) - goto cleanup; + parent_data =kcalloc (num_parents,sizeof (*parent_data),GFP_KERNEL ); +if (!parent_data) +return ; -of_clk_parent_fill (node, parent_names, num_parents); +for (i =0 ; i < num_parents; i++) + parent_data[i].index = i;if (ti_clk_get_reg_addr (node,0 , ®)) goto cleanup;
@@ -207,7 +209,7 @@ static void of_mux_clk_setup(struct device_node *node) mask = (1 <<fls (mask)) -1 ; name =ti_dt_clk_name (node); - clk =_register_mux (node, name, parent_names, num_parents, + clk =_register_mux (node, name, parent_data, num_parents, flags, ®, shift, mask, latch, clk_mux_flags,NULL );
@@ -215,7 +217,7 @@ static void of_mux_clk_setup(struct device_node *node)of_clk_add_provider (node, of_clk_src_simple_get, clk); cleanup: -kfree (parent_names); +kfree (parent_data); }CLK_OF_DECLARE (mux_clk,"ti,mux-clock" , of_mux_clk_setup);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1189/1376 octeontx2-af: initialize lmac_bmap in rvu_mcs_set_lmac_bmap()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 4b92a3710d4a1d850ed6421c773e735cdca69b07 ]
rvu_mcs_set_lmac_bmap() declares lmac_bmap without initializing it and only sets bits for valid lmacs with set_bit(), which ORs into the word without clearing it first. Bits for invalid or skipped ports keep whatever was on the stack, and the garbage is stored into mcs->hw->lmac_bmap.
Initialize lmac_bmap to 0 so only valid lmacs are marked.
Found with Clang's -Wconditional-uninitialized.
--- drivers/net/ethernet/marvell/octeontx2/af/mcs_rvu_if.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/marvell/octeontx2/af/mcs_rvu_if.c +1 -1
@@ -854,7 +854,7 @@ int rvu_mbox_handler_mcs_ctrl_pkt_rule_write(struct rvu *rvu,static void rvu_mcs_set_lmac_bmap (struct rvu *rvu) {struct mcs *mcs =mcs_get_pdata (0 ); -unsigned long lmac_bmap; +unsigned long lmac_bmap =0 ;int cgx, lmac, port;for (port =0 ; port < mcs->hw->lmac_cnt; port++) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1190/1376 drm/xe: tests: fix error message in xe_migrate_sanity_test()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
[ Upstream commit 3d318fe4e99a627aa3c2980699e2e9f13ad18516 ]
This is supposed to print the error code but there is a copy and paste bug so it prints "bo" instead of "err".
--- drivers/gpu/drm/xe/tests/xe_migrate.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/gpu/drm/xe/tests/xe_migrate.c +1 -2
@@ -194,8 +194,7 @@ static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test) err =xe_bo_vmap (bo);if (err) { -KUNIT_FAIL (test,"Failed to vmap our pagetables: %li\n" , -PTR_ERR (bo)); +KUNIT_FAIL (test,"Failed to vmap our pagetables: %d\n" , err);return ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1191/1376 ionic: fix completion descriptor access with 2x desc size
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Prabu Thayalan <[email protected]>
[ Upstream commit 5da6ec6f06f235166bd084466b3386c638e26675 ]
The old ionic_rx_service() and ionic_tx_service() used array indexing to access completion descriptors:
comp = &((struct ionic_rxq_comp *)cq->base)[cq->tail_idx];
This assumes the stride is sizeof(struct ionic_rxq_comp) = 16 bytes. However, when the IONIC_Q_F_2X_CQ_DESC flag is set, the actual completion descriptor size is 32 bytes (2 * sizeof(comp)), and the completion itself is located at the end of that 32-byte slot. Array indexing with a 16-byte stride would access the wrong offset.
Use pointer arithmetic that accounts for the actual descriptor size from cq->desc_size:
comp = cq->base +
cq->desc_size * cq->tail_idx +
cq->desc_size - sizeof(*comp);This correctly calculates the completion location regardless of descriptor size. For the common case where desc_size equals sizeof(*comp), use array indexing in a likely() fast path to avoid performance regression.
--- .../net/ethernet/pensando/ionic/ionic_txrx.c | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-)
drivers/net/ethernet/pensando/ionic/ionic_txrx.c +14 -13
@@ -706,11 +706,7 @@ static void ionic_rx_clean(struct ionic_queue *q,__le64 *cq_desc_hwstamp;u64 hwstamp; - cq_desc_hwstamp = - (void *)comp + - qcq->cq.desc_size - -sizeof (struct ionic_rxq_comp ) - -IONIC_HWSTAMP_CQ_NEGOFFSET ; + cq_desc_hwstamp = (void *)comp -IONIC_HWSTAMP_CQ_NEGOFFSET ; hwstamp =le64_to_cpu (*cq_desc_hwstamp);
@@ -734,7 +730,12 @@ static bool __ionic_rx_service(struct ionic_cq *cq, struct bpf_prog *xdp_prog)struct ionic_queue *q = cq->bound_q;struct ionic_rxq_comp *comp; - comp = &((struct ionic_rxq_comp *)cq->base)[cq->tail_idx]; +if (likely (cq->desc_size ==sizeof (*comp))) + comp = &((struct ionic_rxq_comp *)cq->base)[cq->tail_idx]; +else + comp = cq->base + + cq->desc_size * cq->tail_idx + + cq->desc_size -sizeof (*comp);if (!color_match (comp->pkt_type_color, cq->done_color))return false;
@@ -1185,7 +1186,6 @@ static void ionic_tx_clean(struct ionic_queue *q, bool in_napi) {struct ionic_tx_stats *stats =q_to_tx_stats (q); -struct ionic_qcq *qcq =q_to_qcq (q);struct sk_buff *skb;if (desc_info->xdpf) {
@@ -1210,11 +1210,7 @@ static void ionic_tx_clean(struct ionic_queue *q,__le64 *cq_desc_hwstamp;u64 hwstamp; - cq_desc_hwstamp = - (void *)comp + - qcq->cq.desc_size - -sizeof (struct ionic_txq_comp ) - -IONIC_HWSTAMP_CQ_NEGOFFSET ; + cq_desc_hwstamp = (void *)comp -IONIC_HWSTAMP_CQ_NEGOFFSET ; hwstamp =le64_to_cpu (*cq_desc_hwstamp);
@@ -1249,7 +1245,12 @@ static bool ionic_tx_service(struct ionic_cq *cq,unsigned int pkts =0 ;u16 index; - comp = &((struct ionic_txq_comp *)cq->base)[cq->tail_idx]; +if (likely (cq->desc_size ==sizeof (*comp))) + comp = &((struct ionic_txq_comp *)cq->base)[cq->tail_idx]; +else + comp = cq->base + + cq->desc_size * cq->tail_idx + + cq->desc_size -sizeof (*comp);if (!color_match (comp->color, cq->done_color))return false;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1192/1376 net: kcm: Hold RCU read lock while running BPF parser
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junseo Lim <[email protected]>
[ Upstream commit b0346dd64e4905291cc9c479f2e6cf1884ced4e6 ]
kcm_parse_func_strparser() calls bpf_prog_run_pin_on_cpu() which prevents CPU migration, but does not establish an RCU read-side critical section. Consequently, BPF map operations can trigger WARN_ON_ONCE(!bpf_rcu_lock_held()) when called from the KCM strparser program.
Hold the RCU read lock while running the program.
--- net/kcm/kcmsock.c | 3 +++ 1 file changed, 3 insertions(+)
net/kcm/kcmsock.c +3 -0
@@ -5,6 +5,7 @@* Copyright (c) 2016 Tom Herbert <[email protected]> */ +#include <linux/rcupdate.h> #include <linux/bpf.h> #include <linux/errno.h> #include <linux/errqueue.h>
@@ -389,7 +390,9 @@ static int kcm_parse_func_strparser(struct strparser *strp, struct sk_buff *skb)struct bpf_prog *prog = psock->bpf_prog;int res; +rcu_read_lock (); res =bpf_prog_run_pin_on_cpu (prog, skb); +rcu_read_unlock ();return res; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1193/1376 net: dsa: b53: fix error propagation from b53_fdb_dump()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Oltean <[email protected]>
[ Upstream commit 4f1d06cf8aaa9d2cb18e5ee8835aff6177256bc6 ]
The blamed commit replaced "return ret" statements in b53_fdb_dump() with "break;" which jumps to the mutex_unlock() -> return 0 section.
This is notably problematic because it swallows errors from the b53_fdb_copy() -> cb() path, and this will result in FDB dump truncation when the netlink skb overflows - see commit 21b52fed928e ("net: dsa:
sja1105: fix broken backpressure in .port_fdb_dump").
Let's go back to "return ret". We don't need to preinitialize "ret" with 0, because the "do {} while" block guarantees we cannot reach the end of the function without at least once calling b53_arl_search_wait(), which will have initialized ret to some valid value.
--- drivers/net/dsa/b53/b53_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/dsa/b53/b53_common.c +1 -1
@@ -2020,7 +2020,7 @@ int b53_fdb_dump(struct dsa_switch *ds, int port,mutex_unlock (&priv->arl_mutex); -return 0 ; +return ret; }EXPORT_SYMBOL (b53_fdb_dump);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1194/1376 pppox: drain queued packets on channel handoff
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qingfang Deng <[email protected]>
[ Upstream commit 92c1bf630abf0af646562398eaa36f80b5ff677d ]
PPPIOCGCHAN both returns the channel index and marks a PPPOX socket as bound to generic PPP, despite its getter semantic. Packets received before that transition are queued on sk_receive_queue, but a bound socket is no longer readable. Such packets therefore remain queued until the socket is destroyed.
After marking a socket bound, wait for receive paths that observed the old state to finish queueing packets, and then drain the queue into generic PPP.
--- drivers/net/ppp/pppox.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
drivers/net/ppp/pppox.c +17 -0
@@ -74,7 +74,9 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)switch (cmd) {case PPPIOCGCHAN : { +struct sk_buff *skb;int index; + rc = -ENOTCONN ;if (!(sk->sk_state &PPPOX_CONNECTED ))break ;
@@ -85,7 +87,22 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)break ; rc =0 ; +/* PPPIOCGCHAN historically marks the userspace handoff to +* generic PPP; pppd then attaches the returned channel to +* /dev/ppp. +*/ sk->sk_state |=PPPOX_BOUND ; +/* Let lockless receive paths finish queueing against the old +* state. +*/ +synchronize_net (); +/* Drain packets queued before the handoff because a bound +* socket is no longer readable. +*/ +while ((skb =skb_dequeue (&sk->sk_receive_queue))) { +skb_orphan (skb); +ppp_input (&po->chan, skb); + }break ; }default :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1195/1376 net: hsr: free learned nodes on device setup failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Xie <[email protected]>
[ Upstream commit 7f16289b91eb316f170a6bd22d32e6c632f6a5b6 ]
hsr_dev_finalize() can fail after a lower-device RX handler has already been registered (slave A is added before the failable slave B and interlink adds). RX handlers run in softirq regardless of the master's state, so frames received in that window can learn dynamic nodes into node_db, and the error unwind never releases them.
Free both owned dynamic databases in the unwind, mirroring hsr_dellink(). proxy_node_db is provably empty on every current error exit (only interlink RX feeds it, and the interlink add is the last failable step) and is freed for symmetry. The order is safe:hsr_del_port() unregisters each RX handler with synchronize_net() before hsr_del_nodes() runs, which removes remaining entries with list_del_rcu() and defers their release with call_rcu() for readers already under RCU.
--- net/hsr/hsr_device.c | 2 ++ 1 file changed, 2 insertions(+)
net/hsr/hsr_device.c +2 -0
@@ -819,6 +819,8 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],hsr_del_ports (hsr); err_add_master:hsr_del_self_node (hsr); +hsr_del_nodes (&hsr->node_db); +hsr_del_nodes (&hsr->proxy_node_db);if (unregister)unregister_netdevice (hsr_dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1196/1376 f2fs: fix to parse temperature correctly in f2fs_get_segment_temp()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <[email protected]>
[ Upstream commit 9395fb09e897dcd96f601715e63018fc5c69cf03 ]
In __get_segment_type(), __get_segment_type_6() may return CURSEG_COLD_DATA_PINNED or CURSEG_ALL_DATA_ATGC log type, but following f2fs_get_segment_temp() can only handle persistent log type, fix it.
Stable-dep-of: 0a1703eba237 ("f2fs: fix to avoid pinfile fragment on fragment:{block, segment} mode")
--- fs/f2fs/f2fs.h | 5 +++-- fs/f2fs/file.c | 4 ++-- fs/f2fs/segment.c | 33 +++++++++++++++++++++++++-------- fs/f2fs/segment.h | 4 ---- 4 files changed, 30 insertions(+), 16 deletions(-)
fs/f2fs/f2fs.h +3 -2
@@ -1035,7 +1035,7 @@ static inline void set_new_dnode(struct dnode_of_data *dn, struct inode *inode,#define NR_CURSEG_PERSIST_TYPE (NR_CURSEG_DATA_TYPE + NR_CURSEG_NODE_TYPE)#define NR_CURSEG_TYPE (NR_CURSEG_INMEM_TYPE + NR_CURSEG_PERSIST_TYPE) -enum { +enum log_type {CURSEG_HOT_DATA =0 ,/* directory entry blocks */ CURSEG_WARM_DATA ,/* data blocks */ CURSEG_COLD_DATA ,/* multimedia or GCed data blocks */
@@ -3823,7 +3823,8 @@ void f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn, block_t old_addr, block_t new_addr, unsigned char version, bool recover_curseg, bool recover_newaddr); -int f2fs_get_segment_temp (int seg_type); +enum temp_type f2fs_get_segment_temp (struct f2fs_sb_info *sbi, +enum log_type seg_type); int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, block_t old_blkaddr, block_t *new_blkaddr, struct f2fs_summary *sum, int type,
fs/f2fs/file.c +2 -2
@@ -5022,8 +5022,8 @@ static void f2fs_dio_write_submit_io(const struct iomap_iter *iter, {struct inode *inode = iter->inode;struct f2fs_sb_info *sbi =F2FS_I_SB (inode); -int seg_type =f2fs_rw_hint_to_seg_type (sbi, inode->i_write_hint); -enum temp_type temp =f2fs_get_segment_temp (seg_type); +enum log_type type =f2fs_rw_hint_to_seg_type (sbi, inode->i_write_hint); +enum temp_type temp =f2fs_get_segment_temp (sbi, type); bio->bi_write_hint =f2fs_io_type_to_rw_hint (sbi,DATA , temp);submit_bio (bio);
fs/f2fs/segment.c +25 -8
@@ -3610,18 +3610,35 @@ static int __get_segment_type_6(struct f2fs_io_info *fio) } } -int f2fs_get_segment_temp (int seg_type) +enum temp_type f2fs_get_segment_temp (struct f2fs_sb_info *sbi, +enum log_type type) { -if (IS_HOT (seg_type)) -return HOT ; -else if (IS_WARM (seg_type)) -return WARM ; -return COLD ; +struct curseg_info *curseg =CURSEG_I (sbi, type); +enum temp_type temp =COLD ; + +switch (curseg->seg_type) { +case CURSEG_HOT_NODE : +case CURSEG_HOT_DATA : + temp =HOT ; +break ; +case CURSEG_WARM_NODE : +case CURSEG_WARM_DATA : + temp =WARM ; +break ; +case CURSEG_COLD_NODE : +case CURSEG_COLD_DATA : + temp =COLD ; +break ; +default : +f2fs_bug_on (sbi,1 ); + } + +return temp; }static int __get_segment_type (struct f2fs_io_info *fio) { -int type =0 ; +enum log_type type =CURSEG_HOT_DATA ;switch (F2FS_OPTION (fio->sbi).active_logs) {case 2 :
@@ -3637,7 +3654,7 @@ static int __get_segment_type(struct f2fs_io_info *fio)f2fs_bug_on (fio->sbi, true); } - fio->temp =f2fs_get_segment_temp (type); + fio->temp =f2fs_get_segment_temp (fio->sbi, type);return type; }
fs/f2fs/segment.h +0 -4
@@ -32,10 +32,6 @@ static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi,f2fs_bug_on (sbi, seg_type >=NR_PERSISTENT_LOG ); } -#define IS_HOT (t) ((t) == CURSEG_HOT_NODE || (t) == CURSEG_HOT_DATA) -#define IS_WARM (t) ((t) == CURSEG_WARM_NODE || (t) == CURSEG_WARM_DATA) -#define IS_COLD (t) ((t) == CURSEG_COLD_NODE || (t) == CURSEG_COLD_DATA) -#define IS_CURSEG (sbi, seg) \ (((seg) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno) || \ ((seg) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno) || \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1197/1376 f2fs:Fix incomplete search range in f2fs_get_victim when f2fs_need_rand_seg is enabled
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: liujinbao1 <[email protected]>
[ Upstream commit 5604129b6504c2d6dfbc02515c43e6186a1285e7 ]
During the f2fs_get_victim process, when the f2fs_need_rand_seg is enabled in select_policy, p->offset is a random value, and the search range is from p->offset to MAIN_SECS. When segno >= last_segment, the loop breaks and exits directly without searching the range from 0 to p->offset.This results in an incomplete search when the random offset is not zero.
Stable-dep-of: 0a1703eba237 ("f2fs: fix to avoid pinfile fragment on fragment:{block, segment} mode")
--- fs/f2fs/gc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/f2fs/gc.c +3 -2
@@ -317,10 +317,11 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type, p->max_search = sbi->max_victim_search;/* let's select beginning hot/small space first. */ -if (f2fs_need_rand_seg (sbi)) +if (f2fs_need_rand_seg (sbi)) { p->offset =get_random_u32_below (MAIN_SECS (sbi) *SEGS_PER_SEC (sbi)); -else if (type ==CURSEG_HOT_DATA ||IS_NODESEG (type)) +SIT_I (sbi)->last_victim[p->gc_mode] = p->offset; + }else if (type ==CURSEG_HOT_DATA ||IS_NODESEG (type)) p->offset =0 ;else p->offset =SIT_I (sbi)->last_victim[p->gc_mode];
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1198/1376 f2fs: cleanup w/ f2fs_need_rand_{blk, seg, seg_blk}
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <[email protected]>
[ Upstream commit 6da62bbde487d4678702ef004a911cd1c7a5c746 ]
No logic changes.
Stable-dep-of: 0a1703eba237 ("f2fs: fix to avoid pinfile fragment on fragment:{block, segment} mode")
--- fs/f2fs/f2fs.h | 13 +++++++++++-- fs/f2fs/gc.c | 2 +- fs/f2fs/segment.c | 8 ++++---- fs/f2fs/super.c | 4 ++-- 4 files changed, 18 insertions(+), 9 deletions(-)
fs/f2fs/f2fs.h +11 -2
@@ -3858,10 +3858,19 @@ unsigned int f2fs_usable_blks_in_seg(struct f2fs_sb_info *sbi,#define MIN_FRAGMENT_SIZE 1#define MAX_FRAGMENT_SIZE 512 +static inline bool f2fs_need_rand_blk (struct f2fs_sb_info *sbi) +{ +return F2FS_OPTION (sbi).fs_mode ==FS_MODE_FRAGMENT_BLK ; +} +static inline bool f2fs_need_rand_seg (struct f2fs_sb_info *sbi) { -return F2FS_OPTION (sbi).fs_mode ==FS_MODE_FRAGMENT_SEG || -F2FS_OPTION (sbi).fs_mode ==FS_MODE_FRAGMENT_BLK ; +return F2FS_OPTION (sbi).fs_mode ==FS_MODE_FRAGMENT_SEG ; +} + +static inline bool f2fs_need_rand_seg_blk (struct f2fs_sb_info *sbi) +{ +return f2fs_need_rand_blk (sbi) ||f2fs_need_rand_seg (sbi); }/*
fs/f2fs/gc.c +1 -1
@@ -317,7 +317,7 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type, p->max_search = sbi->max_victim_search;/* let's select beginning hot/small space first. */ -if (f2fs_need_rand_seg (sbi)) { +if (f2fs_need_rand_seg_blk (sbi)) { p->offset =get_random_u32_below (MAIN_SECS (sbi) *SEGS_PER_SEC (sbi));SIT_I (sbi)->last_victim[p->gc_mode] = p->offset;
fs/f2fs/segment.c +4 -4
@@ -2843,7 +2843,7 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type)sanity_check_seg_type (sbi, seg_type);if (__is_large_section (sbi)) { -if (f2fs_need_rand_seg (sbi)) { +if (f2fs_need_rand_seg_blk (sbi)) {unsigned int hint =GET_SEC_FROM_SEG (sbi, curseg->segno);if (GET_SEC_FROM_SEG (sbi, curseg->segno +1 ) != hint)
@@ -2852,7 +2852,7 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type) GET_SEG_FROM_SEC(sbi, hint + 1) - 1); }return curseg->segno; - }else if (f2fs_need_rand_seg (sbi)) { + }else if (f2fs_need_rand_seg_blk (sbi)) {return get_random_u32_below (MAIN_SECS (sbi) *SEGS_PER_SEC (sbi)); }
@@ -2908,7 +2908,7 @@ static int new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec) curseg->next_segno = segno;reset_curseg (sbi, type,1 ); curseg->alloc_type =LFS ; -if (F2FS_OPTION (sbi).fs_mode ==FS_MODE_FRAGMENT_BLK ) +if (f2fs_need_rand_blk (sbi)) curseg->fragment_remained_chunk =get_random_u32_inclusive (1 , sbi->max_fragment_chunk);return 0 ;
@@ -3712,7 +3712,7 @@ int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, curseg->next_blkoff =f2fs_find_next_ssr_block (sbi, curseg); }else { curseg->next_blkoff++; -if (F2FS_OPTION (sbi).fs_mode ==FS_MODE_FRAGMENT_BLK ) +if (f2fs_need_rand_blk (sbi))f2fs_randomize_chunk (sbi, curseg); }if (curseg->next_blkoff >=f2fs_usable_blks_in_seg (sbi, curseg->segno))
fs/f2fs/super.c +2 -2
@@ -2059,9 +2059,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)seq_puts (seq,"adaptive" ); else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_LFS) seq_puts(seq, "lfs"); - else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_SEG) + else if (f2fs_need_rand_seg(sbi)) seq_puts(seq, "fragment:segment"); - else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK) + else if (f2fs_need_rand_blk(sbi)) seq_puts(seq, "fragment:block"); seq_printf(seq, ",active_logs=%u", F2FS_OPTION(sbi).active_logs); if (test_opt(sbi, RESERVE_ROOT))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1199/1376 f2fs: fix to avoid pinfile fragment on fragment:{block, segment} mode
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu <[email protected]>
[ Upstream commit 0a1703eba23707e3b2edfa2a2329352e7abc0ffa ]
pinfile fallocate() conflicts w/ mode=fragment:{block,segment} mount option, result in fragment blocks in pinfile, it violate semantics of pinfile introduced in commit f5a53edcf01e ("f2fs: support aligned pinned file").
mkfs.f2fs -f /dev/vdb
mount -t f2fs -o mode=fragment:block /dev/vdb /mnt/f2fs/ dd if=/dev/zero of=/mnt/f2fs/file bs=1M count=3900 sync
touch /mnt/f2fs/pinfilef2fs_io pinfile set /mnt/f2fs/pinfilef2fs_io fallocate 0 0 $((1024*1024*16)) /mnt/f2fs/pinfile syncf2fs_io fiemap 0 $((1024*1024*16)) /mnt/f2fs/pinfile
[Before]
fallocate failed: No space left on device
Fiemap: offset = 0 len = 16777216
logical addr. physical addr. length flags
0 0000000000000000 00000000d7200000 0000000000004000 00001000 1 0000000000004000 00000000d7207000 0000000000001000 00001000 2 0000000000005000 00000000d720c000 0000000000002000 00001000 3 0000000000007000 00000000d7211000 0000000000001000 00001000 4 0000000000008000 00000000d7214000 0000000000001000 00001000 5 0000000000009000 00000000d7218000 0000000000001000 00001000 6 000000000000a000 00000000d721d000 0000000000001000 00001000 7 000000000000b000 00000000d721f000 0000000000004000 00001000 ... 96 00000000000f1000 00000000d73e9000 0000000000004000 00001000 97 00000000000f5000 00000000d73f1000 0000000000003000 00001000 98 00000000000f8000 00000000d73f5000 0000000000004000 00001000 99 00000000000fc000 00000000d73fa000 0000000000001000 00001000 100 00000000000fd000 00000000d73ff000 0000000000001000 00001001
[After]
fallocated a file: i_size=16777216, i_blocks=32808
Fiemap: offset = 0 len = 16777216
logical addr. physical addr. length flags
0 0000000000000000 0000000018a00000 0000000000400000 00001000 1 0000000000400000 0000000019000000 0000000000400000 00001000 2 0000000000800000 0000000032400000 0000000000200000 00001000 3 0000000000a00000 0000000038000000 0000000000200000 00001000 4 0000000000c00000 0000000039c00000 0000000000200000 00001000 5 0000000000e00000 0000000044c00000 0000000000200000 00001001
Let's ignore mode=fragment:{block,segment} mount option while fallocate() on pinfile.
--- fs/f2fs/f2fs.h | 15 +++++++++++---- fs/f2fs/gc.c | 2 +- fs/f2fs/segment.c | 8 ++++---- fs/f2fs/super.c | 4 ++-- 4 files changed, 18 insertions(+), 11 deletions(-)
fs/f2fs/f2fs.h +11 -4
@@ -3858,19 +3858,26 @@ unsigned int f2fs_usable_blks_in_seg(struct f2fs_sb_info *sbi,#define MIN_FRAGMENT_SIZE 1#define MAX_FRAGMENT_SIZE 512 -static inline bool f2fs_need_rand_blk (struct f2fs_sb_info *sbi) +static inline bool f2fs_need_rand_blk (struct f2fs_sb_info *sbi, +enum log_type type) { +if (type ==CURSEG_COLD_DATA_PINNED ) +return false;return F2FS_OPTION (sbi).fs_mode ==FS_MODE_FRAGMENT_BLK ; } -static inline bool f2fs_need_rand_seg (struct f2fs_sb_info *sbi) +static inline bool f2fs_need_rand_seg (struct f2fs_sb_info *sbi, +enum log_type type) { +if (type ==CURSEG_COLD_DATA_PINNED ) +return false;return F2FS_OPTION (sbi).fs_mode ==FS_MODE_FRAGMENT_SEG ; } -static inline bool f2fs_need_rand_seg_blk (struct f2fs_sb_info *sbi) +static inline bool f2fs_need_rand_seg_blk (struct f2fs_sb_info *sbi, +enum log_type type) { -return f2fs_need_rand_blk (sbi) ||f2fs_need_rand_seg (sbi); +return f2fs_need_rand_blk (sbi, type) ||f2fs_need_rand_seg (sbi, type); }/*
fs/f2fs/gc.c +1 -1
@@ -317,7 +317,7 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type, p->max_search = sbi->max_victim_search;/* let's select beginning hot/small space first. */ -if (f2fs_need_rand_seg_blk (sbi)) { +if (f2fs_need_rand_seg_blk (sbi, type)) { p->offset =get_random_u32_below (MAIN_SECS (sbi) *SEGS_PER_SEC (sbi));SIT_I (sbi)->last_victim[p->gc_mode] = p->offset;
fs/f2fs/segment.c +4 -4
@@ -2843,7 +2843,7 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type)sanity_check_seg_type (sbi, seg_type);if (__is_large_section (sbi)) { -if (f2fs_need_rand_seg_blk (sbi)) { +if (f2fs_need_rand_seg_blk (sbi, type)) {unsigned int hint =GET_SEC_FROM_SEG (sbi, curseg->segno);if (GET_SEC_FROM_SEG (sbi, curseg->segno +1 ) != hint)
@@ -2852,7 +2852,7 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type) GET_SEG_FROM_SEC(sbi, hint + 1) - 1); }return curseg->segno; - }else if (f2fs_need_rand_seg_blk (sbi)) { + }else if (f2fs_need_rand_seg_blk (sbi, type)) {return get_random_u32_below (MAIN_SECS (sbi) *SEGS_PER_SEC (sbi)); }
@@ -2908,7 +2908,7 @@ static int new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec) curseg->next_segno = segno;reset_curseg (sbi, type,1 ); curseg->alloc_type =LFS ; -if (f2fs_need_rand_blk (sbi)) +if (f2fs_need_rand_blk (sbi, type)) curseg->fragment_remained_chunk =get_random_u32_inclusive (1 , sbi->max_fragment_chunk);return 0 ;
@@ -3712,7 +3712,7 @@ int f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, curseg->next_blkoff =f2fs_find_next_ssr_block (sbi, curseg); }else { curseg->next_blkoff++; -if (f2fs_need_rand_blk (sbi)) +if (f2fs_need_rand_blk (sbi, type))f2fs_randomize_chunk (sbi, curseg); }if (curseg->next_blkoff >=f2fs_usable_blks_in_seg (sbi, curseg->segno))
fs/f2fs/super.c +2 -2
@@ -2059,9 +2059,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)seq_puts (seq,"adaptive" ); else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_LFS) seq_puts(seq, "lfs"); - else if (f2fs_need_rand_seg(sbi)) + else if (f2fs_need_rand_seg(sbi, NO_CHECK_TYPE)) seq_puts(seq, "fragment:segment"); - else if (f2fs_need_rand_blk(sbi)) + else if (f2fs_need_rand_blk(sbi, NO_CHECK_TYPE)) seq_puts(seq, "fragment:block"); seq_printf(seq, ",active_logs=%u", F2FS_OPTION(sbi).active_logs); if (test_opt(sbi, RESERVE_ROOT))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1200/1376 ipvs: fix integer overflow in ftp helper port/address parsing
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joas Antonio dos Santos <[email protected]>
[ Upstream commit e625a9477d12baaff4025c5f9989184a907ea8fc ]
ip_vs_ftp_get_addrport() accumulates decimal digits into a __u16 (hport) and into unsigned char (p[]) without checking for overflow. A crafted FTP PASV/EPSV response with an over-long port or address octet wraps the value, so the helper configures the data connection with a truncated port/address.
The netfilter conntrack FTP helper had the same defect, fixed in commit 2b413fc689ba ("netfilter: nf_conntrack_ftp: avoid u16 overflows"). Apply the equivalent fix here: widen the port accumulator to u32 and reject values above 65535, and reject address octets above 255.
--- net/netfilter/ipvs/ip_vs_ftp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
net/netfilter/ipvs/ip_vs_ftp.c +8 -2
@@ -103,7 +103,7 @@ static int ip_vs_ftp_get_addrport(char *data, char *data_limit,char *s, c;unsigned char p[6 ];char edelim; -__u16 hport; +__u32 hport;int i =0 ;if (data_limit - data < plen) {
@@ -145,7 +145,11 @@ static int ip_vs_ftp_get_addrport(char *data, char *data_limit,return -1 ; c = *data;if (isdigit (c)) { - p[i] = p[i]*10 + c -'0' ; +unsigned int val = p[i] *10 + c -'0' ; + +if (val >255 ) +return -1 ; + p[i] = val; }else if (c ==',' && i <5 ) { i++; p[i] =0 ;
@@ -223,6 +227,8 @@ static int ip_vs_ftp_get_addrport(char *data, char *data_limit,if (!isdigit (*s))break ; hport = hport *10 + *s -'0' ; +if (hport >65535 ) +return -1 ; }if (s == data_limit || !hport || *s != edelim)return -1 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1201/1376 vxlan: vnifilter: enforce exact length of GROUP/GROUP6 attributes
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit 984f831dda31b3a18f47454cf64989f65402879e ]
The VXLAN VNI filter entry policy declares the GROUP/GROUP6 address attributes as NLA_BINARY with only a maximum length, so validate_nla() accepts a payload shorter than the address. The GROUP consumer reads it with nla_get_in_addr(), an unconditional 4-byte load, so a short attribute over-reads up to 3 bytes of uninitialised slab data, which are stored into remote_ip and echoed back via RTM_GETTUNNEL, disclosing kernel memory.
Switch both entries to NLA_POLICY_EXACT_LEN() so the validator rejects any GROUP/GROUP6 that is not exactly 4 / 16 bytes; a valid address is always sent at full width.
--- drivers/net/vxlan/vxlan_vnifilter.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/net/vxlan/vxlan_vnifilter.c +2 -4
@@ -467,10 +467,8 @@ static int vxlan_vnifilter_dump(struct sk_buff *skb, struct netlink_callback *cbstatic const struct nla_policy vni_filter_entry_policy[VXLAN_VNIFILTER_ENTRY_MAX +1 ] = { [VXLAN_VNIFILTER_ENTRY_START ] = { .type =NLA_U32 }, [VXLAN_VNIFILTER_ENTRY_END ] = { .type =NLA_U32 }, - [VXLAN_VNIFILTER_ENTRY_GROUP ] = { .type =NLA_BINARY , - .len = sizeof_field(struct iphdr, daddr) }, - [VXLAN_VNIFILTER_ENTRY_GROUP6 ] = { .type =NLA_BINARY , - .len =sizeof (struct in6_addr ) }, + [VXLAN_VNIFILTER_ENTRY_GROUP] = NLA_POLICY_EXACT_LEN(sizeof_field(struct iphdr, daddr)), + [VXLAN_VNIFILTER_ENTRY_GROUP6 ] =NLA_POLICY_EXACT_LEN (sizeof (struct in6_addr )), };static const struct nla_policy vni_filter_policy[VXLAN_VNIFILTER_MAX +1 ] = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1202/1376 net: dsa: mv88e6xxx: Fix PCS link check on CMODE read error
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit 7b196e27ad58e612ad1c04b347d0c2135045aa14 ]
mv88e6352_pcs_link_check() ignores errors returned by port_get_cmode(). If the port status register read fails, mv88e6352_port_get_cmode() returns without setting cmode. The link check then compares an uninitialized value and may incorrectly treat the PCS as active.
Save the return value and fail the link check after releasing the register lock. marvell_c22_pcs_get_state() initializes the reported link state to down before calling the check, so a read failure is handled safely until a later poll succeeds.
This issue was found by a static analysis checker and confirmed by manual source review.
--- drivers/net/dsa/mv88e6xxx/pcs-6352.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/dsa/mv88e6xxx/pcs-6352.c +4 -1
@@ -305,13 +305,16 @@ static bool mv88e6352_pcs_link_check(struct marvell_c22_pcs *mpcs)struct mv88e6xxx_port *port = mpcs->port;struct mv88e6xxx_chip *chip = port->chip;u8 cmode; +int err;/* Port 4 can be in auto-media mode. Check that the port is * associated with the mpcs. */ mv88e6xxx_reg_lock (chip); - chip->info->ops->port_get_cmode (chip, port->port, &cmode); + err = chip->info->ops->port_get_cmode (chip, port->port, &cmode);mv88e6xxx_reg_unlock (chip); +if (err) +return false;return cmode ==MV88E6XXX_PORT_STS_CMODE_100BASEX || cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX ||
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1203/1376 tls: fix RX desync on overlapping skbs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maximilian Immanuel Brandtner <[email protected]>
[ Upstream commit 9466ef3ec972bee926731a766f73533dec590065 ]
The TCP receive queue can hold adjacent skbs whose sequence ranges overlap. The tls fast-path reads the record header with skb_copy_bits() by byte offset, which assumes skbs do not overlap, so a header split across the overlap is misread and the connection aborts (-EMSGSIZE/-EINVAL). tls_strp_check_queue_ok() detects such overlaps but only ran after the header was parsed, never covering the header itself.
Observed with parallel kTLS connections on:
- ConnectX-7 + IPsec crypto offload + GRO
- VirtIO (8 queues) + GRO
--- net/tls/tls_strp.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
net/tls/tls_strp.c +11 -5
@@ -431,9 +431,10 @@ static int tls_strp_read_copy(struct tls_strparser *strp, bool qshort)return 0 ; } -static bool tls_strp_check_queue_ok (struct tls_strparser *strp) +static bool tls_strp_check_queue_ok (struct tls_strparser *strp, +unsigned int len) { -unsigned int len = strp->stm.offset + strp->stm.full_len; +unsigned int remaining = strp->stm.offset + len;struct sk_buff *first, *skb;u32 seq;
@@ -444,9 +445,9 @@ static bool tls_strp_check_queue_ok(struct tls_strparser *strp)/* Make sure there's no duplicate data in the queue, * and the decrypted status matches. */ -while (skb->len < len) { +while (skb->len < remaining) { seq += skb->len; - len -= skb->len; + remaining -= skb->len; skb = skb->next;if (TCP_SKB_CB (skb)->seq != seq)
@@ -525,6 +526,11 @@ static int tls_strp_read_sock(struct tls_strparser *strp)tls_strp_load_anchor_with_queue (strp, inq);if (!strp->stm.full_len) { +if (inq <TLS_HEADER_SIZE ) +return tls_strp_read_copy (strp, true); +if (!tls_strp_check_queue_ok (strp,TLS_HEADER_SIZE )) +return tls_strp_read_copy (strp, false); + sz =tls_rx_msg_size (strp, strp->anchor);if (sz <0 )return sz;
@@ -535,7 +541,7 @@ static int tls_strp_read_sock(struct tls_strparser *strp)return tls_strp_read_copy (strp, true); } -if (!tls_strp_check_queue_ok (strp)) +if (!tls_strp_check_queue_ok (strp, strp->stm.full_len))return tls_strp_read_copy (strp, false);WRITE_ONCE (strp->msg_ready,1 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1204/1376 net: bridge: vlan: fix inverted default vlan notification
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikolay Aleksandrov <[email protected]>
[ Upstream commit 21040c7f931502070dcc66bb0f1aeed07dec032b ]
A notification should be emitted only when the vlan delete was successful and not otherwise. The proper check is if br/nbp_vlan_delete returned 0.
--- net/bridge/br_vlan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/bridge/br_vlan.c +2 -2
@@ -1129,7 +1129,7 @@ int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid,if (err) goto out; -if (br_vlan_delete (br, old_pvid)) +if (!br_vlan_delete (br, old_pvid))br_vlan_notify (br,NULL , old_pvid,0 ,RTM_DELVLAN );br_vlan_notify (br,NULL , pvid,0 ,RTM_NEWVLAN );__set_bit (0 , changed);
@@ -1151,7 +1151,7 @@ int __br_vlan_set_default_pvid(struct net_bridge *br, u16 pvid, &vlchange, extack);if (err) goto err_port; -if (nbp_vlan_delete (p, old_pvid)) +if (!nbp_vlan_delete (p, old_pvid))br_vlan_notify (br, p, old_pvid,0 ,RTM_DELVLAN );br_vlan_notify (p->br, p, pvid,0 ,RTM_NEWVLAN );__set_bit (p->port_no, changed);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1205/1376 cuse: wait for pending RCU callbacks on module exit
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baokun Li <[email protected]>
[ Upstream commit 4deb3edead0c0e172cc7349e8855d741d3c5e162 ]
Since commit 053fc4f755ad ("fuse: fix UAF in rcu pathwalks"), fuse_conn_put() frees the fuse_conn through call_rcu() rather than synchronously. For cuse, fc->release is cuse_fc_release(), which lives in the cuse module. If the module is removed before the RCU grace period ends, the callback jumps into freed module memory:
userspace / module unload | RCU softirq
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
close(/dev/cuse) |
cuse_channel_release() |
fuse_dev_release() |
fuse_conn_put(fch->conn) |
call_rcu(delayed_release) ------+---> callback queued
|
rmmod cuse |
cuse_exit() |
cuse_channel_destroy() |
... |
return |
|
<module text freed> |
| rcu_do_batch()
| delayed_release()
| fc->release()
| -> cuse_fc_release()
| ^^^ freed text!The freed module text is unmapped by vfree(), so the jump into the stale callback triggers a page-fault Oops. If the virtual address is subsequently reused, the callback could execute unrelated code (undefined behaviour).
Fix this by calling rcu_barrier() in cuse_exit() so that any pending fuse_conn release callback completes before the module is removed.
--- fs/fuse/cuse.c | 5 +++++ 1 file changed, 5 insertions(+)
fs/fuse/cuse.c +5 -0
@@ -647,6 +647,11 @@ static void __exit cuse_exit(void) {misc_deregister (&cuse_miscdev);class_destroy (cuse_class); +/* +* Wait for pending call_rcu() callbacks that call back into +* this module via fc->release (cuse_fc_release). +*/ +rcu_barrier (); }module_init (cuse_init);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1206/1376 fs/ntfs3: fix out-of-bounds read in read_log_rec_buf()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Komarov <[email protected]>
[ Upstream commit de603b9d377fab57a5e6432fa84a9f36b32c1636 ]
read_log_rec_buf() copies a log record into a caller buffer starting at
u32 off = lsn_to_page_off(log, lsn) + log->record_header_len;
log->record_header_len (and log->data_off, used for the following pages) comes verbatim from the on-disk restart area and is only checked for 8-byte alignment in is_rst_area_valid(), so off can exceed log->page_size. "tail = log->page_size - off" then underflows and memcpy() reads past the page_size-sized buffer returned by read_log_page(), spilling adjacent slab memory into the replay buffer.
This is reachable by mounting a crafted NTFS image:
BUG: KASAN: slab-out-of-bounds in read_log_rec_buf+0x216/0x580 Read of size 64 at addr ffff88800a877ff8 by task exploit/127 read_log_rec_buf fs/ntfs3/fslog.c:2299 log_replay fs/ntfs3/fslog.c:4216 ntfs_loadlog_and_replay fs/ntfs3/fsntfs.c:324 ntfs_fill_super fs/ntfs3/super.c:1392 get_tree_bdev_flags fs/super.c:1694 __x64_sys_mount fs/namespace.c:4360 The buggy address is located 4088 bytes to the right of the 4096-byte region [ffff88800a876000, ffff88800a877000)
Reject an in-page offset outside the current page before the copy.
--- fs/ntfs3/fslog.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
fs/ntfs3/fslog.c +9 -1
@@ -2299,7 +2299,15 @@ static int read_log_rec_buf(struct ntfs_log *log,*/ for (;;) {bool usa_error; -u32 tail = log->page_size - off; +u32 tail; + +/* off comes from the on-disk restart area; bound it. */ +if (off > log->page_size) { + err = -EINVAL ; + goto out; + } + + tail = log->page_size - off;if (tail >= data_len) tail = data_len;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1207/1376 fs/ntfs3: validate ef->size covers the records name and value
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit c22f91d82cb9a29d22bdffdce6c803467984ad0c ]
When an EA record has a non-zero ef->size, ntfs_read_ea() only checks that the record fits in the remaining buffer (ea_size > bytes), not that ef->size is large enough to hold the record's own name_len + 1 + elength.
A crafted image can pass validation with, e.g., ef->size = 24 but elength = 0xffff. ntfs_get_ea() then trusts elength and copies it out of the undersized record, reading past the kmalloc(info->size) allocation and leaking heap memory to userspace via getxattr():
BUG: KASAN: slab-out-of-bounds in ntfs_get_ea (fs/ntfs3/xattr.c:302) Read of size 65535 at addr ffff888100794550 by task exploit __asan_memcpy (mm/kasan/shadow.c:105) ntfs_get_ea (fs/ntfs3/xattr.c:302) ntfs_getxattr (fs/ntfs3/xattr.c:848) __vfs_getxattr (fs/xattr.c:441) vfs_getxattr (fs/xattr.c:474) do_getxattr (fs/xattr.c:800) path_getxattrat (fs/xattr.c:868) do_syscall_64 (arch/x86/entry/syscall_64.c:94)
The buggy address is located 80 bytes inside of
allocated 84-byte region in cache kmalloc-96
Compute the size the record needs and require ef->size to cover it.
--- fs/ntfs3/xattr.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-)
fs/ntfs3/xattr.c +12 -9
@@ -146,26 +146,29 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,for (off =0 ; off < size; off += ea_size) {const struct EA_FULL *ef =Add2Ptr (ea_p, off);u32 bytes = size - off; +size_t need;/* Check if we can use field ea->size. */ if (bytes <sizeof (ef->size)) goto out1; +/* Check if we can use fields ef->name_len and ef->elength. */ +if (bytes < offsetof(struct EA_FULL , name)) + goto out1; + +/* Size needed to hold this record's name and value. */ + need =struct_size (ef, name, +1 + ef->name_len +le16_to_cpu (ef->elength)); +if (ef->size) { ea_size =le32_to_cpu (ef->size); -if (ea_size > bytes) +/* ef->size must fit the list and cover the record. */ +if (ea_size > bytes || ea_size < need) goto out1;continue ; } -/* Check if we can use fields ef->name_len and ef->elength. */ -if (bytes < offsetof(struct EA_FULL , name)) - goto out1; - - ea_size =ALIGN (struct_size (ef, name, -1 + ef->name_len + -le16_to_cpu (ef->elength)), -4 ); + ea_size =ALIGN (need,4 );if (ea_size > bytes) goto out1; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1208/1376 fuse: support folios in struct fuse_args_pages and fuse_copy_pages()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joanne Koong <[email protected]>
[ Upstream commit a669c2df36db5fa7a2674ec5ae10548760702f99 ]
This adds support in struct fuse_args_pages and fuse_copy_pages() for using folios instead of pages for transferring data. Both folios and pages must be supported right now in struct fuse_args_pages and fuse_copy_pages() until all request types have been converted to use folios. Once all have been converted, then
struct fuse_args_pages and fuse_copy_pages() will only support folios.
Right now in fuse, all folios are one page (large folios are not yet supported). As such, copying folio->page is sufficient for copying the entire folio in fuse_copy_pages().
No functional changes.
Stable-dep-of: 928f659a3e36 ("fuse: check for NULL root inode in fuse_fill_super_submount")
--- fs/fuse/dev.c | 40 ++++++++++++++++++++++++++++++++-------- fs/fuse/fuse_i.h | 22 +++++++++++++++++++--- 2 files changed, 51 insertions(+), 11 deletions(-)
fs/fuse/dev.c +32 -8
@@ -1023,17 +1023,41 @@ static int fuse_copy_pages(struct fuse_copy_state *cs, unsigned nbytes,struct fuse_req *req = cs->req;struct fuse_args_pages *ap =container_of (req->args,typeof (*ap), args); +if (ap->uses_folios) { +for (i =0 ; i < ap->num_folios && (nbytes || zeroing); i++) { +int err; +unsigned int offset = ap->folio_descs[i].offset; +unsigned int count =min (nbytes, ap->folio_descs[i].length); +struct page *orig, *pagep; -for (i =0 ; i < ap->num_pages && (nbytes || zeroing); i++) { -int err; -unsigned int offset = ap->descs[i].offset; -unsigned int count =min (nbytes, ap->descs[i].length); + orig = pagep = &ap->folios[i]->page; - err =fuse_copy_page (cs, &ap->pages[i], offset, count, zeroing); -if (err) -return err; + err =fuse_copy_page (cs, &pagep, offset, count, zeroing); +if (err) +return err; + + nbytes -= count; + +/* +* fuse_copy_page may have moved a page from a pipe +* instead of copying into our given page, so update +* the folios if it was replaced. +*/ +if (pagep != orig) + ap->folios[i] =page_folio (pagep); + } + }else { +for (i =0 ; i < ap->num_pages && (nbytes || zeroing); i++) { +int err; +unsigned int offset = ap->descs[i].offset; +unsigned int count =min (nbytes, ap->descs[i].length); - nbytes -= count; + err =fuse_copy_page (cs, &ap->pages[i], offset, count, zeroing); +if (err) +return err; + + nbytes -= count; + } }return 0 ; }
fs/fuse/fuse_i.h +19 -3
@@ -291,6 +291,12 @@ struct fuse_page_desc {unsigned int offset; }; +/** FUSE folio descriptor */ +struct fuse_folio_desc { +unsigned int length; +unsigned int offset; +}; +struct fuse_args {uint64_t nodeid;uint32_t opcode;
@@ -319,9 +325,19 @@ struct fuse_args {struct fuse_args_pages {struct fuse_args args; -struct page **pages; -struct fuse_page_desc *descs; -unsigned int num_pages; +union { +struct { +struct page **pages; +struct fuse_page_desc *descs; +unsigned int num_pages; + }; +struct { +struct folio **folios; +struct fuse_folio_desc *folio_descs; +unsigned int num_folios; + }; + }; +bool uses_folios; };struct fuse_release_args {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1209/1376 fuse: convert readdir to use folios
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joanne Koong <[email protected]>
[ Upstream commit 02b78c7a7a0c72aee6f600a167e6adee9417ac0e ]
Convert readdir requests to use a folio instead of a page.
No functional changes.
Stable-dep-of: 928f659a3e36 ("fuse: check for NULL root inode in fuse_fill_super_submount")
--- fs/fuse/readdir.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-)
fs/fuse/readdir.c +11 -10
@@ -335,24 +335,25 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx) {int plus;ssize_t res; -struct page *page; +struct folio *folio;struct inode *inode =file_inode (file);struct fuse_mount *fm =get_fuse_mount (inode);struct fuse_io_args ia = {};struct fuse_args_pages *ap = &ia.ap; -struct fuse_page_desc desc = { .length =PAGE_SIZE }; +struct fuse_folio_desc desc = { .length =PAGE_SIZE };u64 attr_version =0 ;bool locked; - page =alloc_page (GFP_KERNEL ); -if (!page) + folio =folio_alloc (GFP_KERNEL ,0 ); +if (!folio)return -ENOMEM ; plus =fuse_use_readdirplus (inode, ctx); ap->args.out_pages = true; - ap->num_pages =1 ; - ap->pages = &page; - ap->descs = &desc; + ap->uses_folios = true; + ap->num_folios =1 ; + ap->folios = &folio; + ap->folio_descs = &desc;if (plus) { attr_version =fuse_get_attr_version (fm->fc); fuse_read_args_fill(&ia, file, ctx->pos, PAGE_SIZE,
@@ -371,15 +372,15 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx)if (ff->open_flags &FOPEN_CACHE_DIR )fuse_readdir_cache_end (file, ctx->pos); }else if (plus) { - res =parse_dirplusfile (page_address (page), res, + res =parse_dirplusfile (folio_address (folio), res, file, ctx, attr_version); }else { - res =parse_dirfile (page_address (page), res, file, + res =parse_dirfile (folio_address (folio), res, file, ctx); } } -__free_page (page); +folio_put (folio);fuse_invalidate_atime (inode);return res; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1210/1376 fuse: check attributes staleness on fuse_iget()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhang Tianci <[email protected]>
[ Upstream commit 69eb56f69efb866c791cc87fd7bf62adf2ffcbb3 ]
Function fuse_direntplus_link() might call fuse_iget() to initialize a new fuse_inode and change its attributes. If fi->attr_version is always initialized with 0, even if the attributes returned by the FUSE_READDIR request is staled, as the new fi->attr_version is 0, fuse_change_attributes will still set the staled attributes to inode. This wrong behaviour may cause file size inconsistency even when there is no changes from server-side.
To reproduce the issue, consider the following 2 programs (A and B) are running concurrently,
A B
---------------------------------- --------------------------------
{ /fusemnt/dir/f is a file path in a fuse mount, the size of f is 0. }
readdir(/fusemnt/dir) start
//Daemon set size 0 to f direntry
fallocate(f, 1024)
stat(f) // B see size 1024
echo 2 > /proc/sys/vm/drop_cachesreaddir(/fusemnt/dir) reply to kernel
Kernel set 0 to the I_NEW inode
stat(f) // B see size 0
In the above case, only program B is modifying the file size, however, B observes file size changing between the 2 'readonly' stat() calls. To fix this issue, we should make sure readdirplus still follows the rule of attr_version staleness checking even if the fi->attr_version is lost due to inode eviction.
To identify this situation, the new fc->evict_ctr is used to record whether the eviction of inodes occurs during the readdirplus request processing. If it does, the result of readdirplus may be inaccurate; otherwise, the result of readdirplus can be trusted. Although this may still lead to incorrect invalidation, considering the relatively low frequency of evict occurrences, it should be acceptable.
Stable-dep-of: 928f659a3e36 ("fuse: check for NULL root inode in fuse_fill_super_submount")
--- fs/fuse/dir.c | 11 +++++----- fs/fuse/fuse_i.h | 14 ++++++++++-- fs/fuse/inode.c | 56 +++++++++++++++++++++++++++++++++++++---------- fs/fuse/readdir.c | 15 ++++++++----- 4 files changed, 71 insertions(+), 25 deletions(-)
fs/fuse/dir.c +6 -5
@@ -366,7 +366,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *namestruct fuse_mount *fm =get_fuse_mount_super (sb);FUSE_ARGS (args);struct fuse_forget_link *forget; -u64 attr_version; +u64 attr_version, evict_ctr;int err; *inode =NULL ;
@@ -381,6 +381,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name goto out; attr_version =fuse_get_attr_version (fm->fc); + evict_ctr =fuse_get_evict_ctr (fm->fc);fuse_lookup_init (fm->fc, &args, nodeid, name, outarg); err =fuse_simple_request (fm, &args);
@@ -398,7 +399,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name *inode =fuse_iget (sb, outarg->nodeid, outarg->generation, &outarg->attr,ATTR_TIMEOUT (outarg), - attr_version); + attr_version, evict_ctr); err = -ENOMEM ;if (!*inode) {fuse_queue_forget (fm->fc, forget, outarg->nodeid,1 );
@@ -691,7 +692,7 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir, ff->nodeid = outentry.nodeid; ff->open_flags = outopenp->open_flags; inode =fuse_iget (dir->i_sb, outentry.nodeid, outentry.generation, - &outentry.attr,ATTR_TIMEOUT (&outentry),0 ); + &outentry.attr,ATTR_TIMEOUT (&outentry),0 ,0 );if (!inode) { flags &= ~(O_CREAT |O_EXCL |O_TRUNC );fuse_sync_release (NULL , ff, flags);
@@ -822,7 +823,7 @@ static int create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, goto out_put_forget_req; inode =fuse_iget (dir->i_sb, outarg.nodeid, outarg.generation, - &outarg.attr,ATTR_TIMEOUT (&outarg),0 ); + &outarg.attr,ATTR_TIMEOUT (&outarg),0 ,0 );if (!inode) {fuse_queue_forget (fm->fc, forget, outarg.nodeid,1 );return -ENOMEM ;
@@ -2041,7 +2042,7 @@ int fuse_do_setattr(struct mnt_idmap *idmap, struct dentry *dentry,fuse_change_attributes_common (inode, &outarg.attr,NULL ,ATTR_TIMEOUT (&outarg), -fuse_get_cache_mask (inode)); +fuse_get_cache_mask (inode),0 ); oldsize = inode->i_size;/* see the comment in fuse_change_attributes() */ if (!is_wb || is_truncate)
fs/fuse/fuse_i.h +12 -2
@@ -906,6 +906,9 @@ struct fuse_conn {/** Version counter for attribute changes */ atomic64_t attr_version; +/** Version counter for evict inode */ +atomic64_t evict_ctr; +/** Called on final put */ void (*release)(struct fuse_conn *);
@@ -1000,6 +1003,11 @@ static inline u64 fuse_get_attr_version(struct fuse_conn *fc)return atomic64_read (&fc->attr_version); } +static inline u64 fuse_get_evict_ctr (struct fuse_conn *fc) +{ +return atomic64_read (&fc->evict_ctr); +} +static inline bool fuse_stale_inode (const struct inode *inode,int generation,struct fuse_attr *attr) {
@@ -1059,7 +1067,8 @@ extern const struct dentry_operations fuse_root_dentry_operations;*/ struct inode *fuse_iget (struct super_block *sb,u64 nodeid,int generation,struct fuse_attr *attr, -u64 attr_valid,u64 attr_version); +u64 attr_valid,u64 attr_version, +u64 evict_ctr);int fuse_lookup_name (struct super_block *sb,u64 nodeid,const struct qstr *name,struct fuse_entry_out *outarg,struct inode **inode);
@@ -1149,7 +1158,8 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,void fuse_change_attributes_common (struct inode *inode,struct fuse_attr *attr,struct fuse_statx *sx, -u64 attr_valid,u32 cache_mask); +u64 attr_valid,u32 cache_mask, +u64 evict_ctr);u32 fuse_get_cache_mask (struct inode *inode);
fs/fuse/inode.c +44 -12
124 lines not on this page · raw message
fs/fuse/readdir.c +9 -6
@@ -153,7 +153,7 @@ static int parse_dirfile(char *buf, size_t nbytes, struct file *file,static int fuse_direntplus_link (struct file *file,struct fuse_direntplus *direntplus, -u64 attr_version) +u64 attr_version,u64 evict_ctr) {struct fuse_entry_out *o = &direntplus->entry_out;struct fuse_dirent *dirent = &direntplus->dirent;
@@ -237,7 +237,7 @@ static int fuse_direntplus_link(struct file *file, }else { inode =fuse_iget (dir->i_sb, o->nodeid, o->generation, &o->attr,ATTR_TIMEOUT (o), - attr_version); + attr_version, evict_ctr);if (!inode) inode =ERR_PTR (-ENOMEM );
@@ -288,7 +288,8 @@ static void fuse_force_forget(struct file *file, u64 nodeid) }static int parse_dirplusfile (char *buf,size_t nbytes,struct file *file, -struct dir_context *ctx,u64 attr_version) +struct dir_context *ctx,u64 attr_version, +u64 evict_ctr) {struct fuse_direntplus *direntplus;struct fuse_dirent *dirent;
@@ -323,7 +324,7 @@ static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file, buf += reclen; nbytes -= reclen; - ret =fuse_direntplus_link (file, direntplus, attr_version); + ret =fuse_direntplus_link (file, direntplus, attr_version, evict_ctr);if (ret)fuse_force_forget (file, direntplus->entry_out.nodeid); }
@@ -341,7 +342,7 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx)struct fuse_io_args ia = {};struct fuse_args_pages *ap = &ia.ap;struct fuse_folio_desc desc = { .length =PAGE_SIZE }; -u64 attr_version =0 ; +u64 attr_version =0 , evict_ctr =0 ;bool locked; folio =folio_alloc (GFP_KERNEL ,0 );
@@ -356,6 +357,7 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx) ap->folio_descs = &desc;if (plus) { attr_version =fuse_get_attr_version (fm->fc); + evict_ctr =fuse_get_evict_ctr (fm->fc);fuse_read_args_fill (&ia, file, ctx->pos,PAGE_SIZE ,FUSE_READDIRPLUS ); }else {
@@ -373,7 +375,8 @@ static int fuse_readdir_uncached(struct file *file, struct dir_context *ctx)fuse_readdir_cache_end (file, ctx->pos); }else if (plus) { res =parse_dirplusfile (folio_address (folio), res, - file, ctx, attr_version); + file, ctx, attr_version, + evict_ctr); }else { res =parse_dirfile (folio_address (folio), res, file, ctx);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1211/1376 fuse: check for NULL root inode in fuse_fill_super_submount
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baokun Li <[email protected]>
[ Upstream commit 928f659a3e3650978a5b4829cc982324f72b474b ]
fuse_iget() can return NULL when its inode allocation fails, but fuse_fill_super_submount() passed the result straight to get_fuse_inode() and decremented fi->nlookup without checking it:
root = fuse_iget(sb, parent_fi->nodeid, ...);
fi = get_fuse_inode(root);
fi->nlookup--;Inside fuse_iget() the inode allocation can fail and return NULL. The submount root takes the iget5_locked() path, whose alloc_inode() can fail under memory pressure (the auto-submount branch can fail the same way in new_inode() or fuse_alloc_submount_lookup()):
inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set,
&nodeid);
if (!inode)
return NULL;A NULL root makes get_fuse_inode() a container_of() on NULL and the nlookup decrement a write to a bogus address, oopsing the mount. With CONFIG_KASAN the following null pointer dereference is reported when the root inode allocation of an auto-submount fails (e.g. under memory pressure):
==================================================================
BUG: KASAN: null-ptr-deref in fuse_get_tree_submount+0x656/0x8b0 Read of size 8 at addr 00000000000002b0 by task ls/942 CPU: 0 PID: 942 Comm: ls Tainted: G W 6.6 #15 Call Trace: <TASK> fuse_get_tree_submount+0x656/0x8b0 vfs_get_tree+0x48/0x140 fc_mount+0x13/0x50 fuse_dentry_automount+0x7a/0xb0 __traverse_mounts+0xca/0x330 step_into+0x339/0xac0 path_lookupat+0xc5/0x2f0 filename_lookup+0x163/0x2a0 vfs_statx+0xd5/0x200 do_statx+0x83/0xd0 __x64_sys_statx+0xa0/0xc0 do_syscall_64+0x37/0x90 entry_SYSCALL_64_after_hwframe+0x78/0xe2 </TASK> ==================================================================
Return -ENOMEM instead; the caller tears down the partially built superblock on error, matching the other error returns in this function.
--- fs/fuse/inode.c | 2 ++ 1 file changed, 2 insertions(+)
fs/fuse/inode.c +2 -0
@@ -1640,6 +1640,8 @@ static int fuse_fill_super_submount(struct super_block *sb,fuse_fill_attr_from_inode (&root_attr, parent_fi); root =fuse_iget (sb, parent_fi->nodeid,0 , &root_attr,0 ,0 ,fuse_get_evict_ctr (fm->fc)); +if (!root) +return -ENOMEM ;/* * This inode is just a duplicate, so it is not looked up and * its nlookup should not be incremented. fuse_iget() does
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1212/1376 ALSA: hda: Fix connection list comparison in proc output
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
[ Upstream commit c139e7e44f58a6f8ddc9d850ea9924d34963b5da ]
print_conn_list() compares the raw hardware connection list with the connection list cached by the HDA driver. When they differ, it prints an additional "In-driver Connection" line so that /proc/asound/card*/codec#* shows the topology actually used by the driver.
The comparison currently passes conn_len directly to memcmp(). However, conn_len is a number of connection-list entries, while memcmp() expects a size in bytes. Both list and conn are arrays of hda_nid_t, which is u16, so only half of the connection data is compared.
For example, for two-entry lists such as:
hardware: 0x0c 0x0d
cached: 0x0c 0x0e
conn_len is 2, and the current comparison checks only the first hda_nid_t. The lists are therefore incorrectly treated as identical even though the second connection differs.
This can happen legitimately when codec fixups replace a cached connection list with snd_hda_override_conn_list(). The codec routing used by the driver is not affected, but the proc output can hide the overridden driver-visible routing and provide misleading topology information during codec debugging.
Convert the entry count to a byte size so that memcmp() covers the complete connection list.
--- sound/pci/hda/hda_proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/pci/hda/hda_proc.c +1 -1
@@ -624,7 +624,7 @@ static void print_conn_list(struct snd_info_buffer *buffer,/* Get Cache connections info */ cache_len =snd_hda_get_conn_list (codec, nid, &list);if (cache_len >=0 && (cache_len != conn_len || -memcmp (list, conn, conn_len) !=0 )) { +memcmp (list, conn, conn_len *sizeof (*conn)) !=0 )) {snd_iprintf (buffer," In-driver Connection: %d\n" , cache_len);if (cache_len >0 ) {snd_iprintf (buffer," " );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1213/1376 vxlan: mdb: Fix use-after-free in vxlan_mdb_flush()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baul Lee <[email protected]>
[ Upstream commit bc2dc66a6693a78f8c1e6ca2dbebd50f16e2c366 ]
vxlan_mdb_flush() iterates over the MDB entries using hlist_for_each_entry_safe(), which only tolerates the removal of the current entry. Contrary to the comment above the loop, the removal of an entry can trigger the removal of another entry.
Flushing the remotes of a (*, G) entry also removes the (S, G) entries that were created for its source list, once they are left without remotes:
vxlan_mdb_remotes_flush()
-> vxlan_mdb_remote_del()
-> vxlan_mdb_remote_srcs_del()
-> vxlan_mdb_remote_src_del()
-> vxlan_mdb_remote_src_fwd_del()
-> __vxlan_mdb_del()
-> vxlan_mdb_entry_put()Such an entry can be located after the (*, G) entry in the list, as vxlan_mdb_entry_get() returns an existing entry without moving it to the head of the list. This order is obtained by adding the (S, G) entry before the (*, G) entry, the latter with NLM_F_REPLACE, as the addition of the source otherwise fails with -EEXIST. The (S, G) entry is then the entry saved by hlist_for_each_entry_safe() and it is freed while the (*, G) entry is processed. The next iteration calls hlist_del() on it again, writing LIST_POISON1 to LIST_POISON2 [1].
Besides device deletion, the flush is also reachable from RTM_DELMDB with NLM_F_BULK.
Fix by re-reading the next entry after the remotes were flushed. The current entry cannot be removed by this flush, as source lists can only be configured on (*, G) entries and the removed entries are (S, G) entries. It is therefore still linked and its next pointer reflects the removals.
[1]
BUG: KASAN: wild-memory-access in vxlan_mdb_entry_put.part.0+0x328/0x588 Write of size 8 at addr dead000000000122 by task ip/327 CPU: 3 UID: 1000 PID: 327 Comm: ip Not tainted 7.2.0-rc7 #2 PREEMPT Call trace: vxlan_mdb_entry_put.part.0+0x328/0x588 vxlan_mdb_flush+0x1d8/0x25c vxlan_mdb_fini+0x8c/0x100 vxlan_uninit+0x1c/0x7c unregister_netdevice_many_notify+0x954/0xd4c rtnl_dellink+0x210/0x530 rtnetlink_rcv_msg+0x434/0x4d0 netlink_rcv_skb+0xc4/0x204 rtnetlink_rcv+0x18/0x24 netlink_unicast+0x4b8/0x548 netlink_sendmsg+0x29c/0x560 ____sys_sendmsg+0x390/0x3ec ___sys_sendmsg+0x114/0x188 __sys_sendmsg+0xf0/0x178 __arm64_sys_sendmsg+0x48/0x60 invoke_syscall.constprop.0+0x58/0x180 el0_svc_common.constprop.0+0x74/0x140 do_el0_svc+0x30/0x40 el0_svc+0x38/0x98 el0t_64_sync_handler+0xa0/0xe4 el0t_64_sync+0x198/0x19c
--- drivers/net/vxlan/vxlan_mdb.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/net/vxlan/vxlan_mdb.c +6 -3
@@ -1428,14 +1428,17 @@ static void vxlan_mdb_flush(struct vxlan_dev *vxlan,struct vxlan_mdb_entry *mdb_entry;struct hlist_node *tmp; -/* The removal of an entry cannot trigger the removal of another entry -* since entries are always added to the head of the list. -*/ hlist_for_each_entry_safe (mdb_entry, tmp, &vxlan->mdb_list, mdb_node) {if (desc->src_vni && desc->src_vni != mdb_entry->key.vni)continue ;vxlan_mdb_remotes_flush (vxlan, mdb_entry, desc); +/* The flush can remove the (S, G) entries created for the +* source list of this entry, including the one saved by +* hlist_for_each_entry_safe(), so re-read it while this entry +* is still linked. +*/ + tmp = mdb_entry->mdb_node.next;/* Entry will only be removed if its remotes list is empty. */ vxlan_mdb_entry_put (vxlan, mdb_entry); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1214/1376 8139cp: fix Rx and Tx not being disabled in cp_suspend
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit cb7643b78d35392f0f434774d78b4c77b80f677f ]
On QEMU rtl8139 model, frames that arrive while the interface is suspended still end up in the stack after resume. With pm_test=devices, which keeps devices suspended for 5s, 200 frames sent to interface during that time and 50 frames after resume, eth0 reports 113 received frames.
cp_suspend() is supposed to stop receiver and the transmitter, but the mask is wrong: (~RxOn | ~TxOn) is ~0, nothing is cleared and Cmd still reads 0x0d when cp_suspend() returns.
Use ~(RxOn | TxOn) so both bits are actually cleared.
--- drivers/net/ethernet/realtek/8139cp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/realtek/8139cp.c +1 -1
@@ -2066,7 +2066,7 @@ static int __maybe_unused cp_suspend(struct device *device)/* Disable Rx and Tx */ cpw16 (IntrMask,0 ); -cpw8 (Cmd,cpr8 (Cmd) & (~RxOn | ~TxOn)); +cpw8 (Cmd,cpr8 (Cmd) & ~(RxOn | TxOn));spin_unlock_irqrestore (&cp->lock, flags);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1215/1376 net/smc: hash socket only after full initialisation in smc_sk_init()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mahanta Jambigi <[email protected]>
[ Upstream commit 8acf691d8017012e1476c30e7381513c1e929c94 ]
smc_sk_init() calls sk->sk_prot->hash(sk) before several fields are fully initialised: clcsock_release_lock, the saved clcsk_* callbacks, use_fallback/fallback_rsn, and conn.close_work. Once hash() returns the socket is visible to concurrent hash walkers, which can then observe uninitialised state.
Move hash(sk) to the end of smc_sk_init() so the socket is published only after it is fully constructed.
--- net/smc/af_smc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/smc/af_smc.c +1 -1
@@ -410,13 +410,13 @@ void smc_sk_init(struct net *net, struct sock *sk, int protocol) "sk_lock-AF_SMC", &smc_key);spin_lock_init (&smc->accept_q_lock);spin_lock_init (&smc->conn.send_lock); - sk->sk_prot->hash (sk);mutex_init (&smc->clcsock_release_lock);smc_init_saved_callbacks (smc); smc->limit_smc_hs = net->smc.limit_smc_hs; smc->use_fallback = false;/* assume rdma capability first */ smc->fallback_rsn =0 ;smc_close_init (smc); + sk->sk_prot->hash (sk); } static struct sock *smc_sock_alloc(struct net *net, struct socket *sock,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1216/1376 platform/x86: dell-wmi-sysman: Fix instance ID bounds
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit 5ab078e3241da0beec2022254b5811a8a52cff84 ]
The get_instance_id() macro walks the per-type attribute array with 'i <= instances_count'. Each array is allocated with exactly instances_count entries, so the valid range is [0, instances_count) and the last iteration reads one element past the end. On a name miss that out-of-bounds attribute_name is handed to strcmp(), which reads on until it finds a NUL byte.
Every kobject in these ksets is built from an entry that was populated, so a miss does not look reachable from sysfs today. The bound is wrong either way and the read is out of bounds.
The matching macro in hp-bioscfg carried the same off-by-one and was corrected by commit 25150715e0b0 ("platform/x86: hp-bioscfg: Fix kernel panic in GET_INSTANCE_ID macro"). That macro takes a kobject pointer out of the out-of-bounds element and dereferences it, so it could fault. This one reads a char array.
Use '<' to match the allocation.
--- drivers/platform/x86/dell/dell-wmi-sysman/dell-wmi-sysman.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/platform/x86/dell/dell-wmi-sysman/dell-wmi-sysman.h +1 -1
@@ -107,7 +107,7 @@ enum { static int get_##type##_instance_id(struct kobject *kobj) \ { \ int i; \ - for (i = 0; i <= wmi_priv.type##_instances_count; i++) { \ + for (i = 0; i < wmi_priv.type##_instances_count; i++) { \ if (!(strcmp(kobj->name, wmi_priv.type##_data[i].attribute_name)))\ return i; \ } \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1217/1376 vsock: avoid timeout for non-blocking accept() with empty backlog
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Laurence Rowe <[email protected]>
[ Upstream commit 98f28d8d6e5a5ed058dd37854c19e9b3bae72eff ]
A common pattern in epoll network servers is to eagerly accept all pending connections from the non-blocking listening socket after epoll_wait indicates the socket is ready by calling accept in a loop until EAGAIN is returned indicating that the backlog is empty.
Scheduling a timeout for a non-blocking accept with an empty backlog meant AF_VSOCK sockets used by epoll network servers incurred hundreds of microseconds of additional latency per accept loop compared to AF_INET or AF_UNIX sockets.
Stable-dep-of: b8c899cf5e7b ("vsock: don't check the listener's sk_err in vsock_accept()")
--- net/vmw_vsock/af_vsock.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-)
net/vmw_vsock/af_vsock.c +6 -9
@@ -1715,10 +1715,10 @@ static int vsock_accept(struct socket *sock, struct socket *newsock,* created upon connection establishment. */ timeout =sock_rcvtimeo (listener, arg->flags &O_NONBLOCK ); -prepare_to_wait (sk_sleep (listener), &wait,TASK_INTERRUPTIBLE );while ((connected =vsock_dequeue_accept (listener)) ==NULL && - listener->sk_err ==0 ) { + listener->sk_err ==0 && timeout !=0 ) { +prepare_to_wait (sk_sleep (listener), &wait,TASK_INTERRUPTIBLE );release_sock (listener); timeout =schedule_timeout (timeout);finish_wait (sk_sleep (listener), &wait);
@@ -1727,17 +1727,14 @@ static int vsock_accept(struct socket *sock, struct socket *newsock,if (signal_pending (current)) { err =sock_intr_errno (timeout); goto out; - }else if (timeout ==0 ) { - err = -EAGAIN ; - goto out; } - -prepare_to_wait (sk_sleep (listener), &wait,TASK_INTERRUPTIBLE ); } -finish_wait (sk_sleep (listener), &wait); -if (listener->sk_err) +if (listener->sk_err) { err = -listener->sk_err; + }else if (!connected) { + err = -EAGAIN ; + }if (connected) {sk_acceptq_removed (listener);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1218/1376 vsock: dont check the listeners sk_err in vsock_accept()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nguyen Dinh Phi <[email protected]>
[ Upstream commit b8c899cf5e7be29840a172c183dedd8d3e7a0287 ]
Syzbot reported an issue which can be reproduced with these steps:
r0 = socket(AF_VSOCK, SOCK_STREAM, 0)
bind(r0, {VMADDR_CID_ANY, PORT})
connect(r0, {VMADDR_CID_LOCAL, PORT}) -> -1, EPROTO (self-connect)
listen(r0, backlog) -> 0
r1 = socket(AF_VSOCK, SOCK_STREAM, 0)
connect(r1, {VMADDR_CID_LOCAL, PORT}) -> 0
accept(r0) -> -1, EPROTO (stale sk_err)Basically, it creates a socket (r0) and triggers a self-connect after binding it. This self-connect fails with EPROTO because it loops back to r0 while the socket is still in the TCP_SYN_SENT state, causing it to be incorrectly dispatched to the connecting-client path. The unexpected packet type encountered there sets sk_err to EPROTO.
After that, it invokes a listen() call on the same socket. This listen() call succeeds because the kernel's listening path never inspects or clears sk_err. Then, a new socket (r1) is created as a normal client and connects to r0. However, vsock_accept() rejects this incoming connection because the listener's sk_err still holds the EPROTO error from the earlier failed self-connect.
This rejection causes the child socket created for r1's connection to never be freed on virtio or hyperv transports; only the VMCI transport implements pending_work to revisit and clean up a rejected socket.
For a non-blocking connect(), vsock_connect() may return -EINPROGRESS immediately, and vsock_connect_timeout() can later set sk->sk_err asynchronously.
Since no vsock transport ever sets sk_err on a socket while it is in TCP_LISTEN state, checking it in vsock_accept() serves no purpose and only carries forward errors left behind by earlier, unrelated connection attempts on the same socket. Remove the checks so accept() no longer rejects valid incoming connections because of a stale error, which also avoids the resource leak described above.
--- net/vmw_vsock/af_vsock.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-)
net/vmw_vsock/af_vsock.c +3 -7
@@ -1717,7 +1717,7 @@ static int vsock_accept(struct socket *sock, struct socket *newsock, timeout =sock_rcvtimeo (listener, arg->flags &O_NONBLOCK );while ((connected =vsock_dequeue_accept (listener)) ==NULL && - listener->sk_err ==0 && timeout !=0 ) { + timeout !=0 ) {prepare_to_wait (sk_sleep (listener), &wait,TASK_INTERRUPTIBLE );release_sock (listener); timeout =schedule_timeout (timeout);
@@ -1730,13 +1730,9 @@ static int vsock_accept(struct socket *sock, struct socket *newsock, } } -if (listener->sk_err) { - err = -listener->sk_err; - }else if (!connected) { +if (!connected) { err = -EAGAIN ; - } - -if (connected) { + }else {sk_acceptq_removed (listener);lock_sock_nested (connected,SINGLE_DEPTH_NESTING );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1219/1376 vsock: use sock_error() to consume sk_err after a failed connect
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nguyen Dinh Phi <[email protected]>
[ Upstream commit 96cbf89993091a163bfedec52a3bd683dc94b3b4 ]
vsock_connect() returns sk_err to userspace but does not clear it:
if (sk->sk_err) {
err = -sk->sk_err;For a blocking connect() the error has already been delivered as connect()'s return value, so leaving it set causes subsequent operations like poll()/epoll() to keep reporting POLLERR even though the connect failure was already delivered.
The error should be consumed once it has been returned to userspace. Switch to sock_error(), which reads and clears sk_err atomically, matching the behavior of other protocol implementations such as __inet_stream_connect().
--- net/vmw_vsock/af_vsock.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
net/vmw_vsock/af_vsock.c +2 -4
@@ -1671,12 +1671,10 @@ static int vsock_connect(struct socket *sock, struct sockaddr *addr,prepare_to_wait (sk_sleep (sk), &wait,TASK_INTERRUPTIBLE ); } -if (sk->sk_err) { - err = -sk->sk_err; + err =sock_error (sk); +if (err) { sk->sk_state =TCP_CLOSE ; sock->state =SS_UNCONNECTED ; - }else { - err =0 ; } out_wait:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1220/1376 platform/x86: hp-bioscfg: fix password encoding bounds check
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit e213939ed9e6e6badf7aa48c4c8dd9a9cdf00615 ]
The password PSWD_ENCODINGS parser reads password_obj[elem + pos_values] while copying the supported password encodings from the ACPI package.
The outer loop only guarantees that elem is within password_obj_count. The encoding count is bounded by MAX_ENCODINGS_SIZE, but that does not guarantee that the ACPI package contains enough entries for all elem + pos_values accesses.
A malformed package can therefore declare a non-zero encoding count without providing enough string objects, causing the parser to read past the ACPI package array and pass an out-of-bounds string pointer and length to hp_convert_hexstr_to_str().
Add the same computed-index bounds check used by the other offset-based package parsing loops before reading password_obj[elem + pos_values].
--- drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c +5 -0
@@ -353,6 +353,11 @@ static int hp_populate_password_elements_from_package(union acpi_object *passworcase PSWD_ENCODINGS : size =min_t (u32, password_data->encodings_size,MAX_ENCODINGS_SIZE );for (pos_values =0 ; pos_values < size; pos_values++) { +if (elem + pos_values >= password_obj_count) { +pr_err ("Error elem-objects package is too small\n" ); +return -EINVAL ; + } + ret =hp_convert_hexstr_to_str (password_obj[elem + pos_values].string.pointer, password_obj[elem + pos_values].string.length, &str_value, &value_len);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1221/1376 mlxbf-bootctl: fix the build error with FIELD_PREP()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikolay Kulikov <[email protected]>
[ Upstream commit 46b14c6f11f558362391e308f4f184ee867ef58f ]
rsh_log_store() calls the FIELD_PREP() macro without including the required header file, resulting a build error:
CC drivers/platform/mellanox/mlxbf-bootctl.odrivers/platform/mellanox/mlxbf-bootctl.c: In function ‘rsh_log_store’:drivers/platform/mellanox/mlxbf-bootctl.c:429:16: error: implicit declaration of function ‘FIELD_PREP’ [-Wimplicit-function-declaration]
429 | data = FIELD_PREP(MLXBF_RSH_LOG_TYPE_MASK, MLXBF_RSH_LOG_TYPE_MSG);
| ^~~~~~~~~~Fix this by including the <linux/bitfield.h> file.
--- drivers/platform/mellanox/mlxbf-bootctl.c | 1 + 1 file changed, 1 insertion(+)
drivers/platform/mellanox/mlxbf-bootctl.c +1 -0
@@ -10,6 +10,7 @@#include <linux/acpi.h> #include <linux/arm-smccc.h> +#include <linux/bitfield.h> #include <linux/delay.h> #include <linux/if_ether.h> #include <linux/iopoll.h>
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1222/1376 bonding: initialize err for empty target lists
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit 8ccc9bf9afeeb46a437081c07154fbf5964682b2 ]
Empty NLA_NESTED attributes are valid, and bonding uses them to clear the ARP and NS target lists. When either target attribute is empty, nla_for_each_nested() does not execute, so err retains an uninitialized value before it is tested. The request can consequently return an unpredictable error after clearing the targets.
Initialize err to zero so an empty target list completes successfully. Non-empty lists still propagate errors from __bond_opt_set() unchanged.
This issue was found by a static analysis checker and confirmed by manual source review.
--- drivers/net/bonding/bond_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/bonding/bond_netlink.c +1 -1
@@ -218,7 +218,7 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],struct bonding *bond =netdev_priv (bond_dev);struct bond_opt_value newval;int miimon =0 ; -int err; +int err =0 ;if (!data)return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1223/1376 net: add missing ref_tracker_dir_exit() to alloc_netdev_mqs()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tetsuo Handa <[email protected]>
[ Upstream commit 0b1c2af8a22c35cb099c735c2f63ea3ba757557d ]
sashiko is reporting that trying to read /sys/kernel/debug/ref_tracker/* causes use-afer-free crash when either alloc_percpu() or dev_addr_init() in alloc_netdev_mqs() failed, for commit 4d92b95ff2f9 ("net: add net device refcount tracker infrastructure") added ref_tracker_dir_exit() to only free_netdev() path.
--- net/core/dev.c | 1 + 1 file changed, 1 insertion(+)
net/core/dev.c +1 -0
@@ -11335,6 +11335,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,free_percpu (dev->pcpu_refcnt); free_dev:#endif +ref_tracker_dir_exit (&dev->refcnt_tracker);kvfree (dev);return NULL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1224/1376 i3c: mipi-i3c-hci: Quieten initialization messages
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <[email protected]>
[ Upstream commit 581d5b7953b8f24d2f379c8c56ceaa7d163488ce ]
The copious initialization messages are at most useful only for debugging. Change them from dev_info() or dev_notice() to dev_dbg().
Stable-dep-of: 308ecb824db3 ("i3c: mipi-i3c-hci: Fix missing STAT_IBI_STATUS_THLD in PIO mode")
--- drivers/i3c/master/mipi-i3c-hci/core.c | 18 +++---- drivers/i3c/master/mipi-i3c-hci/dma.c | 4 +- drivers/i3c/master/mipi-i3c-hci/ext_caps.c | 55 ++++++++++------------ drivers/i3c/master/mipi-i3c-hci/pio.c | 16 +++---- 4 files changed, 45 insertions(+), 48 deletions(-)
drivers/i3c/master/mipi-i3c-hci/core.c +9 -9
@@ -663,8 +663,8 @@ static int i3c_hci_init(struct i3c_hci *hci) hci->DAT_entry_size =FIELD_GET (DAT_ENTRY_SIZE , regval) ?0 :8 ;if (size_in_dwords) hci->DAT_entries =4 * hci->DAT_entries / hci->DAT_entry_size; -dev_info (&hci->master.dev,"DAT: %u %u-bytes entries at offset %#x\n" , - hci->DAT_entries, hci->DAT_entry_size, offset); +dev_dbg (&hci->master.dev,"DAT: %u %u-bytes entries at offset %#x\n" , + hci->DAT_entries, hci->DAT_entry_size, offset); regval =reg_read (DCT_SECTION ); offset =FIELD_GET (DCT_TABLE_OFFSET , regval);
@@ -673,23 +673,23 @@ static int i3c_hci_init(struct i3c_hci *hci) hci->DCT_entry_size =FIELD_GET (DCT_ENTRY_SIZE , regval) ?0 :16 ;if (size_in_dwords) hci->DCT_entries =4 * hci->DCT_entries / hci->DCT_entry_size; -dev_info (&hci->master.dev,"DCT: %u %u-bytes entries at offset %#x\n" , - hci->DCT_entries, hci->DCT_entry_size, offset); +dev_dbg (&hci->master.dev,"DCT: %u %u-bytes entries at offset %#x\n" , + hci->DCT_entries, hci->DCT_entry_size, offset); regval =reg_read (RING_HEADERS_SECTION ); offset =FIELD_GET (RING_HEADERS_OFFSET , regval); hci->RHS_regs = offset ? hci->base_regs + offset :NULL ; -dev_info (&hci->master.dev,"Ring Headers at offset %#x\n" , offset); +dev_dbg (&hci->master.dev,"Ring Headers at offset %#x\n" , offset); regval =reg_read (PIO_SECTION ); offset =FIELD_GET (PIO_REGS_OFFSET , regval); hci->PIO_regs = offset ? hci->base_regs + offset :NULL ; -dev_info (&hci->master.dev,"PIO section at offset %#x\n" , offset); +dev_dbg (&hci->master.dev,"PIO section at offset %#x\n" , offset); regval =reg_read (EXT_CAPS_SECTION ); offset =FIELD_GET (EXT_CAPS_OFFSET , regval); hci->EXTCAPS_regs = offset ? hci->base_regs + offset :NULL ; -dev_info (&hci->master.dev,"Extended Caps at offset %#x\n" , offset); +dev_dbg (&hci->master.dev,"Extended Caps at offset %#x\n" , offset); ret =i3c_hci_parse_ext_caps (hci);if (ret)
@@ -766,7 +766,7 @@ static int i3c_hci_init(struct i3c_hci *hci) ret = -EIO ; }else { hci->io = &mipi_i3c_hci_dma; -dev_info (&hci->master.dev,"Using DMA\n" ); +dev_dbg (&hci->master.dev,"Using DMA\n" ); } }
@@ -778,7 +778,7 @@ static int i3c_hci_init(struct i3c_hci *hci) ret = -EIO ; }else { hci->io = &mipi_i3c_hci_pio; -dev_info (&hci->master.dev,"Using PIO\n" ); +dev_dbg (&hci->master.dev,"Using PIO\n" ); } }
drivers/i3c/master/mipi-i3c-hci/dma.c +2 -2
@@ -201,7 +201,7 @@ static int hci_dma_init(struct i3c_hci *hci) regval =rhs_reg_read (CONTROL ); nr_rings =FIELD_GET (MAX_HEADER_COUNT_CAP , regval); -dev_info (&hci->master.dev,"%d DMA rings available\n" , nr_rings); +dev_dbg (&hci->master.dev,"%d DMA rings available\n" , nr_rings);if (unlikely (nr_rings >8 )) {dev_err (&hci->master.dev,"number of rings should be <= 8\n" ); nr_rings =8 ;
@@ -220,7 +220,7 @@ static int hci_dma_init(struct i3c_hci *hci)for (i =0 ; i < rings->total; i++) {u32 offset =rhs_reg_read (RHn_OFFSET (i)); -dev_info (&hci->master.dev,"Ring %d at offset %#x\n" , i, offset); +dev_dbg (&hci->master.dev,"Ring %d at offset %#x\n" , i, offset); ret = -EINVAL ;if (!offset) goto err_out;
drivers/i3c/master/mipi-i3c-hci/ext_caps.c +26 -29
154 lines not on this page · raw message
drivers/i3c/master/mipi-i3c-hci/pio.c +8 -8
@@ -149,14 +149,14 @@ static int hci_pio_init(struct i3c_hci *hci)spin_lock_init (&pio->lock); size_val =pio_reg_read (QUEUE_SIZE ); -dev_info (&hci->master.dev,"CMD/RESP FIFO = %ld entries\n" , -FIELD_GET (CR_QUEUE_SIZE , size_val)); -dev_info (&hci->master.dev,"IBI FIFO = %ld bytes\n" , -4 *FIELD_GET (IBI_STATUS_SIZE , size_val)); -dev_info (&hci->master.dev,"RX data FIFO = %d bytes\n" , -4 * (2 <<FIELD_GET (RX_DATA_BUFFER_SIZE , size_val))); -dev_info (&hci->master.dev,"TX data FIFO = %d bytes\n" , -4 * (2 <<FIELD_GET (TX_DATA_BUFFER_SIZE , size_val))); +dev_dbg (&hci->master.dev,"CMD/RESP FIFO = %ld entries\n" , +FIELD_GET (CR_QUEUE_SIZE , size_val)); +dev_dbg (&hci->master.dev,"IBI FIFO = %ld bytes\n" , +4 *FIELD_GET (IBI_STATUS_SIZE , size_val)); +dev_dbg (&hci->master.dev,"RX data FIFO = %d bytes\n" , +4 * (2 <<FIELD_GET (RX_DATA_BUFFER_SIZE , size_val))); +dev_dbg (&hci->master.dev,"TX data FIFO = %d bytes\n" , +4 * (2 <<FIELD_GET (TX_DATA_BUFFER_SIZE , size_val)));/* * Let's initialize data thresholds to half of the actual FIFO size.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1225/1376 i3c: mipi-i3c-hci: Switch PIO data allocation to devm_kzalloc()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <[email protected]>
[ Upstream commit 11d17c2855bfc04550557017eae02e92f3eeab1c ]
The driver already uses managed resources, so convert the PIO data structure allocation to devm_zalloc(). Remove the manual kfree().
Stable-dep-of: 308ecb824db3 ("i3c: mipi-i3c-hci: Fix missing STAT_IBI_STATUS_THLD in PIO mode")
--- drivers/i3c/master/mipi-i3c-hci/pio.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/i3c/master/mipi-i3c-hci/pio.c +1 -3
@@ -141,7 +141,7 @@ static int hci_pio_init(struct i3c_hci *hci)struct hci_pio_data *pio;u32 val, size_val, rx_thresh, tx_thresh, ibi_val; - pio =kzalloc (sizeof (*pio),GFP_KERNEL ); + pio =devm_kzalloc (hci->master.dev.parent,sizeof (*pio),GFP_KERNEL );if (!pio)return -ENOMEM ;
@@ -219,8 +219,6 @@ static void hci_pio_cleanup(struct i3c_hci *hci)BUG_ON (pio->curr_rx);BUG_ON (pio->curr_tx);BUG_ON (pio->curr_resp); -kfree (pio); - hci->io_data =NULL ; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1226/1376 i3c: mipi-i3c-hci: Refactor PIO register initialization
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <[email protected]>
[ Upstream commit ca4d4682d353bf4e7e5db7b025e9ecd80bc67b27 ]
Move the PIO register setup logic out of hci_pio_init() into a new helper, __hci_pio_init(). This refactoring prepares for Runtime PM support by allowing PIO registers to be reinitialized independently after resume.
Stable-dep-of: 308ecb824db3 ("i3c: mipi-i3c-hci: Fix missing STAT_IBI_STATUS_THLD in PIO mode")
--- drivers/i3c/master/mipi-i3c-hci/pio.c | 45 +++++++++++++++++---------- 1 file changed, 28 insertions(+), 17 deletions(-)
drivers/i3c/master/mipi-i3c-hci/pio.c +28 -17
@@ -136,27 +136,14 @@ struct hci_pio_data {u32 enabled_irqs; }; -static int hci_pio_init (struct i3c_hci *hci) +static void __hci_pio_init (struct i3c_hci *hci,u32 *size_val_ptr) { -struct hci_pio_data *pio;u32 val, size_val, rx_thresh, tx_thresh, ibi_val; - - pio =devm_kzalloc (hci->master.dev.parent,sizeof (*pio),GFP_KERNEL ); -if (!pio) -return -ENOMEM ; - - hci->io_data = pio; -spin_lock_init (&pio->lock); +struct hci_pio_data *pio = hci->io_data; size_val =pio_reg_read (QUEUE_SIZE ); -dev_dbg (&hci->master.dev,"CMD/RESP FIFO = %ld entries\n" , -FIELD_GET (CR_QUEUE_SIZE , size_val)); -dev_dbg (&hci->master.dev,"IBI FIFO = %ld bytes\n" , -4 *FIELD_GET (IBI_STATUS_SIZE , size_val)); -dev_dbg (&hci->master.dev,"RX data FIFO = %d bytes\n" , -4 * (2 <<FIELD_GET (RX_DATA_BUFFER_SIZE , size_val))); -dev_dbg (&hci->master.dev,"TX data FIFO = %d bytes\n" , -4 * (2 <<FIELD_GET (TX_DATA_BUFFER_SIZE , size_val))); +if (size_val_ptr) + *size_val_ptr = size_val;/* * Let's initialize data thresholds to half of the actual FIFO size.
@@ -202,6 +189,30 @@ static int hci_pio_init(struct i3c_hci *hci)/* Always accept error interrupts (will be activated on first xfer) */ pio->enabled_irqs =STAT_ALL_ERRORS ; +} + +static int hci_pio_init (struct i3c_hci *hci) +{ +struct hci_pio_data *pio; +u32 size_val; + + pio =devm_kzalloc (hci->master.dev.parent,sizeof (*pio),GFP_KERNEL ); +if (!pio) +return -ENOMEM ; + + hci->io_data = pio; +spin_lock_init (&pio->lock); + +__hci_pio_init (hci, &size_val); + +dev_dbg (&hci->master.dev,"CMD/RESP FIFO = %ld entries\n" , +FIELD_GET (CR_QUEUE_SIZE , size_val)); +dev_dbg (&hci->master.dev,"IBI FIFO = %ld bytes\n" , +4 *FIELD_GET (IBI_STATUS_SIZE , size_val)); +dev_dbg (&hci->master.dev,"RX data FIFO = %d bytes\n" , +4 * (2 <<FIELD_GET (RX_DATA_BUFFER_SIZE , size_val))); +dev_dbg (&hci->master.dev,"TX data FIFO = %d bytes\n" , +4 * (2 <<FIELD_GET (TX_DATA_BUFFER_SIZE , size_val)));return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1227/1376 i3c: mipi-i3c-hci: Fix missing STAT_IBI_STATUS_THLD in PIO mode
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jian-Ming Liao <[email protected]>
[ Upstream commit 308ecb824db329a8e22dd0b10f2a3411a6fbbde3 ]
In PIO mode initialization, STAT_IBI_STATUS_THLD was missing from pio->enabled_irqs. As a result, the host controller interrupt signal for IBI threshold was never enabled when transfer starts, preventing IBI status descriptors from being properly processed in PIO mode.
Include STAT_IBI_STATUS_THLD in pio->enabled_irqs so that the IBI threshold interrupt is activated alongside error interrupts upon the first transfer.
--- drivers/i3c/master/mipi-i3c-hci/pio.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/i3c/master/mipi-i3c-hci/pio.c +5 -2
@@ -187,8 +187,11 @@ static void __hci_pio_init(struct i3c_hci *hci, u32 *size_val_ptr)pio_reg_write (INTR_SIGNAL_ENABLE ,0x0 );pio_reg_write (INTR_STATUS_ENABLE ,0xffffffff ); -/* Always accept error interrupts (will be activated on first xfer) */ - pio->enabled_irqs =STAT_ALL_ERRORS ; +/* +* Always accept error interrupts and IBI threshold interrupt +* (will be activated on first xfer). +*/ + pio->enabled_irqs =STAT_ALL_ERRORS |STAT_IBI_STATUS_THLD ; }static int hci_pio_init (struct i3c_hci *hci)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1228/1376 virtio_balloon: disable indirect descriptors
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael S. Tsirkin <[email protected]>
[ Upstream commit 281eb4732aae5473141b84e106fe906c69b2ff3d ]
The page reporting callback submits an sg list to the reporting virtqueue. With VIRTIO_RING_F_INDIRECT_DESC negotiated and total_sg > 1 (which it typically is), virtqueue_add reports it to the host by allocating an indirect descriptor via kmalloc(GFP_KERNEL).
This is not pretty: the reporting worker isolates potentially hundreds of MB of free pages from the buddy allocator (reported pages are at least pageblock_order, and the sg can contain up to PAGE_REPORTING_CAPACITY entries of varying orders). As the result, very theoretically, the kmalloc might trigger OOM when we have in fact a ton of free memory.
Clear VIRTIO_RING_F_INDIRECT_DESC, to avoid using indirect descriptors.
Message-ID: <73fac8a629fd9aca7bb3265ac243a769c28af25d.1783232420.git.mst@redhat.com>
--- drivers/virtio/virtio_balloon.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/virtio/virtio_balloon.c +6 -0
@@ -7,6 +7,7 @@*/ #include <linux/virtio.h> +#include <uapi/linux/virtio_ring.h> #include <linux/virtio_balloon.h> #include <linux/swap.h> #include <linux/workqueue.h>
@@ -1187,6 +1188,11 @@ static int virtballoon_validate(struct virtio_device *vdev)else if (!virtio_has_feature (vdev,VIRTIO_BALLOON_F_PAGE_POISON ))__virtio_clear_bit (vdev,VIRTIO_BALLOON_F_REPORTING ); +/* +* Disable indirect descriptors to avoid memory allocation in +* virtqueue_add during page reporting. +*/ +__virtio_clear_bit (vdev,VIRTIO_RING_F_INDIRECT_DESC );__virtio_clear_bit (vdev,VIRTIO_F_ACCESS_PLATFORM );return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1229/1376 vdpa_sim: fix cleanup after worker creation failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linfeng Sun <[email protected]>
[ Upstream commit bd670e5dfd2b01fd9692f61fa1456434c54026a4 ]
vdpasim_create() leaves vdpasim->worker as an ERR_PTR when kthread_run_worker() fails. The error path then drops the device reference, which releases the partially initialized simulator.
vdpasim_free() unconditionally passes the worker pointer to kthread_destroy_worker(), so the ERR_PTR is dereferenced and can trigger a general protection fault.
Store the worker error, clear the pointer, and only clean up the worker when it was successfully initialized. Also make the release path tolerate partially initialized objects by guarding virtqueue and IOTLB cleanup, since the same release path can be reached from other initialization failures.
I found this bug myself, though the patch was written with AI assistance.
Message-ID: <[email protected]>
--- drivers/vdpa/vdpa_sim/vdpa_sim.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-)
drivers/vdpa/vdpa_sim/vdpa_sim.c +17 -8
@@ -231,8 +231,11 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr,kthread_init_work (&vdpasim->work, vdpasim_work_fn); vdpasim->worker =kthread_create_worker (0 ,"vDPA sim worker: %s" , dev_attr->name); -if (IS_ERR (vdpasim->worker)) +if (IS_ERR (vdpasim->worker)) { + ret =PTR_ERR (vdpasim->worker); + vdpasim->worker =NULL ; goto err_iommu; + }mutex_init (&vdpasim->mutex);spin_lock_init (&vdpasim->iommu_lock);
@@ -744,18 +747,24 @@ static void vdpasim_free(struct vdpa_device *vdpa)struct vdpasim *vdpasim =vdpa_to_sim (vdpa);int i; -kthread_cancel_work_sync (&vdpasim->work); -kthread_destroy_worker (vdpasim->worker); +if (vdpasim->worker) { +kthread_cancel_work_sync (&vdpasim->work); +kthread_destroy_worker (vdpasim->worker); + } -for (i =0 ; i < vdpasim->dev_attr.nvqs; i++) { -vringh_kiov_cleanup (&vdpasim->vqs[i].out_iov); -vringh_kiov_cleanup (&vdpasim->vqs[i].in_iov); +if (vdpasim->vqs) { +for (i =0 ; i < vdpasim->dev_attr.nvqs; i++) { +vringh_kiov_cleanup (&vdpasim->vqs[i].out_iov); +vringh_kiov_cleanup (&vdpasim->vqs[i].in_iov); + } } vdpasim->dev_attr.free (vdpasim); -for (i =0 ; i < vdpasim->dev_attr.nas; i++) -vhost_iotlb_reset (&vdpasim->iommu[i]); +if (vdpasim->iommu) { +for (i =0 ; i < vdpasim->dev_attr.nas; i++) +vhost_iotlb_reset (&vdpasim->iommu[i]); + }kfree (vdpasim->iommu);kfree (vdpasim->iommu_pt);kfree (vdpasim->vqs);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1230/1376 virtio_pci: fix wrong queue index for admin vq in intx path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li RongQing <[email protected]>
[ Upstream commit dc3f1eef9ab678c396baf5df12aba61db061aa8c ]
In vp_find_vqs_intx(), the admin vq was set up using the local queue_idx counter instead of avq->vq_index (the actual queue index obtained from the device). This differs from vp_find_vqs_msix() which correctly uses avq->vq_index. Using the wrong index causes the admin virtqueue to be mapped to an incorrect hardware queue.
Fix it by using avq->vq_index consistent with the msix path.
Message-ID: <[email protected]>
--- drivers/virtio/virtio_pci_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/virtio/virtio_pci_common.c +1 -1
@@ -502,7 +502,7 @@ static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned int nvqs,if (!avq_num)return 0 ;sprintf (avq->name,"avq.%u" , avq->vq_index); - vq =vp_setup_vq (vdev, queue_idx++, vp_modern_avq_done, avq->name, + vq =vp_setup_vq (vdev, avq->vq_index, vp_modern_avq_done, avq->name, false,VIRTIO_MSI_NO_VECTOR , &vp_dev->admin_vq.info);if (IS_ERR (vq)) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1231/1376 vdpa/mlx5: fix wrong list iterated in add_direct_chain error path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li RongQing <[email protected]>
[ Upstream commit 23ae56d9e74c122f95cae71ae3b9fc259fb88446 ]
In add_direct_chain(), newly allocated direct MR entries are added to the local list 'tmp', which is spliced into mr->head only on success. On the error path, the cleanup loop was incorrectly iterating over mr->head instead of tmp.
Fix by iterating over 'tmp' in the err_alloc cleanup path.
Message-ID: <[email protected]>
--- drivers/vdpa/mlx5/core/mr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/vdpa/mlx5/core/mr.c +1 -1
@@ -482,7 +482,7 @@ static int add_direct_chain(struct mlx5_vdpa_dev *mvdev,return 0 ; err_alloc: -list_for_each_entry_safe (dmr, n, &mr->head, list) { +list_for_each_entry_safe (dmr, n, &tmp, list) {list_del_init (&dmr->list);unmap_direct_mr (mvdev, dmr);kfree (dmr);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1232/1376 rtc: pcf8563: fix clock provider leak on unbind
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yi Ding <[email protected]>
[ Upstream commit 9c48a53685040bb0de45a640b34055cbbfc69d4f ]
pcf8563_clkout_register_clk() registers the CLKOUT clock provider with of_clk_add_provider(), but nothing ever unwinds it: there is no of_clk_del_provider() call and the driver has no remove callback. Each of_clk_add_provider() allocates a struct of_clk_provider, takes a reference on the OF node and adds an entry to the global of_clk_providers list, none of which is released when the device is unbound. Every bind/unbind (or module reload) therefore leaks a provider structure and an of_node reference.
The clock itself is already device-managed (devm_clk_register()); only the provider registration was not. Use devm_of_clk_add_hw_provider() so the provider is removed automatically on unbind. Tie it to the parent i2c device, whose OF node carries the #clock-cells and clock-output-names properties (the RTC class device has no OF node of its own).
--- drivers/rtc/rtc-pcf8563.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/rtc/rtc-pcf8563.c +3 -1
@@ -494,7 +494,9 @@ static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563) clk =devm_clk_register (&client->dev, &pcf8563->clkout_hw);if (!IS_ERR (clk)) -of_clk_add_provider (node, of_clk_src_simple_get, clk); +devm_of_clk_add_hw_provider (pcf8563->rtc->dev.parent, + of_clk_hw_simple_get, + &pcf8563->clkout_hw);return clk; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1233/1376 smb: client: fix request buffer leak in smb2_new_read_req()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christopher Lusk <[email protected]>
[ Upstream commit deb6468f4164640e4dc875f008aa449cf55987a5 ]
smb2_new_read_req() allocates the request buffer with smb2_plain_req_init() but only publishes it to the caller with *buf = req at the very end of the function. Two error returns sit in between:
rc = smb2_plain_req_init(SMB2_READ, io_parms->tcon, server, (void **) &req, total_len); if (rc) return rc; if (server == NULL) return -ECONNABORTED; [...] rdata->mr = smbd_register_mr(server->smbd_conn, &rdata->subreq.io_iter, true, need_invalidate); if (!rdata->mr) return -EAGAIN;
On either of them the buffer is neither released nor handed back, so it is leaked. The caller cannot clean up after it: smb2_async_readv() does 'goto out' on a non-zero return, which skips the cifs_small_buf_release(buf) at async_readv_out, and buf has not been assigned at that point in any case.
The write path has never had this problem. smb2_async_writev() registers the memory region inline and jumps to its release label instead of returning:
wdata->mr = smbd_register_mr(...);
if (!wdata->mr) {
rc = -EAGAIN;
goto async_writev_out;
}Commit b7972092199f ("cifs: smbd: Retry on memory registration failure") changed both sides from -ENOBUFS to -EAGAIN in a single patch, which puts the two shapes next to each other.
Only the -EAGAIN return is reachable in practice, because smb2_plain_req_init() calls smb2_reconnect() first and that already fails with -EIO when server is NULL, before anything is allocated. Both returns are given the same treatment here rather than leaving one of them correct only by accident.
Because -EAGAIN is a replayable error, the failure also reaches the retry block at the end of smb2_async_readv(), which marks the subrequest NETFS_SREQ_NEED_RETRY, so a failing registration can be retried rather than ending the I/O, and every attempt that reaches it leaks another buffer. smb2_should_replay() short-circuits on tcon->retry, so on a hard mount the attempt count is not bounded by the retrans setting.
Only the asynchronous read path is affected. The synchronous SMB2_read() caller passes rdata == NULL and the memory registration block is guarded on rdata.
The memory registration failure path was pointed out by the Sashiko AI reviewer while it was reviewing an unrelated patch to smb2_async_readv().
--- fs/smb/client/smb2pdu.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
fs/smb/client/smb2pdu.c +12 -4
@@ -4458,8 +4458,10 @@ smb2_new_read_req(void **buf, unsigned int *total_len,if (rc)return rc; -if (server ==NULL ) -return -ECONNABORTED ; +if (!server) { + rc = -ECONNABORTED ; + goto free_req; + } shdr = &req->hdr; shdr->Id.SyncId.ProcessId =cpu_to_le32 (io_parms->pid);
@@ -4490,8 +4492,10 @@ smb2_new_read_req(void **buf, unsigned int *total_len, rdata->mr =smbd_register_mr (server->smbd_conn, &rdata->subreq.io_iter, true, need_invalidate); -if (!rdata->mr) -return -EAGAIN ; +if (!rdata->mr) { + rc = -EAGAIN ; + goto free_req; + } req->Channel =SMB2_CHANNEL_RDMA_V1_INVALIDATE ;if (need_invalidate)
@@ -4534,6 +4538,10 @@ smb2_new_read_req(void **buf, unsigned int *total_len, *buf = req;return rc; + +free_req: +cifs_small_buf_release (req); +return rc; } static void
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1234/1376 rtc: zynqmp: Return optional clock lookup errors
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 5904c4109554582ce8ded6a4dcfede48b21dbe4d ]
devm_clk_get_optional() returns NULL when the optional clock is absent, but returns an ERR_PTR when the clock provider lookup fails. Probe currently keeps the ERR_PTR and then passes it to clk_get_rate().
Return the lookup error instead. A truly absent optional clock still reaches the existing calibration fallback through clk_get_rate(NULL).
--- drivers/rtc/rtc-zynqmp.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/rtc/rtc-zynqmp.c +3 -4
@@ -320,10 +320,9 @@ static int xlnx_rtc_probe(struct platform_device *pdev)/* Getting the rtc info */ xrtcdev->rtc_clk =devm_clk_get_optional (&pdev->dev,"rtc" ); -if (IS_ERR (xrtcdev->rtc_clk)) { -if (PTR_ERR (xrtcdev->rtc_clk) != -EPROBE_DEFER ) -dev_warn (&pdev->dev,"Device clock not found.\n" ); - } +if (IS_ERR (xrtcdev->rtc_clk)) +return dev_err_probe (&pdev->dev,PTR_ERR (xrtcdev->rtc_clk), +"Failed to get rtc clock\n" ); xrtcdev->freq =clk_get_rate (xrtcdev->rtc_clk);if (!xrtcdev->freq) { ret = of_property_read_u32(pdev->dev.of_node, "calibration",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1235/1376 irqchip/renesas-rzg2l: Fix loss of interrupt
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Biju Das <[email protected]>
[ Upstream commit 50b10bd0c2d721ad38abd1abe3acdefb6caa0944 ]
rzg2l_clear_irq_int() and rzg2l_clear_tint_int() perform a read-modify-write on the ISCR/TSCR status registers to clear the bit for the interrupt just handled. Since these registers are write-0-to-clear per bit, this is racy:
If another interrupt's status bit gets set between the read and the write, that bit is written back as 0 by the software-constructed value, clearing an interrupt that hasn't been serviced yet and losing it.
This can be reproduced by triggering multiple interrupts at once, e.g.:
gpioset -c gpiochip0 355=0 353=0 328=0 352=0
Fix this by writing back only the bit being cleared, with all other bits set to 1, instead of read-modify-writing the whole register. Since 1-bits are left unchanged by hardware, concurrently-set status bits for other interrupts are preserved.
--- drivers/irqchip/irq-renesas-rzg2l.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/irqchip/irq-renesas-rzg2l.c +2 -2
@@ -104,7 +104,7 @@ static void rzg2l_clear_irq_int(struct rzg2l_irqc_priv *priv, unsigned int hwirq* falling/rising-edge. */ if ((iscr & bit) && (iitsr &IITSR_IITSEL_MASK (hw_irq))) { -writel_relaxed (iscr & ~bit, priv->base +ISCR ); +writel_relaxed (~bit, priv->base +ISCR );/* * Enforce that the posted write is flushed to prevent that the * just handled interrupt is raised again.
@@ -120,7 +120,7 @@ static void rzg2l_clear_tint_int(struct rzg2l_irqc_priv *priv, unsigned int hwir reg =readl_relaxed (priv->base +TSCR );if (reg & bit) { -writel_relaxed (reg & ~bit, priv->base +TSCR ); +writel_relaxed (~bit, priv->base +TSCR );/* * Enforce that the posted write is flushed to prevent that the * just handled interrupt is raised again.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1236/1376 i2c: ocores: Disable clock on failed resume
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit 43eb13f13385a1e7251978a1977ac61b99edef01 ]
ocores_i2c_resume() enables the controller clock before reinitializing the hardware. If the clock rate changed while the device was suspended, ocores_init() may reject the resulting prescaler. The callback then returns an error with the clock still enabled, while the controller itself remains disabled.
Disable and unprepare the clock when ocores_init() fails so the failed resume path balances the successful clk_prepare_enable() call.
This issue was found by a static analysis checker and confirmed by manual source review.
--- drivers/i2c/busses/i2c-ocores.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/i2c/busses/i2c-ocores.c +5 -1
@@ -761,7 +761,11 @@ static int ocores_i2c_resume(struct device *dev) rate =clk_get_rate (i2c->clk) /1000 ;if (rate) i2c->ip_clock_khz = rate; -return ocores_init (dev, i2c); + ret =ocores_init (dev, i2c); +if (ret) +clk_disable_unprepare (i2c->clk); + +return ret; } static DEFINE_NOIRQ_DEV_PM_OPS(ocores_i2c_pm,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1237/1376 rtc: gamecube: check return value of devm_rtc_register_device()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linkai Gong <[email protected]>
[ Upstream commit ca45cfa74370644d371b552bef57938c19e3c80c ]
gamecube_rtc_probe() ignored the return value of devm_rtc_register_device() and always returned success. Propagate the error so probe fails when RTC registration fails.
--- drivers/rtc/rtc-gamecube.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/rtc/rtc-gamecube.c +1 -3
@@ -355,9 +355,7 @@ static int gamecube_rtc_probe(struct platform_device *pdev) rtc->range_max =U32_MAX ; rtc->ops = &gamecube_rtc_ops; -devm_rtc_register_device (rtc); - -return 0 ; +return devm_rtc_register_device (rtc); }static const struct of_device_id gamecube_rtc_of_match[] = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1238/1376 prctl: fix PR_SET_MM_AUXV losing the forced AT_NULL terminator
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bradley Morgan <[email protected]>
[ Upstream commit 5146e0688d86f0654263e4b0e4ff1719b4072f16 ]
prctl_set_auxv() copies the user vector into a stack buffer, forces AT_NULL on the last two entries there, and then copies only len bytes into mm->saved_auxv. Which is fine until the vector is shorter than the buffer, because then the forced terminator sits past the end of the copy and never lands in saved_auxv at all.
The code even says
/* Make sure the last entry is always AT_NULL */
and it does, just not in the part that gets copied.
So mm->saved_auxv keeps the stale tail from exec. Reproducing it is easy:
from a process with CAP_SYS_RESOURCE (just run it as root), call prctl(PR_SET_MM, PR_SET_MM_AUXV, ...) with a vector that has a couple of entries and no AT_NULL inside len (32 bytes on arm64), and then hexdump /proc/self/auxv, or gcore the process and look at the AUXV note with readelf -n. This is arm64, the new vector was just { AT_UID, 0x1111, AT_GID, 0x2222 }:
idx before (from exec) after the prctl
[0] AT_SYSINFO_EHDR 0x7ed1d6e000 AT_UID 0x1111 <- new
[1] AT_MINSIGSTKSZ 0x1270 AT_GID 0x2222 <- new
[2] AT_HWCAP 0x119fff AT_HWCAP 0x119fff <- stale
[3] AT_PAGESZ 0x1000 AT_PAGESZ 0x1000 <- stale
... 16 more entries ... <- stale
[20] AT_NULL 0x0 AT_NULL 0x021 entries before the prctl, still 21 after: the two new ones plus all 19 left over from exec.
Every consumer walks the vector until AT_NULL, so what they get now is a vector that never existed at exec, the head from the prctl glued onto the tail of the old binary. gdb and crash pull the AUXV note out of coredumps to find AT_PHDR, AT_ENTRY, AT_SYSINFO_EHDR and friends, and a mixed vector points them at the wrong layout. /proc/<pid>/auxv and PR_GET_AUXV hand the same mess out to live processes too. Nothing crashes, everything just quietly reads a frankenstein auxv.
And callers that terminate their own vector hide the whole thing, which is likely why nobody noticed since PR_SET_MM_AUXV landed in 2012. Nothing exciting security wise either, I mean it needs CAP_SYS_RESOURCE to begin with.
prctl_set_mm_map() right above already copies the whole buffer for exactly this reason, so just do the same here. user_auxv is zero initialized and only partially filled from userspace, so the rest is zeros and nothing leaks.
--- kernel/sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/sys.c +1 -1
@@ -2153,7 +2153,7 @@ static int prctl_set_auxv(struct mm_struct *mm, unsigned long addr,BUILD_BUG_ON (sizeof (user_auxv) !=sizeof (mm->saved_auxv));task_lock (current); -memcpy (mm->saved_auxv, user_auxv, len); +memcpy (mm->saved_auxv, user_auxv,sizeof (user_auxv));task_unlock (current);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1239/1376 clk: ti: Make sure clk_init_data is fully initialized
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geert Uytterhoeven <[email protected]>
[ Upstream commit 3ae1674975d48fb6d343d03ff7961abd6904af1a ]
The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled.
_register_mux() fills in init.parent_data, and assumes that init.parent_names is NULL. However, the latter is uninitialized, and thus may cause a crash.
Make sure all members are fully initialized, to fix such bugs, and to avoid future breakage when converting drivers to a different method for specifying the parents.
--- drivers/clk/ti/adpll.c | 4 ++-- drivers/clk/ti/divider.c | 2 +- drivers/clk/ti/mux.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-)
drivers/clk/ti/adpll.c +2 -2
@@ -483,7 +483,7 @@ static const struct clk_ops ti_adpll_ops = {static int ti_adpll_init_dco (struct ti_adpll_data *d) { -struct clk_init_data init; +struct clk_init_data init = {};struct clk *clock;const char *postfix;int width, err;
@@ -576,7 +576,7 @@ static int ti_adpll_init_clkout(struct ti_adpll_data *d, struct clk *clk1) {struct ti_adpll_clkout_data *co; -struct clk_init_data init; +struct clk_init_data init = {};struct clk_ops *ops;const char *parent_names[2 ];const char *child_name;
drivers/clk/ti/divider.c +1 -1
@@ -309,7 +309,7 @@ static struct clk *_register_divider(struct device_node *node,u32 flags, struct clk_omap_divider *div) { - struct clk_init_data init; + struct clk_init_data init = {};const char *parent_name;const char *name;
drivers/clk/ti/mux.c +1 -1
@@ -124,9 +124,9 @@ static struct clk *_register_mux(struct device_node *node, const char *name, struct clk_omap_reg *reg, u8 shift, u32 mask, s8 latch, u8 clk_mux_flags, u32 *table) { + struct clk_init_data init = {};struct clk_omap_mux *mux;struct clk *clk; -struct clk_init_data init;/* allocate the mux */ mux =kzalloc (sizeof (*mux),GFP_KERNEL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1240/1376 clk: visconti: Make sure clk_init_data is fully initialized
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geert Uytterhoeven <[email protected]>
[ Upstream commit 39c0e6c844a14945040cca4ccf6997792ab764c4 ]
The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled.
visconti_clk_register_gate() fills in init.parent_data, and assumes that init.parent_names is NULL. However, the latter in uninitialized, and thus may cause a crash.
Make sure all members are fully initialized, to fix such bugs, and to avoid future breakage when converting drivers to a different method for specifying the parents.
--- drivers/clk/visconti/clkc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/visconti/clkc.c +1 -1
@@ -81,9 +81,9 @@ static struct clk_hw *visconti_clk_register_gate(struct device *dev,u8 rs_idx, spinlock_t *lock) { + struct clk_init_data init = {};struct visconti_clk_gate *gate;struct clk_parent_data *pdata; -struct clk_init_data init;struct clk_hw *hw;int ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1241/1376 ALSA: core: Add scoped cleanup helper for card references
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cássio Gabriel <[email protected]>
[ Upstream commit c6c6f0aec6fb4cbcc547bb265315fd76f18be731 ]
Several ALSA paths acquire temporary card references with snd_card_ref() and release them manually with snd_card_unref(). control_led.c already defines a local cleanup helper for this pattern, while other core paths still open-code the release.
Move the helper to the common ALSA core header and use it in control-layer card-reference paths. This makes the ownership rule explicit and avoids future missing-unref mistakes when adding early exits.
No functional change is intended.
Stable-dep-of: d736eba9c453 ("ALSA: ice1712: Fix the card leak at probe error with the auto-cleanup")
--- include/sound/core.h | 2 ++ sound/core/control.c | 6 +++--- sound/core/control_led.c | 11 ++++------- 3 files changed, 9 insertions(+), 10 deletions(-)
include/sound/core.h +2 -0
@@ -314,6 +314,8 @@ static inline void snd_card_unref(struct snd_card *card)put_device (&card->card_dev); } +DEFINE_FREE(snd_card_unref, struct snd_card *, if (_T) snd_card_unref(_T)) +#define snd_card_set_dev (card, devptr) ((card)->dev = (devptr))/* device.c */
sound/core/control.c +3 -3
@@ -2219,7 +2219,6 @@ EXPORT_SYMBOL_GPL(snd_ctl_request_layer);*/ void snd_ctl_register_layer (struct snd_ctl_layer_ops *lops) { -struct snd_card *card;int card_number; scoped_guard(rwsem_write, &snd_ctl_layer_rwsem) {
@@ -2227,11 +2226,12 @@ void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops) snd_ctl_layer = lops; }for (card_number =0 ; card_number <SNDRV_CARDS ; card_number++) { - card =snd_card_ref (card_number); + struct snd_card *card __free(snd_card_unref) = +snd_card_ref (card_number); +if (card) {scoped_guard (rwsem_read, &card->controls_rwsem) lops->lregister(card); -snd_card_unref (card); } } }
sound/core/control_led.c +4 -7
@@ -240,8 +240,6 @@ static void snd_ctl_led_notify(struct snd_card *card, unsigned int mask, } } -DEFINE_FREE(snd_card_unref, struct snd_card *, if (_T) snd_card_unref(_T)) -static int snd_ctl_led_set_id (int card_number,struct snd_ctl_elem_id *id,unsigned int group,bool set) {
@@ -758,18 +756,17 @@ static int __init snd_ctl_led_init(void) static void __exit snd_ctl_led_exit(void) {struct snd_ctl_led *led; -struct snd_card *card;unsigned int group, card_number;snd_ctl_disconnect_layer (&snd_ctl_led_lops);for (card_number =0 ; card_number <SNDRV_CARDS ; card_number++) {if (!snd_ctl_led_card_valid[card_number])continue ; - card =snd_card_ref (card_number); -if (card) { + struct snd_card *card __free(snd_card_unref) = +snd_card_ref (card_number); + +if (card)snd_ctl_led_sysfs_remove (card); -snd_card_unref (card); - } }for (group =0 ; group <MAX_LED ; group++) { led = &snd_ctl_leds[group];
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1242/1376 ALSA: ice1712: Fix the card leak at probe error with the auto-cleanup
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haotian Zhang <[email protected]>
[ Upstream commit d736eba9c453fedce664fdf592c8b71ecff1932b ]
snd_ice1712_probe() performs multiple initialization steps after snd_card_new(), but directly returns on failures from later steps without releasing the ALSA card, causing resource leaks when probing fails.
Use snd_devm_card_new() together with scope-based cleanup via __free(snd_card_unref), and clear the card pointer after successful registration to keep it alive.
--- sound/pci/ice1712/ice1712.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
sound/pci/ice1712/ice1712.c +4 -3
@@ -2549,7 +2549,7 @@ static int snd_ice1712_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) {static int dev; -struct snd_card *card; + struct snd_card *card __free(snd_card_unref) = NULL;struct snd_ice1712 *ice;int pcm_dev =0 , err;const struct snd_ice1712_card_info *const *tbl, *c;
@@ -2561,8 +2561,8 @@ static int snd_ice1712_probe(struct pci_dev *pci,return -ENOENT ; } - err =snd_card_new (&pci->dev, index[dev], id[dev],THIS_MODULE , -sizeof (*ice), &card); + err =snd_devm_card_new (&pci->dev, index[dev], id[dev],THIS_MODULE , +sizeof (*ice), &card);if (err <0 )return err; ice = card->private_data;
@@ -2666,6 +2666,7 @@ static int snd_ice1712_probe(struct pci_dev *pci,if (err <0 )return err;pci_set_drvdata (pci, card); + card =NULL ;/* probe succeeded, don't release as error */ dev++;return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1243/1376 RDMA/ucma: Allow path records to exactly fit the output buffer
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Serhat Kumral <[email protected]>
[ Upstream commit 8049741ac93acd3a590dac070e12571fddf0e294 ]
ucma_query_path() emits a path record only when the remaining output buffer is strictly larger than struct ib_path_rec_data. A buffer sized exactly for the response header and N complete records therefore gets only N - 1 records, while resp->num_paths still advertises N. A caller sizing its buffer for a single record gets a header claiming one path and no path data at all.
ucma_query_ib_service() in the same file computes the record count with a plain division and so accepts an exact fit; make ucma_query_path() behave the same way.
Current librdmacm is unaffected because it always sizes the response for six records while the kernel currently reports at most two paths. Other users of the UAPI that provide an exactly sized buffer can observe the truncated response.
--- drivers/infiniband/core/ucma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/core/ucma.c +1 -1
@@ -922,7 +922,7 @@ static ssize_t ucma_query_path(struct ucma_context *ctx, resp->num_paths = ctx->cm_id->route.num_pri_alt_paths;for (i =0 , out_len -=sizeof (*resp); - i < resp->num_paths && out_len >sizeof (struct ib_path_rec_data ); + i < resp->num_paths && out_len >=sizeof (struct ib_path_rec_data ); i++, out_len -=sizeof (struct ib_path_rec_data )) {struct sa_path_rec *rec = &ctx->cm_id->route.path_rec[i];
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1244/1376 xsk: Get rid of xdp_buff_xsk::orig_addr
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej Fijalkowski <[email protected]>
[ Upstream commit bea14124bacbe5c9366381e62635eed28ac892ae ]
Continue the process of dieting xdp_buff_xsk by removing orig_addr member. It can be calculated from xdp->data_hard_start where it was previously used, so it is not anything that has to be carried around in struct used widely in hot path.
This has been used for initializing xdp_buff_xsk::frame_dma during pool setup and as a shortcut in xp_get_handle() to retrieve address provided to xsk Rx queue.
Stable-dep-of: e37b2abca804 ("xsk: fix NULL pointer dereference in __xsk_rcv()")
--- include/net/xsk_buff_pool.h | 19 +++++++++++-------- net/xdp/xsk.c | 2 +- net/xdp/xsk_buff_pool.c | 4 +++- 3 files changed, 15 insertions(+), 10 deletions(-)
include/net/xsk_buff_pool.h +11 -8
@@ -28,7 +28,6 @@ struct xdp_buff_xsk {dma_addr_t dma;dma_addr_t frame_dma;struct xsk_buff_pool *pool; -u64 orig_addr;struct list_head list_node; };
@@ -121,7 +120,6 @@ void xp_free(struct xdp_buff_xsk *xskb);static inline void xp_init_xskb_addr (struct xdp_buff_xsk *xskb,struct xsk_buff_pool *pool,u64 addr) { - xskb->orig_addr = addr; xskb->xdp.data_hard_start = pool->addrs + addr + pool->headroom; }
@@ -223,14 +221,19 @@ static inline void xp_release(struct xdp_buff_xsk *xskb) xskb->pool->free_heads[xskb->pool->free_heads_cnt++] = xskb; } -static inline u64 xp_get_handle (struct xdp_buff_xsk *xskb) +static inline u64 xp_get_handle (struct xdp_buff_xsk *xskb, +struct xsk_buff_pool *pool) { -u64 offset = xskb->xdp.data - xskb->xdp.data_hard_start; +u64 orig_addr = xskb->xdp.data - pool->addrs; +u64 offset; - offset += xskb->pool->headroom; -if (!xskb->pool->unaligned) -return xskb->orig_addr + offset; -return xskb->orig_addr + (offset <<XSK_UNALIGNED_BUF_OFFSET_SHIFT ); +if (!pool->unaligned) +return orig_addr; + + offset = xskb->xdp.data - xskb->xdp.data_hard_start; + orig_addr -= offset; + offset += pool->headroom; +return orig_addr + (offset <<XSK_UNALIGNED_BUF_OFFSET_SHIFT ); }static inline bool xp_tx_metadata_enabled (const struct xsk_buff_pool *pool)
net/xdp/xsk.c +1 -1
@@ -141,7 +141,7 @@ static int __xsk_rcv_zc(struct xdp_sock *xs, struct xdp_buff_xsk *xskb, u32 len,u64 addr;int err; - addr =xp_get_handle (xskb); + addr =xp_get_handle (xskb, xskb->pool); err =xskq_prod_reserve_desc (xs->rx, addr, len, flags);if (err) { xs->rx_queue_full++;
net/xdp/xsk_buff_pool.c +3 -1
@@ -442,8 +442,10 @@ static int xp_init_dma_info(struct xsk_buff_pool *pool, struct xsk_dma_map *dma_for (i =0 ; i < pool->heads_cnt; i++) {struct xdp_buff_xsk *xskb = &pool->heads[i]; +u64 orig_addr; -xp_init_xskb_dma (xskb, pool, dma_map->dma_pages, xskb->orig_addr); + orig_addr = xskb->xdp.data_hard_start - pool->addrs - pool->headroom; +xp_init_xskb_dma (xskb, pool, dma_map->dma_pages, orig_addr); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1245/1376 xsk: avoid double checking against rx queue being full
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej Fijalkowski <[email protected]>
[ Upstream commit f620af11c27b8ec9994a39fe968aa778112d1566 ]
Currently non-zc xsk rx path for multi-buffer case checks twice if xsk rx queue has enough space for producing descriptors:
1.
if (xskq_prod_nb_free(xs->rx, num_desc) < num_desc) {
xs->rx_queue_full++;
return -ENOBUFS;
}
2.
__xsk_rcv_zc(xs, xskb, copied - meta_len, rem ? XDP_PKT_CONTD : 0);
-> err = xskq_prod_reserve_desc(xs->rx, addr, len, flags);
-> if (xskq_prod_is_full(q))Second part is redundant as in 1. we already peeked onto rx queue and checked that there is enough space to produce given amount of descriptors.
Provide helper functions that will skip it and therefore optimize code.
Stable-dep-of: e37b2abca804 ("xsk: fix NULL pointer dereference in __xsk_rcv()")
--- net/xdp/xsk.c | 14 +++++++++++++- net/xdp/xsk_queue.h | 16 +++++++++++----- 2 files changed, 24 insertions(+), 6 deletions(-)
net/xdp/xsk.c +13 -1
@@ -152,6 +152,17 @@ static int __xsk_rcv_zc(struct xdp_sock *xs, struct xdp_buff_xsk *xskb, u32 len,return 0 ; } +static void __xsk_rcv_zc_safe (struct xdp_sock *xs,struct xdp_buff_xsk *xskb, +u32 len,u32 flags) +{ +u64 addr; + + addr =xp_get_handle (xskb, xskb->pool); +__xskq_prod_reserve_desc (xs->rx, addr, len, flags); + +xp_release (xskb); +} +static int xsk_rcv_zc (struct xdp_sock *xs,struct xdp_buff *xdp,u32 len) { struct xdp_buff_xsk *xskb = container_of(xdp, struct xdp_buff_xsk, xdp);
@@ -290,7 +301,8 @@ static int __xsk_rcv(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len) rem -= copied; xskb = container_of(xsk_xdp, struct xdp_buff_xsk, xdp); -__xsk_rcv_zc (xs, xskb, copied - meta_len, rem ?XDP_PKT_CONTD :0 ); +__xsk_rcv_zc_safe (xs, xskb, copied - meta_len, + rem ?XDP_PKT_CONTD :0 ); meta_len =0 ; }while (rem);
net/xdp/xsk_queue.h +11 -5
@@ -428,20 +428,26 @@ static inline void xskq_prod_write_addr_batch(struct xsk_queue *q, struct xdp_de q->cached_prod = cached_prod; } -static inline int xskq_prod_reserve_desc (struct xsk_queue *q, -u64 addr,u32 len,u32 flags) +static inline void __xskq_prod_reserve_desc (struct xsk_queue *q, +u64 addr,u32 len,u32 flags) {struct xdp_rxtx_ring *ring = (struct xdp_rxtx_ring *)q->ring;u32 idx; -if (xskq_prod_is_full (q)) -return -ENOBUFS ; -/* A, matches D */ idx = q->cached_prod++ & q->ring_mask; ring->desc[idx].addr = addr; ring->desc[idx].len = len; ring->desc[idx].options = flags; +} + +static inline int xskq_prod_reserve_desc (struct xsk_queue *q, +u64 addr,u32 len,u32 flags) +{ +if (xskq_prod_is_full (q)) +return -ENOBUFS ; + +__xskq_prod_reserve_desc (q, addr, len, flags);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1246/1376 xsk: fix NULL pointer dereference in __xsk_rcv()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang (Microsoft) <[email protected]>
[ Upstream commit e37b2abca80473e106176e41712a369fd2f72117 ]
In the __xsk_rcv() multi-buffer path, xsk_buff_alloc() is called in a loop without checking its return value. xsk_buff_can_alloc() only counts fill queue entries without validating their addresses, so it can succeed while xsk_buff_alloc() rejects all remaining entries and returns NULL.
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000000 KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] RIP: 0010:__xsk_rcv+0x426/0xc20 (net/xdp/xsk.c:350) Call Trace: xsk_generic_rcv+0x26d/0x5f0 xdp_do_generic_redirect+0x3c5/0xcf0 do_xdp_generic+0x92f/0xe70 __netif_receive_skb_core.constprop.0+0xf7e/0x2b30
Fix this with a two-stage transaction. First allocate and stage all buffers required for the packet, recycling all staged buffers with xsk_buff_free() if any allocation fails. Only after this stage succeeds, copy the data, reserve the RX descriptors, and release the buffers in an error-free loop.
--- net/xdp/xsk.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-)
net/xdp/xsk.c +27 -3
@@ -245,9 +245,11 @@ static int __xsk_rcv(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len)u32 frame_size =__xsk_pool_get_rx_frame_size (xs->pool);void *copy_from =xsk_copy_xdp_start (xdp), *copy_to;u32 from_len, meta_len, rem, num_desc; -struct xdp_buff_xsk *xskb; +struct xdp_buff_xsk *xskb, *tmp;struct xdp_buff *xsk_xdp; +LIST_HEAD (xsk_buffs);skb_frag_t *frag; +u32 i; from_len = xdp->data_end - copy_from; meta_len = xdp->data - copy_from;
@@ -290,23 +292,45 @@ static int __xsk_rcv(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len) frag = &sinfo->frags[0 ]; } +for (i =0 ; i < num_desc; i++) { + xsk_xdp =xsk_buff_alloc (xs->pool); +if (!xsk_xdp) + goto err_alloc; + + xskb = container_of(xsk_xdp, struct xdp_buff_xsk, xdp); +if (unlikely (!list_empty (&xskb->list_node))) + goto err_alloc; + +list_add_tail (&xskb->list_node, &xsk_buffs); + } +do {u32 to_len = frame_size + meta_len;u32 copied; - xsk_xdp =xsk_buff_alloc (xs->pool); + xskb = list_first_entry(&xsk_buffs, struct xdp_buff_xsk, + list_node); +list_del_init (&xskb->list_node); + xsk_xdp = &xskb->xdp; copy_to = xsk_xdp->data - meta_len; copied =xsk_copy_xdp (copy_to, ©_from, to_len, &from_len, &frag, rem); rem -= copied; - xskb = container_of(xsk_xdp, struct xdp_buff_xsk, xdp);__xsk_rcv_zc_safe (xs, xskb, copied - meta_len, rem ?XDP_PKT_CONTD :0 ); meta_len =0 ; }while (rem);return 0 ; + +err_alloc: +list_for_each_entry_safe (xskb, tmp, &xsk_buffs, list_node) { +list_del_init (&xskb->list_node); +xsk_buff_free (&xskb->xdp); + } + xs->rx_dropped++; +return -ENOMEM ; }static bool xsk_tx_writeable (struct xdp_sock *xs)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1247/1376 net: bridge: Reject descending VLAN tunnel ranges
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit b74a072d8fb71d3c9ffba4a17d5943e63266fb38 ]
A pair of descending VLAN and tunnel IDs can pass the tunnel range span check. The VLAN subtraction produces a negative int, which is converted to unsigned when compared with the u32 tunnel ID subtraction. It can therefore equal the wrapped tunnel ID delta.
The range loop then performs no iterations. Since the batched notification handling added a post-loop error check, this leaves err uninitialized and makes the request's return value unpredictable.
Reject descending VLAN ranges before comparing the spans. Valid ascending and single-entry ranges remain unchanged, while malformed descending ranges consistently return -EINVAL.
This issue was found by a static analysis checker and confirmed by manual source review.
--- net/bridge/br_netlink_tunnel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/bridge/br_netlink_tunnel.c +2 -1
@@ -302,7 +302,8 @@ int br_process_vlan_tunnel_info(const struct net_bridge *br,if (!(tinfo_last->flags &BRIDGE_VLAN_INFO_RANGE_BEGIN ))return -EINVAL ; -if ((tinfo_curr->vid - tinfo_last->vid) != +if (tinfo_curr->vid < tinfo_last->vid || + (tinfo_curr->vid - tinfo_last->vid) != (tinfo_curr->tunid - tinfo_last->tunid))return -EINVAL ; t = tinfo_last->tunid;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1248/1376 net/sched: add get_fill_size callbacks for actions missing them
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Victor Nogueira <[email protected]>
[ Upstream commit 8e2efb3f45a5c6f7c8f68685c1c4709040aa2fa0 ]
Several tc actions - act_police, act_bpf, act_pedit, act_ife, act_sample, act_ct, act_ctinfo and act_tunnel_key among them - provide no get_fill_size() callback, so tcf_action_fill_size() falls back to tcf_action_shared_attrs_size() which does not account for the action-specific netlink attributes emitted inside TCA_ACT_OPTIONS by their dump functions.
When an RTM_NEWACTION request with NLM_F_ECHO (or an RTNLGRP_TC listener) creates several actions, tcf_add_notify_msg() allocates the echo skb from this underestimated size. When this happens, the act_api code fails to add all of the fields to the netlink message and, thus, fails to send it. Issue is that, when that happens, this failure doesn't stop the action instances from being added. So any user watching these events will be under the false impression that no actions were created at all.
For example, act_pedit overruns with 32 actions of four munge keys each, act_police with 32 policers once the optional rate/peakrate/result/avrate attributes are present.
To fix this, add the missing get_fill_size callbacks returning the worst-case size of each action's dump attributes, following the pattern used by act_gact/act_skbedit/act_vlan. Also widen the TCA_GACT_TM accounting in tcf_action_shared_attrs_size() to nla_total_size_64bit(), since actions dump their tcf_t with nla_put_64bit(), which may be preceded by an NLA_PAD attribute.
Note: We only provided fixes for the actions we reproduced this bug with as of today. We can send a separate hardening patch for the remaining actions to net-next later. The other pre-existing issues, pointed out by Clashiko [1], will be fixed in upcoming patches.
[1] https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260810164357.1653956-1-victor%40mojatatu.com
--- net/sched/act_api.c | 5 ++- net/sched/act_bpf.c | 26 +++++++++++++ net/sched/act_ct.c | 46 ++++++++++++++++++++++ net/sched/act_ctinfo.c | 11 ++++++ net/sched/act_ife.c | 23 +++++++++++ net/sched/act_pedit.c | 24 ++++++++++++ net/sched/act_police.c | 12 ++++++ net/sched/act_sample.c | 9 +++++ net/sched/act_tunnel_key.c | 80 ++++++++++++++++++++++++++++++++++++++ 9 files changed, 235 insertions(+), 1 deletion(-)
net/sched/act_api.c +4 -1
@@ -452,7 +452,10 @@ static size_t tcf_action_shared_attrs_size(const struct tc_action *act)/* TCA_STATS_QUEUE */ +nla_total_size_64bit (sizeof (struct gnet_stats_queue )) +nla_total_size (0 )/* TCA_ACT_OPTIONS nested */ - +nla_total_size (sizeof (struct tcf_t ));/* TCA_GACT_TM */ +/* TCA_GACT_TM; actions dump their tcf_t with nla_put_64bit(), +* which may emit an extra NLA_PAD attribute. +*/ + +nla_total_size_64bit (sizeof (struct tcf_t )); }static size_t tcf_action_full_attrs_size (size_t sz)
net/sched/act_bpf.c +26 -0
@@ -389,6 +389,31 @@ static void tcf_bpf_cleanup(struct tc_action *act)tcf_bpf_cfg_cleanup (&tmp); } +static size_t tcf_bpf_get_fill_size (const struct tc_action *act) +{ +struct tcf_bpf *prog =to_bpf (act); +size_t size =nla_total_size (sizeof (struct tc_act_bpf )); + +/* bpf_ops and bpf_num_ops are published as separate stores under +* tcf_lock, so take it here as tcf_bpf_dump() does. +*/ +spin_lock_bh (&prog->tcf_lock); +if (tcf_bpf_is_ebpf (prog)) { +/* TCA_ACT_BPF_NAME */ + size +=nla_total_size (ACT_BPF_NAME_LEN +1 ); + size +=nla_total_size (sizeof (u32));/* TCA_ACT_BPF_ID */ + size +=nla_total_size (BPF_TAG_SIZE );/* TCA_ACT_BPF_TAG */ + }else { + size +=nla_total_size (sizeof (u16));/* TCA_ACT_BPF_OPS_LEN */ +/* TCA_ACT_BPF_OPS */ + size +=nla_total_size (prog->bpf_num_ops * +sizeof (struct sock_filter )); + } +spin_unlock_bh (&prog->tcf_lock); + +return size; +} +static struct tc_action_ops act_bpf_ops__read_mostly = { .kind ="bpf" , .id =TCA_ID_BPF ,
@@ -397,6 +422,7 @@ static struct tc_action_ops act_bpf_ops __read_mostly = { .dump = tcf_bpf_dump, .cleanup = tcf_bpf_cleanup, .init = tcf_bpf_init, + .get_fill_size = tcf_bpf_get_fill_size, .size = sizeof(struct tcf_bpf), };MODULE_ALIAS_NET_ACT ("bpf" );
net/sched/act_ct.c +46 -0
58 lines not on this page · raw message
net/sched/act_ctinfo.c +11 -0
@@ -356,6 +356,16 @@ static void tcf_ctinfo_cleanup(struct tc_action *a)kfree_rcu (cp, rcu); } +static size_t tcf_ctinfo_get_fill_size (const struct tc_action *act) +{ +return nla_total_size (sizeof (struct tc_ctinfo ))/* TCA_CTINFO_ACT */ + +nla_total_size (sizeof (u16))/* TCA_CTINFO_ZONE */ +/* TCA_CTINFO_PARMS_{DSCP_MASK,DSCP_STATEMASK,CPMARK_MASK} */ + +3 *nla_total_size (sizeof (u32)) +/* TCA_CTINFO_STATS_{DSCP_SET,DSCP_ERROR,CPMARK_SET} */ + +3 *nla_total_size_64bit (sizeof (u64)); +} +static struct tc_action_ops act_ctinfo_ops = { .kind ="ctinfo" , .id =TCA_ID_CTINFO ,
@@ -364,6 +374,7 @@ static struct tc_action_ops act_ctinfo_ops = { .dump = tcf_ctinfo_dump, .init = tcf_ctinfo_init, .cleanup= tcf_ctinfo_cleanup, + .get_fill_size = tcf_ctinfo_get_fill_size, .size = sizeof(struct tcf_ctinfo), };MODULE_ALIAS_NET_ACT ("ctinfo" );
net/sched/act_ife.c +23 -0
@@ -878,6 +878,28 @@ TC_INDIRECT_SCOPE int tcf_ife_act(struct sk_buff *skb,return tcf_ife_decode (skb, a, res); } +static size_t tcf_ife_get_fill_size (const struct tc_action *act) +{ +struct tcf_ife_info *ife =to_ife (act); +const struct tcf_ife_params *p; +struct tcf_meta_info *e; +size_t size =nla_total_size (sizeof (struct tc_ife ))/* TCA_IFE_PARMS */ + +nla_total_size (ETH_ALEN )/* TCA_IFE_DMAC */ + +nla_total_size (ETH_ALEN )/* TCA_IFE_SMAC */ + +nla_total_size (2 )/* TCA_IFE_TYPE */ + +nla_total_size (0 );/* TCA_IFE_METALST */ + +rcu_read_lock (); + p =rcu_dereference (ife->params); +if (p) { +list_for_each_entry_rcu (e, &p->metalist, metalist) + size +=nla_total_size (sizeof (u32)); + } +rcu_read_unlock (); + +return size; +} +static struct tc_action_ops act_ife_ops = { .kind ="ife" , .id =TCA_ID_IFE ,
@@ -886,6 +908,7 @@ static struct tc_action_ops act_ife_ops = { .dump = tcf_ife_dump, .cleanup = tcf_ife_cleanup, .init = tcf_ife_init, + .get_fill_size = tcf_ife_get_fill_size, .size = sizeof(struct tcf_ife_info), };MODULE_ALIAS_NET_ACT ("ife" );
net/sched/act_pedit.c +24 -0
@@ -622,6 +622,29 @@ static int tcf_pedit_offload_act_setup(struct tc_action *act, void *entry_data,return 0 ; } +static size_t tcf_pedit_get_fill_size (const struct tc_action *act) +{ +const struct tcf_pedit_parms *parms; +size_t size; + +rcu_read_lock (); + parms =rcu_dereference (to_pedit (act)->parms); + size = nla_total_size(struct_size_t(struct tc_pedit, keys, + parms->tcfp_nkeys)); +if (parms->tcfp_keys_ex) { +/* TCA_PEDIT_KEYS_EX, holding one TCA_PEDIT_KEY_EX nest with a +* HTYPE and a CMD attribute per key. +*/ + size +=nla_total_size (0 ) + + parms->tcfp_nkeys * (nla_total_size (0 ) + +nla_total_size (sizeof (u16)) + +nla_total_size (sizeof (u16))); + } +rcu_read_unlock (); + +return size; +} +static struct tc_action_ops act_pedit_ops = { .kind ="pedit" , .id =TCA_ID_PEDIT ,
@@ -631,6 +654,7 @@ static struct tc_action_ops act_pedit_ops = { .dump = tcf_pedit_dump, .cleanup = tcf_pedit_cleanup, .init = tcf_pedit_init, + .get_fill_size = tcf_pedit_get_fill_size, .offload_act_setup = tcf_pedit_offload_act_setup, .size = sizeof(struct tcf_pedit), };
net/sched/act_police.c +12 -0
@@ -492,6 +492,17 @@ static int tcf_police_offload_act_setup(struct tc_action *act, void *entry_data,return 0 ; } +static size_t tcf_police_get_fill_size (const struct tc_action *act) +{ +return nla_total_size (sizeof (struct tc_police ))/* TCA_POLICE_TBF */ + +nla_total_size_64bit (sizeof (u64))/* TCA_POLICE_RATE64 */ + +nla_total_size_64bit (sizeof (u64))/* TCA_POLICE_PEAKRATE64 */ + +nla_total_size_64bit (sizeof (u64))/* TCA_POLICE_PKTRATE64 */ + +nla_total_size_64bit (sizeof (u64))/* TCA_POLICE_PKTBURST64 */ + +nla_total_size (sizeof (u32))/* TCA_POLICE_RESULT */ + +nla_total_size (sizeof (u32));/* TCA_POLICE_AVRATE */ +} +MODULE_AUTHOR ("Alexey Kuznetsov" );MODULE_DESCRIPTION ("Policing actions" );MODULE_LICENSE ("GPL" );
@@ -505,6 +516,7 @@ static struct tc_action_ops act_police_ops = { .dump = tcf_police_dump, .init = tcf_police_init, .cleanup = tcf_police_cleanup, + .get_fill_size = tcf_police_get_fill_size, .offload_act_setup = tcf_police_offload_act_setup, .size = sizeof(struct tcf_police), };
net/sched/act_sample.c +9 -0
@@ -315,6 +315,14 @@ static int tcf_sample_offload_act_setup(struct tc_action *act, void *entry_data,return 0 ; } +static size_t tcf_sample_get_fill_size (const struct tc_action *act) +{ +return nla_total_size (sizeof (struct tc_sample ))/* TCA_SAMPLE_PARMS */ + +nla_total_size (sizeof (u32))/* TCA_SAMPLE_RATE */ + +nla_total_size (sizeof (u32))/* TCA_SAMPLE_TRUNC_SIZE */ + +nla_total_size (sizeof (u32));/* TCA_SAMPLE_PSAMPLE_GROUP */ +} +static struct tc_action_ops act_sample_ops = { .kind ="sample" , .id =TCA_ID_SAMPLE ,
@@ -324,6 +332,7 @@ static struct tc_action_ops act_sample_ops = { .dump = tcf_sample_dump, .init = tcf_sample_init, .cleanup = tcf_sample_cleanup, + .get_fill_size = tcf_sample_get_fill_size, .get_psample_group = tcf_sample_get_group, .offload_act_setup = tcf_sample_offload_act_setup, .size = sizeof(struct tcf_sample),
net/sched/act_tunnel_key.c +80 -0
92 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1249/1376 net: thunderbolt: Count delivered packets in rx_packets and rx_bytes
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Ye <[email protected]>
[ Upstream commit c5ae83ee02c04487b1be1d143b791ec2caca888e ]
tbnet_poll() increments rx_packets once per received frame because that is the NAPI work unit, and then adds the same number to stats.rx_packets. An skb is handed to the stack only when the last frame of a packet arrives, so once the MTU exceeds TBNET_MAX_PAYLOAD_SIZE the statistic reports frames. tx_packets is bumped once per skb, so the two ends of a link
disagree: at MTU 65330 the receiver reports 16 times the packets its sender sent.
rx_bytes has the matching problem: frames of a packet that is later dropped mid-assembly are already accounted, so it does not correspond to rx_packets as documented. Account for both where the packet is completed, and leave the NAPI work counter alone.
--- drivers/net/thunderbolt/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/net/thunderbolt/main.c +3 -3
@@ -907,9 +907,11 @@ static int tbnet_poll(struct napi_struct *napi, int budget)le32_to_cpu (net->rx_hdr.frame_count) -1 ; rx_packets++; - net->stats.rx_bytes += frame_size;if (last) { +/* Before eth_type_trans() pulls the Ethernet header. */ + net->stats.rx_packets++; + net->stats.rx_bytes += skb->len; skb->protocol =eth_type_trans (skb, net->dev);trace_tbnet_rx_skb (skb);napi_gro_receive (&net->napi, skb);
@@ -917,8 +919,6 @@ static int tbnet_poll(struct napi_struct *napi, int budget) } } - net->stats.rx_packets += rx_packets; -if (cleaned_count)tbnet_alloc_rx_buffers (net, cleaned_count);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1250/1376 forcedeth: stop the tx_timeout register dump past the requested window
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marek Czernohous <[email protected]>
[ Upstream commit cfa9178ce2e5b4f2e2a9e8b577a6cff841665aa0 ]
nv_tx_timeout() dumps the register window in rows of eight dwords:
for (i = 0; i <= np->register_size; i += 32) {
netdev_info(dev, "%3x: %08x ... %08x\n", i,
readl(base + i + 0), ..., readl(base + i + 28));The loop bound only checks the row's starting offset, so the final row reads a full 32 bytes from a position that is below the end of the window but too close to it. base is mapped with exactly that length:
np->base = ioremap(addr, np->register_size);
so the tail of that row is read from beyond the length the driver asked for. Per variant, the last iteration reads past register_size by:
NV_PCI_REGSZ_VER1 (0x270): row 0x260 reads to 0x27f, 16 bytes over NV_PCI_REGSZ_VER2 (0x2d4): row 0x2c0 reads to 0x2df, 12 bytes over NV_PCI_REGSZ_VER3 (0x604): row 0x600 reads to 0x61f, 28 bytes over
This happens on every supported device, not just one of them. Note that it is not a consequence of the sizes being odd: with i <= register_size the offending row is reached whatever the size, and a size that were a multiple of 32 would overrun by a full row rather than by a remainder.
To be precise about the severity: the reads stay inside the BAR. Memory BAR sizes are powers of two, the driver only accepts a region with pci_resource_len() >= register_size (forcedeth.c:5757-5762), and the next power of two at or above each register_size already covers the offending row: 0x400 for 0x270 and 0x2d4, 0x800 for 0x604. ioremap() also rounds the mapped length up to page granularity, so the reads land inside the mapping the CPU has as well. What they leave is the window the driver asked for, not the BAR and not the mapping. That is still a driver reading registers it did not ask for, and it is trivial to avoid, but nobody should expect a fault from it.
Changing <= to < is not enough: register_size is a length and every size above is larger than its last row start, so i still reaches the offending row. Check that the whole row fits instead.
The trade-off is that a partial trailing row is no longer dumped: 16 bytes for VER1, 20 for VER2, 4 for VER3. That seemed preferable to reading outside the requested window, and to open-coding a second, narrower dump for the remainder in what is a debug-only path. Extending the dump to cover the tail can be done on top if anyone misses those registers.
Only reachable with the debug_tx_timeout module parameter, which defaults to false. It has not been observed at runtime: forcing a genuine TX timeout on the reference machine is not something I can do safely, so this rests on the arithmetic above and on a build test, not on a reproduction. UBSAN does not catch it either, since these are MMIO reads rather than an array access. It was found by reading the function while fixing the saved_config_space off-by-one in nv_suspend() and nv_resume().
The dump was introduced with a fixed 0x400 bound while ioremap() mapped only NV_PCI_REGSZ (0x270), so it read about 0x190 bytes too far from the start. Commit 86a0f04387bf ("[PATCH] forcedeth: fix initialization") later replaced 0x400 with np->register_size, which shrank the overrun to the remainder but did not remove it.
--- drivers/net/ethernet/nvidia/forcedeth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/nvidia/forcedeth.c +1 -1
@@ -2754,7 +2754,7 @@ static void nv_tx_timeout(struct net_device *dev, unsigned int txqueue)netdev_info (dev,"Ring at %lx\n" , (unsigned long )np->ring_addr);netdev_info (dev,"Dumping tx registers\n" ); -for (i =0 ; i <= np->register_size; i +=32 ) { +for (i =0 ; i +32 <= np->register_size; i +=32 ) { netdev_info(dev, "%3x: %08x %08x %08x %08x " "%08x %08x %08x %08x\n",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1251/1376 net: ipa: balance runtime PM reference on remove error
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit 6b9eaa61ff2df63c6eb35d5cd025e2cef0861d76 ]
ipa_remove() takes a runtime PM reference before accessing IPA hardware during teardown. If a concurrent modem start or stop keeps ipa_modem_stop() busy across both attempts, the callback intentionally returns without releasing the remaining resources because proceeding with teardown could crash. That return also skips the matching pm_runtime_put_noidle(), leaving the callback's usage-count reference held.
Drop only this runtime PM reference before returning. pm_runtime_put_noidle() does not request an idle transition, so the hardware and resources retained on this exceptional path remain untouched while the usage count stays balanced.
This issue was found by a static analysis checker and confirmed by manual source review.
--- drivers/net/ipa/ipa_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/net/ipa/ipa_main.c +3 -3
@@ -974,12 +974,12 @@ static void ipa_remove(struct platform_device *pdev) }if (ret) {/* -* Not cleaning up here properly might also yield a -* crash later on. As the device is still unregistered -* in this case, this might even yield a crash later on. +* Continuing teardown after failing to stop the modem +* could crash, so leave the remaining resources allocated. */ dev_err (dev,"Failed to stop modem (%pe), leaking resources\n" ,ERR_PTR (ret)); +pm_runtime_put_noidle (dev);return ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1252/1376 net: add missing ref_tracker_dir_exit() to net_passive_dec()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tetsuo Handa <[email protected]>
[ Upstream commit f85dc137aabf357bf3d9fe4c9712121039d83798 ]
I found that trying to read /sys/kernel/debug/ref_tracker/* causes NULL pointer dereference crash when alloc_netdev_mqs() via unshare() returned NULL, for commit 9ba74e6c9e9d ("net: add networking namespace refcount tracker") added ref_tracker_dir_exit(&net->refcnt_tracker) to only __put_net() path whereas commit 65b584f53611 ("ref_tracker: automatically register a file in debugfs for a ref_tracker_dir") added ref_tracker_dir_debugfs() to ref_tracker_dir_init() path.
Since preinit_net() calls ref_tracker_dir_init(&net->refcnt_tracker) and ref_tracker_dir_init(&net->notrefcnt_tracker), we need to make sure that both ref_tracker_dir_exit(&net->refcnt_tracker) and ref_tracker_dir_exit(&net->notrefcnt_tracker) are called before net_passive_dec() schedules for kmem_cache_free() via net_complete_free().
ref_tracker_dir_exit(&net->refcnt_tracker) is called via put_net() when ns_ref_put() returned true. But put_net() is not called when copy_net_ns() fails. Therefore, call ref_tracker_dir_exit() from net_passive_dec() if put_net() is not yet called.
--- net/core/net_namespace.c | 4 ++++ 1 file changed, 4 insertions(+)
net/core/net_namespace.c +4 -0
@@ -469,8 +469,12 @@ void net_passive_dec(struct net *net)if (refcount_dec_and_test (&net->passive)) {kfree (rcu_access_pointer (net->gen)); +#ifdef CONFIG_REF_TRACKER /* There should not be any trackers left there. */ ref_tracker_dir_exit (&net->notrefcnt_tracker); +if (!net->refcnt_tracker.dead) +ref_tracker_dir_exit (&net->refcnt_tracker); +#endif /* Wait for an extra rcu_barrier() before final free. */ llist_add (&net->defer_free_list, &defer_free_list);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1253/1376 net: qlcnic: validate unified ROM sections before loading
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
[ Upstream commit 5e8076e4e4124dae75a3e080ddc20404700d7585 ]
The unified ROM parser reads directory, product, and data-descriptor fields from the firmware file. Existing validation forms table and data ends with unchecked additions and multiplications. Malformed values can wrap before they are compared with the firmware size. The parser also dereferences typed pointers at firmware-controlled offsets.
Valid descriptor extents alone are insufficient for the consumers. The loader reads a fixed-size bootloader regardless of its declared size, the version parser assumes a 17-byte tail, and a partial final firmware word is read as a full u64. A truncated image can therefore make the driver read beyond the firmware allocation during validation or loading.
Replace the pointer-returning parser with bounded range helpers. Validate table entry sizes, descriptor indices, section ranges, the fixed bootloader load length, and the version tail before exposing any section. Read all file fields with unaligned little-endian accessors and assemble a partial final word from only the bytes that remain. Apply the same range checks to the legacy image before reading its fixed fields.
--- .../net/ethernet/qlogic/qlcnic/qlcnic_init.c | 445 ++++++++++-------- 1 file changed, 248 insertions(+), 197 deletions(-)
drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c +248 -197
@@ -6,6 +6,7 @@#include "qlcnic.h" #include "qlcnic_hw.h" +#include <linux/unaligned.h> struct crb_addr_pair {u32 addr;
@@ -740,159 +741,212 @@ qlcnic_has_mn(struct qlcnic_adapter *adapter)return 0 ; } -static -struct uni_table_desc *qlcnic_get_table_desc (const u8 *unirom,int section) -{ -u32 i, entries; -struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0 ]; - entries =le32_to_cpu (directory->num_entries); - -for (i =0 ; i < entries; i++) { +#define FILEHEADER_SIZE (14 * 4) +#define QLCNIC_UNI_DIR_TYPE_OFF (8 * sizeof(__le32)) +#define QLCNIC_UNI_DIR_ENTRY_MIN_SIZE (9 * sizeof(__le32)) +#define QLCNIC_UNI_PRODUCT_ENTRY_MIN_SIZE \ + ((QLCNIC_UNI_FIRMWARE_IDX_OFF + 1) * sizeof(__le32)) +#define QLCNIC_UNI_VERSION_TAIL_SIZE 17 +#define QLCNIC_UNI_BOOTLD_SIZE \ + (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) + +struct qlcnic_uni_data { +u32 offset; +u32 size; +}; -u32 offs =le32_to_cpu (directory->findex) + - i *le32_to_cpu (directory->entry_size); -u32 tab_type =le32_to_cpu (*((__le32 *)&unirom[offs] +8 )); +static bool qlcnic_rom_range_valid (size_t size,size_t offset,size_t len) +{ +return offset <= size && len <= size - offset; +} -if (tab_type == section) -return (struct uni_table_desc *) &unirom[offs]; - } +static bool qlcnic_rom_table_valid (size_t size,u32 offset,u32 entries, +u32 entry_size,u32 min_entry_size) +{ +if (entry_size < min_entry_size || offset > size) +return false; -return NULL ; +return entries <= (size - offset) / entry_size; } -#define FILEHEADER_SIZE (14 * 4) - -static int -qlcnic_validate_header (struct qlcnic_adapter *adapter) +static int qlcnic_get_directory (struct qlcnic_adapter *adapter, +size_t *offset,u32 *entries,u32 *entry_size) { -const u8 *unirom = adapter->fw->data; -struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0 ]; -u32 entries, entry_size, tab_size, fw_file_size; - - fw_file_size = adapter->fw->size; +const struct firmware *fw = adapter->fw; +const u8 *directory = fw->data; -if (fw_file_size <FILEHEADER_SIZE ) +if (fw->size <FILEHEADER_SIZE )return -EINVAL ; - entries =le32_to_cpu (directory->num_entries); - entry_size =le32_to_cpu (directory->entry_size); - tab_size =le32_to_cpu (directory->findex) + (entries * entry_size); + *offset =get_unaligned_le32 (directory + + offsetof(struct uni_table_desc , findex)); + *entries =get_unaligned_le32 (directory + + offsetof(struct uni_table_desc , num_entries)); + *entry_size =get_unaligned_le32 (directory + + offsetof(struct uni_table_desc , entry_size)); -if (fw_file_size < tab_size) +if (!qlcnic_rom_table_valid (fw->size, *offset, *entries, *entry_size, +QLCNIC_UNI_DIR_ENTRY_MIN_SIZE ))return -EINVAL ;return 0 ; } -static int -qlcnic_validate_bootld (struct qlcnic_adapter *adapter) +static int qlcnic_get_table_desc (struct qlcnic_adapter *adapter,int section, +size_t *desc_offset) { -struct uni_table_desc *tab_desc; -struct uni_data_desc *descr; -u32 offs, tab_size, data_size, idx;const u8 *unirom = adapter->fw->data; -__le32 temp; - - temp = *((__le32 *)&unirom[adapter->file_prd_off] + -QLCNIC_UNI_BOOTLD_IDX_OFF ); - idx =le32_to_cpu (temp); - tab_desc =qlcnic_get_table_desc (unirom,QLCNIC_UNI_DIR_SECT_BOOTLD ); - -if (!tab_desc) -return -EINVAL ; - - tab_size =le32_to_cpu (tab_desc->findex) + -le32_to_cpu (tab_desc->entry_size) * (idx +1 ); - -if (adapter->fw->size < tab_size) -return -EINVAL ; +size_t directory_offset; +u32 entries, entry_size; +size_t i; +int ret; - offs =le32_to_cpu (tab_desc->findex) + -le32_to_cpu (tab_desc->entry_size) * idx; - descr = (struct uni_data_desc *)&unirom[offs]; + ret =qlcnic_get_directory (adapter, &directory_offset, &entries, + &entry_size); +if (ret) +return ret; - data_size =le32_to_cpu (descr->findex) +le32_to_cpu (descr->size); +for (i =0 ; i < entries; i++) { +size_t offset = directory_offset + i * entry_size; +u32 table_type; -if (adapter->fw->size < data_size) -return -EINVAL ; + table_type =get_unaligned_le32 (unirom + offset + +QLCNIC_UNI_DIR_TYPE_OFF ); +if (table_type == section) { + *desc_offset = offset; +return 0 ; + } + } -return 0 ; +return -ENOENT ; }static int -qlcnic_validate_fw (struct qlcnic_adapter *adapter) +qlcnic_validate_header (struct qlcnic_adapter *adapter) { -struct uni_table_desc *tab_desc; -struct uni_data_desc *descr; -const u8 *unirom = adapter->fw->data; -u32 offs, tab_size, data_size, idx; -__le32 temp; +u32 entries, entry_size; +size_t offset; + +return qlcnic_get_directory (adapter, &offset, &entries, &entry_size); +} - temp = *((__le32 *)&unirom[adapter->file_prd_off] + -QLCNIC_UNI_FIRMWARE_IDX_OFF ); - idx =le32_to_cpu (temp); - tab_desc =qlcnic_get_table_desc (unirom,QLCNIC_UNI_DIR_SECT_FW ); +static int qlcnic_get_data_desc (struct qlcnic_adapter *adapter,u32 section, +u32 index_offset,struct qlcnic_uni_data *data) +{ +size_t table_desc_offset, table_offset, desc_offset; +const struct firmware *fw = adapter->fw; +const u8 *unirom = fw->data; +size_t product_index_offset; +u32 entries, entry_size, idx; +int ret; -if (!tab_desc) + product_index_offset = adapter->file_prd_off + + (size_t )index_offset *sizeof (__le32); +if (!qlcnic_rom_range_valid (fw->size, product_index_offset, +sizeof (__le32)))return -EINVAL ; - tab_size =le32_to_cpu (tab_desc->findex) + -le32_to_cpu (tab_desc->entry_size) * (idx +1 ); + idx =get_unaligned_le32 (unirom + product_index_offset); + ret =qlcnic_get_table_desc (adapter, section, &table_desc_offset); +if (ret) +return ret; -if (adapter->fw->size < tab_size) + table_offset =get_unaligned_le32 (unirom + table_desc_offset + + offsetof(struct uni_table_desc , findex)); + entries =get_unaligned_le32 (unirom + table_desc_offset + + offsetof(struct uni_table_desc , num_entries)); + entry_size =get_unaligned_le32 (unirom + table_desc_offset + + offsetof(struct uni_table_desc , entry_size)); +if (!qlcnic_rom_table_valid (fw->size, table_offset, entries, + entry_size,sizeof (struct uni_data_desc )) || + idx >= entries)return -EINVAL ; - offs =le32_to_cpu (tab_desc->findex) + -le32_to_cpu (tab_desc->entry_size) * idx; - descr = (struct uni_data_desc *)&unirom[offs]; - data_size =le32_to_cpu (descr->findex) +le32_to_cpu (descr->size); + desc_offset = table_offset + (size_t )idx * entry_size; + data->offset =get_unaligned_le32 (unirom + desc_offset + + offsetof(struct uni_data_desc , findex)); + data->size =get_unaligned_le32 (unirom + desc_offset + + offsetof(struct uni_data_desc , size)); -if (adapter->fw->size < data_size) +if (!qlcnic_rom_range_valid (fw->size, data->offset, data->size))return -EINVAL ;return 0 ; } +static int qlcnic_validate_bootld (struct qlcnic_adapter *adapter) +{ +struct qlcnic_uni_data data; +int ret; + + ret =qlcnic_get_data_desc (adapter,QLCNIC_UNI_DIR_SECT_BOOTLD , +QLCNIC_UNI_BOOTLD_IDX_OFF , &data); +if (ret) +return ret; + +return data.size <QLCNIC_UNI_BOOTLD_SIZE ? -EINVAL :0 ; +} + +static int qlcnic_validate_fw (struct qlcnic_adapter *adapter) +{ +struct qlcnic_uni_data data; +int ret; + + ret =qlcnic_get_data_desc (adapter,QLCNIC_UNI_DIR_SECT_FW , +QLCNIC_UNI_FIRMWARE_IDX_OFF , &data); +if (ret) +return ret; + +return data.size <QLCNIC_UNI_VERSION_TAIL_SIZE ? -EINVAL :0 ; +} +static int qlcnic_validate_product_offs (struct qlcnic_adapter *adapter) { -struct uni_table_desc *ptab_descr; +size_t table_desc_offset, table_offset;const u8 *unirom = adapter->fw->data;int mn_present =qlcnic_has_mn (adapter); -u32 entries, entry_size, tab_size, i; -__le32 temp; - - ptab_descr =qlcnic_get_table_desc (unirom, -QLCNIC_UNI_DIR_SECT_PRODUCT_TBL ); -if (!ptab_descr) -return -EINVAL ; +u32 entries, entry_size; +size_t i; +int ret; - entries =le32_to_cpu (ptab_descr->num_entries); - entry_size =le32_to_cpu (ptab_descr->entry_size); - tab_size =le32_to_cpu (ptab_descr->findex) + (entries * entry_size); + ret =qlcnic_get_table_desc (adapter,QLCNIC_UNI_DIR_SECT_PRODUCT_TBL , + &table_desc_offset); +if (ret) +return ret; -if (adapter->fw->size < tab_size) + table_offset =get_unaligned_le32 (unirom + table_desc_offset + + offsetof(struct uni_table_desc , findex)); + entries =get_unaligned_le32 (unirom + table_desc_offset + + offsetof(struct uni_table_desc , num_entries)); + entry_size =get_unaligned_le32 (unirom + table_desc_offset + + offsetof(struct uni_table_desc , entry_size)); +if (!qlcnic_rom_table_valid (adapter->fw->size, table_offset, entries, + entry_size, +QLCNIC_UNI_PRODUCT_ENTRY_MIN_SIZE ))return -EINVAL ; nomn:for (i =0 ; i < entries; i++) { - -u32 flags, file_chiprev, offs; +size_t offset = table_offset + i * entry_size;u8 chiprev = adapter->ahw->revision_id; +u32 flags, file_chiprev;u32 flagbit; - offs =le32_to_cpu (ptab_descr->findex) + - i *le32_to_cpu (ptab_descr->entry_size); - temp = *((__le32 *)&unirom[offs] +QLCNIC_UNI_FLAGS_OFF ); - flags =le32_to_cpu (temp); - temp = *((__le32 *)&unirom[offs] +QLCNIC_UNI_CHIP_REV_OFF ); - file_chiprev =le32_to_cpu (temp); + flags =get_unaligned_le32 (unirom + offset + +QLCNIC_UNI_FLAGS_OFF *sizeof (__le32)); + file_chiprev =get_unaligned_le32 (unirom + offset + +QLCNIC_UNI_CHIP_REV_OFF * +sizeof (__le32)); flagbit = mn_present ?1 :2 ;if ((chiprev == file_chiprev) && ((1ULL << flagbit) & flags)) { - adapter->file_prd_off = offs; +if (offset >U32_MAX ) +return -EINVAL ; + + adapter->file_prd_off = offset;return 0 ; } }
@@ -933,93 +987,81 @@ qlcnic_validate_unified_romimage(struct qlcnic_adapter *adapter)return 0 ; } -static -struct uni_data_desc *qlcnic_get_data_desc (struct qlcnic_adapter *adapter, -u32 section,u32 idx_offset) -{ -const u8 *unirom = adapter->fw->data; -struct uni_table_desc *tab_desc; -u32 offs, idx; -__le32 temp; - - temp = *((__le32 *)&unirom[adapter->file_prd_off] + idx_offset); - idx =le32_to_cpu (temp); - - tab_desc =qlcnic_get_table_desc (unirom, section); - -if (tab_desc ==NULL ) -return NULL ; - - offs =le32_to_cpu (tab_desc->findex) + -le32_to_cpu (tab_desc->entry_size) * idx; - -return (struct uni_data_desc *)&unirom[offs]; -} - -static u8 * -qlcnic_get_bootld_offs (struct qlcnic_adapter *adapter) +static int qlcnic_get_bootld_data (struct qlcnic_adapter *adapter, +const u8 **bootld) {u32 offs =QLCNIC_BOOTLD_START ; -struct uni_data_desc *data_desc; - - data_desc =qlcnic_get_data_desc (adapter,QLCNIC_UNI_DIR_SECT_BOOTLD , -QLCNIC_UNI_BOOTLD_IDX_OFF ); +struct qlcnic_uni_data data; +int ret; -if (adapter->ahw->fw_type ==QLCNIC_UNIFIED_ROMIMAGE ) - offs =le32_to_cpu (data_desc->findex); +if (adapter->ahw->fw_type ==QLCNIC_UNIFIED_ROMIMAGE ) { + ret =qlcnic_get_data_desc (adapter,QLCNIC_UNI_DIR_SECT_BOOTLD , +QLCNIC_UNI_BOOTLD_IDX_OFF , &data); +if (ret || data.size <QLCNIC_UNI_BOOTLD_SIZE ) +return -EINVAL ; + offs = data.offset; + }else if (!qlcnic_rom_range_valid (adapter->fw->size, offs, +QLCNIC_UNI_BOOTLD_SIZE )) { +return -EINVAL ; + } -return (u8 *)&adapter->fw->data[offs]; + *bootld = adapter->fw->data + offs; +return 0 ; } -static u8 * -qlcnic_get_fw_offs (struct qlcnic_adapter *adapter) +static int qlcnic_get_fw_data (struct qlcnic_adapter *adapter, +const u8 **image,u32 *image_size) {u32 offs =QLCNIC_IMAGE_START ; -struct uni_data_desc *data_desc; - - data_desc =qlcnic_get_data_desc (adapter,QLCNIC_UNI_DIR_SECT_FW , -QLCNIC_UNI_FIRMWARE_IDX_OFF ); -if (adapter->ahw->fw_type ==QLCNIC_UNIFIED_ROMIMAGE ) - offs =le32_to_cpu (data_desc->findex); - -return (u8 *)&adapter->fw->data[offs]; -} +struct qlcnic_uni_data data; +int ret; -static u32 qlcnic_get_fw_size (struct qlcnic_adapter *adapter) -{ -struct uni_data_desc *data_desc; -const u8 *unirom = adapter->fw->data; +if (adapter->ahw->fw_type ==QLCNIC_UNIFIED_ROMIMAGE ) { + ret =qlcnic_get_data_desc (adapter,QLCNIC_UNI_DIR_SECT_FW , +QLCNIC_UNI_FIRMWARE_IDX_OFF , &data); +if (ret) +return ret; + offs = data.offset; + *image_size = data.size; + }else { +if (!qlcnic_rom_range_valid (adapter->fw->size, +QLCNIC_FW_SIZE_OFFSET , +sizeof (__le32))) +return -EINVAL ; + *image_size =get_unaligned_le32 (adapter->fw->data + +QLCNIC_FW_SIZE_OFFSET ); + } - data_desc =qlcnic_get_data_desc (adapter,QLCNIC_UNI_DIR_SECT_FW , -QLCNIC_UNI_FIRMWARE_IDX_OFF ); +if (!qlcnic_rom_range_valid (adapter->fw->size, offs, *image_size)) +return -EINVAL ; -if (adapter->ahw->fw_type ==QLCNIC_UNIFIED_ROMIMAGE ) -return le32_to_cpu (data_desc->size); -else -return le32_to_cpu (*(__le32 *)&unirom[QLCNIC_FW_SIZE_OFFSET ]); + *image = adapter->fw->data + offs; +return 0 ; }static u32 qlcnic_get_fw_version (struct qlcnic_adapter *adapter) { -struct uni_data_desc *fw_data_desc; +char ver_str[QLCNIC_UNI_VERSION_TAIL_SIZE +1 ];const struct firmware *fw = adapter->fw; +struct qlcnic_uni_data data;u32 major, minor, sub; -__le32 version_offset; -const u8 *ver_str;int i, ret; -if (adapter->ahw->fw_type !=QLCNIC_UNIFIED_ROMIMAGE ) { - version_offset = *(__le32 *)&fw->data[QLCNIC_FW_VERSION_OFFSET ]; -return le32_to_cpu (version_offset); - } +if (adapter->ahw->fw_type !=QLCNIC_UNIFIED_ROMIMAGE ) +return get_unaligned_le32 (fw->data +QLCNIC_FW_VERSION_OFFSET ); + + ret =qlcnic_get_data_desc (adapter,QLCNIC_UNI_DIR_SECT_FW , +QLCNIC_UNI_FIRMWARE_IDX_OFF , &data); +if (ret || data.size <QLCNIC_UNI_VERSION_TAIL_SIZE ) +return 0 ; - fw_data_desc =qlcnic_get_data_desc (adapter,QLCNIC_UNI_DIR_SECT_FW , -QLCNIC_UNI_FIRMWARE_IDX_OFF ); - ver_str = fw->data +le32_to_cpu (fw_data_desc->findex) + -le32_to_cpu (fw_data_desc->size) -17 ; +memcpy (ver_str, fw->data + data.offset + data.size - +QLCNIC_UNI_VERSION_TAIL_SIZE , +QLCNIC_UNI_VERSION_TAIL_SIZE ); + ver_str[QLCNIC_UNI_VERSION_TAIL_SIZE ] ='\0' ;for (i =0 ; i <12 ; i++) { -if (!strncmp (&ver_str[i],"REV=" ,4 )) { +if (!strncmp (ver_str + i,"REV=" ,4 )) { ret =sscanf (&ver_str[i+4 ],"%u.%u.%u " , &major, &minor, &sub);if (ret !=3 )
@@ -1034,18 +1076,15 @@ static u32 qlcnic_get_fw_version(struct qlcnic_adapter *adapter)static u32 qlcnic_get_bios_version (struct qlcnic_adapter *adapter) { -const struct firmware *fw = adapter->fw;u32 bios_ver, prd_off = adapter->file_prd_off; -u8 *version_offset; -__le32 temp; +const struct firmware *fw = adapter->fw; -if (adapter->ahw->fw_type !=QLCNIC_UNIFIED_ROMIMAGE ) { - version_offset = (u8 *)&fw->data[QLCNIC_BIOS_VERSION_OFFSET ]; -return le32_to_cpu (*(__le32 *)version_offset); - } +if (adapter->ahw->fw_type !=QLCNIC_UNIFIED_ROMIMAGE ) +return get_unaligned_le32 (fw->data +QLCNIC_BIOS_VERSION_OFFSET ); - temp = *((__le32 *)(&fw->data[prd_off]) +QLCNIC_UNI_BIOS_VERSION_OFF ); - bios_ver =le32_to_cpu (temp); + bios_ver =get_unaligned_le32 (fw->data + prd_off + +QLCNIC_UNI_BIOS_VERSION_OFF * +sizeof (__le32));return (bios_ver <<16 ) + ((bios_ver >>8 ) &0xff00 ) + (bios_ver >>24 ); }
@@ -1106,24 +1145,26 @@ static const char *fw_name[] = {int qlcnic_load_firmware (struct qlcnic_adapter *adapter) { -__le64 *ptr64; -u32 i, flashaddr, size;const struct firmware *fw = adapter->fw;struct pci_dev *pdev = adapter->pdev; +const u8 *bootld, *image; +u32 i, flashaddr, image_size; +int ret;dev_info (&pdev->dev,"loading firmware from %s\n" , fw_name[adapter->ahw->fw_type]);if (fw) { +u32 words, remainder;u64 data; - size = (QLCNIC_IMAGE_START -QLCNIC_BOOTLD_START ) /8 ; - - ptr64 = (__le64 *)qlcnic_get_bootld_offs (adapter); + ret =qlcnic_get_bootld_data (adapter, &bootld); +if (ret) +return ret; flashaddr =QLCNIC_BOOTLD_START ; -for (i =0 ; i < size; i++) { - data =le64_to_cpu (ptr64[i]); +for (i =0 ; i <QLCNIC_UNI_BOOTLD_SIZE /sizeof (u64); i++) { + data =get_unaligned_le64 (bootld + i *sizeof (u64));if (qlcnic_pci_mem_write_2M (adapter, flashaddr, data))return -EIO ;
@@ -1131,13 +1172,15 @@ qlcnic_load_firmware(struct qlcnic_adapter *adapter) flashaddr +=8 ; } - size =qlcnic_get_fw_size (adapter) /8 ; - - ptr64 = (__le64 *)qlcnic_get_fw_offs (adapter); + ret =qlcnic_get_fw_data (adapter, &image, &image_size); +if (ret) +return ret; + words = image_size /sizeof (u64); + remainder = image_size %sizeof (u64); flashaddr =QLCNIC_IMAGE_START ; -for (i =0 ; i < size; i++) { - data =le64_to_cpu (ptr64[i]); +for (i =0 ; i < words; i++) { + data =get_unaligned_le64 (image + i *sizeof (u64));if (qlcnic_pci_mem_write_2M (adapter, flashaddr, data))
@@ -1146,9 +1189,11 @@ qlcnic_load_firmware(struct qlcnic_adapter *adapter) flashaddr +=8 ; } - size =qlcnic_get_fw_size (adapter) %8 ; -if (size) { - data =le64_to_cpu (ptr64[i]); +if (remainder) { +__le64 tail =0 ; + +memcpy (&tail, image + words *sizeof (u64), remainder); + data =le64_to_cpu (tail);if (qlcnic_pci_mem_write_2M (adapter, flashaddr, data))
@@ -1156,10 +1201,9 @@ qlcnic_load_firmware(struct qlcnic_adapter *adapter) } }else { -u64 data; -u32 hi, lo; -int ret;struct qlcnic_flt_entry bootld_entry; +u32 hi, lo, size; +u64 data; ret =qlcnic_get_flt_entry (adapter,QLCNIC_BOOTLD_REGION , &bootld_entry);
@@ -1200,26 +1244,33 @@ qlcnic_load_firmware(struct qlcnic_adapter *adapter)static int qlcnic_validate_firmware (struct qlcnic_adapter *adapter) { -u32 val; -u32 ver, bios, min_size; -struct pci_dev *pdev = adapter->pdev;const struct firmware *fw = adapter->fw; +struct pci_dev *pdev = adapter->pdev;u8 fw_type = adapter->ahw->fw_type; +u32 ver, bios, min_size; +const u8 *data; +u32 data_size; +u32 val; + +if (fw_type ==QLCNIC_UNIFIED_ROMIMAGE ) + min_size =QLCNIC_UNI_FW_MIN_SIZE ; +else + min_size =QLCNIC_FW_MIN_SIZE ; + +if (fw->size < min_size) +return -EINVAL ;if (fw_type ==QLCNIC_UNIFIED_ROMIMAGE ) {if (qlcnic_validate_unified_romimage (adapter))return -EINVAL ; - - min_size =QLCNIC_UNI_FW_MIN_SIZE ; }else { - val =le32_to_cpu (*(__le32 *)&fw->data[QLCNIC_FW_MAGIC_OFFSET ]); + val =get_unaligned_le32 (fw->data +QLCNIC_FW_MAGIC_OFFSET );if (val !=QLCNIC_BDINFO_MAGIC )return -EINVAL ; - - min_size =QLCNIC_FW_MIN_SIZE ; } -if (fw->size < min_size) +if (qlcnic_get_bootld_data (adapter, &data) || +qlcnic_get_fw_data (adapter, &data, &data_size))return -EINVAL ; val =qlcnic_get_fw_version (adapter);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1254/1376 inetpeer: randomize RB-tree node comparison using SipHash
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 2ee66e9487172fcd189bc52a767c30dad7141c09 ]
The inetpeer rate limiting system stores peer entries in a Red-Black tree keyed deterministically on the remote IP address. Because tree lookups walk the RB-tree using standard lexicographical comparisons (inetpeer_addr_cmp), an off-path adversary can predict the exact topology of the tree and the sequence of nodes traversed during lookups (the gc_stack candidate list).
By combining deterministic tree traversal with aggressive garbage collection (triggered when tree size exceeds inet_peer_threshold), an attacker can selectively force the eviction of targeted inet_peer nodes. When an evicted node is subsequently re-created upon receiving a new packet, its rate-limiting token bucket (rate_tokens, rate_last) is reset to full capacity. This creates a side-channel primitive allowing off-path attackers to bypass IP-keyed ICMP rate limits and infer open UDP ports (similar to SAD DNS style attacks).
Mitigate this by randomizing the RB-tree node comparison logic using SipHash with a secret key (inetpeer_hash_key) initialized via net_get_random_once(). Nodes are ordered in the tree by SipHash(addr, key) rather than raw IP addresses. Because the secret key is unknown to external entities, the tree layout and lookup traversal paths are unpredictable to off-path adversaries, breaking the deterministic eviction gadget.
Cache the computed 64-bit SipHash (hash) in struct inet_peer and compute the target hash (dhash) once at the beginning of inet_getpeer() to avoid recomputing SipHash at every step of the RB-tree walk.
--- include/net/inetpeer.h | 4 ++++ net/ipv4/inetpeer.c | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 39 insertions(+), 3 deletions(-)
include/net/inetpeer.h +4 -0
@@ -35,6 +35,7 @@ struct inetpeer_addr {struct inet_peer {struct rb_node rb_node; +u64 hash;struct inetpeer_addr daddr;u32 metrics[RTAX_MAX ];
@@ -125,6 +126,9 @@ static inline int inetpeer_addr_cmp(const struct inetpeer_addr *a, {int i, n; +if (a->family != b->family) +return a->family < b->family ?-1 :1 ; +if (a->family ==AF_INET ) n =sizeof (a->a4) /sizeof (u32);else
net/ipv4/inetpeer.c +35 -3
@@ -22,6 +22,7 @@#include <net/ip.h> #include <net/inetpeer.h> #include <net/secure_seq.h> +#include <linux/siphash.h> /* * Theory of operations.
@@ -53,6 +54,34 @@*/ static struct kmem_cache *peer_cachep__ro_after_init ; +static siphash_aligned_key_t inetpeer_hash_key__read_mostly ; + +static u64 inetpeer_addr_hash (const struct inetpeer_addr *a) +{ +net_get_random_once (&inetpeer_hash_key,sizeof (inetpeer_hash_key)); + +if (a->family ==AF_INET ) +return siphash_2u32 ((__force u32 )a->a4.addr, a->a4.vif, + &inetpeer_hash_key); + +return siphash_4u32 ((__force u32 )a->a6.s6_addr32[0 ], + (__force u32 )a->a6.s6_addr32[1 ], + (__force u32 )a->a6.s6_addr32[2 ], + (__force u32 )a->a6.s6_addr32[3 ], + &inetpeer_hash_key); +} + +static int inetpeer_entry_cmp (u64 dhash, +const struct inetpeer_addr *daddr, +const struct inet_peer *p) +{ +if (dhash < p->hash) +return -1 ; +if (dhash > p->hash) +return 1 ; + +return inetpeer_addr_cmp (daddr, &p->daddr); +}void inet_peer_base_init (struct inet_peer_base *bp) {
@@ -86,6 +115,7 @@ void __init inet_initpeers(void)/* Called with rcu_read_lock() or base->lock held */ static struct inet_peer *lookup(const struct inetpeer_addr *daddr, + u64 dhash, struct inet_peer_base *base, unsigned int seq, struct inet_peer *gc_stack[],
@@ -107,7 +137,7 @@ static struct inet_peer *lookup(const struct inetpeer_addr *daddr,break ; parent = next; p = rb_entry(parent, struct inet_peer, rb_node); - cmp =inetpeer_addr_cmp (daddr, &p->daddr); + cmp =inetpeer_entry_cmp (dhash, daddr, p);if (cmp ==0 ) { now = jiffies;if (READ_ONCE (p->dtime) != now)
@@ -177,6 +207,7 @@ struct inet_peer *inet_getpeer(struct inet_peer_base *base, const struct inetpeer_addr *daddr) {struct inet_peer *p, *gc_stack[PEER_MAX_GC ]; +u64 dhash =inetpeer_addr_hash (daddr);struct rb_node **pp, *parent;unsigned int gc_cnt, seq;
@@ -184,7 +215,7 @@ struct inet_peer *inet_getpeer(struct inet_peer_base *base,* Because of a concurrent writer, we might not find an existing entry. */ seq =read_seqbegin (&base->lock); - p =lookup (daddr, base, seq,NULL , &gc_cnt, &parent, &pp); + p =lookup (daddr, dhash, base, seq,NULL , &gc_cnt, &parent, &pp);if (p)return p;
@@ -196,11 +227,12 @@ struct inet_peer *inet_getpeer(struct inet_peer_base *base,write_seqlock_bh (&base->lock); gc_cnt =0 ; - p =lookup (daddr, base, seq, gc_stack, &gc_cnt, &parent, &pp); + p =lookup (daddr, dhash, base, seq, gc_stack, &gc_cnt, &parent, &pp);if (!p) { p =kmem_cache_alloc (peer_cachep,GFP_ATOMIC );if (p) { p->daddr = *daddr; + p->hash = dhash; p->dtime = (__u32 )jiffies;refcount_set (&p->refcnt,1 );atomic_set (&p->rid,0 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1255/1376 net: sched: fix 32-bit backlog wrap in gred, bfifo and plug enqueue
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit 4c660ee8c809637909f4f7eb1017f7b9401c75c4 ]
gred_enqueue(), bfifo_enqueue() and plug_enqueue() admit a packet when the current backlog plus the packet length fits within the queue limit:
sch->qstats.backlog + qdisc_pkt_len(skb) <= sch->limit (gred default VQ) gred_backlog+qdisc_pkt_len(skb) <= q->limit (gred configured VQ) sch->qstats.backlog + qdisc_pkt_len(skb) <= sch->limit (bfifo)
sch->qstats.backlog + skb->len <= q->limit (plug)
sch->qstats.backlog and q->backlog are u32, and qdisc_pkt_len()/skb->len are unsigned int, so all sums are computed in 32 bits and wrap at 2^32. Once the true backlog exceeds 4 GiB the wrapped sum becomes small and admission keeps succeeding, so the queue grows without bound and the kernel can be driven to OOM.
Promote the sums to u64 so admission stops once the true backlog exceeds the limit. The limit is u32, so the bounded queue stays below 2^32 and the stored u32 backlog never wraps.
The bug can only be reproduced as root (albeit with ridiculous setup):
attach a gred (or bfifo/plug) qdisc with a limit near 4 GiB, leaving the default VQ unconfigured (for gred), and drive >4 GiB of queued traffic (e.g. via a size table / stab to inflate qdisc_pkt_len, or sustained high-rate traffic). The u32 backlog+len sum wraps at 2^32, admission keeps succeeding, and the queue grows unboundedly to OOM.
--- net/sched/sch_fifo.c | 2 +- net/sched/sch_gred.c | 4 ++-- net/sched/sch_plug.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-)
net/sched/sch_fifo.c +1 -1
@@ -19,7 +19,7 @@static int bfifo_enqueue (struct sk_buff *skb,struct Qdisc *sch,struct sk_buff **to_free) { -if (likely (sch->qstats.backlog +qdisc_pkt_len (skb) <= +if (likely ((u64 )sch->qstats.backlog +qdisc_pkt_len (skb) <=READ_ONCE (sch->limit)))return qdisc_enqueue_tail (skb, sch);
net/sched/sch_gred.c +2 -2
@@ -179,7 +179,7 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc *sch,* if no default DP has been configured. This * allows for DP flows to be left untouched. */ -if (likely (sch->qstats.backlog +qdisc_pkt_len (skb) <= +if (likely ((u64 )sch->qstats.backlog +qdisc_pkt_len (skb) <= sch->limit))return qdisc_enqueue_tail (skb, sch);else
@@ -244,7 +244,7 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc *sch,break ; } -if (gred_backlog (t, q, sch) +qdisc_pkt_len (skb) <= q->limit) { +if ((u64 )gred_backlog (t, q, sch) +qdisc_pkt_len (skb) <= q->limit) { q->backlog +=qdisc_pkt_len (skb);return qdisc_enqueue_tail (skb, sch); }
net/sched/sch_plug.c +1 -1
@@ -89,7 +89,7 @@ static int plug_enqueue(struct sk_buff *skb, struct Qdisc *sch, {struct plug_sched_data *q =qdisc_priv (sch); -if (likely (sch->qstats.backlog + skb->len <= q->limit)) { +if (likely ((u64 )sch->qstats.backlog + skb->len <= q->limit)) {if (!q->unplug_indefinite) q->pkts_current_epoch++;return qdisc_enqueue_tail (skb, sch);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1256/1376 net/smc: free stashed qentry before overwrite in REQ_ADD_LINK to ADD_LINK transition
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mahanta Jambigi <[email protected]>
[ Upstream commit 036322025d6e440cb75fc6fecbba9a16b271a2ae ]
When smc_llc_event_handler() transitions the local LLC flow from SMC_LLC_FLOW_REQ_ADD_LINK to SMC_LLC_FLOW_ADD_LINK on arrival of an ADD_LINK request, it calls smc_llc_flow_qentry_set() unconditionally:
if (lgr->llc_flow_lcl.type == SMC_LLC_FLOW_REQ_ADD_LINK) {
lgr->llc_flow_lcl.type = SMC_LLC_FLOW_ADD_LINK;
smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, qentry);
...
}A CONFIRM_LINK or ADD_LINK_CONT arriving while flow->type is SMC_LLC_FLOW_REQ_ADD_LINK is stashed into flow->qentry via the SMC_LLC_CONFIRM_LINK / SMC_LLC_ADD_LINK_CONT handler (which stores into flow->qentry for any non-NONE flow type). When the subsequent ADD_LINK arrives, the REQ_ADD_LINK branch overwrites flow->qentry with the new pointer without first freeing the stashed allocation, leaking one kmalloc object.
The stashed entry has no consumer: smc_llc_wait() is only called from llc_add_link_work, which is not yet scheduled while the flow type remains REQ_ADD_LINK. No waiter is sleeping on llc_msg_waiter at this point. It is safe to unconditionally free any stashed qentry before the overwrite.
Call smc_llc_flow_qentry_del() before smc_llc_flow_qentry_set() in the REQ_ADD_LINK branch. smc_llc_flow_qentry_del() already checks flow->qentry before freeing, so the normal path where no entry is stashed is a no-op.
--- net/smc/smc_llc.c | 2 ++ 1 file changed, 2 insertions(+)
net/smc/smc_llc.c +2 -0
@@ -1902,6 +1902,8 @@ static void smc_llc_event_handler(struct smc_llc_qentry *qentry)if (lgr->llc_flow_lcl.type ==SMC_LLC_FLOW_REQ_ADD_LINK ) {/* server started add_link processing */ +/* free any qentry stashed in REQ_ADD_LINK state */ +smc_llc_flow_qentry_del (&lgr->llc_flow_lcl); lgr->llc_flow_lcl.type =SMC_LLC_FLOW_ADD_LINK ;smc_llc_flow_qentry_set (&lgr->llc_flow_lcl, qentry);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1257/1376 net/smc: free pending qentry in smc_llc_flow_stop() before memset
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mahanta Jambigi <[email protected]>
[ Upstream commit 5ee0ceddc7785c6dcf4a8107fef01f0414a354f4 ]
smc_llc_flow_stop() resets a flow struct with a blind memset:
spin_lock_bh(&lgr->llc_flow_lock); memset(flow, 0, sizeof(*flow)); flow->type = SMC_LLC_FLOW_NONE; spin_unlock_bh(&lgr->llc_flow_lock);
If flow->qentry is non-NULL at this point the pointer is overwritten without the allocation being freed, leaking one kmalloc object.
A late-arriving duplicate CONFIRM_LINK or ADD_LINK_CONT message can set flow->qentry after the legitimate message has been consumed by the waiter via smc_llc_flow_qentry_clr() (which NULLs the pointer but leaves flow->type non-zero) but before the flow completes and smc_llc_flow_stop() runs. In that window the duplicate is stashed into flow->qentry, and then lost when smc_llc_flow_stop() zeros the struct.
Call smc_llc_flow_qentry_del() inside the lock before the memset. smc_llc_flow_qentry_del() already checks flow->qentry before freeing, so the normal case where no entry is pending is a no-op.
--- net/smc/smc_llc.c | 1 + 1 file changed, 1 insertion(+)
net/smc/smc_llc.c +1 -0
@@ -320,6 +320,7 @@ int smc_llc_flow_initiate(struct smc_link_group *lgr,void smc_llc_flow_stop (struct smc_link_group *lgr,struct smc_llc_flow *flow) {spin_lock_bh (&lgr->llc_flow_lock); +smc_llc_flow_qentry_del (flow);memset (flow,0 ,sizeof (*flow)); flow->type =SMC_LLC_FLOW_NONE ;spin_unlock_bh (&lgr->llc_flow_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1258/1376 NFSv4.2: fix LAYOUTSTATS send buffer exhaustion
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junrui Luo <[email protected]>
[ Upstream commit c75ef2137e749f2673f0617cfdaae53b2bb7195a ]
encode_layoutstats_maxsz budgets XDR_QUADLEN(PNFS_LAYOUTSTATS_MAXSIZE), i.e. 256 bytes, for the layoutupdate4 body written by the layout driver. The flexfiles record can exceed that.
ff_layout_encode_ff_layoutupdate() emits, per data server, a netaddr4, an nfs_fh4, two ff_io_latency4, an nfstime4 and a bool. A data server whose filehandle is NFS_MAXFHSIZE bytes long already accounts for 132 of those bytes, and the two ff_io_latency4 at 64 bytes each, the nfstime4 and the bool add a further 144, so the body passes 256 bytes before the netaddr4 is encoded at all. encode_layoutstats() additionally writes the deviceid4 and the layoutupdate4 lou_type word, neither of which the macro accounts for.
The filehandle and the address are both chosen by the server, through LAYOUTGET and GETDEVICEINFO, so it can drive the encoder past the end of the send buffer. xdr_reserve_space() returns NULL once that happens, and the two ff_layout_encode_io_latency() calls run with dss_info->mirror->lock held, so a NULL return there leaves the lock permanently held.
Raise PNFS_LAYOUTSTATS_MAXSIZE to 384 so that the record fits inside the reservation.
--- include/linux/nfs_xdr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/nfs_xdr.h +1 -1
@@ -348,7 +348,7 @@ struct nfs4_layoutreturn {struct nfs4_xdr_opaque_data ld_private; }; -#define PNFS_LAYOUTSTATS_MAXSIZE 256 +#define PNFS_LAYOUTSTATS_MAXSIZE 384struct nfs42_layoutstat_args ;struct nfs42_layoutstat_devinfo ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1259/1376 nfs: move the nfs4_data_server_cache into struct nfs_net
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Layton <[email protected]>
[ Upstream commit d5fb22a7c585b12ec3e6cef150689f7386e8cfd0 ]
Since struct nfs4_pnfs_ds should not be shared between net namespaces, move from a global list of objects to a per-netns list and spinlock.
Stable-dep-of: 13c23c5cb977 ("NFSv4/pnfs: key the data server cache on the NFS version")
--- fs/nfs/client.c | 7 +++++++ fs/nfs/netns.h | 6 +++++- fs/nfs/pnfs_nfs.c | 31 +++++++++++++++++-------------- 3 files changed, 29 insertions(+), 15 deletions(-)
fs/nfs/client.c +7 -0
@@ -1260,6 +1260,10 @@ void nfs_clients_init(struct net *net)INIT_LIST_HEAD (&nn->nfs_volume_list);#if IS_ENABLED (CONFIG_NFS_V4 )idr_init (&nn->cb_ident_idr); +#endif +#if IS_ENABLED (CONFIG_NFS_V4_1 ) +INIT_LIST_HEAD (&nn->nfs4_data_server_cache); +spin_lock_init (&nn->nfs4_data_server_lock);#endif spin_lock_init (&nn->nfs_client_lock); nn->boot_time =ktime_get_real ();
@@ -1277,6 +1281,9 @@ void nfs_clients_exit(struct net *net)nfs_cleanup_cb_ident_idr (net);WARN_ON_ONCE (!list_empty (&nn->nfs_client_list));WARN_ON_ONCE (!list_empty (&nn->nfs_volume_list)); +#if IS_ENABLED (CONFIG_NFS_V4_1 ) +WARN_ON_ONCE (!list_empty (&nn->nfs4_data_server_cache)); +#endif }#ifdef CONFIG_PROC_FS
fs/nfs/netns.h +5 -1
@@ -31,7 +31,11 @@ struct nfs_net {unsigned short nfs_callback_tcpport;unsigned short nfs_callback_tcpport6;int cb_users[NFS4_MAX_MINOR_VERSION +1 ]; -#endif +#endif /* CONFIG_NFS_V4 */ +#if IS_ENABLED (CONFIG_NFS_V4_1 ) +struct list_head nfs4_data_server_cache; +spinlock_t nfs4_data_server_lock; +#endif /* CONFIG_NFS_V4_1 */ struct nfs_netns_client *nfs_client;spinlock_t nfs_client_lock;ktime_t boot_time;
fs/nfs/pnfs_nfs.c +17 -14
@@ -16,6 +16,7 @@#include "nfs4session.h" #include "internal.h" #include "pnfs.h" +#include "netns.h" #define NFSDBG_FACILITY NFSDBG_PNFS
@@ -504,14 +505,14 @@ EXPORT_SYMBOL_GPL(pnfs_generic_commit_pagelist);/* * Data server cache * -* Data servers can be mapped to different device ids. -* nfs4_pnfs_ds reference counting +* Data servers can be mapped to different device ids, but should +* never be shared between net namespaces. +* +* nfs4_pnfs_ds reference counting: * - set to 1 on allocation * - incremented when a device id maps a data server already in the cache. * - decremented when deviceid is removed from the cache. */ -static DEFINE_SPINLOCK (nfs4_ds_cache_lock); -static LIST_HEAD (nfs4_data_server_cache);/* Debug routines */ static void
@@ -604,12 +605,12 @@ _same_data_server_addrs_locked(const struct list_head *dsaddrs1,* Lookup DS by addresses. nfs4_ds_cache_lock is held */ static struct nfs4_pnfs_ds * -_data_server_lookup_locked (const struct net *net,const struct list_head *dsaddrs) +_data_server_lookup_locked (const struct nfs_net *nn,const struct list_head *dsaddrs) {struct nfs4_pnfs_ds *ds; -list_for_each_entry (ds, &nfs4_data_server_cache, ds_node) -if (ds->ds_net == net &&_same_data_server_addrs_locked (&ds->ds_addrs, dsaddrs)) +list_for_each_entry (ds, &nn->nfs4_data_server_cache, ds_node) +if (_same_data_server_addrs_locked (&ds->ds_addrs, dsaddrs))return ds;return NULL ; }
@@ -653,10 +654,11 @@ static void destroy_ds(struct nfs4_pnfs_ds *ds)void nfs4_pnfs_ds_put (struct nfs4_pnfs_ds *ds) { -if (refcount_dec_and_lock (&ds->ds_count, - &nfs4_ds_cache_lock)) { +struct nfs_net *nn =net_generic (ds->ds_net, nfs_net_id); + +if (refcount_dec_and_lock (&ds->ds_count, &nn->nfs4_data_server_lock)) {list_del_init (&ds->ds_node); -spin_unlock (&nfs4_ds_cache_lock); +spin_unlock (&nn->nfs4_data_server_lock);destroy_ds (ds); } }
@@ -718,6 +720,7 @@ nfs4_pnfs_remotestr(struct list_head *dsaddrs, gfp_t gfp_flags)struct nfs4_pnfs_ds *nfs4_pnfs_ds_add (const struct net *net,struct list_head *dsaddrs,gfp_t gfp_flags) { +struct nfs_net *nn =net_generic (net, nfs_net_id);struct nfs4_pnfs_ds *tmp_ds, *ds =NULL ;char *remotestr;
@@ -733,8 +736,8 @@ nfs4_pnfs_ds_add(const struct net *net, struct list_head *dsaddrs, gfp_t gfp_fla/* this is only used for debugging, so it's ok if its NULL */ remotestr =nfs4_pnfs_remotestr (dsaddrs, gfp_flags); -spin_lock (&nfs4_ds_cache_lock); - tmp_ds =_data_server_lookup_locked (net, dsaddrs); +spin_lock (&nn->nfs4_data_server_lock); + tmp_ds =_data_server_lookup_locked (nn, dsaddrs);if (tmp_ds ==NULL ) {INIT_LIST_HEAD (&ds->ds_addrs);list_splice_init (dsaddrs, &ds->ds_addrs);
@@ -743,7 +746,7 @@ nfs4_pnfs_ds_add(const struct net *net, struct list_head *dsaddrs, gfp_t gfp_flaINIT_LIST_HEAD (&ds->ds_node); ds->ds_net = net; ds->ds_clp =NULL ; -list_add (&ds->ds_node, &nfs4_data_server_cache); +list_add (&ds->ds_node, &nn->nfs4_data_server_cache);dprintk ("%s add new data server %s\n" , __func__, ds->ds_remotestr); }else {
@@ -755,7 +758,7 @@ nfs4_pnfs_ds_add(const struct net *net, struct list_head *dsaddrs, gfp_t gfp_fla refcount_read(&tmp_ds->ds_count)); ds = tmp_ds; } -spin_unlock (&nfs4_ds_cache_lock); +spin_unlock (&nn->nfs4_data_server_lock); out:return ds; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1260/1376 NFSv4/pnfs: key the data server cache on the NFS version
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junrui Luo <[email protected]>
[ Upstream commit 13c23c5cb977f66390795437fd3837887ce1fd75 ]
nfs4_pnfs_ds_add() keys the per-net data server cache on the multipath address set alone, and struct nfs4_pnfs_ds records no version. That suffices for the files layout driver, which always connects with version 4, but flexfiles takes its version tuple from GETDEVICEINFO per device, and one address can legitimately serve both NFSv3 and NFSv4.
Two deviceids on one address with different ds_versions[0].version therefore share a single nfs4_pnfs_ds, and whichever mirror connects first pins ds_clp to its own version. The other one is handed that client anyway, so it selects rpc_call_ops for a version the connection does not speak, and the mismatched sequence-slot handling dereferences NULL.
Add the version to the cache key so the two cannot alias, giving each version its own nfs4_pnfs_ds and connection while both mirrors stay usable. Only the major version is compared, since that is what selects rpc_call_ops and rpc_ops; v4.0 and v4.1 keep sharing a client. The files layout driver passes the 4 it already hardcodes at connect time.
--- fs/nfs/filelayout/filelayoutdev.c | 3 ++- fs/nfs/flexfilelayout/flexfilelayoutdev.c | 3 ++- fs/nfs/pnfs.h | 3 ++- fs/nfs/pnfs_nfs.c | 14 +++++++++----- 4 files changed, 15 insertions(+), 8 deletions(-)
fs/nfs/filelayout/filelayoutdev.c +2 -1
@@ -170,7 +170,8 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, goto out_err_free_deviceid; } - dsaddr->ds_list[i] =nfs4_pnfs_ds_add (net, &dsaddrs, gfp_flags); + dsaddr->ds_list[i] =nfs4_pnfs_ds_add (net, &dsaddrs,4 , + gfp_flags);if (!dsaddr->ds_list[i]) goto out_err_drain_dsaddrs;trace_fl_getdevinfo (server, &pdev->dev_id, dsaddr->ds_list[i]->ds_remotestr);
fs/nfs/flexfilelayout/flexfilelayoutdev.c +2 -1
@@ -149,7 +149,8 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, new_ds->ds_versions = ds_versions; new_ds->ds_versions_cnt = version_count; - new_ds->ds =nfs4_pnfs_ds_add (net, &dsaddrs, gfp_flags); + new_ds->ds =nfs4_pnfs_ds_add (net, &dsaddrs, ds_versions[0 ].version, + gfp_flags);if (!new_ds->ds) goto out_err_drain_dsaddrs;
fs/nfs/pnfs.h +2 -1
@@ -63,6 +63,7 @@ struct nfs4_pnfs_ds {const struct net *ds_net;struct nfs_client *ds_clp;refcount_t ds_count; +u32 ds_version;/* cache key, with ds_addrs */ unsigned long ds_state;#define NFS4DS_CONNECTING 0/* ds is establishing connection */ };
@@ -417,7 +418,7 @@ void pnfs_generic_write_commit_done(struct rpc_task *task, void *data);void nfs4_pnfs_ds_put (struct nfs4_pnfs_ds *ds);struct nfs4_pnfs_ds *nfs4_pnfs_ds_add (const struct net *net,struct list_head *dsaddrs, -gfp_t gfp_flags); +u32 version,gfp_t gfp_flags);void nfs4_pnfs_v3_ds_connect_unload (void ); int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds, struct nfs4_deviceid_node *devid, unsigned int timeo,
fs/nfs/pnfs_nfs.c +9 -5
@@ -602,15 +602,17 @@ _same_data_server_addrs_locked(const struct list_head *dsaddrs1, }/* -* Lookup DS by addresses. nfs4_ds_cache_lock is held +* Lookup DS by addresses and NFS version. nfs4_ds_cache_lock is held */ static struct nfs4_pnfs_ds * -_data_server_lookup_locked (const struct nfs_net *nn,const struct list_head *dsaddrs) +_data_server_lookup_locked (const struct nfs_net *nn, +const struct list_head *dsaddrs,u32 version) {struct nfs4_pnfs_ds *ds;list_for_each_entry (ds, &nn->nfs4_data_server_cache, ds_node) -if (_same_data_server_addrs_locked (&ds->ds_addrs, dsaddrs)) +if (ds->ds_version == version && +_same_data_server_addrs_locked (&ds->ds_addrs, dsaddrs))return ds;return NULL ; }
@@ -718,7 +720,8 @@ nfs4_pnfs_remotestr(struct list_head *dsaddrs, gfp_t gfp_flags)* uncached and return cached struct nfs4_pnfs_ds. */ struct nfs4_pnfs_ds * -nfs4_pnfs_ds_add (const struct net *net,struct list_head *dsaddrs,gfp_t gfp_flags) +nfs4_pnfs_ds_add (const struct net *net,struct list_head *dsaddrs,u32 version, +gfp_t gfp_flags) {struct nfs_net *nn =net_generic (net, nfs_net_id);struct nfs4_pnfs_ds *tmp_ds, *ds =NULL ;
@@ -737,7 +740,7 @@ nfs4_pnfs_ds_add(const struct net *net, struct list_head *dsaddrs, gfp_t gfp_fla remotestr =nfs4_pnfs_remotestr (dsaddrs, gfp_flags);spin_lock (&nn->nfs4_data_server_lock); - tmp_ds =_data_server_lookup_locked (nn, dsaddrs); + tmp_ds =_data_server_lookup_locked (nn, dsaddrs, version);if (tmp_ds ==NULL ) {INIT_LIST_HEAD (&ds->ds_addrs);list_splice_init (dsaddrs, &ds->ds_addrs);
@@ -746,6 +749,7 @@ nfs4_pnfs_ds_add(const struct net *net, struct list_head *dsaddrs, gfp_t gfp_flaINIT_LIST_HEAD (&ds->ds_node); ds->ds_net = net; ds->ds_clp =NULL ; + ds->ds_version = version;list_add (&ds->ds_node, &nn->nfs4_data_server_cache);dprintk ("%s add new data server %s\n" , __func__, ds->ds_remotestr);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1261/1376 rtc: pcf85363: Add error checking to regmap calls in probe()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cosmo Chou <[email protected]>
[ Upstream commit 78acddfde75177a27000f076e3e828743e38877e ]
The probe() function ignores errors returned by regmap operations. If an I2C transport error occurs (e.g., -ENXIO), the driver continues probing and may register a non-functional RTC device.
Propagate errors from all unchecked regmap calls in probe() using dev_err_probe().
--- drivers/rtc/rtc-pcf85363.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
drivers/rtc/rtc-pcf85363.c +12 -5
@@ -426,8 +426,8 @@ static int pcf85363_probe(struct i2c_client *client) err =pcf85363_load_capacitance (pcf85363, client->dev.of_node);if (err <0 ) -dev_warn (&client->dev,"failed to set xtal load capacitance: %d" , - err); +return dev_err_probe (&client->dev, err, +"failed to set xtal load capacitance\n" ); pcf85363->rtc->ops = &rtc_ops; pcf85363->rtc->range_min =RTC_TIMESTAMP_BEGIN_2000 ;
@@ -436,9 +436,16 @@ static int pcf85363_probe(struct i2c_client *client) wakeup_source =device_property_read_bool (&client->dev,"wakeup-source" );if (client->irq >0 || wakeup_source) { -regmap_write (pcf85363->regmap,CTRL_FLAGS ,0 ); -regmap_update_bits (pcf85363->regmap,CTRL_PIN_IO , -PIN_IO_INTAPM ,PIN_IO_INTA_OUT ); + err =regmap_write (pcf85363->regmap,CTRL_FLAGS ,0 ); +if (err) +return dev_err_probe (&client->dev, err, +"failed to clear flags\n" ); + + err =regmap_update_bits (pcf85363->regmap,CTRL_PIN_IO , +PIN_IO_INTAPM ,PIN_IO_INTA_OUT ); +if (err) +return dev_err_probe (&client->dev, err, +"failed to set interrupt pin mode\n" ); }if (client->irq >0 ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1262/1376 bnxt_en: Fix call to hardware monitoring event handler
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit 622d698df4239fef3e0eb51fe59f4198f957f28a ]
The first parameter of hwmon_notify_event() is supposed to be the hardware monitoring device. The bnxt driver calls it with the platform device as first parameter instead. This API break results in undefined behavior and may result in a crash.
Pass the hardware monitoring device as parameter instead to fix the problem.
--- drivers/net/ethernet/broadcom/bnxt/bnxt_hwmon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/broadcom/bnxt/bnxt_hwmon.c +1 -1
@@ -40,7 +40,7 @@ void bnxt_hwmon_notify_event(struct bnxt *bp)return ; } -hwmon_notify_event (&bp->pdev->dev, hwmon_temp, attr,0 ); +hwmon_notify_event (bp->hwmon_dev, hwmon_temp, attr,0 ); }static int bnxt_hwrm_temp_query (struct bnxt *bp,u8 *temp)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1263/1376 net: page_pool: Remove zone/policy GFP flags when allocating XArray entries
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rong Zhang <[email protected]>
[ Upstream commit 039f248a6cc1f4dec895c001de2c600842022e58 ]
Net drivers request GFP flags according to both the current context and the device constraints, but the XArray entry itself is by no mean used by the device. Passing though device constraints to XArray allocation is a bug and will be warned and fixed up by slab, e.g.:
Unexpected gfp: 0x4 (GFP_DMA32). Fixing up to gfp: 0x82820 (GFP_ATOMIC|__GFP_NOWARN|__GFP_NOMEMALLOC). Fix your code!
CPU: 2 UID: 0 PID: 1071629 Comm: kworker/u80:1 Not tainted 7.2.0-rc7+ #1 PREEMPT(lazy)
Hardware name: LENOVO 21Q4/LNVNB161216, BIOS PXCN27WW 10/20/2025
Workqueue: mt76 mt792x_pm_wake_work [mt792x_lib]
Call Trace:
<TASK>
dump_stack_lvl+0x6e/0x90
kmalloc_fix_flags+0x4d/0x6a
refill_objects+0x10a/0x330
__pcs_replace_empty_main+0x292/0x5c0
kmem_cache_alloc_lru_noprof+0x4c2/0x680
? __xas_nomem+0x3a/0x120
__xas_nomem+0x3a/0x120
__xa_alloc+0xd4/0x190
page_pool_dma_map+0xef/0x400
__page_pool_alloc_netmems_slow+0xed/0x480
? lock_release+0x280/0x490
page_pool_alloc_frag_netmem+0xe0/0x3a0
page_pool_alloc_frag+0xe/0x20
mt76_dma_rx_fill_buf+0x1f6/0x580 [mt76]
mt76_dma_rx_reset+0x1cf/0x230 [mt76]
mt792x_wpdma_reset+0x183/0x1b0 [mt792x_lib]
mt792x_wpdma_reinit_cond+0x5e/0xa0 [mt792x_lib]
mt792xe_mcu_drv_pmctrl+0x28/0x60 [mt792x_lib]
mt792x_mcu_drv_pmctrl+0x3e/0x90 [mt792x_lib]
mt792x_pm_wake_work+0x2d/0x1d0 [mt792x_lib]
? process_one_work+0x20e/0x600
process_one_work+0x230/0x600
? process_one_work+0x256/0x600
worker_thread+0x1ec/0x3c0
? rescuer_thread+0x610/0x610
kthread+0xf2/0x130
? kthread_affine_node+0x140/0x140
ret_from_fork+0x2a5/0x380
? kthread_affine_node+0x140/0x140
ret_from_fork_asm+0x11/0x20
</TASK>Currently mt76 and stmmac may allocate page pool pages with GFP_DMA32.
Fix it by removing zone/policy GFP flags when allocating XArray entries. This is inspired by commit 96d578088085 ("iommu/dma: Use the gfp parameter in __iommu_dma_alloc_noncontiguous()").
--- net/core/page_pool.c | 7 +++++++ 1 file changed, 7 insertions(+)
net/core/page_pool.c +7 -0
@@ -484,6 +484,13 @@ static int page_pool_register_dma_index(struct page_pool *pool,if (unlikely (!PP_DMA_INDEX_BITS )) goto out; +/* +* Drivers request GFP flags according to both the current context and +* the device constraints, but the XArray entry itself is by no mean +* used by the device, so remove zone/policy flags. +*/ + gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM | __GFP_COMP); +if (in_softirq ()) err =xa_alloc (&pool->dma_mapped, &id,netmem_to_page (netmem),PP_DMA_INDEX_LIMIT , gfp);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1264/1376 scsi: qla2xxx: Fix an loop timeout test
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
[ Upstream commit 11e48f5201fd86ffa038809dd9c41144d43ee2e4 ]
This loop timeout with "retries" set to -1, not 0. Fix the test for failure.
--- drivers/scsi/qla2xxx/qla_nx2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/scsi/qla2xxx/qla_nx2.c +1 -1
@@ -3507,7 +3507,7 @@ qla8044_poll_flash_status_reg(struct scsi_qla_host *vha)msleep (QLA8044_FLASH_STATUS_REG_POLL_DELAY ); } -if (!retries) +if (retries ==-1 ) ret_val =QLA_FUNCTION_FAILED ;return ret_val;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1265/1376 erofs: Fix EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS default logic
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geert Uytterhoeven <[email protected]>
[ Upstream commit ab74edaeb1ae7c7194e79007e6afdfe788111a3f ]
When NR_CPUS is less than 16, or when SMP is disabled, the default value of 16 is invalid.
While actual configuration picks up a sensible and valid default (NR_CPUS or 1), "make savedefconfig" will still write a line like
CONFIG_EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS=1
to the defconfig file, even if that matches the sensible default.
Avoid needlessly enlarging the defconfig files, and reduce churn for updating them, by specifying valid defaults depending on SMP and NR_CPUS.
While at it, make the prompt depend on SMP, as there is no point in asking the user about the maximum number of decompression streams if there is only one valid answer.
--- fs/erofs/Kconfig | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
fs/erofs/Kconfig +5 -3
@@ -115,11 +115,13 @@ config EROFS_FS_ZIP_LZMA If unsure, say N. config EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS - int "EROFS LZMA default maximum decompression streams" + int "EROFS LZMA default maximum decompression streams" if SMP depends on EROFS_FS_ZIP_LZMA range 1 NR_CPUS if SMP range 1 1 if !SMP - default 16 + default 16 if SMP && NR_CPUS >= 16 + default NR_CPUS if SMP + default 1 help By default EROFS allocates one LZMA decompression stream per CPU. Each stream can hold a dictionary of up to 8 MiB taken from the
@@ -127,7 +129,7 @@ config EROFS_FS_ZIP_LZMA_DEFAULT_MAX_STREAMS of memory. This caps the default; the lzma_streams module parameter still overrides it. - If unsure, keep the default of 16. + If unsure, keep the suggested default (16 or lower). config EROFS_FS_ZIP_DEFLATE bool "EROFS DEFLATE compressed data support"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1266/1376 arm64: Enable ARCH_HAS_NONLEAF_PMD_YOUNG
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yicong Yang <[email protected]>
[ Upstream commit 62df5870ebf7cec96a51c9b9008daf167e22db14 ]
With the support of FEAT_HAFT, the NONLEAF_PMD_YOUNG can be enabled on arm64 since the hardware is capable of updating the AF flag for PMD table descriptor. Since the AF bit of the table descriptor shares the same bit position in block descriptors, we only need to implement arch_has_hw_nonleaf_pmd_young() and select related configs. The related pmd_young test/update operations keeps the same with and already implemented for transparent page support.
Currently ARCH_HAS_NONLEAF_PMD_YOUNG is used to improve the efficiency of lru-gen aging.
Stable-dep-of: 902caade3cfd ("arm64: ptdump: Make note_page_flush() range aware")
--- arch/arm64/Kconfig | 1 + arch/arm64/include/asm/pgtable.h | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-)
arch/arm64/Kconfig +1 -0
@@ -38,6 +38,7 @@ config ARM64 select ARCH_HAS_MEM_ENCRYPT select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE + select ARCH_HAS_NONLEAF_PMD_YOUNG if ARM64_HAFT select ARCH_HAS_PTE_DEVMAP select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_HW_PTE_YOUNG
arch/arm64/include/asm/pgtable.h +6 -2
@@ -1266,7 +1266,7 @@ static inline int __ptep_clear_flush_young(struct vm_area_struct *vma,return young; } -#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#if defined(CONFIG_TRANSPARENT_HUGEPAGE ) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG )#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, unsigned long address,
@@ -1274,7 +1274,7 @@ static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, {return __ptep_test_and_clear_young (vma, address, (pte_t *)pmdp); } -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +#endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG */ static inline pte_t __ptep_get_and_clear (struct mm_struct *mm,unsigned long address,pte_t *ptep)
@@ -1509,6 +1509,10 @@ static inline void update_mmu_cache_range(struct vm_fault *vmf,*/ #define arch_has_hw_pte_young cpu_has_hw_af +#ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG +#define arch_has_hw_nonleaf_pmd_young system_supports_haft +#endif +/* * Experimentally, it's cheap to set the access flag in hardware and we * benefit from prefaulting mappings as 'old' to start with.
Signature · 1 line
2.53.0
Re: [PATCH 6.12 1266/1376] arm64: Enable ARCH_HAS_NONLEAF_PMD_YOUNG
Quoted 35 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yicong Yang <[email protected]>
[ Upstream commit
62df5870ebf7cec96a51c9b9008daf167e22db14]With the support of
FEAT_HAFT, theNONLEAF_PMD_YOUNGcan be enabled on arm64 since the hardware is capable of updating the AF flag for PMD table descriptor. Since the AF bit of the table descriptor shares the same bit position in block descriptors, we only need to implementarch_has_hw_nonleaf_pmd_young()and select related configs. The relatedpmd_youngtest/update operations keeps the same with and already implemented for transparent page support.Currently
ARCH_HAS_NONLEAF_PMD_YOUNGis used to improve the efficiency of lru-gen aging.Signed-off-by Yicong Yang <[email protected]>Reviewed-by Catalin Marinas <[email protected]>Signed-off-by Catalin Marinas <[email protected]>Stable-dep-of:
902caade3cfd("arm64: ptdump: Makenote_page_flush()range aware")Signed-off-by Sasha Levin <[email protected]>--- arch/arm64/Kconfig | 1 + arch/arm64/include/asm/pgtable.h | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-)arch/arm64/Kconfig +0
-0
arch/arm64/Kconfig config ARM64 · line 41
Quoted 4 lines
arch/arm64/Kconfig +1
-0@@ -38,6 +38,7 @@ config ARM64 select ARCH_HAS_MEM_ENCRYPT select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE + select ARCH_HAS_NONLEAF_PMD_YOUNG if ARM64_HAFT
Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
Upstream prerequisite code:
config ARM64_HAFT
depends on ARM64_HW_AFDBM
static inline bool system_supports_haft(void)
Downstream 6.12.y code:
select ARCH_HAS_NONLEAF_PMD_YOUNG if ARM64_HAFT
Downstream refers to ARM64_HAFT but supplies no definition for it.
The patch selects ARCH_HAS_NONLEAF_PMD_YOUNG only under ARM64_HAFT and maps the hardware predicate to system_supports_haft(), but neither symbol is defined on this branch. The capability is therefore permanently disabled. Upstream obtains all FEAT_HAFT detection and MMU setup from the nine-file prerequisite efe72541355d.
That is a broader hardware feature, not an incidental stable dependency.
Maybe we should revert this, thoughts ?
thanks,
Harshit
Quoted 36 lines
arch/arm64/Kconfig +0
-0select ARCH_HAS_PTE_DEVMAP select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_HW_PTE_YOUNGarch/arm64/include/asm/pgtable.h +6
-2@@ -1266,7 +1266,7 @@ static inline int __ptep_clear_flush_young(struct vm_area_struct *vma,return young; } -#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#if defined(CONFIG_TRANSPARENT_HUGEPAGE ) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG )#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, unsigned long address,@@ -1274,7 +1274,7 @@ static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, {return __ptep_test_and_clear_young (vma, address, (pte_t *)pmdp); } -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +#endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG */ static inline pte_t __ptep_get_and_clear (struct mm_struct *mm,unsigned long address,pte_t *ptep)@@ -1509,6 +1509,10 @@ static inline void update_mmu_cache_range(struct vm_fault *vmf,*/ #define arch_has_hw_pte_young cpu_has_hw_af +#ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG +#define arch_has_hw_nonleaf_pmd_young system_supports_haft +#endif +/* * Experimentally, it's cheap to set the access flag in hardware and we * benefit from prefaulting mappings as 'old' to start with.
Sasha Levin
maintainerRe: [PATCH 6.12 1266/1376] arm64: Enable ARCH_HAS_NONLEAF_PMD_YOUNG
Quoted 4 lines
The patch selects
ARCH_HAS_NONLEAF_PMD_YOUNGonly underARM64_HAFTand maps the hardware predicate tosystem_supports_haft(), but neither symbol is defined on this branch. The capability is therefore permanently disabled.
That is right, and it is why the commit is inert on 6.12. With ARM64_HAFT undefined the select never fires, and the detection and MMU setup from efe72541355d ("arm64: Add support for FEAT_HAFT") is absent, so the guarded code never compiles.
It came in as a dependency walker false positive off a Kconfig context line next to "select ARCH_HAS_PTDUMP" in the hunk taken for 902caade3cfd ("arm64:
ptdump: Make note_page_flush() range aware"), not as a real prerequisite.
It is already released and has no observable effect, so I am keeping it rather than adding a revert.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 1267/1376 s390: Add missing _TIF defines
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Carstens <[email protected]>
[ Upstream commit 546d7bd47973790073b824d69ee59440337b407b ]
Add missing _TIF defines so that for every TIF bit its corresponding _TIF mask exists. Sort the _TIF list to match the TIF order.
Also remove two leftover comments from the pre generic entry time.
Stable-dep-of: 902caade3cfd ("arm64: ptdump: Make note_page_flush() range aware")
--- arch/s390/include/asm/thread_info.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
arch/s390/include/asm/thread_info.h +6 -7
@@ -61,7 +61,6 @@ void arch_setup_new_exec(void);/* * thread information flags bit numbers */ -/* _TIF_WORK bits */ #define TIF_NOTIFY_RESUME 0/* callback before returning to user */ #define TIF_SIGPENDING 1/* signal pending */ #define TIF_NEED_RESCHED 2/* rescheduling necessary */
@@ -72,33 +71,33 @@ void arch_setup_new_exec(void);#define TIF_NOTIFY_SIGNAL 7/* signal notifications exist */ #define TIF_ISOLATE_BP_GUEST 9/* Run KVM guests with isolated BP */ #define TIF_PER_TRAP 10/* Need to handle PER trap on exit to usermode */ -#define TIF_31BIT 16/* 32bit process */ #define TIF_MEMDIE 17/* is terminating due to OOM killer */ #define TIF_RESTORE_SIGMASK 18/* restore signal mask in do_signal() */ #define TIF_SINGLE_STEP 19/* This task is single stepped */ #define TIF_BLOCK_STEP 20/* This task is block stepped */ #define TIF_UPROBE_SINGLESTEP 21/* This task is uprobe single stepped */ - -/* _TIF_TRACE bits */ #define TIF_SYSCALL_TRACE 24/* syscall trace active */ #define TIF_SYSCALL_AUDIT 25/* syscall auditing active */ #define TIF_SECCOMP 26/* secure computing */ #define TIF_SYSCALL_TRACEPOINT 27/* syscall tracepoint instrumentation */ #define _TIF_NOTIFY_RESUME BIT(TIF_NOTIFY_RESUME) -#define _TIF_NOTIFY_SIGNAL BIT(TIF_NOTIFY_SIGNAL)#define _TIF_SIGPENDING BIT(TIF_SIGPENDING)#define _TIF_NEED_RESCHED BIT(TIF_NEED_RESCHED)#define _TIF_UPROBE BIT(TIF_UPROBE)#define _TIF_GUARDED_STORAGE BIT(TIF_GUARDED_STORAGE)#define _TIF_PATCH_PENDING BIT(TIF_PATCH_PENDING) +#define _TIF_PGSTE BIT(TIF_PGSTE) +#define _TIF_NOTIFY_SIGNAL BIT(TIF_NOTIFY_SIGNAL)#define _TIF_ISOLATE_BP_GUEST BIT(TIF_ISOLATE_BP_GUEST)#define _TIF_PER_TRAP BIT(TIF_PER_TRAP) -#define _TIF_31BIT BIT(TIF_31BIT) +#define _TIF_MEMDIE BIT(TIF_MEMDIE) +#define _TIF_RESTORE_SIGMASK BIT(TIF_RESTORE_SIGMASK)#define _TIF_SINGLE_STEP BIT(TIF_SINGLE_STEP) - +#define _TIF_BLOCK_STEP BIT(TIF_BLOCK_STEP) +#define _TIF_UPROBE_SINGLESTEP BIT(TIF_UPROBE_SINGLESTEP)#define _TIF_SYSCALL_TRACE BIT(TIF_SYSCALL_TRACE)#define _TIF_SYSCALL_AUDIT BIT(TIF_SYSCALL_AUDIT)#define _TIF_SECCOMP BIT(TIF_SECCOMP)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1268/1376 s390: Add ARCH_HAS_PREEMPT_LAZY support
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Carstens <[email protected]>
[ Upstream commit 9de3e4bf6cfbcb62e9ec658e3b291cd479018b43 ]
Just add the required TIF bit for ARCH_HAS_PREEMPT_LAZY support.
Shuffle TIF bits to get TIF_NEED_RESCHED_LAZY next to TIF_NEED_RESCHED.
Stable-dep-of: 902caade3cfd ("arm64: ptdump: Make note_page_flush() range aware")
--- arch/s390/Kconfig | 1 + arch/s390/include/asm/thread_info.h | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-)
arch/s390/Kconfig +1 -0
@@ -80,6 +80,7 @@ config S390 select ARCH_HAS_MEMBARRIER_SYNC_CORE select ARCH_HAS_MEM_ENCRYPT select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS + select ARCH_HAS_PREEMPT_LAZY select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_SCALED_CPUTIME select ARCH_HAS_SET_DIRECT_MAP
arch/s390/include/asm/thread_info.h +5 -3
@@ -64,11 +64,12 @@ void arch_setup_new_exec(void);#define TIF_NOTIFY_RESUME 0/* callback before returning to user */ #define TIF_SIGPENDING 1/* signal pending */ #define TIF_NEED_RESCHED 2/* rescheduling necessary */ -#define TIF_UPROBE 3/* breakpointed or single-stepping */ -#define TIF_GUARDED_STORAGE 4/* load guarded storage control block */ +#define TIF_NEED_RESCHED_LAZY 3/* lazy rescheduling needed */ +#define TIF_UPROBE 4/* breakpointed or single-stepping */ #define TIF_PATCH_PENDING 5/* pending live patching update */ #define TIF_PGSTE 6/* New mm's will use 4K page tables */ #define TIF_NOTIFY_SIGNAL 7/* signal notifications exist */ +#define TIF_GUARDED_STORAGE 8/* load guarded storage control block */ #define TIF_ISOLATE_BP_GUEST 9/* Run KVM guests with isolated BP */ #define TIF_PER_TRAP 10/* Need to handle PER trap on exit to usermode */ #define TIF_31BIT 16/* 32bit process */
@@ -85,11 +86,12 @@ void arch_setup_new_exec(void);#define _TIF_NOTIFY_RESUME BIT(TIF_NOTIFY_RESUME)#define _TIF_SIGPENDING BIT(TIF_SIGPENDING)#define _TIF_NEED_RESCHED BIT(TIF_NEED_RESCHED) +#define _TIF_NEED_RESCHED_LAZY BIT(TIF_NEED_RESCHED_LAZY)#define _TIF_UPROBE BIT(TIF_UPROBE) -#define _TIF_GUARDED_STORAGE BIT(TIF_GUARDED_STORAGE)#define _TIF_PATCH_PENDING BIT(TIF_PATCH_PENDING)#define _TIF_PGSTE BIT(TIF_PGSTE)#define _TIF_NOTIFY_SIGNAL BIT(TIF_NOTIFY_SIGNAL) +#define _TIF_GUARDED_STORAGE BIT(TIF_GUARDED_STORAGE)#define _TIF_ISOLATE_BP_GUEST BIT(TIF_ISOLATE_BP_GUEST)#define _TIF_PER_TRAP BIT(TIF_PER_TRAP)#define _TIF_31BIT BIT(TIF_31BIT)
Signature · 1 line
2.53.0
Re: [PATCH 6.12 1268/1376] s390: Add ARCH_HAS_PREEMPT_LAZY support
Quoted 25 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Carstens <[email protected]>
[ Upstream commit
9de3e4bf6cfbcb62e9ec658e3b291cd479018b43]Just add the required TIF bit for
ARCH_HAS_PREEMPT_LAZYsupport.Shuffle TIF bits to get
TIF_NEED_RESCHED_LAZYnext toTIF_NEED_RESCHED.Signed-off-by Heiko Carstens <[email protected]>Stable-dep-of:
902caade3cfd("arm64: ptdump: Makenote_page_flush()range aware")Signed-off-by Sasha Levin <[email protected]>--- arch/s390/Kconfig | 1 + arch/s390/include/asm/thread_info.h | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-)arch/s390/Kconfig +0
-0
arch/s390/Kconfig config S390 · line 83
Quoted 4 lines
arch/s390/Kconfig +1
-0@@ -80,6 +80,7 @@ config S390 select ARCH_HAS_MEMBARRIER_SYNC_CORE select ARCH_HAS_MEM_ENCRYPT select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS + select ARCH_HAS_PREEMPT_LAZY
Hi Greg/Sasha,
I don't see this defined in 6.12.y.
thanks,
Harshit> select ARCH_HAS_PTE_SPECIAL
Quoted 35 lines
arch/s390/Kconfig +0
-0select ARCH_HAS_SCALED_CPUTIME select ARCH_HAS_SET_DIRECT_MAParch/s390/include/asm/thread_info.h +5
-3@@ -64,11 +64,12 @@ void arch_setup_new_exec(void);#define TIF_NOTIFY_RESUME 0/* callback before returning to user */ #define TIF_SIGPENDING 1/* signal pending */ #define TIF_NEED_RESCHED 2/* rescheduling necessary */ -#define TIF_UPROBE 3/* breakpointed or single-stepping */ -#define TIF_GUARDED_STORAGE 4/* load guarded storage control block */ +#define TIF_NEED_RESCHED_LAZY 3/* lazy rescheduling needed */ +#define TIF_UPROBE 4/* breakpointed or single-stepping */ #define TIF_PATCH_PENDING 5/* pending live patching update */ #define TIF_PGSTE 6/* New mm's will use 4K page tables */ #define TIF_NOTIFY_SIGNAL 7/* signal notifications exist */ +#define TIF_GUARDED_STORAGE 8/* load guarded storage control block */ #define TIF_ISOLATE_BP_GUEST 9/* Run KVM guests with isolated BP */ #define TIF_PER_TRAP 10/* Need to handle PER trap on exit to usermode */ #define TIF_31BIT 16/* 32bit process */ @@ -85,11 +86,12 @@ void arch_setup_new_exec(void);#define _TIF_NOTIFY_RESUME BIT(TIF_NOTIFY_RESUME)#define _TIF_SIGPENDING BIT(TIF_SIGPENDING)#define _TIF_NEED_RESCHED BIT(TIF_NEED_RESCHED) +#define _TIF_NEED_RESCHED_LAZY BIT(TIF_NEED_RESCHED_LAZY)#define _TIF_UPROBE BIT(TIF_UPROBE) -#define _TIF_GUARDED_STORAGE BIT(TIF_GUARDED_STORAGE)#define _TIF_PATCH_PENDING BIT(TIF_PATCH_PENDING)#define _TIF_PGSTE BIT(TIF_PGSTE)#define _TIF_NOTIFY_SIGNAL BIT(TIF_NOTIFY_SIGNAL) +#define _TIF_GUARDED_STORAGE BIT(TIF_GUARDED_STORAGE)#define _TIF_ISOLATE_BP_GUEST BIT(TIF_ISOLATE_BP_GUEST)#define _TIF_PER_TRAP BIT(TIF_PER_TRAP)#define _TIF_31BIT BIT(TIF_31BIT)
Sasha Levin
maintainerRe: [PATCH 6.12 1268/1376] s390: Add ARCH_HAS_PREEMPT_LAZY support
Quoted 1 line
I don't see this defined in 6.12.y.
Correct, ARCH_HAS_PREEMPT_LAZY does not exist on 6.12, so the select is silently ignored and 9de3e4bf6cfb ("s390: Add ARCH_HAS_PREEMPT_LAZY support") is inert there.
Same answer as on the powerpc sibling: it came in off a Kconfig context line rather than as a real dependency, it is already released, and reverting a no-op buys nothing.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 1269/1376 powerpc: Add preempt lazy support
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shrikanth Hegde <[email protected]>
[ Upstream commit 00199ed6f2ca6601b2c5856fac64132303d9437a ]
Define preempt lazy bit for Powerpc. Use bit 9 which is free and within 16 bit range of NEED_RESCHED, so compiler can issue single andi.
Since Powerpc doesn't use the generic entry/exit, add lazy check at exit to user. CONFIG_PREEMPTION is defined for lazy/full/rt so use it for return to kernel.
Ran a few benchmarks and db workload on Power10. Performance is close to preempt=none/voluntary.
Since Powerpc systems can have large core count and large memory, preempt lazy is going to be helpful in avoiding soft lockup issues.
Stable-dep-of: 902caade3cfd ("arm64: ptdump: Make note_page_flush() range aware")
--- arch/powerpc/Kconfig | 1 + arch/powerpc/include/asm/thread_info.h | 9 ++++++--- arch/powerpc/kernel/interrupt.c | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-)
arch/powerpc/Kconfig +1 -0
@@ -145,6 +145,7 @@ config PPC select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE select ARCH_HAS_PHYS_TO_DMA select ARCH_HAS_PMEM_API + select ARCH_HAS_PREEMPT_LAZY select ARCH_HAS_PTE_DEVMAP if PPC_BOOK3S_64 select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_SCALED_CPUTIME if VIRT_CPU_ACCOUNTING_NATIVE && PPC_BOOK3S_64
arch/powerpc/include/asm/thread_info.h +6 -3
@@ -103,6 +103,7 @@ void arch_setup_new_exec(void);#define TIF_PATCH_PENDING 6/* pending live patching update */ #define TIF_SYSCALL_AUDIT 7/* syscall auditing active */ #define TIF_SINGLESTEP 8/* singlestepping active */ +#define TIF_NEED_RESCHED_LAZY 9/* Scheduler driven lazy preemption */ #define TIF_SECCOMP 10/* secure computing */ #define TIF_RESTOREALL 11/* Restore all regs (implies NOERROR) */ #define TIF_NOERROR 12/* Force successful syscall return */
@@ -122,6 +123,7 @@ void arch_setup_new_exec(void);#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) +#define _TIF_NEED_RESCHED_LAZY (1<<TIF_NEED_RESCHED_LAZY)#define _TIF_NOTIFY_SIGNAL (1<<TIF_NOTIFY_SIGNAL)#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)#define _TIF_32BIT (1<<TIF_32BIT)
@@ -142,9 +144,10 @@ void arch_setup_new_exec(void); _TIF_SYSCALL_EMU)#define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ - _TIF_NOTIFY_RESUME | _TIF_UPROBE | \ - _TIF_RESTORE_TM | _TIF_PATCH_PENDING | \ - _TIF_NOTIFY_SIGNAL) + _TIF_NEED_RESCHED_LAZY | _TIF_NOTIFY_RESUME | \ + _TIF_UPROBE | _TIF_RESTORE_TM | \ + _TIF_PATCH_PENDING | _TIF_NOTIFY_SIGNAL) +#define _TIF_PERSYSCALL_MASK (_TIF_RESTOREALL|_TIF_NOERROR)/* Bits in local_flags */
arch/powerpc/kernel/interrupt.c +2 -2
@@ -185,7 +185,7 @@ interrupt_exit_user_prepare_main(unsigned long ret, struct pt_regs *regs) ti_flags =read_thread_flags ();while (unlikely (ti_flags & (_TIF_USER_WORK_MASK & ~_TIF_RESTORE_TM))) {local_irq_enable (); -if (ti_flags & _TIF_NEED_RESCHED) { +if (ti_flags & (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY)) {schedule (); }else {/*
@@ -396,7 +396,7 @@ notrace unsigned long interrupt_exit_kernel_prepare(struct pt_regs *regs)/* Returning to a kernel context with local irqs enabled. */ WARN_ON_ONCE (!(regs->msr &MSR_EE )); again: -if (IS_ENABLED (CONFIG_PREEMPT )) { +if (IS_ENABLED (CONFIG_PREEMPTION )) {/* Return to preemptible kernel context */ if (unlikely (read_thread_flags () & _TIF_NEED_RESCHED)) {if (preempt_count () ==0 )
Signature · 1 line
2.53.0
Re: [PATCH 6.12 1269/1376] powerpc: Add preempt lazy support
Quoted 39 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shrikanth Hegde <[email protected]>
[ Upstream commit
00199ed6f2ca6601b2c5856fac64132303d9437a]Define preempt lazy bit for Powerpc. Use bit 9 which is free and within 16 bit range of
NEED_RESCHED, so compiler can issue single andi.Since Powerpc doesn't use the generic entry/exit, add lazy check at exit to user.
CONFIG_PREEMPTIONis defined for lazy/full/rt so use it for return to kernel.Ran a few benchmarks and db workload on Power10. Performance is close to preempt=none/voluntary.
Since Powerpc systems can have large core count and large memory, preempt lazy is going to be helpful in avoiding soft lockup issues.
Reviewed-by Sebastian Andrzej Siewior <[email protected]>Reviewed-by Ankur Arora <[email protected]>Signed-off-by Shrikanth Hegde <[email protected]>Signed-off-by Madhavan Srinivasan <[email protected]>Stable-dep-of:
902caade3cfd("arm64: ptdump: Makenote_page_flush()range aware")Signed-off-by Sasha Levin <[email protected]>--- arch/powerpc/Kconfig | 1 + arch/powerpc/include/asm/thread_info.h | 9 ++++++--- arch/powerpc/kernel/interrupt.c | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-)arch/powerpc/Kconfig +0
-0
arch/powerpc/Kconfig config PPC · line 148
Quoted 4 lines
arch/powerpc/Kconfig +1
-0@@ -145,6 +145,7 @@ config PPC select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE select ARCH_HAS_PHYS_TO_DMA select ARCH_HAS_PMEM_API + select ARCH_HAS_PREEMPT_LAZY
Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
The PowerPC flag definitions and return checks are present, but 6.12 has no PREEMPT_LAZY Kconfig model, resched_curr_lazy() writer, fair-scheduler use, or tick-time promotion. Those generic pieces come from 26baa1f1c4bdc34b8d698c1900b407d863ad0e69 and 7c70cb94d29cd325fabe4a818c18613e3b9919a1, both absent here.
This is a broad scheduler feature rather than an isolated stable fix. Mayeb we should revert this. Thoughts?
thanks,
Harshit> select ARCH_HAS_PTE_DEVMAP if PPC_BOOK3S_64
Quoted 58 lines
arch/powerpc/Kconfig +0
-0select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_SCALED_CPUTIME if VIRT_CPU_ACCOUNTING_NATIVE && PPC_BOOK3S_64arch/powerpc/include/asm/thread_info.h +6
-3@@ -103,6 +103,7 @@ void arch_setup_new_exec(void);#define TIF_PATCH_PENDING 6/* pending live patching update */ #define TIF_SYSCALL_AUDIT 7/* syscall auditing active */ #define TIF_SINGLESTEP 8/* singlestepping active */ +#define TIF_NEED_RESCHED_LAZY 9/* Scheduler driven lazy preemption */ #define TIF_SECCOMP 10/* secure computing */ #define TIF_RESTOREALL 11/* Restore all regs (implies NOERROR) */ #define TIF_NOERROR 12/* Force successful syscall return */ @@ -122,6 +123,7 @@ void arch_setup_new_exec(void);#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) +#define _TIF_NEED_RESCHED_LAZY (1<<TIF_NEED_RESCHED_LAZY)#define _TIF_NOTIFY_SIGNAL (1<<TIF_NOTIFY_SIGNAL)#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)#define _TIF_32BIT (1<<TIF_32BIT)@@ -142,9 +144,10 @@ void arch_setup_new_exec(void); _TIF_SYSCALL_EMU)#define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ - _TIF_NOTIFY_RESUME | _TIF_UPROBE | \ - _TIF_RESTORE_TM | _TIF_PATCH_PENDING | \ - _TIF_NOTIFY_SIGNAL) + _TIF_NEED_RESCHED_LAZY | _TIF_NOTIFY_RESUME | \ + _TIF_UPROBE | _TIF_RESTORE_TM | \ + _TIF_PATCH_PENDING | _TIF_NOTIFY_SIGNAL) +#define _TIF_PERSYSCALL_MASK (_TIF_RESTOREALL|_TIF_NOERROR)/* Bits in local_flags */ arch/powerpc/kernel/interrupt.c +2
-2@@ -185,7 +185,7 @@ interrupt_exit_user_prepare_main(unsigned long ret, struct pt_regs *regs) ti_flags =read_thread_flags ();while (unlikely (ti_flags & (_TIF_USER_WORK_MASK & ~_TIF_RESTORE_TM))) {local_irq_enable (); -if (ti_flags & _TIF_NEED_RESCHED) { +if (ti_flags & (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY)) {schedule (); }else {/* @@ -396,7 +396,7 @@ notrace unsigned long interrupt_exit_kernel_prepare(struct pt_regs *regs)/* Returning to a kernel context with local irqs enabled. */ WARN_ON_ONCE (!(regs->msr &MSR_EE )); again: -if (IS_ENABLED (CONFIG_PREEMPT )) { +if (IS_ENABLED (CONFIG_PREEMPTION )) {/* Return to preemptible kernel context */ if (unlikely (read_thread_flags () & _TIF_NEED_RESCHED)) {if (preempt_count () ==0 )
Sasha Levin
maintainerRe: [PATCH 6.12 1269/1376] powerpc: Add preempt lazy support
Quoted 2 lines
This is a broad scheduler feature rather than an isolated stable fix. Mayeb we should revert this. Thoughts?
The pieces you name are indeed absent, and that is what makes the commit inert on 6.12 rather than incomplete. ARCH_HAS_PREEMPT_LAZY is not defined there, kconfig silently ignores a select of an undefined symbol, and nothing on the tree ever sets TIF_NEED_RESCHED_LAZY, so none of the guarded code compiles.
It arrived as a dependency walker false positive, a Kconfig context line next to "select ARCH_HAS_PTDUMP" in the hunk taken for 902caade3cfd ("arm64: ptdump:
Make note_page_flush() range aware"), not as a real prerequisite.
Since it is released and does nothing observable, I am keeping it rather than adding a revert.
Signature · 2 lines
Thanks, Sasha
Re: [PATCH 6.12 1269/1376] powerpc: Add preempt lazy support
Quoted 2 lines · Sasha Levin
Since it is released and does nothing observable, I am keeping it rather than adding a revert.
Sure, thanks.
Regards,
Harshit
Re: [PATCH 6.12 1269/1376] powerpc: Add preempt lazy support
In reply to Sasha LevinHi Sasha,
Quoted 8 lines · Sasha Levin
Quoted 2 lines
This is a broad scheduler feature rather than an isolated stable fix. Mayeb we should revert this. Thoughts?
The pieces you name are indeed absent, and that is what makes the commit inert on 6.12 rather than incomplete.
ARCH_HAS_PREEMPT_LAZYis not defined there, kconfig silently ignores a select of an undefined symbol, and nothing on the tree ever setsTIF_NEED_RESCHED_LAZY, so none of the guarded code compiles.
Quoted 7 lines
It arrived as a dependency walker false positive, a
Kconfigcontext line next to "selectARCH_HAS_PTDUMP" in the hunk taken for902caade3cfd("arm64: ptdump:
Makenote_page_flush()range aware"), not as a real prerequisite.Since it is released and does nothing observable, I am keeping it rather than adding a revert.
As it has been discussed it is really necessary in 6.12?
Seeing some LAZY related code while main mechanism is missing can be confusing. No?
If main mechanism is not there in 6.12, I think we can drop this patch from 6.12.
Sasha Levin
maintainerRe: [PATCH 6.12 1269/1376] powerpc: Add preempt lazy support
Quoted 4 lines
As it has been discussed it is really necessary in 6.12?
Seeing some LAZY related code while main mechanism is missing can be confusing. No?If main mechanism is not there in 6.12, I think we can drop this patch from 6.12.
It is not necessary, and it is also not doing anything. There is no config PREEMPT_LAZY on 6.12, resched_curr_lazy() has no callers, TIF_NEED_RESCHED_LAZY is never set, and PREEMPTION there is exactly PREEMPT since powerpc selects neither HAVE_PREEMPT_DYNAMIC nor ARCH_SUPPORTS_RT. What landed is dead code rather than a behaviour change, and it came in through a dependency walker false positive rather than as a real prerequisite. The byte identical dead LAZY code also sits in the s390 counterpart.
So I would rather leave it than put a revert on a released tree, since that has its own churn cost for everyone rebasing on 6.12.y. If it ever gets in the way of another backport I will drop it then.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 1270/1376 mm: make DEBUG_WX depdendent on GENERIC_PTDUMP
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anshuman Khandual <[email protected]>
[ Upstream commit 3f54872454a927a2b5f9fb3e2d3cdbd51b3666b7 ]
DEBUG_WX selects PTDUMP_CORE without even ensuring that the given platform implements GENERIC_PTDUMP. This problem has been latent until now, as all the platforms subscribing ARCH_HAS_DEBUG_WX also subscribe GENERIC_PTDUMP.
Stable-dep-of: 902caade3cfd ("arm64: ptdump: Make note_page_flush() range aware")
--- mm/Kconfig.debug | 1 + 1 file changed, 1 insertion(+)
mm/Kconfig.debug +1 -0
@@ -186,6 +186,7 @@ config ARCH_HAS_DEBUG_WX config DEBUG_WX bool "Warn on W+X mappings at boot" depends on ARCH_HAS_DEBUG_WX + depends on GENERIC_PTDUMP depends on MMU select PTDUMP_CORE help
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1271/1376 mm: rename GENERIC_PTDUMP and PTDUMP_CORE
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anshuman Khandual <[email protected]>
[ Upstream commit f9aad622006bd64c28fdf73c03a1c5139fcbf049 ]
Platforms subscribe into generic ptdump implementation via GENERIC_PTDUMP. But generic ptdump gets enabled via PTDUMP_CORE. These configs combination is confusing as they sound very similar and does not differentiate between platform's feature subscription and feature enablement for ptdump. Rename the configs as ARCH_HAS_PTDUMP and PTDUMP making it more clear and improve readability.
Stable-dep-of: 902caade3cfd ("arm64: ptdump: Make note_page_flush() range aware")
--- arch/arm64/Kconfig | 2 +- arch/arm64/include/asm/ptdump.h | 4 ++-- arch/arm64/kvm/Kconfig | 4 ++-- arch/arm64/mm/Makefile | 2 +- arch/powerpc/Kconfig | 2 +- arch/powerpc/mm/Makefile | 2 +- arch/riscv/Kconfig | 2 +- arch/riscv/mm/Makefile | 2 +- arch/s390/Kconfig | 2 +- arch/s390/mm/Makefile | 2 +- arch/x86/Kconfig | 2 +- arch/x86/Kconfig.debug | 2 +- arch/x86/mm/Makefile | 2 +- mm/Kconfig.debug | 12 ++++++------ mm/Makefile | 2 +- 15 files changed, 22 insertions(+), 22 deletions(-)
arch/arm64/Kconfig +1 -1
@@ -39,6 +39,7 @@ config ARM64 select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE select ARCH_HAS_NONLEAF_PMD_YOUNG if ARM64_HAFT + select ARCH_HAS_PTDUMP select ARCH_HAS_PTE_DEVMAP select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_HW_PTE_YOUNG
@@ -153,7 +154,6 @@ config ARM64 select GENERIC_IRQ_SHOW_LEVEL select GENERIC_LIB_DEVMEM_IS_ALLOWED select GENERIC_PCI_IOMAP - select GENERIC_PTDUMP select GENERIC_SCHED_CLOCK select GENERIC_SMP_IDLE_THREAD select GENERIC_TIME_VSYSCALL
arch/arm64/include/asm/ptdump.h +2 -2
@@ -7,7 +7,7 @@#include <linux/ptdump.h> -#ifdef CONFIG_PTDUMP_CORE +#ifdef CONFIG_PTDUMP #include <linux/mm_types.h> #include <linux/seq_file.h>
@@ -70,6 +70,6 @@ static inline void ptdump_debugfs_register(struct ptdump_info *info,#else static inline void note_page (struct ptdump_state *pt_st,unsigned long addr,int level,u64 val) { } -#endif /* CONFIG_PTDUMP_CORE */ +#endif /* CONFIG_PTDUMP */ #endif /* __ASM_PTDUMP_H */
arch/arm64/kvm/Kconfig +2 -2
@@ -71,8 +71,8 @@ config PTDUMP_STAGE2_DEBUGFS depends on KVM depends on DEBUG_KERNEL depends on DEBUG_FS - depends on GENERIC_PTDUMP - select PTDUMP_CORE + depends on ARCH_HAS_PTDUMP + select PTDUMP default n help Say Y here if you want to show the stage-2 kernel pagetables
arch/arm64/mm/Makefile +1 -1
@@ -5,7 +5,7 @@ obj-y := dma-mapping.o extable.o fault.o init.o \ context.o proc.o pageattr.o fixmap.o obj-$(CONFIG_ARM64_CONTPTE) += contpte.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o -obj-$(CONFIG_PTDUMP_CORE) += ptdump.o +obj-$(CONFIG_PTDUMP) += ptdump.o obj-$(CONFIG_PTDUMP_DEBUGFS) += ptdump_debugfs.o obj-$(CONFIG_TRANS_TABLE) += trans_pgd.o obj-$(CONFIG_TRANS_TABLE) += trans_pgd-asm.o
arch/powerpc/Kconfig +1 -1
@@ -146,6 +146,7 @@ config PPC select ARCH_HAS_PHYS_TO_DMA select ARCH_HAS_PMEM_API select ARCH_HAS_PREEMPT_LAZY + select ARCH_HAS_PTDUMP select ARCH_HAS_PTE_DEVMAP if PPC_BOOK3S_64 select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_SCALED_CPUTIME if VIRT_CPU_ACCOUNTING_NATIVE && PPC_BOOK3S_64
@@ -204,7 +205,6 @@ config PPC select GENERIC_IRQ_SHOW select GENERIC_IRQ_SHOW_LEVEL select GENERIC_PCI_IOMAP if PCI - select GENERIC_PTDUMP select GENERIC_SMP_IDLE_THREAD select GENERIC_TIME_VSYSCALL select GENERIC_VDSO_TIME_NS
arch/powerpc/mm/Makefile +1 -1
@@ -15,5 +15,5 @@ obj-$(CONFIG_NUMA) += numa.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o obj-$(CONFIG_PPC_COPRO_BASE) += copro_fault.o -obj-$(CONFIG_PTDUMP_CORE) += ptdump/ +obj-$(CONFIG_PTDUMP) += ptdump/ obj-$(CONFIG_KASAN) += kasan/
arch/riscv/Kconfig +1 -1
@@ -40,6 +40,7 @@ config RISCV select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE select ARCH_HAS_PMEM_API select ARCH_HAS_PREPARE_SYNC_CORE_CMD + select ARCH_HAS_PTDUMP if MMU select ARCH_HAS_PTE_DEVMAP if 64BIT && MMU select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_SET_DIRECT_MAP if MMU
@@ -108,7 +109,6 @@ config RISCV select GENERIC_IRQ_SHOW_LEVEL select GENERIC_LIB_DEVMEM_IS_ALLOWED select GENERIC_PCI_IOMAP - select GENERIC_PTDUMP if MMU select GENERIC_SCHED_CLOCK select GENERIC_SMP_IDLE_THREAD select GENERIC_TIME_VSYSCALL if MMU && 64BIT
arch/riscv/mm/Makefile +1 -1
@@ -19,7 +19,7 @@ obj-y += context.o obj-y += pmem.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o -obj-$(CONFIG_PTDUMP_CORE) += ptdump.o +obj-$(CONFIG_PTDUMP) += ptdump.o obj-$(CONFIG_KASAN) += kasan_init.o ifdef CONFIG_KASAN
arch/s390/Kconfig +1 -1
@@ -81,6 +81,7 @@ config S390 select ARCH_HAS_MEM_ENCRYPT select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS select ARCH_HAS_PREEMPT_LAZY + select ARCH_HAS_PTDUMP select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_SCALED_CPUTIME select ARCH_HAS_SET_DIRECT_MAP
@@ -146,7 +147,6 @@ config S390 select GENERIC_CPU_VULNERABILITIES select GENERIC_ENTRY select GENERIC_GETTIMEOFDAY - select GENERIC_PTDUMP select GENERIC_SMP_IDLE_THREAD select GENERIC_TIME_VSYSCALL select GENERIC_VDSO_TIME_NS
arch/s390/mm/Makefile +1 -1
@@ -9,6 +9,6 @@ obj-y += page-states.o pageattr.o pgtable.o pgalloc.o extable.o obj-$(CONFIG_CMM) += cmm.o obj-$(CONFIG_DEBUG_VIRTUAL) += physaddr.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o -obj-$(CONFIG_PTDUMP_CORE) += dump_pagetables.o +obj-$(CONFIG_PTDUMP) += dump_pagetables.o obj-$(CONFIG_PGSTE) += gmap.o obj-$(CONFIG_PFAULT) += pfault.o
arch/x86/Kconfig +1 -1
@@ -26,6 +26,7 @@ config X86_64 depends on 64BIT # Options that are inherently 64-bit kernel only: select ARCH_HAS_GIGANTIC_PAGE + select ARCH_HAS_PTDUMP select ARCH_SUPPORTS_INT128 if CC_HAS_INT128 select ARCH_SUPPORTS_PER_VMA_LOCK select ARCH_SUPPORTS_HUGE_PFNMAP if TRANSPARENT_HUGEPAGE
@@ -169,7 +170,6 @@ config X86 select GENERIC_IRQ_RESERVATION_MODE select GENERIC_IRQ_SHOW select GENERIC_PENDING_IRQ if SMP - select GENERIC_PTDUMP select GENERIC_SMP_IDLE_THREAD select GENERIC_TIME_VSYSCALL select GENERIC_GETTIMEOFDAY
arch/x86/Kconfig.debug +1 -1
@@ -59,7 +59,7 @@ config EARLY_PRINTK_USB_XDBC config EFI_PGT_DUMP bool "Dump the EFI pagetable" depends on EFI - select PTDUMP_CORE + select PTDUMP help Enable this if you want to dump the EFI page table before enabling virtual mode. This can be used to debug miscellaneous
arch/x86/mm/Makefile +1 -1
@@ -41,7 +41,7 @@ CFLAGS_fault.o := -I $(src)/../include/asm/trace obj-$(CONFIG_X86_32) += pgtable_32.o iomap_32.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o -obj-$(CONFIG_PTDUMP_CORE) += dump_pagetables.o +obj-$(CONFIG_PTDUMP) += dump_pagetables.o obj-$(CONFIG_PTDUMP_DEBUGFS) += debug_pagetables.o obj-$(CONFIG_HIGHMEM) += highmem_32.o
mm/Kconfig.debug +6 -6
@@ -186,9 +186,9 @@ config ARCH_HAS_DEBUG_WX config DEBUG_WX bool "Warn on W+X mappings at boot" depends on ARCH_HAS_DEBUG_WX - depends on GENERIC_PTDUMP + depends on ARCH_HAS_PTDUMP depends on MMU - select PTDUMP_CORE + select PTDUMP help Generate a warning if any W+X mappings are found at boot.
@@ -213,18 +213,18 @@ config DEBUG_WX If in doubt, say "Y". -config GENERIC_PTDUMP +config ARCH_HAS_PTDUMP bool -config PTDUMP_CORE +config PTDUMP bool config PTDUMP_DEBUGFS bool "Export kernel pagetable layout to userspace via debugfs" depends on DEBUG_KERNEL depends on DEBUG_FS - depends on GENERIC_PTDUMP - select PTDUMP_CORE + depends on ARCH_HAS_PTDUMP + select PTDUMP help Say Y here if you want to show the kernel pagetable layout in a debugfs file. This information is only useful for kernel developers
mm/Makefile +1 -1
@@ -137,7 +137,7 @@ obj-$(CONFIG_ZONE_DEVICE) += memremap.o obj-$(CONFIG_HMM_MIRROR) += hmm.o obj-$(CONFIG_MEMFD_CREATE) += memfd.o obj-$(CONFIG_MAPPING_DIRTY_HELPERS) += mapping_dirty_helpers.o -obj-$(CONFIG_PTDUMP_CORE) += ptdump.o +obj-$(CONFIG_PTDUMP) += ptdump.o obj-$(CONFIG_PAGE_REPORTING) += page_reporting.o obj-$(CONFIG_IO_MAPPING) += io-mapping.o obj-$(CONFIG_HAVE_BOOTMEM_INFO_NODE) += bootmem_info.o
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1272/1376 mm/ptdump: split note_page() into level specific callbacks
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anshuman Khandual <[email protected]>
[ Upstream commit e064e7384f991c7df81999cad4ce30fed7ef7d88 ]
Patch series "mm/ptdump: Drop assumption that pxd_val() is u64", v2.
Last argument passed down in note_page() is u64 assuming pxd_val() returned value (all page table levels) is 64 bit - which might not be the case going ahead when D128 page tables is enabled on arm64 platform. Besides pxd_val() is very platform specific and its type should not be assumed in generic MM. A similar problem exists for effective_prot(), although it is restricted to x86 platform.
This series splits note_page() and effective_prot() into individual page table level specific callbacks which accepts corresponding pxd_t page table entry as an argument instead and later on all subscribing platforms could derive pxd_val() from the table entries as required and proceed as before.
Define ptdesc_t type which describes the basic page table descriptor layout on arm64 platform. Subsequently all level specific pxxval_t descriptors are derived from ptdesc_t thus establishing a common original format, which can also be appropriate for page table entries, masks and protection values etc which are used at all page table levels.
This patch (of 3):
Last argument passed down in note_page() is u64 assuming pxd_val() returned value (all page table levels) is 64 bit - which might not be the case going ahead when D128 page tables is enabled on arm64 platform. Besides pxd_val() is very platform specific and its type should not be assumed in generic MM.
Split note_page() into individual page table level specific callbacks which accepts corresponding pxd_t argument instead and then subscribing platforms just derive pxd_val() from the entries as required and proceed as earlier.
Also add a note_page_flush() callback for flushing the last page table page that was being handled earlier via level = -1.
case going ahead when D128 page tables is enabled on arm64 platform. Besides pxd_val() is very platform specific and its type should not be assumed in generic MM. A similar problem exists for effective_prot(), although it is restricted to x86 platform.
This series splits note_page() and effective_prot() into individual page table level specific callbacks which accepts corresponding pxd_t page table entry as an argument instead and later on all subscribing platforms could derive pxd_val() from the table entries as required and proceed as before.
Define ptdesc_t type which describes the basic page table descriptor layout on arm64 platform. Subsequently all level specific pxxval_t descriptors are derived from ptdesc_t thus establishing a common original format, which can also be appropriate for page table entries, masks and protection values etc which are used at all page table levels.
This patch (of 3):
Last argument passed down in note_page() is u64 assuming pxd_val() returned value (all page table levels) is 64 bit - which might not be the case going ahead when D128 page tables is enabled on arm64 platform.
Stable-dep-of: 902caade3cfd ("arm64: ptdump: Make note_page_flush() range aware")
--- arch/arm64/include/asm/ptdump.h | 16 +++++++++-- arch/arm64/mm/ptdump.c | 48 ++++++++++++++++++++++++++++++--- arch/powerpc/mm/ptdump/ptdump.c | 46 +++++++++++++++++++++++++++++-- arch/riscv/mm/ptdump.c | 46 +++++++++++++++++++++++++++++-- arch/s390/mm/dump_pagetables.c | 46 +++++++++++++++++++++++++++++-- arch/x86/mm/dump_pagetables.c | 39 ++++++++++++++++++++++++++- include/linux/ptdump.h | 9 ++++--- mm/ptdump.c | 42 ++++++++++++++++++++++------- 8 files changed, 267 insertions(+), 25 deletions(-)
arch/arm64/include/asm/ptdump.h +14 -2
@@ -59,7 +59,13 @@ struct ptdump_pg_state {void ptdump_walk (struct seq_file *s,struct ptdump_info *info);void note_page (struct ptdump_state *pt_st,unsigned long addr,int level, -u64 val); +pteval_t val); +void note_page_pte (struct ptdump_state *st,unsigned long addr,pte_t pte); +void note_page_pmd (struct ptdump_state *st,unsigned long addr,pmd_t pmd); +void note_page_pud (struct ptdump_state *st,unsigned long addr,pud_t pud); +void note_page_p4d (struct ptdump_state *st,unsigned long addr,p4d_t p4d); +void note_page_pgd (struct ptdump_state *st,unsigned long addr,pgd_t pgd); +void note_page_flush (struct ptdump_state *st);#ifdef CONFIG_PTDUMP_DEBUGFS #define EFI_RUNTIME_MAP_END DEFAULT_MAP_WINDOW_64void __init ptdump_debugfs_register (struct ptdump_info *info,const char *name);
@@ -69,7 +75,13 @@ static inline void ptdump_debugfs_register(struct ptdump_info *info,#endif /* CONFIG_PTDUMP_DEBUGFS */ #else static inline void note_page (struct ptdump_state *pt_st,unsigned long addr, -int level,u64 val) { } +int level,pteval_t val) { } +static inline void note_page_pte (struct ptdump_state *st,unsigned long addr,pte_t pte) { } +static inline void note_page_pmd (struct ptdump_state *st,unsigned long addr,pmd_t pmd) { } +static inline void note_page_pud (struct ptdump_state *st,unsigned long addr,pud_t pud) { } +static inline void note_page_p4d (struct ptdump_state *st,unsigned long addr,p4d_t p4d) { } +static inline void note_page_pgd (struct ptdump_state *st,unsigned long addr,pgd_t pgd) { } +static inline void note_page_flush (struct ptdump_state *st) { }#endif /* CONFIG_PTDUMP */ #endif /* __ASM_PTDUMP_H */
arch/arm64/mm/ptdump.c +45 -3
72 lines not on this page · raw message
arch/powerpc/mm/ptdump/ptdump.c +44 -2
64 lines not on this page · raw message
arch/riscv/mm/ptdump.c +44 -2
64 lines not on this page · raw message
arch/s390/mm/dump_pagetables.c +44 -2
62 lines not on this page · raw message
arch/x86/mm/dump_pagetables.c +38 -1
@@ -362,6 +362,38 @@ static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level, } } +static void note_page_pte (struct ptdump_state *pt_st,unsigned long addr,pte_t pte) +{ +note_page (pt_st, addr,4 ,pte_val (pte)); +} + +static void note_page_pmd (struct ptdump_state *pt_st,unsigned long addr,pmd_t pmd) +{ +note_page (pt_st, addr,3 ,pmd_val (pmd)); +} + +static void note_page_pud (struct ptdump_state *pt_st,unsigned long addr,pud_t pud) +{ +note_page (pt_st, addr,2 ,pud_val (pud)); +} + +static void note_page_p4d (struct ptdump_state *pt_st,unsigned long addr,p4d_t p4d) +{ +note_page (pt_st, addr,1 ,p4d_val (p4d)); +} + +static void note_page_pgd (struct ptdump_state *pt_st,unsigned long addr,pgd_t pgd) +{ +note_page (pt_st, addr,0 ,pgd_val (pgd)); +} + +static void note_page_flush (struct ptdump_state *pt_st) +{ +pte_t pte_zero = {0 }; + +note_page (pt_st,0 ,-1 ,pte_val (pte_zero)); +} +bool ptdump_walk_pgd_level_core (struct seq_file *m,struct mm_struct *mm,pgd_t *pgd,bool checkwx,bool dmesg)
@@ -378,7 +410,12 @@ bool ptdump_walk_pgd_level_core(struct seq_file *m,struct pg_state st = { .ptdump = { - .note_page = note_page, + .note_page_pte = note_page_pte, + .note_page_pmd = note_page_pmd, + .note_page_pud = note_page_pud, + .note_page_p4d = note_page_p4d, + .note_page_pgd = note_page_pgd, + .note_page_flush = note_page_flush, .effective_prot = effective_prot, .range = ptdump_ranges },
include/linux/ptdump.h +6 -3
@@ -11,9 +11,12 @@ struct ptdump_range { };struct ptdump_state { -/* level is 0:PGD to 4:PTE, or -1 if unknown */ -void (*note_page)(struct ptdump_state *st,unsigned long addr, -int level,u64 val); +void (*note_page_pte)(struct ptdump_state *st,unsigned long addr,pte_t pte); +void (*note_page_pmd)(struct ptdump_state *st,unsigned long addr,pmd_t pmd); +void (*note_page_pud)(struct ptdump_state *st,unsigned long addr,pud_t pud); +void (*note_page_p4d)(struct ptdump_state *st,unsigned long addr,p4d_t p4d); +void (*note_page_pgd)(struct ptdump_state *st,unsigned long addr,pgd_t pgd); +void (*note_page_flush)(struct ptdump_state *st);void (*effective_prot)(struct ptdump_state *st,int level,u64 val);const struct ptdump_range *range; };
mm/ptdump.c +32 -10
90 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1273/1376 arm64: ptdump: Make note_page_flush() range aware
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei-Lin Chang <[email protected]>
[ Upstream commit 902caade3cfd60f99bf71b355e7c86344bd831e5 ]
note_page_flush() calls note_page() with addr == 0 and level == -1 to dump the last row of a ptdump. addr == 0 (1 << 64 wrapped around) renders a huge region with enormous size for address spaces with IA bits < 64. For example the stage-2 page tables and the EFI runtime page table.
More importantly, the last region of the address space and everything after the address space up to 1 << 64 are merged into one row of output. If the last region within the address space is valid, it will appear to remain valid up to 1 << 64 with the same attributes.
Currently only the EFI runtime ptdump is affected by this, but KVM will soon fix its stage-2 ptdump by using note_page_flush(). Here is an example of an EFI runtime ptdump (last row):
0x0000008000000000-0x0000000000000000 17179868672G PGD
With this patch:
0x0000008000000000-0x0001000000000000 261632G PGD
To fix this, cache the end address of a ptdump in ptdump_pg_state so note_page_flush() can call the final note_page() with the correct end address.
--- arch/arm64/include/asm/ptdump.h | 2 ++ arch/arm64/mm/ptdump.c | 14 +++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-)
arch/arm64/include/asm/ptdump.h +2 -0
@@ -50,6 +50,8 @@ struct ptdump_pg_state {const struct addr_marker *marker;const struct mm_struct *mm;unsigned long start_address; +/* exclusive end, ULONG_MAX represents an end at 1 << 64 */ +unsigned long end_address;int level;u64 current_prot;bool check_wx;
arch/arm64/mm/ptdump.c +13 -1
@@ -278,9 +278,19 @@ void note_page_pgd(struct ptdump_state *pt_st, unsigned long addr, pgd_t pgd)void note_page_flush (struct ptdump_state *pt_st) { + struct ptdump_pg_state *st = container_of(pt_st, struct ptdump_pg_state, ptdump); +unsigned long end = st->end_address;pte_t pte_zero = {0 }; -note_page (pt_st,0 ,-1 ,pte_val (pte_zero)); +/* +* Address spaces that end at 1 << 64 have end_address == ULONG_MAX, +* but note_page() expects the exclusive end. In this case adjust end +* to the wraparound value 0. +*/ +if (end ==ULONG_MAX ) + end =0 ; + +note_page (pt_st, end,-1 ,pte_val (pte_zero)); }void ptdump_walk (struct seq_file *s,struct ptdump_info *info)
@@ -296,6 +306,7 @@ void ptdump_walk(struct seq_file *s, struct ptdump_info *info) .marker = info->markers, .mm = info->mm, .pg_level = &kernel_pg_levels[0], + .end_address = end, .level = -1, .ptdump = { .note_page_pte = note_page_pte,
@@ -337,6 +348,7 @@ bool ptdump_check_wx(void) { -1, NULL}, }, .pg_level = &kernel_pg_levels[0], + .end_address = ~0UL, .level = -1, .check_wx = true, .ptdump = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1274/1376 Bluetooth: L2CAP: reject accept queue add unless BT_LISTEN
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit d4bfa78fd67929b62b02013c107973e0c5b7aa9a ]
New sk should not be added to parent socket accept queue after last l2cap_sock_cleanup_listen() has run in l2cap_sock_teardown_cb() and state set to BT_CLOSED, as that can result to UAF on dereferencing the dangling parent reference.
l2cap_sock_new_connection_cb() may race with parent l2cap_chan teardown, due to chan->state accessed without consistent locking:
[Task 1] [Task 2]
l2cap_sock_release(parent) l2cap_connect
l2cap_sock_shutdown pchan = l2cap_global_chan_by_psm
l2cap_chan_lock(pchan)
l2cap_chan_close
l2cap_sock_teardown_cb
pchan->state = BT_CLOSED
l2cap_chan_unlock(pchan) ------> l2cap_chan_lock(pchan)
l2cap_new_connection
l2cap_sock_new_connection_cb
l2cap_chan_lock(pchan) <-------- l2cap_chan_unlock(pchan)
l2cap_sock_kill(parent) /* bt_sk(sk)->parent dangling */Fix by adding check for sk_state == BT_LISTEN after acquiring sk lock in l2cap_sock_new_connection_cb(). Add lock_sock() around sk_state writes where missing, to avoid data races.
Although the data races on pchan->state should be fixed too, this defensive sk_state check probably makes sense in any case.
--- net/bluetooth/l2cap_sock.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
net/bluetooth/l2cap_sock.c +13 -0
@@ -1526,6 +1526,11 @@ static int l2cap_sock_new_connection_cb(struct l2cap_chan *chan,lock_sock (parent); +if (parent->sk_state !=BT_LISTEN ) { +release_sock (parent); +return -EINVAL ; + } +/* Check for backlog size */ if (sk_acceptq_is_full (parent)) {BT_DBG ("backlog full %d" , parent->sk_ack_backlog);
@@ -1690,10 +1695,14 @@ static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state,if (!sk)return ; +lock_sock (sk); + sk->sk_state = state;if (err) sk->sk_err = err; + +release_sock (sk); } static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
@@ -1769,6 +1778,8 @@ static void l2cap_sock_resume_cb(struct l2cap_chan *chan)if (!sk)return ; +lock_sock (sk); +if (test_and_clear_bit (FLAG_PENDING_SECURITY , &chan->flags)) { sk->sk_state =BT_CONNECTED ; chan->state =BT_CONNECTED ;
@@ -1776,6 +1787,8 @@ static void l2cap_sock_resume_cb(struct l2cap_chan *chan)clear_bit (BT_SK_SUSPEND , &bt_sk (sk)->flags); sk->sk_state_change (sk); + +release_sock (sk); }static void l2cap_sock_set_shutdown_cb (struct l2cap_chan *chan)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1275/1376 Bluetooth: mgmt: fix hdev->discovery.uuids NULL dereference
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavel Shpakovskiy <[email protected]>
[ Upstream commit 59eecbe2f2f38d8f3e1104bd11da97f9a2c58998 ]
'uuid_count' member of struct 'discovery_state' is assigned and read without any locks, so there is a chance of situation when uuid_count != 0, but uuids is NULL and there will be NULL pointer dereference.
Possible race:
'hci_update_passive_scan_sync'
'hci_discovery_filter_clear'
hdev->discovery.uuid_count = 0;
<----------------------preempted----------------------------->
'start_service_discovery'
// Set uuid_count to value != 0
hdev->discovery.uuid_count = uuid_count;
hdev->discovery.uuids = kmemdup(...);
<----------------------preempted----------------------------->
spin_lock(&hdev->discovery.lock);
kfree(hdev->discovery.uuids);
hdev->discovery.uuids = NULL;
spin_unlock(&hdev->discovery.lock);Now uuids == NULL and uuid_count != 0.
So 'mgmt_device_found' -> 'is_filter_match' -> 'eir_has_uuids' receives non consistent discovery state, where NULL dereference of uuids happens.
To fix it let's add discovery.lock around every read/write of uuid_count, uuids pair of struct members. It is also important to assign uuid_count value only after success kmemdup() allocation in start_service_discovery(), otherwise uuids is NULL, because kmemdup failed, but uuid_count is already assigned to non zero value.
The following panic happens:
[ ] ------------[ cut here ]------------
[ ] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
[ ] Internal error: Oops: 0000000096000006 [#1] PREEMPT SMP [ ] CPU: 0 PID: 15056 Comm: kworker/u9:2
[ ] Workqueue: hci0 hci_rx_work
[ ] pstate: 10400009 (nzcV daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ ] pc : eir_has_uuids+0x2d8/0x590
[ ] lr : is_filter_match+0x258/0x320
...
[ ] Call trace:
[ ] eir_has_uuids+0x2d8/0x590 [ ] is_filter_match+0x258/0x320 [ ] mgmt_device_found+0x5b0/0xafc [ ] process_adv_report.part.0+0x8c8/0xf14 [ ] hci_le_adv_report_evt+0x338/0x3f0 [ ] hci_le_meta_evt+0x1f0/0x4c8 [ ] hci_event_packet+0x440/0xc9c [ ] hci_rx_work+0x44c/0xaf8 [ ] process_one_work+0x54c/0x103c [ ] worker_thread+0x6c4/0x10c4 [ ] kthread+0x274/0x2ec [ ] ret_from_fork+0x10/0x20
[ ] Code: 14000004 91004021 eb14003f 54000180 (f9400024) [ ] ---[ end trace 0000000000000000 ]---
--- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/mgmt.c | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-)
include/net/bluetooth/hci_core.h +1 -1
@@ -892,9 +892,9 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev) hdev->discovery.result_filtering = false; hdev->discovery.report_invalid_rssi = true; hdev->discovery.rssi =HCI_RSSI_INVALID ; - hdev->discovery.uuid_count =0 ;spin_lock (&hdev->discovery.lock); + hdev->discovery.uuid_count =0 ;kfree (hdev->discovery.uuids); hdev->discovery.uuids =NULL ;spin_unlock (&hdev->discovery.lock);
net/bluetooth/mgmt.c +13 -5
@@ -6157,6 +6157,7 @@ static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,struct mgmt_pending_cmd *cmd;const u16 max_uuid_count = ((U16_MAX -sizeof (*cp)) /16 );u16 uuid_count, expected_len; +u8 (*uuids)[16 ] =NULL ;u8 status;int err;
@@ -6233,12 +6234,10 @@ static int start_service_discovery(struct sock *sk, struct hci_dev *hdev, hdev->discovery.result_filtering = true; hdev->discovery.type = cp->type; hdev->discovery.rssi = cp->rssi; - hdev->discovery.uuid_count = uuid_count;if (uuid_count >0 ) { - hdev->discovery.uuids =kmemdup (cp->uuids, uuid_count *16 , -GFP_KERNEL ); -if (!hdev->discovery.uuids) { + uuids =kmemdup (cp->uuids, uuid_count *sizeof (*uuids),GFP_KERNEL ); +if (!uuids) { err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_SERVICE_DISCOVERY, MGMT_STATUS_FAILED,
@@ -6248,6 +6247,11 @@ static int start_service_discovery(struct sock *sk, struct hci_dev *hdev, } } +spin_lock (&hdev->discovery.lock); + hdev->discovery.uuids = uuids; + hdev->discovery.uuid_count = uuid_count; +spin_unlock (&hdev->discovery.lock); + err =hci_cmd_sync_queue (hdev, start_discovery_sync, cmd, start_discovery_complete);if (err <0 ) {
@@ -10440,6 +10444,7 @@ static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir, !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))return false; +spin_lock (&hdev->discovery.lock);if (hdev->discovery.uuid_count !=0 ) {/* If a list of UUIDs is provided in filter, results with no * matching UUID should be dropped.
@@ -10448,9 +10453,12 @@ static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir, hdev->discovery.uuids) && !eir_has_uuids(scan_rsp, scan_rsp_len, hdev->discovery.uuid_count, - hdev->discovery.uuids)) + hdev->discovery.uuids)) { +spin_unlock (&hdev->discovery.lock);return false; + } } +spin_unlock (&hdev->discovery.lock);/* If duplicate filtering does not report RSSI changes, then restart * scanning to ensure updated result with updated RSSI values.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1276/1376 Bluetooth: L2CAP: fix race l2cap_sock_cleanup_listen() vs. put_chan
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit 66d6ef18548ae6d7dd452b84115fc82c0a73a4ea ]
For L2CAP sockets without owning sk->sk_socket, reading l2cap_pi(sk)->chan may race against concurrent l2cap_sock_kill() -> l2cap_sock_put_chan(). This excludes simultaneous proto_ops callbacks, but access in l2cap_sock_cleanup_listen() has unsafe lockless read.
[Task 1] [Task 2 (hdev->workqueue)]
l2cap_sock_release(parent) l2cap_disconn_cfm
l2cap_sock_cleanup_listen l2cap_conn_del
bt_accept_dequeue l2cap_chan_del
lock_sock(sk) l2cap_sock_teardown_cb
bt_accept_unlink
bt_sk(sk)->parent = NULL
release_sock(sk) ----------------> lock_sock(sk)
parent = /* NULL */
lock_sock(sk) <--------------------- release_sock(sk)
sock_set_flag(sk, SOCK_ZAPPED)
l2cap_sock_close_cb
l2cap_sock_kill(sk)
l2cap_sock_put_chan
chan = READ l2cap_pi(sk)->chan l2cap_pi(sk)->chan = NULL
l2cap_chan_hold_unless_zero l2cap_put_chan(chan)
kref_get_unless_zero(&chan->ref)Task 1 may observe NULL which causes null-ptr-deref.
Fix the race by taking lock_sock() in l2cap_sock_kill() to synchronize with l2cap_sock_cleanup_listen(). hold_unless_zero() is not needed here, l2cap_pi(sk)->chan owns reference if it is non-NULL.
Clarify code comments vs. locking.
--- include/net/bluetooth/l2cap.h | 5 +++++ net/bluetooth/l2cap_sock.c | 23 +++++++++++++---------- 2 files changed, 18 insertions(+), 10 deletions(-)
include/net/bluetooth/l2cap.h +5 -0
@@ -702,7 +702,12 @@ struct l2cap_rx_busy {struct l2cap_pinfo {struct bt_sock bt; + +/* With owning sk_socket chan may be read without lock, other access +* should hold lock_sock. +*/ struct l2cap_chan *chan; +struct list_head rx_busy; };
net/bluetooth/l2cap_sock.c +13 -10
@@ -1271,7 +1271,12 @@ static void l2cap_sock_kill(struct sock *sk)BT_DBG ("sk %p state %s" , sk,state_to_string (sk->sk_state)); +/* Take lock to synchronize against access without owning sk->sk_socket, +* eg. in l2cap_sock_cleanup_listen(). proto_ops etc. don't need lock. +*/ +lock_sock (sk);l2cap_sock_put_chan (sk); +release_sock (sk);/* Kill poor orphan */ sock_set_flag (sk,SOCK_DEAD );
@@ -1474,14 +1479,10 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)* establish sk_lock -> conn->lock and invert the established * conn->lock -> chan->lock -> sk_lock order (lockdep deadlock). * -* Instead, briefly take the child sk lock to fetch and pin its chan. -* l2cap_conn_del() reaches the chan free only via -* l2cap_chan_del() -> l2cap_sock_teardown_cb(), which itself takes -* the child sk lock; holding it across l2cap_chan_hold_unless_zero() -* therefore guarantees the chan cannot be freed while we read and -* pin it (hold_unless_zero() additionally skips a chan already past -* its last reference). We then drop the sk lock before taking -* chan->lock, so sk and chan locks are never held together. +* Instead, briefly take the child sk lock to synchronize vs. +* l2cap_sock_kill that puts l2cap_pi(sk)->chan. We then drop the sk +* lock before taking chan->lock, so sk and chan locks are never held +* together. * * Since we cannot call l2cap_chan_close() without conn->lock, * schedule l2cap_chan_timeout to close the channel; it already
@@ -1491,10 +1492,12 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)struct l2cap_chan *chan;lock_sock_nested (sk,L2CAP_NESTING_NORMAL ); - chan =l2cap_chan_hold_unless_zero (l2cap_pi (sk)->chan); + chan =l2cap_pi (sk)->chan; +if (chan) +l2cap_chan_hold (chan);release_sock (sk);if (!chan) { -/* l2cap_conn_del() already tearing this child down */ +/* Already torn down */ sock_put (sk);continue ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1277/1376 Bluetooth: btmtk: Add MT6639 (MT7927) Bluetooth support
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Javier Tia <[email protected]>
[ Upstream commit 28b7c5a6db74e9305c6cbcbe52f259ff1cf85158 ]
The MediaTek MT7927 (Filogic 380) combo WiFi 7 + BT 5.4 module uses hardware variant 0x6639 for its Bluetooth subsystem. Without this patch, the chip fails with "Unsupported hardware variant (00006639)" or hangs during firmware download.
Three changes are needed to support MT6639:
1. CHIPID workaround: On some boards the BT USB MMIO register reads 0x0000 for dev_id, causing the driver to skip the 0x6639 init path. Force dev_id to 0x6639 only when the USB VID/PID matches a known MT6639 device, avoiding misdetection if a future chip also reads zero. This follows the WiFi-side pattern that uses PCI device IDs to scope the same workaround.
2. Firmware naming: MT6639 uses firmware version prefix "2_1" instead of "1_1" used by MT7925 and other variants. The firmware path is mediatek/mt7927/BT_RAM_CODE_MT6639_2_1_hdr.bin, using the mt7927 directory to match the WiFi firmware convention. The filename will likely change to use MT7927 once MediaTek submits a dedicated Linux firmware binary.
3. Section filtering: The MT6639 firmware binary contains 9 sections, but only sections with (dlmodecrctype & 0xff) == 0x01 are Bluetooth-related. Sending the remaining WiFi/other sections causes an irreversible BT subsystem hang requiring a full power cycle. This matches the Windows driver behavior observed via USB captures.
Also add 0x6639 to the reset register (CONNV3) and firmware setup switch cases alongside the existing 0x7925 handling.
Stable-dep-of: 59c3ee19ca88 ("Bluetooth: btmtk: Do not report success when subsys reset fails")
--- drivers/bluetooth/btmtk.c | 60 ++++++++++++++++++++++++++++++++--- drivers/bluetooth/btmtk.h | 7 ++-- drivers/bluetooth/btmtksdio.c | 2 +- 3 files changed, 61 insertions(+), 8 deletions(-)
drivers/bluetooth/btmtk.c +55 -5
@@ -25,6 +25,22 @@/* It is for mt79xx iso data transmission setting */ #define MTK_ISO_THRESHOLD 264 +/* Known MT6639 (MT7927) Bluetooth USB devices. +* Used to scope the zero-CHIPID workaround to real MT6639 hardware, +* since some boards return 0x0000 from the MMIO chip ID register. +*/ +static const struct { +u16 vendor; +u16 product; +} btmtk_mt6639_devs[] = { + {0x0489 ,0xe13a },/* ASUS ROG Crosshair X870E Hero */ + {0x0489 ,0xe0fa },/* Lenovo Legion Pro 7 16ARX9 */ + {0x0489 ,0xe10f },/* Gigabyte Z790 AORUS MASTER X */ + {0x0489 ,0xe110 },/* MSI X870E Ace Max */ + {0x0489 ,0xe116 },/* TP-Link Archer TBE550E */ + {0x13d3 ,0x3588 },/* ASUS ROG STRIX X870E-E */ +}; +struct btmtk_patch_header {u8 datetime[16 ];u8 platform[4 ];
@@ -112,7 +128,11 @@ static void btmtk_coredump_notify(struct hci_dev *hdev, int state)void btmtk_fw_get_filename (char *buf,size_t size,u32 dev_id,u32 fw_ver,u32 fw_flavor) { -if (dev_id ==0x7925 ) +if (dev_id ==0x6639 ) +snprintf (buf, size, +"mediatek/mt7927/BT_RAM_CODE_MT%04x_2_%x_hdr.bin" , + dev_id &0xffff , (fw_ver &0xff ) +1 ); +else if (dev_id ==0x7925 )snprintf (buf, size,"mediatek/mt%04x/BT_RAM_CODE_MT%04x_1_%x_hdr.bin" , dev_id &0xffff , dev_id &0xffff , (fw_ver &0xff ) +1 );
@@ -128,7 +148,8 @@ void btmtk_fw_get_filename(char *buf, size_t size, u32 dev_id, u32 fw_ver,EXPORT_SYMBOL_GPL (btmtk_fw_get_filename);int btmtk_setup_firmware_79xx (struct hci_dev *hdev,const char *fwname, -wmt_cmd_sync_func_t wmt_cmd_sync) +wmt_cmd_sync_func_t wmt_cmd_sync, +u32 dev_id) {struct btmtk_hci_wmt_params wmt_params;struct btmtk_patch_header *hdr;
@@ -166,6 +187,14 @@ int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname, section_offset =le32_to_cpu (sectionmap->secoffset); dl_size =le32_to_cpu (sectionmap->bin_info_spec.dlsize); +/* MT6639: only download sections where dlmode byte0 == 0x01, +* matching the Windows driver behavior which skips WiFi/other +* sections that would cause the chip to hang. +*/ +if (dev_id ==0x6639 && dl_size >0 && + (le32_to_cpu (sectionmap->bin_info_spec.dlmodecrctype) &0xff ) !=0x01 ) +continue ; +if (dl_size >0 ) { retry =20 ;while (retry >0 ) {
@@ -847,7 +876,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)if (err <0 )return err;msleep (100 ); - }else if (dev_id ==0x7925 ) { + }else if (dev_id ==0x7925 || dev_id ==0x6639 ) { err =btmtk_usb_uhw_reg_read (hdev,MTK_BT_RESET_REG_CONNV3 , &val);if (err)return err;
@@ -933,7 +962,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id) } err =btmtk_usb_id_get (hdev,0x70010200 , &val); -if (err <0 || !val) +if (err <0 || (!val && dev_id !=0x6639 ))bt_dev_err (hdev,"Can't get device id, subsys reset fail." );return err;
@@ -1319,6 +1348,24 @@ int btmtk_usb_setup(struct hci_dev *hdev) fw_flavor = (fw_flavor &0x00000080 ) >>7 ; } +if (!dev_id) { +u16 vid =le16_to_cpu (btmtk_data->udev->descriptor.idVendor); +u16 pid =le16_to_cpu (btmtk_data->udev->descriptor.idProduct); +int i; + +for (i =0 ; i <ARRAY_SIZE (btmtk_mt6639_devs); i++) { +if (vid == btmtk_mt6639_devs[i].vendor && + pid == btmtk_mt6639_devs[i].product) { + dev_id =0x6639 ; +break ; + } + } + +if (dev_id) +bt_dev_info (hdev,"MT6639: CHIPID=0x0000 with VID=%04x PID=%04x, using 0x6639" , + vid, pid); + } + btmtk_data->dev_id = dev_id; err =btmtk_register_coredump (hdev, btmtk_data->drv_name, fw_version);
@@ -1336,11 +1383,13 @@ int btmtk_usb_setup(struct hci_dev *hdev)case 0x7925 :case 0x7961 :case 0x7902 : +case 0x6639 :btmtk_fw_get_filename (fw_bin_name,sizeof (fw_bin_name), dev_id, fw_version, fw_flavor); err =btmtk_setup_firmware_79xx (hdev, fw_bin_name, - btmtk_usb_hci_wmt_sync); + btmtk_usb_hci_wmt_sync, + dev_id);if (err <0 ) {bt_dev_err (hdev,"Failed to set up firmware (%d)" , err);return err;
@@ -1507,3 +1556,4 @@ MODULE_FIRMWARE(FIRMWARE_MT7668);MODULE_FIRMWARE (FIRMWARE_MT7922 );MODULE_FIRMWARE (FIRMWARE_MT7961 );MODULE_FIRMWARE (FIRMWARE_MT7925 ); +MODULE_FIRMWARE (FIRMWARE_MT7927 );
drivers/bluetooth/btmtk.h +5 -2
@@ -8,6 +8,7 @@#define FIRMWARE_MT7902 "mediatek/BT_RAM_CODE_MT7902_1_1_hdr.bin"#define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin"#define FIRMWARE_MT7925 "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin" +#define FIRMWARE_MT7927 "mediatek/mt7927/BT_RAM_CODE_MT6639_2_1_hdr.bin"#define HCI_EV_WMT 0xe4#define HCI_WMT_MAX_EVENT_SIZE 64
@@ -188,7 +189,8 @@ typedef int (*wmt_cmd_sync_func_t)(struct hci_dev *,int btmtk_set_bdaddr (struct hci_dev *hdev,const bdaddr_t *bdaddr);int btmtk_setup_firmware_79xx (struct hci_dev *hdev,const char *fwname, -wmt_cmd_sync_func_t wmt_cmd_sync); +wmt_cmd_sync_func_t wmt_cmd_sync, +u32 dev_id);int btmtk_setup_firmware (struct hci_dev *hdev,const char *fwname,wmt_cmd_sync_func_t wmt_cmd_sync);
@@ -227,7 +229,8 @@ static inline int btmtk_set_bdaddr(struct hci_dev *hdev,static inline int btmtk_setup_firmware_79xx (struct hci_dev *hdev,const char *fwname, -wmt_cmd_sync_func_t wmt_cmd_sync) +wmt_cmd_sync_func_t wmt_cmd_sync, +u32 dev_id) {return -EOPNOTSUPP ; }
drivers/bluetooth/btmtksdio.c +1 -1
@@ -884,7 +884,7 @@ static int mt79xx_setup(struct hci_dev *hdev, const char *fwname)u8 param =0x1 ;int err; - err =btmtk_setup_firmware_79xx (hdev, fwname, mtk_hci_wmt_sync); + err =btmtk_setup_firmware_79xx (hdev, fwname, mtk_hci_wmt_sync,0 );if (err <0 ) {bt_dev_err (hdev,"Failed to setup 79xx firmware (%d)" , err);return err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1278/1376 Bluetooth: btmtk: Fix short read errors in btmtk_usb_reg_read()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Greg Kroah-Hartman <[email protected]>
[ Upstream commit 0cc4b5649ae83deb8222100dba31aa0f100a19cd ]
If btmtk_usb_reg_read() gets a "short" read from a device, it will accidentally treat that as a "real" read and populate the returned value with some unknown and probably totally invalid data.
Fix this logic error up by calling usb_control_msg_recv() which guarantees a "full" read happens, and then simplify the error checking for when btmtk_usb_reg_read() is called (it's really just btmtk_usb_id_get() that calls btmtk_usb_reg_read(), so fix up those return sites.
Stable-dep-of: 59c3ee19ca88 ("Bluetooth: btmtk: Do not report success when subsys reset fails")
--- drivers/bluetooth/btmtk.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-)
drivers/bluetooth/btmtk.c +15 -21
@@ -815,27 +815,21 @@ static int btmtk_usb_uhw_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)static int btmtk_usb_reg_read (struct hci_dev *hdev,u32 reg,u32 *val) {struct btmtk_data *data =hci_get_priv (hdev); -int pipe, err, size =sizeof (u32); -void *buf; - - buf =kzalloc (size,GFP_KERNEL ); -if (!buf) -return -ENOMEM ; +u8 buf[sizeof (u32)]; +int err; - pipe =usb_rcvctrlpipe (data->udev,0 ); - err =usb_control_msg (data->udev, pipe,0x63 , -USB_TYPE_VENDOR |USB_DIR_IN , - reg >>16 , reg &0xffff , - buf, size,USB_CTRL_GET_TIMEOUT ); + *val =0 ; + err =usb_control_msg_recv (data->udev,0 ,0x63 , +USB_TYPE_VENDOR |USB_DIR_IN , + reg >>16 , reg &0xffff , + buf,sizeof (buf),USB_CTRL_GET_TIMEOUT , +GFP_KERNEL );if (err <0 ) - goto err_free_buf; +return err; *val =get_unaligned_le32 (buf); -err_free_buf: -kfree (buf); - -return err; +return 0 ; }static int btmtk_usb_id_get (struct hci_dev *hdev,u32 reg,u32 *id)
@@ -962,7 +956,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id) } err =btmtk_usb_id_get (hdev,0x70010200 , &val); -if (err <0 || (!val && dev_id !=0x6639 )) +if (err || (!val && dev_id !=0x6639 ))bt_dev_err (hdev,"Can't get device id, subsys reset fail." );return err;
@@ -1324,24 +1318,24 @@ int btmtk_usb_setup(struct hci_dev *hdev) calltime =ktime_get (); err =btmtk_usb_id_get (hdev,0x80000008 , &dev_id); -if (err <0 ) { +if (err) {bt_dev_err (hdev,"Failed to get device id (%d)" , err);return err; }if (!dev_id || dev_id !=0x7663 ) { err =btmtk_usb_id_get (hdev,0x70010200 , &dev_id); -if (err <0 ) { +if (err) {bt_dev_err (hdev,"Failed to get device id (%d)" , err);return err; } err =btmtk_usb_id_get (hdev,0x80021004 , &fw_version); -if (err <0 ) { +if (err) {bt_dev_err (hdev,"Failed to get fw version (%d)" , err);return err; } err =btmtk_usb_id_get (hdev,0x70010020 , &fw_flavor); -if (err <0 ) { +if (err) {bt_dev_err (hdev,"Failed to get fw flavor (%d)" , err);return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1279/1376 Bluetooth: btmtk: Do not report success when subsys reset fails
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ismail Tarim <[email protected]>
[ Upstream commit 59c3ee19ca88210bfc0e22ce59218091cb1a3c48 ]
btmtk_usb_subsys_reset() validates the subsystem reset by reading the chip id back. When that read succeeds at the bus level but yields an id of zero, the reset has demonstrably not taken effect: the function logs "Can't get device id, subsys reset fail." and then returns the return value of btmtk_usb_id_get(), which in that case is zero, i.e. success.
btusb_mtk_reset() returns that value unchanged, so its caller cannot tell a completed reset from a failed one.
Return -ENODEV when the chip id reads back as zero, leaving the existing MT6639 exemption intact.
Observed on an MT7902 [13d3:3579]. The path can be reached on demand by asking the controller for a coredump, since btmtk requests a reset once the dump completes:
# echo 1 > /sys/class/bluetooth/hci0/device/coredump
Bluetooth: hci0: Mediatek coredump end
Bluetooth: hci0: Can't get device id, subsys reset fail. usb 3-10: reset high-speed USB device number 5 using xhci_hcd usb 3-10: device descriptor read/64, error -110
usb usb3-port10: attempt power cycle
usb usb3-port10: unable to enumerate USB device
The same sequence occurs unprompted when the controller firmware asserts on its own.
Note that this corrects the error reporting only; it does not by itself make the controller recoverable in the case above.
--- drivers/bluetooth/btmtk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/bluetooth/btmtk.c +3 -1
@@ -956,8 +956,10 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id) } err =btmtk_usb_id_get (hdev,0x70010200 , &val); -if (err || (!val && dev_id !=0x6639 )) +if (err || (!val && dev_id !=0x6639 )) {bt_dev_err (hdev,"Can't get device id, subsys reset fail." ); +return err ? err : -ENODEV ; + }return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1280/1376 Bluetooth: btmtk: Do not discard the subsystem reset timeout
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ismail Tarim <[email protected]>
[ Upstream commit 21b50c24843b51f88ac4316dd470d2803da0c42f ]
When the MTK_BT_RST_DONE poll times out, btmtk_usb_subsys_reset() logs "Reset timeout" and keeps the error in err, but err is then overwritten by the return value of the following btmtk_usb_id_get() call, so the timeout is never reported to the caller.
Commit 25b6d7593a3a ("Bluetooth: btmtk: introduce btmtk reset work") discarded the return value of the chip id read, so the function returned the timeout error as intended. Commit 3dcb122b3064 ("Bluetooth: btusb:
mediatek: return error for failed reg access") started assigning err at that call and silently dropped it.
Keep the timeout in a separate variable and return it, restoring the original behaviour without changing the control flow.
--- drivers/bluetooth/btmtk.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/bluetooth/btmtk.c +5 -2
@@ -848,6 +848,7 @@ static u32 btmtk_usb_reset_done(struct hci_dev *hdev)int btmtk_usb_subsys_reset (struct hci_dev *hdev,u32 dev_id) { +int reset_err =0 ;u32 val;int err;
@@ -946,8 +947,10 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id) err =readx_poll_timeout (btmtk_usb_reset_done, hdev, val, val &MTK_BT_RST_DONE ,20000 ,1000000 ); -if (err <0 ) +if (err <0 ) {bt_dev_err (hdev,"Reset timeout" ); + reset_err = err; + }if (dev_id ==0x7922 ) { err =btmtk_usb_uhw_reg_write (hdev,MTK_UDMA_INT_STA_BT ,0x000000FF );
@@ -961,7 +964,7 @@ int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)return err ? err : -ENODEV ; } -return err; +return reset_err; }EXPORT_SYMBOL_GPL (btmtk_usb_subsys_reset);
Signature · 1 line
2.53.0