[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20200416021703.GD816@sol.localdomain>
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