FAILED: patch "[PATCH] crypto: algif_hash - Require setkey before accept(2)" failed to apply to 3.10-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 3.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
Quoted 1 line
From
6de62f15b581f920ade22d758f4c338311c2f0d4Mon Sep 17 00:00:00 2001
From: Herbert Xu <[email protected]>
Date: Fri, 8 Jan 2016 21:31:04 +0800
Subject: [PATCH] crypto: algif_hash - Require setkey before accept(2)
Hash implementations that require a key may crash if you use them without setting a key. This patch adds the necessary checks so that if you do attempt to use them without a key that we return -ENOKEY instead of proceeding.
This patch also adds a compatibility path to support old applications that do acept(2) before setkey.
crypto/algif_hash.c +193 -8
@@ -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) {
@@ -235,22 +240,151 @@ static struct proto_ops algif_hash_ops = { .accept = hash_accept, }; +static int hash_check_key (struct socket *sock) +{ +int err; +struct sock *psk; +struct alg_sock *pask; +struct algif_hash_tfm *tfm; +struct sock *sk = sock->sk; +struct alg_sock *ask =alg_sk (sk); + +if (ask->refcnt) +return 0 ; + + psk = ask->parent; + pask =alg_sk (ask->parent); + tfm = pask->private; + + err = -ENOKEY ; +lock_sock (psk); +if (!tfm->has_key) + goto unlock; + +if (!pask->refcnt++) +sock_hold (psk); + + ask->refcnt =1 ; +sock_put (psk); + + err =0 ; + +unlock: +release_sock (psk); + +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) +static void hash_sock_destruct_common (struct sock *sk) {struct alg_sock *ask =alg_sk (sk);struct hash_ctx *ctx = ask->private;
@@ -258,15 +392,40 @@ static void hash_sock_destruct(struct sock *sk)sock_kzfree_s (sk, ctx->result,crypto_ahash_digestsize (crypto_ahash_reqtfm (&ctx->req)));sock_kfree_s (sk, ctx, ctx->len); +} + +static void hash_sock_destruct (struct sock *sk) +{ +hash_sock_destruct_common (sk);af_alg_release_parent (sk); } -static int hash_accept_parent (void *private,struct sock *sk) +static void hash_release_parent_nokey (struct sock *sk) +{ +struct alg_sock *ask =alg_sk (sk); + +if (!ask->refcnt) { +sock_put (ask->parent); +return ; + } + +af_alg_release_parent (sk); +} + +static void hash_sock_destruct_nokey (struct sock *sk) +{ +hash_sock_destruct_common (sk); +hash_release_parent_nokey (sk); +} + +static int hash_accept_parent_common (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)
@@ -286,7 +445,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);
@@ -295,12 +454,38 @@ 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_common (private, sk); +} + +static int hash_accept_parent_nokey (void *private,struct sock *sk) +{ +int err; + + err =hash_accept_parent_common (private, sk); +if (err) + goto out; + + sk->sk_destruct = hash_sock_destruct_nokey; + +out: +return err; +} +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 };