Skip to content

Commit

Permalink
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git…
Browse files Browse the repository at this point in the history
…/herbert/crypto-2.6

Pull crypto fixes from Herbert Xu:
 "This fixes the following problems:

   - regression in new XTS/LRW code when used with async crypto

   - long-standing bug in ahash API when used with certain algos

   - bogus memory dereference in async algif_aead with certain algos"

* 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6:
  crypto: algif_aead - Fix bogus request dereference in completion function
  crypto: ahash - Fix EINPROGRESS notification callback
  crypto: lrw - Fix use-after-free on EINPROGRESS
  crypto: xts - Fix use-after-free on EINPROGRESS
  • Loading branch information
Linus Torvalds committed Apr 18, 2017
2 parents 20bb78f + e6534ae commit 5ee4c5a
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 35 deletions.
79 changes: 50 additions & 29 deletions crypto/ahash.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct ahash_request_priv {
crypto_completion_t complete;
void *data;
u8 *result;
u32 flags;
void *ubuf[] CRYPTO_MINALIGN_ATTR;
};

Expand Down Expand Up @@ -253,6 +254,8 @@ static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt)
priv->result = req->result;
priv->complete = req->base.complete;
priv->data = req->base.data;
priv->flags = req->base.flags;

/*
* WARNING: We do not backup req->priv here! The req->priv
* is for internal use of the Crypto API and the
Expand All @@ -267,38 +270,44 @@ static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt)
return 0;
}

static void ahash_restore_req(struct ahash_request *req)
static void ahash_restore_req(struct ahash_request *req, int err)
{
struct ahash_request_priv *priv = req->priv;

if (!err)
memcpy(priv->result, req->result,
crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));

/* Restore the original crypto request. */
req->result = priv->result;
req->base.complete = priv->complete;
req->base.data = priv->data;

ahash_request_set_callback(req, priv->flags,
priv->complete, priv->data);
req->priv = NULL;

/* Free the req->priv.priv from the ADJUSTED request. */
kzfree(priv);
}

static void ahash_op_unaligned_finish(struct ahash_request *req, int err)
static void ahash_notify_einprogress(struct ahash_request *req)
{
struct ahash_request_priv *priv = req->priv;
struct crypto_async_request oreq;

if (err == -EINPROGRESS)
return;

if (!err)
memcpy(priv->result, req->result,
crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
oreq.data = priv->data;

ahash_restore_req(req);
priv->complete(&oreq, -EINPROGRESS);
}

static void ahash_op_unaligned_done(struct crypto_async_request *req, int err)
{
struct ahash_request *areq = req->data;

if (err == -EINPROGRESS) {
ahash_notify_einprogress(areq);
return;
}

/*
* Restore the original request, see ahash_op_unaligned() for what
* goes where.
Expand All @@ -309,7 +318,7 @@ static void ahash_op_unaligned_done(struct crypto_async_request *req, int err)
*/

/* First copy req->result into req->priv.result */
ahash_op_unaligned_finish(areq, err);
ahash_restore_req(areq, err);

/* Complete the ORIGINAL request. */
areq->base.complete(&areq->base, err);
Expand All @@ -325,7 +334,12 @@ static int ahash_op_unaligned(struct ahash_request *req,
return err;

err = op(req);
ahash_op_unaligned_finish(req, err);
if (err == -EINPROGRESS ||
(err == -EBUSY && (ahash_request_flags(req) &
CRYPTO_TFM_REQ_MAY_BACKLOG)))
return err;

ahash_restore_req(req, err);

return err;
}
Expand Down Expand Up @@ -360,25 +374,14 @@ int crypto_ahash_digest(struct ahash_request *req)
}
EXPORT_SYMBOL_GPL(crypto_ahash_digest);

static void ahash_def_finup_finish2(struct ahash_request *req, int err)
static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
{
struct ahash_request_priv *priv = req->priv;
struct ahash_request *areq = req->data;

if (err == -EINPROGRESS)
return;

if (!err)
memcpy(priv->result, req->result,
crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));

ahash_restore_req(req);
}

static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
{
struct ahash_request *areq = req->data;

ahash_def_finup_finish2(areq, err);
ahash_restore_req(areq, err);

areq->base.complete(&areq->base, err);
}
Expand All @@ -389,19 +392,32 @@ static int ahash_def_finup_finish1(struct ahash_request *req, int err)
goto out;

req->base.complete = ahash_def_finup_done2;
req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;

err = crypto_ahash_reqtfm(req)->final(req);
if (err == -EINPROGRESS ||
(err == -EBUSY && (ahash_request_flags(req) &
CRYPTO_TFM_REQ_MAY_BACKLOG)))
return err;

out:
ahash_def_finup_finish2(req, err);
ahash_restore_req(req, err);
return err;
}

static void ahash_def_finup_done1(struct crypto_async_request *req, int err)
{
struct ahash_request *areq = req->data;

if (err == -EINPROGRESS) {
ahash_notify_einprogress(areq);
return;
}

areq->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;

err = ahash_def_finup_finish1(areq, err);
if (areq->priv)
return;

areq->base.complete(&areq->base, err);
}
Expand All @@ -416,6 +432,11 @@ static int ahash_def_finup(struct ahash_request *req)
return err;

