I found this bug while running under mips64, but it also effects
other 64bit architectures that have 32bit userspace compatibility.
I verified the problem exists with 2.6.12 on mips64 and x86_64.
Only kernels with CONFIG_COMPAT enabled should be effected (as
MSG_CMSG_COMPAT is defined as 0 otherwise).
Programs that make use of sendmsg/recvmsg with a large iovec will
cause the leak. The below test program will cause a OOM DoS rather
quickly.
My original post to linux-mips mailing list follows.
--
Dave Johnson
Starent Networks
============
sendmsg()/recvmsg() syscalls from o32/n32 apps to a 64bit kernel will
cause a kernel memory leak if iov_len > UIO_FASTIOV for each syscall!
This is because both sys_sendmsg() and verify_compat_iovec() kmalloc a
new iovec structure. Only the one from sys_sendmsg() is free'ed.
I wrote a simple test program to confirm this after identifying the
problem:
http://davej.org/programs/testsendmsg.c
Running it shows the leak in the slab:
$ grep '^size-256 ' /proc/slabinfo
size-256 55972 55972 280 14 1 : tunables 32 16 8 : slabdata 3998 3998 0 : globalstat 58914 55972 4001 3 0 0 46 0 : cpustat 3806737 4480 3755027 240
$ ./testsendmsg
iterations=100 vec_size=16 block_size=256
$ grep '^size-256 ' /proc/slabinfo
size-256 56168 56168 280 14 1 : tunables 32 16 8 : slabdata 4012 4012 0 : globalstat 59110 56168 4015 3 0 0 46 0 : cpustat 3853259 4494 3801362 240
$ ./testsendmsg
iterations=100 vec_size=16 block_size=256
$ grep '^size-256 ' /proc/slabinfo
size-256 56378 56378 280 14 1 : tunables 32 16 8 : slabdata 4027 4027 0 : globalstat 59320 56378 4030 3 0 0 46 0 : cpustat 3853910 4509 3801828 240
$ ./testsendmsg
iterations=100 vec_size=16 block_size=256
$ grep '^size-256 ' /proc/slabinfo
size-256 56574 56574 280 14 1 : tunables 32 16 8 : slabdata 4041 4041 0 : globalstat 59516 56574 4044 3 0 0 46 0 : cpustat 3854888 4523 3802620 240
$ ./testsendmsg
iterations=100 vec_size=16 block_size=256
$ grep '^size-256 ' /proc/slabinfo
size-256 56756 56756 280 14 1 : tunables 32 16 8 : slabdata 4054 4054 0 : globalstat 59698 56756 4057 3 0 0 46 0 : cpustat 3856397 4536 3803942 240
$ ./testsendmsg
iterations=100 vec_size=16 block_size=256
$ grep '^size-256 ' /proc/slabinfo
size-256 56966 56966 280 14 1 : tunables 32 16 8 : slabdata 4069 4069 0 : globalstat 59908 56966 4072 3 0 0 46 0 : cpustat 3858528 4551 3805888 240
$ ./testsendmsg
iterations=100 vec_size=16 block_size=256
$ grep '^size-256 ' /proc/slabinfo
size-256 57176 57176 280 14 1 : tunables 32 16 8 : slabdata 4084 4084 0 : globalstat 60118 57176 4087 3 0 0 46 0 : cpustat 3863987 4566 3811162 240
$ ./testsendmsg
iterations=100 vec_size=16 block_size=256
$ grep '^size-256 ' /proc/slabinfo
size-256 57358 57358 280 14 1 : tunables 32 16 8 : slabdata 4097 4097 0 : globalstat 60300 57358 4100 3 0 0 46 0 : cpustat 3864397 4579 3811385 240
Note that the below fix will break solaris_sendmsg()/solaris_recvmsg()
as it also calls verify_compat_iovec() but expects it to malloc
internally.
======================
diff -Nru a/net/compat.c b/net/compat.c
--- a/net/compat.c 2005-07-29 16:12:39 -04:00
+++ b/net/compat.c 2005-07-29 16:12:39 -04:00
@@ -91,20 +91,11 @@
} else
kern_msg->msg_name = NULL;
- if(kern_msg->msg_iovlen > UIO_FASTIOV) {
- kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec),
- GFP_KERNEL);
- if(!kern_iov)
- return -ENOMEM;
- }
-
tot_len = iov_from_user_compat_to_kern(kern_iov,
(struct compat_iovec __user *)kern_msg->msg_iov,
kern_msg->msg_iovlen);
if(tot_len >= 0)
kern_msg->msg_iov = kern_iov;
- else if(kern_msg->msg_iovlen > UIO_FASTIOV)
- kfree(kern_iov);
return tot_len;
}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
|
|