Fixes: 07928d9bfc81 ("padata: Remove broken queue flushing")
Subsystems (2)
PATCH v3 1/1 Fixes: 07928d9bfc81 ("padata: Remove broken queue flushing")
In a high-load arm64 environment, the pcrypt_aead01 test in LTP can lead to system UAF (Use-After-Free) issues. Due to the lengthy analysis of the pcrypt_aead01 function call, I'll describe the problem scenario using a simplified model:
Suppose there's a user of padata named user_function that adheres to the padata requirement of calling padata_free_shell after serial() has been invoked, as demonstrated in the following code:
```c
struct request {
struct padata_priv padata;
struct completion *done;
};
void parallel(struct padata_priv *padata) {
do_something();
}
void serial(struct padata_priv *padata) {
struct request *request = container_of(padata, struct request, padata);
complete(request->done);
}
void user_function() {
struct request request;
DECLARE_COMPLETION(done)
request->done = done;
padata = &request.padata;
padata->parallel = parallel;
padata->serial = serial;
padata_do_parallel();
wait_for_completion(&done);
padata_free_shell();
}
```In the corresponding padata.c file, there's the following code:
```c
static void padata_serial_worker(struct work_struct *serial_work) {
...
cnt = 0;
while (!list_empty(&local_list)) {
...
padata->serial(padata);
cnt++;
}
local_bh_enable();
if (refcount_sub_and_test(cnt, &pd->refcnt))
padata_free_pd(pd);
}
```Because of the high system load and the accumulation of unexecuted softirq at this moment, local_bh_enable() in padata takes longer to execute than usual. Subsequently, when accessing pd->refcnt, pd has already been released by padata_free_shell(), resulting in a UAF issue with pd->refcnt.
The fix is straightforward: add refcount_dec_and_test before calling padata_free_pd in padata_free_shell.
---
V3:
Include Daniel's ack
V2: https://lore.kernel.org/all/ZRTLHY5A+VqIKhA2@fedora/
To satisfy Sparse, use rcu_dereference_protected.
V1: https://lore.kernel.org/all/ZRE4XvOOhz4HSOgR@fedora/
kernel/padata.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
kernel/padata.c +5 -1
@@ -1102,12 +1102,16 @@ EXPORT_SYMBOL(padata_alloc_shell);*/ void padata_free_shell (struct padata_shell *ps) { +struct parallel_data *pd; +if (!ps)return ;mutex_lock (&ps->pinst->lock);list_del (&ps->list); -padata_free_pd (rcu_dereference_protected (ps->pd,1 )); + pd =rcu_dereference_protected (ps->pd,1 ); +if (refcount_dec_and_test (&pd->refcnt)) +padata_free_pd (rcu_dereference_protected (ps->pd,1 ));mutex_unlock (&ps->pinst->lock);kfree (ps);
Signature · 1 line
2.40.0
Herbert Xu
maintainerQuoted 10 lines · Wang Jinchao
kernel/padata.c +1
-0@@ -1102,12 +1102,16 @@ EXPORT_SYMBOL(padata_alloc_shell);*/ void padata_free_shell (struct padata_shell *ps) { +struct parallel_data *pd;
kernel/padata.c EXPORT_SYMBOL(padata_alloc_shell); · line 1114
Quoted 10 lines
kernel/padata.c +4
-1+if (!ps)return ;mutex_lock (&ps->pinst->lock);list_del (&ps->list); -padata_free_pd (rcu_dereference_protected (ps->pd,1 )); + pd =rcu_dereference_protected (ps->pd,1 ); +if (refcount_dec_and_test (&pd->refcnt)) +padata_free_pd (rcu_dereference_protected (ps->pd,1 ));
Why is this dereferencing ps->pd again after the refcount_dec_and_test?
If this is necessary please explain it in the code because it is not at all obvious.
Thanks,
Signature · 3 lines
Email: Herbert Xu <[email protected]> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
Daniel Jordan
maintainerHi,
Quoted 1 line · Wang Jinchao
Signed-off-by Wang Jinchao <[email protected]>
The Fixes: tag should be near your Signed-off-by:, and the subject of the patch should be something descriptive like
padata: Fix refcnt handling in padata_free_shell()
Here's some documentation about this:
https://docs.kernel.org/process/5.Posting.html#patch-formatting-and-changelogs
Quoted 9 lines
Acked-by Daniel Jordan <[email protected]>---
V3:
Include Daniel's ackV2: https://lore.kernel.org/all/ZRTLHY5A+VqIKhA2@fedora/
To satisfy Sparse, usercu_dereference_protected.
These two tags can also go near your SoB.
Quoted 14 lines
V1: https://lore.kernel.org/all/ZRE4XvOOhz4HSOgR@fedora/
kernel/padata.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)kernel/padata.c +1
-0@@ -1102,12 +1102,16 @@ EXPORT_SYMBOL(padata_alloc_shell);*/ void padata_free_shell (struct padata_shell *ps) { +struct parallel_data *pd;
kernel/padata.c EXPORT_SYMBOL(padata_alloc_shell); · line 1114
Quoted 10 lines
kernel/padata.c +4
-1+if (!ps)return ;mutex_lock (&ps->pinst->lock);list_del (&ps->list); -padata_free_pd (rcu_dereference_protected (ps->pd,1 )); + pd =rcu_dereference_protected (ps->pd,1 ); +if (refcount_dec_and_test (&pd->refcnt)) +padata_free_pd (rcu_dereference_protected (ps->pd,1 ));
As Herbert points out, this version changes the code by rcu-dereferencing pd twice. Usually previous acks are dropped when introducing new changes, but you can have it back by only rcu-dereferencing once and addressing the other comments above.
Quoted 6 lines
kernel/padata.c +0
-0mutex_unlock (&ps->pinst->lock);kfree (ps);Signature · 1 line
2.40.0
Quoted 5 lines · Daniel Jordan
Hi,
Quoted 1 line · Wang Jinchao
Signed-off-by Wang Jinchao <[email protected]>
Quoted 9 lines
The Fixes: tag should be near your Signed-off-by:, and the subject of the patch should be something descriptive like
padata: Fix refcnt handling in
padata_free_shell()Here's some documentation about this:
https://docs.kernel.org/process/5.Posting.html#patch-formatting-and-changelogs
Updated in patch v4.
Quoted 5 lines
Quoted 5 lines
Acked-by Daniel Jordan <[email protected]>---
V3:
Include Daniel's ack
Quoted 7 lines
Quoted 4 lines
V2: https://lore.kernel.org/all/ZRTLHY5A+VqIKhA2@fedora/
To satisfy Sparse, usercu_dereference_protected.These two tags can also go near your SoB.
From intel kernel test robot:
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
So I updated the patch without these tags.
Quoted 18 lines
Quoted 18 lines
V1: https://lore.kernel.org/all/ZRE4XvOOhz4HSOgR@fedora/
kernel/padata.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)kernel/padata.c +2
-0@@ -1102,12 +1102,16 @@ EXPORT_SYMBOL(padata_alloc_shell);*/ void padata_free_shell (struct padata_shell *ps) { +struct parallel_data *pd; +if (!ps)return ;
Quoted 11 lines
kernel/padata.c EXPORT_SYMBOL(padata_alloc_shell); · line 1114
Quoted 6 lines
kernel/padata.c +3
-1mutex_lock (&ps->pinst->lock);list_del (&ps->list); -padata_free_pd (rcu_dereference_protected (ps->pd,1 )); + pd =rcu_dereference_protected (ps->pd,1 ); +if (refcount_dec_and_test (&pd->refcnt)) +padata_free_pd (rcu_dereference_protected (ps->pd,1 ));As Herbert points out, this version changes the code by rcu-dereferencing pd twice. Usually previous acks are dropped when introducing new changes, but you can have it back by only rcu-dereferencing once and addressing the other comments above.
Thanks for your and Herbert's acks, which were included in patch v4.
I know Herbert has acked my patch from your email; however, I have not received Herbert's acknowledgment email, and I do not know why.
Quoted 7 lines
Quoted 7 lines
kernel/padata.c +0
-0mutex_unlock (&ps->pinst->lock);kfree (ps);Signature · 1 line
2.40.0