From de04f6d6f5b136590b659e9a5bb165dbda0ef95b Mon Sep 17 00:00:00 2001 From: Alexander K Date: Mon, 25 Jun 2018 15:39:08 +0300 Subject: [PATCH 01/11] tcp_write_xmit() hook to create dynamically-sized TLS records --- include/linux/skbuff.h | 46 ++++++++++++++++++++++++++++++++++++++++++ include/net/sock.h | 4 ++++ include/net/tcp.h | 3 +++ include/net/tls.h | 6 ++++++ net/ipv4/tcp_output.c | 35 +++++++++++++++++++++++++++++++- 5 files changed, 93 insertions(+), 1 deletion(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index e6438bfa9..7f6363497 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -854,6 +854,52 @@ struct sk_buff { #define SKB_ALLOC_RX 0x02 #define SKB_ALLOC_NAPI 0x04 +#ifdef CONFIG_SECURITY_TEMPESTA +/** + * The skb mark are used only for time between @skb was inserted into TCP send + * queue and it's processed (first time) in tcp_write_xmit(). This time the @skb + * isn't scheduled yet, so we can use skb->dev for our needs to avoid extending + * sk_buff. We use the least significant bit to be sure that the this isn't a + * pointer to not to break anything. TLS message type << 1 is alwasy smaller + * than 0xff. + */ +static inline int +tempesta_tls_skb_settype(struct sk_buff *skb, unsigned char type) +{ + BUG_ON(type >= 0x80); + if (unlikely(skb->dev)) { + WARN_ON_ONCE(skb->dev); + return -EINVAL; + } + skb->dev = (void *)((type << 1) | 1UL); +} + +static inline unsigned char +tempesta_tls_skb_type(struct sk_buff *skb) +{ + unsigned long d = (unsigned long)skb->dev; + + if (unlikely(d ^ 1UL)) + return 0; + return d >> 1; +} + +static inline void +tempesta_tls_skb_typecp(struct sk_buff *dst, struct sk_buff *src) +{ + dst->dev = src->dev; +} + +static inline void +tempesta_tls_skb_clear(struct sk_buff *skb) +{ + unsigned long d = (unsigned long)skb->dev; + + WARN_ON_ONCE(d & ~0xff); + skb->dev = NULL; +} +#endif + /* Returns true if the skb was allocated from PFMEMALLOC reserves */ static inline bool skb_pfmemalloc(const struct sk_buff *skb) { diff --git a/include/net/sock.h b/include/net/sock.h index ece2126c0..b914e197d 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -471,6 +471,10 @@ struct sock { void (*sk_state_change)(struct sock *sk); void (*sk_data_ready)(struct sock *sk); void (*sk_write_space)(struct sock *sk); +#ifdef CONFIG_SECURITY_TEMPESTA + int (*sk_write_xmit)(struct sock *sk, + struct sk_buff *skb); +#endif void (*sk_error_report)(struct sock *sk); int (*sk_backlog_rcv)(struct sock *sk, struct sk_buff *skb); diff --git a/include/net/tcp.h b/include/net/tcp.h index b2a6ca581..0f6bd0cf2 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1719,6 +1719,9 @@ static inline void tcp_insert_write_queue_after(struct sk_buff *skb, struct sk_buff *buff, struct sock *sk) { +#ifdef CONFIG_SECURITY_TEMPESTA + tempesta_tls_skb_typecp(buff, skb); +#endif __skb_queue_after(&sk->sk_write_queue, skb, buff); } diff --git a/include/net/tls.h b/include/net/tls.h index df950383b..c3d45c5ea 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -55,6 +55,12 @@ #define TLS_AAD_SPACE_SIZE 13 +#ifdef CONFIG_SECURITY_TEMPESTA +#define TLS_MAX_TAG_SZ 16 +/* Maximum size for required skb overhead: header, IV, tag. */ +#define TLS_MAX_OVERHEAD (TLS_AAD_SPACE_SIZE + TLS_MAX_TAG_SZ) +#endif + struct tls_sw_context { struct crypto_aead *aead_send; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index c6e64e8f5..f9f393786 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -37,6 +37,9 @@ #define pr_fmt(fmt) "TCP: " fmt #include +#ifdef CONFIG_SECURITY_TEMPESTA +#include +#endif #include #include @@ -2324,6 +2327,20 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, } limit = mss_now; +#ifdef CONFIG_SECURITY_TEMPESTA + if (sk->sk_write_xmit && tempesta_tls_skb_type(skb)) { + if (unlikely(limit <= TLS_MAX_MSG_OVERHEAD)) { + net_warn_ratelimited("%s: too small MSS %u" + " for TLS\n", + __func__, mss_now); + break; + } + if (limit < TLS_MAX_PAYLOAD_SIZE) + limit -= TLS_MAX_MSG_OVERHEAD; + else + limit = TLS_MAX_PAYLOAD_SIZE; + } +#endif if (tso_segs > 1 && !tcp_urg_mode(tp)) limit = tcp_mss_split_point(sk, skb, mss_now, min_t(unsigned int, @@ -2339,7 +2356,23 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, clear_bit(TCP_TSQ_DEFERRED, &sk->sk_tsq_flags); if (tcp_small_queue_check(sk, skb, 0)) break; - +#ifdef CONFIG_SECURITY_TEMPESTA + /* + * This isn't the only place where tcp_transmit_skb() is called, + * but this is the only place were we are from Tempesta FW + * ss_do_send(), so call the hook here. At this point, with + * @limit adjusted above, we have exact understanding how much + * data we can and should send to the peer, so we call + * encryption here and get the best TLS record size. + * + * TODO Sometimes HTTP servers send headers and response body in + * different TCP segments, so coalese skbs for transmission to + * get 16KB (maximum size of TLS message). + */ + if (sk->sk_write_xmit && tempesta_tls_skb_type(skb)) + if (unlikely(sk->sk_write_xmit(sk, skb))) + break; +#endif if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp))) break; From 96455fdec885cbebd402a0530276a6f0b0b95514 Mon Sep 17 00:00:00 2001 From: Alexander K Date: Wed, 4 Jul 2018 15:22:27 +0300 Subject: [PATCH 02/11] Export pg_skb_alloc() for external allocation of the small page chunks --- include/linux/skbuff.h | 7 +++++++ net/core/skbuff.c | 13 +++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 7f6363497..f1c52db48 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -232,6 +232,12 @@ SKB_WITH_OVERHEAD((PAGE_SIZE << (ORDER)) - (X)) #define SKB_MAX_HEAD(X) (SKB_MAX_ORDER((X), 0)) #define SKB_MAX_ALLOC (SKB_MAX_ORDER(0, 2)) +#ifndef CONFIG_SECURITY_TEMPESTA +#define SKB_MAX_HEADER (PAGE_SIZE - MAX_TCP_HEADER \ + - SKB_DATA_ALIGN(sizeof(struct sk_buff)) \ + - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) \ + - SKB_DATA_ALIGN(1)) +#endif /* return minimum truesize of one skb containing X bytes of data */ #define SKB_TRUESIZE(X) ((X) + \ @@ -1018,6 +1024,7 @@ void kfree_skb_partial(struct sk_buff *skb, bool head_stolen); bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from, bool *fragstolen, int *delta_truesize); +void *pg_skb_alloc(unsigned int size, gfp_t gfp_mask, int node); struct sk_buff *__alloc_skb(unsigned int size, gfp_t priority, int flags, int node); struct sk_buff *__build_skb(void *data, unsigned int frag_size); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 4a8b1b165..85620d3ee 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -219,8 +219,8 @@ __pg_pool_shrink(TfwSkbMemPool *pool) return true; } -static void * -__pg_skb_alloc(unsigned int size, gfp_t gfp_mask, int node) +void * +pg_skb_alloc(unsigned int size, gfp_t gfp_mask, int node) { /* * Don't disable softirq if hardirqs are already disabled to avoid @@ -319,6 +319,7 @@ do { \ #undef PREEMPT_CTX_DISABLE #undef PREEMPT_CTX_ENABLE } +EXPORT_SYMBOL(pg_skg_alloc); #endif static void @@ -455,7 +456,7 @@ __alloc_skb(unsigned int size, gfp_t gfp_mask, int flags, int node) if (sk_memalloc_socks() && (flags & SKB_ALLOC_RX)) gfp_mask |= __GFP_MEMALLOC; - if (!(skb = __pg_skb_alloc(n, gfp_mask, node))) + if (!(skb = pg_skb_alloc(n, gfp_mask, node))) return NULL; data = (u8 *)skb + skb_sz; @@ -1706,7 +1707,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, if (skb_pfmemalloc(skb)) gfp_mask |= __GFP_MEMALLOC; #ifdef CONFIG_SECURITY_TEMPESTA - data = __pg_skb_alloc(size, gfp_mask, NUMA_NO_NODE); + data = pg_skb_alloc(size, gfp_mask, NUMA_NO_NODE); if (!data) goto nodata; size = SKB_WITH_OVERHEAD(PG_ALLOC_SZ(size)); @@ -5493,7 +5494,7 @@ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off, gfp_mask |= __GFP_MEMALLOC; #ifdef CONFIG_SECURITY_TEMPESTA size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - data = __pg_skb_alloc(size, gfp_mask, NUMA_NO_NODE); + data = pg_skb_alloc(size, gfp_mask, NUMA_NO_NODE); if (!data) return -ENOMEM; size = SKB_WITH_OVERHEAD(PG_ALLOC_SZ(size)); @@ -5632,7 +5633,7 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off, gfp_mask |= __GFP_MEMALLOC; #ifdef CONFIG_SECURITY_TEMPESTA size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - data = __pg_skb_alloc(size, gfp_mask, NUMA_NO_NODE); + data = pg_skb_alloc(size, gfp_mask, NUMA_NO_NODE); if (!data) return -ENOMEM; size = SKB_WITH_OVERHEAD(PG_ALLOC_SZ(size)); From de3870741ad673b2a9048859b89aef94b98ee0c0 Mon Sep 17 00:00:00 2001 From: Alexander K Date: Mon, 9 Jul 2018 14:36:00 +0300 Subject: [PATCH 03/11] Minor fixes --- include/linux/skbuff.h | 3 ++- net/core/skbuff.c | 2 +- net/ipv4/tcp_output.c | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index f1c52db48..30ca3af13 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -232,7 +232,7 @@ SKB_WITH_OVERHEAD((PAGE_SIZE << (ORDER)) - (X)) #define SKB_MAX_HEAD(X) (SKB_MAX_ORDER((X), 0)) #define SKB_MAX_ALLOC (SKB_MAX_ORDER(0, 2)) -#ifndef CONFIG_SECURITY_TEMPESTA +#ifdef CONFIG_SECURITY_TEMPESTA #define SKB_MAX_HEADER (PAGE_SIZE - MAX_TCP_HEADER \ - SKB_DATA_ALIGN(sizeof(struct sk_buff)) \ - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) \ @@ -878,6 +878,7 @@ tempesta_tls_skb_settype(struct sk_buff *skb, unsigned char type) return -EINVAL; } skb->dev = (void *)((type << 1) | 1UL); + return 0; } static inline unsigned char diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 85620d3ee..92e9a635d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -319,7 +319,7 @@ do { \ #undef PREEMPT_CTX_DISABLE #undef PREEMPT_CTX_ENABLE } -EXPORT_SYMBOL(pg_skg_alloc); +EXPORT_SYMBOL(pg_skb_alloc); #endif static void diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index f9f393786..3d6ced432 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2329,14 +2329,14 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, limit = mss_now; #ifdef CONFIG_SECURITY_TEMPESTA if (sk->sk_write_xmit && tempesta_tls_skb_type(skb)) { - if (unlikely(limit <= TLS_MAX_MSG_OVERHEAD)) { + if (unlikely(limit <= TLS_MAX_OVERHEAD)) { net_warn_ratelimited("%s: too small MSS %u" " for TLS\n", __func__, mss_now); break; } if (limit < TLS_MAX_PAYLOAD_SIZE) - limit -= TLS_MAX_MSG_OVERHEAD; + limit -= TLS_MAX_OVERHEAD; else limit = TLS_MAX_PAYLOAD_SIZE; } From a2e0ad91a967cb3eb5abe644f40cc4c2f9a3dd0a Mon Sep 17 00:00:00 2001 From: Alexander K Date: Wed, 11 Jul 2018 01:23:09 +0300 Subject: [PATCH 04/11] Call TLS encryption for min(cwnd,rwnd) --- include/net/sock.h | 3 ++- net/ipv4/tcp_output.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index b914e197d..4b990fe91 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -473,7 +473,8 @@ struct sock { void (*sk_write_space)(struct sock *sk); #ifdef CONFIG_SECURITY_TEMPESTA int (*sk_write_xmit)(struct sock *sk, - struct sk_buff *skb); + struct sk_buff *skb, + unsigned int limit); #endif void (*sk_error_report)(struct sock *sk); int (*sk_backlog_rcv)(struct sock *sk, diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 3d6ced432..0eecab7c7 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2327,6 +2327,12 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, } limit = mss_now; + if (tso_segs > 1 && !tcp_urg_mode(tp)) + limit = tcp_mss_split_point(sk, skb, mss_now, + min_t(unsigned int, + cwnd_quota, + max_segs), + nonagle); #ifdef CONFIG_SECURITY_TEMPESTA if (sk->sk_write_xmit && tempesta_tls_skb_type(skb)) { if (unlikely(limit <= TLS_MAX_OVERHEAD)) { @@ -2341,13 +2347,6 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, limit = TLS_MAX_PAYLOAD_SIZE; } #endif - if (tso_segs > 1 && !tcp_urg_mode(tp)) - limit = tcp_mss_split_point(sk, skb, mss_now, - min_t(unsigned int, - cwnd_quota, - max_segs), - nonagle); - if (skb->len > limit && unlikely(tso_fragment(sk, skb, limit, mss_now, gfp))) break; @@ -2370,9 +2369,10 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, * get 16KB (maximum size of TLS message). */ if (sk->sk_write_xmit && tempesta_tls_skb_type(skb)) - if (unlikely(sk->sk_write_xmit(sk, skb))) + if (unlikely(sk->sk_write_xmit(sk, skb, limit))) break; #endif + pr_err("AK_DBG %s: skb=%pK len=%u\n", __func__, skb, skb->len); if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp))) break; From 6bc35c81baa28cb7aa7cf29af7afc5e7b8848f41 Mon Sep 17 00:00:00 2001 From: Alexander K Date: Wed, 11 Jul 2018 01:25:09 +0300 Subject: [PATCH 05/11] Remove debugging message --- net/ipv4/tcp_output.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 0eecab7c7..01bd67d84 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2372,7 +2372,6 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, if (unlikely(sk->sk_write_xmit(sk, skb, limit))) break; #endif - pr_err("AK_DBG %s: skb=%pK len=%u\n", __func__, skb, skb->len); if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp))) break; From 2167d08bde49ea9504cbf9214c913fcb83c7968e Mon Sep 17 00:00:00 2001 From: Alexander K Date: Tue, 21 Aug 2018 00:23:49 +0300 Subject: [PATCH 06/11] Make irq_fpu_usable() return true for Tempesta softirqs so that SIMD crypto algorithms won't be called through cryptd. --- arch/x86/kernel/fpu/core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 532480a46..d27c08f48 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -86,6 +86,10 @@ static bool interrupted_user_mode(void) */ bool irq_fpu_usable(void) { +#ifdef CONFIG_SECURITY_TEMPESTA + if (likely(in_serving_softirq())) + return true; +#endif return !in_interrupt() || interrupted_user_mode() || interrupted_kernel_fpu_idle(); From 4494baedc65e2991baaa7384c47e1943e03b5b0a Mon Sep 17 00:00:00 2001 From: Alexander K Date: Fri, 30 Nov 2018 02:09:47 +0300 Subject: [PATCH 07/11] * Fix TLS skb type handling to call sk_write_xmit() callback. * Reserve room for TLS header in skb headroom. * Reset TCP connection if we can not encrypt data on it instead of retransmit it in plaintext. This leads to warning similar to #984 - leave as TODO for now. --- include/linux/netdevice.h | 15 +++++++++++++-- include/linux/skbuff.h | 17 +++++++---------- net/ipv4/tcp_output.c | 11 ++++++++++- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 46bf7cc7d..b698c645b 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -148,11 +148,22 @@ static inline bool dev_xmit_complete(int rc) # define LL_MAX_HEADER 32 #endif +#ifdef CONFIG_SECURITY_TEMPESTA +/* + * For Tempesta case the most traffic is TLS encrypted, so we need the extra + * room for TLS record header and explicit IV on skb allocation to avoid data + * movement on tcp_write_xmit(). Not all skbs have TLS headers - not a big deal + * to allocate 16 more bytes (5 - TLS header, 8 - IV, 3 - alignment). + */ +#define TLS_MAX_HDR 16 +#else +#define TLS_MAX_HDR 0 +#endif #if !IS_ENABLED(CONFIG_NET_IPIP) && !IS_ENABLED(CONFIG_NET_IPGRE) && \ !IS_ENABLED(CONFIG_IPV6_SIT) && !IS_ENABLED(CONFIG_IPV6_TUNNEL) -#define MAX_HEADER LL_MAX_HEADER +#define MAX_HEADER (LL_MAX_HEADER + TLS_MAX_HDR) #else -#define MAX_HEADER (LL_MAX_HEADER + 48) +#define MAX_HEADER (LL_MAX_HEADER + 48 + TLS_MAX_HDR) #endif /* diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 30ca3af13..15e9d2938 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -862,23 +862,20 @@ struct sk_buff { #ifdef CONFIG_SECURITY_TEMPESTA /** - * The skb mark are used only for time between @skb was inserted into TCP send + * The skb type is used only for time between @skb was inserted into TCP send * queue and it's processed (first time) in tcp_write_xmit(). This time the @skb * isn't scheduled yet, so we can use skb->dev for our needs to avoid extending - * sk_buff. We use the least significant bit to be sure that the this isn't a + * sk_buff. We use the least significant bit to be sure that this isn't a * pointer to not to break anything. TLS message type << 1 is alwasy smaller * than 0xff. */ -static inline int +static inline void tempesta_tls_skb_settype(struct sk_buff *skb, unsigned char type) { BUG_ON(type >= 0x80); - if (unlikely(skb->dev)) { - WARN_ON_ONCE(skb->dev); - return -EINVAL; - } + WARN_ON_ONCE(skb->dev); + skb->dev = (void *)((type << 1) | 1UL); - return 0; } static inline unsigned char @@ -886,8 +883,8 @@ tempesta_tls_skb_type(struct sk_buff *skb) { unsigned long d = (unsigned long)skb->dev; - if (unlikely(d ^ 1UL)) - return 0; + if (!(d & 1UL)) + return 0; /* a pointer in skb->dev */ return d >> 1; } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 01bd67d84..60da7ef47 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2369,8 +2369,17 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, * get 16KB (maximum size of TLS message). */ if (sk->sk_write_xmit && tempesta_tls_skb_type(skb)) - if (unlikely(sk->sk_write_xmit(sk, skb, limit))) + if (unlikely(sk->sk_write_xmit(sk, skb, limit))) { + net_warn_ratelimited( + "Tempesta: cannot encrypt data," + " so reset a TLS connection.\n"); + /* + * FIXME #984 WARNING: at net/core/stream.c:205 + * sk_stream_kill_queues+0x106/0x120 + */ + tcp_reset(sk); break; + } #endif if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp))) break; From 873ea4df516acd149f79cc75a462442bf30c374d Mon Sep 17 00:00:00 2001 From: Alexander K Date: Tue, 11 Dec 2018 03:30:56 +0300 Subject: [PATCH 08/11] Use atomic allocations for crypto context allocations --- crypto/api.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crypto/api.c b/crypto/api.c index 941cd4c6c..5fd308d8e 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -451,7 +451,11 @@ void *crypto_create_tfm(struct crypto_alg *alg, tfmsize = frontend->tfmsize; total = tfmsize + sizeof(*tfm) + frontend->extsize(alg); +#ifdef CONFIG_SECURITY_TEMPESTA + mem = kzalloc(total, GFP_ATOMIC); +#else mem = kzalloc(total, GFP_KERNEL); +#endif if (mem == NULL) goto out_err; From 3aa88fc4dbbdeab2a2651567db105dd850e936a3 Mon Sep 17 00:00:00 2001 From: Alexander K Date: Fri, 21 Dec 2018 04:13:17 +0300 Subject: [PATCH 09/11] Accurately calculate TLS record overhead and and merge it with TCP current transmission limit. --- include/net/tls.h | 3 ++- net/ipv4/tcp_output.c | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/net/tls.h b/include/net/tls.h index c3d45c5ea..4a99f03df 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -58,7 +58,8 @@ #ifdef CONFIG_SECURITY_TEMPESTA #define TLS_MAX_TAG_SZ 16 /* Maximum size for required skb overhead: header, IV, tag. */ -#define TLS_MAX_OVERHEAD (TLS_AAD_SPACE_SIZE + TLS_MAX_TAG_SZ) +#define TLS_MAX_OVERHEAD (TLS_HEADER_SIZE + TLS_AAD_SPACE_SIZE \ + + TLS_MAX_TAG_SZ) #endif struct tls_sw_context { diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 60da7ef47..88dd7b54c 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2341,10 +2341,10 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, __func__, mss_now); break; } - if (limit < TLS_MAX_PAYLOAD_SIZE) - limit -= TLS_MAX_OVERHEAD; - else + if (limit > TLS_MAX_PAYLOAD_SIZE + TLS_MAX_OVERHEAD) limit = TLS_MAX_PAYLOAD_SIZE; + else + limit -= TLS_MAX_OVERHEAD; } #endif if (skb->len > limit && From a403e62e87fef1055946a88beb29b2b1fa66dc18 Mon Sep 17 00:00:00 2001 From: Alexander K Date: Tue, 25 Dec 2018 05:44:39 +0300 Subject: [PATCH 10/11] Print error code on sk_write_xmit() fail --- net/ipv4/tcp_output.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 88dd7b54c..c1f604a56 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2368,11 +2368,12 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, * different TCP segments, so coalese skbs for transmission to * get 16KB (maximum size of TLS message). */ - if (sk->sk_write_xmit && tempesta_tls_skb_type(skb)) - if (unlikely(sk->sk_write_xmit(sk, skb, limit))) { + if (sk->sk_write_xmit && tempesta_tls_skb_type(skb)) { + result = sk->sk_write_xmit(sk, skb, limit); + if (unlikely(result)) { net_warn_ratelimited( - "Tempesta: cannot encrypt data," - " so reset a TLS connection.\n"); + "Tempesta: cannot encrypt data (%d)," + " reset a TLS connection.\n", result); /* * FIXME #984 WARNING: at net/core/stream.c:205 * sk_stream_kill_queues+0x106/0x120 @@ -2380,6 +2381,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, tcp_reset(sk); break; } + } #endif if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp))) break; From edc175573dd651b4ffc985a2dd738c78a4751d16 Mon Sep 17 00:00:00 2001 From: Alexander K Date: Sun, 30 Dec 2018 17:12:19 +0300 Subject: [PATCH 11/11] Fix couple misspels (code review) --- include/linux/skbuff.h | 2 +- net/ipv4/tcp_output.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 15e9d2938..0d90fcf05 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -866,7 +866,7 @@ struct sk_buff { * queue and it's processed (first time) in tcp_write_xmit(). This time the @skb * isn't scheduled yet, so we can use skb->dev for our needs to avoid extending * sk_buff. We use the least significant bit to be sure that this isn't a - * pointer to not to break anything. TLS message type << 1 is alwasy smaller + * pointer to not to break anything. TLS message type << 1 is always smaller * than 0xff. */ static inline void diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index c1f604a56..4e79cb5ef 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2358,14 +2358,14 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, #ifdef CONFIG_SECURITY_TEMPESTA /* * This isn't the only place where tcp_transmit_skb() is called, - * but this is the only place were we are from Tempesta FW + * but this is the only place where we are from Tempesta FW * ss_do_send(), so call the hook here. At this point, with * @limit adjusted above, we have exact understanding how much * data we can and should send to the peer, so we call * encryption here and get the best TLS record size. * * TODO Sometimes HTTP servers send headers and response body in - * different TCP segments, so coalese skbs for transmission to + * different TCP segments, so coalesce skbs for transmission to * get 16KB (maximum size of TLS message). */ if (sk->sk_write_xmit && tempesta_tls_skb_type(skb)) {