diff options
author | Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru> | 2005-11-20 16:41:59 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2005-11-20 16:41:59 -0500 |
commit | 4909724b5dee8fb7c52bbe90afa40c65b17be9eb (patch) | |
tree | 7611a0f01ff0b0a1389928683b4223c160123d2a /fs | |
parent | fb0d366b0803571f06a5b838f02c6706fc287995 (diff) |
[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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/compat_ioctl.c | 8 |
1 files changed, 3 insertions, 5 deletions
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 31b7efd94d66..43a2508ac696 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c | |||
@@ -686,7 +686,8 @@ static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) | |||
686 | 686 | ||
687 | ifr = ifc.ifc_req; | 687 | ifr = ifc.ifc_req; |
688 | ifr32 = compat_ptr(ifc32.ifcbuf); | 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 | i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) { | 691 | i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) { |
691 | if (copy_in_user(ifr32, ifr, sizeof (struct ifreq32))) | 692 | if (copy_in_user(ifr32, ifr, sizeof (struct ifreq32))) |
692 | return -EFAULT; | 693 | return -EFAULT; |
@@ -702,10 +703,7 @@ static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) | |||
702 | i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32)); | 703 | i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32)); |
703 | ifc32.ifc_len = i; | 704 | ifc32.ifc_len = i; |
704 | } else { | 705 | } else { |
705 | if (i <= ifc32.ifc_len) | 706 | ifc32.ifc_len = i; |
706 | ifc32.ifc_len = i; | ||
707 | else | ||
708 | ifc32.ifc_len = i - sizeof (struct ifreq32); | ||
709 | } | 707 | } |
710 | if (copy_to_user(compat_ptr(arg), &ifc32, sizeof(struct ifconf32))) | 708 | if (copy_to_user(compat_ptr(arg), &ifc32, sizeof(struct ifconf32))) |
711 | return -EFAULT; | 709 | return -EFAULT; |