* Re: [PATCH] arm_pmu: acpi: fix reference leak on failed device registration
From: Johan Hovold @ 2026-04-20 7:28 UTC (permalink / raw)
To: Mark Rutland
Cc: Greg Kroah-Hartman, Guangshuo Li, Will Deacon, Anshuman Khandual,
linux-arm-kernel, linux-perf-users, linux-kernel, stable
In-Reply-To: <aeCsLy-45QyeCwGA@J2N7QTR9R3>
On Thu, Apr 16, 2026 at 10:30:23AM +0100, Mark Rutland wrote:
> On Thu, Apr 16, 2026 at 09:23:33AM +0200, Johan Hovold wrote:
> > It's not just the platform code as this directly reflects the behaviour
> > of device_register() as Mark pointed out.
> >
> > It is indeed an unfortunate quirk of the driver model, but one can argue
> > that having a registration function that frees its argument on errors
> > would be even worse. And even more so when many (or most) users get this
> > right.
>
> Ah, sorry; I had missed that the _put() step would actually free the
> object (and as you explain below, how that won't work for many callers).
>
> > So if we want to change this, I think we would need to deprecate
> > device_register() in favour of explicit device_initialize() and
> > device_add().
>
> Is is possible to have {platfom_,}device_uninitialize() functions that
> does everything except the ->release() call? If we had that, then we'd
> be able to have a flow along the lines of:
>
> int some_init_function(void)
> {
> int err;
>
> platform_device_init(&static_pdev);
>
> err = platform_device_add(&static_pdev))
> if (err)
> goto out_uninit;
>
> return 0;
>
> out_uninit:
> platform_device_uninit(&static_pdev);
> return err;
> }
>
> ... which I think would align with what people generally expect to have
> to do.
The issue here is that platform_device_add() allocates a device name and
such resources are not released until the last reference is dropped.
It's been this way since 2008, but some of the static platform devices
predates that and they both lack a release callback (explicitly required
since 2003) and are not cleaned up on registration failure.
Since registration would essentially only fail during development (e.g.
due to name collision or fault injection), this is hardly something to
worry about, but we could consider moving towards dynamic objects to
address both issues.
We have a few functions for allocating *and* registering platform
devices that could be used in many of these cases (and they already
clean up after themselves on errors):
platform_device_register_simple()
platform_device_register_data()
platform_device_register_resndata()
platform_device_register_full()
and where those do not fit (and cannot be extended) we have the
underlying:
platform_device_alloc()
platform_device_add_resources()
platform_device_add_data()
plaform_device_add()
But there are some 800 static platform devices left, mostly in legacy
platform code and board files that I assume few people care about.
Johan
^ permalink raw reply
* Re: [f2fs-dev] [PATCH] f2fs: fix node_cnt race between extent node destroy and writeback
From: Chao Yu @ 2026-04-20 7:28 UTC (permalink / raw)
To: Yongpeng Yang, Jaegeuk Kim; +Cc: chao, Yongpeng Yang, stable, linux-f2fs-devel
In-Reply-To: <a643b967-cb05-4de5-96f2-f1b783c9758d@sina.com>
On 4/19/2026 12:29 AM, Yongpeng Yang wrote:
>
> On 4/18/26 8:51 AM, Chao Yu via Linux-f2fs-devel wrote:
>> On 4/17/26 21:26, Yongpeng Yang wrote:
>>>
>>> On 4/17/26 17:00, Chao Yu via Linux-f2fs-devel wrote:
>>>> On 4/3/26 22:40, Yongpeng Yang wrote:
>>>>> From: Yongpeng Yang <yangyongpeng@xiaomi.com>
>>>>>
>>>>> f2fs_destroy_extent_node() does not set FI_NO_EXTENT before clearing
>>>>> extent nodes. When called from f2fs_drop_inode() with I_SYNC set,
>>>>> concurrent kworker writeback can insert new extent nodes into the same
>>>>> extent tree, racing with the destroy and triggering f2fs_bug_on() in
>>>>> __destroy_extent_node(). The scenario is as follows:
>>>>>
>>>>> drop inode writeback
>>>>> - iput
>>>>> - f2fs_drop_inode // I_SYNC set
>>>>> - f2fs_destroy_extent_node
>>>>> - __destroy_extent_node
>>>>> - while (node_cnt) {
>>>>> write_lock(&et->lock)
>>>>> __free_extent_tree
>>>>> write_unlock(&et->lock)
>>>>> - __writeback_single_inode
>>>>> - f2fs_outplace_write_data
>>>>> -
>>>>> f2fs_update_read_extent_cache
>>>>> -
>>>>> __update_extent_tree_range
>>>>> // FI_NO_EXTENT not set,
>>>>> // insert new extent node
>>>>> } // node_cnt == 0, exit while
>>>>> - f2fs_bug_on(node_cnt) // node_cnt > 0
>>>>>
>>>>> Additionally, __update_extent_tree_range() only checks FI_NO_EXTENT for
>>>>> EX_READ type, leaving EX_BLOCK_AGE updates completely unprotected.
>>>>>
>>>>> This patch set FI_NO_EXTENT under et->lock in __destroy_extent_node(),
>>>>> consistent with other callers (__update_extent_tree_range and
>>>>> __drop_extent_tree) and check FI_NO_EXTENT for both EX_READ and
>>>>> EX_BLOCK_AGE tree.
>>>>
>>>> I suffered below test failure, then I bisect to this change.
>>>>
>>>> generic/475 84s ... [failed, exit status 1]- output mismatch
>>>> (see /
>>>> share/git/fstests/results//generic/475.out.bad)
>>>> --- tests/generic/475.out 2025-01-12 21:57:40.279440664 +0800
>>>> +++ /share/git/fstests/results//generic/475.out.bad 2026-04-17
>>>> 12:08:28.000000000 +0800
>>>> @@ -1,2 +1,6 @@
>>>> QA output created by 475
>>>> Silence is golden.
>>>> +mount: /mnt/scratch_f2fs: mount system call failed: Structure
>>>> needs
>>>> cleaning.
>>>> + dmesg(1) may have more information after failed mount
>>>> system
>>>> call.
>>>> +mount failed
>>>> +(see /share/git/fstests/results//generic/475.full for details)
>>>> ...
>>>> (Run 'diff -u /share/git/fstests/tests/generic/475.out /share/git/
>>>> fstests/results//generic/475.out.bad' to see the entire diff)
>>>>
>>>>
>>>> generic/388 73s ... [failed, exit status 1]- output mismatch
>>>> (see /
>>>> share/git/fstests/results//generic/388.out.bad)
>>>> --- tests/generic/388.out 2025-01-12 21:57:40.275440602 +0800
>>>> +++ /share/git/fstests/results//generic/388.out.bad 2026-04-17
>>>> 11:58:05.000000000 +0800
>>>> @@ -1,2 +1,6 @@
>>>> QA output created by 388
>>>> Silence is golden.
>>>> +mount: /mnt/scratch_f2fs: mount system call failed: Structure
>>>> needs
>>>> cleaning.
>>>> + dmesg(1) may have more information after failed mount
>>>> system
>>>> call.
>>>> +cycle mount failed
>>>> +(see /share/git/fstests/results//generic/388.full for details)
>>>> ...
>>>> (Run 'diff -u /share/git/fstests/tests/generic/388.out /share/git/
>>>> fstests/results//generic/388.out.bad' to see the entire diff)
>>>>
>>>>
>>>> F2FS-fs (dm-0): sanity_check_extent_cache: inode (ino=1761) extent
>>>> info [220057, 57, 6] is incorrect, run fsck to fix
>>>>
>>>> I suspect we may miss any extent updates after we set FI_NO_EXTENT in
>>>> __destroy_extent_node(), result in failing in
>>>> sanity_check_extent_cache().
>>>>
>>>> Can we just relocate f2fs_bug_on(node_cnt) rather than complicated
>>>> change?
>>>> Thoughts?
>>>
>>> Oh, I overlooked largest extent. How about relocate
>>> f2fs_bug_on(node_cnt) to __destroy_extent_tree?
>>>
>>> static void __destroy_extent_tree(struct inode *inode, enum extent_type
>>> type)
>>>
>>> /* free all extent info belong to this extent tree */
>>> node_cnt = __destroy_extent_node(inode, type);
>>> + f2fs_bug_on(sbi, atomic_read(&et->node_cnt));
>>
>> /* free all extent info belong to this extent tree */
>> node_cnt = __destroy_extent_node(inode, type);
>>
>> /* delete extent tree entry in radix tree */
>> mutex_lock(&eti->extent_tree_lock);
>> f2fs_bug_on(sbi, atomic_read(&et->node_cnt)); <---
>>
>> Oh, it has already checked node_cnt, so, maybe we can just remove the
>> check in
>> __destroy_extent_node()?
>
> Yes. BTW, is it correct to remove the call to f2fs_destroy_extent_node()
> in f2fs_drop_inode()? It seems this call is unnecessary, since
> f2fs_evict_inode() will eventually delete all extent nodes properly.
I think it's fine to keep it according to original intention "destroy
extent_tree for the truncation case" introduced from 3e72f721390d
("f2fs: use extent_cache by default"). It helps the performance w/
in batch extent node release.
Thanks,
>
> Thanks
> Yongpeng,
>
>>
>> Thanks,
>>
>>
>>>
>>> Thanks
>>> Yongpeng,
>>>
>>>>
>>>> Thanks,
>>>>
>>>>>
>>>>> Fixes: 3fc5d5a182f6 ("f2fs: fix to shrink read extent node in batches")
>>>>> Cc: stable@vger.kernel.org
>>>>> Signed-off-by: Yongpeng Yang <yangyongpeng@xiaomi.com>
>>>>> ---
>>>>> fs/f2fs/extent_cache.c | 17 ++++++++++-------
>>>>> 1 file changed, 10 insertions(+), 7 deletions(-)
>>>>>
>>>>> diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c
>>>>> index 0ed84cc065a7..87169fd29d89 100644
>>>>> --- a/fs/f2fs/extent_cache.c
>>>>> +++ b/fs/f2fs/extent_cache.c
>>>>> @@ -119,9 +119,10 @@ static bool __may_extent_tree(struct inode
>>>>> *inode, enum extent_type type)
>>>>> if (!__init_may_extent_tree(inode, type))
>>>>> return false;
>>>>> + if (is_inode_flag_set(inode, FI_NO_EXTENT))
>>>>> + return false;
>>>>> +
>>>>> if (type == EX_READ) {
>>>>> - if (is_inode_flag_set(inode, FI_NO_EXTENT))
>>>>> - return false;
>>>>> if (is_inode_flag_set(inode, FI_COMPRESSED_FILE) &&
>>>>> !f2fs_sb_has_readonly(F2FS_I_SB(inode)))
>>>>> return false;
>>>>> @@ -644,6 +645,8 @@ static unsigned int __destroy_extent_node(struct
>>>>> inode *inode,
>>>>> while (atomic_read(&et->node_cnt)) {
>>>>> write_lock(&et->lock);
>>>>> + if (!is_inode_flag_set(inode, FI_NO_EXTENT))
>>>>> + set_inode_flag(inode, FI_NO_EXTENT);
>>>>> node_cnt += __free_extent_tree(sbi, et, nr_shrink);
>>>>> write_unlock(&et->lock);
>>>>> }
>>>>> @@ -688,12 +691,12 @@ static void __update_extent_tree_range(struct
>>>>> inode *inode,
>>>>> write_lock(&et->lock);
>>>>> - if (type == EX_READ) {
>>>>> - if (is_inode_flag_set(inode, FI_NO_EXTENT)) {
>>>>> - write_unlock(&et->lock);
>>>>> - return;
>>>>> - }
>>>>> + if (is_inode_flag_set(inode, FI_NO_EXTENT)) {
>>>>> + write_unlock(&et->lock);
>>>>> + return;
>>>>> + }
>>>>> + if (type == EX_READ) {
>>>>> prev = et->largest;
>>>>> dei.len = 0;
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> Linux-f2fs-devel mailing list
>>>> Linux-f2fs-devel@lists.sourceforge.net
>>>> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
>>>
>>
>>
>>
>> _______________________________________________
>> Linux-f2fs-devel mailing list
>> Linux-f2fs-devel@lists.sourceforge.net
>> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
>
^ permalink raw reply
* Re: [PATCH v2] gpu: host1x: Fix device reference leak in device_add() error path
From: Mikko Perttunen @ 2026-04-20 7:19 UTC (permalink / raw)
To: Thierry Reding, David Airlie, Simona Vetter, Guangshuo Li,
Vamsee Vardhan Thummala, linux-kernel, dri-devel, linux-tegra,
Guangshuo Li
Cc: stable
In-Reply-To: <20260413141328.2954939-1-lgs201920130244@gmail.com>
On Monday, April 13, 2026 11:13 PM Guangshuo Li wrote:
> After device_initialize(), the embedded struct device in struct
> host1x_device should be released through the device core with
> put_device().
>
> In host1x_device_add(), the empty-subdevice path calls
> device_add(&device->dev), but if that fails it only logs the error and
> continues without dropping the device reference. That leaks the
> reference held on the embedded struct device.
>
> The issue was identified by a static analysis tool I developed and
> confirmed by manual review.
>
> Fix this by removing the device from host1x->devices and calling
> put_device() when device_add() fails.
>
> Fixes: fab823d82ee50 ("gpu: host1x: Allow loading tegra-drm without enabled engines")
> Cc: stable@vger.kernel.org
> Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
> ---
> v2:
> - note that the issue was identified by my static analysis tool
> - and confirmed by manual review
>
> drivers/firmware/edd.c | 2 +-
> drivers/gpu/host1x/bus.c | 6 +++++-
> 2 files changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
> index 55dec4eb2c00..82b326ce83ce 100644
> --- a/drivers/firmware/edd.c
> +++ b/drivers/firmware/edd.c
> @@ -748,7 +748,7 @@ edd_init(void)
>
> rc = edd_device_register(edev, i);
> if (rc) {
> - kfree(edev);
> + kobject_put(&edev->kobj);
> goto out;
> }
> edd_devices[i] = edev;
Unrelated ..
> diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
> index 723a80895cd4..63fe037c3b65 100644
> --- a/drivers/gpu/host1x/bus.c
> +++ b/drivers/gpu/host1x/bus.c
> @@ -477,8 +477,12 @@ static int host1x_device_add(struct host1x *host1x,
> */
> if (list_empty(&device->subdevs)) {
> err = device_add(&device->dev);
> - if (err < 0)
> + if (err < 0) {
> dev_err(&device->dev, "failed to add device: %d\n", err);
> + list_del(&device->list);
> + put_device(&device->dev);
> + return err;
> + }
> else
> device->registered = true;
This isn't a leak -- if device_add fails, the device is still on the
device list, though in a "stuck" state, and will get cleaned up through
host1x_device_del.
Thanks
Mikko
> }
> --
> 2.43.0
>
>
^ permalink raw reply
* Re: [PATCH] drm/bridge: imx8qxp-pxl2dpi: avoid of_node_put() on ERR_PTR()
From: Liu Ying @ 2026-04-20 6:53 UTC (permalink / raw)
To: Guangshuo Li, Frank Li
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Luca Ceresoli, dri-devel,
imx, linux-arm-kernel, linux-kernel, stable
In-Reply-To: <CANUHTR8FaXLX+Nbeb7+sWRF9jQ5SoBgWc2y_LVD38KE7TqsxeQ@mail.gmail.com>
On Mon, Apr 20, 2026 at 10:19:35AM +0800, Guangshuo Li wrote:
> [You don't often get email from lgs201920130244@gmail.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>
> Hi Frank,
>
> Thanks for the review.
>
> On Mon, 20 Apr 2026 at 09:56, Frank Li <Frank.li@nxp.com> wrote:
>>
>>
>> Please fix
>> DEFINE_FREE(device_node, struct device_node *, if (_T) of_node_put(_T))
>>
>> If (!IS_ERR(_T))
>>
>
> You're right, fixing DEFINE_FREE(device_node, ...) is the proper way
> to handle this:
> if (_T && !IS_ERR(_T)) of_node_put(_T)
This would be intrusive because it effectively changes the cleanup action.
A similar case[1] was handled by ensuring only NULL pointer was returned
on error. And, this is actually what i2c_of_probe_get_i2c_node()[2] does
now.
[1] https://lore.kernel.org/all/Zw-VkQ3di5nFHiXB@smile.fi.intel.com/
[2] https://elixir.bootlin.com/linux/v7.0/source/drivers/i2c/i2c-core-of-prober.c#L38-L58
BTW, even if the cleanup action needs to be changed, the 'if' condition
should be '!IS_ERR_OR_NULL(_T)'.
>
> This is a better fix than handling it only in this driver.
>
> I'll rework the patch based on your suggestion and send v2 later.
>
> Thanks,
> Guangshuo
--
Regards,
Liu Ying
^ permalink raw reply
* [PATCH 05/38] crypto: drbg - Fix the fips_enabled priority boost
From: Eric Biggers @ 2026-04-20 6:33 UTC (permalink / raw)
To: linux-crypto, Herbert Xu
Cc: linux-kernel, Stephan Mueller, Jason A . Donenfeld, Eric Biggers,
stable
In-Reply-To: <20260420063422.324906-1-ebiggers@kernel.org>
When fips_enabled=1, it seems to have been intended for one of the
algorithms defined in crypto/drbg.c to be the highest priority "stdrng"
algorithm, so that it is what is used by "stdrng" users.
However, the code only boosts the priority to 400, which is less than
the priority 500 used in drivers/crypto/caam/caamprng.c. Thus, the CAAM
RNG could be used instead.
Fix this by boosting the priority by 2000 instead of 200.
Fixes: 541af946fe13 ("crypto: drbg - SP800-90A Deterministic Random Bit Generator")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
crypto/drbg.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crypto/drbg.c b/crypto/drbg.c
index f23b431bd490..e3065fb9541b 100644
--- a/crypto/drbg.c
+++ b/crypto/drbg.c
@@ -1830,11 +1830,11 @@ static inline void __init drbg_fill_array(struct rng_alg *alg,
* If FIPS mode enabled, the selected DRBG shall have the
* highest cra_priority over other stdrng instances to ensure
* it is selected.
*/
if (fips_enabled)
- alg->base.cra_priority += 200;
+ alg->base.cra_priority += 2000;
alg->base.cra_ctxsize = sizeof(struct drbg_state);
alg->base.cra_module = THIS_MODULE;
alg->base.cra_init = drbg_kcapi_init;
alg->base.cra_exit = drbg_kcapi_cleanup;
--
2.53.0
^ permalink raw reply related
* [PATCH 04/38] crypto: drbg - Fix drbg_max_addtl() on 64-bit kernels
From: Eric Biggers @ 2026-04-20 6:33 UTC (permalink / raw)
To: linux-crypto, Herbert Xu
Cc: linux-kernel, Stephan Mueller, Jason A . Donenfeld, Eric Biggers,
stable
In-Reply-To: <20260420063422.324906-1-ebiggers@kernel.org>
On 64-bit kernels, drbg_max_addtl() returns 2**35 bytes. That's too
large, for two reasons:
1. SP800-90A says the maximum limit is 2**35 *bits*, not 2**35 bytes.
So the implemented limit has confused bits and bytes.
2. When drbg_kcapi_hash() calls crypto_shash_update() on the additional
information string, the length is implicitly cast to 'unsigned int'.
That truncates the additional information string to U32_MAX bytes.
Fix the maximum additional information string length to always be
U32_MAX - 1, causing an error to be returned for any longer lengths.
Fixes: 541af946fe13 ("crypto: drbg - SP800-90A Deterministic Random Bit Generator")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
include/crypto/drbg.h | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/include/crypto/drbg.h b/include/crypto/drbg.h
index 2d42518cbdce..c11eaf757ed0 100644
--- a/include/crypto/drbg.h
+++ b/include/crypto/drbg.h
@@ -146,23 +146,19 @@ static inline size_t drbg_max_request_bytes(struct drbg_state *drbg)
{
/* SP800-90A requires the limit 2**19 bits, but we return bytes */
return (1 << 16);
}
+/*
+ * SP800-90A allows implementations to support additional info / personalization
+ * strings of up to 2**35 bits. Implementations can have a smaller maximum. We
+ * use 2**35 - 16 bits == U32_MAX - 1 bytes so that the max + 1 always fits in a
+ * size_t, allowing drbg_healthcheck_sanity() to verify its enforcement.
+ */
static inline size_t drbg_max_addtl(struct drbg_state *drbg)
{
- /* SP800-90A requires 2**35 bytes additional info str / pers str */
-#if (__BITS_PER_LONG == 32)
- /*
- * SP800-90A allows smaller maximum numbers to be returned -- we
- * return SIZE_MAX - 1 to allow the verification of the enforcement
- * of this value in drbg_healthcheck_sanity.
- */
- return (SIZE_MAX - 1);
-#else
- return (1UL<<35);
-#endif
+ return U32_MAX - 1;
}
static inline size_t drbg_max_requests(struct drbg_state *drbg)
{
/* SP800-90A requires 2**48 maximum requests before reseeding */
--
2.53.0
^ permalink raw reply related
* [PATCH 03/38] crypto: drbg - Fix ineffective sanity check
From: Eric Biggers @ 2026-04-20 6:33 UTC (permalink / raw)
To: linux-crypto, Herbert Xu
Cc: linux-kernel, Stephan Mueller, Jason A . Donenfeld, Eric Biggers,
stable
In-Reply-To: <20260420063422.324906-1-ebiggers@kernel.org>
Fix drbg_healthcheck_sanity() to correctly check the return value of
drbg_generate(). drbg_generate() returns 0 on success, or a negative
errno value on failure. drbg_healthcheck_sanity() incorrectly assumed
that it returned a positive value on success.
This didn't make the sanity check fail, but it made it ineffective.
Fixes: cde001e4c3c3 ("crypto: rng - RNGs must return 0 in success case")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
crypto/drbg.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/crypto/drbg.c b/crypto/drbg.c
index de4c69032155..f23b431bd490 100644
--- a/crypto/drbg.c
+++ b/crypto/drbg.c
@@ -1735,11 +1735,10 @@ static int drbg_kcapi_seed(struct crypto_rng *tfm,
* Note 2: There is no sensible way of testing the reseed counter
* enforcement, so skip it.
*/
static inline int __init drbg_healthcheck_sanity(void)
{
- int len = 0;
#define OUTBUFLEN 16
unsigned char buf[OUTBUFLEN];
struct drbg_state *drbg = NULL;
int ret;
int rc = -EFAULT;
@@ -1780,15 +1779,15 @@ static inline int __init drbg_healthcheck_sanity(void)
max_addtllen = drbg_max_addtl(drbg);
max_request_bytes = drbg_max_request_bytes(drbg);
drbg_string_fill(&addtl, buf, max_addtllen + 1);
/* overflow addtllen with additional info string */
- len = drbg_generate(drbg, buf, OUTBUFLEN, &addtl);
- BUG_ON(0 < len);
+ ret = drbg_generate(drbg, buf, OUTBUFLEN, &addtl);
+ BUG_ON(ret == 0);
/* overflow max_bits */
- len = drbg_generate(drbg, buf, (max_request_bytes + 1), NULL);
- BUG_ON(0 < len);
+ ret = drbg_generate(drbg, buf, max_request_bytes + 1, NULL);
+ BUG_ON(ret == 0);
/* overflow max addtllen with personalization string */
ret = drbg_seed(drbg, &addtl, false);
BUG_ON(0 == ret);
/* all tests passed */
--
2.53.0
^ permalink raw reply related
* [PATCH 02/38] crypto: drbg - Fix misaligned writes in CTR_DRBG and HASH_DRBG
From: Eric Biggers @ 2026-04-20 6:33 UTC (permalink / raw)
To: linux-crypto, Herbert Xu
Cc: linux-kernel, Stephan Mueller, Jason A . Donenfeld, Eric Biggers,
stable
In-Reply-To: <20260420063422.324906-1-ebiggers@kernel.org>
drbg_cpu_to_be32() is being used to do a plain write to a byte array,
which doesn't have any alignment guarantee. This can cause a misaligned
write. Replace it with the correct function, put_unaligned_be32().
Fixes: 72f3e00dd67e ("crypto: drbg - replace int2byte with cpu_to_be")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
crypto/df_sp80090a.c | 7 ++++---
crypto/drbg.c | 3 ++-
include/crypto/internal/drbg.h | 18 ------------------
3 files changed, 6 insertions(+), 22 deletions(-)
diff --git a/crypto/df_sp80090a.c b/crypto/df_sp80090a.c
index b8134be6f7ad..f4bb7be016e8 100644
--- a/crypto/df_sp80090a.c
+++ b/crypto/df_sp80090a.c
@@ -8,10 +8,11 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
+#include <linux/unaligned.h>
#include <crypto/aes.h>
#include <crypto/df_sp80090a.h>
#include <crypto/internal/drbg.h>
static void drbg_kcapi_sym(struct aes_enckey *aeskey, unsigned char *outval,
@@ -139,14 +140,14 @@ int crypto_drbg_ctr_df(struct aes_enckey *aeskey,
return -EINVAL;
/* 10.4.2 step 2 -- calculate the entire length of all input data */
list_for_each_entry(seed, seedlist, list)
inputlen += seed->len;
- drbg_cpu_to_be32(inputlen, &L_N[0]);
+ put_unaligned_be32(inputlen, &L_N[0]);
/* 10.4.2 step 3 */
- drbg_cpu_to_be32(bytes_to_return, &L_N[4]);
+ put_unaligned_be32(bytes_to_return, &L_N[4]);
/* 10.4.2 step 5: length is L_N, input_string, one byte, padding */
padlen = (inputlen + sizeof(L_N) + 1) % (blocklen_bytes);
/* wrap the padlen appropriately */
if (padlen)
@@ -173,11 +174,11 @@ int crypto_drbg_ctr_df(struct aes_enckey *aeskey,
/*
* 10.4.2 step 9.1 - the padding is implicit as the buffer
* holds zeros after allocation -- even the increment of i
* is irrelevant as the increment remains within length of i
*/
- drbg_cpu_to_be32(i, iv);
+ put_unaligned_be32(i, iv);
/* 10.4.2 step 9.2 -- BCC and concatenation with temp */
drbg_ctr_bcc(aeskey, temp + templen, K, &bcc_list,
blocklen_bytes, keylen);
/* 10.4.2 step 9.3 */
i++;
diff --git a/crypto/drbg.c b/crypto/drbg.c
index e4eb78ed222b..de4c69032155 100644
--- a/crypto/drbg.c
+++ b/crypto/drbg.c
@@ -101,10 +101,11 @@
#include <crypto/df_sp80090a.h>
#include <crypto/internal/cipher.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/string_choices.h>
+#include <linux/unaligned.h>
/***************************************************************
* Backend cipher definitions available to DRBG
***************************************************************/
@@ -599,11 +600,11 @@ static int drbg_hash_df(struct drbg_state *drbg,
unsigned char *tmp = drbg->scratchpad + drbg_statelen(drbg);
struct drbg_string data;
/* 10.4.1 step 3 */
input[0] = 1;
- drbg_cpu_to_be32((outlen * 8), &input[1]);
+ put_unaligned_be32(outlen * 8, &input[1]);
/* 10.4.1 step 4.1 -- concatenation of data for input into hash */
drbg_string_fill(&data, input, 5);
list_add(&data.list, entropylist);
diff --git a/include/crypto/internal/drbg.h b/include/crypto/internal/drbg.h
index 371e52dcee6c..b4e5ef0be602 100644
--- a/include/crypto/internal/drbg.h
+++ b/include/crypto/internal/drbg.h
@@ -7,28 +7,10 @@
*/
#ifndef _INTERNAL_DRBG_H
#define _INTERNAL_DRBG_H
-/*
- * Convert an integer into a byte representation of this integer.
- * The byte representation is big-endian
- *
- * @val value to be converted
- * @buf buffer holding the converted integer -- caller must ensure that
- * buffer size is at least 32 bit
- */
-static inline void drbg_cpu_to_be32(__u32 val, unsigned char *buf)
-{
- struct s {
- __be32 conv;
- };
- struct s *conversion = (struct s *)buf;
-
- conversion->conv = cpu_to_be32(val);
-}
-
/*
* Concatenation Helper and string operation helper
*
* SP800-90A requires the concatenation of different data. To avoid copying
* buffers around or allocate additional memory, the following data structure
--
2.53.0
^ permalink raw reply related
* [PATCH 01/38] crypto: drbg - Fix returning success on failure in CTR_DRBG
From: Eric Biggers @ 2026-04-20 6:33 UTC (permalink / raw)
To: linux-crypto, Herbert Xu
Cc: linux-kernel, Stephan Mueller, Jason A . Donenfeld, Eric Biggers,
stable
In-Reply-To: <20260420063422.324906-1-ebiggers@kernel.org>
drbg_ctr_generate() sometimes returns success when it fails, leaving the
output buffer uninitialized. Fix it.
Fixes: cde001e4c3c3 ("crypto: rng - RNGs must return 0 in success case")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
crypto/drbg.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crypto/drbg.c b/crypto/drbg.c
index 9204e6edb426..e4eb78ed222b 100644
--- a/crypto/drbg.c
+++ b/crypto/drbg.c
@@ -375,11 +375,11 @@ static int drbg_ctr_generate(struct drbg_state *drbg,
/* 10.2.1.5.2 step 2 */
if (addtl && !list_empty(addtl)) {
ret = drbg_ctr_update(drbg, addtl, 2);
if (ret)
- return 0;
+ return ret;
}
/* 10.2.1.5.2 step 4.1 */
ret = drbg_kcapi_sym_ctr(drbg, NULL, 0, buf, len);
if (ret)
base-commit: c1f49dea2b8f335813d3b348fd39117fb8efb428
--
2.53.0
^ permalink raw reply related
* Re: [REGRESSION] Return change in 6.12.80+ with volatile mounting
From: Chenglong Tang @ 2026-04-20 6:31 UTC (permalink / raw)
To: Amir Goldstein; +Cc: Derek Taylor, stable, regressions, Kevin Berry, overlayfs
In-Reply-To: <CAOQ4uxhUn6oCBuVJqZu+FcMx8XeAQHZbXFAGon4Xeg2SPLJW_A@mail.gmail.com>
Hi, Amir,
Thanks for looking into this! To answer your questions:
1. Production vs. Test Suite Impact
The immediate failure we encountered is in containerd's integration
test suite (TestImageVolumeCheckVolatileOption). The test explicitly
reads /proc/mounts and expects the exact string "volatile".
In default production, containerd passes the legacy "volatile" string
to the mount syscall, which your patch correctly handles under the
hood. So the standard "happy path" is not broken in production.
2. The purpose of WithTempMount() / RemoveVolatileOption
Containerd regularly makes temporary overlay mounts (e.g., for
unpacking layers). Because overlayfs rejects reusing upper/work dirs
from a volatile mount, containerd uses RemoveVolatileOption to strip
the volatile flag before these temporary mounts.
Currently, containerd's RemoveVolatileOption does an exact string
match for "volatile". While it works for the default path, there is a
production edge case: if a user explicitly configures their container
runtime to use the new "fsync=volatile" option, older containerd
binaries will fail to strip it, and the temporary mounts will be
rejected by the kernel.
Conclusion
While containerd could theoretically patch their code to accept
strings.Contains() or fsync=volatile going forward, there are many
existing containerd binaries in the wild. Given that this patch breaks
containerd's CI tests and introduces an edge case for
RemoveVolatileOption, it might be safest to fix ovl_show_options in
the kernel to continue outputting the legacy "volatile" string to
strictly guarantee backwards compatibility with userspace.
Thanks,
Chenglong
On Sat, Apr 18, 2026 at 8:40 AM Amir Goldstein <amir73il@gmail.com> wrote:
>
> On Sat, Apr 18, 2026 at 1:33 AM Chenglong Tang <chenglongtang@google.com> wrote:
> >
> > CC Amir,
> >
> > For example, containerd 2.2.0 uses `volatile` instead of `fsync=volatile`:
> > https://github.com/containerd/containerd/blob/main/core/mount/temp.go#L91C1-L92C1
> >
> > On Fri, Apr 17, 2026 at 3:41 PM Derek Taylor <ddtaylor@google.com> wrote:
> > >
> > > This change seems to have so far affected at least containerd in an
> > > issue reported here
> > > https://github.com/containerd/containerd/issues/13250.
> > >
> > > In stable versions 6.12.80+, commit
> > > 6c0cfbe020c0fcd2a544fcd2931fbc366ee3cd12 with the specific change
> > > being:
> > > [*] The mount option "volatile" is an alias to "fsync=volatile".
> > > In this scenario, code relying on checking "volatile" will now fail
> > > due to the return being "fsync=volatile".
> > >
> > > #regzbot introduced:v6.12.80
>
> Hi Chenglong,
>
> Thanks for the report.
>
> Is this problem in production containerd or in a test suite?
> I did not understand the purpose of WithTempMount().
>
> Is it possible to fix this function to use string.Contains() instead of
> exact match to the "volatile" mount option?
>
> If needed I can fix the kernel to show the legacy "volatile" option,
> but I would like to first understand how bad the impact of this regression
> is on real production workloads.
>
> Thanks,
> Amir.
^ permalink raw reply
* Re: [PATCH v2] dmaengine: Fix refcount leak in channel register error path
From: Frank Li @ 2026-04-20 6:23 UTC (permalink / raw)
To: Guangshuo Li; +Cc: Vinod Koul, Dave Jiang, dmaengine, linux-kernel, stable
In-Reply-To: <20260413135857.2898676-1-lgs201920130244@gmail.com>
On Mon, Apr 13, 2026 at 09:58:57PM +0800, Guangshuo Li wrote:
> After device_register(), the lifetime of the embedded struct device is
> expected to be managed through the device core reference counting.
>
> In __dma_async_device_channel_register(), if device_register() fails,
> the error path frees chan->dev directly instead of releasing the device
> reference with put_device(). This bypasses the normal device lifetime
> rules and may leave the reference count of the embedded struct device
> unbalanced, resulting in a refcount leak.
>
> The issue was identified by a static analysis tool I developed and
> confirmed by manual review.
I think it is meanless, no one reproduce this. Provide tools link if open
source. Or you descript how problem happen.
> diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
> index ca13cd39330b..6bb1212ae0e1 100644
> --- a/drivers/dma/dmaengine.c
> +++ b/drivers/dma/dmaengine.c
> @@ -1111,8 +1111,12 @@ static int __dma_async_device_channel_register(struct dma_device *device,
>
> err_out_ida:
> ida_free(&device->chan_ida, chan->chan_id);
> + put_device(&chan->dev->device);
> + chan->dev = NULL;
> + goto err_free_local;
avoid err path goto again
Frank
> err_free_dev:
> kfree(chan->dev);
> + chan->dev = NULL;
> err_free_local:
> free_percpu(chan->local);
> chan->local = NULL;
> --
> 2.43.0
>
^ permalink raw reply
* Re: [PATCH v2] drm/bridge: dw-hdmi-qp: Guard clear_audio_infoframe when PHY is down
From: Frank Zhang @ 2026-04-20 6:11 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: andrzej.hajda, neil.armstrong, rfoss, maarten.lankhorst, mripard,
tzimmermann, airlied, simona, detlev.casanova, cristian.ciocaltea,
Laurent.pinchart, jonas, jernej.skrabec, dri-devel, linux-kernel,
stable
In-Reply-To: <hdl63shkqubkvczlg7ryjah5psiqzrhu5llelzaetw7skbpujv@nyxgriryjxd5>
On 4/19/26 08:40, Dmitry Baryshkov wrote:
> On Sat, Apr 18, 2026 at 06:19:36PM +0800, Frank Zhang wrote:
>> The following panic was observed during system reboot:
>>
>> Kernel panic - not syncing: Asynchronous SError Interrupt
>> CPU: 7 UID: 1000 PID: 2637 Comm: pipewire ... 6.19.10-300.fc44.aarch64
>> Call trace:
>> ...
>> regmap_update_bits_base+0x5c/0x90
>> dw_hdmi_qp_bridge_clear_infoframe+0xb0/0x120 [dw_hdmi_qp]
>> drm_bridge_connector_clear_infoframe+0x28/0x48 [drm_display_helper]
>> ...
>> dw_hdmi_qp_audio_disable+0x24/0xb8 [dw_hdmi_qp]
>> drm_bridge_connector_audio_shutdown+0x30/0x60 [drm_display_helper]
>> drm_connector_hdmi_audio_shutdown+0x24/0x38 [drm_display_helper]
>> hdmi_codec_shutdown+0x60/0x90 [snd_soc_hdmi_codec]
>> ...
>> snd_pcm_release_substream.part.0+0x44/0xd8 [snd_pcm]
>> snd_pcm_release+0x60/0xe8 [snd_pcm]
>> ...
>>
>> The root cause is pipewire tries to close the HDMI audio device after
>> atomic_disable(), which sets tmds_char_rate to 0 and disable the PHY.
>>
>> In this case, dw_hdmi_qp_audio_disable() will call
>> drm_atomic_helper_connector_hdmi_clear_audio_infoframe() directly,
>> accessing registers without checking tmds_char_rate.
>>
>> Move drm_atomic_helper_connector_hdmi_clear_audio_infoframe() inside the
>> if (hdmi->tmds_char_rate) of dw_hdmi_qp_audio_disable().
>>
>> Fixes: fd0141d1a8a2 ("drm/bridge: synopsys: Add audio support for dw-hdmi-qp")
>> Signed-off-by: Frank Zhang <rmxpzlb@gmail.com>
>>
>> ---
>> Changes in v2:
>> - Move drm_atomic_helper_connector_hdmi_clear_audio_infoframe() inside
>> the if (hdmi->tmds_char_rate) of dw_hdmi_qp_audio_disable().
>> - Link to v1: https://lore.kernel.org/all/20260416093150.13853-1-rmxpzlb@gmail.com/
>>
>> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
>> index d649a1cf07f5..7760527484c8 100644
>> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
>> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
>> @@ -526,10 +526,10 @@ static void dw_hdmi_qp_audio_disable(struct drm_bridge *bridge,
>> {
>> struct dw_hdmi_qp *hdmi = dw_hdmi_qp_from_bridge(bridge);
>>
>> - drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector);
>> -
>> - if (hdmi->tmds_char_rate)
>> + if (hdmi->tmds_char_rate) {
>> + drm_atomic_helper_connector_hdmi_clear_audio_infoframe(connector);
>> dw_hdmi_qp_audio_disable_regs(hdmi);
>> + }
>
> Will audio and audio infoframe remain disabled after consequetive
> atomic_enable() call?
>
>> }
>>
>> static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi,
>> --
>> 2.53.0
>>
>
Sorry, I missed clearing the audio infoframe when the PHY is down. The
next atomic_enable() will write the stale audio infoframe. My mistake.
To clear the stale audio infoframe, dw_hdmi_qp_audio_disable() can
handle it in the else branch directly, but this seems like a layering
violation for a bridge driver
I think the better approach is to add a 'reset_audio_infoframe'
interface in drm_hdmi_state_helper.c that does basically the same as
drm_atomic_helper_connector_hdmi_clear_audio_infoframe(), but only
clearing the software state without calling clear_infoframe(). It's also
a bit odd since it would only be used by dw-hdmi-qp.
I'd like to get the maintainers' opinion about adding such an interface.
Thanks,
Frank Zhang
^ permalink raw reply
* [PATCH] media: pvrusb2: fix disconnect and teardown races
From: Sangyun Kim @ 2026-04-20 6:06 UTC (permalink / raw)
To: Mike Isely, Mauro Carvalho Chehab, Hans Verkuil,
Edward Adam Davis
Cc: linux-media, linux-kernel, stable
pvr2_context_disconnect() queues a notification to the pvrusb2-context
kthread before it stores mp->disconnect_flag:
pvr2_hdw_disconnect(mp->hdw);
if (!pvr2_context_shutok())
pvr2_context_notify(mp);
mp->disconnect_flag = !0;
The context thread only destroys a context when disconnect_flag is set
and mc_first is NULL. If the notification wakes the thread before the
flag store becomes visible, the thread dequeues the context, runs
pvr2_context_check() with disconnect_flag still observed as 0, decides
that the destroy condition is not met yet, and goes back to sleep.
Nothing wakes the thread again once the flag is finally stored, so the
context stays on the global exist list forever and
pvr2_context_global_done() blocks module unload. commit 0a0b79ea55de
("media: pvrusb2: fix uaf in pvr2_context_set_notify") made this
liveness failure easier to hit by moving the notify earlier in the
disconnect path.
The same teardown sequence still contains a use-after-free.
pvr2_context_exit() inspects disconnect_flag after releasing mp->mutex
and may then call pvr2_context_notify(mp) after the context thread has
already freed the object via pvr2_context_destroy()/kfree(). The hdw
completion callback registered through pvr2_hdw_initialize() can race
the same way. Reordering the disconnect path alone closes the unload
hang, but it still leaves late notifiers able to touch freed memory.
Fix both problems together:
- Split pvr2_context_set_notify() into a locked helper
(pvr2_context_set_notify_locked()) and a wrapper that acquires
pvr2_context_mutex. This lets callers update several pieces of
related state inside a single critical section without relocking.
- In pvr2_context_disconnect(), set disconnect_flag and enqueue the
thread notification under pvr2_context_mutex. The context thread
manipulates the notify list under the same mutex, so when it observes
the queued entry it is guaranteed to observe disconnect_flag = 1 as
well and the destroy condition evaluates correctly. This eliminates
the original notify-before-flag liveness hole.
- Add a per-context refcount_t. pvr2_context_create() initialises it to
1 (creator reference). pvr2_channel_init() and pvr2_channel_done()
take and drop a reference around each channel's lifetime.
pvr2_context_disconnect() takes a temporary reference across its body
so the context cannot be freed while disconnect is still touching it.
pvr2_context_destroy() no longer calls kfree() directly; it drops its
reference via pvr2_context_put(), and whichever caller drops the last
reference performs the actual kfree. This keeps the object alive
until disconnect and the final channel teardown finish, regardless of
how the context thread, channel close, and USB disconnect paths
interleave.
- Add a destroying_flag that pvr2_context_destroy() sets under
pvr2_context_mutex before unlinking the context from the notify and
exist lists. pvr2_context_set_notify_locked() refuses to re-enqueue a
context whose destroying_flag is set, so a late notifier arriving
after destroy has started cannot resurrect the context on the notify
list. The dequeue path (fl == 0) still proceeds unconditionally
because destroy itself must be able to remove any still-queued entry.
- Update pvr2_context_exit() to enqueue through
pvr2_context_set_notify_locked() after releasing mp->mutex. The
caller (channel close or disconnect) always holds a reference, so the
object is stable across the mp->mutex / pvr2_context_mutex hand-off
and a concurrent destroy cannot free it under us. If destroy has
already won the race, destroying_flag short-circuits the enqueue into
a no-op.
Lock ordering: pvr2_context_mutex is only acquired after mp->mutex is
released; no path holds pvr2_context_mutex while acquiring mp->mutex,
so no AB/BA deadlock is introduced. wake_up() on
pvr2_context_sync_data is moved outside pvr2_context_mutex in every
path that grew a new locked section, matching the existing style.
Fixes: 0a0b79ea55de ("media: pvrusb2: fix uaf in pvr2_context_set_notify")
Cc: stable@vger.kernel.org
Signed-off-by: Sangyun Kim <sangyun.kim@snu.ac.kr>
---
drivers/media/usb/pvrusb2/pvrusb2-context.c | 56 ++++++++++++++++++---
drivers/media/usb/pvrusb2/pvrusb2-context.h | 3 ++
2 files changed, 51 insertions(+), 8 deletions(-)
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.c b/drivers/media/usb/pvrusb2/pvrusb2-context.c
index 93f5da65ead9..fb9bdbf5c886 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-context.c
@@ -27,11 +27,19 @@ static int pvr2_context_cleaned_flag;
static struct task_struct *pvr2_context_thread_ptr;
-static void pvr2_context_set_notify(struct pvr2_context *mp, int fl)
+static void pvr2_context_put(struct pvr2_context *mp)
+{
+ if (refcount_dec_and_test(&mp->refcount))
+ kfree(mp);
+}
+
+static int pvr2_context_set_notify_locked(struct pvr2_context *mp, int fl)
{
int signal_flag = 0;
- mutex_lock(&pvr2_context_mutex);
+
if (fl) {
+ if (mp->destroying_flag)
+ return 0;
if (!mp->notify_flag) {
signal_flag = (pvr2_context_notify_first == NULL);
mp->notify_prev = pvr2_context_notify_last;
@@ -59,6 +67,15 @@ static void pvr2_context_set_notify(struct pvr2_context *mp, int fl)
}
}
}
+ return signal_flag;
+}
+
+static void pvr2_context_set_notify(struct pvr2_context *mp, int fl)
+{
+ int signal_flag = 0;
+
+ mutex_lock(&pvr2_context_mutex);
+ signal_flag = pvr2_context_set_notify_locked(mp, fl);
mutex_unlock(&pvr2_context_mutex);
if (signal_flag) wake_up(&pvr2_context_sync_data);
}
@@ -66,10 +83,13 @@ static void pvr2_context_set_notify(struct pvr2_context *mp, int fl)
static void pvr2_context_destroy(struct pvr2_context *mp)
{
+ int signal_flag = 0;
+
pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp);
pvr2_hdw_destroy(mp->hdw);
- pvr2_context_set_notify(mp, 0);
mutex_lock(&pvr2_context_mutex);
+ mp->destroying_flag = !0;
+ pvr2_context_set_notify_locked(mp, 0);
if (mp->exist_next) {
mp->exist_next->exist_prev = mp->exist_prev;
} else {
@@ -83,10 +103,12 @@ static void pvr2_context_destroy(struct pvr2_context *mp)
if (!pvr2_context_exist_first) {
/* Trigger wakeup on control thread in case it is waiting
for an exit condition. */
- wake_up(&pvr2_context_sync_data);
+ signal_flag = !0;
}
mutex_unlock(&pvr2_context_mutex);
- kfree(mp);
+ if (signal_flag)
+ wake_up(&pvr2_context_sync_data);
+ pvr2_context_put(mp);
}
@@ -209,6 +231,7 @@ struct pvr2_context *pvr2_context_create(
pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (create)",mp);
mp->setup_func = setup_func;
mutex_init(&mp->mutex);
+ refcount_set(&mp->refcount, 1);
mutex_lock(&pvr2_context_mutex);
mp->exist_prev = pvr2_context_exist_last;
mp->exist_next = NULL;
@@ -256,25 +279,41 @@ static void pvr2_context_enter(struct pvr2_context *mp)
static void pvr2_context_exit(struct pvr2_context *mp)
{
int destroy_flag = 0;
+ int signal_flag = 0;
if (!(mp->mc_first || !mp->disconnect_flag)) {
destroy_flag = !0;
}
mutex_unlock(&mp->mutex);
- if (destroy_flag) pvr2_context_notify(mp);
+ if (destroy_flag) {
+ mutex_lock(&pvr2_context_mutex);
+ signal_flag = pvr2_context_set_notify_locked(mp, !0);
+ mutex_unlock(&pvr2_context_mutex);
+ if (signal_flag)
+ wake_up(&pvr2_context_sync_data);
+ }
}
void pvr2_context_disconnect(struct pvr2_context *mp)
{
+ int signal_flag = 0;
+
+ refcount_inc(&mp->refcount);
pvr2_hdw_disconnect(mp->hdw);
- if (!pvr2_context_shutok())
- pvr2_context_notify(mp);
+ mutex_lock(&pvr2_context_mutex);
mp->disconnect_flag = !0;
+ if (!pvr2_context_shutok())
+ signal_flag = pvr2_context_set_notify_locked(mp, !0);
+ mutex_unlock(&pvr2_context_mutex);
+ if (signal_flag)
+ wake_up(&pvr2_context_sync_data);
+ pvr2_context_put(mp);
}
void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
{
+ refcount_inc(&mp->refcount);
pvr2_context_enter(mp);
cp->hdw = mp->hdw;
cp->mc_head = mp;
@@ -318,6 +357,7 @@ void pvr2_channel_done(struct pvr2_channel *cp)
}
cp->hdw = NULL;
pvr2_context_exit(mp);
+ pvr2_context_put(mp);
}
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.h b/drivers/media/usb/pvrusb2/pvrusb2-context.h
index 5840b2ce8f1e..4e06530eccb8 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-context.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-context.h
@@ -7,6 +7,7 @@
#define __PVRUSB2_CONTEXT_H
#include <linux/mutex.h>
+#include <linux/refcount.h>
#include <linux/usb.h>
#include <linux/workqueue.h>
@@ -33,9 +34,11 @@ struct pvr2_context {
struct pvr2_hdw *hdw;
struct pvr2_context_stream video_stream;
struct mutex mutex;
+ refcount_t refcount;
int notify_flag;
int initialized_flag;
int disconnect_flag;
+ int destroying_flag;
/* Called after pvr2_context initialization is complete */
void (*setup_func)(struct pvr2_context *);
--
2.34.1
^ permalink raw reply related
* Re: [PATCH] dmaengine: idxd: Fix saved engines array leak in config save
From: Frank Li @ 2026-04-20 5:59 UTC (permalink / raw)
To: Guangshuo Li
Cc: Vinicius Costa Gomes, Dave Jiang, Vinod Koul, Frank Li,
Fenghua Yu, dmaengine, linux-kernel, stable
In-Reply-To: <20260419140839.99672-1-lgs201920130244@gmail.com>
On Sun, Apr 19, 2026 at 10:08:39PM +0800, Guangshuo Li wrote:
> idxd_device_config_save() uses cleanup.h helpers for temporary
> allocations while saving device configuration. The saved_groups and
> saved_wqs pointer arrays are declared with __free(kfree), and ownership
> is transferred to idxd_saved with no_free_ptr() on the success path.
>
> The saved_engines pointer array follows the same ownership pattern on the
> success path, but it is not declared with __free(kfree). As a result, if
> an error happens after saved_engines is allocated, idxd_free_saved()
> frees the saved engine objects but not the saved_engines array itself.
>
> This leaks saved_engines on error paths such as:
> - failure to allocate an individual saved engine
> - failure to allocate saved_wq_enable_map
> - failure to allocate saved_wqs
> - failure to allocate an individual saved WQ
>
> Declare saved_engines with __free(kfree) so the array is released
> automatically on failure, matching saved_groups and saved_wqs. The success
> path is unchanged because ownership is already transferred with
> no_free_ptr().
>
> Fixes: 6078a315aec1 ("dmaengine: idxd: Add idxd_device_config_save() and idxd_device_config_restore() helpers")
> Cc: stable@vger.kernel.org
> Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
> ---
> drivers/dma/idxd/init.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
> index f1cfc7790d95..02210f16d391 100644
> --- a/drivers/dma/idxd/init.c
> +++ b/drivers/dma/idxd/init.c
> @@ -880,7 +880,7 @@ static int idxd_device_config_save(struct idxd_device *idxd,
> saved_groups[i] = no_free_ptr(saved_group);
> }
>
> - struct idxd_engine **saved_engines =
> + struct idxd_engine **saved_engines __free(kfree) =
> kcalloc_node(idxd->max_engines,
> sizeof(struct idxd_engine *),
> GFP_KERNEL, dev_to_node(dev));
The follow code have problem.
saved_engines[i] = no_free_ptr(saved_engine);
if (...)
return -ENOMEM;
there should not have an error branch after no_free_ptr(), you mix to use
manual and auto alloc()/free(), which may cause hidden problem.
Frank
> --
> 2.43.0
>
^ permalink raw reply
* Re: [PATCH v3] gpu: host1x: Fix device reference leak in host1x_device_parse_dt() error path
From: Mikko Perttunen @ 2026-04-20 5:51 UTC (permalink / raw)
To: Thierry Reding, David Airlie, Simona Vetter, Mark Zhang,
Sean Paul, dri-devel, linux-tegra, linux-kernel, Guangshuo Li
Cc: Guangshuo Li, stable
In-Reply-To: <20260413141526.2961841-1-lgs201920130244@gmail.com>
On Monday, April 13, 2026 11:15 PM Guangshuo Li wrote:
> After device_initialize(), the embedded struct device in struct
> host1x_device should be released through the device core with
> put_device().
>
> In host1x_device_add(), if host1x_device_parse_dt() fails, the current
> error path frees the object directly with kfree(device). That bypasses
> the normal device lifetime handling and leaks the reference held on the
> embedded struct device.
>
> The issue was identified by a static analysis tool I developed and
> confirmed by manual review.
>
> Fix this by using put_device() in the host1x_device_parse_dt() failure
> path.
>
> Fixes: f4c5cf88fbd50 ("gpu: host1x: Provide a proper struct bus_type")
> Cc: stable@vger.kernel.org
> Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
> ---
> v3:
> - note that the issue was identified by my static analysis tool
> - and confirmed by manual review
>
> v2:
> - add Cc: stable@vger.kernel.org
>
> drivers/gpu/host1x/bus.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
> index 63fe037c3b65..e3ac85848aec 100644
> --- a/drivers/gpu/host1x/bus.c
> +++ b/drivers/gpu/host1x/bus.c
> @@ -452,7 +452,7 @@ static int host1x_device_add(struct host1x *host1x,
>
> err = host1x_device_parse_dt(device, driver);
> if (err < 0) {
> - kfree(device);
> + put_device(&device->dev);
> return err;
> }
>
> --
> 2.43.0
>
>
Thanks!
Acked-by: Mikko Perttunen <mperttunen@nvidia.com>
^ permalink raw reply
* Re: [PATCH net] net: mctp: fix don't require received header reserved bits to be zero
From: Jeremy Kerr @ 2026-04-20 5:41 UTC (permalink / raw)
To: wit_yuan
Cc: yuanzm2, matt, davem, edumazet, kuba, pabeni, netdev,
linux-kernel, stable
In-Reply-To: <20260417141340.5306-1-yuanzhaoming901030@126.com>
Hi,
> From the MCTP Base specification (DSP0236 v1.2.1), the first byte of
> the MCTP header contains a 4 bit reserved field, and 4 bit version.
>
> On our current receive path, we require those 4 reserved bits to be
> zero, but the 9500-8i card is non-conformant, and may set these
> reserved bits.
>
> DSP0236 states that the reserved bits must be written as zero, and
> ignored when read. While the device might not conform to the former,
> we should accept these message to conform to the latter.
>
> Relax our check on the MCTP version byte to allow non-zero bits in the
> reserved field.
>
> Fixes: 889b7da23abf ("mctp: Add initial routing framework")
> Signed-off-by: Yuan Zhaoming <yuanzm2@lenovo.com>
Looks good, thanks for the contribution!
Acked-by: Jeremy Kerr <jk@codeconstruct.com.au>
Cheers,
Jeremy
^ permalink raw reply
* [PATCH 5.10.y] ipv6: add NULL checks for idev in SRv6 paths
From: Li hongliang @ 2026-04-20 5:43 UTC (permalink / raw)
To: gregkh, stable, heminhong
Cc: patches, linux-kernel, davem, dsahern, edumazet, kuba, pabeni,
horms, david.lebrun, netdev, andrea.mayer
From: Minhong He <heminhong@kylinos.cn>
[ Upstream commit 06413793526251870e20402c39930804f14d59c0 ]
__in6_dev_get() can return NULL when the device has no IPv6 configuration
(e.g. MTU < IPV6_MIN_MTU or after NETDEV_UNREGISTER).
Add NULL checks for idev returned by __in6_dev_get() in both
seg6_hmac_validate_skb() and ipv6_srh_rcv() to prevent potential NULL
pointer dereferences.
Fixes: 1ababeba4a21 ("ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header)")
Fixes: bf355b8d2c30 ("ipv6: sr: add core files for SR HMAC support")
Signed-off-by: Minhong He <heminhong@kylinos.cn>
Reviewed-by: Andrea Mayer <andrea.mayer@uniroma2.it>
Link: https://patch.msgid.link/20260316073301.106643-1-heminhong@kylinos.cn
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Li hongliang <1468888505@139.com>
---
net/ipv6/exthdrs.c | 4 ++++
net/ipv6/seg6_hmac.c | 2 ++
2 files changed, 6 insertions(+)
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index cdad9019c77c..dfa0fb3d6c35 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -361,6 +361,10 @@ static int ipv6_srh_rcv(struct sk_buff *skb)
hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
idev = __in6_dev_get(skb->dev);
+ if (!idev) {
+ kfree_skb(skb);
+ return -1;
+ }
accept_seg6 = net->ipv6.devconf_all->seg6_enabled;
if (accept_seg6 > idev->cnf.seg6_enabled)
diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c
index f82fcd8908e1..b52985c867c2 100644
--- a/net/ipv6/seg6_hmac.c
+++ b/net/ipv6/seg6_hmac.c
@@ -245,6 +245,8 @@ bool seg6_hmac_validate_skb(struct sk_buff *skb)
struct inet6_dev *idev;
idev = __in6_dev_get(skb->dev);
+ if (!idev)
+ return false;
srh = (struct ipv6_sr_hdr *)skb_transport_header(skb);
--
2.34.1
^ permalink raw reply related
* [PATCH 5.15.y] ipv6: add NULL checks for idev in SRv6 paths
From: Li hongliang @ 2026-04-20 5:43 UTC (permalink / raw)
To: gregkh, stable, heminhong
Cc: patches, linux-kernel, davem, dsahern, edumazet, kuba, pabeni,
horms, david.lebrun, netdev, andrea.mayer
From: Minhong He <heminhong@kylinos.cn>
[ Upstream commit 06413793526251870e20402c39930804f14d59c0 ]
__in6_dev_get() can return NULL when the device has no IPv6 configuration
(e.g. MTU < IPV6_MIN_MTU or after NETDEV_UNREGISTER).
Add NULL checks for idev returned by __in6_dev_get() in both
seg6_hmac_validate_skb() and ipv6_srh_rcv() to prevent potential NULL
pointer dereferences.
Fixes: 1ababeba4a21 ("ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header)")
Fixes: bf355b8d2c30 ("ipv6: sr: add core files for SR HMAC support")
Signed-off-by: Minhong He <heminhong@kylinos.cn>
Reviewed-by: Andrea Mayer <andrea.mayer@uniroma2.it>
Link: https://patch.msgid.link/20260316073301.106643-1-heminhong@kylinos.cn
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Li hongliang <1468888505@139.com>
---
net/ipv6/exthdrs.c | 4 ++++
net/ipv6/seg6_hmac.c | 2 ++
2 files changed, 6 insertions(+)
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 10772dab66bb..3d249c10e3e9 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -373,6 +373,10 @@ static int ipv6_srh_rcv(struct sk_buff *skb)
hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
idev = __in6_dev_get(skb->dev);
+ if (!idev) {
+ kfree_skb(skb);
+ return -1;
+ }
accept_seg6 = net->ipv6.devconf_all->seg6_enabled;
if (accept_seg6 > idev->cnf.seg6_enabled)
diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c
index 7e3a85769932..68acff337e41 100644
--- a/net/ipv6/seg6_hmac.c
+++ b/net/ipv6/seg6_hmac.c
@@ -244,6 +244,8 @@ bool seg6_hmac_validate_skb(struct sk_buff *skb)
struct inet6_dev *idev;
idev = __in6_dev_get(skb->dev);
+ if (!idev)
+ return false;
srh = (struct ipv6_sr_hdr *)skb_transport_header(skb);
--
2.34.1
^ permalink raw reply related
* [PATCH 6.1.y] ipv6: add NULL checks for idev in SRv6 paths
From: Li hongliang @ 2026-04-20 5:43 UTC (permalink / raw)
To: gregkh, stable, heminhong
Cc: patches, linux-kernel, davem, dsahern, edumazet, kuba, pabeni,
horms, david.lebrun, netdev, andrea.mayer
From: Minhong He <heminhong@kylinos.cn>
[ Upstream commit 06413793526251870e20402c39930804f14d59c0 ]
__in6_dev_get() can return NULL when the device has no IPv6 configuration
(e.g. MTU < IPV6_MIN_MTU or after NETDEV_UNREGISTER).
Add NULL checks for idev returned by __in6_dev_get() in both
seg6_hmac_validate_skb() and ipv6_srh_rcv() to prevent potential NULL
pointer dereferences.
Fixes: 1ababeba4a21 ("ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header)")
Fixes: bf355b8d2c30 ("ipv6: sr: add core files for SR HMAC support")
Signed-off-by: Minhong He <heminhong@kylinos.cn>
Reviewed-by: Andrea Mayer <andrea.mayer@uniroma2.it>
Link: https://patch.msgid.link/20260316073301.106643-1-heminhong@kylinos.cn
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Li hongliang <1468888505@139.com>
---
net/ipv6/exthdrs.c | 4 ++++
net/ipv6/seg6_hmac.c | 2 ++
2 files changed, 6 insertions(+)
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 61e0060185f4..5fb97a87d2cb 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -381,6 +381,10 @@ static int ipv6_srh_rcv(struct sk_buff *skb)
hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
idev = __in6_dev_get(skb->dev);
+ if (!idev) {
+ kfree_skb(skb);
+ return -1;
+ }
accept_seg6 = net->ipv6.devconf_all->seg6_enabled;
if (accept_seg6 > idev->cnf.seg6_enabled)
diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c
index b90c286d77ed..e784f539194a 100644
--- a/net/ipv6/seg6_hmac.c
+++ b/net/ipv6/seg6_hmac.c
@@ -244,6 +244,8 @@ bool seg6_hmac_validate_skb(struct sk_buff *skb)
struct inet6_dev *idev;
idev = __in6_dev_get(skb->dev);
+ if (!idev)
+ return false;
srh = (struct ipv6_sr_hdr *)skb_transport_header(skb);
--
2.34.1
^ permalink raw reply related
* [PATCH 6.6.y] ipv6: add NULL checks for idev in SRv6 paths
From: Li hongliang @ 2026-04-20 5:42 UTC (permalink / raw)
To: gregkh, stable, heminhong
Cc: patches, linux-kernel, davem, dsahern, edumazet, kuba, pabeni,
horms, david.lebrun, netdev, andrea.mayer
From: Minhong He <heminhong@kylinos.cn>
[ Upstream commit 06413793526251870e20402c39930804f14d59c0 ]
__in6_dev_get() can return NULL when the device has no IPv6 configuration
(e.g. MTU < IPV6_MIN_MTU or after NETDEV_UNREGISTER).
Add NULL checks for idev returned by __in6_dev_get() in both
seg6_hmac_validate_skb() and ipv6_srh_rcv() to prevent potential NULL
pointer dereferences.
Fixes: 1ababeba4a21 ("ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header)")
Fixes: bf355b8d2c30 ("ipv6: sr: add core files for SR HMAC support")
Signed-off-by: Minhong He <heminhong@kylinos.cn>
Reviewed-by: Andrea Mayer <andrea.mayer@uniroma2.it>
Link: https://patch.msgid.link/20260316073301.106643-1-heminhong@kylinos.cn
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Li hongliang <1468888505@139.com>
---
net/ipv6/exthdrs.c | 4 ++++
net/ipv6/seg6_hmac.c | 2 ++
2 files changed, 6 insertions(+)
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 676284b6efe8..a8790163e8b6 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -378,6 +378,10 @@ static int ipv6_srh_rcv(struct sk_buff *skb)
hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
idev = __in6_dev_get(skb->dev);
+ if (!idev) {
+ kfree_skb(skb);
+ return -1;
+ }
accept_seg6 = net->ipv6.devconf_all->seg6_enabled;
if (accept_seg6 > idev->cnf.seg6_enabled)
diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c
index 6e15a65faecc..bf97bf5ac138 100644
--- a/net/ipv6/seg6_hmac.c
+++ b/net/ipv6/seg6_hmac.c
@@ -244,6 +244,8 @@ bool seg6_hmac_validate_skb(struct sk_buff *skb)
struct inet6_dev *idev;
idev = __in6_dev_get(skb->dev);
+ if (!idev)
+ return false;
srh = (struct ipv6_sr_hdr *)skb_transport_header(skb);
--
2.34.1
^ permalink raw reply related
* [PATCH 6.12.y] ipv6: add NULL checks for idev in SRv6 paths
From: Li hongliang @ 2026-04-20 5:42 UTC (permalink / raw)
To: gregkh, stable, heminhong
Cc: patches, linux-kernel, davem, dsahern, edumazet, kuba, pabeni,
horms, david.lebrun, netdev, andrea.mayer
From: Minhong He <heminhong@kylinos.cn>
[ Upstream commit 06413793526251870e20402c39930804f14d59c0 ]
__in6_dev_get() can return NULL when the device has no IPv6 configuration
(e.g. MTU < IPV6_MIN_MTU or after NETDEV_UNREGISTER).
Add NULL checks for idev returned by __in6_dev_get() in both
seg6_hmac_validate_skb() and ipv6_srh_rcv() to prevent potential NULL
pointer dereferences.
Fixes: 1ababeba4a21 ("ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header)")
Fixes: bf355b8d2c30 ("ipv6: sr: add core files for SR HMAC support")
Signed-off-by: Minhong He <heminhong@kylinos.cn>
Reviewed-by: Andrea Mayer <andrea.mayer@uniroma2.it>
Link: https://patch.msgid.link/20260316073301.106643-1-heminhong@kylinos.cn
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Li hongliang <1468888505@139.com>
---
net/ipv6/exthdrs.c | 4 ++++
net/ipv6/seg6_hmac.c | 2 ++
2 files changed, 6 insertions(+)
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 1a627c24e4c3..8a30dd83cf0b 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -379,6 +379,10 @@ static int ipv6_srh_rcv(struct sk_buff *skb)
hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
idev = __in6_dev_get(skb->dev);
+ if (!idev) {
+ kfree_skb(skb);
+ return -1;
+ }
accept_seg6 = min(READ_ONCE(net->ipv6.devconf_all->seg6_enabled),
READ_ONCE(idev->cnf.seg6_enabled));
diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c
index 5d21a74c1165..214d137d545e 100644
--- a/net/ipv6/seg6_hmac.c
+++ b/net/ipv6/seg6_hmac.c
@@ -245,6 +245,8 @@ bool seg6_hmac_validate_skb(struct sk_buff *skb)
int require_hmac;
idev = __in6_dev_get(skb->dev);
+ if (!idev)
+ return false;
srh = (struct ipv6_sr_hdr *)skb_transport_header(skb);
--
2.34.1
^ permalink raw reply related
* [PATCH 6.12-stable] PCI: Fix placement of pci_save_state() in pci_bus_add_device()
From: Lukas Wunner @ 2026-04-20 5:11 UTC (permalink / raw)
To: Greg Kroah-Hartman, Sasha Levin; +Cc: stable
Commit 58130e7ce6cb ("PCI/ERR: Ensure error recoverability at all
times") sought to backport upstream commit a2f1e22390ac, but misplaced
the call to pci_save_state() in pci_bus_add_device():
It put the call at the top of the function even though the upstream
commit deliberately put it in the middle to capture config space changes
caused by pci_fixup_final().
Fix the placement.
Signed-off-by: Lukas Wunner <lukas@wunner.de>
---
drivers/pci/bus.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 429c0c8ce93d..bdb3e10f947a 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -331,9 +331,6 @@ void pci_bus_add_device(struct pci_dev *dev)
struct device_node *dn = dev->dev.of_node;
int retval;
- /* Save config space for error recoverability */
- pci_save_state(dev);
-
/*
* Can not put in pci_device_add yet because resources
* are not assigned yet for some devices.
@@ -346,6 +343,9 @@ void pci_bus_add_device(struct pci_dev *dev)
pci_proc_attach_device(dev);
pci_bridge_d3_update(dev);
+ /* Save config space for error recoverability */
+ pci_save_state(dev);
+
dev->match_driver = !dn || of_device_is_available(dn);
retval = device_attach(&dev->dev);
if (retval < 0 && retval != -EPROBE_DEFER)
--
2.51.0
^ permalink raw reply related
* Re: [PATCH v2] Drivers: hv: mshv: fix integer overflow in memory region overlap check
From: Junrui Luo @ 2026-04-20 5:17 UTC (permalink / raw)
To: Stanislav Kinsburskii
Cc: vdso@mailbox.org, K. Y. Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Nuno Das Neves, Anirudh Rayabharam,
Mukesh Rathor, Muminul Islam, Praveen K Paladugu, Jinank Jain,
linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org,
Yuhao Jiang, stable@vger.kernel.org
In-Reply-To: <1644495552.14476.1776103846016@app.mailbox.org>
Hi Stanislav,
Gentle ping on this. Does this approach work for you?
Thanks,
Junrui Luo
^ permalink raw reply
* [PATCH 2/2] HID: appletb-kbd: run inactivity autodim from workqueues
From: Sangyun Kim @ 2026-04-20 5:13 UTC (permalink / raw)
To: jikos, bentiss; +Cc: qasdev00, gargaditya08, linux-input, linux-kernel, stable
In-Reply-To: <20260420051318.1411671-1-sangyun.kim@snu.ac.kr>
The autodim code in hid-appletb-kbd takes backlight_device->ops_lock
via backlight_device_set_brightness() -> mutex_lock() from two
different atomic contexts:
* appletb_inactivity_timer() is a struct timer_list callback, so it
runs in softirq context. Every expiry triggers
BUG: sleeping function called from invalid context at kernel/locking/mutex.c:591
Call Trace:
<IRQ>
__might_resched
__mutex_lock
backlight_device_set_brightness
appletb_inactivity_timer
call_timer_fn
run_timer_softirq
* reset_inactivity_timer() is called from appletb_kbd_hid_event() and
appletb_kbd_inp_event(). On real USB hardware these run in
softirq/IRQ context (URB completion and input-event dispatch).
When the Touch Bar has already been dimmed or turned off, the
reset path calls backlight_device_set_brightness() directly to
restore brightness, producing the same warning.
Both call sites hit the same mutex_lock()-from-atomic bug. Fix them
together by moving the blocking work onto the system workqueue:
* Convert the inactivity timer from struct timer_list to
struct delayed_work; the callback (appletb_inactivity_work) now
runs in process context where mutex_lock() is legal.
* Add a dedicated struct work_struct restore_brightness_work and have
reset_inactivity_timer() schedule it instead of calling
backlight_device_set_brightness() directly.
Cancel both works synchronously during driver tear-down alongside the
existing backlight reference drop.
The semantics are unchanged (same delays, same state transitions on
dim, turn-off and user activity); only the execution context of the
sleeping call changes. The timer field and callback are renamed to
match their new type; reset_inactivity_timer() keeps its name because
it is invoked from input event paths that read naturally as "reset
the inactivity timer".
Fixes: 93a0fc489481 ("HID: hid-appletb-kbd: add support for automatic brightness control while using the touchbar")
Cc: stable@vger.kernel.org
Signed-off-by: Sangyun Kim <sangyun.kim@snu.ac.kr>
---
drivers/hid/hid-appletb-kbd.c | 44 ++++++++++++++++++++++++-----------
1 file changed, 30 insertions(+), 14 deletions(-)
diff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c
index 8feac9e3589b..462010a75899 100644
--- a/drivers/hid/hid-appletb-kbd.c
+++ b/drivers/hid/hid-appletb-kbd.c
@@ -17,7 +17,7 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/backlight.h>
-#include <linux/timer.h>
+#include <linux/workqueue.h>
#include <linux/input/sparse-keymap.h>
#include "hid-ids.h"
@@ -62,7 +62,8 @@ struct appletb_kbd {
struct input_handle kbd_handle;
struct input_handle tpd_handle;
struct backlight_device *backlight_dev;
- struct timer_list inactivity_timer;
+ struct delayed_work inactivity_work;
+ struct work_struct restore_brightness_work;
bool has_dimmed;
bool has_turned_off;
u8 saved_mode;
@@ -164,16 +165,18 @@ static int appletb_tb_key_to_slot(unsigned int code)
}
}
-static void appletb_inactivity_timer(struct timer_list *t)
+static void appletb_inactivity_work(struct work_struct *work)
{
- struct appletb_kbd *kbd = timer_container_of(kbd, t, inactivity_timer);
+ struct appletb_kbd *kbd = container_of(to_delayed_work(work),
+ struct appletb_kbd,
+ inactivity_work);
if (kbd->backlight_dev && appletb_tb_autodim) {
if (!kbd->has_dimmed) {
backlight_device_set_brightness(kbd->backlight_dev, 1);
kbd->has_dimmed = true;
- mod_timer(&kbd->inactivity_timer,
- jiffies + secs_to_jiffies(appletb_tb_idle_timeout));
+ mod_delayed_work(system_wq, &kbd->inactivity_work,
+ secs_to_jiffies(appletb_tb_idle_timeout));
} else if (!kbd->has_turned_off) {
backlight_device_set_brightness(kbd->backlight_dev, 0);
kbd->has_turned_off = true;
@@ -181,16 +184,25 @@ static void appletb_inactivity_timer(struct timer_list *t)
}
}
+static void appletb_restore_brightness_work(struct work_struct *work)
+{
+ struct appletb_kbd *kbd = container_of(work, struct appletb_kbd,
+ restore_brightness_work);
+
+ if (kbd->backlight_dev)
+ backlight_device_set_brightness(kbd->backlight_dev, 2);
+}
+
static void reset_inactivity_timer(struct appletb_kbd *kbd)
{
if (kbd->backlight_dev && appletb_tb_autodim) {
if (kbd->has_dimmed || kbd->has_turned_off) {
- backlight_device_set_brightness(kbd->backlight_dev, 2);
kbd->has_dimmed = false;
kbd->has_turned_off = false;
+ schedule_work(&kbd->restore_brightness_work);
}
- mod_timer(&kbd->inactivity_timer,
- jiffies + secs_to_jiffies(appletb_tb_dim_timeout));
+ mod_delayed_work(system_wq, &kbd->inactivity_work,
+ secs_to_jiffies(appletb_tb_dim_timeout));
}
}
@@ -408,9 +420,11 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id
dev_err_probe(dev, -ENODEV, "Failed to get backlight device\n");
} else {
backlight_device_set_brightness(kbd->backlight_dev, 2);
- timer_setup(&kbd->inactivity_timer, appletb_inactivity_timer, 0);
- mod_timer(&kbd->inactivity_timer,
- jiffies + secs_to_jiffies(appletb_tb_dim_timeout));
+ INIT_DELAYED_WORK(&kbd->inactivity_work, appletb_inactivity_work);
+ INIT_WORK(&kbd->restore_brightness_work,
+ appletb_restore_brightness_work);
+ mod_delayed_work(system_wq, &kbd->inactivity_work,
+ secs_to_jiffies(appletb_tb_dim_timeout));
}
kbd->inp_handler.event = appletb_kbd_inp_event;
@@ -444,7 +458,8 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id
stop_hw:
hid_hw_stop(hdev);
if (kbd->backlight_dev) {
- timer_delete_sync(&kbd->inactivity_timer);
+ cancel_delayed_work_sync(&kbd->inactivity_work);
+ cancel_work_sync(&kbd->restore_brightness_work);
put_device(&kbd->backlight_dev->dev);
}
return ret;
@@ -461,7 +476,8 @@ static void appletb_kbd_remove(struct hid_device *hdev)
hid_hw_stop(hdev);
if (kbd->backlight_dev) {
- timer_delete_sync(&kbd->inactivity_timer);
+ cancel_delayed_work_sync(&kbd->inactivity_work);
+ cancel_work_sync(&kbd->restore_brightness_work);
put_device(&kbd->backlight_dev->dev);
}
}
--
2.34.1
^ permalink raw reply related
* [PATCH 1/2] HID: appletb-kbd: fix UAF in inactivity-timer cleanup path
From: Sangyun Kim @ 2026-04-20 5:13 UTC (permalink / raw)
To: jikos, bentiss; +Cc: qasdev00, gargaditya08, linux-input, linux-kernel, stable
In-Reply-To: <20260420051318.1411671-1-sangyun.kim@snu.ac.kr>
Commit 38224c472a03 ("HID: appletb-kbd: fix slab use-after-free bug in
appletb_kbd_probe") added timer_delete_sync(&kbd->inactivity_timer) to
both the probe close_hw error path and appletb_kbd_remove(), but the
way it was wired in left the inactivity timer reachable during driver
tear-down via two distinct windows.
Window A -- put_device() before timer_delete_sync():
put_device(&kbd->backlight_dev->dev);
timer_delete_sync(&kbd->inactivity_timer);
The inactivity_timer softirq reads kbd->backlight_dev and calls
backlight_device_set_brightness() -> mutex_lock(&ops_lock). If a
concurrent hid_appletb_bl unbind drops the last devm reference
between these two calls, the backlight_device is freed and the
mutex_lock() touches freed memory.
Window B -- backlight cleanup before hid_hw_stop():
if (kbd->backlight_dev) {
timer_delete_sync(...);
put_device(...);
}
hid_hw_close(hdev);
hid_hw_stop(hdev);
Even after Window A is closed, hid_hw_close()/hid_hw_stop() still run
afterwards, so a late ".event" callback from the HID core (USB URB
completion on real Apple hardware) can arrive after
timer_delete_sync() drained the softirq but before put_device() drops
the reference. That callback reaches reset_inactivity_timer(), which
calls mod_timer() and re-arms the timer. The freshly re-armed timer
can then fire on the about-to-be-freed backlight_device.
Both windows produce the same KASAN slab-use-after-free:
BUG: KASAN: slab-use-after-free in __mutex_lock+0x1aab/0x21c0
Read of size 8 at addr ffff88803ee9a108 by task swapper/0/0
Call Trace:
<IRQ>
__mutex_lock
backlight_device_set_brightness
appletb_inactivity_timer
call_timer_fn
run_timer_softirq
handle_softirqs
Allocated by task N:
devm_backlight_device_register
appletb_bl_probe
Freed by task M:
(concurrent hid_appletb_bl unbind path)
Close both windows at once by reworking the tear-down in
appletb_kbd_remove() and in the probe close_hw error path so that
1) hid_hw_close()/hid_hw_stop() run before the backlight cleanup,
guaranteeing no further .event callback can fire and re-arm the
timer, and
2) inside the "if (kbd->backlight_dev)" block, timer_delete_sync()
runs before put_device(), so the softirq is drained before the
final reference is dropped.
Fixes: 38224c472a03 ("HID: appletb-kbd: fix slab use-after-free bug in appletb_kbd_probe")
Cc: stable@vger.kernel.org
Signed-off-by: Sangyun Kim <sangyun.kim@snu.ac.kr>
---
drivers/hid/hid-appletb-kbd.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/hid/hid-appletb-kbd.c b/drivers/hid/hid-appletb-kbd.c
index 0fdc0968b9ef..8feac9e3589b 100644
--- a/drivers/hid/hid-appletb-kbd.c
+++ b/drivers/hid/hid-appletb-kbd.c
@@ -440,13 +440,13 @@ static int appletb_kbd_probe(struct hid_device *hdev, const struct hid_device_id
unregister_handler:
input_unregister_handler(&kbd->inp_handler);
close_hw:
- if (kbd->backlight_dev) {
- put_device(&kbd->backlight_dev->dev);
- timer_delete_sync(&kbd->inactivity_timer);
- }
hid_hw_close(hdev);
stop_hw:
hid_hw_stop(hdev);
+ if (kbd->backlight_dev) {
+ timer_delete_sync(&kbd->inactivity_timer);
+ put_device(&kbd->backlight_dev->dev);
+ }
return ret;
}
@@ -457,13 +457,13 @@ static void appletb_kbd_remove(struct hid_device *hdev)
appletb_kbd_set_mode(kbd, APPLETB_KBD_MODE_OFF);
input_unregister_handler(&kbd->inp_handler);
+ hid_hw_close(hdev);
+ hid_hw_stop(hdev);
+
if (kbd->backlight_dev) {
- put_device(&kbd->backlight_dev->dev);
timer_delete_sync(&kbd->inactivity_timer);
+ put_device(&kbd->backlight_dev->dev);
}
-
- hid_hw_close(hdev);
- hid_hw_stop(hdev);
}
static int appletb_kbd_suspend(struct hid_device *hdev, pm_message_t msg)
--
2.34.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox