]> git.hungrycats.org Git - linux/commitdiff
tls: Use correct sk->sk_prot for IPV6
authorBoris Pismenny <borisp@mellanox.com>
Tue, 27 Feb 2018 12:18:39 +0000 (14:18 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 9 Mar 2018 06:47:39 +0000 (22:47 -0800)
[ Upstream commit c113187d38ff85dc302a1bb55864b203ebb2ba10 ]

The tls ulp overrides sk->prot with a new tls specific proto structs.
The tls specific structs were previously based on the ipv4 specific
tcp_prot sturct.
As a result, attaching the tls ulp to an ipv6 tcp socket replaced
some ipv6 callback with the ipv4 equivalents.

This patch adds ipv6 tls proto structs and uses them when
attached to ipv6 sockets.

Fixes: 3c4d7559159b ('tls: kernel TLS support')
Signed-off-by: Boris Pismenny <borisp@mellanox.com>
Signed-off-by: Ilya Lesokhin <ilyal@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/tls/tls_main.c

index 736719c8314e83e0c0fca2dabed30a1535fbfdcb..3a780337c3939350aa08305a1302119fbcb3988d 100644 (file)
@@ -45,17 +45,27 @@ MODULE_AUTHOR("Mellanox Technologies");
 MODULE_DESCRIPTION("Transport Layer Security Support");
 MODULE_LICENSE("Dual BSD/GPL");
 
+enum {
+       TLSV4,
+       TLSV6,
+       TLS_NUM_PROTS,
+};
+
 enum {
        TLS_BASE_TX,
        TLS_SW_TX,
        TLS_NUM_CONFIG,
 };
 
-static struct proto tls_prots[TLS_NUM_CONFIG];
+static struct proto *saved_tcpv6_prot;
+static DEFINE_MUTEX(tcpv6_prot_mutex);
+static struct proto tls_prots[TLS_NUM_PROTS][TLS_NUM_CONFIG];
 
 static inline void update_sk_prot(struct sock *sk, struct tls_context *ctx)
 {
-       sk->sk_prot = &tls_prots[ctx->tx_conf];
+       int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4;
+
+       sk->sk_prot = &tls_prots[ip_ver][ctx->tx_conf];
 }
 
 int wait_on_pending_writer(struct sock *sk, long *timeo)
@@ -450,8 +460,21 @@ static int tls_setsockopt(struct sock *sk, int level, int optname,
        return do_tls_setsockopt(sk, optname, optval, optlen);
 }
 
+static void build_protos(struct proto *prot, struct proto *base)
+{
+       prot[TLS_BASE_TX] = *base;
+       prot[TLS_BASE_TX].setsockopt    = tls_setsockopt;
+       prot[TLS_BASE_TX].getsockopt    = tls_getsockopt;
+       prot[TLS_BASE_TX].close         = tls_sk_proto_close;
+
+       prot[TLS_SW_TX] = prot[TLS_BASE_TX];
+       prot[TLS_SW_TX].sendmsg         = tls_sw_sendmsg;
+       prot[TLS_SW_TX].sendpage        = tls_sw_sendpage;
+}
+
 static int tls_init(struct sock *sk)
 {
+       int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4;
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct tls_context *ctx;
        int rc = 0;
@@ -476,6 +499,17 @@ static int tls_init(struct sock *sk)
        ctx->getsockopt = sk->sk_prot->getsockopt;
        ctx->sk_proto_close = sk->sk_prot->close;
 
+       /* Build IPv6 TLS whenever the address of tcpv6_prot changes */
+       if (ip_ver == TLSV6 &&
+           unlikely(sk->sk_prot != smp_load_acquire(&saved_tcpv6_prot))) {
+               mutex_lock(&tcpv6_prot_mutex);
+               if (likely(sk->sk_prot != saved_tcpv6_prot)) {
+                       build_protos(tls_prots[TLSV6], sk->sk_prot);
+                       smp_store_release(&saved_tcpv6_prot, sk->sk_prot);
+               }
+               mutex_unlock(&tcpv6_prot_mutex);
+       }
+
        ctx->tx_conf = TLS_BASE_TX;
        update_sk_prot(sk, ctx);
 out:
@@ -488,21 +522,9 @@ static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = {
        .init                   = tls_init,
 };
 
-static void build_protos(struct proto *prot, struct proto *base)
-{
-       prot[TLS_BASE_TX] = *base;
-       prot[TLS_BASE_TX].setsockopt    = tls_setsockopt;
-       prot[TLS_BASE_TX].getsockopt    = tls_getsockopt;
-       prot[TLS_BASE_TX].close         = tls_sk_proto_close;
-
-       prot[TLS_SW_TX] = prot[TLS_BASE_TX];
-       prot[TLS_SW_TX].sendmsg         = tls_sw_sendmsg;
-       prot[TLS_SW_TX].sendpage        = tls_sw_sendpage;
-}
-
 static int __init tls_register(void)
 {
-       build_protos(tls_prots, &tcp_prot);
+       build_protos(tls_prots[TLSV4], &tcp_prot);
 
        tcp_register_ulp(&tcp_tls_ulp_ops);