lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <paajlxnnp6isq435i7w2onndi56xpwahq6tl6hbjwqdhta375l@kqgpf5nkcsog>
Date:   Wed, 4 Oct 2023 15:07:10 -0400
From:   Daniel Jordan <daniel.m.jordan@...cle.com>
To:     Wang Jinchao <wangjinchao@...sion.com>
Cc:     Steffen Klassert <steffen.klassert@...unet.com>,
        linux-crypto@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH v2] padata: Fix the UAF issue related to parallel_data

On Wed, Oct 04, 2023 at 10:54:29AM -0400, Daniel Jordan wrote:
> On Thu, Sep 28, 2023 at 08:38:53AM +0800, Wang Jinchao wrote:
> > 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() {
> >     DECLARE_COMPLETION(done)
> >     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`.
> 
> This could use a Fixes tag.  From Nicolai's patch[0] we agreed on
> 
> Fixes: 07928d9bfc81 ("padata: Remove broken queue flushing")
> 
> With that,
> 
> Acked-by: Daniel Jordan <daniel.m.jordan@...cle.com>
> 
> Thanks!
> 
> [0] https://lore.kernel.org/all/87educb7rm.fsf@suse.de/
> 
> > Signed-off-by: Wang Jinchao <wangjinchao@...sion.com>
> > ---
> > V2:
> >     To satisfy Sparse, use rcu_dereference_protected.
> >     Reported-by: kernel test robot <lkp@...el.com>
> >     Closes: https://lore.kernel.org/oe-kbuild-all/202309270829.xHgTOMKw-lkp@intel.com/
> > 
> > V1: https://lore.kernel.org/all/ZRE4XvOOhz4HSOgR@fedora/
> > 
> >  kernel/padata.c | 4 +++-
> >  1 file changed, 3 insertions(+), 1 deletion(-)
> > 
> > diff --git a/kernel/padata.c b/kernel/padata.c
> > index 222d60195de6..acef1e703a8b 100644
> > --- a/kernel/padata.c
> > +++ b/kernel/padata.c
> > @@ -1107,7 +1107,9 @@ void padata_free_shell(struct padata_shell *ps)
> >  
> >  	mutex_lock(&ps->pinst->lock);
> >  	list_del(&ps->list);
> > -	padata_free_pd(rcu_dereference_protected(ps->pd, 1));
> > +	struct parallel_data *pd = rcu_dereference_protected(ps->pd, 1);

Oh, I should've also said please move the declaration of pd to the top
of the function like scripts/checkpatch.pl suggests.

> > +	if (refcount_dec_and_test(&pd->refcnt))
> > +		padata_free_pd(pd);
> >  	mutex_unlock(&ps->pinst->lock);
> >  
> >  	kfree(ps);
> > -- 
> > 2.40.0
> > 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