tcp: ULP infrastructure
Subsystems (7)
PATCH v2 1/4 tcp: ULP infrastructure
In reply to a message not in the archiveAdd the infrustructure for attaching Upper Layer Protocols (ULPs) over TCP sockets. Based on a similar infrastructure in tcp_cong. The idea is that any ULP can add its own logic by changing the TCP proto_ops structure to its own methods.
Example usage:
setsockopt(sock, SOL_TCP, TCP_ULP, "tls", sizeof("tls"));
modules will call:tcp_register_ulp(&tcp_tls_ulp_ops);
to register/unregister their ulp, with an init function and name.
A list of registered ulps will be returned by tcp_get_available_ulp, which is hooked up to /proc. Example:
$ cat /proc/sys/net/ipv4/tcp_available_ulp tls
There is currently no functionality to remove or chain ULPs, but it should be possible to add these in the future if needed.
--- include/net/inet_connection_sock.h | 4 ++ include/net/tcp.h | 25 +++++++ include/uapi/linux/tcp.h | 1 + net/ipv4/Makefile | 2 +- net/ipv4/sysctl_net_ipv4.c | 25 +++++++ net/ipv4/tcp.c | 28 ++++++++ net/ipv4/tcp_ipv4.c | 2 + net/ipv4/tcp_ulp.c | 134 +++++++++++++++++++++++++++++++++++++ 8 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 net/ipv4/tcp_ulp.c
include/net/inet_connection_sock.h +4 -0
@@ -75,6 +75,8 @@ struct inet_connection_sock_af_ops {* @icsk_pmtu_cookie Last pmtu seen by socket * @icsk_ca_ops Pluggable congestion control hook * @icsk_af_ops Operations which are AF_INET{4,6} specific +* @icsk_ulp_ops Pluggable ULP control hook +* @icsk_ulp_data ULP private data * @icsk_ca_state: Congestion control state * @icsk_retransmits: Number of unrecovered [RTO] timeouts * @icsk_pending: Scheduled timer event
@@ -97,6 +99,8 @@ struct inet_connection_sock {__u32 icsk_pmtu_cookie;const struct tcp_congestion_ops *icsk_ca_ops;const struct inet_connection_sock_af_ops *icsk_af_ops; +const struct tcp_ulp_ops *icsk_ulp_ops; +void *icsk_ulp_data;unsigned int (*icsk_sync_mss)(struct sock *sk,u32 pmtu); __u8 icsk_ca_state:6, icsk_ca_setsockopt:1,
include/net/tcp.h +25 -0
@@ -1992,4 +1992,29 @@ static inline void tcp_listendrop(const struct sock *sk)enum hrtimer_restart tcp_pace_kick (struct hrtimer *timer); +/* +* Interface for adding Upper Level Protocols over TCP +*/ + +#define TCP_ULP_NAME_MAX 16 +#define TCP_ULP_MAX 128 +#define TCP_ULP_BUF_MAX (TCP_ULP_NAME_MAX*TCP_ULP_MAX) + +struct tcp_ulp_ops { +struct list_head list; + +/* initialize ulp */ +int (*init)(struct sock *sk); +/* cleanup ulp */ +void (*release)(struct sock *sk); + +char name[TCP_ULP_NAME_MAX ]; +struct module *owner; +}; +int tcp_register_ulp (struct tcp_ulp_ops *type); +void tcp_unregister_ulp (struct tcp_ulp_ops *type); +int tcp_set_ulp (struct sock *sk,const char *name); +void tcp_get_available_ulp (char *buf,size_t len); +void tcp_cleanup_ulp (struct sock *sk); +#endif /* _TCP_H */
include/uapi/linux/tcp.h +1 -0
@@ -117,6 +117,7 @@ enum {#define TCP_SAVED_SYN 28/* Get SYN headers recorded for connection */ #define TCP_REPAIR_WINDOW 29/* Get/set window parameters */ #define TCP_FASTOPEN_CONNECT 30/* Attempt FastOpen with connect */ +#define TCP_ULP 31/* Attach a ULP to a TCP connection */ struct tcp_repair_opt {__u32 opt_code;
net/ipv4/Makefile +1 -1
@@ -8,7 +8,7 @@ obj-y := route.o inetpeer.o protocol.o \ inet_timewait_sock.o inet_connection_sock.o \ tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ tcp_minisocks.o tcp_cong.o tcp_metrics.o tcp_fastopen.o \ - tcp_rate.o tcp_recovery.o \ + tcp_rate.o tcp_recovery.o tcp_ulp.o \ tcp_offload.o datagram.o raw.o udp.o udplite.o \ udp_offload.o arp.o icmp.o devinet.o af_inet.o igmp.o \ fib_frontend.o fib_semantics.o fib_trie.o fib_notifier.o \
net/ipv4/sysctl_net_ipv4.c +25 -0
@@ -360,6 +360,25 @@ static int proc_tfo_blackhole_detect_timeout(struct ctl_table *table, ret =proc_dointvec_minmax (table, write, buffer, lenp, ppos);if (write && ret ==0 )tcp_fastopen_active_timeout_reset (); + +return ret; +} + +static int proc_tcp_available_ulp (struct ctl_table *ctl, +int write, +void __user *buffer,size_t *lenp, +loff_t *ppos) +{ +struct ctl_table tbl = { .maxlen =TCP_ULP_BUF_MAX , }; +int ret; + + tbl.data =kmalloc (tbl.maxlen,GFP_USER ); +if (!tbl.data) +return -ENOMEM ; +tcp_get_available_ulp (tbl.data,TCP_ULP_BUF_MAX ); + ret =proc_dostring (&tbl, write, buffer, lenp, ppos); +kfree (tbl.data); +return ret; }
@@ -707,6 +726,12 @@ static struct ctl_table ipv4_table[] = { .proc_handler = proc_dointvec_ms_jiffies, }, { + .procname = "tcp_available_ulp", + .maxlen = TCP_ULP_BUF_MAX, + .mode = 0444, + .proc_handler = proc_tcp_available_ulp, + }, + { .procname = "icmp_msgs_per_sec", .data = &sysctl_icmp_msgs_per_sec, .maxlen = sizeof(int),
net/ipv4/tcp.c +28 -0
@@ -2461,6 +2461,24 @@ static int do_tcp_setsockopt(struct sock *sk, int level,release_sock (sk);return err; } +case TCP_ULP : { +char name[TCP_ULP_NAME_MAX ]; + +if (optlen <1 ) +return -EINVAL ; + + val =strncpy_from_user (name, optval, +min_t (long,TCP_ULP_NAME_MAX -1 , + optlen)); +if (val <0 ) +return -EFAULT ; + name[val] =0 ; + +lock_sock (sk); + err =tcp_set_ulp (sk, name); +release_sock (sk); +return err; + }default :/* fallthru */ break ;
@@ -3017,6 +3035,16 @@ static int do_tcp_getsockopt(struct sock *sk, int level,return -EFAULT ;return 0 ; +case TCP_ULP : +if (get_user (len, optlen)) +return -EFAULT ; + len = min_t(unsigned int, len, TCP_ULP_NAME_MAX); +if (put_user (len, optlen)) +return -EFAULT ; +if (copy_to_user (optval, icsk->icsk_ulp_ops->name, len)) +return -EFAULT ; +return 0 ; +case TCP_THIN_LINEAR_TIMEOUTS : val = tp->thin_lto;break ;
net/ipv4/tcp_ipv4.c +2 -0
@@ -1860,6 +1860,8 @@ void tcp_v4_destroy_sock(struct sock *sk)tcp_cleanup_congestion_control (sk); +tcp_cleanup_ulp (sk); +/* Cleanup up the write buffer. */ tcp_write_queue_purge (sk);
net/ipv4/tcp_ulp.c new file +134 -0
134 lines not on this page · raw message
Signature · 1 line
2.9.3
PATCH v2 2/4 tcp: export do_tcp_sendpages and tcp_rate_check_app_limited functions
In reply to a message not in the archiveExport do_tcp_sendpages and tcp_rate_check_app_limited, since tls will need to sendpages while the socket is already locked.
tcp_sendpage is exported, but requires the socket lock to not be held already.
--- include/net/tcp.h | 2 ++ net/ipv4/tcp.c | 5 +++-- net/ipv4/tcp_rate.c | 1 + 3 files changed, 6 insertions(+), 2 deletions(-)
include/net/tcp.h +2 -0
@@ -353,6 +353,8 @@ int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);int tcp_sendmsg (struct sock *sk,struct msghdr *msg,size_t size);int tcp_sendpage (struct sock *sk,struct page *page,int offset,size_t size,int flags); +ssize_t do_tcp_sendpages (struct sock *sk,struct page *page,int offset, +size_t size,int flags);void tcp_release_cb (struct sock *sk);void tcp_wfree (struct sk_buff *skb);void tcp_write_timer_handler (struct sock *sk);
net/ipv4/tcp.c +3 -2
@@ -882,8 +882,8 @@ static int tcp_send_mss(struct sock *sk, int *size_goal, int flags)return mss_now; } -static ssize_t do_tcp_sendpages (struct sock *sk,struct page *page,int offset, -size_t size,int flags) +ssize_t do_tcp_sendpages (struct sock *sk,struct page *page,int offset, +size_t size,int flags) {struct tcp_sock *tp =tcp_sk (sk);int mss_now, size_goal;
@@ -1013,6 +1013,7 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset, }return sk_stream_error (sk, flags, err); } +EXPORT_SYMBOL_GPL (do_tcp_sendpages);int tcp_sendpage (struct sock *sk,struct page *page,int offset,size_t size,int flags)
net/ipv4/tcp_rate.c +1 -0
@@ -185,3 +185,4 @@ void tcp_rate_check_app_limited(struct sock *sk) tp->app_limited = (tp->delivered +tcp_packets_in_flight (tp)) ? :1 ; } +EXPORT_SYMBOL_GPL (tcp_rate_check_app_limited);
Signature · 1 line
2.9.3
PATCH v2 3/4 tls: kernel TLS support
In reply to a message not in the archiveSoftware implementation of transport layer security, implemented using ULP infrastructure. tcp proto_ops are replaced with tls equivalents of sendmsg and sendpage.
Only symmetric crypto is done in the kernel, keys are passed by setsockopt after the handshake is complete. All control messages are supported via CMSG data - the actual symmetric encryption is the same, just the message type needs to be passed separately.
For user API, please see Documentation patch.
Pieces that can be shared between hw and sw implementation are in tls_main.c
--- MAINTAINERS | 10 + include/linux/socket.h | 1 + include/net/tls.h | 222 +++++++++++++ include/uapi/linux/tls.h | 79 +++++ net/Kconfig | 1 + net/Makefile | 1 + net/tls/Kconfig | 12 + net/tls/Makefile | 7 + net/tls/tls_main.c | 485 +++++++++++++++++++++++++++++ net/tls/tls_sw.c | 794 +++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 1612 insertions(+) create mode 100644 include/net/tls.h create mode 100644 include/uapi/linux/tls.h create mode 100644 net/tls/Kconfig create mode 100644 net/tls/Makefile create mode 100644 net/tls/tls_main.c create mode 100644 net/tls/tls_sw.c
MAINTAINERS +10 -0
@@ -8973,6 +8973,16 @@ F: net/ipv6/ F: include/net/ip* F: arch/x86/net/* +NETWORKING [TLS] +M: Ilya Lesokhin <[email protected]> +M: Aviad Yehezkel <[email protected]> +M: Dave Watson <[email protected]> +L: [email protected] +S: Maintained +F: net/tls/* +F: include/uapi/linux/tls.h +F: include/net/tls.h + NETWORKING [IPSEC] M: Steffen Klassert <[email protected]> M: Herbert Xu <[email protected]>
include/linux/socket.h +1 -0
@@ -334,6 +334,7 @@ struct ucred {#define SOL_ALG 279#define SOL_NFC 280#define SOL_KCM 281 +#define SOL_TLS 282/* IPX options */ #define IPX_TYPE 1
include/net/tls.h new file +222 -0
222 lines not on this page · raw message
include/uapi/linux/tls.h new file +79 -0
79 lines not on this page · raw message
net/Kconfig +1 -0
@@ -55,6 +55,7 @@ menu "Networking options" source "net/packet/Kconfig" source "net/unix/Kconfig" +source "net/tls/Kconfig" source "net/xfrm/Kconfig" source "net/iucv/Kconfig" source "net/smc/Kconfig"
net/Makefile +1 -0
@@ -15,6 +15,7 @@ obj-$(CONFIG_LLC) += llc/ obj-$(CONFIG_NET) += ethernet/ 802/ sched/ netlink/ bpf/ obj-$(CONFIG_NETFILTER) += netfilter/ obj-$(CONFIG_INET) += ipv4/ +obj-$(CONFIG_TLS) += tls/ obj-$(CONFIG_XFRM) += xfrm/ obj-$(CONFIG_UNIX) += unix/ obj-$(CONFIG_NET) += ipv6/
net/tls/Kconfig new file +12 -0
@@ -0,0 +1,12 @@ +# +# TLS configuration +# +config TLS + tristate "Transport Layer Security support" + depends on NET + default m + ---help--- + Enable kernel support for TLS protocol. This allows symmetric + encryption handling of the TLS protocol to be done in-kernel. + + If unsure, say M.
net/tls/Makefile new file +7 -0
@@ -0,0 +1,7 @@ +# +# Makefile for the TLS subsystem. +# + +obj-$(CONFIG_TLS) += tls.o + +tls-y := tls_main.o tls_sw.o
net/tls/tls_main.c new file +485 -0
485 lines not on this page · raw message
net/tls/tls_sw.c new file +794 -0
794 lines not on this page · raw message
Signature · 1 line
2.9.3
PATCH v2 4/4 tls: Documentation
In reply to a message not in the archiveAdd documentation for the tcp ULP tls interface.
--- Documentation/networking/tls.txt | 135 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 Documentation/networking/tls.txt
Documentation/networking/tls.txt new file +135 -0
@@ -0,0 +1,135 @@ +Overview +======== + +Transport Layer Security (TLS) is a Upper Layer Protocol (ULP) that runs over +TCP. TLS provides end-to-end data integrity and confidentiality. + +User interface +============== + +Creating a TLS connection +------------------------- + +First create a new TCP socket and set the TLS ULP. + + sock = socket(AF_INET, SOCK_STREAM, 0); + setsockopt(sock, SOL_TCP, TCP_ULP, "tls", sizeof("tls")); + +Setting the TLS ULP allows us to set/get TLS socket options. Currently +only the symmetric encryption is handled in the kernel. After the TLS +handshake is complete, we have all the parameters required to move the +data-path to the kernel. There is a separate socket option for moving +the transmit and the receive into the kernel. + + /* From linux/tls.h */ + struct tls_crypto_info { + unsigned short version; + unsigned short cipher_type; + }; + + struct tls12_crypto_info_aes_gcm_128 { + struct tls_crypto_info info; + unsigned char iv[TLS_CIPHER_AES_GCM_128_IV_SIZE]; + unsigned char key[TLS_CIPHER_AES_GCM_128_KEY_SIZE]; + unsigned char salt[TLS_CIPHER_AES_GCM_128_SALT_SIZE]; + unsigned char rec_seq[TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE]; + }; + + + struct tls12_crypto_info_aes_gcm_128 crypto_info; + + crypto_info.info.version = TLS_1_2_VERSION; + crypto_info.info.cipher_type = TLS_CIPHER_AES_GCM_128; + memcpy(crypto_info.iv, iv_write, TLS_CIPHER_AES_GCM_128_IV_SIZE); + memcpy(crypto_info.rec_seq, seq_number_write, + TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE); + memcpy(crypto_info.key, cipher_key_write, TLS_CIPHER_AES_GCM_128_KEY_SIZE); + memcpy(crypto_info.salt, implicit_iv_write, TLS_CIPHER_AES_GCM_128_SALT_SIZE); + + setsockopt(sock, SOL_TLS, TLS_TX, &crypto_info, sizeof(crypto_info)); + +Sending TLS application data +---------------------------- + +After setting the TLS_TX socket option all application data sent over this +socket is encrypted using TLS and the parameters provided in the socket option. +For example, we can send an encrypted hello world record as follows: + + const char *msg = "hello world\n"; + send(sock, msg, strlen(msg)); + +send() data is directly encrypted from the userspace buffer provided +to the encrypted kernel send buffer if possible. + +The sendfile system call will send the file's data over TLS records of maximum +length (2^14). + + file = open(filename, O_RDONLY); + fstat(file, &stat); + sendfile(sock, file, &offset, stat.st_size); + +TLS records are created and sent after each send() call, unless +MSG_MORE is passed. MSG_MORE will delay creation of a record until +MSG_MORE is not passed, or the maximum record size is reached. + +The kernel will need to allocate a buffer for the encrypted data. +This buffer is allocated at the time send() is called, such that +either the entire send() call will return -ENOMEM (or block waiting +for memory), or the encryption will always succeed. If send() returns +-ENOMEM and some data was left on the socket buffer from a previous +call using MSG_MORE, the MSG_MORE data is left on the socket buffer. + +Send TLS control messages +------------------------- + +Other than application data, TLS has control messages such as alert +messages (record type 21) and handshake messages (record type 22), etc. +These messages can be sent over the socket by providing the TLS record type +via a CMSG. For example the following function sends @data of @length bytes +using a record of type @record_type. + +/* send TLS control message using record_type */ + static int klts_send_ctrl_message(int sock, unsigned char record_type, + void *data, size_t length) + { + struct msghdr msg = {0}; + int cmsg_len = sizeof(record_type); + struct cmsghdr *cmsg; + char buf[CMSG_SPACE(cmsg_len)]; + struct iovec msg_iov; /* Vector of data to send/receive into. */ + + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_TLS; + cmsg->cmsg_type = TLS_SET_RECORD_TYPE; + cmsg->cmsg_len = CMSG_LEN(cmsg_len); + *CMSG_DATA(cmsg) = record_type; + msg.msg_controllen = cmsg->cmsg_len; + + msg_iov.iov_base = data; + msg_iov.iov_len = length; + msg.msg_iov = &msg_iov; + msg.msg_iovlen = 1; + + return sendmsg(sock, &msg, 0); + } + +Control message data should be provided unencrypted, and will be +encrypted by the kernel. + +Integrating in to userspace TLS library +--------------------------------------- + +At a high level, the kernel TLS ULP is a replacement for the record +layer of a userspace TLS library. + +A patchset to OpenSSL to use ktls as the record layer is here: + +https://github.com/Mellanox/tls-openssl + +An example of calling send directly after a handshake using +gnutls. Since it doesn't implement a full record layer, control +messages are not supported: + +https://github.com/Mellanox/tls-af_ktls_tool
Signature · 1 line
2.9.3
David Miller
maintainerFrom: Dave Watson <[email protected]>
Date: Tue, 6 Jun 2017 10:00:20 -0700
Quoted 1 line
+EXPORT_SYMBOL(tcp_register_ulp);
EXPORT_SYMBOL_GPL() please.
Quoted 1 line
+EXPORT_SYMBOL(tcp_unregister_ulp);
Likewise.