Skip to content

Commit 059ec82

Browse files
kuba-moogregkh
authored andcommitted
net: tls: avoid discarding data on record close
commit 6b47808 upstream. 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 <[email protected]> Signed-off-by: David S. Miller <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 05e6b93 commit 059ec82

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) {
@@ -313,36 +315,33 @@ static int tls_push_record(struct sock *sk,
313315
return tls_push_sg(sk, ctx, offload_ctx->sg_tx_data, 0, flags);
314316
}
315317

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

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

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

348347
static int tls_create_new_record(struct tls_offload_context_tx *offload_ctx,
@@ -535,18 +534,8 @@ static int tls_push_data(struct sock *sk,
535534

536535
if (done || record->len >= max_open_record_len ||
537536
(record->num_frags >= MAX_SKB_FRAGS - 1)) {
538-
rc = tls_device_record_close(sk, tls_ctx, record,
539-
pfrag, record_type);
540-
if (rc) {
541-
if (rc > 0) {
542-
size += rc;
543-
} else {
544-
size = orig_size;
545-
destroy_record(record);
546-
ctx->open_record = NULL;
547-
break;
548-
}
549-
}
537+
tls_device_record_close(sk, tls_ctx, record,
538+
pfrag, record_type);
550539

551540
rc = tls_push_record(sk,
552541
tls_ctx,
@@ -1466,14 +1455,26 @@ int __init tls_device_init(void)
14661455
{
14671456
int err;
14681457

1469-
destruct_wq = alloc_workqueue("ktls_device_destruct", 0, 0);
1470-
if (!destruct_wq)
1458+
dummy_page = alloc_page(GFP_KERNEL);
1459+
if (!dummy_page)
14711460
return -ENOMEM;
14721461

1462+
destruct_wq = alloc_workqueue("ktls_device_destruct", 0, 0);
1463+
if (!destruct_wq) {
1464+
err = -ENOMEM;
1465+
goto err_free_dummy;
1466+
}
1467+
14731468
err = register_netdevice_notifier(&tls_dev_notifier);
14741469
if (err)
1475-
destroy_workqueue(destruct_wq);
1470+
goto err_destroy_wq;
14761471

1472+
return 0;
1473+
1474+
err_destroy_wq:
1475+
destroy_workqueue(destruct_wq);
1476+
err_free_dummy:
1477+
put_page(dummy_page);
14771478
return err;
14781479
}
14791480

@@ -1482,4 +1483,5 @@ void __exit tls_device_cleanup(void)
14821483
unregister_netdevice_notifier(&tls_dev_notifier);
14831484
destroy_workqueue(destruct_wq);
14841485
clean_acked_data_flush();
1486+
put_page(dummy_page);
14851487
}

0 commit comments

Comments
 (0)