diff options
author | Andy Lutomirski <luto@amacapital.net> | 2013-05-22 17:07:44 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-05-29 02:55:41 -0400 |
commit | 1be374a0518a288147c6a7398792583200a67261 (patch) | |
tree | 83f0bbaa40655d1af02dc761b594f46958354a00 /net/socket.c | |
parent | f96ef988cc603487c03a6de07807b06cbe641829 (diff) |
net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg
To: linux-kernel@vger.kernel.org
Cc: x86@kernel.org, trinity@vger.kernel.org, Andy Lutomirski <luto@amacapital.net>, netdev@vger.kernel.org, "David S.
Miller" <davem@davemloft.net>
Subject: [PATCH 5/5] net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg
MSG_CMSG_COMPAT is (AFAIK) not intended to be part of the API --
it's a hack that steals a bit to indicate to other networking code
that a compat entry was used. So don't allow it from a non-compat
syscall.
This prevents an oops when running this code:
int main()
{
int s;
struct sockaddr_in addr;
struct msghdr *hdr;
char *highpage = mmap((void*)(TASK_SIZE_MAX - 4096), 4096,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (highpage == MAP_FAILED)
err(1, "mmap");
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == -1)
err(1, "socket");
addr.sin_family = AF_INET;
addr.sin_port = htons(1);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) != 0)
err(1, "connect");
void *evil = highpage + 4096 - COMPAT_MSGHDR_SIZE;
printf("Evil address is %p\n", evil);
if (syscall(__NR_sendmmsg, s, evil, 1, MSG_CMSG_COMPAT) < 0)
err(1, "sendmmsg");
return 0;
}
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/socket.c')
-rw-r--r-- | net/socket.c | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/net/socket.c b/net/socket.c index 6b94633ca61d..9ff6366fee13 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -2075,8 +2075,12 @@ SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, fla | |||
2075 | { | 2075 | { |
2076 | int fput_needed, err; | 2076 | int fput_needed, err; |
2077 | struct msghdr msg_sys; | 2077 | struct msghdr msg_sys; |
2078 | struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed); | 2078 | struct socket *sock; |
2079 | |||
2080 | if (flags & MSG_CMSG_COMPAT) | ||
2081 | return -EINVAL; | ||
2079 | 2082 | ||
2083 | sock = sockfd_lookup_light(fd, &err, &fput_needed); | ||
2080 | if (!sock) | 2084 | if (!sock) |
2081 | goto out; | 2085 | goto out; |
2082 | 2086 | ||
@@ -2149,6 +2153,8 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, | |||
2149 | SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg, | 2153 | SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg, |
2150 | unsigned int, vlen, unsigned int, flags) | 2154 | unsigned int, vlen, unsigned int, flags) |
2151 | { | 2155 | { |
2156 | if (flags & MSG_CMSG_COMPAT) | ||
2157 | return -EINVAL; | ||
2152 | return __sys_sendmmsg(fd, mmsg, vlen, flags); | 2158 | return __sys_sendmmsg(fd, mmsg, vlen, flags); |
2153 | } | 2159 | } |
2154 | 2160 | ||
@@ -2249,8 +2255,12 @@ SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg, | |||
2249 | { | 2255 | { |
2250 | int fput_needed, err; | 2256 | int fput_needed, err; |
2251 | struct msghdr msg_sys; | 2257 | struct msghdr msg_sys; |
2252 | struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed); | 2258 | struct socket *sock; |
2259 | |||
2260 | if (flags & MSG_CMSG_COMPAT) | ||
2261 | return -EINVAL; | ||
2253 | 2262 | ||
2263 | sock = sockfd_lookup_light(fd, &err, &fput_needed); | ||
2254 | if (!sock) | 2264 | if (!sock) |
2255 | goto out; | 2265 | goto out; |
2256 | 2266 | ||
@@ -2375,6 +2385,9 @@ SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg, | |||
2375 | int datagrams; | 2385 | int datagrams; |
2376 | struct timespec timeout_sys; | 2386 | struct timespec timeout_sys; |
2377 | 2387 | ||
2388 | if (flags & MSG_CMSG_COMPAT) | ||
2389 | return -EINVAL; | ||
2390 | |||
2378 | if (!timeout) | 2391 | if (!timeout) |
2379 | return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL); | 2392 | return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL); |
2380 | 2393 | ||
@@ -2492,15 +2505,31 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) | |||
2492 | (int __user *)a[4]); | 2505 | (int __user *)a[4]); |
2493 | break; | 2506 | break; |
2494 | case SYS_SENDMSG: | 2507 | case SYS_SENDMSG: |
2508 | if (a[2] & MSG_CMSG_COMPAT) { | ||
2509 | err = -EINVAL; | ||
2510 | break; | ||
2511 | } | ||
2495 | err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]); | 2512 | err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]); |
2496 | break; | 2513 | break; |
2497 | case SYS_SENDMMSG: | 2514 | case SYS_SENDMMSG: |
2515 | if (a[3] & MSG_CMSG_COMPAT) { | ||
2516 | err = -EINVAL; | ||
2517 | break; | ||
2518 | } | ||
2498 | err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]); | 2519 | err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]); |
2499 | break; | 2520 | break; |
2500 | case SYS_RECVMSG: | 2521 | case SYS_RECVMSG: |
2522 | if (a[2] & MSG_CMSG_COMPAT) { | ||
2523 | err = -EINVAL; | ||
2524 | break; | ||
2525 | } | ||
2501 | err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]); | 2526 | err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]); |
2502 | break; | 2527 | break; |
2503 | case SYS_RECVMMSG: | 2528 | case SYS_RECVMMSG: |
2529 | if (a[3] & MSG_CMSG_COMPAT) { | ||
2530 | err = -EINVAL; | ||
2531 | break; | ||
2532 | } | ||
2504 | err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3], | 2533 | err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3], |
2505 | (struct timespec __user *)a[4]); | 2534 | (struct timespec __user *)a[4]); |
2506 | break; | 2535 | break; |