From: "Brad Bosch" <bradbosch@comcast.net>
To: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Brad Bosch <bradbosch@comcast.net>,
linux-crypto@vger.kernel.org, netdev@vger.kernel.org,
offbase0@gmail.com
Subject: Re: Crypto oops in async_chainiv_do_postponed
Date: Mon, 31 Aug 2009 11:11:42 -0500 [thread overview]
Message-ID: <19099.63038.425414.514063@waldo.imnotcreative.homeip.net> (raw)
In-Reply-To: <20090829104606.GA13141@gondor.apana.org.au>
Herbert Xu writes:
> Thanks for the detailed analysis and patch!
No problem, thanks for looking at it!
>
> > The null dereference occurs when subreq is dereferenced in
> > async_chainiv_do_postponed(). My guess is that the
> > skcipher_givcrypt_request block has been freed and subsequently
> > overwritten by the time the postponed request is processed. This
> > could happen if chainiv_givencrypt() returns anything other than
> > -EINPROGRESS after postponing the request. From what I can see, this
> > could indeed happen since the same err field in async_chainiv_ctx is
> > used both when the request is postponed and also when it is later
> > processed by the worker thread. Neither the lock, nor the
> > CHAINIV_STATE_INUSE bit in ctx->state will prevent this race which
> > results in the -EINPROGRESS err being overwritten between the time it
> > is placed in ctx->err in async_chainiv_postpone_request() and when it
> > is read back out in async_chainiv_schedule_work(). I am curious why
> > this method of returning the error code was used in the first place.
>
> Actually I think the problem is much less subtle than that :)
OK. I was looking for something subtle because the crash takes a long
time to happen. But do you agree that the race I described above also
a real bug?
>
> The problem is that whenever crypto_dequeue_request returns NULL,
> chainiv will never see the NULL pointer because we end up converting
> the pointer to skcipher_givcrypt_request which would have the value
> (NULL - off) where off is non-zero.
Yes, I see that this bug must be the bug we would likely encounter first.
Apparently, async_chainiv_do_postponed was never tested? But I don't
see how the patch you proposed below helps. We still don't seem to be
returning NULL from skcipher_dequeue_givcrypt when we reach the end of
the queue because __crypto_dequeue_request is not checking for NULL
before it subtracts offset.
Wouldn't the following (simpler, but untested) patch work?
Index: skcipher.h
===================================================================
RCS file: /share/cvs/sdg/kernels/kernel.wms/kernel_2_6_27/src/include/crypto/internal/skcipher.h,v
retrieving revision 1.1.1.1.4.2
diff -u -r1.1.1.1.4.2 skcipher.h
--- skcipher.h 10 Mar 2009 05:25:25 -0000 1.1.1.1.4.2
+++ skcipher.h 31 Aug 2009 15:56:50 -0000
@@ -85,8 +85,9 @@
static inline struct skcipher_givcrypt_request *skcipher_dequeue_givcrypt(
struct crypto_queue *queue)
{
- return container_of(ablkcipher_dequeue_request(queue),
- struct skcipher_givcrypt_request, creq);
+ struct ablkcipher_request *req = ablkcipher_dequeue_request(queue);
+ return req ? container_of(req, struct skcipher_givcrypt_request, creq)
+ : NULL;
}
static inline void *skcipher_givcrypt_reqctx(
Thanks!
--Brad
>
> Please let me know if this patch fixes the crash for you.
>
> commit 0c7d400fafaeab6014504a6a6249f01bac7f7db4
> Author: Herbert Xu <herbert@gondor.apana.org.au>
> Date: Sat Aug 29 20:44:04 2009 +1000
>
> crypto: skcipher - Fix skcipher_dequeue_givcrypt NULL test
>
> As struct skcipher_givcrypt_request includes struct crypto_request
> at a non-zero offset, testing for NULL after converting the pointer
> returned by crypto_dequeue_request does not work. This can result
> in IPsec crashes when the queue is depleted.
>
> This patch fixes it by doing the pointer conversion only when the
> return value is non-NULL. In particular, we create a new function
> __crypto_dequeue_request that does the pointer conversion.
>
> Reported-by: Brad Bosch <bradbosch@comcast.net>
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
>
> diff --git a/crypto/algapi.c b/crypto/algapi.c
> index 56c62e2..df0863d 100644
> --- a/crypto/algapi.c
> +++ b/crypto/algapi.c
> @@ -692,7 +692,7 @@ out:
> }
> EXPORT_SYMBOL_GPL(crypto_enqueue_request);
>
> -struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue)
> +void *__crypto_dequeue_request(struct crypto_queue *queue, unsigned int offset)
> {
> struct list_head *request;
>
> @@ -707,7 +707,14 @@ struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue)
> request = queue->list.next;
> list_del(request);
>
> - return list_entry(request, struct crypto_async_request, list);
> + return (char *)list_entry(request, struct crypto_async_request, list) -
> + offset;
> +}
> +EXPORT_SYMBOL_GPL(__crypto_dequeue_request);
> +
> +struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue)
> +{
> + return __crypto_dequeue_request(queue, 0);
> }
> EXPORT_SYMBOL_GPL(crypto_dequeue_request);
>
> diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
> index 0105454..5a2bd1c 100644
> --- a/include/crypto/algapi.h
> +++ b/include/crypto/algapi.h
> @@ -137,6 +137,7 @@ struct crypto_instance *crypto_alloc_instance(const char *name,
> void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen);
> int crypto_enqueue_request(struct crypto_queue *queue,
> struct crypto_async_request *request);
> +void *__crypto_dequeue_request(struct crypto_queue *queue, unsigned int offset);
> struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue);
> int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm);
>
> diff --git a/include/crypto/internal/skcipher.h b/include/crypto/internal/skcipher.h
> index 2ba42cd..3a748a6 100644
> --- a/include/crypto/internal/skcipher.h
> +++ b/include/crypto/internal/skcipher.h
> @@ -79,8 +79,8 @@ static inline int skcipher_enqueue_givcrypt(
> static inline struct skcipher_givcrypt_request *skcipher_dequeue_givcrypt(
> struct crypto_queue *queue)
> {
> - return container_of(ablkcipher_dequeue_request(queue),
> - struct skcipher_givcrypt_request, creq);
> + return __crypto_dequeue_request(
> + queue, offsetof(struct skcipher_givcrypt_request, creq.base));
> }
>
> static inline void *skcipher_givcrypt_reqctx(
>
> Cheers,
> --
> Visit Openswan at http://www.openswan.org/
> Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
> Home Page: http://gondor.apana.org.au/~herbert/
> PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
next prev parent reply other threads:[~2009-08-31 16:11 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <19095.1264.682820.125602@waldo.imnotcreative.homeip.net>
2009-08-29 10:46 ` Crypto oops in async_chainiv_do_postponed Herbert Xu
2009-08-31 16:11 ` Brad Bosch [this message]
2009-08-31 22:04 ` Herbert Xu
2009-09-01 15:42 ` Brad Bosch
2009-09-01 22:17 ` Herbert Xu
2009-09-02 14:08 ` Brad Bosch
2009-09-02 21:57 ` Herbert Xu
2009-09-02 23:47 ` Brad Bosch
2009-09-03 1:53 ` Herbert Xu
2009-09-02 14:23 ` Brad Bosch
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=19099.63038.425414.514063@waldo.imnotcreative.homeip.net \
--to=bradbosch@comcast.net \
--cc=herbert@gondor.apana.org.au \
--cc=linux-crypto@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=offbase0@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox