Skip to content

Commit

Permalink
crypto: algif_skcipher - Require setkey before accept(2)
Browse files Browse the repository at this point in the history
Some cipher implementations will crash if you try to use them
without calling setkey first.  This patch adds a check so that
the accept(2) call will fail with -ENOKEY if setkey hasn't been
done on the socket yet.

Cc: stable@vger.kernel.org
Reported-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Tested-by: Dmitry Vyukov <dvyukov@google.com>
  • Loading branch information
Herbert Xu committed Jan 18, 2016
1 parent c597b6b commit dd50458
Showing 1 changed file with 41 additions and 7 deletions.
48 changes: 41 additions & 7 deletions crypto/algif_skcipher.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ struct skcipher_sg_list {
struct scatterlist sg[0];
};

struct skcipher_tfm {
struct crypto_skcipher *skcipher;
bool has_key;
};

struct skcipher_ctx {
struct list_head tsgl;
struct af_alg_sgl rsgl;
Expand Down Expand Up @@ -750,17 +755,41 @@ static struct proto_ops algif_skcipher_ops = {

static void *skcipher_bind(const char *name, u32 type, u32 mask)
{
return crypto_alloc_skcipher(name, type, mask);
struct skcipher_tfm *tfm;
struct crypto_skcipher *skcipher;

tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
if (!tfm)
return ERR_PTR(-ENOMEM);

skcipher = crypto_alloc_skcipher(name, type, mask);
if (IS_ERR(skcipher)) {
kfree(tfm);
return ERR_CAST(skcipher);
}

tfm->skcipher = skcipher;

return tfm;
}

static void skcipher_release(void *private)
{
crypto_free_skcipher(private);
struct skcipher_tfm *tfm = private;

crypto_free_skcipher(tfm->skcipher);
kfree(tfm);
}

static int skcipher_setkey(void *private, const u8 *key, unsigned int keylen)
{
return crypto_skcipher_setkey(private, key, keylen);
struct skcipher_tfm *tfm = private;
int err;

err = crypto_skcipher_setkey(tfm->skcipher, key, keylen);
tfm->has_key = !err;

return err;
}

static void skcipher_wait(struct sock *sk)
Expand Down Expand Up @@ -792,20 +821,25 @@ static int skcipher_accept_parent(void *private, struct sock *sk)
{
struct skcipher_ctx *ctx;
struct alg_sock *ask = alg_sk(sk);
unsigned int len = sizeof(*ctx) + crypto_skcipher_reqsize(private);
struct skcipher_tfm *tfm = private;
struct crypto_skcipher *skcipher = tfm->skcipher;
unsigned int len = sizeof(*ctx) + crypto_skcipher_reqsize(skcipher);

if (!tfm->has_key)
return -ENOKEY;

ctx = sock_kmalloc(sk, len, GFP_KERNEL);
if (!ctx)
return -ENOMEM;

ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(private),
ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(skcipher),
GFP_KERNEL);
if (!ctx->iv) {
sock_kfree_s(sk, ctx, len);
return -ENOMEM;
}

memset(ctx->iv, 0, crypto_skcipher_ivsize(private));
memset(ctx->iv, 0, crypto_skcipher_ivsize(skcipher));

INIT_LIST_HEAD(&ctx->tsgl);
ctx->len = len;
Expand All @@ -818,7 +852,7 @@ static int skcipher_accept_parent(void *private, struct sock *sk)

ask->private = ctx;

skcipher_request_set_tfm(&ctx->req, private);
skcipher_request_set_tfm(&ctx->req, skcipher);
skcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
af_alg_complete, &ctx->completion);

Expand Down

0 comments on commit dd50458

Please sign in to comment.