← Back to team overview

group.of.nepali.translators team mailing list archive

[Bug 1888715] Re: UDP data corruption caused by buggy udp_recvmsg() -> skb_copy_and_csum_datagram_msg()

 

** Also affects: linux (Ubuntu Xenial)
   Importance: Undecided
       Status: New

-- 
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:
  New

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