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]
Date:   Wed, 15 Apr 2020 19:17:03 -0700
From:   Eric Biggers <ebiggers@...nel.org>
To:     Herbert Xu <herbert@...dor.apana.org.au>
Cc:     syzbot <syzbot+fc0674cde00b66844470@...kaller.appspotmail.com>,
        davem@...emloft.net, linux-crypto@...r.kernel.org,
        linux-kernel@...r.kernel.org, netdev@...r.kernel.org,
        syzkaller-bugs@...glegroups.com
Subject: Re: crypto: api - Fix use-after-free and race in crypto_spawn_alg

On Fri, Apr 10, 2020 at 04:09:42PM +1000, Herbert Xu wrote:
> There are two problems in crypto_spawn_alg.  First of all it may
> return spawn->alg even if spawn->dead is set.  This results in a
> double-free as detected by syzbot.
> 
> Secondly the setting of the DYING flag is racy because we hold
> the read-lock instead of the write-lock.  We should instead call
> crypto_shoot_alg in a safe manner by gaining a refcount, dropping
> the lock, and then releasing the refcount.
> 
> This patch fixes both problems.
> 
> Reported-by: syzbot+fc0674cde00b66844470@...kaller.appspotmail.com
> Fixes: 4f87ee118d16 ("crypto: api - Do not zap spawn->alg")
> Fixes: 73669cc55646 ("crypto: api - Fix race condition in...")
> Cc: <stable@...r.kernel.org>
> Signed-off-by: Herbert Xu <herbert@...dor.apana.org.au>
> 
> diff --git a/crypto/algapi.c b/crypto/algapi.c
> index 69605e21af92..f8b4dc161c02 100644
> --- a/crypto/algapi.c
> +++ b/crypto/algapi.c
> @@ -716,17 +716,27 @@ EXPORT_SYMBOL_GPL(crypto_drop_spawn);
>  
>  static struct crypto_alg *crypto_spawn_alg(struct crypto_spawn *spawn)
>  {
> -	struct crypto_alg *alg;
> +	struct crypto_alg *alg = ERR_PTR(-EAGAIN);
> +	struct crypto_alg *target;
> +	bool shoot = false;
>  
>  	down_read(&crypto_alg_sem);
> -	alg = spawn->alg;
> -	if (!spawn->dead && !crypto_mod_get(alg)) {
> -		alg->cra_flags |= CRYPTO_ALG_DYING;
> -		alg = NULL;
> +	if (!spawn->dead) {
> +		alg = spawn->alg;
> +		if (!crypto_mod_get(alg)) {
> +			target = crypto_alg_get(alg);
> +			shoot = true;
> +			alg = ERR_PTR(-EAGAIN);
> +		}
>  	}
>  	up_read(&crypto_alg_sem);
>  
> -	return alg ?: ERR_PTR(-EAGAIN);
> +	if (shoot) {
> +		crypto_shoot_alg(target);
> +		crypto_alg_put(target);
> +	}
> +
> +	return alg;
>  }

Wouldn't it be a bit simpler to set 'target = NULL', remove 'shoot',
and use 'if (target)' instead of 'if (shoot)'?

- Eric

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