All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] params: fix charp corruption on allocation failure
  2026-07-28  8:55 [PATCH] params: fix charp corruption on allocation failure Jiacheng Yu
@ 2026-07-28  7:58 ` sashiko-bot
  2026-07-28 10:46 ` Petr Pavlu
  1 sibling, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-07-28  7:58 UTC (permalink / raw)
  To: Jiacheng Yu; +Cc: linux-modules

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Use-after-free window in param_set_charp due to freeing old parameter before updating the pointer.
--

--- Patch [1]: [PATCH] params: fix charp corruption on allocation failure ---
commit 0bae951c4e6e4a0145f488c9bedd9a7a2b9a129f
Author: Jiacheng Yu <yujiacheng3@huawei.com>

params: fix charp corruption on allocation failure

This commit fixes an issue in param_set_charp() where a failure to allocate
memory for a parameter update leaves the parameter set to NULL after its old
value has already been freed. It allocates and copies the new string into a
temporary variable first, replacing the actual parameter only after success.

> diff --git a/kernel/params.c b/kernel/params.c
> --- a/kernel/params.c
> +++ b/kernel/params.c
[ ... ]
> @@ -269,19 +270,20 @@ int param_set_charp(const char *val, const struct kernel_param *kp)
[ ... ]
>  	if (slab_is_available()) {
> -		*(char **)kp->arg = kmalloc_parameter(len + 1);
> -		if (!*(char **)kp->arg)
> +		tmp = kmalloc_parameter(len + 1);
> +		if (!tmp)
>  			return -ENOMEM;
> -		strcpy(*(char **)kp->arg, val);
> +		strscpy(tmp, val, len + 1);
>  	} else
> -		*(const char **)kp->arg = val;
> +		tmp = (char *)val;
> +
> +	maybe_kfree_parameter(*(char **)kp->arg);
> +	*(char **)kp->arg = tmp;

[Severity: High]
This is a pre-existing issue, but does freeing the old parameter before
updating the pointer create a use-after-free window?

By calling maybe_kfree_parameter() on the old value before assigning tmp to
the global kp->arg pointer, there is a brief window where kp->arg points to
freed memory. If another kernel subsystem locklessly reads this parameter
during this window, could it trigger a use-after-free dereference?

Since the patch rewrites this logic to use a temporary variable, would it
be safer to assign tmp to *(char **)kp->arg before calling
maybe_kfree_parameter() on the old string to ensure readers always see a
valid pointer?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260728085518.3865621-1-yujiacheng3@huawei.com?part=1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH] params: fix charp corruption on allocation failure
@ 2026-07-28  8:55 Jiacheng Yu
  2026-07-28  7:58 ` sashiko-bot
  2026-07-28 10:46 ` Petr Pavlu
  0 siblings, 2 replies; 5+ messages in thread
From: Jiacheng Yu @ 2026-07-28  8:55 UTC (permalink / raw)
  To: petr.pavlu
  Cc: samitolvanen, rusty, hannes, yosry, nphamcs, liuyongqiang13,
	linux-modules, linux-mm, linux-kernel, Jiacheng Yu, stable

param_set_charp() stores charp parameters in allocated memory after slab is
available, and releases the previous value when the parameter is updated.

The previous value is released before the replacement allocation succeeds.
If kmalloc_parameter() fails, the setter returns -ENOMEM with the parameter
left as NULL.

Failing zswap's compressor update before zswap is initialized can later
trigger:

  BUG: kernel NULL pointer dereference, address: 0000000000000000
  RIP: 0010:strcmp+0x10/0x30
  Call Trace:
    zswap_setup+0x3b1/0x490
    zswap_enabled_param_set+0x5b/0xa0
    param_attr_store+0x93/0xe0
    module_attr_store+0x1c/0x30
    kernfs_fop_write_iter+0x116/0x1f0

Allocate and copy the replacement first, then replace the parameter value
only after allocation succeeds.

Fixes: e180a6b7759a ("param: fix charp parameters set via sysfs")
Cc: stable@vger.kernel.org
Signed-off-by: Jiacheng Yu <yujiacheng3@huawei.com>
---
 kernel/params.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/kernel/params.c b/kernel/params.c
index a668863a4bb6..e4f2b71dde1e 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -261,6 +261,7 @@ EXPORT_SYMBOL_GPL(param_set_uint_minmax);
 
 int param_set_charp(const char *val, const struct kernel_param *kp)
 {
+	char *tmp;
 	size_t len, maxlen = 1024;
 
 	len = strnlen(val, maxlen + 1);
@@ -269,19 +270,20 @@ int param_set_charp(const char *val, const struct kernel_param *kp)
 		return -ENOSPC;
 	}
 
