diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2016-01-03 23:36:12 -0500 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2016-01-18 05:16:11 -0500 |
commit | a0fa2d037129a9849918a92d91b79ed6c7bd2818 (patch) | |
tree | f47b94a584d539028ef941f261c1ea2ce15a7d68 | |
parent | 37766586c965d63758ad542325a96d5384f4a8c9 (diff) |
crypto: algif_skcipher - Add nokey compatibility path
This patch adds a compatibility path to support old applications
that do acept(2) before setkey.
Cc: stable@vger.kernel.org
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r-- | crypto/algif_skcipher.c | 149 |
1 files changed, 144 insertions, 5 deletions
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index f4431bc1ce43..110bab499e43 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c | |||
@@ -753,6 +753,99 @@ static struct proto_ops algif_skcipher_ops = { | |||
753 | .poll = skcipher_poll, | 753 | .poll = skcipher_poll, |
754 | }; | 754 | }; |
755 | 755 | ||
756 | static int skcipher_check_key(struct socket *sock) | ||
757 | { | ||
758 | int err; | ||
759 | struct sock *psk; | ||
760 | struct alg_sock *pask; | ||
761 | struct skcipher_tfm *tfm; | ||
762 | struct sock *sk = sock->sk; | ||
763 | struct alg_sock *ask = alg_sk(sk); | ||
764 | |||
765 | if (ask->refcnt) | ||
766 | return 0; | ||
767 | |||
768 | psk = ask->parent; | ||
769 | pask = alg_sk(ask->parent); | ||
770 | tfm = pask->private; | ||
771 | |||
772 | err = -ENOKEY; | ||
773 | lock_sock(psk); | ||
774 | if (!tfm->has_key) | ||
775 | goto unlock; | ||
776 | |||
777 | if (!pask->refcnt++) | ||
778 | sock_hold(psk); | ||
779 | |||
780 | ask->refcnt = 1; | ||
781 | sock_put(psk); | ||
782 | |||
783 | err = 0; | ||
784 | |||
785 | unlock: | ||
786 | release_sock(psk); | ||
787 | |||
788 | return err; | ||
789 | } | ||
790 | |||
791 | static int skcipher_sendmsg_nokey(struct socket *sock, struct msghdr *msg, | ||
792 | size_t size) | ||
793 | { | ||
794 | int err; | ||
795 | |||
796 | err = skcipher_check_key(sock); | ||
797 | if (err) | ||
798 | return err; | ||
799 | |||
800 | return skcipher_sendmsg(sock, msg, size); | ||
801 | } | ||
802 | |||
803 | static ssize_t skcipher_sendpage_nokey(struct socket *sock, struct page *page, | ||
804 | int offset, size_t size, int flags) | ||
805 | { | ||
806 | int err; | ||
807 | |||
808 | err = skcipher_check_key(sock); | ||
809 | if (err) | ||
810 | return err; | ||
811 | |||
812 | return skcipher_sendpage(sock, page, offset, size, flags); | ||
813 | } | ||
814 | |||
815 | static int skcipher_recvmsg_nokey(struct socket *sock, struct msghdr *msg, | ||
816 | size_t ignored, int flags) | ||
817 | { | ||
818 | int err; | ||
819 | |||
820 | err = skcipher_check_key(sock); | ||
821 | if (err) | ||
822 | return err; | ||
823 | |||
824 | return skcipher_recvmsg(sock, msg, ignored, flags); | ||
825 | } | ||
826 | |||
827 | static struct proto_ops algif_skcipher_ops_nokey = { | ||
828 | .family = PF_ALG, | ||
829 | |||
830 | .connect = sock_no_connect, | ||
831 | .socketpair = sock_no_socketpair, | ||
832 | .getname = sock_no_getname, | ||
833 | .ioctl = sock_no_ioctl, | ||
834 | .listen = sock_no_listen, | ||
835 | .shutdown = sock_no_shutdown, | ||
836 | .getsockopt = sock_no_getsockopt, | ||
837 | .mmap = sock_no_mmap, | ||
838 | .bind = sock_no_bind, | ||
839 | .accept = sock_no_accept, | ||
840 | .setsockopt = sock_no_setsockopt, | ||
841 | |||
842 | .release = af_alg_release, | ||
843 | .sendmsg = skcipher_sendmsg_nokey, | ||
844 | .sendpage = skcipher_sendpage_nokey, | ||
845 | .recvmsg = skcipher_recvmsg_nokey, | ||
846 | .poll = skcipher_poll, | ||
847 | }; | ||
848 | |||
756 | static void *skcipher_bind(const char *name, u32 type, u32 mask) | 849 | static void *skcipher_bind(const char *name, u32 type, u32 mask) |
757 | { | 850 | { |
758 | struct skcipher_tfm *tfm; | 851 | struct skcipher_tfm *tfm; |
@@ -802,7 +895,7 @@ static void skcipher_wait(struct sock *sk) | |||
802 | msleep(100); | 895 | msleep(100); |
803 | } | 896 | } |
804 | 897 | ||
805 | static void skcipher_sock_destruct(struct sock *sk) | 898 | static void skcipher_sock_destruct_common(struct sock *sk) |
806 | { | 899 | { |
807 | struct alg_sock *ask = alg_sk(sk); | 900 | struct alg_sock *ask = alg_sk(sk); |
808 | struct skcipher_ctx *ctx = ask->private; | 901 | struct skcipher_ctx *ctx = ask->private; |
@@ -814,10 +907,33 @@ static void skcipher_sock_destruct(struct sock *sk) | |||
814 | skcipher_free_sgl(sk); | 907 | skcipher_free_sgl(sk); |
815 | sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm)); | 908 | sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm)); |
816 | sock_kfree_s(sk, ctx, ctx->len); | 909 | sock_kfree_s(sk, ctx, ctx->len); |
910 | } | ||
911 | |||
912 | static void skcipher_sock_destruct(struct sock *sk) | ||
913 | { | ||
914 | skcipher_sock_destruct_common(sk); | ||
817 | af_alg_release_parent(sk); | 915 | af_alg_release_parent(sk); |
818 | } | 916 | } |
819 | 917 | ||
820 | static int skcipher_accept_parent(void *private, struct sock *sk) | 918 | static void skcipher_release_parent_nokey(struct sock *sk) |
919 | { | ||
920 | struct alg_sock *ask = alg_sk(sk); | ||
921 | |||
922 | if (!ask->refcnt) { | ||
923 | sock_put(ask->parent); | ||
924 | return; | ||
925 | } | ||
926 | |||
927 | af_alg_release_parent(sk); | ||
928 | } | ||
929 | |||
930 | static void skcipher_sock_destruct_nokey(struct sock *sk) | ||
931 | { | ||
932 | skcipher_sock_destruct_common(sk); | ||
933 | skcipher_release_parent_nokey(sk); | ||
934 | } | ||
935 | |||
936 | static int skcipher_accept_parent_common(void *private, struct sock *sk) | ||
821 | { | 937 | { |
822 | struct skcipher_ctx *ctx; | 938 | struct skcipher_ctx *ctx; |
823 | struct alg_sock *ask = alg_sk(sk); | 939 | struct alg_sock *ask = alg_sk(sk); |
@@ -825,9 +941,6 @@ static int skcipher_accept_parent(void *private, struct sock *sk) | |||
825 | struct crypto_skcipher *skcipher = tfm->skcipher; | 941 | struct crypto_skcipher *skcipher = tfm->skcipher; |
826 | unsigned int len = sizeof(*ctx) + crypto_skcipher_reqsize(skcipher); | 942 | unsigned int len = sizeof(*ctx) + crypto_skcipher_reqsize(skcipher); |
827 | 943 | ||
828 | if (!tfm->has_key) | ||
829 | return -ENOKEY; | ||
830 | |||
831 | ctx = sock_kmalloc(sk, len, GFP_KERNEL); | 944 | ctx = sock_kmalloc(sk, len, GFP_KERNEL); |
832 | if (!ctx) | 945 | if (!ctx) |
833 | return -ENOMEM; | 946 | return -ENOMEM; |
@@ -861,12 +974,38 @@ static int skcipher_accept_parent(void *private, struct sock *sk) | |||
861 | return 0; | 974 | return 0; |
862 | } | 975 | } |
863 | 976 | ||
977 | static int skcipher_accept_parent(void *private, struct sock *sk) | ||
978 | { | ||
979 | struct skcipher_tfm *tfm = private; | ||
980 | |||
981 | if (!tfm->has_key) | ||
982 | return -ENOKEY; | ||
983 | |||
984 | return skcipher_accept_parent_common(private, sk); | ||
985 | } | ||
986 | |||
987 | static int skcipher_accept_parent_nokey(void *private, struct sock *sk) | ||
988 | { | ||
989 | int err; | ||
990 | |||
991 | err = skcipher_accept_parent_common(private, sk); | ||
992 | if (err) | ||
993 | goto out; | ||
994 | |||
995 | sk->sk_destruct = skcipher_sock_destruct_nokey; | ||
996 | |||
997 | out: | ||
998 | return err; | ||
999 | } | ||
1000 | |||
864 | static const struct af_alg_type algif_type_skcipher = { | 1001 | static const struct af_alg_type algif_type_skcipher = { |
865 | .bind = skcipher_bind, | 1002 | .bind = skcipher_bind, |
866 | .release = skcipher_release, | 1003 | .release = skcipher_release, |
867 | .setkey = skcipher_setkey, | 1004 | .setkey = skcipher_setkey, |
868 | .accept = skcipher_accept_parent, | 1005 | .accept = skcipher_accept_parent, |
1006 | .accept_nokey = skcipher_accept_parent_nokey, | ||
869 | .ops = &algif_skcipher_ops, | 1007 | .ops = &algif_skcipher_ops, |
1008 | .ops_nokey = &algif_skcipher_ops_nokey, | ||
870 | .name = "skcipher", | 1009 | .name = "skcipher", |
871 | .owner = THIS_MODULE | 1010 | .owner = THIS_MODULE |
872 | }; | 1011 | }; |