lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening PHC | |
Open Source and information security mailing list archives
| ||
|
Date: Wed, 10 Sep 2014 20:29:53 -0700 From: Andy Zhou <azhou@...ira.com> To: davem@...emloft.net Cc: netdev@...r.kernel.org, Andy Zhou <azhou@...ira.com> Subject: [net-next v5 3/3] l2tp: Refactor l2tp core driver to make use of the common UDP tunnel functions Signed-off-by: Andy Zhou <azhou@...ira.com> --- net/l2tp/l2tp_core.c | 208 +++++++++++++++++++++++++++++++------------------- 1 file changed, 128 insertions(+), 80 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 2aa2b6c..1f2bb8e 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -113,6 +113,11 @@ struct l2tp_net { spinlock_t l2tp_session_hlist_lock; }; +struct l2tp_udp_tunnel { + struct udp_tunnel_sock uts; + struct l2tp_tunnel tunnel; +}; + static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel); static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk) @@ -1198,7 +1203,6 @@ static void l2tp_tunnel_destruct(struct sock *sk) l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: closing...\n", tunnel->name); - /* Disable udp encapsulation */ switch (tunnel->encap) { case L2TP_ENCAPTYPE_UDP: @@ -1298,6 +1302,18 @@ static void l2tp_udp_encap_destroy(struct sock *sk) } } +static void free_l2tp_udp_sock_rcu(struct rcu_head *rcu) +{ + struct l2tp_tunnel *tunnel; + struct l2tp_udp_tunnel *udp_tunnel; + + tunnel = container_of(rcu, struct l2tp_tunnel, rcu); + + udp_tunnel = container_of(tunnel, struct l2tp_udp_tunnel, tunnel); + + udp_tunnel_sock_free(&udp_tunnel->uts); +} + /* Really kill the tunnel. * Come here only when all sessions have been cleared from the tunnel. */ @@ -1306,7 +1322,19 @@ static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel) BUG_ON(atomic_read(&tunnel->ref_count) != 0); BUG_ON(tunnel->sock != NULL); l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: free...\n", tunnel->name); - kfree_rcu(tunnel, rcu); + + switch (tunnel->encap) { + case L2TP_ENCAPTYPE_UDP: + call_rcu(&tunnel->rcu, free_l2tp_udp_sock_rcu); + break; + + case L2TP_ENCAPTYPE_IP: + kfree_rcu(tunnel, rcu); + break; + + default: + BUG(); + } } /* Workqueue tunnel deletion function */ @@ -1342,6 +1370,35 @@ static void l2tp_tunnel_del_work(struct work_struct *work) l2tp_tunnel_sock_put(sk); } +static void l2tp_tunnel_udp_port_conf(struct l2tp_tunnel_cfg *cfg, + struct udp_port_cfg *udp_conf) +{ + memset(udp_conf, 0, sizeof(*udp_conf)); + +#if IS_ENABLED(CONFIG_IPV6) + if (cfg->local_ip6 && cfg->peer_ip6) { + udp_conf->family = AF_INET6; + memcpy(&udp_conf->local_ip6, cfg->local_ip6, + sizeof(udp_conf->local_ip6)); + memcpy(&udp_conf->peer_ip6, cfg->peer_ip6, + sizeof(udp_conf->peer_ip6)); + udp_conf->use_udp6_tx_checksums = + cfg->udp6_zero_tx_checksums; + udp_conf->use_udp6_rx_checksums = + cfg->udp6_zero_rx_checksums; + } else +#endif + { + udp_conf->family = AF_INET; + udp_conf->local_ip = cfg->local_ip; + udp_conf->peer_ip = cfg->peer_ip; + udp_conf->use_udp_checksums = cfg->use_udp_checksums; + } + + udp_conf->local_udp_port = htons(cfg->local_udp_port); + udp_conf->peer_udp_port = htons(cfg->peer_udp_port); +} + /* Create a socket for the tunnel, if one isn't set up by * userspace. This is used for static tunnels where there is no * managing L2TP daemon. @@ -1363,31 +1420,7 @@ static int l2tp_tunnel_sock_create(struct net *net, switch (cfg->encap) { case L2TP_ENCAPTYPE_UDP: - memset(&udp_conf, 0, sizeof(udp_conf)); - -#if IS_ENABLED(CONFIG_IPV6) - if (cfg->local_ip6 && cfg->peer_ip6) { - udp_conf.family = AF_INET6; - memcpy(&udp_conf.local_ip6, cfg->local_ip6, - sizeof(udp_conf.local_ip6)); - memcpy(&udp_conf.peer_ip6, cfg->peer_ip6, - sizeof(udp_conf.peer_ip6)); - udp_conf.use_udp6_tx_checksums = - cfg->udp6_zero_tx_checksums; - udp_conf.use_udp6_rx_checksums = - cfg->udp6_zero_rx_checksums; - } else -#endif - { - udp_conf.family = AF_INET; - udp_conf.local_ip = cfg->local_ip; - udp_conf.peer_ip = cfg->peer_ip; - udp_conf.use_udp_checksums = cfg->use_udp_checksums; - } - - udp_conf.local_udp_port = htons(cfg->local_udp_port); - udp_conf.peer_udp_port = htons(cfg->peer_udp_port); - + l2tp_tunnel_udp_port_conf(cfg, &udp_conf); err = udp_sock_create(net, &udp_conf, &sock); if (err < 0) goto out; @@ -1473,6 +1506,31 @@ out: static struct lock_class_key l2tp_socket_class; +static int l2tp_sk_sanity_check(struct sock *sk, enum l2tp_encap_type encap, + u32 tunnel_id, int fd) +{ + unsigned int expected_protocol; + + switch (encap) { + case L2TP_ENCAPTYPE_UDP: + expected_protocol = IPPROTO_UDP; + break; + case L2TP_ENCAPTYPE_IP: + expected_protocol = IPPROTO_L2TP; + break; + default: + return -EPROTONOSUPPORT; + } + + if (sk->sk_protocol != expected_protocol) { + pr_err("tunl %hu: fd %d wrong protocol, got %d, expected %d\n", + tunnel_id, fd, sk->sk_protocol, expected_protocol); + return -EPROTONOSUPPORT; + } + + return 0; +} + int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp) { struct l2tp_tunnel *tunnel = NULL; @@ -1480,7 +1538,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 struct socket *sock = NULL; struct sock *sk = NULL; struct l2tp_net *pn; - enum l2tp_encap_type encap = L2TP_ENCAPTYPE_UDP; + enum l2tp_encap_type encap = cfg ? cfg->encap : L2TP_ENCAPTYPE_UDP; /* Get the tunnel socket from the fd, which was opened by * the userspace L2TP daemon. If not specified, create a @@ -1488,9 +1546,11 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 */ if (fd < 0) { err = l2tp_tunnel_sock_create(net, tunnel_id, peer_tunnel_id, - cfg, &sock); + cfg, &sock); if (err < 0) goto err; + + sk = sock->sk; } else { sock = sockfd_lookup(fd, &err); if (!sock) { @@ -1500,58 +1560,66 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 goto err; } + sk = sock->sk; + /* Reject namespace mismatches */ - if (!net_eq(sock_net(sock->sk), net)) { + if (!net_eq(sock_net(sk), net)) { pr_err("tunl %u: netns mismatch\n", tunnel_id); err = -EINVAL; goto err; } - } - sk = sock->sk; + /* Quick sanity checks */ + err = l2tp_sk_sanity_check(sk, encap, tunnel_id, fd); + if (err) + goto err; - if (cfg != NULL) - encap = cfg->encap; + /* Check if this socket has already been prepped */ + tunnel = l2tp_tunnel(sk); + if (tunnel != NULL) { + /* This socket has already been prepped */ + err = -EBUSY; + goto err; + } + } - /* Quick sanity checks */ switch (encap) { - case L2TP_ENCAPTYPE_UDP: - err = -EPROTONOSUPPORT; - if (sk->sk_protocol != IPPROTO_UDP) { - pr_err("tunl %hu: fd %d wrong protocol, got %d, expected %d\n", - tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP); + case L2TP_ENCAPTYPE_UDP: { + struct udp_tunnel_sock_cfg udp_cfg; + struct l2tp_udp_tunnel *udp_tunnel; + struct udp_tunnel_sock *uts; + + udp_cfg.sock = sock; + udp_cfg.encap_type = UDP_ENCAP_L2TPINUDP; + udp_cfg.encap_rcv = l2tp_udp_encap_recv; + udp_cfg.encap_destroy = l2tp_udp_encap_destroy; + + uts = create_udp_tunnel_sock(net, sizeof(*udp_tunnel), + &udp_cfg); + if (!uts) { + err = -ENOMEM; goto err; } + + udp_tunnel = container_of(uts, struct l2tp_udp_tunnel, uts); + tunnel = &udp_tunnel->tunnel; break; + } case L2TP_ENCAPTYPE_IP: - err = -EPROTONOSUPPORT; - if (sk->sk_protocol != IPPROTO_L2TP) { - pr_err("tunl %hu: fd %d wrong protocol, got %d, expected %d\n", - tunnel_id, fd, sk->sk_protocol, IPPROTO_L2TP); + tunnel = kzalloc(sizeof(*tunnel), GFP_KERNEL); + if (tunnel == NULL) { + err = -ENOMEM; goto err; } - break; } - /* Check if this socket has already been prepped */ - tunnel = l2tp_tunnel(sk); - if (tunnel != NULL) { - /* This socket has already been prepped */ - err = -EBUSY; - goto err; - } - - tunnel = kzalloc(sizeof(struct l2tp_tunnel), GFP_KERNEL); - if (tunnel == NULL) { - err = -ENOMEM; - goto err; - } + rcu_assign_sk_user_data(sk, tunnel); + tunnel->encap = encap; tunnel->version = version; tunnel->tunnel_id = tunnel_id; tunnel->peer_tunnel_id = peer_tunnel_id; - tunnel->debug = L2TP_DEFAULT_DEBUG_FLAGS; - + tunnel->debug = cfg ? cfg->debug : L2TP_DEFAULT_DEBUG_FLAGS; tunnel->magic = L2TP_TUNNEL_MAGIC; sprintf(&tunnel->name[0], "tunl %u", tunnel_id); rwlock_init(&tunnel->hlist_lock); @@ -1560,9 +1628,6 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 tunnel->l2tp_net = net; pn = l2tp_pernet(net); - if (cfg != NULL) - tunnel->debug = cfg->debug; - #if IS_ENABLED(CONFIG_IPV6) if (sk->sk_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); @@ -1581,23 +1646,6 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 } #endif - /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */ - tunnel->encap = encap; - if (encap == L2TP_ENCAPTYPE_UDP) { - /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */ - udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP; - udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv; - udp_sk(sk)->encap_destroy = l2tp_udp_encap_destroy; -#if IS_ENABLED(CONFIG_IPV6) - if (sk->sk_family == PF_INET6 && !tunnel->v4mapped) - udpv6_encap_enable(); - else -#endif - udp_encap_enable(); - } - - sk->sk_user_data = tunnel; - /* Hook on the tunnel socket destructor so that we can cleanup * if the tunnel socket goes away. */ -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@...r.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists