forked from mirrors/linux
		
	tls: convert to generic sk_msg interface
Convert kTLS over to make use of sk_msg interface for plaintext and encrypted scattergather data, so it reuses all the sk_msg helpers and data structure which later on in a second step enables to glue this to BPF. This also allows to remove quite a bit of open coded helpers which are covered by the sk_msg API. Recent changes in kTLs80ece6a03a("tls: Remove redundant vars from tls record structure") and4e6d47206c("tls: Add support for inplace records encryption") changed the data path handling a bit; while we've kept the latter optimization intact, we had to undo the former change to better fit the sk_msg model, hence the sg_aead_in and sg_aead_out have been brought back and are linked into the sk_msg sgs. Now the kTLS record contains a msg_plaintext and msg_encrypted sk_msg each. In the original code, the zerocopy_from_iter() has been used out of TX but also RX path. For the strparser skb-based RX path, we've left the zerocopy_from_iter() in decrypt_internal() mostly untouched, meaning it has been moved into tls_setup_from_iter() with charging logic removed (as not used from RX). Given RX path is not based on sk_msg objects, we haven't pursued setting up a dummy sk_msg to call into sk_msg_zerocopy_from_iter(), but it could be an option to prusue in a later step. Joint work with John. Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: John Fastabend <john.fastabend@gmail.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
		
							parent
							
								
									604326b41a
								
							
						
					
					
						commit
						d829e9c411
					
				
					 8 changed files with 236 additions and 402 deletions
				
			
		|  | @ -102,6 +102,8 @@ struct sk_psock { | ||||||
| 
 | 
 | ||||||
| int sk_msg_alloc(struct sock *sk, struct sk_msg *msg, int len, | int sk_msg_alloc(struct sock *sk, struct sk_msg *msg, int len, | ||||||
| 		 int elem_first_coalesce); | 		 int elem_first_coalesce); | ||||||
|  | int sk_msg_clone(struct sock *sk, struct sk_msg *dst, struct sk_msg *src, | ||||||
|  | 		 u32 off, u32 len); | ||||||
| void sk_msg_trim(struct sock *sk, struct sk_msg *msg, int len); | void sk_msg_trim(struct sock *sk, struct sk_msg *msg, int len); | ||||||
| int sk_msg_free(struct sock *sk, struct sk_msg *msg); | int sk_msg_free(struct sock *sk, struct sk_msg *msg); | ||||||
| int sk_msg_free_nocharge(struct sock *sk, struct sk_msg *msg); | int sk_msg_free_nocharge(struct sock *sk, struct sk_msg *msg); | ||||||
|  |  | ||||||
|  | @ -2214,10 +2214,6 @@ static inline struct page_frag *sk_page_frag(struct sock *sk) | ||||||
| 
 | 
 | ||||||
| bool sk_page_frag_refill(struct sock *sk, struct page_frag *pfrag); | bool sk_page_frag_refill(struct sock *sk, struct page_frag *pfrag); | ||||||
| 
 | 
 | ||||||
| int sk_alloc_sg(struct sock *sk, int len, struct scatterlist *sg, |  | ||||||
| 		int sg_start, int *sg_curr, unsigned int *sg_size, |  | ||||||
| 		int first_coalesce); |  | ||||||
| 
 |  | ||||||
| /*
 | /*
 | ||||||
|  *	Default write policy as shown to user space via poll/select/SIGIO |  *	Default write policy as shown to user space via poll/select/SIGIO | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | @ -39,6 +39,8 @@ | ||||||
| #include <linux/crypto.h> | #include <linux/crypto.h> | ||||||
| #include <linux/socket.h> | #include <linux/socket.h> | ||||||
| #include <linux/tcp.h> | #include <linux/tcp.h> | ||||||
|  | #include <linux/skmsg.h> | ||||||
|  | 
 | ||||||
| #include <net/tcp.h> | #include <net/tcp.h> | ||||||
| #include <net/strparser.h> | #include <net/strparser.h> | ||||||
| #include <crypto/aead.h> | #include <crypto/aead.h> | ||||||
|  | @ -103,15 +105,13 @@ struct tls_rec { | ||||||
| 	int tx_flags; | 	int tx_flags; | ||||||
| 	int inplace_crypto; | 	int inplace_crypto; | ||||||
| 
 | 
 | ||||||
| 	/* AAD | sg_plaintext_data | sg_tag */ | 	struct sk_msg msg_plaintext; | ||||||
| 	struct scatterlist sg_plaintext_data[MAX_SKB_FRAGS + 1]; | 	struct sk_msg msg_encrypted; | ||||||
| 	/* AAD | sg_encrypted_data (data contain overhead for hdr&iv&tag) */ |  | ||||||
| 	struct scatterlist sg_encrypted_data[MAX_SKB_FRAGS + 1]; |  | ||||||
| 
 | 
 | ||||||
| 	unsigned int sg_plaintext_size; | 	/* AAD | msg_plaintext.sg.data | sg_tag */ | ||||||
| 	unsigned int sg_encrypted_size; | 	struct scatterlist sg_aead_in[2]; | ||||||
| 	int sg_plaintext_num_elem; | 	/* AAD | msg_encrypted.sg.data (data contains overhead for hdr & iv & tag) */ | ||||||
| 	int sg_encrypted_num_elem; | 	struct scatterlist sg_aead_out[2]; | ||||||
| 
 | 
 | ||||||
| 	char aad_space[TLS_AAD_SPACE_SIZE]; | 	char aad_space[TLS_AAD_SPACE_SIZE]; | ||||||
| 	struct aead_request aead_req; | 	struct aead_request aead_req; | ||||||
|  | @ -223,8 +223,8 @@ struct tls_context { | ||||||
| 
 | 
 | ||||||
| 	unsigned long flags; | 	unsigned long flags; | ||||||
| 	bool in_tcp_sendpages; | 	bool in_tcp_sendpages; | ||||||
|  | 	bool pending_open_record_frags; | ||||||
| 
 | 
 | ||||||
| 	u16 pending_open_record_frags; |  | ||||||
| 	int (*push_pending_record)(struct sock *sk, int flags); | 	int (*push_pending_record)(struct sock *sk, int flags); | ||||||
| 
 | 
 | ||||||
| 	void (*sk_write_space)(struct sock *sk); | 	void (*sk_write_space)(struct sock *sk); | ||||||
|  |  | ||||||
|  | @ -73,6 +73,45 @@ int sk_msg_alloc(struct sock *sk, struct sk_msg *msg, int len, | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(sk_msg_alloc); | EXPORT_SYMBOL_GPL(sk_msg_alloc); | ||||||
| 
 | 
 | ||||||
|  | int sk_msg_clone(struct sock *sk, struct sk_msg *dst, struct sk_msg *src, | ||||||
|  | 		 u32 off, u32 len) | ||||||
|  | { | ||||||
|  | 	int i = src->sg.start; | ||||||
|  | 	struct scatterlist *sge = sk_msg_elem(src, i); | ||||||
|  | 	u32 sge_len, sge_off; | ||||||
|  | 
 | ||||||
|  | 	if (sk_msg_full(dst)) | ||||||
|  | 		return -ENOSPC; | ||||||
|  | 
 | ||||||
|  | 	while (off) { | ||||||
|  | 		if (sge->length > off) | ||||||
|  | 			break; | ||||||
|  | 		off -= sge->length; | ||||||
|  | 		sk_msg_iter_var_next(i); | ||||||
|  | 		if (i == src->sg.end && off) | ||||||
|  | 			return -ENOSPC; | ||||||
|  | 		sge = sk_msg_elem(src, i); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	while (len) { | ||||||
|  | 		sge_len = sge->length - off; | ||||||
|  | 		sge_off = sge->offset + off; | ||||||
|  | 		if (sge_len > len) | ||||||
|  | 			sge_len = len; | ||||||
|  | 		off = 0; | ||||||
|  | 		len -= sge_len; | ||||||
|  | 		sk_msg_page_add(dst, sg_page(sge), sge_len, sge_off); | ||||||
|  | 		sk_mem_charge(sk, sge_len); | ||||||
|  | 		sk_msg_iter_var_next(i); | ||||||
|  | 		if (i == src->sg.end && len) | ||||||
|  | 			return -ENOSPC; | ||||||
|  | 		sge = sk_msg_elem(src, i); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(sk_msg_clone); | ||||||
|  | 
 | ||||||
| void sk_msg_return_zero(struct sock *sk, struct sk_msg *msg, int bytes) | void sk_msg_return_zero(struct sock *sk, struct sk_msg *msg, int bytes) | ||||||
| { | { | ||||||
| 	int i = msg->sg.start; | 	int i = msg->sg.start; | ||||||
|  |  | ||||||
|  | @ -2238,67 +2238,6 @@ bool sk_page_frag_refill(struct sock *sk, struct page_frag *pfrag) | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(sk_page_frag_refill); | EXPORT_SYMBOL(sk_page_frag_refill); | ||||||
| 
 | 
 | ||||||
| int sk_alloc_sg(struct sock *sk, int len, struct scatterlist *sg, |  | ||||||
| 		int sg_start, int *sg_curr_index, unsigned int *sg_curr_size, |  | ||||||
| 		int first_coalesce) |  | ||||||
| { |  | ||||||
| 	int sg_curr = *sg_curr_index, use = 0, rc = 0; |  | ||||||
| 	unsigned int size = *sg_curr_size; |  | ||||||
| 	struct page_frag *pfrag; |  | ||||||
| 	struct scatterlist *sge; |  | ||||||
| 
 |  | ||||||
| 	len -= size; |  | ||||||
| 	pfrag = sk_page_frag(sk); |  | ||||||
| 
 |  | ||||||
| 	while (len > 0) { |  | ||||||
| 		unsigned int orig_offset; |  | ||||||
| 
 |  | ||||||
| 		if (!sk_page_frag_refill(sk, pfrag)) { |  | ||||||
| 			rc = -ENOMEM; |  | ||||||
| 			goto out; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		use = min_t(int, len, pfrag->size - pfrag->offset); |  | ||||||
| 
 |  | ||||||
| 		if (!sk_wmem_schedule(sk, use)) { |  | ||||||
| 			rc = -ENOMEM; |  | ||||||
| 			goto out; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		sk_mem_charge(sk, use); |  | ||||||
| 		size += use; |  | ||||||
| 		orig_offset = pfrag->offset; |  | ||||||
| 		pfrag->offset += use; |  | ||||||
| 
 |  | ||||||
| 		sge = sg + sg_curr - 1; |  | ||||||
| 		if (sg_curr > first_coalesce && sg_page(sge) == pfrag->page && |  | ||||||
| 		    sge->offset + sge->length == orig_offset) { |  | ||||||
| 			sge->length += use; |  | ||||||
| 		} else { |  | ||||||
| 			sge = sg + sg_curr; |  | ||||||
| 			sg_unmark_end(sge); |  | ||||||
| 			sg_set_page(sge, pfrag->page, use, orig_offset); |  | ||||||
| 			get_page(pfrag->page); |  | ||||||
| 			sg_curr++; |  | ||||||
| 
 |  | ||||||
| 			if (sg_curr == MAX_SKB_FRAGS) |  | ||||||
| 				sg_curr = 0; |  | ||||||
| 
 |  | ||||||
| 			if (sg_curr == sg_start) { |  | ||||||
| 				rc = -ENOSPC; |  | ||||||
| 				break; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		len -= use; |  | ||||||
| 	} |  | ||||||
| out: |  | ||||||
| 	*sg_curr_size = size; |  | ||||||
| 	*sg_curr_index = sg_curr; |  | ||||||
| 	return rc; |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL(sk_alloc_sg); |  | ||||||
| 
 |  | ||||||
| static void __lock_sock(struct sock *sk) | static void __lock_sock(struct sock *sk) | ||||||
| 	__releases(&sk->sk_lock.slock) | 	__releases(&sk->sk_lock.slock) | ||||||
| 	__acquires(&sk->sk_lock.slock) | 	__acquires(&sk->sk_lock.slock) | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ config TLS | ||||||
| 	select CRYPTO_AES | 	select CRYPTO_AES | ||||||
| 	select CRYPTO_GCM | 	select CRYPTO_GCM | ||||||
| 	select STREAM_PARSER | 	select STREAM_PARSER | ||||||
|  | 	select NET_SOCK_MSG | ||||||
| 	default n | 	default n | ||||||
| 	---help--- | 	---help--- | ||||||
| 	Enable kernel support for TLS protocol. This allows symmetric | 	Enable kernel support for TLS protocol. This allows symmetric | ||||||
|  |  | ||||||
|  | @ -421,7 +421,7 @@ static int tls_push_data(struct sock *sk, | ||||||
| 			tls_push_record_flags = flags; | 			tls_push_record_flags = flags; | ||||||
| 			if (more) { | 			if (more) { | ||||||
| 				tls_ctx->pending_open_record_frags = | 				tls_ctx->pending_open_record_frags = | ||||||
| 						record->num_frags; | 						!!record->num_frags; | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										511
									
								
								net/tls/tls_sw.c
									
									
									
									
									
								
							
							
						
						
									
										511
									
								
								net/tls/tls_sw.c
									
									
									
									
									
								
							|  | @ -213,153 +213,49 @@ static int tls_do_decryption(struct sock *sk, | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void trim_sg(struct sock *sk, struct scatterlist *sg, | static void tls_trim_both_msgs(struct sock *sk, int target_size) | ||||||
| 		    int *sg_num_elem, unsigned int *sg_size, int target_size) |  | ||||||
| { |  | ||||||
| 	int i = *sg_num_elem - 1; |  | ||||||
| 	int trim = *sg_size - target_size; |  | ||||||
| 
 |  | ||||||
| 	if (trim <= 0) { |  | ||||||
| 		WARN_ON(trim < 0); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	*sg_size = target_size; |  | ||||||
| 	while (trim >= sg[i].length) { |  | ||||||
| 		trim -= sg[i].length; |  | ||||||
| 		sk_mem_uncharge(sk, sg[i].length); |  | ||||||
| 		put_page(sg_page(&sg[i])); |  | ||||||
| 		i--; |  | ||||||
| 
 |  | ||||||
| 		if (i < 0) |  | ||||||
| 			goto out; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	sg[i].length -= trim; |  | ||||||
| 	sk_mem_uncharge(sk, trim); |  | ||||||
| 
 |  | ||||||
| out: |  | ||||||
| 	*sg_num_elem = i + 1; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void trim_both_sgl(struct sock *sk, int target_size) |  | ||||||
| { | { | ||||||
| 	struct tls_context *tls_ctx = tls_get_ctx(sk); | 	struct tls_context *tls_ctx = tls_get_ctx(sk); | ||||||
| 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); | 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); | ||||||
| 	struct tls_rec *rec = ctx->open_rec; | 	struct tls_rec *rec = ctx->open_rec; | ||||||
| 
 | 
 | ||||||
| 	trim_sg(sk, &rec->sg_plaintext_data[1], | 	sk_msg_trim(sk, &rec->msg_plaintext, target_size); | ||||||
| 		&rec->sg_plaintext_num_elem, |  | ||||||
| 		&rec->sg_plaintext_size, |  | ||||||
| 		target_size); |  | ||||||
| 
 |  | ||||||
| 	if (target_size > 0) | 	if (target_size > 0) | ||||||
| 		target_size += tls_ctx->tx.overhead_size; | 		target_size += tls_ctx->tx.overhead_size; | ||||||
| 
 | 	sk_msg_trim(sk, &rec->msg_encrypted, target_size); | ||||||
| 	trim_sg(sk, &rec->sg_encrypted_data[1], |  | ||||||
| 		&rec->sg_encrypted_num_elem, |  | ||||||
| 		&rec->sg_encrypted_size, |  | ||||||
| 		target_size); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int alloc_encrypted_sg(struct sock *sk, int len) | static int tls_alloc_encrypted_msg(struct sock *sk, int len) | ||||||
| { | { | ||||||
| 	struct tls_context *tls_ctx = tls_get_ctx(sk); | 	struct tls_context *tls_ctx = tls_get_ctx(sk); | ||||||
| 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); | 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); | ||||||
| 	struct tls_rec *rec = ctx->open_rec; | 	struct tls_rec *rec = ctx->open_rec; | ||||||
| 	int rc = 0; | 	struct sk_msg *msg_en = &rec->msg_encrypted; | ||||||
| 
 | 
 | ||||||
| 	rc = sk_alloc_sg(sk, len, | 	return sk_msg_alloc(sk, msg_en, len, 0); | ||||||
| 			 &rec->sg_encrypted_data[1], 0, |  | ||||||
| 			 &rec->sg_encrypted_num_elem, |  | ||||||
| 			 &rec->sg_encrypted_size, 0); |  | ||||||
| 
 |  | ||||||
| 	if (rc == -ENOSPC) |  | ||||||
| 		rec->sg_encrypted_num_elem = |  | ||||||
| 			ARRAY_SIZE(rec->sg_encrypted_data) - 1; |  | ||||||
| 
 |  | ||||||
| 	return rc; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int move_to_plaintext_sg(struct sock *sk, int required_size) | static int tls_clone_plaintext_msg(struct sock *sk, int required) | ||||||
| { | { | ||||||
| 	struct tls_context *tls_ctx = tls_get_ctx(sk); | 	struct tls_context *tls_ctx = tls_get_ctx(sk); | ||||||
| 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); | 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); | ||||||
| 	struct tls_rec *rec = ctx->open_rec; | 	struct tls_rec *rec = ctx->open_rec; | ||||||
| 	struct scatterlist *plain_sg = &rec->sg_plaintext_data[1]; | 	struct sk_msg *msg_pl = &rec->msg_plaintext; | ||||||
| 	struct scatterlist *enc_sg = &rec->sg_encrypted_data[1]; | 	struct sk_msg *msg_en = &rec->msg_encrypted; | ||||||
| 	int enc_sg_idx = 0; |  | ||||||
| 	int skip, len; | 	int skip, len; | ||||||
| 
 | 
 | ||||||
| 	if (rec->sg_plaintext_num_elem == MAX_SKB_FRAGS) | 	/* We add page references worth len bytes from encrypted sg
 | ||||||
| 		return -ENOSPC; | 	 * at the end of plaintext sg. It is guaranteed that msg_en | ||||||
| 
 |  | ||||||
| 	/* We add page references worth len bytes from enc_sg at the
 |  | ||||||
| 	 * end of plain_sg. It is guaranteed that sg_encrypted_data |  | ||||||
| 	 * has enough required room (ensured by caller). | 	 * has enough required room (ensured by caller). | ||||||
| 	 */ | 	 */ | ||||||
| 	len = required_size - rec->sg_plaintext_size; | 	len = required - msg_pl->sg.size; | ||||||
| 
 | 
 | ||||||
| 	/* Skip initial bytes in sg_encrypted_data to be able
 | 	/* Skip initial bytes in msg_en's data to be able to use
 | ||||||
| 	 * to use same offset of both plain and encrypted data. | 	 * same offset of both plain and encrypted data. | ||||||
| 	 */ | 	 */ | ||||||
| 	skip = tls_ctx->tx.prepend_size + rec->sg_plaintext_size; | 	skip = tls_ctx->tx.prepend_size + msg_pl->sg.size; | ||||||
| 
 | 
 | ||||||
| 	while (enc_sg_idx < rec->sg_encrypted_num_elem) { | 	return sk_msg_clone(sk, msg_pl, msg_en, skip, len); | ||||||
| 		if (enc_sg[enc_sg_idx].length > skip) |  | ||||||
| 			break; |  | ||||||
| 
 |  | ||||||
| 		skip -= enc_sg[enc_sg_idx].length; |  | ||||||
| 		enc_sg_idx++; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* unmark the end of plain_sg*/ |  | ||||||
| 	sg_unmark_end(plain_sg + rec->sg_plaintext_num_elem - 1); |  | ||||||
| 
 |  | ||||||
| 	while (len) { |  | ||||||
| 		struct page *page = sg_page(&enc_sg[enc_sg_idx]); |  | ||||||
| 		int bytes = enc_sg[enc_sg_idx].length - skip; |  | ||||||
| 		int offset = enc_sg[enc_sg_idx].offset + skip; |  | ||||||
| 
 |  | ||||||
| 		if (bytes > len) |  | ||||||
| 			bytes = len; |  | ||||||
| 		else |  | ||||||
| 			enc_sg_idx++; |  | ||||||
| 
 |  | ||||||
| 		/* Skipping is required only one time */ |  | ||||||
| 		skip = 0; |  | ||||||
| 
 |  | ||||||
| 		/* Increment page reference */ |  | ||||||
| 		get_page(page); |  | ||||||
| 
 |  | ||||||
| 		sg_set_page(&plain_sg[rec->sg_plaintext_num_elem], page, |  | ||||||
| 			    bytes, offset); |  | ||||||
| 
 |  | ||||||
| 		sk_mem_charge(sk, bytes); |  | ||||||
| 
 |  | ||||||
| 		len -= bytes; |  | ||||||
| 		rec->sg_plaintext_size += bytes; |  | ||||||
| 
 |  | ||||||
| 		rec->sg_plaintext_num_elem++; |  | ||||||
| 
 |  | ||||||
| 		if (rec->sg_plaintext_num_elem == MAX_SKB_FRAGS) |  | ||||||
| 			return -ENOSPC; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void free_sg(struct sock *sk, struct scatterlist *sg, |  | ||||||
| 		    int *sg_num_elem, unsigned int *sg_size) |  | ||||||
| { |  | ||||||
| 	int i, n = *sg_num_elem; |  | ||||||
| 
 |  | ||||||
| 	for (i = 0; i < n; ++i) { |  | ||||||
| 		sk_mem_uncharge(sk, sg[i].length); |  | ||||||
| 		put_page(sg_page(&sg[i])); |  | ||||||
| 	} |  | ||||||
| 	*sg_num_elem = 0; |  | ||||||
| 	*sg_size = 0; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void tls_free_open_rec(struct sock *sk) | static void tls_free_open_rec(struct sock *sk) | ||||||
|  | @ -372,14 +268,8 @@ static void tls_free_open_rec(struct sock *sk) | ||||||
| 	if (!rec) | 	if (!rec) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
| 	free_sg(sk, &rec->sg_encrypted_data[1], | 	sk_msg_free(sk, &rec->msg_encrypted); | ||||||
| 		&rec->sg_encrypted_num_elem, | 	sk_msg_free(sk, &rec->msg_plaintext); | ||||||
| 		&rec->sg_encrypted_size); |  | ||||||
| 
 |  | ||||||
| 	free_sg(sk, &rec->sg_plaintext_data[1], |  | ||||||
| 		&rec->sg_plaintext_num_elem, |  | ||||||
| 		&rec->sg_plaintext_size); |  | ||||||
| 
 |  | ||||||
| 	kfree(rec); | 	kfree(rec); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -388,6 +278,7 @@ int tls_tx_records(struct sock *sk, int flags) | ||||||
| 	struct tls_context *tls_ctx = tls_get_ctx(sk); | 	struct tls_context *tls_ctx = tls_get_ctx(sk); | ||||||
| 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); | 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); | ||||||
| 	struct tls_rec *rec, *tmp; | 	struct tls_rec *rec, *tmp; | ||||||
|  | 	struct sk_msg *msg_en; | ||||||
| 	int tx_flags, rc = 0; | 	int tx_flags, rc = 0; | ||||||
| 
 | 
 | ||||||
| 	if (tls_is_partially_sent_record(tls_ctx)) { | 	if (tls_is_partially_sent_record(tls_ctx)) { | ||||||
|  | @ -407,9 +298,7 @@ int tls_tx_records(struct sock *sk, int flags) | ||||||
| 		 * Remove the head of tx_list | 		 * Remove the head of tx_list | ||||||
| 		 */ | 		 */ | ||||||
| 		list_del(&rec->list); | 		list_del(&rec->list); | ||||||
| 		free_sg(sk, &rec->sg_plaintext_data[1], | 		sk_msg_free(sk, &rec->msg_plaintext); | ||||||
| 			&rec->sg_plaintext_num_elem, &rec->sg_plaintext_size); |  | ||||||
| 
 |  | ||||||
| 		kfree(rec); | 		kfree(rec); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -421,17 +310,15 @@ int tls_tx_records(struct sock *sk, int flags) | ||||||
| 			else | 			else | ||||||
| 				tx_flags = flags; | 				tx_flags = flags; | ||||||
| 
 | 
 | ||||||
|  | 			msg_en = &rec->msg_encrypted; | ||||||
| 			rc = tls_push_sg(sk, tls_ctx, | 			rc = tls_push_sg(sk, tls_ctx, | ||||||
| 					 &rec->sg_encrypted_data[1], | 					 &msg_en->sg.data[msg_en->sg.curr], | ||||||
| 					 0, tx_flags); | 					 0, tx_flags); | ||||||
| 			if (rc) | 			if (rc) | ||||||
| 				goto tx_err; | 				goto tx_err; | ||||||
| 
 | 
 | ||||||
| 			list_del(&rec->list); | 			list_del(&rec->list); | ||||||
| 			free_sg(sk, &rec->sg_plaintext_data[1], | 			sk_msg_free(sk, &rec->msg_plaintext); | ||||||
| 				&rec->sg_plaintext_num_elem, |  | ||||||
| 				&rec->sg_plaintext_size); |  | ||||||
| 
 |  | ||||||
| 			kfree(rec); | 			kfree(rec); | ||||||
| 		} else { | 		} else { | ||||||
| 			break; | 			break; | ||||||
|  | @ -451,15 +338,18 @@ static void tls_encrypt_done(struct crypto_async_request *req, int err) | ||||||
| 	struct sock *sk = req->data; | 	struct sock *sk = req->data; | ||||||
| 	struct tls_context *tls_ctx = tls_get_ctx(sk); | 	struct tls_context *tls_ctx = tls_get_ctx(sk); | ||||||
| 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); | 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); | ||||||
|  | 	struct scatterlist *sge; | ||||||
|  | 	struct sk_msg *msg_en; | ||||||
| 	struct tls_rec *rec; | 	struct tls_rec *rec; | ||||||
| 	bool ready = false; | 	bool ready = false; | ||||||
| 	int pending; | 	int pending; | ||||||
| 
 | 
 | ||||||
| 	rec = container_of(aead_req, struct tls_rec, aead_req); | 	rec = container_of(aead_req, struct tls_rec, aead_req); | ||||||
|  | 	msg_en = &rec->msg_encrypted; | ||||||
| 
 | 
 | ||||||
| 	rec->sg_encrypted_data[1].offset -= tls_ctx->tx.prepend_size; | 	sge = sk_msg_elem(msg_en, msg_en->sg.curr); | ||||||
| 	rec->sg_encrypted_data[1].length += tls_ctx->tx.prepend_size; | 	sge->offset -= tls_ctx->tx.prepend_size; | ||||||
| 
 | 	sge->length += tls_ctx->tx.prepend_size; | ||||||
| 
 | 
 | ||||||
| 	/* Check if error is previously set on socket */ | 	/* Check if error is previously set on socket */ | ||||||
| 	if (err || sk->sk_err) { | 	if (err || sk->sk_err) { | ||||||
|  | @ -497,31 +387,29 @@ static void tls_encrypt_done(struct crypto_async_request *req, int err) | ||||||
| 
 | 
 | ||||||
| 	/* Schedule the transmission */ | 	/* Schedule the transmission */ | ||||||
| 	if (!test_and_set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) | 	if (!test_and_set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask)) | ||||||
| 		schedule_delayed_work(&ctx->tx_work.work, 2); | 		schedule_delayed_work(&ctx->tx_work.work, 1); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int tls_do_encryption(struct sock *sk, | static int tls_do_encryption(struct sock *sk, | ||||||
| 			     struct tls_context *tls_ctx, | 			     struct tls_context *tls_ctx, | ||||||
| 			     struct tls_sw_context_tx *ctx, | 			     struct tls_sw_context_tx *ctx, | ||||||
| 			     struct aead_request *aead_req, | 			     struct aead_request *aead_req, | ||||||
| 			     size_t data_len) | 			     size_t data_len, u32 start) | ||||||
| { | { | ||||||
| 	struct tls_rec *rec = ctx->open_rec; | 	struct tls_rec *rec = ctx->open_rec; | ||||||
| 	struct scatterlist *plain_sg = rec->sg_plaintext_data; | 	struct sk_msg *msg_en = &rec->msg_encrypted; | ||||||
| 	struct scatterlist *enc_sg = rec->sg_encrypted_data; | 	struct scatterlist *sge = sk_msg_elem(msg_en, start); | ||||||
| 	int rc; | 	int rc; | ||||||
| 
 | 
 | ||||||
| 	/* Skip the first index as it contains AAD data */ | 	sge->offset += tls_ctx->tx.prepend_size; | ||||||
| 	rec->sg_encrypted_data[1].offset += tls_ctx->tx.prepend_size; | 	sge->length -= tls_ctx->tx.prepend_size; | ||||||
| 	rec->sg_encrypted_data[1].length -= tls_ctx->tx.prepend_size; |  | ||||||
| 
 | 
 | ||||||
| 	/* If it is inplace crypto, then pass same SG list as both src, dst */ | 	msg_en->sg.curr = start; | ||||||
| 	if (rec->inplace_crypto) |  | ||||||
| 		plain_sg = enc_sg; |  | ||||||
| 
 | 
 | ||||||
| 	aead_request_set_tfm(aead_req, ctx->aead_send); | 	aead_request_set_tfm(aead_req, ctx->aead_send); | ||||||
| 	aead_request_set_ad(aead_req, TLS_AAD_SPACE_SIZE); | 	aead_request_set_ad(aead_req, TLS_AAD_SPACE_SIZE); | ||||||
| 	aead_request_set_crypt(aead_req, plain_sg, enc_sg, | 	aead_request_set_crypt(aead_req, rec->sg_aead_in, | ||||||
|  | 			       rec->sg_aead_out, | ||||||
| 			       data_len, tls_ctx->tx.iv); | 			       data_len, tls_ctx->tx.iv); | ||||||
| 
 | 
 | ||||||
| 	aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, | 	aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG, | ||||||
|  | @ -534,8 +422,8 @@ static int tls_do_encryption(struct sock *sk, | ||||||
| 	rc = crypto_aead_encrypt(aead_req); | 	rc = crypto_aead_encrypt(aead_req); | ||||||
| 	if (!rc || rc != -EINPROGRESS) { | 	if (!rc || rc != -EINPROGRESS) { | ||||||
| 		atomic_dec(&ctx->encrypt_pending); | 		atomic_dec(&ctx->encrypt_pending); | ||||||
| 		rec->sg_encrypted_data[1].offset -= tls_ctx->tx.prepend_size; | 		sge->offset -= tls_ctx->tx.prepend_size; | ||||||
| 		rec->sg_encrypted_data[1].length += tls_ctx->tx.prepend_size; | 		sge->length += tls_ctx->tx.prepend_size; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (!rc) { | 	if (!rc) { | ||||||
|  | @ -557,35 +445,50 @@ static int tls_push_record(struct sock *sk, int flags, | ||||||
| 	struct tls_context *tls_ctx = tls_get_ctx(sk); | 	struct tls_context *tls_ctx = tls_get_ctx(sk); | ||||||
| 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); | 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); | ||||||
| 	struct tls_rec *rec = ctx->open_rec; | 	struct tls_rec *rec = ctx->open_rec; | ||||||
|  | 	struct sk_msg *msg_pl, *msg_en; | ||||||
| 	struct aead_request *req; | 	struct aead_request *req; | ||||||
| 	int rc; | 	int rc; | ||||||
|  | 	u32 i; | ||||||
| 
 | 
 | ||||||
| 	if (!rec) | 	if (!rec) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
|  | 	msg_pl = &rec->msg_plaintext; | ||||||
|  | 	msg_en = &rec->msg_encrypted; | ||||||
|  | 
 | ||||||
| 	rec->tx_flags = flags; | 	rec->tx_flags = flags; | ||||||
| 	req = &rec->aead_req; | 	req = &rec->aead_req; | ||||||
| 
 | 
 | ||||||
| 	sg_mark_end(rec->sg_plaintext_data + rec->sg_plaintext_num_elem); | 	i = msg_pl->sg.end; | ||||||
| 	sg_mark_end(rec->sg_encrypted_data + rec->sg_encrypted_num_elem); | 	sk_msg_iter_var_prev(i); | ||||||
|  | 	sg_mark_end(sk_msg_elem(msg_pl, i)); | ||||||
| 
 | 
 | ||||||
| 	tls_make_aad(rec->aad_space, rec->sg_plaintext_size, | 	i = msg_pl->sg.start; | ||||||
|  | 	sg_chain(rec->sg_aead_in, 2, rec->inplace_crypto ? | ||||||
|  | 		 &msg_en->sg.data[i] : &msg_pl->sg.data[i]); | ||||||
|  | 
 | ||||||
|  | 	i = msg_en->sg.end; | ||||||
|  | 	sk_msg_iter_var_prev(i); | ||||||
|  | 	sg_mark_end(sk_msg_elem(msg_en, i)); | ||||||
|  | 
 | ||||||
|  | 	i = msg_en->sg.start; | ||||||
|  | 	sg_chain(rec->sg_aead_out, 2, &msg_en->sg.data[i]); | ||||||
|  | 
 | ||||||
|  | 	tls_make_aad(rec->aad_space, msg_pl->sg.size, | ||||||
| 		     tls_ctx->tx.rec_seq, tls_ctx->tx.rec_seq_size, | 		     tls_ctx->tx.rec_seq, tls_ctx->tx.rec_seq_size, | ||||||
| 		     record_type); | 		     record_type); | ||||||
| 
 | 
 | ||||||
| 	tls_fill_prepend(tls_ctx, | 	tls_fill_prepend(tls_ctx, | ||||||
| 			 page_address(sg_page(&rec->sg_encrypted_data[1])) + | 			 page_address(sg_page(&msg_en->sg.data[i])) + | ||||||
| 			 rec->sg_encrypted_data[1].offset, | 			 msg_en->sg.data[i].offset, msg_pl->sg.size, | ||||||
| 			 rec->sg_plaintext_size, record_type); | 			 record_type); | ||||||
| 
 | 
 | ||||||
| 	tls_ctx->pending_open_record_frags = 0; | 	tls_ctx->pending_open_record_frags = false; | ||||||
| 
 |  | ||||||
| 	rc = tls_do_encryption(sk, tls_ctx, ctx, req, rec->sg_plaintext_size); |  | ||||||
| 	if (rc == -EINPROGRESS) |  | ||||||
| 		return -EINPROGRESS; |  | ||||||
| 
 | 
 | ||||||
|  | 	rc = tls_do_encryption(sk, tls_ctx, ctx, req, msg_pl->sg.size, i); | ||||||
| 	if (rc < 0) { | 	if (rc < 0) { | ||||||
| 		tls_err_abort(sk, EBADMSG); | 		if (rc != -EINPROGRESS) | ||||||
|  | 			tls_err_abort(sk, EBADMSG); | ||||||
| 		return rc; | 		return rc; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -597,104 +500,11 @@ static int tls_sw_push_pending_record(struct sock *sk, int flags) | ||||||
| 	return tls_push_record(sk, flags, TLS_RECORD_TYPE_DATA); | 	return tls_push_record(sk, flags, TLS_RECORD_TYPE_DATA); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int zerocopy_from_iter(struct sock *sk, struct iov_iter *from, |  | ||||||
| 			      int length, int *pages_used, |  | ||||||
| 			      unsigned int *size_used, |  | ||||||
| 			      struct scatterlist *to, int to_max_pages, |  | ||||||
| 			      bool charge) |  | ||||||
| { |  | ||||||
| 	struct page *pages[MAX_SKB_FRAGS]; |  | ||||||
| 
 |  | ||||||
| 	size_t offset; |  | ||||||
| 	ssize_t copied, use; |  | ||||||
| 	int i = 0; |  | ||||||
| 	unsigned int size = *size_used; |  | ||||||
| 	int num_elem = *pages_used; |  | ||||||
| 	int rc = 0; |  | ||||||
| 	int maxpages; |  | ||||||
| 
 |  | ||||||
| 	while (length > 0) { |  | ||||||
| 		i = 0; |  | ||||||
| 		maxpages = to_max_pages - num_elem; |  | ||||||
| 		if (maxpages == 0) { |  | ||||||
| 			rc = -EFAULT; |  | ||||||
| 			goto out; |  | ||||||
| 		} |  | ||||||
| 		copied = iov_iter_get_pages(from, pages, |  | ||||||
| 					    length, |  | ||||||
| 					    maxpages, &offset); |  | ||||||
| 		if (copied <= 0) { |  | ||||||
| 			rc = -EFAULT; |  | ||||||
| 			goto out; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		iov_iter_advance(from, copied); |  | ||||||
| 
 |  | ||||||
| 		length -= copied; |  | ||||||
| 		size += copied; |  | ||||||
| 		while (copied) { |  | ||||||
| 			use = min_t(int, copied, PAGE_SIZE - offset); |  | ||||||
| 
 |  | ||||||
| 			sg_set_page(&to[num_elem], |  | ||||||
| 				    pages[i], use, offset); |  | ||||||
| 			sg_unmark_end(&to[num_elem]); |  | ||||||
| 			if (charge) |  | ||||||
| 				sk_mem_charge(sk, use); |  | ||||||
| 
 |  | ||||||
| 			offset = 0; |  | ||||||
| 			copied -= use; |  | ||||||
| 
 |  | ||||||
| 			++i; |  | ||||||
| 			++num_elem; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* Mark the end in the last sg entry if newly added */ |  | ||||||
| 	if (num_elem > *pages_used) |  | ||||||
| 		sg_mark_end(&to[num_elem - 1]); |  | ||||||
| out: |  | ||||||
| 	if (rc) |  | ||||||
| 		iov_iter_revert(from, size - *size_used); |  | ||||||
| 	*size_used = size; |  | ||||||
| 	*pages_used = num_elem; |  | ||||||
| 
 |  | ||||||
| 	return rc; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static int memcopy_from_iter(struct sock *sk, struct iov_iter *from, |  | ||||||
| 			     int bytes) |  | ||||||
| { |  | ||||||
| 	struct tls_context *tls_ctx = tls_get_ctx(sk); |  | ||||||
| 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); |  | ||||||
| 	struct tls_rec *rec = ctx->open_rec; |  | ||||||
| 	struct scatterlist *sg = &rec->sg_plaintext_data[1]; |  | ||||||
| 	int copy, i, rc = 0; |  | ||||||
| 
 |  | ||||||
| 	for (i = tls_ctx->pending_open_record_frags; |  | ||||||
| 	     i < rec->sg_plaintext_num_elem; ++i) { |  | ||||||
| 		copy = sg[i].length; |  | ||||||
| 		if (copy_from_iter( |  | ||||||
| 				page_address(sg_page(&sg[i])) + sg[i].offset, |  | ||||||
| 				copy, from) != copy) { |  | ||||||
| 			rc = -EFAULT; |  | ||||||
| 			goto out; |  | ||||||
| 		} |  | ||||||
| 		bytes -= copy; |  | ||||||
| 
 |  | ||||||
| 		++tls_ctx->pending_open_record_frags; |  | ||||||
| 
 |  | ||||||
| 		if (!bytes) |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| out: |  | ||||||
| 	return rc; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static struct tls_rec *get_rec(struct sock *sk) | static struct tls_rec *get_rec(struct sock *sk) | ||||||
| { | { | ||||||
| 	struct tls_context *tls_ctx = tls_get_ctx(sk); | 	struct tls_context *tls_ctx = tls_get_ctx(sk); | ||||||
| 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); | 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); | ||||||
|  | 	struct sk_msg *msg_pl, *msg_en; | ||||||
| 	struct tls_rec *rec; | 	struct tls_rec *rec; | ||||||
| 	int mem_size; | 	int mem_size; | ||||||
| 
 | 
 | ||||||
|  | @ -708,15 +518,21 @@ static struct tls_rec *get_rec(struct sock *sk) | ||||||
| 	if (!rec) | 	if (!rec) | ||||||
| 		return NULL; | 		return NULL; | ||||||
| 
 | 
 | ||||||
| 	sg_init_table(&rec->sg_plaintext_data[0], | 	msg_pl = &rec->msg_plaintext; | ||||||
| 		      ARRAY_SIZE(rec->sg_plaintext_data)); | 	msg_en = &rec->msg_encrypted; | ||||||
| 	sg_init_table(&rec->sg_encrypted_data[0], |  | ||||||
| 		      ARRAY_SIZE(rec->sg_encrypted_data)); |  | ||||||
| 
 | 
 | ||||||
| 	sg_set_buf(&rec->sg_plaintext_data[0], rec->aad_space, | 	sk_msg_init(msg_pl); | ||||||
|  | 	sk_msg_init(msg_en); | ||||||
|  | 
 | ||||||
|  | 	sg_init_table(rec->sg_aead_in, 2); | ||||||
|  | 	sg_set_buf(&rec->sg_aead_in[0], rec->aad_space, | ||||||
| 		   sizeof(rec->aad_space)); | 		   sizeof(rec->aad_space)); | ||||||
| 	sg_set_buf(&rec->sg_encrypted_data[0], rec->aad_space, | 	sg_unmark_end(&rec->sg_aead_in[1]); | ||||||
|  | 
 | ||||||
|  | 	sg_init_table(rec->sg_aead_out, 2); | ||||||
|  | 	sg_set_buf(&rec->sg_aead_out[0], rec->aad_space, | ||||||
| 		   sizeof(rec->aad_space)); | 		   sizeof(rec->aad_space)); | ||||||
|  | 	sg_unmark_end(&rec->sg_aead_out[1]); | ||||||
| 
 | 
 | ||||||
| 	ctx->open_rec = rec; | 	ctx->open_rec = rec; | ||||||
| 	rec->inplace_crypto = 1; | 	rec->inplace_crypto = 1; | ||||||
|  | @ -735,6 +551,7 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) | ||||||
| 	bool is_kvec = msg->msg_iter.type & ITER_KVEC; | 	bool is_kvec = msg->msg_iter.type & ITER_KVEC; | ||||||
| 	bool eor = !(msg->msg_flags & MSG_MORE); | 	bool eor = !(msg->msg_flags & MSG_MORE); | ||||||
| 	size_t try_to_copy, copied = 0; | 	size_t try_to_copy, copied = 0; | ||||||
|  | 	struct sk_msg *msg_pl, *msg_en; | ||||||
| 	struct tls_rec *rec; | 	struct tls_rec *rec; | ||||||
| 	int required_size; | 	int required_size; | ||||||
| 	int num_async = 0; | 	int num_async = 0; | ||||||
|  | @ -778,23 +595,26 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) | ||||||
| 			goto send_end; | 			goto send_end; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		orig_size = rec->sg_plaintext_size; | 		msg_pl = &rec->msg_plaintext; | ||||||
|  | 		msg_en = &rec->msg_encrypted; | ||||||
|  | 
 | ||||||
|  | 		orig_size = msg_pl->sg.size; | ||||||
| 		full_record = false; | 		full_record = false; | ||||||
| 		try_to_copy = msg_data_left(msg); | 		try_to_copy = msg_data_left(msg); | ||||||
| 		record_room = TLS_MAX_PAYLOAD_SIZE - rec->sg_plaintext_size; | 		record_room = TLS_MAX_PAYLOAD_SIZE - msg_pl->sg.size; | ||||||
| 		if (try_to_copy >= record_room) { | 		if (try_to_copy >= record_room) { | ||||||
| 			try_to_copy = record_room; | 			try_to_copy = record_room; | ||||||
| 			full_record = true; | 			full_record = true; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		required_size = rec->sg_plaintext_size + try_to_copy + | 		required_size = msg_pl->sg.size + try_to_copy + | ||||||
| 				tls_ctx->tx.overhead_size; | 				tls_ctx->tx.overhead_size; | ||||||
| 
 | 
 | ||||||
| 		if (!sk_stream_memory_free(sk)) | 		if (!sk_stream_memory_free(sk)) | ||||||
| 			goto wait_for_sndbuf; | 			goto wait_for_sndbuf; | ||||||
| 
 | 
 | ||||||
| alloc_encrypted: | alloc_encrypted: | ||||||
| 		ret = alloc_encrypted_sg(sk, required_size); | 		ret = tls_alloc_encrypted_msg(sk, required_size); | ||||||
| 		if (ret) { | 		if (ret) { | ||||||
| 			if (ret != -ENOSPC) | 			if (ret != -ENOSPC) | ||||||
| 				goto wait_for_memory; | 				goto wait_for_memory; | ||||||
|  | @ -803,17 +623,13 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) | ||||||
| 			 * actually allocated. The difference is due | 			 * actually allocated. The difference is due | ||||||
| 			 * to max sg elements limit | 			 * to max sg elements limit | ||||||
| 			 */ | 			 */ | ||||||
| 			try_to_copy -= required_size - rec->sg_encrypted_size; | 			try_to_copy -= required_size - msg_en->sg.size; | ||||||
| 			full_record = true; | 			full_record = true; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (!is_kvec && (full_record || eor) && !async_capable) { | 		if (!is_kvec && (full_record || eor) && !async_capable) { | ||||||
| 			ret = zerocopy_from_iter(sk, &msg->msg_iter, | 			ret = sk_msg_zerocopy_from_iter(sk, &msg->msg_iter, | ||||||
| 				try_to_copy, &rec->sg_plaintext_num_elem, | 							msg_pl, try_to_copy); | ||||||
| 				&rec->sg_plaintext_size, |  | ||||||
| 				&rec->sg_plaintext_data[1], |  | ||||||
| 				ARRAY_SIZE(rec->sg_plaintext_data) - 1, |  | ||||||
| 				true); |  | ||||||
| 			if (ret) | 			if (ret) | ||||||
| 				goto fallback_to_reg_send; | 				goto fallback_to_reg_send; | ||||||
| 
 | 
 | ||||||
|  | @ -831,15 +647,12 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
| fallback_to_reg_send: | fallback_to_reg_send: | ||||||
| 			trim_sg(sk, &rec->sg_plaintext_data[1], | 			sk_msg_trim(sk, msg_pl, orig_size); | ||||||
| 				&rec->sg_plaintext_num_elem, |  | ||||||
| 				&rec->sg_plaintext_size, |  | ||||||
| 				orig_size); |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		required_size = rec->sg_plaintext_size + try_to_copy; | 		required_size = msg_pl->sg.size + try_to_copy; | ||||||
| 
 | 
 | ||||||
| 		ret = move_to_plaintext_sg(sk, required_size); | 		ret = tls_clone_plaintext_msg(sk, required_size); | ||||||
| 		if (ret) { | 		if (ret) { | ||||||
| 			if (ret != -ENOSPC) | 			if (ret != -ENOSPC) | ||||||
| 				goto send_end; | 				goto send_end; | ||||||
|  | @ -848,20 +661,21 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) | ||||||
| 			 * actually allocated. The difference is due | 			 * actually allocated. The difference is due | ||||||
| 			 * to max sg elements limit | 			 * to max sg elements limit | ||||||
| 			 */ | 			 */ | ||||||
| 			try_to_copy -= required_size - rec->sg_plaintext_size; | 			try_to_copy -= required_size - msg_pl->sg.size; | ||||||
| 			full_record = true; | 			full_record = true; | ||||||
| 
 | 			sk_msg_trim(sk, msg_en, msg_pl->sg.size + | ||||||
| 			trim_sg(sk, &rec->sg_encrypted_data[1], | 				    tls_ctx->tx.overhead_size); | ||||||
| 				&rec->sg_encrypted_num_elem, |  | ||||||
| 				&rec->sg_encrypted_size, |  | ||||||
| 				rec->sg_plaintext_size + |  | ||||||
| 				tls_ctx->tx.overhead_size); |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		ret = memcopy_from_iter(sk, &msg->msg_iter, try_to_copy); | 		ret = sk_msg_memcopy_from_iter(sk, &msg->msg_iter, msg_pl, | ||||||
| 		if (ret) | 					       try_to_copy); | ||||||
|  | 		if (ret < 0) | ||||||
| 			goto trim_sgl; | 			goto trim_sgl; | ||||||
| 
 | 
 | ||||||
|  | 		/* Open records defined only if successfully copied, otherwise
 | ||||||
|  | 		 * we would trim the sg but not reset the open record frags. | ||||||
|  | 		 */ | ||||||
|  | 		tls_ctx->pending_open_record_frags = true; | ||||||
| 		copied += try_to_copy; | 		copied += try_to_copy; | ||||||
| 		if (full_record || eor) { | 		if (full_record || eor) { | ||||||
| 			ret = tls_push_record(sk, msg->msg_flags, record_type); | 			ret = tls_push_record(sk, msg->msg_flags, record_type); | ||||||
|  | @ -881,11 +695,11 @@ int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) | ||||||
| 		ret = sk_stream_wait_memory(sk, &timeo); | 		ret = sk_stream_wait_memory(sk, &timeo); | ||||||
| 		if (ret) { | 		if (ret) { | ||||||
| trim_sgl: | trim_sgl: | ||||||
| 			trim_both_sgl(sk, orig_size); | 			tls_trim_both_msgs(sk, orig_size); | ||||||
| 			goto send_end; | 			goto send_end; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (rec->sg_encrypted_size < required_size) | 		if (msg_en->sg.size < required_size) | ||||||
| 			goto alloc_encrypted; | 			goto alloc_encrypted; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -929,7 +743,7 @@ int tls_sw_sendpage(struct sock *sk, struct page *page, | ||||||
| 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); | 	struct tls_sw_context_tx *ctx = tls_sw_ctx_tx(tls_ctx); | ||||||
| 	unsigned char record_type = TLS_RECORD_TYPE_DATA; | 	unsigned char record_type = TLS_RECORD_TYPE_DATA; | ||||||
| 	size_t orig_size = size; | 	size_t orig_size = size; | ||||||
| 	struct scatterlist *sg; | 	struct sk_msg *msg_pl; | ||||||
| 	struct tls_rec *rec; | 	struct tls_rec *rec; | ||||||
| 	int num_async = 0; | 	int num_async = 0; | ||||||
| 	bool full_record; | 	bool full_record; | ||||||
|  | @ -970,20 +784,23 @@ int tls_sw_sendpage(struct sock *sk, struct page *page, | ||||||
| 			goto sendpage_end; | 			goto sendpage_end; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		msg_pl = &rec->msg_plaintext; | ||||||
|  | 
 | ||||||
| 		full_record = false; | 		full_record = false; | ||||||
| 		record_room = TLS_MAX_PAYLOAD_SIZE - rec->sg_plaintext_size; | 		record_room = TLS_MAX_PAYLOAD_SIZE - msg_pl->sg.size; | ||||||
| 		copy = size; | 		copy = size; | ||||||
| 		if (copy >= record_room) { | 		if (copy >= record_room) { | ||||||
| 			copy = record_room; | 			copy = record_room; | ||||||
| 			full_record = true; | 			full_record = true; | ||||||
| 		} | 		} | ||||||
| 		required_size = rec->sg_plaintext_size + copy + | 
 | ||||||
| 			      tls_ctx->tx.overhead_size; | 		required_size = msg_pl->sg.size + copy + | ||||||
|  | 				tls_ctx->tx.overhead_size; | ||||||
| 
 | 
 | ||||||
| 		if (!sk_stream_memory_free(sk)) | 		if (!sk_stream_memory_free(sk)) | ||||||
| 			goto wait_for_sndbuf; | 			goto wait_for_sndbuf; | ||||||
| alloc_payload: | alloc_payload: | ||||||
| 		ret = alloc_encrypted_sg(sk, required_size); | 		ret = tls_alloc_encrypted_msg(sk, required_size); | ||||||
| 		if (ret) { | 		if (ret) { | ||||||
| 			if (ret != -ENOSPC) | 			if (ret != -ENOSPC) | ||||||
| 				goto wait_for_memory; | 				goto wait_for_memory; | ||||||
|  | @ -992,26 +809,18 @@ int tls_sw_sendpage(struct sock *sk, struct page *page, | ||||||
| 			 * actually allocated. The difference is due | 			 * actually allocated. The difference is due | ||||||
| 			 * to max sg elements limit | 			 * to max sg elements limit | ||||||
| 			 */ | 			 */ | ||||||
| 			copy -= required_size - rec->sg_plaintext_size; | 			copy -= required_size - msg_pl->sg.size; | ||||||
| 			full_record = true; | 			full_record = true; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		get_page(page); | 		sk_msg_page_add(msg_pl, page, copy, offset); | ||||||
| 		sg = &rec->sg_plaintext_data[1] + rec->sg_plaintext_num_elem; |  | ||||||
| 		sg_set_page(sg, page, copy, offset); |  | ||||||
| 		sg_unmark_end(sg); |  | ||||||
| 
 |  | ||||||
| 		rec->sg_plaintext_num_elem++; |  | ||||||
| 
 |  | ||||||
| 		sk_mem_charge(sk, copy); | 		sk_mem_charge(sk, copy); | ||||||
|  | 
 | ||||||
| 		offset += copy; | 		offset += copy; | ||||||
| 		size -= copy; | 		size -= copy; | ||||||
| 		rec->sg_plaintext_size += copy; |  | ||||||
| 		tls_ctx->pending_open_record_frags = rec->sg_plaintext_num_elem; |  | ||||||
| 
 | 
 | ||||||
| 		if (full_record || eor || | 		tls_ctx->pending_open_record_frags = true; | ||||||
| 		    rec->sg_plaintext_num_elem == | 		if (full_record || eor || sk_msg_full(msg_pl)) { | ||||||
| 		    ARRAY_SIZE(rec->sg_plaintext_data) - 1) { |  | ||||||
| 			rec->inplace_crypto = 0; | 			rec->inplace_crypto = 0; | ||||||
| 			ret = tls_push_record(sk, flags, record_type); | 			ret = tls_push_record(sk, flags, record_type); | ||||||
| 			if (ret) { | 			if (ret) { | ||||||
|  | @ -1027,7 +836,7 @@ int tls_sw_sendpage(struct sock *sk, struct page *page, | ||||||
| wait_for_memory: | wait_for_memory: | ||||||
| 		ret = sk_stream_wait_memory(sk, &timeo); | 		ret = sk_stream_wait_memory(sk, &timeo); | ||||||
| 		if (ret) { | 		if (ret) { | ||||||
| 			trim_both_sgl(sk, rec->sg_plaintext_size); | 			tls_trim_both_msgs(sk, msg_pl->sg.size); | ||||||
| 			goto sendpage_end; | 			goto sendpage_end; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -1092,6 +901,64 @@ static struct sk_buff *tls_wait_data(struct sock *sk, int flags, | ||||||
| 	return skb; | 	return skb; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int tls_setup_from_iter(struct sock *sk, struct iov_iter *from, | ||||||
|  | 			       int length, int *pages_used, | ||||||
|  | 			       unsigned int *size_used, | ||||||
|  | 			       struct scatterlist *to, | ||||||
|  | 			       int to_max_pages) | ||||||
|  | { | ||||||
|  | 	int rc = 0, i = 0, num_elem = *pages_used, maxpages; | ||||||
|  | 	struct page *pages[MAX_SKB_FRAGS]; | ||||||
|  | 	unsigned int size = *size_used; | ||||||
|  | 	ssize_t copied, use; | ||||||
|  | 	size_t offset; | ||||||
|  | 
 | ||||||
|  | 	while (length > 0) { | ||||||
|  | 		i = 0; | ||||||
|  | 		maxpages = to_max_pages - num_elem; | ||||||
|  | 		if (maxpages == 0) { | ||||||
|  | 			rc = -EFAULT; | ||||||
|  | 			goto out; | ||||||
|  | 		} | ||||||
|  | 		copied = iov_iter_get_pages(from, pages, | ||||||
|  | 					    length, | ||||||
|  | 					    maxpages, &offset); | ||||||
|  | 		if (copied <= 0) { | ||||||
|  | 			rc = -EFAULT; | ||||||
|  | 			goto out; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		iov_iter_advance(from, copied); | ||||||
|  | 
 | ||||||
|  | 		length -= copied; | ||||||
|  | 		size += copied; | ||||||
|  | 		while (copied) { | ||||||
|  | 			use = min_t(int, copied, PAGE_SIZE - offset); | ||||||
|  | 
 | ||||||
|  | 			sg_set_page(&to[num_elem], | ||||||
|  | 				    pages[i], use, offset); | ||||||
|  | 			sg_unmark_end(&to[num_elem]); | ||||||
|  | 			/* We do not uncharge memory from this API */ | ||||||
|  | 
 | ||||||
|  | 			offset = 0; | ||||||
|  | 			copied -= use; | ||||||
|  | 
 | ||||||
|  | 			i++; | ||||||
|  | 			num_elem++; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	/* Mark the end in the last sg entry if newly added */ | ||||||
|  | 	if (num_elem > *pages_used) | ||||||
|  | 		sg_mark_end(&to[num_elem - 1]); | ||||||
|  | out: | ||||||
|  | 	if (rc) | ||||||
|  | 		iov_iter_revert(from, size - *size_used); | ||||||
|  | 	*size_used = size; | ||||||
|  | 	*pages_used = num_elem; | ||||||
|  | 
 | ||||||
|  | 	return rc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* This function decrypts the input skb into either out_iov or in out_sg
 | /* This function decrypts the input skb into either out_iov or in out_sg
 | ||||||
|  * or in skb buffers itself. The input parameter 'zc' indicates if |  * or in skb buffers itself. The input parameter 'zc' indicates if | ||||||
|  * zero-copy mode needs to be tried or not. With zero-copy mode, either |  * zero-copy mode needs to be tried or not. With zero-copy mode, either | ||||||
|  | @ -1189,9 +1056,9 @@ static int decrypt_internal(struct sock *sk, struct sk_buff *skb, | ||||||
| 			sg_set_buf(&sgout[0], aad, TLS_AAD_SPACE_SIZE); | 			sg_set_buf(&sgout[0], aad, TLS_AAD_SPACE_SIZE); | ||||||
| 
 | 
 | ||||||
| 			*chunk = 0; | 			*chunk = 0; | ||||||
| 			err = zerocopy_from_iter(sk, out_iov, data_len, &pages, | 			err = tls_setup_from_iter(sk, out_iov, data_len, | ||||||
| 						 chunk, &sgout[1], | 						  &pages, chunk, &sgout[1], | ||||||
| 						 (n_sgout - 1), false); | 						  (n_sgout - 1)); | ||||||
| 			if (err < 0) | 			if (err < 0) | ||||||
| 				goto fallback_to_reg_recv; | 				goto fallback_to_reg_recv; | ||||||
| 		} else if (out_sg) { | 		} else if (out_sg) { | ||||||
|  | @ -1619,25 +1486,15 @@ void tls_sw_free_resources_tx(struct sock *sk) | ||||||
| 
 | 
 | ||||||
| 		rec = list_first_entry(&ctx->tx_list, | 		rec = list_first_entry(&ctx->tx_list, | ||||||
| 				       struct tls_rec, list); | 				       struct tls_rec, list); | ||||||
| 
 |  | ||||||
| 		free_sg(sk, &rec->sg_plaintext_data[1], |  | ||||||
| 			&rec->sg_plaintext_num_elem, |  | ||||||
| 			&rec->sg_plaintext_size); |  | ||||||
| 
 |  | ||||||
| 		list_del(&rec->list); | 		list_del(&rec->list); | ||||||
|  | 		sk_msg_free(sk, &rec->msg_plaintext); | ||||||
| 		kfree(rec); | 		kfree(rec); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	list_for_each_entry_safe(rec, tmp, &ctx->tx_list, list) { | 	list_for_each_entry_safe(rec, tmp, &ctx->tx_list, list) { | ||||||
| 		free_sg(sk, &rec->sg_encrypted_data[1], |  | ||||||
| 			&rec->sg_encrypted_num_elem, |  | ||||||
| 			&rec->sg_encrypted_size); |  | ||||||
| 
 |  | ||||||
| 		free_sg(sk, &rec->sg_plaintext_data[1], |  | ||||||
| 			&rec->sg_plaintext_num_elem, |  | ||||||
| 			&rec->sg_plaintext_size); |  | ||||||
| 
 |  | ||||||
| 		list_del(&rec->list); | 		list_del(&rec->list); | ||||||
|  | 		sk_msg_free(sk, &rec->msg_encrypted); | ||||||
|  | 		sk_msg_free(sk, &rec->msg_plaintext); | ||||||
| 		kfree(rec); | 		kfree(rec); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Daniel Borkmann
						Daniel Borkmann