Skip to content

Commit 0f71c9c

Browse files
dhowellskuba-moo
authored andcommitted
udp: Fix __ip_append_data()'s handling of MSG_SPLICE_PAGES
__ip_append_data() can get into an infinite loop when asked to splice into a partially-built UDP message that has more than the frag-limit data and up to the MTU limit. Something like: pipe(pfd); sfd = socket(AF_INET, SOCK_DGRAM, 0); connect(sfd, ...); send(sfd, buffer, 8161, MSG_CONFIRM|MSG_MORE); write(pfd[1], buffer, 8); splice(pfd[0], 0, sfd, 0, 0x4ffe0ul, 0); where the amount of data given to send() is dependent on the MTU size (in this instance an interface with an MTU of 8192). The problem is that the calculation of the amount to copy in __ip_append_data() goes negative in two places, and, in the second place, this gets subtracted from the length remaining, thereby increasing it. This happens when pagedlen > 0 (which happens for MSG_ZEROCOPY and MSG_SPLICE_PAGES), because the terms in: copy = datalen - transhdrlen - fraggap - pagedlen; then mostly cancel when pagedlen is substituted for, leaving just -fraggap. This causes: length -= copy + transhdrlen; to increase the length to more than the amount of data in msg->msg_iter, which causes skb_splice_from_iter() to be unable to fill the request and it returns less than 'copied' - which means that length never gets to 0 and we never exit the loop. Fix this by: (1) Insert a note about the dodgy calculation of 'copy'. (2) If MSG_SPLICE_PAGES, clear copy if it is negative from the above equation, so that 'offset' isn't regressed and 'length' isn't increased, which will mean that length and thus copy should match the amount left in the iterator. (3) When handling MSG_SPLICE_PAGES, give a warning and return -EIO if we're asked to splice more than is in the iterator. It might be better to not give the warning or even just give a 'short' write. [!] Note that this ought to also affect MSG_ZEROCOPY, but MSG_ZEROCOPY avoids the problem by simply assuming that everything asked for got copied, not just the amount that was in the iterator. This is a potential bug for the future. Fixes: 7ac7c98 ("udp: Convert udp_sendpage() to use MSG_SPLICE_PAGES") Reported-by: syzbot+f527b971b4bdc8e79f9e@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/000000000000881d0606004541d1@google.com/ Signed-off-by: David Howells <dhowells@redhat.com> cc: David Ahern <dsahern@kernel.org> cc: Jens Axboe <axboe@kernel.dk> Reviewed-by: Willem de Bruijn <willemb@google.com> Link: https://lore.kernel.org/r/1420063.1690904933@warthog.procyon.org.uk Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent a2d9831 commit 0f71c9c

File tree

1 file changed

+9
-0
lines changed

1 file changed

+9
-0
lines changed

net/ipv4/ip_output.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,10 +1158,15 @@ static int __ip_append_data(struct sock *sk,
11581158
}
11591159

11601160
copy = datalen - transhdrlen - fraggap - pagedlen;
1161+
/* [!] NOTE: copy will be negative if pagedlen>0
1162+
* because then the equation reduces to -fraggap.
1163+
*/
11611164
if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) {
11621165
err = -EFAULT;
11631166
kfree_skb(skb);
11641167
goto error;
1168+
} else if (flags & MSG_SPLICE_PAGES) {
1169+
copy = 0;
11651170
}
11661171

11671172
offset += copy;
@@ -1209,6 +1214,10 @@ static int __ip_append_data(struct sock *sk,
12091214
} else if (flags & MSG_SPLICE_PAGES) {
12101215
struct msghdr *msg = from;
12111216

1217+
err = -EIO;
1218+
if (WARN_ON_ONCE(copy > msg->msg_iter.count))
1219+
goto error;
1220+
12121221
err = skb_splice_from_iter(skb, &msg->msg_iter, copy,
12131222
sk->sk_allocation);
12141223
if (err < 0)

0 commit comments

Comments
 (0)