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 issues:

  API:
   - A large number of bug fixes for the af_alg interface, credit goes
     to Dmitry Vyukov for discovering and reporting these issues.

  Algorithms:
   - sw842 needs to select crc32.
   - The soft dependency on crc32c is now in the correct spot.

  Drivers:
   - The atmel AES driver needs HAS_DMA.
   - The atmel AES driver was a missing break statement, fortunately
     it's only a debug function.
   - A number of bug fixes for the Intel qat driver"

* 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: (24 commits)
  crypto: algif_skcipher - sendmsg SG marking is off by one
  crypto: crc32c - Fix crc32c soft dependency
  crypto: algif_skcipher - Load TX SG list after waiting
  crypto: atmel-aes - Add missing break to atmel_aes_reg_name
  crypto: algif_skcipher - Fix race condition in skcipher_check_key
  crypto: algif_hash - Fix race condition in hash_check_key
  crypto: CRYPTO_DEV_ATMEL_AES should depend on HAS_DMA
  lib: sw842: select crc32
  crypto: af_alg - Forbid bind(2) when nokey child sockets are present
  crypto: algif_skcipher - Remove custom release parent function
  crypto: algif_hash - Remove custom release parent function
  crypto: af_alg - Allow af_af_alg_release_parent to be called on nokey path
  crypto: qat - update init_esram for C3xxx dev type
  crypto: qat - fix timeout issues
  crypto: qat - remove to call get_sram_bar_id for qat_c3xxx
  crypto: algif_skcipher - Add key check exception for cipher_null
  crypto: skcipher - Add crypto_skcipher_has_setkey
  crypto: algif_hash - Require setkey before accept(2)
  crypto: hash - Add crypto_ahash_has_setkey
  crypto: algif_skcipher - Add nokey compatibility path
  ...
  • Loading branch information
torvalds committed Jan 22, 2016
2 parents e7cc3ed + 202736d commit 48162a2
Show file tree
Hide file tree
Showing 15 changed files with 411 additions and 45 deletions.
55 changes: 49 additions & 6 deletions crypto/af_alg.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ int af_alg_register_type(const struct af_alg_type *type)
goto unlock;

type->ops->owner = THIS_MODULE;
if (type->ops_nokey)
type->ops_nokey->owner = THIS_MODULE;
node->type = type;
list_add(&node->list, &alg_types);
err = 0;
Expand Down Expand Up @@ -125,6 +127,26 @@ int af_alg_release(struct socket *sock)
}
EXPORT_SYMBOL_GPL(af_alg_release);

void af_alg_release_parent(struct sock *sk)
{
struct alg_sock *ask = alg_sk(sk);
unsigned int nokey = ask->nokey_refcnt;
bool last = nokey && !ask->refcnt;

sk = ask->parent;
ask = alg_sk(sk);

lock_sock(sk);
ask->nokey_refcnt -= nokey;
if (!last)
last = !--ask->refcnt;
release_sock(sk);

if (last)
sock_put(sk);
}
EXPORT_SYMBOL_GPL(af_alg_release_parent);

static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
const u32 forbidden = CRYPTO_ALG_INTERNAL;
Expand All @@ -133,6 +155,7 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct sockaddr_alg *sa = (void *)uaddr;
const struct af_alg_type *type;
void *private;
int err;

if (sock->state == SS_CONNECTED)
return -EINVAL;
Expand Down Expand Up @@ -160,16 +183,22 @@ static int alg_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
return PTR_ERR(private);
}

err = -EBUSY;
lock_sock(sk);
if (ask->refcnt | ask->nokey_refcnt)
goto unlock;

swap(ask->type, type);
swap(ask->private, private);

err = 0;

unlock:
release_sock(sk);

alg_do_release(type, private);

return 0;
return err;
}

static int alg_setkey(struct sock *sk, char __user *ukey,
Expand Down Expand Up @@ -202,11 +231,15 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
struct sock *sk = sock->sk;
struct alg_sock *ask = alg_sk(sk);
const struct af_alg_type *type;
int err = -ENOPROTOOPT;
int err = -EBUSY;

lock_sock(sk);
if (ask->refcnt)
goto unlock;

type = ask->type;

err = -ENOPROTOOPT;
if (level != SOL_ALG || !type)
goto unlock;

Expand Down Expand Up @@ -238,6 +271,7 @@ int af_alg_accept(struct sock *sk, struct socket *newsock)
struct alg_sock *ask = alg_sk(sk);
const struct af_alg_type *type;
struct sock *sk2;
unsigned int nokey;
int err;

lock_sock(sk);
Expand All @@ -257,20 +291,29 @@ int af_alg_accept(struct sock *sk, struct socket *newsock)
security_sk_clone(sk, sk2);

err = type->accept(ask->private, sk2);
if (err) {
sk_free(sk2);

nokey = err == -ENOKEY;
if (nokey && type->accept_nokey)
err = type->accept_nokey(ask->private, sk2);

if (err)
goto unlock;
}

sk2->sk_family = PF_ALG;

sock_hold(sk);
if (nokey || !ask->refcnt++)
sock_hold(sk);
ask->nokey_refcnt += nokey;
alg_sk(sk2)->parent = sk;
alg_sk(sk2)->type = type;
alg_sk(sk2)->nokey_refcnt = nokey;

newsock->ops = type->ops;
newsock->state = SS_CONNECTED;

if (nokey)
newsock->ops = type->ops_nokey;

err = 0;

unlock:
Expand Down
5 changes: 4 additions & 1 deletion crypto/ahash.c
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
struct ahash_alg *alg = crypto_ahash_alg(hash);

hash->setkey = ahash_nosetkey;
hash->has_setkey = false;
hash->export = ahash_no_export;
hash->import = ahash_no_import;

Expand All @@ -463,8 +464,10 @@ static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
hash->finup = alg->finup ?: ahash_def_finup;
hash->digest = alg->digest;

if (alg->setkey)
if (alg->setkey) {
hash->setkey = alg->setkey;
hash->has_setkey = true;
}
if (alg->export)
hash->export = alg->export;
if (alg->import)
Expand Down
165 changes: 158 additions & 7 deletions crypto/algif_hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ struct hash_ctx {
struct ahash_request req;
};

struct algif_hash_tfm {
struct crypto_ahash *hash;
bool has_key;
};

static int hash_sendmsg(struct socket *sock, struct msghdr *msg,
size_t ignored)
{
Expand Down Expand Up @@ -235,19 +240,151 @@ static struct proto_ops algif_hash_ops = {
.accept = hash_accept,
};

static int hash_check_key(struct socket *sock)
{
int err = 0;
struct sock *psk;
struct alg_sock *pask;
struct algif_hash_tfm *tfm;
struct sock *sk = sock->sk;
struct alg_sock *ask = alg_sk(sk);

lock_sock(sk);
if (ask->refcnt)
goto unlock_child;

psk = ask->parent;
pask = alg_sk(ask->parent);
tfm = pask->private;

err = -ENOKEY;
lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
if (!tfm->has_key)
goto unlock;

if (!pask->refcnt++)
sock_hold(psk);

ask->refcnt = 1;
sock_put(psk);

err = 0;

unlock:
release_sock(psk);
unlock_child:
release_sock(sk);

return err;
}

static int hash_sendmsg_nokey(struct socket *sock, struct msghdr *msg,
size_t size)
{
int err;

err = hash_check_key(sock);
if (err)
return err;

return hash_sendmsg(sock, msg, size);
}

static ssize_t hash_sendpage_nokey(struct socket *sock, struct page *page,
int offset, size_t size, int flags)
{
int err;

err = hash_check_key(sock);
if (err)
return err;

return hash_sendpage(sock, page, offset, size, flags);
}

static int hash_recvmsg_nokey(struct socket *sock, struct msghdr *msg,
size_t ignored, int flags)
{
int err;

err = hash_check_key(sock);
if (err)
return err;

return hash_recvmsg(sock, msg, ignored, flags);
}

static int hash_accept_nokey(struct socket *sock, struct socket *newsock,
int flags)
{
int err;

err = hash_check_key(sock);
if (err)
return err;

return hash_accept(sock, newsock, flags);
}

static struct proto_ops algif_hash_ops_nokey = {
.family = PF_ALG,

.connect = sock_no_connect,
.socketpair = sock_no_socketpair,
.getname = sock_no_getname,
.ioctl = sock_no_ioctl,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
.getsockopt = sock_no_getsockopt,
.mmap = sock_no_mmap,
.bind = sock_no_bind,
.setsockopt = sock_no_setsockopt,
.poll = sock_no_poll,

.release = af_alg_release,
.sendmsg = hash_sendmsg_nokey,
.sendpage = hash_sendpage_nokey,
.recvmsg = hash_recvmsg_nokey,
.accept = hash_accept_nokey,
};

static void *hash_bind(const char *name, u32 type, u32 mask)
{
return crypto_alloc_ahash(name, type, mask);
struct algif_hash_tfm *tfm;
struct crypto_ahash *hash;

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

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

tfm->hash = hash;

return tfm;
}

static void hash_release(void *private)
{
crypto_free_ahash(private);
struct algif_hash_tfm *tfm = private;

crypto_free_ahash(tfm->hash);
kfree(tfm);
}

static int hash_setkey(void *private, const u8 *key, unsigned int keylen)
{
return crypto_ahash_setkey(private, key, keylen);
struct algif_hash_tfm *tfm = private;
int err;

err = crypto_ahash_setkey(tfm->hash, key, keylen);
tfm->has_key = !err;

return err;
}

static void hash_sock_destruct(struct sock *sk)
Expand All @@ -261,12 +398,14 @@ static void hash_sock_destruct(struct sock *sk)
af_alg_release_parent(sk);
}

static int hash_accept_parent(void *private, struct sock *sk)
static int hash_accept_parent_nokey(void *private, struct sock *sk)
{
struct hash_ctx *ctx;
struct alg_sock *ask = alg_sk(sk);
unsigned len = sizeof(*ctx) + crypto_ahash_reqsize(private);
unsigned ds = crypto_ahash_digestsize(private);
struct algif_hash_tfm *tfm = private;
struct crypto_ahash *hash = tfm->hash;
unsigned len = sizeof(*ctx) + crypto_ahash_reqsize(hash);
unsigned ds = crypto_ahash_digestsize(hash);

ctx = sock_kmalloc(sk, len, GFP_KERNEL);
if (!ctx)
Expand All @@ -286,7 +425,7 @@ static int hash_accept_parent(void *private, struct sock *sk)

ask->private = ctx;

ahash_request_set_tfm(&ctx->req, private);
ahash_request_set_tfm(&ctx->req, hash);
ahash_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
af_alg_complete, &ctx->completion);

Expand All @@ -295,12 +434,24 @@ static int hash_accept_parent(void *private, struct sock *sk)
return 0;
}

static int hash_accept_parent(void *private, struct sock *sk)
{
struct algif_hash_tfm *tfm = private;

if (!tfm->has_key && crypto_ahash_has_setkey(tfm->hash))
return -ENOKEY;

return hash_accept_parent_nokey(private, sk);
}

static const struct af_alg_type algif_type_hash = {
.bind = hash_bind,
.release = hash_release,
.setkey = hash_setkey,
.accept = hash_accept_parent,
.accept_nokey = hash_accept_parent_nokey,
.ops = &algif_hash_ops,
.ops_nokey = &algif_hash_ops_nokey,
.name = "hash",
.owner = THIS_MODULE
};
Expand Down
Loading

0 comments on commit 48162a2

Please sign in to comment.