err = tfm->update(req);
if (err == -EINPROGRESS ||
(err == -EBUSY && (ahash_request_flags(req) &
CRYPTO_TFM_REQ_MAY_BACKLOG)))
return err;

return ahash_def_finup_finish1(req, err);
}

Expand Down
12 changes: 6 additions & 6 deletions crypto/algif_aead.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ struct aead_async_req {
struct aead_async_rsgl first_rsgl;
struct list_head list;
struct kiocb *iocb;
struct sock *sk;
unsigned int tsgls;
char iv[];
};
Expand Down Expand Up @@ -379,12 +380,10 @@ static ssize_t aead_sendpage(struct socket *sock, struct page *page,

static void aead_async_cb(struct crypto_async_request *_req, int err)
{
struct sock *sk = _req->data;
struct alg_sock *ask = alg_sk(sk);
struct aead_ctx *ctx = ask->private;
struct crypto_aead *tfm = crypto_aead_reqtfm(&ctx->aead_req);
struct aead_request *req = aead_request_cast(_req);
struct aead_request *req = _req->data;
struct crypto_aead *tfm = crypto_aead_reqtfm(req);
struct aead_async_req *areq = GET_ASYM_REQ(req, tfm);
struct sock *sk = areq->sk;
struct scatterlist *sg = areq->tsgl;
struct aead_async_rsgl *rsgl;
struct kiocb *iocb = areq->iocb;
Expand Down Expand Up @@ -447,11 +446,12 @@ static int aead_recvmsg_async(struct socket *sock, struct msghdr *msg,
memset(&areq->first_rsgl, '\0', sizeof(areq->first_rsgl));
INIT_LIST_HEAD(&areq->list);
areq->iocb = msg->msg_iocb;
areq->sk = sk;
memcpy(areq->iv, ctx->iv, crypto_aead_ivsize(tfm));
aead_request_set_tfm(req, tfm);
aead_request_set_ad(req, ctx->aead_assoclen);
aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
aead_async_cb, sk);
aead_async_cb, req);
used -= ctx->aead_assoclen;

/* take over all tx sgls from ctx */
Expand Down
16 changes: 16 additions & 0 deletions crypto/lrw.c
Original file line number Diff line number Diff line change
Expand Up @@ -345,13 +345,21 @@ static void encrypt_done(struct crypto_async_request *areq, int err)
struct rctx *rctx;

rctx = skcipher_request_ctx(req);

if (err == -EINPROGRESS) {
if (rctx->left != req->cryptlen)
return;
goto out;
}

subreq = &rctx->subreq;
subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;

err = do_encrypt(req, err ?: post_crypt(req));
if (rctx->left)
return;

out:
skcipher_request_complete(req, err);
}

Expand Down Expand Up @@ -389,13 +397,21 @@ static void decrypt_done(struct crypto_async_request *areq, int err)
struct rctx *rctx;

rctx = skcipher_request_ctx(req);

if (err == -EINPROGRESS) {
if (rctx->left != req->cryptlen)
return;
goto out;
}

subreq = &rctx->subreq;
subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;

err = do_decrypt(req, err ?: post_crypt(req));
if (rctx->left)
return;

out:
skcipher_request_complete(req, err);
}

Expand Down
16 changes: 16 additions & 0 deletions crypto/xts.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,13 +286,21 @@ static void encrypt_done(struct crypto_async_request *areq, int err)
struct rctx *rctx;

rctx = skcipher_request_ctx(req);

if (err == -EINPROGRESS) {
if (rctx->left != req->cryptlen)
return;
goto out;
}

subreq = &rctx->subreq;
subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;

err = do_encrypt(req, err ?: post_crypt(req));
if (rctx->left)
return;

out:
skcipher_request_complete(req, err);
}

Expand Down Expand Up @@ -330,13 +338,21 @@ static void decrypt_done(struct crypto_async_request *areq, int err)
struct rctx *rctx;

rctx = skcipher_request_ctx(req);

if (err == -EINPROGRESS) {
if (rctx->left != req->cryptlen)
return;
goto out;
}

subreq = &rctx->subreq;
subreq->base.flags &= CRYPTO_TFM_REQ_MAY_BACKLOG;

err = do_decrypt(req, err ?: post_crypt(req));
if (rctx->left)
return;

out:
skcipher_request_complete(req, err);
}

Expand Down
10 changes: 10 additions & 0 deletions include/crypto/internal/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,16 @@ static inline struct ahash_instance *ahash_alloc_instance(
return crypto_alloc_instance2(name, alg, ahash_instance_headroom());
}

static inline void ahash_request_complete(struct ahash_request *req, int err)
{
req->base.complete(&req->base, err);
}

static inline u32 ahash_request_flags(struct ahash_request *req)
{
return req->base.flags;
}

static inline struct crypto_ahash *crypto_spawn_ahash(
struct crypto_ahash_spawn *spawn)
{
Expand Down

0 comments on commit 5ee4c5a

Please sign in to comment.