Skip to content

Commit eb3d38d

Browse files
Jakub Kicinskidavem330
authored andcommitted
net/tls: fix copy to fragments in reencrypt
Fragments may contain data from other records so we have to account for that when we calculate the destination and max length of copy we can perform. Note that 'offset' is the offset within the message, so it can't be passed as offset within the frag.. Here skb_store_bits() would have realised the call is wrong and simply not copy data. Fixes: 4799ac8 ("tls: Add rx inline crypto offload") Signed-off-by: Jakub Kicinski <[email protected]> Reviewed-by: John Hurley <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 97e1caa commit eb3d38d

File tree

1 file changed

+22
-7
lines changed

1 file changed

+22
-7
lines changed

net/tls/tls_device.c

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ void handle_device_resync(struct sock *sk, u32 seq, u64 rcd_sn)
597597
static int tls_device_reencrypt(struct sock *sk, struct sk_buff *skb)
598598
{
599599
struct strp_msg *rxm = strp_msg(skb);
600-
int err = 0, offset = rxm->offset, copy, nsg;
600+
int err = 0, offset = rxm->offset, copy, nsg, data_len, pos;
601601
struct sk_buff *skb_iter, *unused;
602602
struct scatterlist sg[1];
603603
char *orig_buf, *buf;
@@ -628,9 +628,10 @@ static int tls_device_reencrypt(struct sock *sk, struct sk_buff *skb)
628628
else
629629
err = 0;
630630

631+
data_len = rxm->full_len - TLS_CIPHER_AES_GCM_128_TAG_SIZE;
632+
631633
if (skb_pagelen(skb) > offset) {
632-
copy = min_t(int, skb_pagelen(skb) - offset,
633-
rxm->full_len - TLS_CIPHER_AES_GCM_128_TAG_SIZE);
634+
copy = min_t(int, skb_pagelen(skb) - offset, data_len);
634635

635636
if (skb->decrypted)
636637
skb_store_bits(skb, offset, buf, copy);
@@ -639,16 +640,30 @@ static int tls_device_reencrypt(struct sock *sk, struct sk_buff *skb)
639640
buf += copy;
640641
}
641642

643+
pos = skb_pagelen(skb);
642644
skb_walk_frags(skb, skb_iter) {
643-
copy = min_t(int, skb_iter->len,
644-
rxm->full_len - offset + rxm->offset -
645-
TLS_CIPHER_AES_GCM_128_TAG_SIZE);
645+
int frag_pos;
646+
647+
/* Practically all frags must belong to msg if reencrypt
648+
* is needed with current strparser and coalescing logic,
649+
* but strparser may "get optimized", so let's be safe.
650+
*/
651+
if (pos + skb_iter->len <= offset)
652+
goto done_with_frag;
653+
if (pos >= data_len + rxm->offset)
654+
break;
655+
656+
frag_pos = offset - pos;
657+
copy = min_t(int, skb_iter->len - frag_pos,
658+
data_len + rxm->offset - offset);
646659

647660
if (skb_iter->decrypted)
648-
skb_store_bits(skb_iter, offset, buf, copy);
661+
skb_store_bits(skb_iter, frag_pos, buf, copy);
649662

650663
offset += copy;
651664
buf += copy;
665+
done_with_frag:
666+
pos += skb_iter->len;
652667
}
653668

654669
free_buf:

0 commit comments

Comments
 (0)