group.of.nepali.translators team mailing list archive
-
group.of.nepali.translators team
-
Mailing list archive
-
Message #37328
[Bug 1888715] Re: UDP data corruption caused by buggy udp_recvmsg() -> skb_copy_and_csum_datagram_msg()
The fix was already released as part of 4.4.0-190.220 for the upstream
stable update from bug #1892822.
** Changed in: linux (Ubuntu Xenial)
Status: New => Fix Released
--
You received this bug notification because you are a member of नेपाली
भाषा समायोजकहरुको समूह, which is subscribed to Xenial.
Matching subscriptions: Ubuntu 16.04 Bugs
https://bugs.launchpad.net/bugs/1888715
Title:
UDP data corruption caused by buggy udp_recvmsg() ->
skb_copy_and_csum_datagram_msg()
Status in linux package in Ubuntu:
Incomplete
Status in linux source package in Xenial:
Fix Released
Bug description:
The Xenial v4.4 kernel (https://kernel.ubuntu.com/git/ubuntu/ubuntu-
xenial.git/tag/?h=Ubuntu-4.4.0-184.214) lacks this upstream bug
fix("make skb_copy_datagram_msg() et.al. preserve ->msg_iter on erro"
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3278682123811dd8ef07de5eb701fc4548fcebf2);
as a result, the v4.4 kernel can deliver corrupt data to the
application when a corrupt packet is closely followed by a valid
packet, and actually the UDP payload of the corrupt packet is
delivered to the application with the "from IP/Port" of the valid
packet, so this is actually a security vulnerability that can be used
to trick the application to think the corrupt packet’s payload is sent
from the valid packet’s IP address/port, i.e. a source IP based
security authentication mechanism can be bypassed.
Details:
For a packet longer than 76 bytes (see line 3951,
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/skbuff.h?h=v5.8-rc6#n3948),
Linux delays the UDP checksum verification until the application
invokes the syscall recvmsg().
In the recvmsg() syscall handler, while Linux is copying the UDP
payload to the application’s memory, it calculates the UDP checksum.
If the calculated checksum doesn’t match the received checksum, Linux
drops the corrupt UDP packet, and then starts to process the next
packet (if any), and if the next packet is valid (i.e. the checksum is
correct), Linux will copy the valid UDP packet's payload to the
application’s receiver buffer.
The bug is: before Linux starts to copy the valid UDP packet, the data
structure used to track how many more bytes should be copied to the
application memory is not reset to what it was when the application
just entered the kernel by the syscall! Consequently, only a small
portion or none of the valid packet’s payload is copied to the
application’s receive buffer, and later when the application exits
from the kernel, actually most of the application’s receive buffer
contains the payload of the corrupt packet while recvmsg() returns the
size of the UDP payload of the valid packet. Note: this is actually a
security vulnerability that can be used to trick the application to
think the corrupt packet’s payload is sent from the valid packet’s IP
address/port -- so a source IP based security authentication mechanism
can be bypassed.
The bug was fixed in this 2017 patch “make skb_copy_datagram_msg()
et.al. preserve ->msg_iter on error
(https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3278682123811dd8ef07de5eb701fc4548fcebf2)”,
but unluckily the patch is only backported to the upstream v4.9+
kernels. I'm reporting this bug to request the bugfix to be backported
to the v4.4 Xenial kernel, which is still used by some users and has
not been EOL'ed (https://ubuntu.com/about/release-cycle).
I have the below one-line workaround patch to force the recvmsg() syscall handler to return to the userspace when Linux detects a corrupt UDP packet, so the application will invoke the syscall again to receive the next good UDP packet:
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1367,6 +1367,7 @@ csum_copy_err:
/* starting over for a new packet, but check if we need to yield */
cond_resched();
msg->msg_flags &= ~MSG_TRUNC;
+ return -EAGAIN;
goto try_again;
}
Note: the patch may not work well with blocking sockets, for which
typically the application doesn’t expect an error of -EAGAIN. I guess
it would be safer to return -EINTR instead.
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1888715/+subscriptions