Skip to content

Commit e87eb9a

Browse files
qsnHashcode
authored andcommitted
net: add length argument to skb_copy_and_csum_datagram_iovec
Without this length argument, we can read past the end of the iovec in memcpy_toiovec because we have no way of knowing the total length of the iovec's buffers. This is needed for stable kernels where 89c22d8c3b27 ("net: Fix skb csum races when peeking") has been backported but that don't have the ioviter conversion, which is almost all the stable trees <= 3.18. This also fixes a kernel crash for NFS servers when the client uses -onfsvers=3,proto=udp to mount the export. Change-Id: I1865e3d7a1faee42a5008a9ad58c4d3323ea4bab Signed-off-by: Sabrina Dubroca <sd@queasysnail.net> Reviewed-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
1 parent defced7 commit e87eb9a

7 files changed

Lines changed: 14 additions & 7 deletions

File tree

include/linux/skbuff.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2105,7 +2105,8 @@ extern int skb_copy_datagram_iovec(const struct sk_buff *from,
21052105
int size);
21062106
extern int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb,
21072107
int hlen,
2108-
struct iovec *iov);
2108+
struct iovec *iov,
2109+
int len);
21092110
extern int skb_copy_datagram_from_iovec(struct sk_buff *skb,
21102111
int offset,
21112112
const struct iovec *from,

net/core/datagram.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,7 @@ EXPORT_SYMBOL(__skb_checksum_complete);
677677
* @skb: skbuff
678678
* @hlen: hardware length
679679
* @iov: io vector
680+
* @len: amount of data to copy from skb to iov
680681
*
681682
* Caller _must_ check that skb will fit to this iovec.
682683
*
@@ -686,11 +687,14 @@ EXPORT_SYMBOL(__skb_checksum_complete);
686687
* can be modified!
687688
*/
688689
int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb,
689-
int hlen, struct iovec *iov)
690+
int hlen, struct iovec *iov, int len)
690691
{
691692
__wsum csum;
692693
int chunk = skb->len - hlen;
693694

695+
if (chunk > len)
696+
chunk = len;
697+
694698
if (!chunk)
695699
return 0;
696700

net/ipv4/tcp_input.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5187,7 +5187,7 @@ static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen)
51875187
err = skb_copy_datagram_iovec(skb, hlen, tp->ucopy.iov, chunk);
51885188
else
51895189
err = skb_copy_and_csum_datagram_iovec(skb, hlen,
5190-
tp->ucopy.iov);
5190+
tp->ucopy.iov, chunk);
51915191

51925192
if (!err) {
51935193
tp->ucopy.len -= chunk;

net/ipv4/udp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1213,7 +1213,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
12131213
else {
12141214
err = skb_copy_and_csum_datagram_iovec(skb,
12151215
sizeof(struct udphdr),
1216-
msg->msg_iov);
1216+
msg->msg_iov, copied);
12171217

12181218
if (err == -EINVAL)
12191219
goto csum_copy_err;

net/ipv6/raw.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
484484
goto csum_copy_err;
485485
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
486486
} else {
487-
err = skb_copy_and_csum_datagram_iovec(skb, 0, msg->msg_iov);
487+
err = skb_copy_and_csum_datagram_iovec(skb, 0, msg->msg_iov, copied);
488488
if (err == -EINVAL)
489489
goto csum_copy_err;
490490
}

net/ipv6/udp.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,8 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
387387
err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr),
388388
msg->msg_iov, copied );
389389
else {
390-
err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov);
390+
err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr),
391+
msg->msg_iov, copied);
391392
if (err == -EINVAL)
392393
goto csum_copy_err;
393394
}

net/rxrpc/ar-recvmsg.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
182182
msg->msg_iov, copy);
183183
} else {
184184
ret = skb_copy_and_csum_datagram_iovec(skb, offset,
185-
msg->msg_iov);
185+
msg->msg_iov,
186+
copy);
186187
if (ret == -EINVAL)
187188
goto csum_copy_error;
188189
}

0 commit comments

Comments
 (0)