-	maybe_kfree_parameter(*(char **)kp->arg);
-
 	/*
 	 * This is a hack. We can't kmalloc() in early boot, and we
 	 * don't need to; this mangled commandline is preserved.
 	 */
 	if (slab_is_available()) {
-		*(char **)kp->arg = kmalloc_parameter(len + 1);
-		if (!*(char **)kp->arg)
+		tmp = kmalloc_parameter(len + 1);
+		if (!tmp)
 			return -ENOMEM;
-		strcpy(*(char **)kp->arg, val);
+		strscpy(tmp, val, len + 1);
 	} else
-		*(const char **)kp->arg = val;
+		tmp = (char *)val;
+
+	maybe_kfree_parameter(*(char **)kp->arg);
+	*(char **)kp->arg = tmp;
 
 	return 0;
 }
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH] params: fix charp corruption on allocation failure
  2026-07-28  8:55 [PATCH] params: fix charp corruption on allocation failure Jiacheng Yu
  2026-07-28  7:58 ` sashiko-bot
@ 2026-07-28 10:46 ` Petr Pavlu
  2026-07-28 12:22   ` Jiacheng Yu
  1 sibling, 1 reply; 5+ messages in thread
From: Petr Pavlu @ 2026-07-28 10:46 UTC (permalink / raw)
  To: Jiacheng Yu
  Cc: samitolvanen, rusty, hannes, yosry, nphamcs, liuyongqiang13,
	linux-modules, linux-mm, linux-kernel, stable

On 7/28/26 10:55 AM, Jiacheng Yu wrote:
> param_set_charp() stores charp parameters in allocated memory after slab is
> available, and releases the previous value when the parameter is updated.
> 
> The previous value is released before the replacement allocation succeeds.
> If kmalloc_parameter() fails, the setter returns -ENOMEM with the parameter
> left as NULL.
> 
> Failing zswap's compressor update before zswap is initialized can later
> trigger:
> 
>   BUG: kernel NULL pointer dereference, address: 0000000000000000
>   RIP: 0010:strcmp+0x10/0x30
>   Call Trace:
>     zswap_setup+0x3b1/0x490
>     zswap_enabled_param_set+0x5b/0xa0
>     param_attr_store+0x93/0xe0
>     module_attr_store+0x1c/0x30
>     kernfs_fop_write_iter+0x116/0x1f0
> 
> Allocate and copy the replacement first, then replace the parameter value
> only after allocation succeeds.
> 
> Fixes: e180a6b7759a ("param: fix charp parameters set via sysfs")
> Cc: stable@vger.kernel.org
> Signed-off-by: Jiacheng Yu <yujiacheng3@huawei.com>

It makes sense to me for param_set_charp() to have commit-or-rollback
semantics. The set callbacks of other standard parameters behave this
way, with the exception of array parameters.

> ---
>  kernel/params.c | 14 ++++++++------
>  1 file changed, 8 insertions(+), 6 deletions(-)
> 
> diff --git a/kernel/params.c b/kernel/params.c
> index a668863a4bb6..e4f2b71dde1e 100644
> --- a/kernel/params.c
> +++ b/kernel/params.c
> @@ -261,6 +261,7 @@ EXPORT_SYMBOL_GPL(param_set_uint_minmax);
>  
>  int param_set_charp(const char *val, const struct kernel_param *kp)
>  {
> +	char *tmp;
>  	size_t len, maxlen = 1024;
>  
>  	len = strnlen(val, maxlen + 1);
> @@ -269,19 +270,20 @@ int param_set_charp(const char *val, const struct kernel_param *kp)
>  		return -ENOSPC;
>  	}
>  
> -	maybe_kfree_parameter(*(char **)kp->arg);
> -
>  	/*
>  	 * This is a hack. We can't kmalloc() in early boot, and we
>  	 * don't need to; this mangled commandline is preserved.
>  	 */
>  	if (slab_is_available()) {
> -		*(char **)kp->arg = kmalloc_parameter(len + 1);
> -		if (!*(char **)kp->arg)
> +		tmp = kmalloc_parameter(len + 1);
> +		if (!tmp)
>  			return -ENOMEM;
> -		strcpy(*(char **)kp->arg, val);
> +		strscpy(tmp, val, len + 1);

What's wrong with the plain strcpy() here?

>  	} else
> -		*(const char **)kp->arg = val;
> +		tmp = (char *)val;
> +
> +	maybe_kfree_parameter(*(char **)kp->arg);
> +	*(char **)kp->arg = tmp;

Sashiko reports [1] that there is a pre-existing use-after-free window
between freeing the old parameter and updating kp->arg. However, this
issue doesn't appear to be valid because any concurrent access to
a writable charp parameter should be protected by kernel_param_lock().
This is documented include/linux/moduleparam.h [2].

>  
>  	return 0;
>  }

[1] https://lore.kernel.org/linux-modules/20260728075803.AA13C1F000E9@smtp.kernel.org/
[2] https://github.com/torvalds/linux/blob/v7.2-rc5/include/linux/moduleparam.h#L124

-- 
Thanks,
Petr


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] params: fix charp corruption on allocation failure
  2026-07-28 10:46 ` Petr Pavlu
