tcp: Initial support for RFC5925 auth option
Subsystems (6)
v3 cover tcp: Initial support for RFC5925 auth option
This is similar to TCP MD5 in functionality but it's sufficiently different that wire formats are incompatible. Compared to TCP-MD5 more algorithms are supported and multiple keys can be used on the same connection but there is still no negotiation mechanism.
Expected use-case is protecting long-duration BGP/LDP connections between routers using pre-shared keys. The goal of this series is to allow routers using the linux TCP stack to interoperate with vendors such as Cisco and Juniper.
Both algorithms described in RFC5926 are implemented but the code is not very easily extensible beyond that. In particular there are several code paths making stack allocations based on RFC5926 maximum, those would have to be increased. Support for arbitrary algorithms was requested in reply to previous posts but I believe there is no real use case for that.
The current implementation is somewhat loose regarding configuration:
* Overlaping MKTs can be configured despite what RFC5925 says
* Current key can be deleted
* If multiple keys are valid for a destination the kernel picks one in an unpredictable manner (this can be overridden).
These conditions could be tightened but it is not clear the kernel should prevent misconfiguration from userspace.
This version implements prefixlen and incorporates comments from v2 as well as some unrelated fixes. Here are some known flaws and limitations:
* Crypto API is used with buffers on the stack and inside struct sock, this might not work on all arches. I'm currently only testing x64 VMs
* Interaction with TCP-MD5 not tested in all corners.
* Interaction with FASTOPEN not tested and unlikely to work because sequence number assumptions for syn/ack.
* Not clear if crypto_ahash_setkey might sleep. If some implementation do that then maybe they could be excluded through alloc flags.
* Traffic key is not cached (reducing performance)
* There is no useful way to list keys, making userspace debug difficult.
Some testing support is included in nettest and fcnal-test.sh, similar to the current level of tcp-md5 testing.
A more elaborate test suite using pytest and scapy is available out of
tree: https://github.com/cdleonard/tcp-authopt-test That test suite is much larger that the kernel code and did not receive many comments so I will attempt to push it separately (if at all).
Changes for frr (old): https://github.com/FRRouting/frr/pull/9442
That PR was made early for ABI feedback, it has many issues.
Changes for yabgp (old): https://github.com/cdleonard/yabgp/commits/tcp_authopt
This can be use for easy interoperability testing with cisco/juniper/etc.
Changes since PATCH v2:
* Protect tcp_authopt_alg_get/put_tfm with local_bh_disable instead of preempt_disable. This caused signature corruption when send path executing with BH enabled was interrupted by recv.
* Fix accepted keyids not configured locally as "unexpected". If any key is configured that matches the peer then traffic MUST be signed.
* Fix issues related to sne rollover during handshake itself. (Francesco)
* Implement and test prefixlen (David)
* Replace shash with ahash and reuse some of the MD5 code (Dmitry)
* Parse md5+ao options only once in the same function (Dmitry)
* Pass tcp_authopt_info into inbound check path, this avoids second rcu dereference for same packet.
* Pass tcp_request_socket into inbound check path instead of just listen socket. This is required for SNE rollover during handshake and clearifies ISN handling.
* Do not allow disabling via sysctl after enabling once, this is difficult to support well (David)
* Verbose check for sysctl_tcp_authopt (Dmitry)
* Use netif_index_is_l3_master (David)
* Cleanup ipvx_addr_match (David)
* Add a #define tcp_authopt_needed to wrap static key usage because it looks nicer.
* Replace rcu_read_lock with rcu_dereference_protected in SNE updates (Eric)
Changes since PATCH v1:
* Implement Sequence Number Extension
* Implement l3index for vrf: TCP_AUTHOPT_KEY_IFINDEX as equivalent of TCP_MD5SIG_FLAG_IFINDEX
* Expand TCP-AO tests in fcnal-test.sh to near-parity with md5.
* Show addr/port on failure similar to md5
* Remove tox dependency from test suite (create venv directly)
* Switch default pytest output format to TAP (kselftest standard)
* Fix _copy_from_sockptr_tolerant stack corruption on short sockopts. This was covered in test but error was invisible without STACKPROTECTOR=y
* Fix sysctl_tcp_authopt check in tcp_get_authopt_val before memset. This was harmless because error code is checked in getsockopt anyway.
* Fix dropping md5 packets on all sockets with AO enabled
* Fix checking (key->recv_id & TCP_AUTHOPT_KEY_ADDR_BIND) instead of key->flags in tcp_authopt_key_match_exact
* Fix PATCH 1/19 not compiling due to missing "int err" declaration
* Add ratelimited message for AO and MD5 both present
* Export all symbols required by CONFIG_IPV6=m (again)
* Fix compilation with CONFIG_TCP_AUTHOPT=y CONFIG_TCP_MD5SIG=n
* Fix checkpatch issues
* Pass -rrequirements.txt to tox to avoid dependency variation.
Changes since RFCv3:
* Implement TCP_AUTHOPT handling for timewait and reset replies. Write tests to execute these paths by injecting packets with scapy
* Handle combining md5 and authopt: if both are configured use authopt.
* Fix locking issues around send_key, introduced in on of the later patches.
* Handle IPv4-mapped-IPv6 addresses: it used to be that an ipv4 SYN sent to an ipv6 socket with TCP-AO triggered WARN
* Implement un-namespaced sysctl disabled this feature by default
* Allocate new key before removing any old one in setsockopt (Dmitry)
* Remove tcp_authopt_key_info.local_id because it's no longer used (Dmitry)
* Propagate errors from TCP_AUTHOPT getsockopt (Dmitry)
* Fix no-longer-correct TCP_AUTHOPT_KEY_DEL docs (Dmitry)
* Simplify crypto allocation (Eric)
* Use kzmalloc instead of __GFP_ZERO (Eric)
* Add static_key_false tcp_authopt_needed (Eric)
* Clear authopt_info copied from oldsk in __tcp_authopt_openreq (Eric)
* Replace memcmp in ipv4 and ipv6 addr comparisons (Eric)
* Export symbols for CONFIG_IPV6=m (kernel test robot)
* Mark more functions static (kernel test robot)
* Fix build with CONFIG_PROVE_RCU_LIST=y (kernel test robot)
Changes since RFCv2:
* Removed local_id from ABI and match on send_id/recv_id/addr
* Add all relevant out-of-tree tests to tools/testing/selftests
* Return an error instead of ignoring unknown flags, hopefully this makes it easier to extend.
* Check sk_family before __tcp_authopt_info_get_or_create in tcp_set_authopt_key
* Use sock_owned_by_me instead of WARN_ON(!lockdep_sock_is_held(sk))
* Fix some intermediate build failures reported by kbuild robot
* Improve documentation
Changes since RFC:
* Split into per-topic commits for ease of review. The intermediate commits compile with a few "unused function" warnings and don't do anything useful by themselves.
* Add ABI documention including kernel-doc on uapi
* Fix lockdep warnings from crypto by creating pools with one shash for each cpu
* Accept short options to setsockopt by padding with zeros; this approach allows increasing the size of the structs in the future.
* Support for aes-128-cmac-96
* Support for binding addresses to keys in a way similar to old tcp_md5
* Add support for retrieving received keyid/rnextkeyid and controling the keyid/rnextkeyid being sent.
```
Leonard Crestez (18):
tcp: authopt: Initial support and key management
docs: Add user documentation for tcp_authopt
tcp: authopt: Add crypto initialization
tcp: md5: Refactor tcp_sig_hash_skb_data for AO
tcp: authopt: Compute packet signatures
tcp: authopt: Hook into tcp core
tcp: authopt: Disable via sysctl by default
tcp: authopt: Implement Sequence Number Extension
tcp: ipv6: Add AO signing for tcp_v6_send_response
tcp: authopt: Add support for signing skb-less replies
tcp: ipv4: Add AO signing for skb-less replies
tcp: authopt: Add key selection controls
tcp: authopt: Add initial l3index support
tcp: authopt: Add NOSEND/NORECV flags
tcp: authopt: Add prefixlen support
selftests: nettest: Rename md5_prefix to key_addr_prefix
selftests: nettest: Initial tcp_authopt support
selftests: net/fcnal: Initial tcp_authopt support
Documentation/networking/index.rst | 1 + Documentation/networking/ip-sysctl.rst | 6 + Documentation/networking/tcp_authopt.rst | 69 + include/linux/tcp.h | 9 + include/net/tcp.h | 27 +- include/net/tcp_authopt.h | 316 ++++ include/uapi/linux/snmp.h | 1 + include/uapi/linux/tcp.h | 137 ++ net/ipv4/Kconfig | 14 + net/ipv4/Makefile | 1 + net/ipv4/proc.c | 1 + net/ipv4/sysctl_net_ipv4.c | 39 + net/ipv4/tcp.c | 68 +- net/ipv4/tcp_authopt.c | 1671 +++++++++++++++++++++ net/ipv4/tcp_input.c | 41 +- net/ipv4/tcp_ipv4.c | 136 +- net/ipv4/tcp_minisocks.c | 12 + net/ipv4/tcp_output.c | 86 +- net/ipv6/tcp_ipv6.c | 108 +- tools/testing/selftests/net/fcnal-test.sh | 298 ++++ tools/testing/selftests/net/nettest.c | 123 +- 21 files changed, 3085 insertions(+), 79 deletions(-) create mode 100644 Documentation/networking/tcp_authopt.rst create mode 100644 include/net/tcp_authopt.h create mode 100644 net/ipv4/tcp_authopt.c
base-commit: 1fe5b01262844be03de98afdd56d1d393df04d7e
Signature · 1 line
2.25.1
PATCH v3 1/18 tcp: authopt: Initial support and key management
This commit adds support to add and remove keys but does not use them further.
Similar to tcp md5 a single pointer to a struct tcp_authopt_info* struct is added to struct tcp_sock, this avoids increasing memory usage. The data structures related to tcp_authopt are initialized on setsockopt and only freed on socket close.
--- include/linux/tcp.h | 9 ++ include/net/tcp.h | 1 + include/net/tcp_authopt.h | 76 +++++++++++ include/uapi/linux/tcp.h | 81 ++++++++++++ net/ipv4/Kconfig | 14 ++ net/ipv4/Makefile | 1 + net/ipv4/tcp.c | 30 +++++ net/ipv4/tcp_authopt.c | 263 ++++++++++++++++++++++++++++++++++++++ net/ipv4/tcp_ipv4.c | 2 + 9 files changed, 477 insertions(+) create mode 100644 include/net/tcp_authopt.h create mode 100644 net/ipv4/tcp_authopt.c
include/linux/tcp.h +9 -0
@@ -140,10 +140,12 @@ struct tcp_request_sock {static inline struct tcp_request_sock *tcp_rsk (const struct request_sock *req) {return (struct tcp_request_sock *)req; } +struct tcp_authopt_info ; +struct tcp_sock {/* inet_connection_sock has to be the first member of tcp_sock */ struct inet_connection_sock inet_conn;u16 tcp_header_len;/* Bytes of tcp header to send */ u16 gso_segs;/* Max number of segs per GSO packet */
@@ -403,10 +405,14 @@ struct tcp_sock {/* TCP MD5 Signature Option information */ struct tcp_md5sig_info __rcu *md5sig_info;#endif +#ifdef CONFIG_TCP_AUTHOPT +struct tcp_authopt_info __rcu *authopt_info; +#endif +/* TCP fastopen related information */ struct tcp_fastopen_request *fastopen_req;/* fastopen_rsk points to request_sock that resulted in this big * socket. Used to retransmit SYNACKs etc. */
@@ -453,10 +459,13 @@ struct tcp_timewait_sock {int tw_ts_recent_stamp;u32 tw_tx_delay;#ifdef CONFIG_TCP_MD5SIG struct tcp_md5sig_key *tw_md5_key;#endif +#ifdef CONFIG_TCP_AUTHOPT +struct tcp_authopt_info *tw_authopt_info; +#endif };static inline struct tcp_timewait_sock *tcp_twsk (const struct sock *sk) {return (struct tcp_timewait_sock *)sk;
include/net/tcp.h +1 -0
@@ -184,10 +184,11 @@ void tcp_time_wait(struct sock *sk, int state, int timeo);#define TCPOPT_WINDOW 3/* Window scaling */ #define TCPOPT_SACK_PERM 4/* SACK Permitted */ #define TCPOPT_SACK 5/* SACK Block */ #define TCPOPT_TIMESTAMP 8/* Better RTT estimations/PAWS */ #define TCPOPT_MD5SIG 19/* MD5 Signature (RFC2385) */ +#define TCPOPT_AUTHOPT 29/* Auth Option (RFC5925) */ #define TCPOPT_MPTCP 30/* Multipath TCP (RFC6824) */ #define TCPOPT_FASTOPEN 34/* Fast open (RFC7413) */ #define TCPOPT_EXP 254/* Experimental */ /* Magic number to be after the option value for sharing TCP * experimental options. See draft-ietf-tcpm-experimental-options-00.txt
include/net/tcp_authopt.h new file +76 -0
76 lines not on this page · raw message
include/uapi/linux/tcp.h +81 -0
101 lines not on this page · raw message
net/ipv4/Kconfig +14 -0
@@ -740,5 +740,19 @@ config TCP_MD5SIG RFC2385 specifies a method of giving MD5 protection to TCP sessions. Its main (only?) use is to protect BGP sessions between core routers on the Internet. If unsure, say N. + +config TCP_AUTHOPT + bool "TCP: Authentication Option support (RFC5925)" + select CRYPTO + select CRYPTO_SHA1 + select CRYPTO_HMAC + select CRYPTO_AES + select CRYPTO_CMAC + help + RFC5925 specifies a new method of giving protection to TCP sessions. + Its intended use is to protect BGP sessions between core routers + on the Internet. It obsoletes TCP MD5 (RFC2385) but is incompatible. + + If unsure, say N.
net/ipv4/Makefile +1 -0
@@ -59,10 +59,11 @@ obj-$(CONFIG_TCP_CONG_NV) += tcp_nv.o obj-$(CONFIG_TCP_CONG_VENO) += tcp_veno.o obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o +obj-$(CONFIG_TCP_AUTHOPT) += tcp_authopt.o obj-$(CONFIG_NET_SOCK_MSG) += tcp_bpf.o obj-$(CONFIG_BPF_SYSCALL) += udp_bpf.o obj-$(CONFIG_NETLABEL) += cipso_ipv4.o obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
net/ipv4/tcp.c +30 -0
@@ -270,10 +270,11 @@#include <net/icmp.h> #include <net/inet_common.h> #include <net/tcp.h> #include <net/mptcp.h> +#include <net/tcp_authopt.h> #include <net/xfrm.h> #include <net/ip.h> #include <net/sock.h> #include <linux/uaccess.h>
@@ -3602,10 +3603,16 @@ static int do_tcp_setsockopt(struct sock *sk, int level, int optname,case TCP_MD5SIG :case TCP_MD5SIG_EXT : err = tp->af_specific->md5_parse (sk, optname, optval, optlen);break ;#endif +case TCP_AUTHOPT : + err =tcp_set_authopt (sk, optval, optlen); +break ; +case TCP_AUTHOPT_KEY : + err =tcp_set_authopt_key (sk, optval, optlen); +break ;case TCP_USER_TIMEOUT :/* Cap the max time in ms TCP will retry or probe the window * before giving up and aborting (ETIMEDOUT) a connection. */ if (val <0 )
@@ -4251,10 +4258,33 @@ static int do_tcp_getsockopt(struct sock *sk, int level,if (!err &©_to_user (optval, &zc, len)) err = -EFAULT ;return err; }#endif +#ifdef CONFIG_TCP_AUTHOPT +case TCP_AUTHOPT : { +struct tcp_authopt info; +int err; + +if (get_user (len, optlen)) +return -EFAULT ; + +lock_sock (sk); + err =tcp_get_authopt_val (sk, &info); +release_sock (sk); + +if (err) +return err; + len = min_t(unsigned int, len, sizeof(info)); +if (put_user (len, optlen)) +return -EFAULT ; +if (copy_to_user (optval, &info, len)) +return -EFAULT ; +return 0 ; + } +#endif +default :return -ENOPROTOOPT ; }if (put_user (len, optlen))
net/ipv4/tcp_authopt.c new file +263 -0
263 lines not on this page · raw message
net/ipv4/tcp_ipv4.c +2 -0
@@ -60,10 +60,11 @@#include <net/net_namespace.h> #include <net/icmp.h> #include <net/inet_hashtables.h> #include <net/tcp.h> +#include <net/tcp_authopt.h> #include <net/transp_v6.h> #include <net/ipv6.h> #include <net/inet_common.h> #include <net/timewait_sock.h> #include <net/xfrm.h>
@@ -2276,10 +2277,11 @@ void tcp_v4_destroy_sock(struct sock *sk)tcp_clear_md5_list (sk);kfree_rcu (rcu_dereference_protected (tp->md5sig_info,1 ), rcu); tp->md5sig_info = NULL; }#endif +tcp_authopt_clear (sk);/* Clean up a referenced TCP bind bucket. */ if (inet_csk (sk)->icsk_bind_hash)inet_put_port (sk);
Signature · 1 line
2.25.1
PATCH v3 2/18 docs: Add user documentation for tcp_authopt
In reply to Leonard CrestezThe .rst documentation contains a brief description of the user interface and includes kernel-doc generated from uapi header.
--- Documentation/networking/index.rst | 1 + Documentation/networking/tcp_authopt.rst | 44 ++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 Documentation/networking/tcp_authopt.rst
Documentation/networking/index.rst +1 -0
@@ -100,10 +100,11 @@ Contents: strparser switchdev sysfs-tagging tc-actions-env-rules tcp-thin + tcp_authopt team timestamping tipc tproxy tuntap
Documentation/networking/tcp_authopt.rst new file +44 -0
44 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v3 3/18 tcp: authopt: Add crypto initialization
In reply to Leonard CrestezThe crypto_shash API is used in order to compute packet signatures. The API comes with several unfortunate limitations:
1) Allocating a crypto_shash can sleep and must be done in user context.
2) Packet signatures must be computed in softirq context
3) Packet signatures use dynamic "traffic keys" which require exclusive access to crypto_shash for crypto_setkey.
The solution is to allocate one crypto_shash for each possible cpu for each algorithm at setsockopt time. The per-cpu tfm is then borrowed from softirq context, signatures are computed and the tfm is returned.
The pool for each algorithm is allocated on first use.
--- include/net/tcp_authopt.h | 16 ++++ net/ipv4/tcp_authopt.c | 166 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+)
include/net/tcp_authopt.h +16 -0
@@ -2,10 +2,24 @@#ifndef _LINUX_TCP_AUTHOPT_H#define _LINUX_TCP_AUTHOPT_H#include <uapi/linux/tcp.h> +/* According to RFC5925 the length of the authentication option varies based on +* the signature algorithm. Linux only implements the algorithms defined in +* RFC5926 which have a constant length of 16. +* +* This is used in stack allocation of tcp option buffers for output. It is +* shorter than the length of the MD5 option. +* +* Input packets can have authentication options of different lengths but they +* will always be flagged as invalid (since no such algorithms are supported). +*/ +#define TCPOLEN_AUTHOPT_OUTPUT 16 + +struct tcp_authopt_alg_imp ; +/** * struct tcp_authopt_key_info - Representation of a Master Key Tuple as per RFC5925 * * Key structure lifetime is only protected by RCU so readers needs to hold a * single rcu_read_lock until they're done with the key.
@@ -27,10 +41,12 @@ struct tcp_authopt_key_info {u8 keylen;/** @key: Same as &tcp_authopt_key.key */ u8 key[TCP_AUTHOPT_MAXKEYLEN ];/** @addr: Same as &tcp_authopt_key.addr */ struct sockaddr_storage addr; +/** @alg: Algorithm implementation matching alg_id */ +struct tcp_authopt_alg_imp *alg; };/** * struct tcp_authopt_info - Per-socket information regarding tcp_authopt *
net/ipv4/tcp_authopt.c +166 -0
206 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v3 4/18 tcp: md5: Refactor tcp_sig_hash_skb_data for AO
In reply to Leonard CrestezThis chunk of code is identical between the implementation of TCP-MD5 and TCP-AO so rename and refactor
--- include/net/tcp.h | 2 +- net/ipv4/tcp.c | 38 ++++++++++++++++++++------------------ net/ipv4/tcp_ipv4.c | 2 +- net/ipv6/tcp_ipv6.c | 2 +- 4 files changed, 23 insertions(+), 21 deletions(-)
include/net/tcp.h +1 -1
@@ -1688,11 +1688,11 @@ struct tcp_md5sig_pool *tcp_get_md5sig_pool(void);static inline void tcp_put_md5sig_pool (void ) {local_bh_enable (); } -int tcp_md5_hash_skb_data (struct tcp_md5sig_pool *,const struct sk_buff *, +int tcp_sig_hash_skb_data (struct ahash_request *,const struct sk_buff *,unsigned int header_len);int tcp_md5_hash_key (struct tcp_md5sig_pool *hp,const struct tcp_md5sig_key *key);/* From tcp_fastopen.c */
net/ipv4/tcp.c +20 -18
@@ -4400,16 +4400,31 @@ struct tcp_md5sig_pool *tcp_get_md5sig_pool(void)local_bh_enable ();return NULL ; }EXPORT_SYMBOL (tcp_get_md5sig_pool); -int tcp_md5_hash_skb_data (struct tcp_md5sig_pool *hp, +int tcp_md5_hash_key (struct tcp_md5sig_pool *hp,const struct tcp_md5sig_key *key) +{ +u8 keylen =READ_ONCE (key->keylen);/* paired with WRITE_ONCE() in tcp_md5_do_add */ +struct scatterlist sg; + +sg_init_one (&sg, key->key, keylen); +ahash_request_set_crypt (hp->md5_req, &sg,NULL , keylen); + +/* We use data_race() because tcp_md5_do_add() might change key->key under us */ +return data_race (crypto_ahash_update (hp->md5_req)); +} +EXPORT_SYMBOL (tcp_md5_hash_key); +#endif /* CONFIG_TCP_MD5SIG */ + +#if defined(CONFIG_TCP_MD5SIG ) || defined(CONFIG_TCP_AUTHOPT ) + +int tcp_sig_hash_skb_data (struct ahash_request *req,const struct sk_buff *skb,unsigned int header_len) {struct scatterlist sg;const struct tcphdr *tp =tcp_hdr (skb); -struct ahash_request *req = hp->md5_req;unsigned int i;const unsigned int head_data_len =skb_headlen (skb) > header_len ?skb_headlen (skb) - header_len :0 ;const struct skb_shared_info *shi =skb_shinfo (skb);struct sk_buff *frag_iter;
@@ -4432,31 +4447,18 @@ int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp,if (crypto_ahash_update (req))return 1 ; } skb_walk_frags(skb, frag_iter) -if (tcp_md5_hash_skb_data (hp, frag_iter,0 )) +if (tcp_sig_hash_skb_data (req, frag_iter,0 ))return 1 ;return 0 ; } -EXPORT_SYMBOL (tcp_md5_hash_skb_data); +EXPORT_SYMBOL (tcp_sig_hash_skb_data); -int tcp_md5_hash_key (struct tcp_md5sig_pool *hp,const struct tcp_md5sig_key *key) -{ -u8 keylen =READ_ONCE (key->keylen);/* paired with WRITE_ONCE() in tcp_md5_do_add */ -struct scatterlist sg; - -sg_init_one (&sg, key->key, keylen); -ahash_request_set_crypt (hp->md5_req, &sg,NULL , keylen); - -/* We use data_race() because tcp_md5_do_add() might change key->key under us */ -return data_race (crypto_ahash_update (hp->md5_req)); -} -EXPORT_SYMBOL (tcp_md5_hash_key); - -#endif +#endif /* defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AUTHOPT) */ void tcp_done (struct sock *sk) {struct request_sock *req;
net/ipv4/tcp_ipv4.c +1 -1
@@ -1381,11 +1381,11 @@ int tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key,if (crypto_ahash_init (req)) goto clear_hash;if (tcp_v4_md5_hash_headers (hp, daddr, saddr, th, skb->len)) goto clear_hash; -if (tcp_md5_hash_skb_data (hp, skb, th->doff <<2 )) +if (tcp_sig_hash_skb_data (hp->md5_req, skb, th->doff <<2 )) goto clear_hash;if (tcp_md5_hash_key (hp, key)) goto clear_hash;ahash_request_set_crypt (req,NULL , md5_hash,0 );if (crypto_ahash_final (req))
net/ipv6/tcp_ipv6.c +1 -1
@@ -750,11 +750,11 @@ static int tcp_v6_md5_hash_skb(char *md5_hash,if (crypto_ahash_init (req)) goto clear_hash;if (tcp_v6_md5_hash_headers (hp, daddr, saddr, th, skb->len)) goto clear_hash; -if (tcp_md5_hash_skb_data (hp, skb, th->doff <<2 )) +if (tcp_sig_hash_skb_data (hp->md5_req, skb, th->doff <<2 )) goto clear_hash;if (tcp_md5_hash_key (hp, key)) goto clear_hash;ahash_request_set_crypt (req,NULL , md5_hash,0 );if (crypto_ahash_final (req))
Signature · 1 line
2.25.1
PATCH v3 5/18 tcp: authopt: Compute packet signatures
In reply to Leonard CrestezComputing tcp authopt packet signatures is a two step process:
* traffic key is computed based on tcp 4-tuple, initial sequence numbers and the secret key.
* packet mac is computed based on traffic key and content of individual packets.
The traffic key could be cached for established sockets but it is not.
A single code path exists for ipv4/ipv6 and input/output. This keeps the code short but slightly slower due to lots of conditionals.
On output we read remote IP address from socket members on output, we can't use skb network header because it's computed after TCP options.
On input we read remote IP address from skb network headers, we can't use socket binding members because those are not available for SYN.
--- include/net/tcp_authopt.h | 9 + net/ipv4/tcp_authopt.c | 537 +++++++++++++++++++++++++++++++++++--- 2 files changed, 510 insertions(+), 36 deletions(-)
include/net/tcp_authopt.h +9 -0
@@ -64,10 +64,19 @@ struct tcp_authopt_info {u32 src_isn;/** @dst_isn: Remote Initial Sequence Number */ u32 dst_isn; }; +/* TCP authopt as found in header */ +struct tcphdr_authopt { +u8 num; +u8 len; +u8 keyid; +u8 rnextkeyid; +u8 mac[0 ]; +}; +#ifdef CONFIG_TCP_AUTHOPT void tcp_authopt_clear (struct sock *sk);int tcp_set_authopt (struct sock *sk,sockptr_t optval,unsigned int optlen);int tcp_get_authopt_val (struct sock *sk,struct tcp_authopt *key);int tcp_set_authopt_key (struct sock *sk,sockptr_t optval,unsigned int optlen);
net/ipv4/tcp_authopt.c +501 -36
631 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v3 6/18 tcp: authopt: Hook into tcp core
In reply to Leonard CrestezThe tcp_authopt features exposes a minimal interface to the rest of the TCP stack. Only a few functions are exposed and if the feature is disabled they return neutral values, avoiding ifdefs in the rest of the code. This approach is different from MD5.
There very few interactions with MD5 but tcp_parse_md5sig_option was modifed to parse AO and MD5 simultaneously. If both are present the packet is droppped as required by RFC5925.
Add calls into tcp authopt from send, receive and accept code.
--- include/net/tcp.h | 24 +++- include/net/tcp_authopt.h | 135 ++++++++++++++++++ include/uapi/linux/snmp.h | 1 + net/ipv4/proc.c | 1 + net/ipv4/tcp_authopt.c | 293 ++++++++++++++++++++++++++++++++++++++ net/ipv4/tcp_input.c | 40 ++++-- net/ipv4/tcp_ipv4.c | 50 ++++++- net/ipv4/tcp_minisocks.c | 12 ++ net/ipv4/tcp_output.c | 85 ++++++++++- net/ipv6/tcp_ipv6.c | 49 ++++++- 10 files changed, 665 insertions(+), 25 deletions(-)
include/net/tcp.h +23 -1
@@ -422,11 +422,33 @@ int tcp_mmap(struct file *file, struct socket *sock, struct vm_area_struct *vma);#endif void tcp_parse_options (const struct net *net,const struct sk_buff *skb,struct tcp_options_received *opt_rx,int estab,struct tcp_fastopen_cookie *foc); -const u8 *tcp_parse_md5sig_option (const struct tcphdr *th); +#if defined(CONFIG_TCP_MD5SIG ) || defined(CONFIG_TCP_AUTHOPT ) +int tcp_parse_sig_options (const struct tcphdr *th, +const u8 **md5ptr, +const u8 **aoptr); +#else +static inline int tcp_parse_sig_options (const struct tcphdr *th, +const u8 **md5ptr, +const u8 **aoptr) +{ + aoptr =NULL ; + md5ptr =NULL ; +return 0 ; +} +#endif +static inline const u8 *tcp_parse_md5sig_option (const struct tcphdr *th) +{ +const u8 *md5, *ao; +int ret; + + ret =tcp_parse_sig_options (th, &md5, &ao); + +return (md5 && !ao && !ret) ? md5 :NULL ; +}/* * BPF SKB-less helpers */ u16 tcp_v4_get_syncookie(struct sock *sk, struct iphdr *iph,
include/net/tcp_authopt.h +135 -0
163 lines not on this page · raw message
include/uapi/linux/snmp.h +1 -0
@@ -290,10 +290,11 @@ enumLINUX_MIB_TCPDUPLICATEDATAREHASH ,/* TCPDuplicateDataRehash */ LINUX_MIB_TCPDSACKRECVSEGS ,/* TCPDSACKRecvSegs */ LINUX_MIB_TCPDSACKIGNOREDDUBIOUS ,/* TCPDSACKIgnoredDubious */ LINUX_MIB_TCPMIGRATEREQSUCCESS ,/* TCPMigrateReqSuccess */ LINUX_MIB_TCPMIGRATEREQFAILURE ,/* TCPMigrateReqFailure */ +LINUX_MIB_TCPAUTHOPTFAILURE ,/* TCPAuthOptFailure */ __LINUX_MIB_MAX };/* linux Xfrm mib definitions */ enum
net/ipv4/proc.c +1 -0
@@ -295,10 +295,11 @@ static const struct snmp_mib snmp4_net_list[] = {SNMP_MIB_ITEM ("TcpDuplicateDataRehash" ,LINUX_MIB_TCPDUPLICATEDATAREHASH ),SNMP_MIB_ITEM ("TCPDSACKRecvSegs" ,LINUX_MIB_TCPDSACKRECVSEGS ),SNMP_MIB_ITEM ("TCPDSACKIgnoredDubious" ,LINUX_MIB_TCPDSACKIGNOREDDUBIOUS ),SNMP_MIB_ITEM ("TCPMigrateReqSuccess" ,LINUX_MIB_TCPMIGRATEREQSUCCESS ),SNMP_MIB_ITEM ("TCPMigrateReqFailure" ,LINUX_MIB_TCPMIGRATEREQFAILURE ), +SNMP_MIB_ITEM ("TCPAuthOptFailure" ,LINUX_MIB_TCPAUTHOPTFAILURE ), SNMP_MIB_SENTINEL };static void icmpmsg_put_line (struct seq_file *seq,unsigned long *vals,unsigned short *type,int count)
net/ipv4/tcp_authopt.c +293 -0
367 lines not on this page · raw message
net/ipv4/tcp_input.c +30 -10
@@ -70,10 +70,11 @@#include <linux/sysctl.h> #include <linux/kernel.h> #include <linux/prefetch.h> #include <net/dst.h> #include <net/tcp.h> +#include <net/tcp_authopt.h> #include <net/inet_common.h> #include <linux/ipsec.h> #include <asm/unaligned.h> #include <linux/errqueue.h> #include <trace/events/tcp.h>
@@ -4173,43 +4174,60 @@ static bool tcp_fast_parse_options(const struct net *net, tp->rx_opt.rcv_tsecr -= tp->tsoffset;return true; } -#ifdef CONFIG_TCP_MD5SIG +#if defined(CONFIG_TCP_MD5SIG ) || defined(CONFIG_TCP_AUTHOPT )/* -* Parse MD5 Signature option +* Parse MD5 and AO options +* +* md5ptr: pointer to content of MD5 option (16-byte hash) +* aoptr: pointer to start of AO option (variable length) */ -const u8 *tcp_parse_md5sig_option (const struct tcphdr *th) +int tcp_parse_sig_options (const struct tcphdr *th,const u8 **md5ptr,const u8 **aoptr) {int length = (th->doff <<2 ) -sizeof (*th);const u8 *ptr = (const u8 *)(th +1 ); + *md5ptr =NULL ; + *aoptr =NULL ; +/* If not enough data remaining, we can short cut */ -while (length >=TCPOLEN_MD5SIG ) { +while (length >=4 ) {int opcode = *ptr++;int opsize;switch (opcode) {case TCPOPT_EOL : -return NULL ; + goto out;case TCPOPT_NOP : length--;continue ;default : opsize = *ptr++;if (opsize <2 || opsize > length) -return NULL ; -if (opcode ==TCPOPT_MD5SIG ) -return opsize ==TCPOLEN_MD5SIG ? ptr :NULL ; + goto out; +if (opcode ==TCPOPT_MD5SIG && opsize ==TCPOLEN_MD5SIG ) + *md5ptr = ptr; +if (opcode ==TCPOPT_AUTHOPT ) + *aoptr = ptr -2 ; } ptr += opsize -2 ; length -= opsize; } -return NULL ; + +out: +/* RFC5925 2.2: An endpoint MUST NOT use TCP-AO for the same connection +* in which TCP MD5 is used. When both options appear, TCP MUST silently +* discard the segment. +*/ +if (*md5ptr && *aoptr) +return -EINVAL ; + +return 0 ; } -EXPORT_SYMBOL (tcp_parse_md5sig_option); +EXPORT_SYMBOL (tcp_parse_sig_options);#endif /* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM * * It is not fatal. If this ACK does _not_ change critical state (seqs, window)
@@ -5992,10 +6010,12 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb)struct inet_connection_sock *icsk =inet_csk (sk);tcp_set_state (sk,TCP_ESTABLISHED ); icsk->icsk_ack.lrcvtime = tcp_jiffies32; +tcp_authopt_finish_connect (sk, skb); +if (skb) { icsk->icsk_af_ops->sk_rx_dst_set (sk, skb);security_inet_conn_established (sk, skb);sk_mark_napi_id (sk, skb); }
net/ipv4/tcp_ipv4.c +43 -7
108 lines not on this page · raw message
net/ipv4/tcp_minisocks.c +12 -0
@@ -18,10 +18,11 @@* Arnt Gulbrandsen, <[email protected]> * Jorge Cwik, <[email protected]> */ #include <net/tcp.h> +#include <net/tcp_authopt.h> #include <net/xfrm.h> #include <net/busy_poll.h> static bool tcp_in_window (u32 seq,u32 end_seq,u32 s_win,u32 e_win) {
@@ -300,10 +301,11 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) BUG_ON(tcptw->tw_md5_key && !tcp_alloc_md5sig_pool()); } } }while (0 );#endif +tcp_authopt_time_wait (tcptw,tcp_sk (sk));/* Get the TIME_WAIT timeout firing. */ if (timeo < rto) timeo = rto;
@@ -342,10 +344,19 @@ void tcp_twsk_destructor(struct sock *sk)if (twsk->tw_md5_key) kfree_rcu(twsk->tw_md5_key, rcu); }#endif +#ifdef CONFIG_TCP_AUTHOPT +if (tcp_authopt_needed) { +struct tcp_timewait_sock *twsk =tcp_twsk (sk); + +/* twsk only contains sock_common so pass NULL as sk. */ +if (twsk->tw_authopt_info) +tcp_authopt_free (NULL , twsk->tw_authopt_info); + } +#endif }EXPORT_SYMBOL_GPL (tcp_twsk_destructor);/* Warning : This function is called without sk_listener being locked. * Be sure to read socket fields once, as their value could change under us.
@@ -532,10 +543,11 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,#ifdef CONFIG_TCP_MD5SIG newtp->md5sig_info =NULL ;/*XXX*/ if (newtp->af_specific->md5_lookup (sk, newsk)) newtp->tcp_header_len +=TCPOLEN_MD5SIG_ALIGNED ;#endif +tcp_authopt_openreq (newsk, sk, req);if (skb->len >=TCP_MSS_DEFAULT + newtp->tcp_header_len) newicsk->icsk_ack.last_seg_size = skb->len - newtp->tcp_header_len; newtp->rx_opt.mss_clamp = req->mss;tcp_ecn_openreq_child (newtp, req); newtp->fastopen_req =NULL ;
net/ipv4/tcp_output.c +83 -2
228 lines not on this page · raw message
net/ipv6/tcp_ipv6.c +44 -5
111 lines not on this page · raw message
Signature · 1 line
2.25.1
kernel test robot
build botRe: [PATCH v3 06/18] tcp: authopt: Hook into tcp core
Thank you for the patch! Perhaps something to improve:
Hi Leonard,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on 1fe5b01262844be03de98afdd56d1d393df04d7e]
url: https://github.com/0day-ci/linux/commits/Leonard-Crestez/tcp-Initial-support-for-RFC5925-auth-option/20211208-194125 base: 1fe5b01262844be03de98afdd56d1d393df04d7e config: um-i386_defconfig (https://download.01.org/0day-ci/archive/20211209/202112090014.hZOqnSC4-lkp(a)intel.com/config) compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce (this is a W=1 build):
# https://github.com/0day-ci/linux/commit/5935c41094c73eec0e3c39119d7bfb22de066c3b
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Leonard-Crestez/tcp-Initial-support-for-RFC5925-auth-option/20211208-194125 git checkout 5935c41094c73eec0e3c39119d7bfb22de066c3b
# save the config file to linux build tree
mkdir build_dir
make W=1 O=build_dir ARCH=um SUBARCH=i386 SHELL=/bin/bash net/core/
If you fix the issue, kindly add following tag as appropriate
All warnings (new ones prefixed by >>):
In file included from net/core/sock.c:139:
include/net/tcp.h: In function 'tcp_parse_sig_options':
>> include/net/tcp.h:433:17: warning: parameter 'md5ptr' set but not used [-Wunused-but-set-parameter]
433 | const u8 **md5ptr,
| ~~~~~~~~~~~^~~~~~
>> include/net/tcp.h:434:17: warning: parameter 'aoptr' set but not used [-Wunused-but-set-parameter]
434 | const u8 **aoptr)
| ~~~~~~~~~~~^~~~~vim +/md5ptr +433 include/net/tcp.h
381
382
383 enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw,
384 struct sk_buff *skb,
385 const struct tcphdr *th);
386 struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
387 struct request_sock *req, bool fastopen,
388 bool *lost_race);
389 int tcp_child_process(struct sock *parent, struct sock *child,
390 struct sk_buff *skb);
391 void tcp_enter_loss(struct sock *sk);
392 void tcp_cwnd_reduction(struct sock *sk, int newly_acked_sacked, int newly_lost, int flag);
393 void tcp_clear_retrans(struct tcp_sock *tp);
394 void tcp_update_metrics(struct sock *sk);
395 void tcp_init_metrics(struct sock *sk);
396 void tcp_metrics_init(void);
397 bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst);
398 void __tcp_close(struct sock *sk, long timeout);
399 void tcp_close(struct sock *sk, long timeout);
400 void tcp_init_sock(struct sock *sk);
401 void tcp_init_transfer(struct sock *sk, int bpf_op, struct sk_buff *skb);
402 __poll_t tcp_poll(struct file *file, struct socket *sock,
403 struct poll_table_struct *wait);
404 int tcp_getsockopt(struct sock *sk, int level, int optname,
405 char __user *optval, int __user *optlen);
406 bool tcp_bpf_bypass_getsockopt(int level, int optname);
407 int tcp_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
408 unsigned int optlen);
409 void tcp_set_keepalive(struct sock *sk, int val);
410 void tcp_syn_ack_timeout(const struct request_sock *req);
411 int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
412 int flags, int *addr_len);
413 int tcp_set_rcvlowat(struct sock *sk, int val);
414 int tcp_set_window_clamp(struct sock *sk, int val);
415 void tcp_update_recv_tstamps(struct sk_buff *skb,
416 struct scm_timestamping_internal *tss);
417 void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
418 struct scm_timestamping_internal *tss);
419 void tcp_data_ready(struct sock *sk);
420 #ifdef CONFIG_MMU
421 int tcp_mmap(struct file *file, struct socket *sock,
422 struct vm_area_struct *vma);
423 #endif
424 void tcp_parse_options(const struct net *net, const struct sk_buff *skb,
425 struct tcp_options_received *opt_rx,
426 int estab, struct tcp_fastopen_cookie *foc);
427 #if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AUTHOPT)
428 int tcp_parse_sig_options(const struct tcphdr *th,
429 const u8 **md5ptr,
430 const u8 **aoptr);
431 #else
432 static inline int tcp_parse_sig_options(const struct tcphdr *th,
> 433 const u8 **md5ptr, > 434 const u8 **aoptr)
435 {
436 aoptr = NULL;
437 md5ptr = NULL;
438 return 0;
439 }
440 #endif
441 static inline const u8 *tcp_parse_md5sig_option(const struct tcphdr *th)
442 {
443 const u8 *md5, *ao;
444 int ret;
445
446 ret = tcp_parse_sig_options(th, &md5, &ao);
447
448 return (md5 && !ao && !ret) ? md5 : NULL;
449 }
450
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
kernel test robot
build botRe: [PATCH v3 06/18] tcp: authopt: Hook into tcp core
In reply to Leonard CrestezThank you for the patch! Perhaps something to improve:
Hi Leonard,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on 1fe5b01262844be03de98afdd56d1d393df04d7e]
url: https://github.com/0day-ci/linux/commits/Leonard-Crestez/tcp-Initial-support-for-RFC5925-auth-option/20211208-194125 base: 1fe5b01262844be03de98afdd56d1d393df04d7e config: i386-randconfig-a013-20211207 (https://download.01.org/0day-ci/archive/20211209/202112090452.jW34oJZF-lkp(a)intel.com/config) compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project 097a1cb1d5ebb3a0ec4bcaed8ba3ff6a8e33c00a)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/5935c41094c73eec0e3c39119d7bfb22de066c3b
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Leonard-Crestez/tcp-Initial-support-for-RFC5925-auth-option/20211208-194125 git checkout 5935c41094c73eec0e3c39119d7bfb22de066c3b
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 SHELL=/bin/bash
If you fix the issue, kindly add following tag as appropriate
All warnings (new ones prefixed by >>):
In file included from net/bpf/test_run.c:15:
>> include/net/tcp.h:433:17: warning: parameter 'md5ptr' set but not used [-Wunused-but-set-parameter]
const u8 **md5ptr,
^
>> include/net/tcp.h:434:17: warning: parameter 'aoptr' set but not used [-Wunused-but-set-parameter]
const u8 **aoptr)
^
net/bpf/test_run.c:170:14: warning: no previous prototype for function 'bpf_fentry_test1' [-Wmissing-prototypes]
int noinline bpf_fentry_test1(int a)
^
net/bpf/test_run.c:170:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int noinline bpf_fentry_test1(int a)
^
static
net/bpf/test_run.c:175:14: warning: no previous prototype for function 'bpf_fentry_test2' [-Wmissing-prototypes]
int noinline bpf_fentry_test2(int a, u64 b)
^
net/bpf/test_run.c:175:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int noinline bpf_fentry_test2(int a, u64 b)
^
static
net/bpf/test_run.c:180:14: warning: no previous prototype for function 'bpf_fentry_test3' [-Wmissing-prototypes]
int noinline bpf_fentry_test3(char a, int b, u64 c)
^
net/bpf/test_run.c:180:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int noinline bpf_fentry_test3(char a, int b, u64 c)
^
static
net/bpf/test_run.c:185:14: warning: no previous prototype for function 'bpf_fentry_test4' [-Wmissing-prototypes]
int noinline bpf_fentry_test4(void *a, char b, int c, u64 d)
^
net/bpf/test_run.c:185:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int noinline bpf_fentry_test4(void *a, char b, int c, u64 d)
^
static
net/bpf/test_run.c:190:14: warning: no previous prototype for function 'bpf_fentry_test5' [-Wmissing-prototypes]
int noinline bpf_fentry_test5(u64 a, void *b, short c, int d, u64 e)
^
net/bpf/test_run.c:190:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int noinline bpf_fentry_test5(u64 a, void *b, short c, int d, u64 e)
^
static
net/bpf/test_run.c:195:14: warning: no previous prototype for function 'bpf_fentry_test6' [-Wmissing-prototypes]
int noinline bpf_fentry_test6(u64 a, void *b, short c, int d, void *e, u64 f)
^
net/bpf/test_run.c:195:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int noinline bpf_fentry_test6(u64 a, void *b, short c, int d, void *e, u64 f)
^
static
net/bpf/test_run.c:204:14: warning: no previous prototype for function 'bpf_fentry_test7' [-Wmissing-prototypes]
int noinline bpf_fentry_test7(struct bpf_fentry_test_t *arg)
^
net/bpf/test_run.c:204:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int noinline bpf_fentry_test7(struct bpf_fentry_test_t *arg)
^
static
net/bpf/test_run.c:209:14: warning: no previous prototype for function 'bpf_fentry_test8' [-Wmissing-prototypes]
int noinline bpf_fentry_test8(struct bpf_fentry_test_t *arg)
^
net/bpf/test_run.c:209:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int noinline bpf_fentry_test8(struct bpf_fentry_test_t *arg)
^
static
net/bpf/test_run.c:214:14: warning: no previous prototype for function 'bpf_modify_return_test' [-Wmissing-prototypes]
int noinline bpf_modify_return_test(int a, int *b)
^
net/bpf/test_run.c:214:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int noinline bpf_modify_return_test(int a, int *b)
^
static
net/bpf/test_run.c:220:14: warning: no previous prototype for function 'bpf_kfunc_call_test1' [-Wmissing-prototypes]
u64 noinline bpf_kfunc_call_test1(struct sock *sk, u32 a, u64 b, u32 c, u64 d)
^
net/bpf/test_run.c:220:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
u64 noinline bpf_kfunc_call_test1(struct sock *sk, u32 a, u64 b, u32 c, u64 d)
^
static
net/bpf/test_run.c:225:14: warning: no previous prototype for function 'bpf_kfunc_call_test2' [-Wmissing-prototypes]
int noinline bpf_kfunc_call_test2(struct sock *sk, u32 a, u32 b)
^
net/bpf/test_run.c:225:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
int noinline bpf_kfunc_call_test2(struct sock *sk, u32 a, u32 b)
^
static
net/bpf/test_run.c:230:24: warning: no previous prototype for function 'bpf_kfunc_call_test3' [-Wmissing-prototypes]
struct sock * noinline bpf_kfunc_call_test3(struct sock *sk)
^ net/bpf/test_run.c:230:1: note: declare 'static' if the function is not intended to be used outside of this translation unit struct sock * noinline bpf_kfunc_call_test3(struct sock *sk)
^
static
14 warnings generated.
--
In file included from net/core/skmsg.c:4:
In file included from include/linux/skmsg.h:13:
>> include/net/tcp.h:433:17: warning: parameter 'md5ptr' set but not used [-Wunused-but-set-parameter]
const u8 **md5ptr,
^
>> include/net/tcp.h:434:17: warning: parameter 'aoptr' set but not used [-Wunused-but-set-parameter] const u8 **aoptr)
^
2 warnings generated.
--
In file included from net/core/sock_map.c:11:
In file included from include/linux/skmsg.h:13:
>> include/net/tcp.h:434:17: warning: parameter 'aoptr' set but not used [-Wunused-but-set-parameter]
const u8 **aoptr)
^
>> include/net/tcp.h:433:17: warning: parameter 'md5ptr' set but not used [-Wunused-but-set-parameter]
const u8 **md5ptr,
^
2 warnings generated.
--
In file included from net/ipv4/route.c:94:
>> include/net/tcp.h:433:17: warning: parameter 'md5ptr' set but not used [-Wunused-but-set-parameter]
const u8 **md5ptr,
^
>> include/net/tcp.h:434:17: warning: parameter 'aoptr' set but not used [-Wunused-but-set-parameter]
const u8 **aoptr)
^
net/ipv4/route.c:869:6: warning: variable 'log_martians' set but not used [-Wunused-but-set-variable]
int log_martians;
^
3 warnings generated.
--
In file included from net/ipv4/tcp_output.c:40:
>> include/net/tcp.h:434:17: warning: parameter 'aoptr' set but not used [-Wunused-but-set-parameter]
const u8 **aoptr)
^
>> include/net/tcp.h:433:17: warning: parameter 'md5ptr' set but not used [-Wunused-but-set-parameter]
const u8 **md5ptr,
^
net/ipv4/tcp_output.c:189:3: warning: result of comparison of constant -1 with expression of type 'u8' (aka 'unsigned char') is always false [-Wtautological-constant-out-of-range-compare]
NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPACKCOMPRESSED,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/net/ip.h:292:41: note: expanded from macro 'NET_ADD_STATS'
#define NET_ADD_STATS(net, field, adnd) SNMP_ADD_STATS((net)->mib.net_statistics, field, adnd)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/net/snmp.h:143:4: note: expanded from macro 'SNMP_ADD_STATS'
this_cpu_add(mib->mibs[field], addend)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/percpu-defs.h:509:33: note: expanded from macro 'this_cpu_add'
#define this_cpu_add(pcp, val) __pcpu_size_call(this_cpu_add_, pcp, val)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: (skipping 1 expansions in backtrace; use -fmacro-backtrace-limit=0 to see all)
<scratch space>:113:1: note: expanded from here
this_cpu_add_4
^
arch/x86/include/asm/percpu.h:268:34: note: expanded from macro 'this_cpu_add_4'
#define this_cpu_add_4(pcp, val) percpu_add_op(4, volatile, (pcp), val)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
arch/x86/include/asm/percpu.h:127:31: note: expanded from macro 'percpu_add_op'
((val) == 1 || (val) == -1)) ? \
~~~~~ ^ ~~
3 warnings generated.
--
In file included from net/mptcp/options.c:11:
>> include/net/tcp.h:434:17: warning: parameter 'aoptr' set but not used [-Wunused-but-set-parameter]
const u8 **aoptr)
^
>> include/net/tcp.h:433:17: warning: parameter 'md5ptr' set but not used [-Wunused-but-set-parameter]
const u8 **md5ptr,
^ net/mptcp/options.c:552:21: warning: parameter 'remaining' set but not used [-Wunused-but-set-parameter]
unsigned int remaining,
^
3 warnings generated.
vim +/md5ptr +433 include/net/tcp.h
381
382
383 enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw,
384 struct sk_buff *skb,
385 const struct tcphdr *th);
386 struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
387 struct request_sock *req, bool fastopen,
388 bool *lost_race);
389 int tcp_child_process(struct sock *parent, struct sock *child,
390 struct sk_buff *skb);
391 void tcp_enter_loss(struct sock *sk);
392 void tcp_cwnd_reduction(struct sock *sk, int newly_acked_sacked, int newly_lost, int flag);
393 void tcp_clear_retrans(struct tcp_sock *tp);
394 void tcp_update_metrics(struct sock *sk);
395 void tcp_init_metrics(struct sock *sk);
396 void tcp_metrics_init(void);
397 bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst);
398 void __tcp_close(struct sock *sk, long timeout);
399 void tcp_close(struct sock *sk, long timeout);
400 void tcp_init_sock(struct sock *sk);
401 void tcp_init_transfer(struct sock *sk, int bpf_op, struct sk_buff *skb);
402 __poll_t tcp_poll(struct file *file, struct socket *sock,
403 struct poll_table_struct *wait);
404 int tcp_getsockopt(struct sock *sk, int level, int optname,
405 char __user *optval, int __user *optlen);
406 bool tcp_bpf_bypass_getsockopt(int level, int optname);
407 int tcp_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
408 unsigned int optlen);
409 void tcp_set_keepalive(struct sock *sk, int val);
410 void tcp_syn_ack_timeout(const struct request_sock *req);
411 int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
412 int flags, int *addr_len);
413 int tcp_set_rcvlowat(struct sock *sk, int val);
414 int tcp_set_window_clamp(struct sock *sk, int val);
415 void tcp_update_recv_tstamps(struct sk_buff *skb,
416 struct scm_timestamping_internal *tss);
417 void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
418 struct scm_timestamping_internal *tss);
419 void tcp_data_ready(struct sock *sk);
420 #ifdef CONFIG_MMU
421 int tcp_mmap(struct file *file, struct socket *sock,
422 struct vm_area_struct *vma);
423 #endif
424 void tcp_parse_options(const struct net *net, const struct sk_buff *skb,
425 struct tcp_options_received *opt_rx,
426 int estab, struct tcp_fastopen_cookie *foc);
427 #if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AUTHOPT)
428 int tcp_parse_sig_options(const struct tcphdr *th,
429 const u8 **md5ptr,
430 const u8 **aoptr);
431 #else
432 static inline int tcp_parse_sig_options(const struct tcphdr *th,
> 433 const u8 **md5ptr, > 434 const u8 **aoptr)
435 {
436 aoptr = NULL;
437 md5ptr = NULL;
438 return 0;
439 }
440 #endif
441 static inline const u8 *tcp_parse_md5sig_option(const struct tcphdr *th)
442 {
443 const u8 *md5, *ao;
444 int ret;
445
446 ret = tcp_parse_sig_options(th, &md5, &ao);
447
448 return (md5 && !ao && !ret) ? md5 : NULL;
449 }
450
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
kernel test robot
build botRe: [PATCH v3 06/18] tcp: authopt: Hook into tcp core
In reply to Leonard CrestezThank you for the patch! Perhaps something to improve:
Hi Leonard,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on 1fe5b01262844be03de98afdd56d1d393df04d7e]
url: https://github.com/0day-ci/linux/commits/Leonard-Crestez/tcp-Initial-support-for-RFC5925-auth-option/20211208-194125 base: 1fe5b01262844be03de98afdd56d1d393df04d7e config: m68k-randconfig-s031-20211209 (https://download.01.org/0day-ci/archive/20211209/202112092027.W9QemnAk-lkp(a)intel.com/config) compiler: m68k-linux-gcc (GCC) 11.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# apt-get install sparse
# sparse version: v0.6.4-dirty
# https://github.com/0day-ci/linux/commit/5935c41094c73eec0e3c39119d7bfb22de066c3b
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Leonard-Crestez/tcp-Initial-support-for-RFC5925-auth-option/20211208-194125
git checkout 5935c41094c73eec0e3c39119d7bfb22de066c3b
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=m68k SHELL=/bin/bash net/ipv4/
If you fix the issue, kindly add following tag as appropriate
sparse warnings: (new ones prefixed by >>)
net/ipv4/tcp_minisocks.c: note: in included file:
>> include/net/tcp_authopt.h:145:40: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct tcp_authopt_info *tw_authopt_info @@ got struct tcp_authopt_info [noderef] __rcu *authopt_info @@
include/net/tcp_authopt.h:145:40: sparse: expected struct tcp_authopt_info *tw_authopt_info
include/net/tcp_authopt.h:145:40: sparse: got struct tcp_authopt_info [noderef] __rcu *authopt_info
vim +145 include/net/tcp_authopt.h
81
82 void tcp_authopt_free(struct sock *sk, struct tcp_authopt_info *info);
83 void tcp_authopt_clear(struct sock *sk);
84 int tcp_set_authopt(struct sock *sk, sockptr_t optval, unsigned int optlen);
85 int tcp_get_authopt_val(struct sock *sk, struct tcp_authopt *key);
86 int tcp_set_authopt_key(struct sock *sk, sockptr_t optval, unsigned int optlen);
87 struct tcp_authopt_key_info *__tcp_authopt_select_key(
88 const struct sock *sk,
89 struct tcp_authopt_info *info,
90 const struct sock *addr_sk,
91 u8 *rnextkeyid);
92 static inline struct tcp_authopt_key_info *tcp_authopt_select_key(
93 const struct sock *sk,
94 const struct sock *addr_sk,
95 struct tcp_authopt_info **info,
96 u8 *rnextkeyid)
97 {
98 if (tcp_authopt_needed) {
99 *info = rcu_dereference(tcp_sk(sk)->authopt_info);
100
101 if (*info)
102 return __tcp_authopt_select_key(sk, *info, addr_sk, rnextkeyid);
103 }
104 return NULL;
105 }
106 int tcp_authopt_hash(
107 char *hash_location,
108 struct tcp_authopt_key_info *key,
109 struct tcp_authopt_info *info,
110 struct sock *sk, struct sk_buff *skb);
111 int __tcp_authopt_openreq(struct sock *newsk, const struct sock *oldsk, struct request_sock *req);
112 static inline int tcp_authopt_openreq(
113 struct sock *newsk,
114 const struct sock *oldsk,
115 struct request_sock *req)
116 {
117 if (!rcu_dereference(tcp_sk(oldsk)->authopt_info))
118 return 0;
119 else
120 return __tcp_authopt_openreq(newsk, oldsk, req);
121 }
122 void __tcp_authopt_finish_connect(struct sock *sk, struct sk_buff *skb,
123 struct tcp_authopt_info *info);
124 static inline void tcp_authopt_finish_connect(struct sock *sk, struct sk_buff *skb)
125 {
126 struct tcp_authopt_info *info;
127
128 if (tcp_authopt_needed) {
129 info = rcu_dereference_protected(tcp_sk(sk)->authopt_info,
130 lockdep_sock_is_held(sk));
131
132 if (info)
133 __tcp_authopt_finish_connect(sk, skb, info);
134 }
135 }
136 static inline void tcp_authopt_time_wait(
137 struct tcp_timewait_sock *tcptw,
138 struct tcp_sock *tp)
139 {
140 if (tcp_authopt_needed) {
141 /* Transfer ownership of authopt_info to the twsk
142 * This requires no other users of the origin sock.
143 */
144 sock_owned_by_me((struct sock *)tp);
> 145 tcptw->tw_authopt_info = tp->authopt_info; 146 tp->authopt_info = NULL;
147 } else {
148 tcptw->tw_authopt_info = NULL;
149 }
150 }
151 /** tcp_authopt_inbound_check - check for valid TCP-AO signature.
152 *
153 * Return negative ERRNO on error, 0 if not present and 1 if present and valid.
154 *
155 * If the AO signature is present and valid then caller skips MD5 check.
156 */
157 int __tcp_authopt_inbound_check(
158 struct sock *sk,
159 struct sk_buff *skb,
160 struct tcp_authopt_info *info,
161 const u8 *opt);
162 static inline int tcp_authopt_inbound_check(struct sock *sk, struct sk_buff *skb, const u8 *opt)
163 {
164 if (tcp_authopt_needed) {
165 struct tcp_authopt_info *info = rcu_dereference(tcp_sk(sk)->authopt_info);
166
167 if (info)
168 return __tcp_authopt_inbound_check(sk, skb, info, opt);
169 }
170 return 0;
171 }
172 static inline int tcp_authopt_inbound_check_req(struct request_sock *req, struct sk_buff *skb,
173 const u8 *opt)
174 {
175 if (tcp_authopt_needed) {
176 struct sock *lsk = req->rsk_listener;
177 struct tcp_authopt_info *info = rcu_dereference(tcp_sk(lsk)->authopt_info);
178
179 if (info)
180 return __tcp_authopt_inbound_check((struct sock *)req, skb, info, opt);
181 }
182 return 0;
183 }
184 #else
185 static inline int tcp_set_authopt(struct sock *sk, sockptr_t optval, unsigned int optlen)
186 {
187 return -ENOPROTOOPT;
188 }
189 static inline int tcp_get_authopt_val(struct sock *sk, struct tcp_authopt *key)
190 {
191 return -ENOPROTOOPT;
192 }
193 static inline void tcp_authopt_free(struct sock *sk, struct tcp_authopt_info *info)
194 {
195 }
196 static inline void tcp_authopt_clear(struct sock *sk)
197 {
198 }
199 static inline int tcp_set_authopt_key(struct sock *sk, sockptr_t optval, unsigned int optlen)
200 {
201 return -ENOPROTOOPT;
202 }
203 static inline int tcp_authopt_hash(
204 char *hash_location,
205 struct tcp_authopt_key_info *key,
206 struct tcp_authopt_key *info,
207 struct sock *sk, struct sk_buff *skb)
208 {
209 return -EINVAL;
210 }
211 static inline int tcp_authopt_openreq(struct sock *newsk,
212 const struct sock *oldsk,
213 struct request_sock *req)
214 {
215 return 0;
216 }
217 static inline void tcp_authopt_finish_connect(struct sock *sk, struct sk_buff *skb)
218 {
219 }
220 static inline void tcp_authopt_time_wait(
221 struct tcp_timewait_sock *tcptw,
222 struct tcp_sock *tp)
223 {
224 }
225 static inline int tcp_authopt_inbound_check(struct sock *sk, struct sk_buff *skb, const u8 *opt)
226 {
227 return 0;
228 }
229 static inline int tcp_authopt_inbound_check_req(struct request_sock *sk, struct sk_buff *skb,
230 const u8 *opt)
231 {
232 return 0;
233 }
234 #endif
235
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
PATCH v3 7/18 tcp: authopt: Disable via sysctl by default
In reply to Leonard CrestezThis is mainly intended to protect against local privilege escalations through a rarely used feature so it is deliberately not namespaced.
Enforcement is only at the setsockopt level, this should be enough to ensure that the tcp_authopt_needed static key never turns on.
No effort is made to handle disabling when the feature is already in use.
--- Documentation/networking/ip-sysctl.rst | 6 ++++ include/net/tcp_authopt.h | 1 + net/ipv4/sysctl_net_ipv4.c | 39 ++++++++++++++++++++++++++ net/ipv4/tcp_authopt.c | 27 +++++++++++++++++- 4 files changed, 72 insertions(+), 1 deletion(-)
Documentation/networking/ip-sysctl.rst +6 -0
@@ -987,10 +987,16 @@ tcp_limit_output_bytes - INTEGER tcp_challenge_ack_limit - INTEGER Limits number of Challenge ACK sent per second, as recommended in RFC 5961 (Improving TCP's Robustness to Blind In-Window Attacks) Default: 1000 +tcp_authopt - BOOLEAN + Enable the TCP Authentication Option (RFC5925), a replacement for TCP + MD5 Signatures (RFC2835). + + Default: 0 + UDP variables ============= udp_l3mdev_accept - BOOLEAN Enabling this option allows a "global" bound socket to work
include/net/tcp_authopt.h +1 -0
@@ -76,10 +76,11 @@ struct tcphdr_authopt { };#ifdef CONFIG_TCP_AUTHOPT DECLARE_STATIC_KEY_FALSE (tcp_authopt_needed_key);#define tcp_authopt_needed (static_branch_unlikely(&tcp_authopt_needed_key)) +extern int sysctl_tcp_authopt;void tcp_authopt_free (struct sock *sk,struct tcp_authopt_info *info);void tcp_authopt_clear (struct sock *sk);int tcp_set_authopt (struct sock *sk,sockptr_t optval,unsigned int optlen);int tcp_get_authopt_val (struct sock *sk,struct tcp_authopt *key);
net/ipv4/sysctl_net_ipv4.c +39 -0
@@ -17,10 +17,11 @@#include <net/udp.h> #include <net/cipso_ipv4.h> #include <net/ping.h> #include <net/protocol.h> #include <net/netevent.h> +#include <net/tcp_authopt.h> static int two =2 ;static int three__maybe_unused =3 ;static int four =4 ;static int thousand =1000 ;
@@ -472,10 +473,37 @@ static int proc_fib_multipath_hash_fields(struct ctl_table *table, int write,return ret; }#endif +#ifdef CONFIG_TCP_AUTHOPT +static int proc_tcp_authopt (struct ctl_table *ctl, +int write,void *buffer,size_t *lenp, +loff_t *ppos) +{ +int val = sysctl_tcp_authopt; +struct ctl_table tmp = { + .data = &val, + .mode = ctl->mode, + .maxlen =sizeof (val), + .extra1 =SYSCTL_ZERO , + .extra2 =SYSCTL_ONE , + }; +int err; + + err =proc_dointvec_minmax (&tmp, write, buffer, lenp, ppos); +if (err) +return err; +if (sysctl_tcp_authopt && !val) { +net_warn_ratelimited ("Enabling TCP Authentication Option is permanent\n" ); +return -EINVAL ; + } + sysctl_tcp_authopt = val; +return 0 ; +} +#endif +static struct ctl_table ipv4_table[] = { { .procname ="tcp_max_orphans" , .data = &sysctl_tcp_max_orphans, .maxlen =sizeof (int ),
@@ -583,10 +611,21 @@ static struct ctl_table ipv4_table[] = { .mode = 0644, .proc_handler = proc_douintvec_minmax, .extra1 = &sysctl_fib_sync_mem_min, .extra2 = &sysctl_fib_sync_mem_max, }, +#ifdef CONFIG_TCP_AUTHOPT + { + .procname = "tcp_authopt", + .data = &sysctl_tcp_authopt, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_tcp_authopt, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, +#endif { } }; static struct ctl_table ipv4_net_table[] = { {
net/ipv4/tcp_authopt.c +26 -1
@@ -3,10 +3,15 @@#include <linux/kernel.h> #include <net/tcp.h> #include <net/tcp_authopt.h> #include <crypto/hash.h> +/* This is mainly intended to protect against local privilege escalations through +* a rarely used feature so it is deliberately not namespaced. +*/ +int sysctl_tcp_authopt; +/* This is enabled when first struct tcp_authopt_info is allocated and never released */ DEFINE_STATIC_KEY_FALSE (tcp_authopt_needed_key);EXPORT_SYMBOL (tcp_authopt_needed_key);/* All current algorithms have a mac length of 12 but crypto API digestsize can be larger */
@@ -377,17 +382,30 @@ static int _copy_from_sockptr_tolerant(u8 *dst,memset (dst + srclen,0 , dstlen - srclen);return err; } +static int check_sysctl_tcp_authopt (void ) +{ +if (!sysctl_tcp_authopt) { +net_warn_ratelimited ("TCP Authentication Option disabled by sysctl.\n" ); +return -EPERM ; + } + +return 0 ; +} +int tcp_set_authopt (struct sock *sk,sockptr_t optval,unsigned int optlen) {struct tcp_authopt opt;struct tcp_authopt_info *info;int err;sock_owned_by_me (sk); + err =check_sysctl_tcp_authopt (); +if (err) +return err; err =_copy_from_sockptr_tolerant ((u8 *)&opt,sizeof (opt), optval, optlen);if (err)return err;
@@ -405,14 +423,18 @@ int tcp_set_authopt(struct sock *sk, sockptr_t optval, unsigned int optlen)int tcp_get_authopt_val (struct sock *sk,struct tcp_authopt *opt) {struct tcp_sock *tp =tcp_sk (sk);struct tcp_authopt_info *info; +int err; +memset (opt,0 ,sizeof (*opt));sock_owned_by_me (sk); + err =check_sysctl_tcp_authopt (); +if (err) +return err; -memset (opt,0 ,sizeof (*opt)); info =rcu_dereference_check (tp->authopt_info,lockdep_sock_is_held (sk));if (!info)return -ENOENT ; opt->flags = info->flags &TCP_AUTHOPT_KNOWN_FLAGS ;
@@ -475,10 +497,13 @@ int tcp_set_authopt_key(struct sock *sk, sockptr_t optval, unsigned int optlen)struct tcp_authopt_key_info *key_info, *old_key_info;struct tcp_authopt_alg_imp *alg;int err;sock_owned_by_me (sk); + err =check_sysctl_tcp_authopt (); +if (err) +return err; err =_copy_from_sockptr_tolerant ((u8 *)&opt,sizeof (opt), optval, optlen);if (err)return err;
Signature · 1 line
2.25.1
PATCH v3 8/18 tcp: authopt: Implement Sequence Number Extension
In reply to Leonard CrestezAdd a compute_sne function which finds the value of SNE for a certain SEQ given an already known "recent" SNE/SEQ. This is implemented using the standard tcp before/after macro and will work for SEQ values that are without 2^31 of the SEQ for which we know the SNE.
For updating we advance the value for rcv_sne at the same time as rcv_nxt and for snd_sne at the same time as snd_nxt. We could track other values (for example snd_una) but this is good enough and works very easily for timewait socket.
This implementation is different from RFC suggestions and doesn't require additional flags. It does pass tests from this draft:
https://datatracker.ietf.org/doc/draft-touch-sne/
--- include/net/tcp_authopt.h | 34 ++++++++++++++ net/ipv4/tcp_authopt.c | 98 ++++++++++++++++++++++++++++++++++++++- net/ipv4/tcp_input.c | 1 + net/ipv4/tcp_output.c | 1 + 4 files changed, 132 insertions(+), 2 deletions(-)
include/net/tcp_authopt.h +34 -0
@@ -62,10 +62,14 @@ struct tcp_authopt_info {u32 flags;/** @src_isn: Local Initial Sequence Number */ u32 src_isn;/** @dst_isn: Remote Initial Sequence Number */ u32 dst_isn; +/** @rcv_sne: Recv-side Sequence Number Extension tracking tcp_sock.rcv_nxt */ +u32 rcv_sne; +/** @snd_sne: Send-side Sequence Number Extension tracking tcp_sock.snd_nxt */ +u32 snd_sne; };/* TCP authopt as found in header */ struct tcphdr_authopt {u8 num;
@@ -180,10 +184,34 @@ static inline int tcp_authopt_inbound_check_req(struct request_sock *req, structif (info) return __tcp_authopt_inbound_check((struct sock *)req, skb, info, opt); }return 0 ; } +void __tcp_authopt_update_rcv_sne (struct tcp_sock *tp,struct tcp_authopt_info *info,u32 seq); +static inline void tcp_authopt_update_rcv_sne (struct tcp_sock *tp,u32 seq) +{ +struct tcp_authopt_info *info; + +if (tcp_authopt_needed) { + info =rcu_dereference_protected (tp->authopt_info, +lockdep_sock_is_held ((struct sock *)tp)); +if (info) +__tcp_authopt_update_rcv_sne (tp, info, seq); + } +} +void __tcp_authopt_update_snd_sne (struct tcp_sock *tp,struct tcp_authopt_info *info,u32 seq); +static inline void tcp_authopt_update_snd_sne (struct tcp_sock *tp,u32 seq) +{ +struct tcp_authopt_info *info; + +if (tcp_authopt_needed) { + info =rcu_dereference_protected (tp->authopt_info, +lockdep_sock_is_held ((struct sock *)tp)); +if (info) +__tcp_authopt_update_snd_sne (tp, info, seq); + } +}#else static inline int tcp_set_authopt (struct sock *sk,sockptr_t optval,unsigned int optlen) {return -ENOPROTOOPT ; }
@@ -230,8 +258,14 @@ static inline int tcp_authopt_inbound_check(struct sock *sk, struct sk_buff *skbstatic inline int tcp_authopt_inbound_check_req (struct request_sock *sk,struct sk_buff *skb,const u8 *opt) {return 0 ; } +static inline void tcp_authopt_update_rcv_sne (struct tcp_sock *tp,u32 seq) +{ +} +static inline void tcp_authopt_update_snd_sne (struct tcp_sock *tp,u32 seq) +{ +}#endif #endif /* _LINUX_TCP_AUTHOPT_H */
net/ipv4/tcp_authopt.c +96 -2
140 lines not on this page · raw message
net/ipv4/tcp_input.c +1 -0
@@ -3517,10 +3517,11 @@ static void tcp_snd_una_update(struct tcp_sock *tp, u32 ack)static void tcp_rcv_nxt_update (struct tcp_sock *tp,u32 seq) {u32 delta = seq - tp->rcv_nxt;sock_owned_by_me ((struct sock *)tp); +tcp_authopt_update_rcv_sne (tp, seq); tp->bytes_received += delta;WRITE_ONCE (tp->rcv_nxt, seq); }/* Update our send window.
net/ipv4/tcp_output.c +1 -0
@@ -67,10 +67,11 @@ static void tcp_event_new_data_sent(struct sock *sk, struct sk_buff *skb) {struct inet_connection_sock *icsk =inet_csk (sk);struct tcp_sock *tp =tcp_sk (sk);unsigned int prior_packets = tp->packets_out; +tcp_authopt_update_snd_sne (tp,TCP_SKB_CB (skb)->end_seq);WRITE_ONCE (tp->snd_nxt,TCP_SKB_CB (skb)->end_seq);__skb_unlink (skb, &sk->sk_write_queue);tcp_rbtree_insert (&sk->tcp_rtx_queue, skb);
Signature · 1 line
2.25.1
PATCH v3 9/18 tcp: ipv6: Add AO signing for tcp_v6_send_response
In reply to Leonard CrestezThis is a special code path for acks and resets outside of normal connection establishment and closing.
--- net/ipv4/tcp_authopt.c | 2 ++ net/ipv6/tcp_ipv6.c | 57 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+)
net/ipv4/tcp_authopt.c +2 -0
@@ -320,10 +320,11 @@ struct tcp_authopt_key_info *__tcp_authopt_select_key(const struct sock *sk,const struct sock *addr_sk, u8 *rnextkeyid) { return tcp_authopt_lookup_send(info, addr_sk, -1); } +EXPORT_SYMBOL (__tcp_authopt_select_key);static struct tcp_authopt_info *__tcp_authopt_info_get_or_create (struct sock *sk) {struct tcp_sock *tp =tcp_sk (sk);struct tcp_authopt_info *info;
@@ -1195,10 +1196,11 @@ int tcp_authopt_hash(char *hash_location,* try to make it obvious inside the packet. */ memset (hash_location,0 ,TCP_AUTHOPT_MACLEN );return err; } +EXPORT_SYMBOL (tcp_authopt_hash); static struct tcp_authopt_key_info *tcp_authopt_lookup_recv(struct sock *sk, struct sk_buff *skb, struct tcp_authopt_info *info, int recv_id,
net/ipv6/tcp_ipv6.c +57 -0
90 lines not on this page · raw message
Signature · 1 line
2.25.1
kernel test robot
build botRe: [PATCH v3 09/18] tcp: ipv6: Add AO signing for tcp_v6_send_response
Thank you for the patch! Perhaps something to improve:
Hi Leonard,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on 1fe5b01262844be03de98afdd56d1d393df04d7e]
url: https://github.com/0day-ci/linux/commits/Leonard-Crestez/tcp-Initial-support-for-RFC5925-auth-option/20211208-194125 base: 1fe5b01262844be03de98afdd56d1d393df04d7e config: openrisc-randconfig-r014-20211208 (https://download.01.org/0day-ci/archive/20211209/202112090528.v4sYAZMH-lkp(a)intel.com/config) compiler: or1k-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/c40d052f30af7bd56b0803412e4f391532253116
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Leonard-Crestez/tcp-Initial-support-for-RFC5925-auth-option/20211208-194125 git checkout c40d052f30af7bd56b0803412e4f391532253116
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=openrisc SHELL=/bin/bash net/ipv4/ net/ipv6/
If you fix the issue, kindly add following tag as appropriate
All warnings (new ones prefixed by >>):
net/ipv6/tcp_ipv6.c: In function 'tcp_v6_send_response':
>> net/ipv6/tcp_ipv6.c:931:66: warning: parameter 'key' set but not used [-Wunused-but-set-parameter]
931 | int oif, struct tcp_md5sig_key *key, int rst,
| ~~~~~~~~~~~~~~~~~~~~~~~^~~
vim +/key +931 net/ipv6/tcp_ipv6.c
c40d052f30af7b Leonard Crestez 2021-12-08 928
a00e74442bac5a Eric Dumazet 2015-09-29 929 static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 seq,
0f85feae6b710c Eric Dumazet 2014-12-09 930 u32 ack, u32 win, u32 tsval, u32 tsecr,
0f85feae6b710c Eric Dumazet 2014-12-09 @931 int oif, struct tcp_md5sig_key *key, int rst,
e9a5dceee56cb5 Eric Dumazet 2019-09-24 932 u8 tclass, __be32 label, u32 priority)
^1da177e4c3f41 Linus Torvalds 2005-04-16 933 {
cf533ea53ebfae Eric Dumazet 2011-10-21 934 const struct tcphdr *th = tcp_hdr(skb);
cf533ea53ebfae Eric Dumazet 2011-10-21 935 struct tcphdr *t1;
^1da177e4c3f41 Linus Torvalds 2005-04-16 936 struct sk_buff *buff;
4c9483b2fb5d25 David S. Miller 2011-03-12 937 struct flowi6 fl6;
0f85feae6b710c Eric Dumazet 2014-12-09 938 struct net *net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev);
e504799276e530 Daniel Lezcano 2008-03-07 939 struct sock *ctl_sk = net->ipv6.tcp_sk;
77c676da1b717e Ilpo Järvinen 2008-10-09 940 unsigned int tot_len = sizeof(struct tcphdr);
dc87efdb1a5cd4 Florian Westphal 2021-04-01 941 __be32 mrst = 0, *topt;
adf30907d63893 Eric Dumazet 2009-06-02 942 struct dst_entry *dst;
00483690552c5f Jon Maxwell 2018-05-10 943 __u32 mark = 0;
c40d052f30af7b Leonard Crestez 2021-12-08 944 #ifdef CONFIG_TCP_AUTHOPT
c40d052f30af7b Leonard Crestez 2021-12-08 945 struct tcp_authopt_info *aoinfo;
c40d052f30af7b Leonard Crestez 2021-12-08 946 struct tcp_authopt_key_info *aokey;
c40d052f30af7b Leonard Crestez 2021-12-08 947 u8 aornextkeyid;
c40d052f30af7b Leonard Crestez 2021-12-08 948 int aolen;
c40d052f30af7b Leonard Crestez 2021-12-08 949 #endif
^1da177e4c3f41 Linus Torvalds 2005-04-16 950
ee684b6f283004 Andrey Vagin 2013-02-11 951 if (tsecr)
626e264dd1989b Ilpo Järvinen 2008-10-09 952 tot_len += TCPOLEN_TSTAMP_ALIGNED;
c40d052f30af7b Leonard Crestez 2021-12-08 953 #ifdef CONFIG_TCP_AUTHOPT
c40d052f30af7b Leonard Crestez 2021-12-08 954 /* Key lookup before SKB allocation */
c40d052f30af7b Leonard Crestez 2021-12-08 955 aolen = tcp_v6_send_response_init_authopt(sk, &aoinfo, &aokey, &aornextkeyid);
c40d052f30af7b Leonard Crestez 2021-12-08 956 if (aolen) {
c40d052f30af7b Leonard Crestez 2021-12-08 957 tot_len += aolen;
c40d052f30af7b Leonard Crestez 2021-12-08 958 /* Don't use MD5 */
c40d052f30af7b Leonard Crestez 2021-12-08 959 key = NULL;
c40d052f30af7b Leonard Crestez 2021-12-08 960 }
c40d052f30af7b Leonard Crestez 2021-12-08 961 #endif
cfb6eeb4c86059 YOSHIFUJI Hideaki 2006-11-14 962 #ifdef CONFIG_TCP_MD5SIG
cfb6eeb4c86059 YOSHIFUJI Hideaki 2006-11-14 963 if (key)
cfb6eeb4c86059 YOSHIFUJI Hideaki 2006-11-14 964 tot_len += TCPOLEN_MD5SIG_ALIGNED;
cfb6eeb4c86059 YOSHIFUJI Hideaki 2006-11-14 965 #endif
cfb6eeb4c86059 YOSHIFUJI Hideaki 2006-11-14 966 ---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
PATCH v3 10/18 tcp: authopt: Add support for signing skb-less replies
In reply to Leonard CrestezThis is required because tcp ipv4 sometimes sends replies without allocating a full skb that can be signed by tcp authopt.
Handle this with additional code in tcp authopt.
--- include/net/tcp_authopt.h | 7 ++ net/ipv4/tcp_authopt.c | 144 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+)
include/net/tcp_authopt.h +7 -0
@@ -111,10 +111,17 @@ static inline struct tcp_authopt_key_info *tcp_authopt_select_key(int tcp_authopt_hash (char *hash_location,struct tcp_authopt_key_info *key,struct tcp_authopt_info *info,struct sock *sk,struct sk_buff *skb); +int tcp_v4_authopt_hash_reply ( +char *hash_location, +struct tcp_authopt_info *info, +struct tcp_authopt_key_info *key, +__be32 saddr, +__be32 daddr, +struct tcphdr *th);int __tcp_authopt_openreq (struct sock *newsk,const struct sock *oldsk,struct request_sock *req);static inline int tcp_authopt_openreq (struct sock *newsk,const struct sock *oldsk,struct request_sock *req)
net/ipv4/tcp_authopt.c +144 -0
164 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v3 11/18 tcp: ipv4: Add AO signing for skb-less replies
In reply to Leonard CrestezThe code in tcp_v4_send_ack and tcp_v4_send_reset does not allocate a full skb so special handling is required for tcp-authopt handling.
--- net/ipv4/tcp_ipv4.c | 82 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 3 deletions(-)
net/ipv4/tcp_ipv4.c +79 -3
@@ -644,10 +644,50 @@ void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb)__tcp_v4_send_check (skb, inet->inet_saddr, inet->inet_daddr); }EXPORT_SYMBOL (tcp_v4_send_check); +#ifdef CONFIG_TCP_AUTHOPT +/** tcp_v4_authopt_handle_reply - Insert TCPOPT_AUTHOPT if required +* +* returns number of bytes (always aligned to 4) or zero +*/ +static int tcp_v4_authopt_handle_reply (const struct sock *sk, +struct sk_buff *skb, +__be32 *optptr, +struct tcphdr *th) +{ +struct tcp_authopt_info *info; +struct tcp_authopt_key_info *key_info; +u8 rnextkeyid; + +if (sk->sk_state ==TCP_TIME_WAIT ) + info =tcp_twsk (sk)->tw_authopt_info; +else + info =tcp_sk (sk)->authopt_info; +if (!info) +return 0 ; + key_info =__tcp_authopt_select_key (sk, info, sk, &rnextkeyid); +if (!key_info) +return 0 ; + *optptr =htonl ((TCPOPT_AUTHOPT <<24 ) | + (TCPOLEN_AUTHOPT_OUTPUT <<16 ) | + (key_info->send_id <<8 ) | + (rnextkeyid)); +/* must update doff before signature computation */ + th->doff +=TCPOLEN_AUTHOPT_OUTPUT /4 ; +tcp_v4_authopt_hash_reply ((char *)(optptr +1 ), + info, + key_info, +ip_hdr (skb)->daddr, +ip_hdr (skb)->saddr, + th); + +return TCPOLEN_AUTHOPT_OUTPUT ; +} +#endif +/* * This routine will send an RST to the other tcp. * * Someone asks: why I NEVER use socket parameters (TOS, TTL etc.) * for reset.
@@ -659,10 +699,12 @@ EXPORT_SYMBOL(tcp_v4_send_check);* Exception: precedence violation. We do not implement it in any case. */ #ifdef CONFIG_TCP_MD5SIG #define OPTION_BYTES TCPOLEN_MD5SIG_ALIGNED +#elif defined(OPTION_BYTES_TCP_AUTHOPT ) +#define OPTION_BYTES TCPOLEN_AUTHOPT_OUTPUT#else #define OPTION_BYTES sizeof(__be32)#endif static void tcp_v4_send_reset (const struct sock *sk,struct sk_buff *skb)
@@ -712,12 +754,29 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)memset (&arg,0 ,sizeof (arg)); arg.iov[0 ].iov_base = (unsigned char *)&rep; arg.iov[0 ].iov_len =sizeof (rep.th); net = sk ?sock_net (sk) :dev_net (skb_dst (skb)->dev); -#ifdef CONFIG_TCP_MD5SIG +#if defined(CONFIG_TCP_MD5SIG ) || defined(CONFIG_TCP_AUTHOPT )rcu_read_lock (); +#endif +#ifdef CONFIG_TCP_AUTHOPT +/* Unlike TCP-MD5 the signatures for TCP-AO depend on initial sequence +* numbers so we can only handle established and time-wait sockets. +*/ +if (tcp_authopt_needed && sk && + sk->sk_state !=TCP_NEW_SYN_RECV && + sk->sk_state !=TCP_LISTEN ) { +int tcp_authopt_ret =tcp_v4_authopt_handle_reply (sk, skb, rep.opt, &rep.th); + +if (tcp_authopt_ret) { + arg.iov[0 ].iov_len += tcp_authopt_ret; + goto skip_md5sig; + } + } +#endif +#ifdef CONFIG_TCP_MD5SIG hash_location =tcp_parse_md5sig_option (th);if (sk &&sk_fullsock (sk)) {const union tcp_md5_addr *addr;int l3index;
@@ -755,11 +814,10 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) addr = (union tcp_md5_addr *)&ip_hdr (skb)->saddr; key =tcp_md5_do_lookup (sk1, l3index, addr,AF_INET );if (!key) goto out; - genhash =tcp_v4_md5_hash_skb (newhash, key,NULL , skb);if (genhash ||memcmp (hash_location, newhash,16 ) !=0 ) goto out; }
@@ -775,10 +833,13 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)tcp_v4_md5_hash_hdr ((__u8 *) &rep.opt[1 ], key,ip_hdr (skb)->saddr,ip_hdr (skb)->daddr, &rep.th); } +#endif +#ifdef CONFIG_TCP_AUTHOPT +skip_md5sig:#endif /* Can't co-exist with TCPMD5, hence check rep.opt[0] */ if (rep.opt[0 ] ==0 ) {__be32 mrst =mptcp_reset_option (skb);
@@ -828,12 +889,14 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) ctl_sk->sk_mark =0 ;__TCP_INC_STATS (net,TCP_MIB_OUTSEGS );__TCP_INC_STATS (net,TCP_MIB_OUTRSTS );local_bh_enable (); -#ifdef CONFIG_TCP_MD5SIG +#if defined(CONFIG_TCP_MD5SIG ) out: +#endif +#if defined(CONFIG_TCP_MD5SIG ) || defined(CONFIG_TCP_AUTHOPT )rcu_read_unlock ();#endif }/* The code following below sending ACKs in SYN-RECV and TIME-WAIT states
@@ -850,10 +913,12 @@ static void tcp_v4_send_ack(const struct sock *sk,struct {struct tcphdr th;__be32 opt[(TCPOLEN_TSTAMP_ALIGNED >>2 ) #ifdef CONFIG_TCP_MD5SIG + (TCPOLEN_MD5SIG_ALIGNED >>2 ) +#elif defined(CONFIG_TCP_AUTHOPT) + + (TCPOLEN_AUTHOPT_OUTPUT >>2 ) #endif ]; } rep;struct net *net =sock_net (sk);struct ip_reply_arg arg;
@@ -881,10 +946,21 @@ static void tcp_v4_send_ack(const struct sock *sk, rep.th.seq =htonl (seq); rep.th.ack_seq =htonl (ack); rep.th.ack =1 ; rep.th.window =htons (win); +#ifdef CONFIG_TCP_AUTHOPT +if (tcp_authopt_needed) { +int aoret, offset = (tsecr) ?3 :0 ; + + aoret =tcp_v4_authopt_handle_reply (sk, skb, &rep.opt[offset], &rep.th); +if (aoret) { + arg.iov[0 ].iov_len += aoret; + key =NULL ; + } + } +#endif #ifdef CONFIG_TCP_MD5SIG if (key) {int offset = (tsecr) ?3 :0 ; rep.opt[offset++] = htonl((TCPOPT_NOP << 24) |
Signature · 1 line
2.25.1
kernel test robot
build botRe: [PATCH v3 11/18] tcp: ipv4: Add AO signing for skb-less replies
Thank you for the patch! Perhaps something to improve:
Hi Leonard,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on 1fe5b01262844be03de98afdd56d1d393df04d7e]
url: https://github.com/0day-ci/linux/commits/Leonard-Crestez/tcp-Initial-support-for-RFC5925-auth-option/20211208-194125 base: 1fe5b01262844be03de98afdd56d1d393df04d7e config: openrisc-randconfig-r014-20211208 (https://download.01.org/0day-ci/archive/20211209/202112090745.LdVOpiG4-lkp(a)intel.com/config) compiler: or1k-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/8d4bf3a9b770cb44bf4e37e794e63f7db7a08cb6
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Leonard-Crestez/tcp-Initial-support-for-RFC5925-auth-option/20211208-194125 git checkout 8d4bf3a9b770cb44bf4e37e794e63f7db7a08cb6
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=openrisc SHELL=/bin/bash net/ipv4/
If you fix the issue, kindly add following tag as appropriate
All warnings (new ones prefixed by >>):
net/ipv4/tcp_ipv4.c: In function 'tcp_v4_send_ack':
>> net/ipv4/tcp_ipv4.c:909:52: warning: parameter 'key' set but not used [-Wunused-but-set-parameter]
909 | struct tcp_md5sig_key *key,
| ~~~~~~~~~~~~~~~~~~~~~~~^~~vim +/key +909 net/ipv4/tcp_ipv4.c
^1da177e4c3f41 Linus Torvalds 2005-04-16 901
^1da177e4c3f41 Linus Torvalds 2005-04-16 902 /* The code following below sending ACKs in SYN-RECV and TIME-WAIT states
^1da177e4c3f41 Linus Torvalds 2005-04-16 903 outside socket context is ugly, certainly. What can I do?
^1da177e4c3f41 Linus Torvalds 2005-04-16 904 */
^1da177e4c3f41 Linus Torvalds 2005-04-16 905
e2d118a1cb5e60 Lorenzo Colitti 2016-11-04 906 static void tcp_v4_send_ack(const struct sock *sk,
e62a123b8ef7c5 Eric Dumazet 2016-01-21 907 struct sk_buff *skb, u32 seq, u32 ack,
ee684b6f283004 Andrey Vagin 2013-02-11 908 u32 win, u32 tsval, u32 tsecr, int oif,
88ef4a5a78e634 KOVACS Krisztian 2008-10-01 @909 struct tcp_md5sig_key *key,
66b13d99d96a1a Eric Dumazet 2011-10-24 910 int reply_flags, u8 tos)
^1da177e4c3f41 Linus Torvalds 2005-04-16 911 {
cf533ea53ebfae Eric Dumazet 2011-10-21 912 const struct tcphdr *th = tcp_hdr(skb);
^1da177e4c3f41 Linus Torvalds 2005-04-16 913 struct {
^1da177e4c3f41 Linus Torvalds 2005-04-16 914 struct tcphdr th;
714e85be355722 Al Viro 2006-11-14 915 __be32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2)
cfb6eeb4c86059 YOSHIFUJI Hideaki 2006-11-14 916 #ifdef CONFIG_TCP_MD5SIG
cfb6eeb4c86059 YOSHIFUJI Hideaki 2006-11-14 917 + (TCPOLEN_MD5SIG_ALIGNED >> 2)
8d4bf3a9b770cb Leonard Crestez 2021-12-08 918 #elif defined(CONFIG_TCP_AUTHOPT)
8d4bf3a9b770cb Leonard Crestez 2021-12-08 919 + (TCPOLEN_AUTHOPT_OUTPUT >> 2)
cfb6eeb4c86059 YOSHIFUJI Hideaki 2006-11-14 920 #endif
cfb6eeb4c86059 YOSHIFUJI Hideaki 2006-11-14 921 ];
^1da177e4c3f41 Linus Torvalds 2005-04-16 922 } rep;
e2d118a1cb5e60 Lorenzo Colitti 2016-11-04 923 struct net *net = sock_net(sk);
^1da177e4c3f41 Linus Torvalds 2005-04-16 924 struct ip_reply_arg arg;
00483690552c5f Jon Maxwell 2018-05-10 925 struct sock *ctl_sk;
d6fb396cfaa71a Eric Dumazet 2019-06-13 926 u64 transmit_time;
^1da177e4c3f41 Linus Torvalds 2005-04-16 927
^1da177e4c3f41 Linus Torvalds 2005-04-16 928 memset(&rep.th, 0, sizeof(struct tcphdr));
7174259e6ced15 Arnaldo Carvalho de Melo 2006-11-17 929 memset(&arg, 0, sizeof(arg));
^1da177e4c3f41 Linus Torvalds 2005-04-16 930
^1da177e4c3f41 Linus Torvalds 2005-04-16 931 arg.iov[0].iov_base = (unsigned char *)&rep;
^1da177e4c3f41 Linus Torvalds 2005-04-16 932 arg.iov[0].iov_len = sizeof(rep.th);
ee684b6f283004 Andrey Vagin 2013-02-11 933 if (tsecr) {
cfb6eeb4c86059 YOSHIFUJI Hideaki 2006-11-14 934 rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
^1da177e4c3f41 Linus Torvalds 2005-04-16 935 (TCPOPT_TIMESTAMP << 8) |
^1da177e4c3f41 Linus Torvalds 2005-04-16 936 TCPOLEN_TIMESTAMP);
ee684b6f283004 Andrey Vagin 2013-02-11 937 rep.opt[1] = htonl(tsval);
ee684b6f283004 Andrey Vagin 2013-02-11 938 rep.opt[2] = htonl(tsecr);
cb48cfe8079ddd Craig Schlenter 2007-01-09 939 arg.iov[0].iov_len += TCPOLEN_TSTAMP_ALIGNED;
^1da177e4c3f41 Linus Torvalds 2005-04-16 940 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 941
^1da177e4c3f41 Linus Torvalds 2005-04-16 942 /* Swap the send and the receive. */
^1da177e4c3f41 Linus Torvalds 2005-04-16 943 rep.th.dest = th->source;
^1da177e4c3f41 Linus Torvalds 2005-04-16 944 rep.th.source = th->dest;
^1da177e4c3f41 Linus Torvalds 2005-04-16 945 rep.th.doff = arg.iov[0].iov_len / 4;
^1da177e4c3f41 Linus Torvalds 2005-04-16 946 rep.th.seq = htonl(seq);
^1da177e4c3f41 Linus Torvalds 2005-04-16 947 rep.th.ack_seq = htonl(ack);
^1da177e4c3f41 Linus Torvalds 2005-04-16 948 rep.th.ack = 1;
^1da177e4c3f41 Linus Torvalds 2005-04-16 949 rep.th.window = htons(win);
^1da177e4c3f41 Linus Torvalds 2005-04-16 950 ---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
kernel test robot
build botRe: [PATCH v3 11/18] tcp: ipv4: Add AO signing for skb-less replies
In reply to Leonard CrestezThank you for the patch! Perhaps something to improve:
Hi Leonard,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on 1fe5b01262844be03de98afdd56d1d393df04d7e]
url: https://github.com/0day-ci/linux/commits/Leonard-Crestez/tcp-Initial-support-for-RFC5925-auth-option/20211208-194125 base: 1fe5b01262844be03de98afdd56d1d393df04d7e config: m68k-randconfig-s031-20211209 (https://download.01.org/0day-ci/archive/20211209/202112092244.UyUWpjLG-lkp(a)intel.com/config) compiler: m68k-linux-gcc (GCC) 11.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# apt-get install sparse
# sparse version: v0.6.4-dirty
# https://github.com/0day-ci/linux/commit/8d4bf3a9b770cb44bf4e37e794e63f7db7a08cb6
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Leonard-Crestez/tcp-Initial-support-for-RFC5925-auth-option/20211208-194125
git checkout 8d4bf3a9b770cb44bf4e37e794e63f7db7a08cb6
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=m68k SHELL=/bin/bash net/ipv4/
If you fix the issue, kindly add following tag as appropriate
sparse warnings: (new ones prefixed by >>)
>> net/ipv4/tcp_ipv4.c:666:22: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct tcp_authopt_info *[assigned] info @@ got struct tcp_authopt_info [noderef] __rcu *authopt_info @@
net/ipv4/tcp_ipv4.c:666:22: sparse: expected struct tcp_authopt_info *[assigned] info
net/ipv4/tcp_ipv4.c:666:22: sparse: got struct tcp_authopt_info [noderef] __rcu *authopt_info
net/ipv4/tcp_ipv4.c:3219:41: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *data @@ got struct tcp_congestion_ops const [noderef] __rcu *tcp_congestion_control @@
net/ipv4/tcp_ipv4.c:3219:41: sparse: expected void const *data
net/ipv4/tcp_ipv4.c:3219:41: sparse: got struct tcp_congestion_ops const [noderef] __rcu *tcp_congestion_control
net/ipv4/tcp_ipv4.c:3327:45: sparse: sparse: incorrect type in argument 1 (different address spaces) @@ expected void const *data @@ got struct tcp_congestion_ops const [noderef] __rcu *extern [addressable] [toplevel] tcp_congestion_control @@
net/ipv4/tcp_ipv4.c:3327:45: sparse: expected void const *data
net/ipv4/tcp_ipv4.c:3327:45: sparse: got struct tcp_congestion_ops const [noderef] __rcu *extern [addressable] [toplevel] tcp_congestion_control
net/ipv4/tcp_ipv4.c:3331:50: sparse: sparse: incorrect type in assignment (different address spaces) @@ expected struct tcp_congestion_ops const [noderef] __rcu *tcp_congestion_control @@ got struct tcp_congestion_ops * @@
net/ipv4/tcp_ipv4.c:3331:50: sparse: expected struct tcp_congestion_ops const [noderef] __rcu *tcp_congestion_control
net/ipv4/tcp_ipv4.c:3331:50: sparse: got struct tcp_congestion_ops *
net/ipv4/tcp_ipv4.c:1715:25: sparse: sparse: context imbalance in 'tcp_v4_syn_recv_sock' - unexpected unlock net/ipv4/tcp_ipv4.c:1988:17: sparse: sparse: context imbalance in 'tcp_add_backlog' - unexpected unlock net/ipv4/tcp_ipv4.c:2258:21: sparse: sparse: context imbalance in 'tcp_v4_rcv' - different lock contexts for basic block net/ipv4/tcp_ipv4.c:3220:41: sparse: sparse: dereference of noderef expression net/ipv4/tcp_ipv4.c:3220:41: sparse: sparse: dereference of noderef expression net/ipv4/tcp_ipv4.c:3328:45: sparse: sparse: dereference of noderef expression net/ipv4/tcp_ipv4.c:3328:45: sparse: sparse: dereference of noderef expression
vim +666 net/ipv4/tcp_ipv4.c
648
649 #ifdef CONFIG_TCP_AUTHOPT
650 /** tcp_v4_authopt_handle_reply - Insert TCPOPT_AUTHOPT if required
651 *
652 * returns number of bytes (always aligned to 4) or zero
653 */
654 static int tcp_v4_authopt_handle_reply(const struct sock *sk,
655 struct sk_buff *skb,
656 __be32 *optptr,
657 struct tcphdr *th)
658 {
659 struct tcp_authopt_info *info;
660 struct tcp_authopt_key_info *key_info;
661 u8 rnextkeyid;
662
663 if (sk->sk_state == TCP_TIME_WAIT)
664 info = tcp_twsk(sk)->tw_authopt_info;
665 else
> 666 info = tcp_sk(sk)->authopt_info;
667 if (!info)
668 return 0;
669 key_info = __tcp_authopt_select_key(sk, info, sk, &rnextkeyid);
670 if (!key_info)
671 return 0;
672 *optptr = htonl((TCPOPT_AUTHOPT << 24) |
673 (TCPOLEN_AUTHOPT_OUTPUT << 16) |
674 (key_info->send_id << 8) |
675 (rnextkeyid));
676 /* must update doff before signature computation */
677 th->doff += TCPOLEN_AUTHOPT_OUTPUT / 4;
678 tcp_v4_authopt_hash_reply((char *)(optptr + 1),
679 info,
680 key_info,
681 ip_hdr(skb)->daddr,
682 ip_hdr(skb)->saddr,
683 th); 684
685 return TCPOLEN_AUTHOPT_OUTPUT;
686 }
687 #endif
688
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
PATCH v3 12/18 tcp: authopt: Add key selection controls
In reply to Leonard CrestezThe RFC requires that TCP can report the keyid and rnextkeyid values being sent or received, implement this via getsockopt values.
The RFC also requires that user can select the sending key and that the sending key is automatically switched based on rnextkeyid. These requirements can conflict so we implement both and add a flag which specifies if user or peer request takes priority.
Also add an option to control rnextkeyid explicitly from userspace.
--- Documentation/networking/tcp_authopt.rst | 25 ++++++ include/net/tcp_authopt.h | 38 ++++++++- include/uapi/linux/tcp.h | 31 ++++++++ net/ipv4/tcp_authopt.c | 98 +++++++++++++++++++++++- net/ipv4/tcp_ipv4.c | 2 +- net/ipv6/tcp_ipv6.c | 2 +- 6 files changed, 189 insertions(+), 7 deletions(-)
Documentation/networking/tcp_authopt.rst +25 -0
@@ -35,10 +35,35 @@ Keys can be bound to remote addresses in a way that is similar to TCP_MD5. RFC5925 requires that key ids do not overlap when tcp identifiers (addr/port) overlap. This is not enforced by linux, configuring ambiguous keys will result in packet drops and lost connections. +Key selection +------------- + +On getsockopt(TCP_AUTHOPT) information is provided about keyid/rnextkeyid in +the last send packet and about the keyid/rnextkeyd in the last valid received +packet. + +By default the sending keyid is selected to match the "rnextkeyid" value sent +by the remote side. If that keyid is not available (or for new connections) a +random matching key is selected. + +If the `TCP_AUTHOPT_LOCK_KEYID` is set then the sending key is selected by the +`tcp_authopt.send_local_id` field and rnextkeyid is ignored. If no key with +local_id == send_local_id is configured then a random matching key is +selected. + +The current sending key is cached in the socket and will not change unless +requested by remote rnextkeyid or by setsockopt. + +The rnextkeyid value sent on the wire is usually the recv_id of the current +key used for sending. If the TCP_AUTHOPT_LOCK_RNEXTKEY flag is set in +`tcp_authopt.flags` the value of `tcp_authopt.send_rnextkeyid` is send +instead. This can be used to implement smooth rollover: the peer will switch +its keyid to the received rnextkeyid when it is available. + ABI Reference ============= .. kernel-doc:: include/uapi/linux/tcp.h :identifiers: tcp_authopt tcp_authopt_flag tcp_authopt_key tcp_authopt_key_flag tcp_authopt_alg
include/net/tcp_authopt.h +36 -2
@@ -66,10 +66,43 @@ struct tcp_authopt_info {u32 dst_isn;/** @rcv_sne: Recv-side Sequence Number Extension tracking tcp_sock.rcv_nxt */ u32 rcv_sne;/** @snd_sne: Send-side Sequence Number Extension tracking tcp_sock.snd_nxt */ u32 snd_sne; + +/** +* @send_keyid: keyid currently being sent +* +* This is controlled by userspace by userspace if +* TCP_AUTHOPT_FLAG_LOCK_KEYID, otherwise we try to match recv_rnextkeyid +*/ +u8 send_keyid; +/** +* @send_rnextkeyid: rnextkeyid currently being sent +* +* This is controlled by userspace if TCP_AUTHOPT_FLAG_LOCK_RNEXTKEYID is set +*/ +u8 send_rnextkeyid; +/** +* @recv_keyid: last keyid received from remote +* +* This is reported to userspace but has no other special behavior attached. +*/ +u8 recv_keyid; +/** +* @recv_rnextkeyid: last rnextkeyid received from remote +* +* Linux tries to honor this unless TCP_AUTHOPT_FLAG_LOCK_KEYID is set +*/ +u8 recv_rnextkeyid; + +/** +* @send_key: Current key used for sending, cached. +* +* Once a key is found it only changes by user or remote request. +*/ +struct tcp_authopt_key_info *send_key; };/* TCP authopt as found in header */ struct tcphdr_authopt {u8 num;
@@ -91,22 +124,23 @@ int tcp_get_authopt_val(struct sock *sk, struct tcp_authopt *key);int tcp_set_authopt_key (struct sock *sk,sockptr_t optval,unsigned int optlen);struct tcp_authopt_key_info *__tcp_authopt_select_key (const struct sock *sk,struct tcp_authopt_info *info,const struct sock *addr_sk, -u8 *rnextkeyid); +u8 *rnextkeyid, +bool locked);static inline struct tcp_authopt_key_info *tcp_authopt_select_key (const struct sock *sk,const struct sock *addr_sk,struct tcp_authopt_info **info,u8 *rnextkeyid) {if (tcp_authopt_needed) { *info =rcu_dereference (tcp_sk (sk)->authopt_info);if (*info) -return __tcp_authopt_select_key (sk, *info, addr_sk, rnextkeyid); +return __tcp_authopt_select_key (sk, *info, addr_sk, rnextkeyid, true); }return NULL ; } int tcp_authopt_hash( char *hash_location,
include/uapi/linux/tcp.h +31 -0
@@ -346,10 +346,24 @@ struct tcp_diag_md5sig {/** * enum tcp_authopt_flag - flags for `tcp_authopt.flags` */ enum tcp_authopt_flag { +/** +* @TCP_AUTHOPT_FLAG_LOCK_KEYID: keyid controlled by sockopt +* +* If this is set `tcp_authopt.send_keyid` is used to determined sending +* key. Otherwise a key with send_id == recv_rnextkeyid is preferred. +*/ +TCP_AUTHOPT_FLAG_LOCK_KEYID = (1 <<0 ), +/** +* @TCP_AUTHOPT_FLAG_LOCK_RNEXTKEYID: Override rnextkeyid from userspace +* +* If this is set then `tcp_authopt.send_rnextkeyid` is sent on outbound +* packets. Other the recv_id of the current sending key is sent. +*/ +TCP_AUTHOPT_FLAG_LOCK_RNEXTKEYID = (1 <<1 ),/** * @TCP_AUTHOPT_FLAG_REJECT_UNEXPECTED: * Configure behavior of segments with TCP-AO coming from hosts for which no * key is configured. The default recommended by RFC is to silently accept * such connections.
@@ -361,10 +375,27 @@ enum tcp_authopt_flag {* struct tcp_authopt - Per-socket options related to TCP Authentication Option */ struct tcp_authopt {/** @flags: Combination of &enum tcp_authopt_flag */ __u32 flags; +/** +* @send_keyid: `tcp_authopt_key.send_id` of preferred send key +* +* This is only used if `TCP_AUTHOPT_FLAG_LOCK_KEYID` is set. +*/ +__u8 send_keyid; +/** +* @send_rnextkeyid: The rnextkeyid to send in packets +* +* This is controlled by the user iff TCP_AUTHOPT_FLAG_LOCK_RNEXTKEYID is +* set. Otherwise rnextkeyid is the recv_id of the current key. +*/ +__u8 send_rnextkeyid; +/** @recv_keyid: A recently-received keyid value. Only for getsockopt. */ +__u8 recv_keyid; +/** @recv_rnextkeyid: A recently-received rnextkeyid value. Only for getsockopt. */ +__u8 recv_rnextkeyid; };/** * enum tcp_authopt_key_flag - flags for `tcp_authopt.flags` *
net/ipv4/tcp_authopt.c +95 -3
182 lines not on this page · raw message
net/ipv4/tcp_ipv4.c +1 -1
@@ -664,11 +664,11 @@ static int tcp_v4_authopt_handle_reply(const struct sock *sk, info =tcp_twsk (sk)->tw_authopt_info; else info =tcp_sk (sk)->authopt_info;if (!info)return 0 ; - key_info =__tcp_authopt_select_key (sk, info, sk, &rnextkeyid); + key_info =__tcp_authopt_select_key (sk, info, sk, &rnextkeyid, false);if (!key_info)return 0 ; *optptr = htonl((TCPOPT_AUTHOPT << 24) | (TCPOLEN_AUTHOPT_OUTPUT << 16) | (key_info->send_id << 8) |
net/ipv6/tcp_ipv6.c +1 -1
@@ -901,11 +901,11 @@ static int tcp_v6_send_response_init_authopt(const struct sock *sk, *info =tcp_twsk (sk)->tw_authopt_info; else *info =rcu_dereference (tcp_sk (sk)->authopt_info);if (!*info)return 0 ; - *key =__tcp_authopt_select_key (sk, *info, sk, rnextkeyid); + *key =__tcp_authopt_select_key (sk, *info, sk, rnextkeyid, false);if (*key)return TCPOLEN_AUTHOPT_OUTPUT ;return 0 ; }
Signature · 1 line
2.25.1
kernel test robot
build botRe: [PATCH v3 12/18] tcp: authopt: Add key selection controls
Thank you for the patch! Perhaps something to improve:
Hi Leonard,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on 1fe5b01262844be03de98afdd56d1d393df04d7e]
url: https://github.com/0day-ci/linux/commits/Leonard-Crestez/tcp-Initial-support-for-RFC5925-auth-option/20211208-194125 base: 1fe5b01262844be03de98afdd56d1d393df04d7e config: m68k-randconfig-s031-20211209 (https://download.01.org/0day-ci/archive/20211210/202112100044.EM5GEcUJ-lkp(a)intel.com/config) compiler: m68k-linux-gcc (GCC) 11.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# apt-get install sparse
# sparse version: v0.6.4-dirty
# https://github.com/0day-ci/linux/commit/8082f98bdfa221e0dc891e89beecb5d1e3ac64ac
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Leonard-Crestez/tcp-Initial-support-for-RFC5925-auth-option/20211208-194125
git checkout 8082f98bdfa221e0dc891e89beecb5d1e3ac64ac
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=m68k SHELL=/bin/bash net/ipv4/
If you fix the issue, kindly add following tag as appropriate
sparse warnings: (new ones prefixed by >>)
>> net/ipv4/tcp_authopt.c:343:23: sparse: sparse: incompatible types in comparison expression (different address spaces): >> net/ipv4/tcp_authopt.c:343:23: sparse: struct tcp_authopt_key_info [noderef] __rcu * >> net/ipv4/tcp_authopt.c:343:23: sparse: struct tcp_authopt_key_info *
net/ipv4/tcp_authopt.c:345:23: sparse: sparse: incompatible types in comparison expression (different address spaces):
net/ipv4/tcp_authopt.c:345:23: sparse: struct tcp_authopt_key_info [noderef] __rcu *
net/ipv4/tcp_authopt.c:345:23: sparse: struct tcp_authopt_key_info *
net/ipv4/tcp_authopt.c:369:25: sparse: sparse: incompatible types in comparison expression (different address spaces):
net/ipv4/tcp_authopt.c:369:25: sparse: struct tcp_authopt_key_info [noderef] __rcu *
net/ipv4/tcp_authopt.c:369:25: sparse: struct tcp_authopt_key_info *
net/ipv4/tcp_authopt.c:509:20: sparse: sparse: incompatible types in comparison expression (different address spaces):
net/ipv4/tcp_authopt.c:509:20: sparse: struct tcp_authopt_key_info [noderef] __rcu *
net/ipv4/tcp_authopt.c:509:20: sparse: struct tcp_authopt_key_info *
net/ipv4/tcp_authopt.c:528:13: sparse: sparse: incompatible types in comparison expression (different address spaces):
net/ipv4/tcp_authopt.c:528:13: sparse: struct tcp_authopt_key_info [noderef] __rcu *
net/ipv4/tcp_authopt.c:528:13: sparse: struct tcp_authopt_key_info *
net/ipv4/tcp_authopt.c:529:17: sparse: sparse: incompatible types in comparison expression (different address spaces):
net/ipv4/tcp_authopt.c:529:17: sparse: struct tcp_authopt_key_info [noderef] __rcu *
net/ipv4/tcp_authopt.c:529:17: sparse: struct tcp_authopt_key_info *
vim +343 net/ipv4/tcp_authopt.c
306
307 /**
308 * __tcp_authopt_select_key - select key for sending
309 *
310 * @sk: socket
311 * @info: socket's tcp_authopt_info
312 * @addr_sk: socket used for address lookup. Same as sk except for synack case
313 * @rnextkeyid: value of rnextkeyid caller should write in packet
314 * @locked: If we're holding the socket lock. This is false for some timewait and reset cases
315 *
316 * Result is protected by RCU and can't be stored, it may only be passed to
317 * tcp_authopt_hash and only under a single rcu_read_lock.
318 */
319 struct tcp_authopt_key_info *__tcp_authopt_select_key(const struct sock *sk,
320 struct tcp_authopt_info *info,
321 const struct sock *addr_sk,
322 u8 *rnextkeyid,
323 bool locked)
324 {
325 struct tcp_authopt_key_info *key, *new_key = NULL;
326
327 /* Listen sockets don't refer to any specific connection so we don't try
328 * to keep using the same key and ignore any received keyids.
329 */
330 if (sk->sk_state == TCP_LISTEN) {
331 int send_keyid = -1;
332
333 if (info->flags & TCP_AUTHOPT_FLAG_LOCK_KEYID)
334 send_keyid = info->send_keyid;
335 key = tcp_authopt_lookup_send(info, addr_sk, send_keyid);
336 if (key)
337 *rnextkeyid = key->recv_id;
338
339 return key;
340 }
341
342 if (locked)
> 343 key = rcu_dereference_protected(info->send_key, lockdep_sock_is_held(sk)); 344 else
345 key = rcu_dereference(info->send_key);
346
347 /* Try to keep the same sending key unless user or peer requires a different key
348 * User request (via TCP_AUTHOPT_FLAG_LOCK_KEYID) always overrides peer request.
349 */
350 if (info->flags & TCP_AUTHOPT_FLAG_LOCK_KEYID) {
351 int send_keyid = info->send_keyid;
352
353 if (!key || key->send_id != send_keyid)
354 new_key = tcp_authopt_lookup_send(info, addr_sk, send_keyid);
355 } else {
356 if (!key || key->send_id != info->recv_rnextkeyid)
357 new_key = tcp_authopt_lookup_send(info, addr_sk, info->recv_rnextkeyid);
358 }
359 /* If no key found with specific send_id try anything else. */
360 if (!key && !new_key)
361 new_key = tcp_authopt_lookup_send(info, addr_sk, -1);
362
363 /* Update current key only if we hold the socket lock, otherwise we might
364 * store a pointer that goes stale
365 */
366 if (new_key && key != new_key) {
367 key = new_key;
368 if (locked)
369 rcu_assign_pointer(info->send_key, key);
370 }
371
372 if (key) {
373 if (info->flags & TCP_AUTHOPT_FLAG_LOCK_RNEXTKEYID)
374 *rnextkeyid = info->send_rnextkeyid;
375 else
376 *rnextkeyid = info->send_rnextkeyid = key->recv_id;
377 }
378
379 return key;
380 }
381 EXPORT_SYMBOL(__tcp_authopt_select_key);
382
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
PATCH v3 13/18 tcp: authopt: Add initial l3index support
In reply to Leonard CrestezThis is a parallel feature to tcp_md5sig.tcpm_ifindex support and allows applications to server multiple VRFs with a single socket.
The ifindex argument must be the ifindex of a VRF device and must match exactly, keys with ifindex == 0 (outside of VRF) will not match for connections inside a VRF.
Keys without the TCP_AUTHOPT_KEY_IFINDEX will ignore ifindex and match both inside and outside VRF.
--- include/net/tcp_authopt.h | 2 ++ include/uapi/linux/tcp.h | 11 ++++++ net/ipv4/tcp_authopt.c | 71 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 79 insertions(+), 5 deletions(-)
include/net/tcp_authopt.h +2 -0
@@ -39,10 +39,12 @@ struct tcp_authopt_key_info {u8 alg_id;/** @keylen: Same as &tcp_authopt_key.keylen */ u8 keylen;/** @key: Same as &tcp_authopt_key.key */ u8 key[TCP_AUTHOPT_MAXKEYLEN ]; +/** @l3index: Same as &tcp_authopt_key.ifindex */ +int l3index;/** @addr: Same as &tcp_authopt_key.addr */ struct sockaddr_storage addr;/** @alg: Algorithm implementation matching alg_id */ struct tcp_authopt_alg_imp *alg; };
include/uapi/linux/tcp.h +11 -0
@@ -400,15 +400,17 @@ struct tcp_authopt {* enum tcp_authopt_key_flag - flags for `tcp_authopt.flags` * * @TCP_AUTHOPT_KEY_DEL: Delete the key and ignore non-id fields * @TCP_AUTHOPT_KEY_EXCLUDE_OPTS: Exclude TCP options from signature * @TCP_AUTHOPT_KEY_ADDR_BIND: Key only valid for `tcp_authopt.addr` +* @TCP_AUTHOPT_KEY_IFINDEX: Key only valid for `tcp_authopt.ifindex` */ enum tcp_authopt_key_flag {TCP_AUTHOPT_KEY_DEL = (1 <<0 ),TCP_AUTHOPT_KEY_EXCLUDE_OPTS = (1 <<1 ),TCP_AUTHOPT_KEY_ADDR_BIND = (1 <<2 ), +TCP_AUTHOPT_KEY_IFINDEX = (1 <<3 ), };/** * enum tcp_authopt_alg - Algorithms for TCP Authentication Option */
@@ -450,10 +452,19 @@ struct tcp_authopt_key {* @addr: Key is only valid for this address * * Ignored unless TCP_AUTHOPT_KEY_ADDR_BIND flag is set */ struct __kernel_sockaddr_storage addr; +/** +* @ifindex: ifindex of vrf (l3mdev_master) interface +* +* If the TCP_AUTHOPT_KEY_IFINDEX flag is set then key only applies for +* connections through this interface. Interface must be an vrf master. +* +* This is similar to `tcp_msg5sig.tcpm_ifindex` +*/ +int ifindex; };/* setsockopt(fd, IPPROTO_TCP, TCP_ZEROCOPY_RECEIVE, ...) */ #define TCP_RECEIVE_ZEROCOPY_FLAG_TLB_CLEAN_HINT 0x1
net/ipv4/tcp_authopt.c +66 -5
168 lines not on this page · raw message
Signature · 1 line
2.25.1
PATCH v3 14/18 tcp: authopt: Add NOSEND/NORECV flags
In reply to Leonard CrestezAdd flags to allow marking individual keys and invalid for send or recv. Making keys assymetric this way is not mentioned in RFC5925 but RFC8177 requires that keys inside a keychain have independent "accept" and "send" lifetimes.
Flag names are negative so that the default behavior is for keys to be valid for both send and recv.
Setting both NOSEND and NORECV for a certain peer address can be used on a listen socket can be used to mean "TCP-AO is required from this peer but no keys are currently valid".
--- include/uapi/linux/tcp.h | 4 ++++ net/ipv4/tcp_authopt.c | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-)
include/uapi/linux/tcp.h +4 -0
@@ -401,16 +401,20 @@ struct tcp_authopt {* * @TCP_AUTHOPT_KEY_DEL: Delete the key and ignore non-id fields * @TCP_AUTHOPT_KEY_EXCLUDE_OPTS: Exclude TCP options from signature * @TCP_AUTHOPT_KEY_ADDR_BIND: Key only valid for `tcp_authopt.addr` * @TCP_AUTHOPT_KEY_IFINDEX: Key only valid for `tcp_authopt.ifindex` +* @TCP_AUTHOPT_KEY_NOSEND: Key invalid for send (expired) +* @TCP_AUTHOPT_KEY_NORECV: Key invalid for recv (expired) */ enum tcp_authopt_key_flag {TCP_AUTHOPT_KEY_DEL = (1 <<0 ),TCP_AUTHOPT_KEY_EXCLUDE_OPTS = (1 <<1 ),TCP_AUTHOPT_KEY_ADDR_BIND = (1 <<2 ),TCP_AUTHOPT_KEY_IFINDEX = (1 <<3 ), +TCP_AUTHOPT_KEY_NOSEND = (1 <<4 ), +TCP_AUTHOPT_KEY_NORECV = (1 <<5 ), };/** * enum tcp_authopt_alg - Algorithms for TCP Authentication Option */
net/ipv4/tcp_authopt.c +8 -1
@@ -311,10 +311,12 @@ static struct tcp_authopt_key_info *tcp_authopt_lookup_send(struct tcp_authopt_iint l3index =-1 ;hlist_for_each_entry_rcu (key, &info->head, node,0 ) {if (send_id >=0 && key->send_id != send_id)continue ; +if (key->flags &TCP_AUTHOPT_KEY_NOSEND ) +continue ;if (key->flags &TCP_AUTHOPT_KEY_ADDR_BIND )if (!tcp_authopt_key_match_sk_addr (key, addr_sk))continue ;if (key->flags &TCP_AUTHOPT_KEY_IFINDEX ) {if (l3index <0 )
@@ -593,11 +595,13 @@ void tcp_authopt_clear(struct sock *sk)#define TCP_AUTHOPT_KEY_KNOWN_FLAGS ( \ TCP_AUTHOPT_KEY_DEL | \ TCP_AUTHOPT_KEY_EXCLUDE_OPTS | \ TCP_AUTHOPT_KEY_ADDR_BIND | \ - TCP_AUTHOPT_KEY_IFINDEX) + TCP_AUTHOPT_KEY_IFINDEX | \ + TCP_AUTHOPT_KEY_NOSEND | \ + TCP_AUTHOPT_KEY_NORECV)int tcp_set_authopt_key (struct sock *sk,sockptr_t optval,unsigned int optlen) {struct tcp_authopt_key opt;struct tcp_authopt_info *info;
@@ -1496,10 +1500,13 @@ static struct tcp_authopt_key_info *tcp_authopt_lookup_recv(struct sock *sk,if (l3index != key->l3index)continue ; } *anykey = true; +// If only keys with norecv flag are present still consider that +if (key->flags &TCP_AUTHOPT_KEY_NORECV ) +continue ;if (recv_id >=0 && key->recv_id != recv_id)continue ;if (better_key_match (result, key)) result = key;else if (result)
Signature · 1 line
2.25.1
PATCH v3 15/18 tcp: authopt: Add prefixlen support
In reply to Leonard CrestezThis allows making a key apply to an addr/prefix instead of just the full addr. This is enabled through a custom flag, default behavior is still full address match.
This is equivalent to TCP_MD5SIG_FLAG_PREFIX from TCP_MD5SIG and has the same use-cases.
--- include/net/tcp_authopt.h | 2 ++ include/uapi/linux/tcp.h | 10 ++++++ net/ipv4/tcp_authopt.c | 67 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 75 insertions(+), 4 deletions(-)
include/net/tcp_authopt.h +2 -0
@@ -41,10 +41,12 @@ struct tcp_authopt_key_info {u8 keylen;/** @key: Same as &tcp_authopt_key.key */ u8 key[TCP_AUTHOPT_MAXKEYLEN ];/** @l3index: Same as &tcp_authopt_key.ifindex */ int l3index; +/** @prefix: Length of addr match (default full) */ +int prefixlen;/** @addr: Same as &tcp_authopt_key.addr */ struct sockaddr_storage addr;/** @alg: Algorithm implementation matching alg_id */ struct tcp_authopt_alg_imp *alg; };
include/uapi/linux/tcp.h +10 -0
@@ -403,18 +403,21 @@ struct tcp_authopt {* @TCP_AUTHOPT_KEY_EXCLUDE_OPTS: Exclude TCP options from signature * @TCP_AUTHOPT_KEY_ADDR_BIND: Key only valid for `tcp_authopt.addr` * @TCP_AUTHOPT_KEY_IFINDEX: Key only valid for `tcp_authopt.ifindex` * @TCP_AUTHOPT_KEY_NOSEND: Key invalid for send (expired) * @TCP_AUTHOPT_KEY_NORECV: Key invalid for recv (expired) +* @TCP_AUTHOPT_KEY_PREFIXLEN: Valid value in `tcp_authopt.prefixlen`, otherwise +* match full address length */ enum tcp_authopt_key_flag {TCP_AUTHOPT_KEY_DEL = (1 <<0 ),TCP_AUTHOPT_KEY_EXCLUDE_OPTS = (1 <<1 ),TCP_AUTHOPT_KEY_ADDR_BIND = (1 <<2 ),TCP_AUTHOPT_KEY_IFINDEX = (1 <<3 ),TCP_AUTHOPT_KEY_NOSEND = (1 <<4 ),TCP_AUTHOPT_KEY_NORECV = (1 <<5 ), +TCP_AUTHOPT_KEY_PREFIXLEN = (1 <<6 ), };/** * enum tcp_authopt_alg - Algorithms for TCP Authentication Option */
@@ -465,10 +468,17 @@ struct tcp_authopt_key {* connections through this interface. Interface must be an vrf master. * * This is similar to `tcp_msg5sig.tcpm_ifindex` */ int ifindex; +/** +* @prefixlen: length of prefix to match +* +* Without the TCP_AUTHOPT_KEY_PREFIXLEN flag this is ignored and a full +* address match is performed. +*/ +int prefixlen; };/* setsockopt(fd, IPPROTO_TCP, TCP_ZEROCOPY_RECEIVE, ...) */ #define TCP_RECEIVE_ZEROCOPY_FLAG_TLB_CLEAN_HINT 0x1
net/ipv4/tcp_authopt.c +63 -4
164 lines not on this page · raw message
Signature · 1 line
2.25.1
kernel test robot
build botRe: [PATCH v3 15/18] tcp: authopt: Add prefixlen support
Thank you for the patch! Perhaps something to improve:
Hi Leonard,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on 1fe5b01262844be03de98afdd56d1d393df04d7e]
url: https://github.com/0day-ci/linux/commits/Leonard-Crestez/tcp-Initial-support-for-RFC5925-auth-option/20211208-194125 base: 1fe5b01262844be03de98afdd56d1d393df04d7e config: m68k-randconfig-s031-20211209 (https://download.01.org/0day-ci/archive/20211210/202112100225.hqdTG8c9-lkp(a)intel.com/config) compiler: m68k-linux-gcc (GCC) 11.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# apt-get install sparse
# sparse version: v0.6.4-dirty
# https://github.com/0day-ci/linux/commit/7498e5058485276b294b76ec94a4769b36084115
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Leonard-Crestez/tcp-Initial-support-for-RFC5925-auth-option/20211208-194125
git checkout 7498e5058485276b294b76ec94a4769b36084115
# save the config file to linux build tree
mkdir build_dir
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=m68k SHELL=/bin/bash net/ipv4/
If you fix the issue, kindly add following tag as appropriate
sparse warnings: (new ones prefixed by >>)
>> net/ipv4/tcp_authopt.c:250:42: sparse: sparse: incorrect type in initializer (different base types) @@ expected unsigned int [usertype] mask @@ got restricted __be32 @@ net/ipv4/tcp_authopt.c:250:42: sparse: expected unsigned int [usertype] mask net/ipv4/tcp_authopt.c:250:42: sparse: got restricted __be32 >> net/ipv4/tcp_authopt.c:252:28: sparse: sparse: restricted __be32 degrades to integer
net/ipv4/tcp_authopt.c:252:65: sparse: sparse: restricted __be32 degrades to integer
net/ipv4/tcp_authopt.c:279:42: sparse: sparse: incorrect type in initializer (different base types) @@ expected unsigned int [usertype] mask @@ got restricted __be32 @@
net/ipv4/tcp_authopt.c:279:42: sparse: expected unsigned int [usertype] mask
net/ipv4/tcp_authopt.c:279:42: sparse: got restricted __be32
net/ipv4/tcp_authopt.c:281:34: sparse: sparse: restricted __be32 degrades to integer net/ipv4/tcp_authopt.c:281:72: sparse: sparse: restricted __be32 degrades to integer net/ipv4/tcp_authopt.c:394:23: sparse: sparse: incompatible types in comparison expression (different address spaces):
net/ipv4/tcp_authopt.c:394:23: sparse: struct tcp_authopt_key_info [noderef] __rcu *
net/ipv4/tcp_authopt.c:394:23: sparse: struct tcp_authopt_key_info *
net/ipv4/tcp_authopt.c:396:23: sparse: sparse: incompatible types in comparison expression (different address spaces):
net/ipv4/tcp_authopt.c:396:23: sparse: struct tcp_authopt_key_info [noderef] __rcu *
net/ipv4/tcp_authopt.c:396:23: sparse: struct tcp_authopt_key_info *
net/ipv4/tcp_authopt.c:420:25: sparse: sparse: incompatible types in comparison expression (different address spaces):
net/ipv4/tcp_authopt.c:420:25: sparse: struct tcp_authopt_key_info [noderef] __rcu *
net/ipv4/tcp_authopt.c:420:25: sparse: struct tcp_authopt_key_info *
net/ipv4/tcp_authopt.c:560:20: sparse: sparse: incompatible types in comparison expression (different address spaces):
net/ipv4/tcp_authopt.c:560:20: sparse: struct tcp_authopt_key_info [noderef] __rcu *
net/ipv4/tcp_authopt.c:560:20: sparse: struct tcp_authopt_key_info *
net/ipv4/tcp_authopt.c:579:13: sparse: sparse: incompatible types in comparison expression (different address spaces):
net/ipv4/tcp_authopt.c:579:13: sparse: struct tcp_authopt_key_info [noderef] __rcu *
net/ipv4/tcp_authopt.c:579:13: sparse: struct tcp_authopt_key_info *
net/ipv4/tcp_authopt.c:580:17: sparse: sparse: incompatible types in comparison expression (different address spaces):
net/ipv4/tcp_authopt.c:580:17: sparse: struct tcp_authopt_key_info [noderef] __rcu *
net/ipv4/tcp_authopt.c:580:17: sparse: struct tcp_authopt_key_info *
vim +250 net/ipv4/tcp_authopt.c
241
242 static bool tcp_authopt_key_match_skb_addr(struct tcp_authopt_key_info *key,
243 struct sk_buff *skb)
244 {
245 u16 keyaf = key->addr.ss_family;
246 struct iphdr *iph = (struct iphdr *)skb_network_header(skb);
247
248 if (keyaf == AF_INET && iph->version == 4) {
249 struct sockaddr_in *key_addr = (struct sockaddr_in *)&key->addr;
> 250 u32 mask = inet_make_mask(key->prefixlen); 251 > 252 return (iph->saddr & mask) == key_addr->sin_addr.s_addr;
253 } else if (keyaf == AF_INET6 && iph->version == 6) {
254 struct ipv6hdr *ip6h = (struct ipv6hdr *)skb_network_header(skb);
255 struct sockaddr_in6 *key_addr = (struct sockaddr_in6 *)&key->addr;
256
257 return ipv6_prefix_equal(&ip6h->saddr,
258 &key_addr->sin6_addr,
259 key->prefixlen);
260 }
261
262 /* This actually happens with ipv6-mapped-ipv4-addresses
263 * IPv6 listen sockets will be asked to validate ipv4 packets.
264 */
265 return false;
266 }
267
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
PATCH v3 16/18 selftests: nettest: Rename md5_prefix to key_addr_prefix
In reply to Leonard CrestezThis is in preparation for reusing the same option for TCP-AO
--- tools/testing/selftests/net/nettest.c | 50 +++++++++++++-------------- 1 file changed, 25 insertions(+), 25 deletions(-)
tools/testing/selftests/net/nettest.c +25 -25
@@ -94,17 +94,17 @@ struct sock_args {const char *clientns;const char *serverns;const char *password;const char *client_pw; -/* prefix for MD5 password */ -const char *md5_prefix_str; +/* prefix for MD5/AO*/ +const char *key_addr_prefix_str;union {struct sockaddr_in v4;struct sockaddr_in6 v6; - } md5_prefix; -unsigned int prefix_len; + } key_addr; +unsigned int key_addr_prefix_len;/* 0: default, -1: force off, +1: force on */ int bind_key_ifindex;/* expected addresses and device index for connection */ const char *expected_dev;
@@ -264,16 +264,16 @@ static int tcp_md5sig(int sd, void *addr, socklen_t alen, struct sock_args *argsint rc; md5sig.tcpm_keylen = keylen;memcpy (md5sig.tcpm_key, args->password, keylen); -if (args->prefix_len) { +if (args->key_addr_prefix_len) { opt =TCP_MD5SIG_EXT ; md5sig.tcpm_flags |=TCP_MD5SIG_FLAG_PREFIX ; - md5sig.tcpm_prefixlen = args->prefix_len; - addr = &args->md5_prefix; + md5sig.tcpm_prefixlen = args->key_addr_prefix_len; + addr = &args->key_addr; }memcpy (&md5sig.tcpm_addr, addr, alen);if ((args->ifindex && args->bind_key_ifindex >=0 ) || args->bind_key_ifindex >=1 ) { opt =TCP_MD5SIG_EXT ;
@@ -309,17 +309,17 @@ static int tcp_md5_remote(int sd, struct sock_args *args)int alen;switch (args->version) {case AF_INET : sin.sin_port =htons (args->port); - sin.sin_addr = args->md5_prefix.v4.sin_addr; + sin.sin_addr = args->key_addr.v4.sin_addr; addr = &sin; alen =sizeof (sin);break ;case AF_INET6 : sin6.sin6_port =htons (args->port); - sin6.sin6_addr = args->md5_prefix.v6.sin6_addr; + sin6.sin6_addr = args->key_addr.v6.sin6_addr; addr = &sin6; alen =sizeof (sin6);break ;default :log_error ("unknown address family\n" );
@@ -705,11 +705,11 @@ enum addr_type {ADDR_TYPE_LOCAL ,ADDR_TYPE_REMOTE ,ADDR_TYPE_MCAST ,ADDR_TYPE_EXPECTED_LOCAL ,ADDR_TYPE_EXPECTED_REMOTE , - ADDR_TYPE_MD5_PREFIX, + ADDR_TYPE_KEY_PREFIX, };static int convert_addr (struct sock_args *args,const char *_str,enum addr_type atype) {
@@ -745,32 +745,32 @@ static int convert_addr(struct sock_args *args, const char *_str,break ;case ADDR_TYPE_EXPECTED_REMOTE : desc ="expected remote" ; addr = &args->expected_raddr;break ; -case ADDR_TYPE_MD5_PREFIX : - desc ="md5 prefix" ; +case ADDR_TYPE_KEY_PREFIX : + desc ="key addr prefix" ;if (family ==AF_INET ) { - args->md5_prefix.v4.sin_family =AF_INET ; - addr = &args->md5_prefix.v4.sin_addr; + args->key_addr.v4.sin_family =AF_INET ; + addr = &args->key_addr.v4.sin_addr; }else if (family ==AF_INET6 ) { - args->md5_prefix.v6.sin6_family =AF_INET6 ; - addr = &args->md5_prefix.v6.sin6_addr; + args->key_addr.v6.sin6_family =AF_INET6 ; + addr = &args->key_addr.v6.sin6_addr; }else return 1 ; sep =strchr (str,'/' );if (sep) { *sep ='\0' ; sep++;if (str_to_uint (sep,1 , pfx_len_max, - &args->prefix_len) !=0 ) { -fprintf (stderr,"Invalid port\n" ); + &args->key_addr_prefix_len) !=0 ) { +fprintf (stderr,"Invalid prefix\n" );return 1 ; } }else { - args->prefix_len =0 ; + args->key_addr_prefix_len =0 ; }break ;default :log_error ("unknown address type\n" );exit (1 );
@@ -835,13 +835,13 @@ static int validate_addresses(struct sock_args *args)if (args->remote_addr_str &&convert_addr (args, args->remote_addr_str,ADDR_TYPE_REMOTE ) <0 )return 1 ; -if (args->md5_prefix_str && -convert_addr (args, args->md5_prefix_str, -ADDR_TYPE_MD5_PREFIX ) <0 ) +if (args->key_addr_prefix_str && +convert_addr (args, args->key_addr_prefix_str, +ADDR_TYPE_KEY_PREFIX ) <0 )return 1 ;if (args->expected_laddr_str &&convert_addr (args, args->expected_laddr_str,ADDR_TYPE_EXPECTED_LOCAL ))
@@ -2020,11 +2020,11 @@ int main(int argc, char *argv[])break ;case 'X' : args.client_pw = optarg;break ;case 'm' : - args.md5_prefix_str = optarg; + args.key_addr_prefix_str = optarg;break ;case 'S' : args.use_setsockopt =1 ;break ;case 'f' :
@@ -2079,17 +2079,17 @@ int main(int argc, char *argv[])return 1 ; } }if (args.password && - ((!args.has_remote_ip && !args.md5_prefix_str) || + ((!args.has_remote_ip && !args.key_addr_prefix_str) || args.type !=SOCK_STREAM )) {log_error ("MD5 passwords apply to TCP only and require a remote ip for the password\n" );return 1 ; } -if (args.md5_prefix_str && !args.password) { +if (args.key_addr_prefix_str && !args.password) {log_error ("Prefix range for MD5 protection specified without a password\n" );return 1 ; }if (iter ==0 ) {
Signature · 1 line
2.25.1
PATCH v3 17/18 selftests: nettest: Initial tcp_authopt support
In reply to Leonard CrestezAdd support for configuring TCP Authentication Option. Only a single key is supported with default options.
--- tools/testing/selftests/net/nettest.c | 75 ++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 6 deletions(-)
tools/testing/selftests/net/nettest.c +69 -6
@@ -104,10 +104,12 @@ struct sock_args { } key_addr;unsigned int key_addr_prefix_len;/* 0: default, -1: force off, +1: force on */ int bind_key_ifindex; +const char *authopt_password; +/* expected addresses and device index for connection */ const char *expected_dev;const char *expected_server_dev;int expected_ifindex;
@@ -254,10 +256,54 @@ static int switch_ns(const char *ns)close (fd);return ret; } +static int tcp_set_authopt (int sd,struct sock_args *args) +{ +struct tcp_authopt_key key; +int rc; + +memset (&key,0 ,sizeof (key)); +strcpy ((char *)key.key, args->authopt_password); + key.keylen =strlen (args->authopt_password); + key.alg =TCP_AUTHOPT_ALG_HMAC_SHA_1_96 ; + +if (args->key_addr_prefix_str) { + key.flags |=TCP_AUTHOPT_KEY_ADDR_BIND ; +switch (args->version) { +case AF_INET : +memcpy (&key.addr, &args->key_addr.v4,sizeof (args->key_addr.v4)); +break ; +case AF_INET6 : +memcpy (&key.addr, &args->key_addr.v6,sizeof (args->key_addr.v6)); +break ; +default : +log_error ("unknown address family\n" ); +exit (1 ); + } +if (args->key_addr_prefix_len) { + key.flags |=TCP_AUTHOPT_KEY_PREFIXLEN ; + key.prefixlen = args->key_addr_prefix_len; + } + } + +if ((args->ifindex && args->bind_key_ifindex >=0 ) || args->bind_key_ifindex >=1 ) { + key.flags |=TCP_AUTHOPT_KEY_IFINDEX ; + key.ifindex = args->ifindex; +log_msg ("TCP_AUTHOPT_KEY_IFINDEX set ifindex=%d\n" , key.ifindex); + }else { +log_msg ("TCP_AUTHOPT_KEY_IFINDEX off\n" , key.ifindex); + } + + rc =setsockopt (sd,IPPROTO_TCP ,TCP_AUTHOPT_KEY , &key,sizeof (key)); +if (rc <0 ) +log_err_errno ("setsockopt(TCP_AUTHOPT_KEY)" ); + +return rc; +} +static int tcp_md5sig (int sd,void *addr,socklen_t alen,struct sock_args *args) {int keylen =strlen (args->password);struct tcp_md5sig md5sig = {};int opt =TCP_MD5SIG ;
@@ -1541,10 +1587,15 @@ static int do_server(struct sock_args *args, int ipc_fd)if (args->password &&tcp_md5_remote (lsd, args)) {close (lsd); goto err_exit; } +if (args->authopt_password &&tcp_set_authopt (lsd, args)) { +close (lsd); + goto err_exit; + } +ipc_write (ipc_fd,1 );while (1 ) {log_msg ("waiting for client connection.\n" );FD_ZERO (&rfds);FD_SET (lsd, &rfds);
@@ -1663,10 +1714,13 @@ static int connectsock(void *addr, socklen_t alen, struct sock_args *args) goto out;if (args->password &&tcp_md5sig (sd, addr, alen, args)) goto err; +if (args->authopt_password &&tcp_set_authopt (sd, args)) + goto err; +if (args->bind_test_only) goto out;if (connect (sd, addr, alen) <0 ) {if (errno !=EINPROGRESS ) {
@@ -1852,11 +1906,11 @@ static int ipc_parent(int cpid, int fd, struct sock_args *args)wait (&status);return client_status; } -#define GETOPT_STR "sr:l:c:p:t:g:P:DRn:M:X:m:d:I:BN:O:SCi6xL:0:1:2:3:Fbqf" +#define GETOPT_STR "sr:l:c:p:t:g:P:DRn:M:X:m:A:d:I:BN:O:SCi6xL:0:1:2:3:Fbqf"#define OPT_FORCE_BIND_KEY_IFINDEX 1001#define OPT_NO_BIND_KEY_IFINDEX 1002static struct option long_opts[] = { {"force-bind-key-ifindex" ,0 ,0 ,OPT_FORCE_BIND_KEY_IFINDEX },
@@ -1897,14 +1951,15 @@ static void print_usage(char *prog)" -L len send random message of given length\n" " -n num number of times to send message\n" "\n" " -M password use MD5 sum protection\n" " -X password MD5 password for client mode\n" -" -m prefix/len prefix and length to use for MD5 key\n" -" --no-bind-key-ifindex: Force TCP_MD5SIG_FLAG_IFINDEX off\n" -" --force-bind-key-ifindex: Force TCP_MD5SIG_FLAG_IFINDEX on\n" +" -m prefix/len prefix and length to use for MD5/AO key\n" +" --no-bind-key-ifindex: Force disable binding key to ifindex\n" +" --force-bind-key-ifindex: Force enable binding key to ifindex\n" " (default: only if -I is passed)\n" +" -A password use RFC5925 TCP Authentication Option with password\n" "\n" " -g grp multicast group (e.g., 239.1.1.1)\n" " -i interactive mode (default is echo and terminate)\n" "\n" " -0 addr Expected local address\n"
@@ -2022,10 +2077,13 @@ int main(int argc, char *argv[]) args.client_pw = optarg;break ;case 'm' : args.key_addr_prefix_str = optarg;break ; +case 'A' : + args.authopt_password = optarg; +break ;case 'S' : args.use_setsockopt =1 ;break ;case 'f' : args.use_freebind =1 ;
@@ -2085,12 +2143,17 @@ int main(int argc, char *argv[]) args.type != SOCK_STREAM)) {log_error ("MD5 passwords apply to TCP only and require a remote ip for the password\n" );return 1 ; } -if (args.key_addr_prefix_str && !args.password) { -log_error ("Prefix range for MD5 protection specified without a password\n" ); +if (args.key_addr_prefix_str && !args.password && !args.authopt_password) { +log_error ("Prefix range for authentication requires -M or -A\n" ); +return 1 ; + } + +if (args.key_addr_prefix_len && args.authopt_password) { +log_error ("TCP-AO does not support prefix match, only full address\n" );return 1 ; }if (iter ==0 ) {fprintf (stderr,"Invalid number of messages to send\n" );
Signature · 1 line
2.25.1
PATCH v3 18/18 selftests: net/fcnal: Initial tcp_authopt support
In reply to Leonard CrestezTests are mostly copied from tcp_md5 with minor changes.
It covers VRF support but only based on binding multiple servers: not multiple keys bound to different interfaces.
Also add a specific -t tcp_authopt to run only these tests specifically.
--- tools/testing/selftests/net/fcnal-test.sh | 298 ++++++++++++++++++++++ 1 file changed, 298 insertions(+)
tools/testing/selftests/net/fcnal-test.sh +298 -0
@@ -807,10 +807,301 @@ ipv4_ping() } ################################################################################ # IPv4 TCP +# +# TCP Authentication Option Tests +# + +# try to enable tcp_authopt sysctl +enable_tcp_authopt() +{ + if [[ -e /proc/sys/net/ipv4/tcp_authopt ]]; then + sysctl -w net.ipv4.tcp_authopt=1 + fi +} + +# check if tcp_authopt is compiled with a client-side bind test +has_tcp_authopt() +{ + run_cmd_nsb nettest -b -A ${MD5_PW} -r ${NSA_IP} +} + +ipv4_tcp_authopt_novrf() +{ + enable_tcp_authopt + if ! has_tcp_authopt; then + echo "TCP-AO appears to be missing, skip" + return 0 + fi + + log_start + run_cmd nettest -s -A ${MD5_PW} -m ${NSB_IP} & + sleep 1 + run_cmd_nsb nettest -r ${NSA_IP} -A ${MD5_PW} + log_test $? 0 "AO: Single address config" + + log_start + run_cmd nettest -s & + sleep 1 + run_cmd_nsb nettest -r ${NSA_IP} -A ${MD5_PW} + log_test $? 2 "AO: Server no config, client uses password" + + log_start + run_cmd nettest -s -A ${MD5_PW} -m ${NSB_IP} & + sleep 1 + run_cmd_nsb nettest -r ${NSA_IP} -A ${MD5_WRONG_PW} + log_test $? 2 "AO: Client uses wrong password" + + log_start + run_cmd nettest -s -A ${MD5_PW} -m ${NSB_LO_IP} & + sleep 1 + run_cmd_nsb nettest -r ${NSA_IP} -A ${MD5_PW} + log_test $? 2 "AO: Client address does not match address configured on server" + + # client in prefix + log_start + run_cmd nettest -s -A ${MD5_PW} -m ${NS_NET} & + sleep 1 + run_cmd_nsb nettest -r ${NSA_IP} -A ${MD5_PW} + log_test $? 0 "AO: Prefix config" + + # client in prefix, wrong password + log_start + show_hint "Should timeout since client uses wrong password" + run_cmd nettest -s -A ${MD5_PW} -m ${NS_NET} & + sleep 1 + run_cmd_nsb nettest -r ${NSA_IP} -A ${MD5_WRONG_PW} + log_test $? 2 "AO: Prefix config, client uses wrong password" + + # client outside of prefix + log_start + show_hint "Should timeout due to MD5 mismatch" + run_cmd nettest -s -A ${MD5_PW} -m ${NS_NET} & + sleep 1 + run_cmd_nsb nettest -c ${NSB_LO_IP} -r ${NSA_IP} -A ${MD5_PW} + log_test $? 2 "AO: Prefix config, client address not in configured prefix" +} + +ipv6_tcp_authopt_novrf() +{ + enable_tcp_authopt + if ! has_tcp_authopt; then + echo "TCP-AO appears to be missing, skip" + return 0 + fi + + log_start + run_cmd nettest -6 -s -A ${MD5_PW} & + sleep 1 + run_cmd_nsb nettest -6 -r ${NSA_IP6} -A ${MD5_PW} + log_test $? 0 "AO: Simple correct config" + + log_start + run_cmd nettest -6 -s + sleep 1 + run_cmd_nsb nettest -6 -r ${NSA_IP6} -A ${MD5_PW} + log_test $? 2 "AO: Server no config, client uses password" + + log_start + run_cmd nettest -6 -s -A ${MD5_PW} -m ${NSB_IP6} & + sleep 1 + run_cmd_nsb nettest -6 -r ${NSA_IP6} -A ${MD5_WRONG_PW} + log_test $? 2 "AO: Client uses wrong password" + + log_start + run_cmd nettest -6 -s -A ${MD5_PW} -m ${NSB_LO_IP6} & + sleep 1 + run_cmd_nsb nettest -6 -r ${NSA_IP6} -A ${MD5_PW} + log_test $? 2 "AO: Client address does not match address configured on server" +} + +ipv4_tcp_authopt_vrf() +{ + enable_tcp_authopt + if ! has_tcp_authopt; then + echo "TCP-AO appears to be missing, skip" + return 0 + fi + + log_start + run_cmd nettest -s -I ${VRF} -A ${MD5_PW} & + sleep 1 + run_cmd_nsb nettest -r ${NSA_IP} -A ${MD5_PW} + log_test $? 0 "AO: VRF: Simple config" + + # + # duplicate config between default VRF and a VRF + # + + log_start + run_cmd nettest -s -I ${VRF} -A ${MD5_PW} -m ${NSB_IP} & + run_cmd nettest -s -A ${MD5_WRONG_PW} -m ${NSB_IP} & + sleep 1 + run_cmd_nsb nettest -r ${NSA_IP} -A ${MD5_PW} + log_test $? 0 "AO: VRF: Servers in default-VRF and VRF, client in VRF" + + log_start + run_cmd nettest -s -I ${VRF} -A ${MD5_PW} -m ${NSB_IP} & + run_cmd nettest -s -A ${MD5_WRONG_PW} -m ${NSB_IP} & + sleep 1 + run_cmd_nsc nettest -r ${NSA_IP} -A ${MD5_WRONG_PW} + log_test $? 0 "AO: VRF: Servers in default-VRF and VRF, client in default-VRF" + + log_start + show_hint "Should timeout since client in default VRF uses VRF password" + run_cmd nettest -s -I ${VRF} -A ${MD5_PW} -m ${NSB_IP} & + run_cmd nettest -s -A ${MD5_WRONG_PW} -m ${NSB_IP} & + sleep 1 + run_cmd_nsc nettest -r ${NSA_IP} -A ${MD5_PW} + log_test $? 2 "AO: VRF: Servers in default VRF and VRF, conn in default-VRF with VRF pw" + + log_start + show_hint "Should timeout since client in VRF uses default VRF password" + run_cmd nettest -s -I ${VRF} -A ${MD5_PW} -m ${NSB_IP} & + run_cmd nettest -s -A ${MD5_WRONG_PW} -m ${NSB_IP} & + sleep 1 + run_cmd_nsb nettest -r ${NSA_IP} -A ${MD5_WRONG_PW} + log_test $? 2 "AO: VRF: Servers in default VRF and VRF, conn in VRF with default-VRF pw" + + test_ipv4_tcp_authopt_vrf__global_server__bind_ifindex0 +} + +test_ipv4_tcp_authopt_vrf__global_server__bind_ifindex0() +{ + # This particular test needs tcp_l3mdev_accept=1 for Global server to accept VRF connections + local old_tcp_l3mdev_accept + old_tcp_l3mdev_accept=$(get_sysctl net.ipv4.tcp_l3mdev_accept) + set_sysctl net.ipv4.tcp_l3mdev_accept=1 + + log_start + run_cmd nettest -s -A ${MD5_PW} --force-bind-key-ifindex & + sleep 1 + run_cmd_nsb nettest -r ${NSA_IP} -A ${MD5_PW} + log_test $? 2 "AO: VRF: Global server, Key bound to ifindex=0 rejects VRF connection" + + log_start + run_cmd nettest -s -A ${MD5_PW} --force-bind-key-ifindex & + sleep 1 + run_cmd_nsc nettest -r ${NSA_IP} -A ${MD5_PW} + log_test $? 0 "AO: VRF: Global server, key bound to ifindex=0 accepts non-VRF connection" + log_start + + run_cmd nettest -s -A ${MD5_PW} --no-bind-key-ifindex & + sleep 1 + run_cmd_nsb nettest -r ${NSA_IP} -A ${MD5_PW} + log_test $? 0 "AO: VRF: Global server, key not bound to ifindex accepts VRF connection" + + log_start + run_cmd nettest -s -A ${MD5_PW} --no-bind-key-ifindex & + sleep 1 + run_cmd_nsc nettest -r ${NSA_IP} -A ${MD5_PW} + log_test $? 0 "AO: VRF: Global server, key not bound to ifindex accepts non-VRF connection" + + # restore value + set_sysctl net.ipv4.tcp_l3mdev_accept="$old_tcp_l3mdev_accept" +} + +ipv6_tcp_authopt_vrf() +{ + enable_tcp_authopt + if ! has_tcp_authopt; then + echo "TCP-AO appears to be missing, skip" + return 0 + fi + + log_start + run_cmd nettest -6 -s -I ${VRF} -A ${MD5_PW} & + sleep 1 + run_cmd_nsb nettest -6 -r ${NSA_IP6} -A ${MD5_PW} + log_test $? 0 "AO: VRF: Simple config" + + # + # duplicate config between default VRF and a VRF + # + + log_start + run_cmd nettest -6 -s -I ${VRF} -A ${MD5_PW} -m ${NSB_IP6} & + run_cmd nettest -6 -s -A ${MD5_WRONG_PW} -m ${NSB_IP6} & + sleep 1 + run_cmd_nsb nettest -6 -r ${NSA_IP6} -A ${MD5_PW} + log_test $? 0 "AO: VRF: Servers in default-VRF and VRF, client in VRF" + + log_start + run_cmd nettest -6 -s -I ${VRF} -A ${MD5_PW} -m ${NSB_IP6} & + run_cmd nettest -6 -s -A ${MD5_WRONG_PW} -m ${NSB_IP6} & + sleep 1 + run_cmd_nsc nettest -6 -r ${NSA_IP6} -A ${MD5_WRONG_PW} + log_test $? 0 "AO: VRF: Servers in default-VRF and VRF, client in default-VRF" + + log_start + show_hint "Should timeout since client in default VRF uses VRF password" + run_cmd nettest -6 -s -I ${VRF} -A ${MD5_PW} -m ${NSB_IP6} & + run_cmd nettest -6 -s -A ${MD5_WRONG_PW} -m ${NSB_IP6} & + sleep 1 + run_cmd_nsc nettest -6 -r ${NSA_IP6} -A ${MD5_PW} + log_test $? 2 "AO: VRF: Servers in default VRF and VRF, conn in default-VRF with VRF pw" + + log_start + show_hint "Should timeout since client in VRF uses default VRF password" + run_cmd nettest -6 -s -I ${VRF} -A ${MD5_PW} -m ${NSB_IP6} & + run_cmd nettest -6 -s -A ${MD5_WRONG_PW} -m ${NSB_IP6} & + sleep 1 + run_cmd_nsb nettest -6 -r ${NSA_IP6} -A ${MD5_WRONG_PW} + log_test $? 2 "AO: VRF: Servers in default VRF and VRF, conn in VRF with default-VRF pw" + + log_start + run_cmd nettest -6 -s -I ${VRF} -A ${MD5_PW} -m ${NS_NET6} & + run_cmd nettest -6 -s -A ${MD5_WRONG_PW} -m ${NS_NET6} & + sleep 1 + run_cmd_nsb nettest -6 -r ${NSA_IP6} -A ${MD5_PW} + log_test $? 0 "AO: VRF: Prefix config in default VRF and VRF, conn in VRF" + + log_start + run_cmd nettest -6 -s -I ${VRF} -A ${MD5_PW} -m ${NS_NET6} & + run_cmd nettest -6 -s -A ${MD5_WRONG_PW} -m ${NS_NET6} & + sleep 1 + run_cmd_nsc nettest -6 -r ${NSA_IP6} -A ${MD5_WRONG_PW} + log_test $? 0 "AO: VRF: Prefix config in default VRF and VRF, conn in default VRF" + + log_start + show_hint "Should timeout since client in default VRF uses VRF password" + run_cmd nettest -6 -s -I ${VRF} -A ${MD5_PW} -m ${NS_NET6} & + run_cmd nettest -6 -s -A ${MD5_WRONG_PW} -m ${NS_NET6} & + sleep 1 + run_cmd_nsc nettest -6 -r ${NSA_IP6} -A ${MD5_PW} + log_test $? 2 "AO: VRF: Prefix config in def VRF and VRF, conn in def VRF with VRF pw" + + log_start + show_hint "Should timeout since client in VRF uses default VRF password" + run_cmd nettest -6 -s -I ${VRF} -A ${MD5_PW} -m ${NS_NET6} & + run_cmd nettest -6 -s -A ${MD5_WRONG_PW} -m ${NS_NET6} & + sleep 1 + run_cmd_nsb nettest -6 -r ${NSA_IP6} -A ${MD5_WRONG_PW} + log_test $? 2 "AO: VRF: Prefix config in dev VRF and VRF, conn in VRF with def VRF pw" +} + +only_tcp_authopt() +{ + log_section "TCP Authentication Option" + + setup + set_sysctl net.ipv4.tcp_l3mdev_accept=0 + log_subsection "TCP-AO IPv4 no VRF" + ipv4_tcp_authopt_novrf + log_subsection "TCP-AO IPv6 no VRF" + ipv6_tcp_authopt_novrf + + setup "yes" + set_sysctl net.ipv4.tcp_l3mdev_accept=0 + log_subsection "TCP-AO IPv4 VRF" + ipv4_tcp_authopt_vrf + log_subsection "TCP-AO IPv6 VRF" + ipv6_tcp_authopt_vrf +} + # # MD5 tests without VRF # ipv4_tcp_md5_novrf() {
@@ -1192,10 +1483,11 @@ ipv4_tcp_novrf() show_hint "Should fail 'Connection refused'" run_cmd nettest -d ${NSA_DEV} -r ${a} log_test_addr ${a} $? 1 "No server, device client, local conn" ipv4_tcp_md5_novrf + ipv4_tcp_authopt_novrf } ipv4_tcp_vrf() { local a
@@ -1246,10 +1538,12 @@ ipv4_tcp_vrf() run_cmd nettest -r ${a} -d ${NSA_DEV} log_test_addr ${a} $? 1 "Global server, local connection" # run MD5 tests ipv4_tcp_md5 + # run AO tests + ipv6_tcp_md5_vrf # # enable VRF global server # log_subsection "VRF Global server enabled"
@@ -2672,10 +2966,11 @@ ipv6_tcp_novrf() run_cmd nettest -6 -d ${NSA_DEV} -r ${a} log_test_addr ${a} $? 1 "No server, device client, local conn" done ipv6_tcp_md5_novrf + ipv6_tcp_authopt_novrf } ipv6_tcp_vrf() { local a
@@ -2742,10 +3037,12 @@ ipv6_tcp_vrf() run_cmd nettest -6 -r ${a} -d ${NSA_DEV} log_test_addr ${a} $? 1 "Global server, local connection" # run MD5 tests ipv6_tcp_md5 + # run AO tests + ipv6_tcp_authopt_vrf # # enable VRF global server # log_subsection "VRF Global server enabled"
@@ -4102,10 +4399,11 @@ do ipv6_bind|bind6) ipv6_addr_bind;; ipv6_runtime) ipv6_runtime;; ipv6_netfilter) ipv6_netfilter;; use_cases) use_cases;; + tcp_authopt) only_tcp_authopt;; # setup namespaces and config, but do not run any tests setup) setup; exit 0;; vrf_setup) setup "yes"; exit 0;; esac
Signature · 1 line
2.25.1
Quoted 191 lines · Leonard Crestez
This is similar to TCP MD5 in functionality but it's sufficiently different that wire formats are incompatible. Compared to TCP-MD5 more algorithms are supported and multiple keys can be used on the same connection but there is still no negotiation mechanism.
Expected use-case is protecting long-duration BGP/LDP connections between routers using pre-shared keys. The goal of this series is to allow routers using the linux TCP stack to interoperate with vendors such as Cisco and Juniper.
Both algorithms described in RFC5926 are implemented but the code is not very easily extensible beyond that. In particular there are several code paths making stack allocations based on RFC5926 maximum, those would have to be increased. Support for arbitrary algorithms was requested in reply to previous posts but I believe there is no real use case for that.
The current implementation is somewhat loose regarding configuration:
* Overlaping MKTs can be configured despite what RFC5925 says
* Current key can be deleted
* If multiple keys are valid for a destination the kernel picks one in an unpredictable manner (this can be overridden).
These conditions could be tightened but it is not clear the kernel should prevent misconfiguration from userspace.This version implements prefixlen and incorporates comments from v2 as well as some unrelated fixes. Here are some known flaws and limitations:
* Crypto API is used with buffers on the stack and inside struct sock, this might not work on all arches. I'm currently only testing x64 VMs
* Interaction with TCP-MD5 not tested in all corners.
* Interaction with FASTOPEN not tested and unlikely to work because sequence number assumptions for syn/ack.
* Not clear ifcrypto_ahash_setkeymight sleep. If some implementation do that then maybe they could be excluded through alloc flags.
* Traffic key is not cached (reducing performance)
* There is no useful way to list keys, making userspace debug difficult.Some testing support is included in nettest and
fcnal-test.sh, similar to the current level of tcp-md5 testing.A more elaborate test suite using pytest and scapy is available out of
tree: https://github.com/cdleonard/tcp-authopt-test That test suite is much larger that the kernel code and did not receive many comments so I will attempt to push it separately (if at all).Changes for frr (old): https://github.com/FRRouting/frr/pull/9442
That PR was made early for ABI feedback, it has many issues.Changes for yabgp (old): https://github.com/cdleonard/yabgp/commits/tcp_authopt
This can be use for easy interoperability testing with cisco/juniper/etc.Changes since PATCH v2:
* Protect tcp_authopt_alg_get/put_tfm withlocal_bh_disableinstead ofpreempt_disable. This caused signature corruption when send path executing with BH enabled was interrupted by recv.
* Fix accepted keyids not configured locally as "unexpected". If any key is configured that matches the peer then traffic MUST be signed.
* Fix issues related to sne rollover during handshake itself. (Francesco)
* Implement and test prefixlen (David)
* Replace shash with ahash and reuse some of the MD5 code (Dmitry)
* Parse md5+ao options only once in the same function (Dmitry)
* Passtcp_authopt_infointo inbound check path, this avoids second rcu dereference for same packet.
* Passtcp_request_socketinto inbound check path instead of just listen socket. This is required for SNE rollover during handshake and clearifies ISN handling.
* Do not allow disabling via sysctl after enabling once, this is difficult to support well (David)
* Verbose check forsysctl_tcp_authopt(Dmitry)
* Usenetif_index_is_l3_master(David)
* Cleanupipvx_addr_match(David)
* Add a #definetcp_authopt_neededto wrap static key usage because it looks nicer.
* Replacercu_read_lockwithrcu_dereference_protectedin SNE updates (Eric)Changes since PATCH v1:
* Implement Sequence Number Extension
* Implement l3index for vrf:TCP_AUTHOPT_KEY_IFINDEXas equivalent ofTCP_MD5SIG_FLAG_IFINDEX
* Expand TCP-AO tests infcnal-test.shto near-parity with md5.
* Show addr/port on failure similar to md5
* Remove tox dependency from test suite (create venv directly)
* Switch default pytest output format to TAP (kselftest standard)
* Fix_copy_from_sockptr_tolerantstack corruption on short sockopts. This was covered in test but error was invisible without STACKPROTECTOR=y
* Fixsysctl_tcp_authoptcheck intcp_get_authopt_valbefore memset. This was harmless because error code is checked in getsockopt anyway.
* Fix dropping md5 packets on all sockets with AO enabled
* Fix checking (key->recv_id&TCP_AUTHOPT_KEY_ADDR_BIND) instead ofkey->flagsintcp_authopt_key_match_exact
* Fix PATCH 1/19 not compiling due to missing "int err" declaration
* Add ratelimited message for AO and MD5 both present
* Export all symbols required byCONFIG_IPV6=m(again)
* Fix compilation withCONFIG_TCP_AUTHOPT=yCONFIG_TCP_MD5SIG=n
* Fix checkpatch issues
* Pass -rrequirements.txt to tox to avoid dependency variation.Changes since RFCv3:
* ImplementTCP_AUTHOPThandling for timewait and reset replies. Write tests to execute these paths by injecting packets with scapy
* Handle combining md5 and authopt: if both are configured use authopt.
* Fix locking issues aroundsend_key, introduced in on of the later patches.
* Handle IPv4-mapped-IPv6 addresses: it used to be that an ipv4 SYN sent to an ipv6 socket with TCP-AO triggered WARN
* Implement un-namespaced sysctl disabled this feature by default
* Allocate new key before removing any old one in setsockopt (Dmitry)
* Remove tcp_authopt_key_info.local_id because it's no longer used (Dmitry)
* Propagate errors fromTCP_AUTHOPTgetsockopt (Dmitry)
* Fix no-longer-correctTCP_AUTHOPT_KEY_DELdocs (Dmitry)
* Simplify crypto allocation (Eric)
* Use kzmalloc instead of__GFP_ZERO(Eric)
* Addstatic_key_falsetcp_authopt_needed(Eric)
* Clearauthopt_infocopied from oldsk in__tcp_authopt_openreq(Eric)
* Replace memcmp in ipv4 and ipv6 addr comparisons (Eric)
* Export symbols forCONFIG_IPV6=m(kernel test robot)
* Mark more functions static (kernel test robot)
* Fix build withCONFIG_PROVE_RCU_LIST=y(kernel test robot)Changes since RFCv2:
* Removedlocal_idfrom ABI and match on send_id/recv_id/addr
* Add all relevant out-of-tree tests totools/testing/selftests
* Return an error instead of ignoring unknown flags, hopefully this makes it easier to extend.
* Checksk_familybefore__tcp_authopt_info_get_or_createintcp_set_authopt_key
* Usesock_owned_by_meinstead of WARN_ON(!lockdep_sock_is_held(sk))
* Fix some intermediate build failures reported by kbuild robot
* Improve documentationChanges since RFC:
* Split into per-topic commits for ease of review. The intermediate commits compile with a few "unused function" warnings and don't do anything useful by themselves.
* Add ABI documention including kernel-doc on uapi
* Fix lockdep warnings from crypto by creating pools with one shash for each cpu
* Accept short options to setsockopt by padding with zeros; this approach allows increasing the size of the structs in the future.
* Support for aes-128-cmac-96
* Support for binding addresses to keys in a way similar to oldtcp_md5
* Add support for retrieving received keyid/rnextkeyid and controling the keyid/rnextkeyid being sent.```
Leonard Crestez (18):
tcp: authopt: Initial support and key management
docs: Add user documentation fortcp_authopt
tcp: authopt: Add crypto initialization
tcp: md5: Refactortcp_sig_hash_skb_datafor AO
tcp: authopt: Compute packet signatures
tcp: authopt: Hook into tcp core
tcp: authopt: Disable via sysctl by default
tcp: authopt: Implement Sequence Number Extension
tcp: ipv6: Add AO signing fortcp_v6_send_response
tcp: authopt: Add support for signing skb-less replies
tcp: ipv4: Add AO signing for skb-less replies
tcp: authopt: Add key selection controls
tcp: authopt: Add initial l3index support
tcp: authopt: Add NOSEND/NORECV flags
tcp: authopt: Add prefixlen support
selftests: nettest: Renamemd5_prefixtokey_addr_prefix
selftests: nettest: Initialtcp_authoptsupport
selftests: net/fcnal: Initialtcp_authoptsupportDocumentation/networking/index.rst | 1 + Documentation/networking/ip-sysctl.rst | 6 + Documentation/networking/tcp_authopt.rst | 69 + include/linux/tcp.h | 9 + include/net/tcp.h | 27 +- include/net/tcp_authopt.h | 316 ++++ include/uapi/linux/snmp.h | 1 + include/uapi/linux/tcp.h | 137 ++ net/ipv4/Kconfig | 14 + net/ipv4/Makefile | 1 + net/ipv4/proc.c | 1 + net/ipv4/sysctl_net_ipv4.c | 39 + net/ipv4/tcp.c | 68 +- net/ipv4/tcp_authopt.c | 1671 +++++++++++++++++++++ net/ipv4/tcp_input.c | 41 +- net/ipv4/tcp_ipv4.c | 136 +- net/ipv4/tcp_minisocks.c | 12 + net/ipv4/tcp_output.c | 86 +- net/ipv6/tcp_ipv6.c | 108 +- tools/testing/selftests/net/fcnal-test.sh | 298 ++++ tools/testing/selftests/net/nettest.c | 123 +- 21 files changed, 3085 insertions(+), 79 deletions(-)
Quoted 6 lines
create mode 100644
Documentation/networking/tcp_authopt.rstcreate mode 100644include/net/tcp_authopt.hcreate mode 100644net/ipv4/tcp_authopt.cbase-commit:
1fe5b01262844be03de98afdd56d1d393df04d7e
One issue that I realized recently is that there is an ugly race with the following steps:
1) remote connect
2) server key delete on listen socket
3) server accept
Under the current implementation the new file descriptor created at step 3 has a set of key that is essentially unpredictable. This is because the list of keys is copied from listen socket to newly accepted socket at "tcp_create_openreq_child" time which happens after the 3-way handshake is completely (with an ACK from client) but before accept().
The simplest incorrect behavior is that an incoming connection using a key that is being deleted may be accepted and it will last indefinitely. But it's worse than that: if server sockets have an arbitrarily old version of the key chain then userspace can't reliably implement key management.
Possible solutions:
1. Make linux TCP copy the keys list from the listen socket on "accept" specifically. Not clear where in the code.
2. Add a sockopt to copy keys on demand from listen to accept. Like solution 2 but dumped on userspace.
3. Make userspace check if current key on accepted sockets is expired? Not clear how exactly and right now there isn't even an interface to list current keys on a socket.
4. Make keys global, per-namespace instead of per-socket.
Solution 4 is quite a large change to make so late but it would also simplify userspace in other ways, for example there would no longer be a need to do the same keyadd/keydel on all the established sockets.
Can you think of other solutions? TCP_MD5SIG does not suffer from this very much because it only ever supports one for each established socket.
---
I also had a recent conversation with Philip Paeps which plans to implement TCP-AO for freebsd and various open-source userspace daemons, hopefully in a way that requires minimum os-specific ifdefs.
His initial idea was to use PF_KEY for a global list of keys but I don't think it has any clear advantage over just doing SOL_TCP setsockopts on any random TCP socket. I think if an interface such as PF_KEY or xfrm or netlink would be supported it would still make sense to have an internal list of custom struct tcp_authopt_key anyway. So why not just implement the most specific interface.
Global keys would also be vaguely aligned to this suggestion from FRR: (https://github.com/FRRouting/frr/pull/9442#issuecomment-904766419)
In theory it would be possible to support both socket-specific and global keys, but I can't think of a reason to do so other than compatibility with older version of this patch series.
Can anyone think of a realistic scenario that can only be made to work with per-socket keys?
---
It would also be possible to push all key rollover policy into the kernel. Current proprietary implementations implement something similar to RFC8177: optional time intervals for "accept" and "send". This logic is very simple, it just requires extending the key struct with 4 wall-time fields.
This is not however required for making keys global so it can be a separate discussion.
I also received a bunch of kernel build robot complains that I need to fix.
It's also not clear that making the tcp_authopt_info member in twsk a plain pointer is correct, it might need RCU annotations.
--
Regards,
Leonard