mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
net/tcp: Introduce TCP_AO setsockopt()s
Add 3 setsockopt()s: 1. TCP_AO_ADD_KEY to add a new Master Key Tuple (MKT) on a socket 2. TCP_AO_DEL_KEY to delete present MKT from a socket 3. TCP_AO_INFO to change flags, Current_key/RNext_key on a TCP-AO sk Userspace has to introduce keys on every socket it wants to use TCP-AO option on, similarly to TCP_MD5SIG/TCP_MD5SIG_EXT. RFC5925 prohibits definition of MKTs that would match the same peer, so do sanity checks on the data provided by userspace. Be as conservative as possible, including refusal of defining MKT on an established connection with no AO, removing the key in-use and etc. (1) and (2) are to be used by userspace key manager to add/remove keys. (3) main purpose is to set RNext_key, which (as prescribed by RFC5925) is the KeyID that will be requested in TCP-AO header from the peer to sign their segments with. At this moment the life of ao_info ends in tcp_v4_destroy_sock(). Co-developed-by: Francesco Ruggeri <fruggeri@arista.com> Signed-off-by: Francesco Ruggeri <fruggeri@arista.com> Co-developed-by: Salam Noureddine <noureddine@arista.com> Signed-off-by: Salam Noureddine <noureddine@arista.com> Signed-off-by: Dmitry Safonov <dima@arista.com> Acked-by: David Ahern <dsahern@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
c845f5f359
commit
4954f17dde
@@ -55,6 +55,29 @@ static inline int copy_from_sockptr(void *dst, sockptr_t src, size_t size)
|
||||
return copy_from_sockptr_offset(dst, src, 0, size);
|
||||
}
|
||||
|
||||
static inline int copy_struct_from_sockptr(void *dst, size_t ksize,
|
||||
sockptr_t src, size_t usize)
|
||||
{
|
||||
size_t size = min(ksize, usize);
|
||||
size_t rest = max(ksize, usize) - size;
|
||||
|
||||
if (!sockptr_is_kernel(src))
|
||||
return copy_struct_from_user(dst, ksize, src.user, size);
|
||||
|
||||
if (usize < ksize) {
|
||||
memset(dst + size, 0, rest);
|
||||
} else if (usize > ksize) {
|
||||
char *p = src.kernel;
|
||||
|
||||
while (rest--) {
|
||||
if (*p++)
|
||||
return -E2BIG;
|
||||
}
|
||||
}
|
||||
memcpy(dst, src.kernel, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int copy_to_sockptr_offset(sockptr_t dst, size_t offset,
|
||||
const void *src, size_t size)
|
||||
{
|
||||
|
||||
@@ -2175,6 +2175,9 @@ struct tcp_sock_af_ops {
|
||||
sockptr_t optval,
|
||||
int optlen);
|
||||
#endif
|
||||
#ifdef CONFIG_TCP_AO
|
||||
int (*ao_parse)(struct sock *sk, int optname, sockptr_t optval, int optlen);
|
||||
#endif
|
||||
};
|
||||
|
||||
struct tcp_request_sock_ops {
|
||||
|
||||
+16
-1
@@ -81,10 +81,25 @@ struct tcp_ao_info {
|
||||
*/
|
||||
struct tcp_ao_key *current_key;
|
||||
struct tcp_ao_key *rnext_key;
|
||||
u32 flags;
|
||||
u32 ao_required :1,
|
||||
__unused :31;
|
||||
__be32 lisn;
|
||||
__be32 risn;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_TCP_AO
|
||||
int tcp_parse_ao(struct sock *sk, int cmd, unsigned short int family,
|
||||
sockptr_t optval, int optlen);
|
||||
void tcp_ao_destroy_sock(struct sock *sk);
|
||||
/* ipv4 specific functions */
|
||||
int tcp_v4_parse_ao(struct sock *sk, int cmd, sockptr_t optval, int optlen);
|
||||
/* ipv6 specific functions */
|
||||
int tcp_v6_parse_ao(struct sock *sk, int cmd, sockptr_t optval, int optlen);
|
||||
#else
|
||||
static inline void tcp_ao_destroy_sock(struct sock *sk)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TCP_AO_H */
|
||||
|
||||
@@ -129,6 +129,9 @@ enum {
|
||||
|
||||
#define TCP_TX_DELAY 37 /* delay outgoing packets by XX usec */
|
||||
|
||||
#define TCP_AO_ADD_KEY 38 /* Add/Set MKT */
|
||||
#define TCP_AO_DEL_KEY 39 /* Delete MKT */
|
||||
#define TCP_AO_INFO 40 /* Modify TCP-AO per-socket options */
|
||||
|
||||
#define TCP_REPAIR_ON 1
|
||||
#define TCP_REPAIR_OFF 0
|
||||
@@ -363,6 +366,49 @@ struct tcp_diag_md5sig {
|
||||
|
||||
#define TCP_AO_MAXKEYLEN 80
|
||||
|
||||
#define TCP_AO_KEYF_IFINDEX (1 << 0) /* L3 ifindex for VRF */
|
||||
|
||||
struct tcp_ao_add { /* setsockopt(TCP_AO_ADD_KEY) */
|
||||
struct __kernel_sockaddr_storage addr; /* peer's address for the key */
|
||||
char alg_name[64]; /* crypto hash algorithm to use */
|
||||
__s32 ifindex; /* L3 dev index for VRF */
|
||||
__u32 set_current :1, /* set key as Current_key at once */
|
||||
set_rnext :1, /* request it from peer with RNext_key */
|
||||
reserved :30; /* must be 0 */
|
||||
__u16 reserved2; /* padding, must be 0 */
|
||||
__u8 prefix; /* peer's address prefix */
|
||||
__u8 sndid; /* SendID for outgoing segments */
|
||||
__u8 rcvid; /* RecvID to match for incoming seg */
|
||||
__u8 maclen; /* length of authentication code (hash) */
|
||||
__u8 keyflags; /* see TCP_AO_KEYF_ */
|
||||
__u8 keylen; /* length of ::key */
|
||||
__u8 key[TCP_AO_MAXKEYLEN];
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct tcp_ao_del { /* setsockopt(TCP_AO_DEL_KEY) */
|
||||
struct __kernel_sockaddr_storage addr; /* peer's address for the key */
|
||||
__s32 ifindex; /* L3 dev index for VRF */
|
||||
__u32 set_current :1, /* corresponding ::current_key */
|
||||
set_rnext :1, /* corresponding ::rnext */
|
||||
reserved :30; /* must be 0 */
|
||||
__u16 reserved2; /* padding, must be 0 */
|
||||
__u8 prefix; /* peer's address prefix */
|
||||
__u8 sndid; /* SendID for outgoing segments */
|
||||
__u8 rcvid; /* RecvID to match for incoming seg */
|
||||
__u8 current_key; /* KeyID to set as Current_key */
|
||||
__u8 rnext; /* KeyID to set as Rnext_key */
|
||||
__u8 keyflags; /* see TCP_AO_KEYF_ */
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct tcp_ao_info_opt { /* setsockopt(TCP_AO_INFO) */
|
||||
__u32 set_current :1, /* corresponding ::current_key */
|
||||
set_rnext :1, /* corresponding ::rnext */
|
||||
ao_required :1, /* don't accept non-AO connects */
|
||||
reserved :29; /* must be 0 */
|
||||
__u8 current_key; /* KeyID to set as Current_key */
|
||||
__u8 rnext; /* KeyID to set as Rnext_key */
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
/* setsockopt(fd, IPPROTO_TCP, TCP_ZEROCOPY_RECEIVE, ...) */
|
||||
|
||||
#define TCP_RECEIVE_ZEROCOPY_FLAG_TLB_CLEAN_HINT 0x1
|
||||
|
||||
@@ -69,6 +69,7 @@ obj-$(CONFIG_NETLABEL) += cipso_ipv4.o
|
||||
|
||||
obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
|
||||
xfrm4_output.o xfrm4_protocol.o
|
||||
obj-$(CONFIG_TCP_AO) += tcp_ao.o
|
||||
|
||||
ifeq ($(CONFIG_BPF_JIT),y)
|
||||
obj-$(CONFIG_BPF_SYSCALL) += bpf_tcp_ca.o
|
||||
|
||||
@@ -3593,6 +3593,23 @@ int do_tcp_setsockopt(struct sock *sk, int level, int optname,
|
||||
__tcp_sock_set_quickack(sk, val);
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_TCP_AO
|
||||
case TCP_AO_ADD_KEY:
|
||||
case TCP_AO_DEL_KEY:
|
||||
case TCP_AO_INFO: {
|
||||
/* If this is the first TCP-AO setsockopt() on the socket,
|
||||
* sk_state has to be LISTEN or CLOSE
|
||||
*/
|
||||
if (((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) ||
|
||||
rcu_dereference_protected(tcp_sk(sk)->ao_info,
|
||||
lockdep_sock_is_held(sk)))
|
||||
err = tp->af_specific->ao_parse(sk, optname, optval,
|
||||
optlen);
|
||||
else
|
||||
err = -EISCONN;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
case TCP_MD5SIG:
|
||||
case TCP_MD5SIG_EXT:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+8
-2
@@ -2271,11 +2271,16 @@ const struct inet_connection_sock_af_ops ipv4_specific = {
|
||||
};
|
||||
EXPORT_SYMBOL(ipv4_specific);
|
||||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO)
|
||||
static const struct tcp_sock_af_ops tcp_sock_ipv4_specific = {
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
.md5_lookup = tcp_v4_md5_lookup,
|
||||
.calc_md5_hash = tcp_v4_md5_hash_skb,
|
||||
.md5_parse = tcp_v4_parse_md5_keys,
|
||||
#endif
|
||||
#ifdef CONFIG_TCP_AO
|
||||
.ao_parse = tcp_v4_parse_ao,
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -2290,7 +2295,7 @@ static int tcp_v4_init_sock(struct sock *sk)
|
||||
|
||||
icsk->icsk_af_ops = &ipv4_specific;
|
||||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO)
|
||||
tcp_sk(sk)->af_specific = &tcp_sock_ipv4_specific;
|
||||
#endif
|
||||
|
||||
@@ -2341,6 +2346,7 @@ void tcp_v4_destroy_sock(struct sock *sk)
|
||||
rcu_assign_pointer(tp->md5sig_info, NULL);
|
||||
}
|
||||
#endif
|
||||
tcp_ao_destroy_sock(sk);
|
||||
|
||||
/* Clean up a referenced TCP bind bucket. */
|
||||
if (inet_csk(sk)->icsk_bind_hash)
|
||||
|
||||
@@ -52,4 +52,5 @@ obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
|
||||
ifneq ($(CONFIG_IPV6),)
|
||||
obj-$(CONFIG_NET_UDP_TUNNEL) += ip6_udp_tunnel.o
|
||||
obj-y += mcast_snoop.o
|
||||
obj-$(CONFIG_TCP_AO) += tcp_ao.o
|
||||
endif
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* INET An implementation of the TCP Authentication Option (TCP-AO).
|
||||
* See RFC5925.
|
||||
*
|
||||
* Authors: Dmitry Safonov <dima@arista.com>
|
||||
* Francesco Ruggeri <fruggeri@arista.com>
|
||||
* Salam Noureddine <noureddine@arista.com>
|
||||
*/
|
||||
#include <linux/tcp.h>
|
||||
|
||||
#include <net/tcp.h>
|
||||
#include <net/ipv6.h>
|
||||
|
||||
int tcp_v6_parse_ao(struct sock *sk, int cmd,
|
||||
sockptr_t optval, int optlen)
|
||||
{
|
||||
return tcp_parse_ao(sk, cmd, AF_INET6, optval, optlen);
|
||||
}
|
||||
+24
-15
@@ -76,16 +76,9 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
|
||||
|
||||
static const struct inet_connection_sock_af_ops ipv6_mapped;
|
||||
const struct inet_connection_sock_af_ops ipv6_specific;
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO)
|
||||
static const struct tcp_sock_af_ops tcp_sock_ipv6_specific;
|
||||
static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific;
|
||||
#else
|
||||
static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(const struct sock *sk,
|
||||
const struct in6_addr *addr,
|
||||
int l3index)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Helper returning the inet6 address from a given tcp socket.
|
||||
@@ -239,7 +232,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
|
||||
if (sk_is_mptcp(sk))
|
||||
mptcpv6_handle_mapped(sk, true);
|
||||
sk->sk_backlog_rcv = tcp_v4_do_rcv;
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO)
|
||||
tp->af_specific = &tcp_sock_ipv6_mapped_specific;
|
||||
#endif
|
||||
|
||||
@@ -252,7 +245,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
|
||||
if (sk_is_mptcp(sk))
|
||||
mptcpv6_handle_mapped(sk, false);
|
||||
sk->sk_backlog_rcv = tcp_v6_do_rcv;
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO)
|
||||
tp->af_specific = &tcp_sock_ipv6_specific;
|
||||
#endif
|
||||
goto failure;
|
||||
@@ -769,7 +762,13 @@ clear_hash_nostart:
|
||||
memset(md5_hash, 0, 16);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else /* CONFIG_TCP_MD5SIG */
|
||||
static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(const struct sock *sk,
|
||||
const struct in6_addr *addr,
|
||||
int l3index)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void tcp_v6_init_req(struct request_sock *req,
|
||||
@@ -1228,7 +1227,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
|
||||
if (sk_is_mptcp(newsk))
|
||||
mptcpv6_handle_mapped(newsk, true);
|
||||
newsk->sk_backlog_rcv = tcp_v4_do_rcv;
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO)
|
||||
newtp->af_specific = &tcp_sock_ipv6_mapped_specific;
|
||||
#endif
|
||||
|
||||
@@ -1896,11 +1895,16 @@ const struct inet_connection_sock_af_ops ipv6_specific = {
|
||||
.mtu_reduced = tcp_v6_mtu_reduced,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO)
|
||||
static const struct tcp_sock_af_ops tcp_sock_ipv6_specific = {
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
.md5_lookup = tcp_v6_md5_lookup,
|
||||
.calc_md5_hash = tcp_v6_md5_hash_skb,
|
||||
.md5_parse = tcp_v6_parse_md5_keys,
|
||||
#endif
|
||||
#ifdef CONFIG_TCP_AO
|
||||
.ao_parse = tcp_v6_parse_ao,
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1922,11 +1926,16 @@ static const struct inet_connection_sock_af_ops ipv6_mapped = {
|
||||
.mtu_reduced = tcp_v4_mtu_reduced,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO)
|
||||
static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = {
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
.md5_lookup = tcp_v4_md5_lookup,
|
||||
.calc_md5_hash = tcp_v4_md5_hash_skb,
|
||||
.md5_parse = tcp_v6_parse_md5_keys,
|
||||
#endif
|
||||
#ifdef CONFIG_TCP_AO
|
||||
.ao_parse = tcp_v6_parse_ao,
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1941,7 +1950,7 @@ static int tcp_v6_init_sock(struct sock *sk)
|
||||
|
||||
icsk->icsk_af_ops = &ipv6_specific;
|
||||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO)
|
||||
tcp_sk(sk)->af_specific = &tcp_sock_ipv6_specific;
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user