@ 2026-07-28 12:22   ` Jiacheng Yu
  2026-07-28 12:57     ` Petr Pavlu
  0 siblings, 1 reply; 5+ messages in thread
From: Jiacheng Yu @ 2026-07-28 12:22 UTC (permalink / raw)
  To: Petr Pavlu
  Cc: samitolvanen, rusty, hannes, yosry, nphamcs, liuyongqiang13,
	linux-modules, linux-mm, linux-kernel, stable

On 28/07/2026 18:46, Petr Pavlu wrote:
> On 7/28/26 10:55 AM, Jiacheng Yu wrote:
>> param_set_charp() stores charp parameters in allocated memory after slab is
>> available, and releases the previous value when the parameter is updated.
>>
>> The previous value is released before the replacement allocation succeeds.
>> If kmalloc_parameter() fails, the setter returns -ENOMEM with the parameter
>> left as NULL.
>>
>> Failing zswap's compressor update before zswap is initialized can later
>> trigger:
>>
>>   BUG: kernel NULL pointer dereference, address: 0000000000000000
>>   RIP: 0010:strcmp+0x10/0x30
>>   Call Trace:
>>     zswap_setup+0x3b1/0x490
>>     zswap_enabled_param_set+0x5b/0xa0
>>     param_attr_store+0x93/0xe0
>>     module_attr_store+0x1c/0x30
>>     kernfs_fop_write_iter+0x116/0x1f0
>>
>> Allocate and copy the replacement first, then replace the parameter value
>> only after allocation succeeds.
>>
>> Fixes: e180a6b7759a ("param: fix charp parameters set via sysfs")
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Jiacheng Yu <yujiacheng3@huawei.com>
> 
> It makes sense to me for param_set_charp() to have commit-or-rollback
> semantics. The set callbacks of other standard parameters behave this
> way, with the exception of array parameters.

Thanks. That is the intent of this patch.

> 
>> ---
>>  kernel/params.c | 14 ++++++++------
>>  1 file changed, 8 insertions(+), 6 deletions(-)
>>
>> diff --git a/kernel/params.c b/kernel/params.c
>> index a668863a4bb6..e4f2b71dde1e 100644
>> --- a/kernel/params.c
>> +++ b/kernel/params.c
>> @@ -261,6 +261,7 @@ EXPORT_SYMBOL_GPL(param_set_uint_minmax);
>>  
>>  int param_set_charp(const char *val, const struct kernel_param *kp)
>>  {
>> +	char *tmp;
>>  	size_t len, maxlen = 1024;
>>  
>>  	len = strnlen(val, maxlen + 1);
>> @@ -269,19 +270,20 @@ int param_set_charp(const char *val, const struct kernel_param *kp)
>>  		return -ENOSPC;
>>  	}
>>  
>> -	maybe_kfree_parameter(*(char **)kp->arg);
>> -
>>  	/*
>>  	 * This is a hack. We can't kmalloc() in early boot, and we
>>  	 * don't need to; this mangled commandline is preserved.
>>  	 */
>>  	if (slab_is_available()) {
>> -		*(char **)kp->arg = kmalloc_parameter(len + 1);
>> -		if (!*(char **)kp->arg)
>> +		tmp = kmalloc_parameter(len + 1);
>> +		if (!tmp)
>>  			return -ENOMEM;
>> -		strcpy(*(char **)kp->arg, val);
>> +		strscpy(tmp, val, len + 1);
> 
> What's wrong with the plain strcpy() here?

Functionally, plain strcpy() is fine here.  The preceding
strnlen(val, maxlen + 1) either finds the NUL byte within the limit or
rejects the string, and the new allocation is exactly len + 1 bytes.

However, when this patch rewrites the line to use tmp,
checkpatch --strict reports the following warning:

    WARNING: Prefer strscpy over strcpy

Since the line is being rewritten anyway, I changed strcpy() to
strscpy() to follow that preference:
https://github.com/KSPP/linux/issues/88

> 
>>  	} else
>> -		*(const char **)kp->arg = val;
>> +		tmp = (char *)val;
>> +
>> +	maybe_kfree_parameter(*(char **)kp->arg);
>> +	*(char **)kp->arg = tmp;
> 
> Sashiko reports [1] that there is a pre-existing use-after-free window
> between freeing the old parameter and updating kp->arg. However, this
> issue doesn't appear to be valid because any concurrent access to
> a writable charp parameter should be protected by kernel_param_lock().
> This is documented include/linux/moduleparam.h [2].

