From c6f8ea675c668ce8902e890da9b83f5644850738 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 14 Feb 2016 13:30:38 -0800 Subject: [PATCH] 4.3-stable patches added patches: crypto-af_alg-add-nokey-compatibility-path.patch crypto-af_alg-disallow-bind-setkey-...-after-accept-2.patch crypto-af_alg-fix-socket-double-free-when-accept-fails.patch crypto-algif_hash-require-setkey-before-accept-2.patch crypto-algif_skcipher-add-key-check-exception-for-cipher_null.patch crypto-algif_skcipher-add-nokey-compatibility-path.patch crypto-algif_skcipher-require-setkey-before-accept-2.patch crypto-hash-add-crypto_ahash_has_setkey.patch crypto-skcipher-add-crypto_skcipher_has_setkey.patch --- ...-af_alg-add-nokey-compatibility-path.patch | 82 +++++ ...allow-bind-setkey-...-after-accept-2.patch | 145 +++++++++ ...socket-double-free-when-accept-fails.patch | 37 +++ ..._hash-require-setkey-before-accept-2.patch | 286 ++++++++++++++++++ ...-key-check-exception-for-cipher_null.patch | 30 ++ ...kcipher-add-nokey-compatibility-path.patch | 214 +++++++++++++ ...ipher-require-setkey-before-accept-2.patch | 120 ++++++++ ...pto-hash-add-crypto_ahash_has_setkey.patch | 79 +++++ ...ipher-add-crypto_skcipher_has_setkey.patch | 61 ++++ queue-4.3/series | 9 + 10 files changed, 1063 insertions(+) create mode 100644 queue-4.3/crypto-af_alg-add-nokey-compatibility-path.patch create mode 100644 queue-4.3/crypto-af_alg-disallow-bind-setkey-...-after-accept-2.patch create mode 100644 queue-4.3/crypto-af_alg-fix-socket-double-free-when-accept-fails.patch create mode 100644 queue-4.3/crypto-algif_hash-require-setkey-before-accept-2.patch create mode 100644 queue-4.3/crypto-algif_skcipher-add-key-check-exception-for-cipher_null.patch create mode 100644 queue-4.3/crypto-algif_skcipher-add-nokey-compatibility-path.patch create mode 100644 queue-4.3/crypto-algif_skcipher-require-setkey-before-accept-2.patch create mode 100644 queue-4.3/crypto-hash-add-crypto_ahash_has_setkey.patch create mode 100644 queue-4.3/crypto-skcipher-add-crypto_skcipher_has_setkey.patch diff --git a/queue-4.3/crypto-af_alg-add-nokey-compatibility-path.patch b/queue-4.3/crypto-af_alg-add-nokey-compatibility-path.patch new file mode 100644 index 00000000000..60d6658ecb1 --- /dev/null +++ b/queue-4.3/crypto-af_alg-add-nokey-compatibility-path.patch @@ -0,0 +1,82 @@ +From 37766586c965d63758ad542325a96d5384f4a8c9 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Mon, 4 Jan 2016 13:35:18 +0900 +Subject: crypto: af_alg - Add nokey compatibility path + +From: Herbert Xu + +commit 37766586c965d63758ad542325a96d5384f4a8c9 upstream. + +This patch adds a compatibility path to support old applications +that do acept(2) before setkey. + +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + crypto/af_alg.c | 13 ++++++++++++- + include/crypto/if_alg.h | 2 ++ + 2 files changed, 14 insertions(+), 1 deletion(-) + +--- a/crypto/af_alg.c ++++ b/crypto/af_alg.c +@@ -76,6 +76,8 @@ int af_alg_register_type(const struct af + 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; +@@ -267,6 +269,7 @@ int af_alg_accept(struct sock *sk, struc + const struct af_alg_type *type; + struct sock *sk2; + int err; ++ bool nokey; + + lock_sock(sk); + type = ask->type; +@@ -285,12 +288,17 @@ int af_alg_accept(struct sock *sk, struc + security_sk_clone(sk, sk2); + + err = type->accept(ask->private, 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; + +- if (!ask->refcnt++) ++ if (nokey || !ask->refcnt++) + sock_hold(sk); + alg_sk(sk2)->parent = sk; + alg_sk(sk2)->type = type; +@@ -298,6 +306,9 @@ int af_alg_accept(struct sock *sk, struc + newsock->ops = type->ops; + newsock->state = SS_CONNECTED; + ++ if (nokey) ++ newsock->ops = type->ops_nokey; ++ + err = 0; + + unlock: +--- a/include/crypto/if_alg.h ++++ b/include/crypto/if_alg.h +@@ -52,9 +52,11 @@ struct af_alg_type { + void (*release)(void *private); + int (*setkey)(void *private, const u8 *key, unsigned int keylen); + int (*accept)(void *private, struct sock *sk); ++ int (*accept_nokey)(void *private, struct sock *sk); + int (*setauthsize)(void *private, unsigned int authsize); + + struct proto_ops *ops; ++ struct proto_ops *ops_nokey; + struct module *owner; + char name[14]; + }; diff --git a/queue-4.3/crypto-af_alg-disallow-bind-setkey-...-after-accept-2.patch b/queue-4.3/crypto-af_alg-disallow-bind-setkey-...-after-accept-2.patch new file mode 100644 index 00000000000..9ebb111bedd --- /dev/null +++ b/queue-4.3/crypto-af_alg-disallow-bind-setkey-...-after-accept-2.patch @@ -0,0 +1,145 @@ +From c840ac6af3f8713a71b4d2363419145760bd6044 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Wed, 30 Dec 2015 11:47:53 +0800 +Subject: crypto: af_alg - Disallow bind/setkey/... after accept(2) + +From: Herbert Xu + +commit c840ac6af3f8713a71b4d2363419145760bd6044 upstream. + +Each af_alg parent socket obtained by socket(2) corresponds to a +tfm object once bind(2) has succeeded. An accept(2) call on that +parent socket creates a context which then uses the tfm object. + +Therefore as long as any child sockets created by accept(2) exist +the parent socket must not be modified or freed. + +This patch guarantees this by using locks and a reference count +on the parent socket. Any attempt to modify the parent socket will +fail with EBUSY. + +Reported-by: Dmitry Vyukov +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + crypto/af_alg.c | 35 ++++++++++++++++++++++++++++++++--- + include/crypto/if_alg.h | 8 +++----- + 2 files changed, 35 insertions(+), 8 deletions(-) + +--- a/crypto/af_alg.c ++++ b/crypto/af_alg.c +@@ -125,6 +125,23 @@ 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); ++ bool last; ++ ++ sk = ask->parent; ++ ask = alg_sk(sk); ++ ++ lock_sock(sk); ++ 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; +@@ -133,6 +150,7 @@ static int alg_bind(struct socket *sock, + struct sockaddr_alg *sa = (void *)uaddr; + const struct af_alg_type *type; + void *private; ++ int err; + + if (sock->state == SS_CONNECTED) + return -EINVAL; +@@ -160,16 +178,22 @@ static int alg_bind(struct socket *sock, + return PTR_ERR(private); + } + ++ err = -EBUSY; + lock_sock(sk); ++ if (ask->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, +@@ -202,11 +226,15 @@ static int alg_setsockopt(struct socket + 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; + +@@ -264,7 +292,8 @@ int af_alg_accept(struct sock *sk, struc + + sk2->sk_family = PF_ALG; + +- sock_hold(sk); ++ if (!ask->refcnt++) ++ sock_hold(sk); + alg_sk(sk2)->parent = sk; + alg_sk(sk2)->type = type; + +--- a/include/crypto/if_alg.h ++++ b/include/crypto/if_alg.h +@@ -30,6 +30,8 @@ struct alg_sock { + + struct sock *parent; + ++ unsigned int refcnt; ++ + const struct af_alg_type *type; + void *private; + }; +@@ -67,6 +69,7 @@ int af_alg_register_type(const struct af + int af_alg_unregister_type(const struct af_alg_type *type); + + int af_alg_release(struct socket *sock); ++void af_alg_release_parent(struct sock *sk); + int af_alg_accept(struct sock *sk, struct socket *newsock); + + int af_alg_make_sg(struct af_alg_sgl *sgl, struct iov_iter *iter, int len); +@@ -83,11 +86,6 @@ static inline struct alg_sock *alg_sk(st + return (struct alg_sock *)sk; + } + +-static inline void af_alg_release_parent(struct sock *sk) +-{ +- sock_put(alg_sk(sk)->parent); +-} +- + static inline void af_alg_init_completion(struct af_alg_completion *completion) + { + init_completion(&completion->completion); diff --git a/queue-4.3/crypto-af_alg-fix-socket-double-free-when-accept-fails.patch b/queue-4.3/crypto-af_alg-fix-socket-double-free-when-accept-fails.patch new file mode 100644 index 00000000000..ec8bae4f199 --- /dev/null +++ b/queue-4.3/crypto-af_alg-fix-socket-double-free-when-accept-fails.patch @@ -0,0 +1,37 @@ +From a383292c86663bbc31ac62cc0c04fc77504636a6 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Wed, 30 Dec 2015 20:24:17 +0800 +Subject: crypto: af_alg - Fix socket double-free when accept fails + +From: Herbert Xu + +commit a383292c86663bbc31ac62cc0c04fc77504636a6 upstream. + +When we fail an accept(2) call we will end up freeing the socket +twice, once due to the direct sk_free call and once again through +newsock. + +This patch fixes this by removing the sk_free call. + +Reported-by: Dmitry Vyukov +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + crypto/af_alg.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/crypto/af_alg.c ++++ b/crypto/af_alg.c +@@ -285,10 +285,8 @@ int af_alg_accept(struct sock *sk, struc + security_sk_clone(sk, sk2); + + err = type->accept(ask->private, sk2); +- if (err) { +- sk_free(sk2); ++ if (err) + goto unlock; +- } + + sk2->sk_family = PF_ALG; + diff --git a/queue-4.3/crypto-algif_hash-require-setkey-before-accept-2.patch b/queue-4.3/crypto-algif_hash-require-setkey-before-accept-2.patch new file mode 100644 index 00000000000..788e147422a --- /dev/null +++ b/queue-4.3/crypto-algif_hash-require-setkey-before-accept-2.patch @@ -0,0 +1,286 @@ +From 6de62f15b581f920ade22d758f4c338311c2f0d4 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Fri, 8 Jan 2016 21:31:04 +0800 +Subject: crypto: algif_hash - Require setkey before accept(2) + +From: Herbert Xu + +commit 6de62f15b581f920ade22d758f4c338311c2f0d4 upstream. + +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. + +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + crypto/algif_hash.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 193 insertions(+), 8 deletions(-) + +--- a/crypto/algif_hash.c ++++ b/crypto/algif_hash.c +@@ -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 so + 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 *priv + + 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 *priv + 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 + }; diff --git a/queue-4.3/crypto-algif_skcipher-add-key-check-exception-for-cipher_null.patch b/queue-4.3/crypto-algif_skcipher-add-key-check-exception-for-cipher_null.patch new file mode 100644 index 00000000000..b69603d86a6 --- /dev/null +++ b/queue-4.3/crypto-algif_skcipher-add-key-check-exception-for-cipher_null.patch @@ -0,0 +1,30 @@ +From 6e8d8ecf438792ecf7a3207488fb4eebc4edb040 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Mon, 11 Jan 2016 21:29:41 +0800 +Subject: crypto: algif_skcipher - Add key check exception for cipher_null + +From: Herbert Xu + +commit 6e8d8ecf438792ecf7a3207488fb4eebc4edb040 upstream. + +This patch adds an exception to the key check so that cipher_null +users may continue to use algif_skcipher without setting a key. + +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + crypto/algif_skcipher.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -978,7 +978,7 @@ static int skcipher_accept_parent(void * + { + struct skcipher_tfm *tfm = private; + +- if (!tfm->has_key) ++ if (!tfm->has_key && crypto_skcipher_has_setkey(tfm->skcipher)) + return -ENOKEY; + + return skcipher_accept_parent_common(private, sk); diff --git a/queue-4.3/crypto-algif_skcipher-add-nokey-compatibility-path.patch b/queue-4.3/crypto-algif_skcipher-add-nokey-compatibility-path.patch new file mode 100644 index 00000000000..9cd4f7cb11e --- /dev/null +++ b/queue-4.3/crypto-algif_skcipher-add-nokey-compatibility-path.patch @@ -0,0 +1,214 @@ +From a0fa2d037129a9849918a92d91b79ed6c7bd2818 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Mon, 4 Jan 2016 13:36:12 +0900 +Subject: crypto: algif_skcipher - Add nokey compatibility path + +From: Herbert Xu + +commit a0fa2d037129a9849918a92d91b79ed6c7bd2818 upstream. + +This patch adds a compatibility path to support old applications +that do acept(2) before setkey. + +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + crypto/algif_skcipher.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 144 insertions(+), 5 deletions(-) + +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -753,6 +753,99 @@ static struct proto_ops algif_skcipher_o + .poll = skcipher_poll, + }; + ++static int skcipher_check_key(struct socket *sock) ++{ ++ int err; ++ struct sock *psk; ++ struct alg_sock *pask; ++ struct skcipher_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 skcipher_sendmsg_nokey(struct socket *sock, struct msghdr *msg, ++ size_t size) ++{ ++ int err; ++ ++ err = skcipher_check_key(sock); ++ if (err) ++ return err; ++ ++ return skcipher_sendmsg(sock, msg, size); ++} ++ ++static ssize_t skcipher_sendpage_nokey(struct socket *sock, struct page *page, ++ int offset, size_t size, int flags) ++{ ++ int err; ++ ++ err = skcipher_check_key(sock); ++ if (err) ++ return err; ++ ++ return skcipher_sendpage(sock, page, offset, size, flags); ++} ++ ++static int skcipher_recvmsg_nokey(struct socket *sock, struct msghdr *msg, ++ size_t ignored, int flags) ++{ ++ int err; ++ ++ err = skcipher_check_key(sock); ++ if (err) ++ return err; ++ ++ return skcipher_recvmsg(sock, msg, ignored, flags); ++} ++ ++static struct proto_ops algif_skcipher_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, ++ .accept = sock_no_accept, ++ .setsockopt = sock_no_setsockopt, ++ ++ .release = af_alg_release, ++ .sendmsg = skcipher_sendmsg_nokey, ++ .sendpage = skcipher_sendpage_nokey, ++ .recvmsg = skcipher_recvmsg_nokey, ++ .poll = skcipher_poll, ++}; ++ + static void *skcipher_bind(const char *name, u32 type, u32 mask) + { + struct skcipher_tfm *tfm; +@@ -802,7 +895,7 @@ static void skcipher_wait(struct sock *s + msleep(100); + } + +-static void skcipher_sock_destruct(struct sock *sk) ++static void skcipher_sock_destruct_common(struct sock *sk) + { + struct alg_sock *ask = alg_sk(sk); + struct skcipher_ctx *ctx = ask->private; +@@ -814,10 +907,33 @@ static void skcipher_sock_destruct(struc + skcipher_free_sgl(sk); + sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm)); + sock_kfree_s(sk, ctx, ctx->len); ++} ++ ++static void skcipher_sock_destruct(struct sock *sk) ++{ ++ skcipher_sock_destruct_common(sk); + af_alg_release_parent(sk); + } + +-static int skcipher_accept_parent(void *private, struct sock *sk) ++static void skcipher_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 skcipher_sock_destruct_nokey(struct sock *sk) ++{ ++ skcipher_sock_destruct_common(sk); ++ skcipher_release_parent_nokey(sk); ++} ++ ++static int skcipher_accept_parent_common(void *private, struct sock *sk) + { + struct skcipher_ctx *ctx; + struct alg_sock *ask = alg_sk(sk); +@@ -825,9 +941,6 @@ static int skcipher_accept_parent(void * + 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; +@@ -861,12 +974,38 @@ static int skcipher_accept_parent(void * + return 0; + } + ++static int skcipher_accept_parent(void *private, struct sock *sk) ++{ ++ struct skcipher_tfm *tfm = private; ++ ++ if (!tfm->has_key) ++ return -ENOKEY; ++ ++ return skcipher_accept_parent_common(private, sk); ++} ++ ++static int skcipher_accept_parent_nokey(void *private, struct sock *sk) ++{ ++ int err; ++ ++ err = skcipher_accept_parent_common(private, sk); ++ if (err) ++ goto out; ++ ++ sk->sk_destruct = skcipher_sock_destruct_nokey; ++ ++out: ++ return err; ++} ++ + static const struct af_alg_type algif_type_skcipher = { + .bind = skcipher_bind, + .release = skcipher_release, + .setkey = skcipher_setkey, + .accept = skcipher_accept_parent, ++ .accept_nokey = skcipher_accept_parent_nokey, + .ops = &algif_skcipher_ops, ++ .ops_nokey = &algif_skcipher_ops_nokey, + .name = "skcipher", + .owner = THIS_MODULE + }; diff --git a/queue-4.3/crypto-algif_skcipher-require-setkey-before-accept-2.patch b/queue-4.3/crypto-algif_skcipher-require-setkey-before-accept-2.patch new file mode 100644 index 00000000000..39f395222b7 --- /dev/null +++ b/queue-4.3/crypto-algif_skcipher-require-setkey-before-accept-2.patch @@ -0,0 +1,120 @@ +From dd504589577d8e8e70f51f997ad487a4cb6c026f Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Fri, 25 Dec 2015 15:40:05 +0800 +Subject: crypto: algif_skcipher - Require setkey before accept(2) + +From: Herbert Xu + +commit dd504589577d8e8e70f51f997ad487a4cb6c026f upstream. + +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. + +Reported-by: Dmitry Vyukov +Signed-off-by: Herbert Xu +Tested-by: Dmitry Vyukov +Signed-off-by: Greg Kroah-Hartman + +--- + crypto/algif_skcipher.c | 48 +++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 41 insertions(+), 7 deletions(-) + +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -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; +@@ -750,17 +755,41 @@ static struct proto_ops algif_skcipher_o + + 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) +@@ -792,20 +821,25 @@ static int skcipher_accept_parent(void * + { + 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; +@@ -818,7 +852,7 @@ static int skcipher_accept_parent(void * + + 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); + diff --git a/queue-4.3/crypto-hash-add-crypto_ahash_has_setkey.patch b/queue-4.3/crypto-hash-add-crypto_ahash_has_setkey.patch new file mode 100644 index 00000000000..790174dec5b --- /dev/null +++ b/queue-4.3/crypto-hash-add-crypto_ahash_has_setkey.patch @@ -0,0 +1,79 @@ +From a5596d6332787fd383b3b5427b41f94254430827 Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Fri, 8 Jan 2016 21:28:26 +0800 +Subject: crypto: hash - Add crypto_ahash_has_setkey + +From: Herbert Xu + +commit a5596d6332787fd383b3b5427b41f94254430827 upstream. + +This patch adds a way for ahash users to determine whether a key +is required by a crypto_ahash transform. + +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + crypto/ahash.c | 5 ++++- + crypto/shash.c | 4 +++- + include/crypto/hash.h | 6 ++++++ + 3 files changed, 13 insertions(+), 2 deletions(-) + +--- a/crypto/ahash.c ++++ b/crypto/ahash.c +@@ -451,6 +451,7 @@ static int crypto_ahash_init_tfm(struct + 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; + +@@ -463,8 +464,10 @@ static int crypto_ahash_init_tfm(struct + 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) +--- a/crypto/shash.c ++++ b/crypto/shash.c +@@ -355,8 +355,10 @@ int crypto_init_shash_ops_async(struct c + crt->finup = shash_async_finup; + crt->digest = shash_async_digest; + +- if (alg->setkey) ++ if (alg->setkey) { + crt->setkey = shash_async_setkey; ++ crt->has_setkey = true; ++ } + if (alg->export) + crt->export = shash_async_export; + if (alg->import) +--- a/include/crypto/hash.h ++++ b/include/crypto/hash.h +@@ -204,6 +204,7 @@ struct crypto_ahash { + unsigned int keylen); + + unsigned int reqsize; ++ bool has_setkey; + struct crypto_tfm base; + }; + +@@ -361,6 +362,11 @@ static inline void *ahash_request_ctx(st + int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, + unsigned int keylen); + ++static inline bool crypto_ahash_has_setkey(struct crypto_ahash *tfm) ++{ ++ return tfm->has_setkey; ++} ++ + /** + * crypto_ahash_finup() - update and finalize message digest + * @req: reference to the ahash_request handle that holds all information diff --git a/queue-4.3/crypto-skcipher-add-crypto_skcipher_has_setkey.patch b/queue-4.3/crypto-skcipher-add-crypto_skcipher_has_setkey.patch new file mode 100644 index 00000000000..f32731b937e --- /dev/null +++ b/queue-4.3/crypto-skcipher-add-crypto_skcipher_has_setkey.patch @@ -0,0 +1,61 @@ +From a1383cd86a062fc798899ab20f0ec2116cce39cb Mon Sep 17 00:00:00 2001 +From: Herbert Xu +Date: Mon, 11 Jan 2016 21:26:50 +0800 +Subject: crypto: skcipher - Add crypto_skcipher_has_setkey + +From: Herbert Xu + +commit a1383cd86a062fc798899ab20f0ec2116cce39cb upstream. + +This patch adds a way for skcipher users to determine whether a key +is required by a transform. + +Signed-off-by: Herbert Xu +Signed-off-by: Greg Kroah-Hartman + +--- + crypto/skcipher.c | 2 ++ + include/crypto/skcipher.h | 7 +++++++ + 2 files changed, 9 insertions(+) + +--- a/crypto/skcipher.c ++++ b/crypto/skcipher.c +@@ -118,6 +118,7 @@ int crypto_init_skcipher_ops_blkcipher(s + skcipher->decrypt = skcipher_decrypt_blkcipher; + + skcipher->ivsize = crypto_blkcipher_ivsize(blkcipher); ++ skcipher->has_setkey = calg->cra_blkcipher.max_keysize; + + return 0; + } +@@ -210,6 +211,7 @@ int crypto_init_skcipher_ops_ablkcipher( + skcipher->ivsize = crypto_ablkcipher_ivsize(ablkcipher); + skcipher->reqsize = crypto_ablkcipher_reqsize(ablkcipher) + + sizeof(struct ablkcipher_request); ++ skcipher->has_setkey = calg->cra_ablkcipher.max_keysize; + + return 0; + } +--- a/include/crypto/skcipher.h ++++ b/include/crypto/skcipher.h +@@ -61,6 +61,8 @@ struct crypto_skcipher { + unsigned int ivsize; + unsigned int reqsize; + ++ bool has_setkey; ++ + struct crypto_tfm base; + }; + +@@ -305,6 +307,11 @@ static inline int crypto_skcipher_setkey + return tfm->setkey(tfm, key, keylen); + } + ++static inline bool crypto_skcipher_has_setkey(struct crypto_skcipher *tfm) ++{ ++ return tfm->has_setkey; ++} ++ + /** + * crypto_skcipher_reqtfm() - obtain cipher handle from request + * @req: skcipher_request out of which the cipher handle is to be obtained diff --git a/queue-4.3/series b/queue-4.3/series index db4eda68007..bcdb2951f08 100644 --- a/queue-4.3/series +++ b/queue-4.3/series @@ -154,3 +154,12 @@ ext4-fix-handling-of-extended-tv_sec.patch ext4-fix-an-endianness-bug-in-ext4_encrypted_zeroout.patch ext4-fix-an-endianness-bug-in-ext4_encrypted_follow_link.patch sched-fix-crash-in-sched_init_numa.patch +crypto-algif_skcipher-require-setkey-before-accept-2.patch +crypto-af_alg-disallow-bind-setkey-...-after-accept-2.patch +crypto-af_alg-fix-socket-double-free-when-accept-fails.patch +crypto-af_alg-add-nokey-compatibility-path.patch +crypto-algif_skcipher-add-nokey-compatibility-path.patch +crypto-hash-add-crypto_ahash_has_setkey.patch +crypto-algif_hash-require-setkey-before-accept-2.patch +crypto-skcipher-add-crypto_skcipher_has_setkey.patch +crypto-algif_skcipher-add-key-check-exception-for-cipher_null.patch -- 2.47.3