Commit 4909724b5dee8fb7c52bbe90afa40c65b17be9eb
Committed by
David S. Miller
1 parent
fb0d366b08
[COMPAT] net: SIOCGIFCONF data corruption
From: Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru> From http://bugzilla.kernel.org/show_bug.cgi?id=4746 There is user data corruption when using ioctl(SIOCGIFCONF) in 32-bit application running amd64 kernel. I do not think that this problem is exploitable, but any data corruption may lead to security problems. Following code demonstrates the problem #include <stdint.h> #include <stdio.h> #include <sys/time.h> #include <sys/socket.h> #include <net/if.h> #include <sys/ioctl.h> char buf[256]; main() { int s = socket(AF_INET, SOCK_DGRAM, 0); struct ifconf req; int i; req.ifc_buf = buf; req.ifc_len = 41; printf("Result %d\n", ioctl(s, SIOCGIFCONF, &req)); printf("Len %d\n", req.ifc_len); for (i = 41; i < 256; i++) if (buf[i] != 0) printf("Byte %d is corrupted\n", i); } Steps to reproduce: Compile the code above into 32-bit elf and run it. You'll get Result 0 Len 32 Byte 48 is corrupted Byte 52 is corrupted Byte 53 is corrupted Byte 54 is corrupted Byte 55 is corrupted Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 1 changed file with 3 additions and 5 deletions Side-by-side Diff
fs/compat_ioctl.c
... | ... | @@ -686,7 +686,8 @@ |
686 | 686 | |
687 | 687 | ifr = ifc.ifc_req; |
688 | 688 | ifr32 = compat_ptr(ifc32.ifcbuf); |
689 | - for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len; | |
689 | + for (i = 0, j = 0; | |
690 | + i + sizeof (struct ifreq32) < ifc32.ifc_len && j < ifc.ifc_len; | |
690 | 691 | i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) { |
691 | 692 | if (copy_in_user(ifr32, ifr, sizeof (struct ifreq32))) |
692 | 693 | return -EFAULT; |
... | ... | @@ -702,10 +703,7 @@ |
702 | 703 | i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32)); |
703 | 704 | ifc32.ifc_len = i; |
704 | 705 | } else { |
705 | - if (i <= ifc32.ifc_len) | |
706 | - ifc32.ifc_len = i; | |
707 | - else | |
708 | - ifc32.ifc_len = i - sizeof (struct ifreq32); | |
706 | + ifc32.ifc_len = i; | |
709 | 707 | } |
710 | 708 | if (copy_to_user(compat_ptr(arg), &ifc32, sizeof(struct ifconf32))) |
711 | 709 | return -EFAULT; |