I agree.  Writable charp parameters are expected to be protected by
kernel_param_lock(), and this patch does not change that locking model.

> 
>>  
>>  	return 0;
>>  }
> 
> [1] https://lore.kernel.org/linux-modules/20260728075803.AA13C1F000E9@smtp.kernel.org/
> [2] https://github.com/torvalds/linux/blob/v7.2-rc5/include/linux/moduleparam.h#L124
> 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] params: fix charp corruption on allocation failure
  2026-07-28 12:22   ` Jiacheng Yu
@ 2026-07-28 12:57     ` Petr Pavlu
  0 siblings, 0 replies; 5+ messages in thread
From: Petr Pavlu @ 2026-07-28 12:57 UTC (permalink / raw)
  To: Jiacheng Yu
  Cc: samitolvanen, rusty, hannes, yosry, nphamcs, liuyongqiang13,
	linux-modules, linux-mm, linux-kernel, stable

On 7/28/26 2:22 PM, Jiacheng Yu wrote:
> On 28/07/2026 18:46, Petr Pavlu wrote:
>> On 7/28/26 10:55 AM, Jiacheng Yu wrote:
>>> diff --git a/kernel/params.c b/kernel/params.c
>>> index a668863a4bb6..e4f2b71dde1e 100644
>>> --- a/kernel/params.c
>>> +++ b/kernel/params.c
>>> @@ -261,6 +261,7 @@ EXPORT_SYMBOL_GPL(param_set_uint_minmax);
>>>  
>>>  int param_set_charp(const char *val, const struct kernel_param *kp)
>>>  {
>>> +	char *tmp;
>>>  	size_t len, maxlen = 1024;
>>>  
>>>  	len = strnlen(val, maxlen + 1);
>>> @@ -269,19 +270,20 @@ int param_set_charp(const char *val, const struct kernel_param *kp)
>>>  		return -ENOSPC;
>>>  	}
>>>  
>>> -	maybe_kfree_parameter(*(char **)kp->arg);
>>> -
>>>  	/*
>>>  	 * This is a hack. We can't kmalloc() in early boot, and we
>>>  	 * don't need to; this mangled commandline is preserved.
>>>  	 */
>>>  	if (slab_is_available()) {
>>> -		*(char **)kp->arg = kmalloc_parameter(len + 1);
>>> -		if (!*(char **)kp->arg)
>>> +		tmp = kmalloc_parameter(len + 1);
>>> +		if (!tmp)
>>>  			return -ENOMEM;
>>> -		strcpy(*(char **)kp->arg, val);
>>> +		strscpy(tmp, val, len + 1);
>>
>> What's wrong with the plain strcpy() here?
> 
> Functionally, plain strcpy() is fine here.  The preceding
> strnlen(val, maxlen + 1) either finds the NUL byte within the limit or
> rejects the string, and the new allocation is exactly len + 1 bytes.
> 
> However, when this patch rewrites the line to use tmp,
> checkpatch --strict reports the following warning:
> 
>     WARNING: Prefer strscpy over strcpy
> 
> Since the line is being rewritten anyway, I changed strcpy() to
> strscpy() to follow that preference:
> https://github.com/KSPP/linux/issues/88

I don't see a benefit to using strscpy() here. The length of the string
is already known and the tmp buffer is correctly sized, so using
`memcpy(tmp, val, len + 1)` seems most appropriate to me.

-- 
Thanks,
Petr

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-07-28 12:57 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-28  8:55 [PATCH] params: fix charp corruption on allocation failure Jiacheng Yu
2026-07-28  7:58 ` sashiko-bot
2026-07-28 10:46 ` Petr Pavlu
2026-07-28 12:22   ` Jiacheng Yu
2026-07-28 12:57     ` Petr Pavlu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.