]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.3-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 14 Feb 2016 21:30:38 +0000 (13:30 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 14 Feb 2016 21:30:38 +0000 (13:30 -0800)
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

queue-4.3/crypto-af_alg-add-nokey-compatibility-path.patch [new file with mode: 0644]
queue-4.3/crypto-af_alg-disallow-bind-setkey-...-after-accept-2.patch [new file with mode: 0644]
queue-4.3/crypto-af_alg-fix-socket-double-free-when-accept-fails.patch [new file with mode: 0644]
queue-4.3/crypto-algif_hash-require-setkey-before-accept-2.patch [new file with mode: 0644]
queue-4.3/crypto-algif_skcipher-add-key-check-exception-for-cipher_null.patch [new file with mode: 0644]
queue-4.3/crypto-algif_skcipher-add-nokey-compatibility-path.patch [new file with mode: 0644]
queue-4.3/crypto-algif_skcipher-require-setkey-before-accept-2.patch [new file with mode: 0644]
queue-4.3/crypto-hash-add-crypto_ahash_has_setkey.patch [new file with mode: 0644]
queue-4.3/crypto-skcipher-add-crypto_skcipher_has_setkey.patch [new file with mode: 0644]
queue-4.3/series

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 (file)
index 0000000..60d6658
--- /dev/null
@@ -0,0 +1,82 @@
+From 37766586c965d63758ad542325a96d5384f4a8c9 Mon Sep 17 00:00:00 2001
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Mon, 4 Jan 2016 13:35:18 +0900
+Subject: crypto: af_alg - Add nokey compatibility path
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+commit 37766586c965d63758ad542325a96d5384f4a8c9 upstream.
+
+This patch adds a compatibility path to support old applications
+that do acept(2) before setkey.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..9ebb111
--- /dev/null
@@ -0,0 +1,145 @@
+From c840ac6af3f8713a71b4d2363419145760bd6044 Mon Sep 17 00:00:00 2001
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Wed, 30 Dec 2015 11:47:53 +0800
+Subject: crypto: af_alg - Disallow bind/setkey/... after accept(2)
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+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 <dvyukov@google.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..ec8bae4
--- /dev/null
@@ -0,0 +1,37 @@
+From a383292c86663bbc31ac62cc0c04fc77504636a6 Mon Sep 17 00:00:00 2001
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Wed, 30 Dec 2015 20:24:17 +0800
+Subject: crypto: af_alg - Fix socket double-free when accept fails
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+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 <dvyukov@google.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..788e147
--- /dev/null
@@ -0,0 +1,286 @@
+From 6de62f15b581f920ade22d758f4c338311c2f0d4 Mon Sep 17 00:00:00 2001
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Fri, 8 Jan 2016 21:31:04 +0800
+Subject: crypto: algif_hash - Require setkey before accept(2)
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+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 <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..b69603d
--- /dev/null
@@ -0,0 +1,30 @@
+From 6e8d8ecf438792ecf7a3207488fb4eebc4edb040 Mon Sep 17 00:00:00 2001
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Mon, 11 Jan 2016 21:29:41 +0800
+Subject: crypto: algif_skcipher - Add key check exception for cipher_null
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+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 <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..9cd4f7c
--- /dev/null
@@ -0,0 +1,214 @@
+From a0fa2d037129a9849918a92d91b79ed6c7bd2818 Mon Sep 17 00:00:00 2001
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Mon, 4 Jan 2016 13:36:12 +0900
+Subject: crypto: algif_skcipher - Add nokey compatibility path
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+commit a0fa2d037129a9849918a92d91b79ed6c7bd2818 upstream.
+
+This patch adds a compatibility path to support old applications
+that do acept(2) before setkey.
+
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..39f3952
--- /dev/null
@@ -0,0 +1,120 @@
+From dd504589577d8e8e70f51f997ad487a4cb6c026f Mon Sep 17 00:00:00 2001
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Fri, 25 Dec 2015 15:40:05 +0800
+Subject: crypto: algif_skcipher - Require setkey before accept(2)
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+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 <dvyukov@google.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Tested-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..790174d
--- /dev/null
@@ -0,0 +1,79 @@
+From a5596d6332787fd383b3b5427b41f94254430827 Mon Sep 17 00:00:00 2001
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Fri, 8 Jan 2016 21:28:26 +0800
+Subject: crypto: hash - Add crypto_ahash_has_setkey
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+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 <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..f32731b
--- /dev/null
@@ -0,0 +1,61 @@
+From a1383cd86a062fc798899ab20f0ec2116cce39cb Mon Sep 17 00:00:00 2001
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Mon, 11 Jan 2016 21:26:50 +0800
+Subject: crypto: skcipher - Add crypto_skcipher_has_setkey
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+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 <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
index db4eda68007c5f16f403795ec6c506b116d49dda..bcdb2951f08d4d8f0e4205a9cca46b89b38bac93 100644 (file)
@@ -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