Skip to content

Commit 6b47808

Browse files
kuba-moodavem330
authored andcommitted
net: tls: avoid discarding data on record close
TLS records end with a 16B tag. For TLS device offload we only need to make space for this tag in the stream, the device will generate and replace it with the actual calculated tag. Long time ago the code would just re-reference the head frag which mostly worked but was suboptimal because it prevented TCP from combining the record into a single skb frag. I'm not sure if it was correct as the first frag may be shorter than the tag. The commit under fixes tried to replace that with using the page frag and if the allocation failed rolling back the data, if record was long enough. It achieves better fragment coalescing but is also buggy. We don't roll back the iterator, so unless we're at the end of send we'll skip the data we designated as tag and start the next record as if the rollback never happened. There's also the possibility that the record was constructed with MSG_MORE and the data came from a different syscall and we already told the user space that we "got it". Allocate a single dummy page and use it as fallback. Found by code inspection, and proven by forcing allocation failures. Fixes: e7b159a ("net/tls: remove the record tail optimization") Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent a47e598 commit 6b47808

File tree

1 file changed

+33
-31
lines changed

1 file changed

+33
-31
lines changed

net/tls/tls_device.c

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ static LIST_HEAD(tls_device_list);
5252
static LIST_HEAD(tls_device_down_list);
5353
static DEFINE_SPINLOCK(tls_device_lock);
5454

55+
static struct page *dummy_page;
56+
5557
static void tls_device_free_ctx(struct tls_context *ctx)
5658
{
5759
if (ctx->tx_conf == TLS_HW) {
@@ -312,36 +314,33 @@ static int tls_push_record(struct sock *sk,
312314
return tls_push_sg(sk, ctx, offload_ctx->sg_tx_data, 0, flags);
313315
}
314316

315-
static int tls_device_record_close(struct sock *sk,
316-
struct tls_context *ctx,
317-
struct tls_record_info *record,
318-
struct page_frag *pfrag,
319-
unsigned char record_type)
317+
static void tls_device_record_close(struct sock *sk,
318+
struct tls_context *ctx,
319+
struct tls_record_info *record,
320+
struct page_frag *pfrag,
321+
unsigned char record_type)
320322
{
321323
struct tls_prot_info *prot = &ctx->prot_info;
322-
int ret;
324+
struct page_frag dummy_tag_frag;
323325

324326
/* append tag
325327
* device will fill in the tag, we just need to append a placeholder
326328
* use socket memory to improve coalescing (re-using a single buffer
327329
* increases frag count)
328-
* if we can't allocate memory now, steal some back from data
330+
* if we can't allocate memory now use the dummy page
329331
*/
330-
if (likely(skb_page_frag_refill(prot->tag_size, pfrag,
331-
sk->sk_allocation))) {
332-
ret = 0;
333-
tls_append_frag(record, pfrag, prot->tag_size);
334-
} else {
335-
ret = prot->tag_size;
336-
if (record->len <= prot->overhead_size)
337-
return -ENOMEM;
332+
if (unlikely(pfrag->size - pfrag->offset < prot->tag_size) &&
333+
!skb_page_frag_refill(prot->tag_size, pfrag, sk->sk_allocation)) {
334+
dummy_tag_frag.page = dummy_page;
335+
dummy_tag_frag.offset = 0;
336+
pfrag = &dummy_tag_frag;
338337
}
338+
tls_append_frag(record, pfrag, prot->tag_size);
339339

340340
/* fill prepend */
341341
tls_fill_prepend(ctx, skb_frag_address(&record->frags[0]),
342342
record->len - prot->overhead_size,
343343
record_type);
344-
return ret;
345344
}
346345

347346
static int tls_create_new_record(struct tls_offload_context_tx *offload_ctx,
@@ -541,18 +540,8 @@ static int tls_push_data(struct sock *sk,
541540

542541
if (done || record->len >= max_open_record_len ||
543542
(record->num_frags >= MAX_SKB_FRAGS - 1)) {
544-
rc = tls_device_record_close(sk, tls_ctx, record,
545-
pfrag, record_type);
546-
if (rc) {
547-
if (rc > 0) {
548-
size += rc;
549-
} else {
550-
size = orig_size;
551-
destroy_record(record);
552-
ctx->open_record = NULL;
553-
break;
554-
}
555-
}
543+
tls_device_record_close(sk, tls_ctx, record,
544+
pfrag, record_type);
556545

557546
rc = tls_push_record(sk,
558547
tls_ctx,
@@ -1450,14 +1439,26 @@ int __init tls_device_init(void)
14501439
{
14511440
int err;
14521441

1453-
destruct_wq = alloc_workqueue("ktls_device_destruct", 0, 0);
1454-
if (!destruct_wq)
1442+
dummy_page = alloc_page(GFP_KERNEL);
1443+
if (!dummy_page)
14551444
return -ENOMEM;
14561445

1446+
destruct_wq = alloc_workqueue("ktls_device_destruct", 0, 0);
1447+
if (!destruct_wq) {
1448+
err = -ENOMEM;
1449+
goto err_free_dummy;
1450+
}
1451+
14571452
err = register_netdevice_notifier(&tls_dev_notifier);
14581453
if (err)
1459-
destroy_workqueue(destruct_wq);
1454+
goto err_destroy_wq;
14601455

1456+
return 0;
1457+
1458+
err_destroy_wq:
1459+
destroy_workqueue(destruct_wq);
1460+
err_free_dummy:
1461+
put_page(dummy_page);
14611462
return err;
14621463
}
14631464

@@ -1466,4 +1467,5 @@ void __exit tls_device_cleanup(void)
14661467
unregister_netdevice_notifier(&tls_dev_notifier);
14671468
destroy_workqueue(destruct_wq);
14681469
clean_acked_data_flush();
1470+
put_page(dummy_page);
14691471
}

0 commit comments

Comments
 (0)