Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

udp: fix skb_copy_and_csum_datagram with odd segment sizes

When iteratively computing a checksum with csum_block_add, track the
offset "pos" to correctly rotate in csum_block_add when offset is odd.

The open coded implementation of skb_copy_and_csum_datagram did this.
With the switch to __skb_datagram_iter calling csum_and_copy_to_iter,
pos was reinitialized to 0 on each call.

Bring back the pos by passing it along with the csum to the callback.

Changes v1->v2
- pass csum value, instead of csump pointer (Alexander Duyck)

Link: https://lore.kernel.org/netdev/20210128152353.GB27281@optiplex/
Fixes: 950fcaecd5cc ("datagram: consolidate datagram copy to iter helpers")
Reported-by: Oliver Graute <oliver.graute@gmail.com>
Signed-off-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: Alexander Duyck <alexanderduyck@fb.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://lore.kernel.org/r/20210203192952.1849843-1-willemdebruijn.kernel@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Willem de Bruijn and committed by
Jakub Kicinski
52cbd23a 1d23a56b

+31 -13
+7 -1
include/linux/uio.h
··· 260 260 { 261 261 i->count = count; 262 262 } 263 - size_t csum_and_copy_to_iter(const void *addr, size_t bytes, void *csump, struct iov_iter *i); 263 + 264 + struct csum_state { 265 + __wsum csum; 266 + size_t off; 267 + }; 268 + 269 + size_t csum_and_copy_to_iter(const void *addr, size_t bytes, void *csstate, struct iov_iter *i); 264 270 size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); 265 271 bool csum_and_copy_from_iter_full(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); 266 272 size_t hash_and_copy_to_iter(const void *addr, size_t bytes, void *hashp,
+14 -10
lib/iov_iter.c
··· 592 592 } 593 593 594 594 static size_t csum_and_copy_to_pipe_iter(const void *addr, size_t bytes, 595 - __wsum *csum, struct iov_iter *i) 595 + struct csum_state *csstate, 596 + struct iov_iter *i) 596 597 { 597 598 struct pipe_inode_info *pipe = i->pipe; 598 599 unsigned int p_mask = pipe->ring_size - 1; 600 + __wsum sum = csstate->csum; 601 + size_t off = csstate->off; 599 602 unsigned int i_head; 600 603 size_t n, r; 601 - size_t off = 0; 602 - __wsum sum = *csum; 603 604 604 605 if (!sanity(i)) 605 606 return 0; ··· 622 621 i_head++; 623 622 } while (n); 624 623 i->count -= bytes; 625 - *csum = sum; 624 + csstate->csum = sum; 625 + csstate->off = off; 626 626 return bytes; 627 627 } 628 628 ··· 1524 1522 } 1525 1523 EXPORT_SYMBOL(csum_and_copy_from_iter_full); 1526 1524 1527 - size_t csum_and_copy_to_iter(const void *addr, size_t bytes, void *csump, 1525 + size_t csum_and_copy_to_iter(const void *addr, size_t bytes, void *_csstate, 1528 1526 struct iov_iter *i) 1529 1527 { 1528 + struct csum_state *csstate = _csstate; 1530 1529 const char *from = addr; 1531 - __wsum *csum = csump; 1532 1530 __wsum sum, next; 1533 - size_t off = 0; 1531 + size_t off; 1534 1532 1535 1533 if (unlikely(iov_iter_is_pipe(i))) 1536 - return csum_and_copy_to_pipe_iter(addr, bytes, csum, i); 1534 + return csum_and_copy_to_pipe_iter(addr, bytes, _csstate, i); 1537 1535 1538 - sum = *csum; 1536 + sum = csstate->csum; 1537 + off = csstate->off; 1539 1538 if (unlikely(iov_iter_is_discard(i))) { 1540 1539 WARN_ON(1); /* for now */ 1541 1540 return 0; ··· 1564 1561 off += v.iov_len; 1565 1562 }) 1566 1563 ) 1567 - *csum = sum; 1564 + csstate->csum = sum; 1565 + csstate->off = off; 1568 1566 return bytes; 1569 1567 } 1570 1568 EXPORT_SYMBOL(csum_and_copy_to_iter);
+10 -2
net/core/datagram.c
··· 721 721 struct iov_iter *to, int len, 722 722 __wsum *csump) 723 723 { 724 - return __skb_datagram_iter(skb, offset, to, len, true, 725 - csum_and_copy_to_iter, csump); 724 + struct csum_state csdata = { .csum = *csump }; 725 + int ret; 726 + 727 + ret = __skb_datagram_iter(skb, offset, to, len, true, 728 + csum_and_copy_to_iter, &csdata); 729 + if (ret) 730 + return ret; 731 + 732 + *csump = csdata.csum; 733 + return 0; 726 734 } 727 735 728 736 /**