1 From d82ab26fe98468628ffccc82bdb3d970b28ff200 Mon Sep 17 00:00:00 2001
2 From: Andy Lutomirski <luto@amacapital.net>
3 Date: Wed, 22 May 2013 14:07:44 -0700
4 Subject: net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg
6 From: Andy Lutomirski <luto@amacapital.net>
8 [ Upstream commits 1be374a0518a288147c6a7398792583200a67261 and
9 a7526eb5d06b0084ef12d7b168d008fcf516caab ]
11 MSG_CMSG_COMPAT is (AFAIK) not intended to be part of the API --
12 it's a hack that steals a bit to indicate to other networking code
13 that a compat entry was used. So don't allow it from a non-compat
16 This prevents an oops when running this code:
21 struct sockaddr_in addr;
24 char *highpage = mmap((void*)(TASK_SIZE_MAX - 4096), 4096,
25 PROT_READ | PROT_WRITE,
26 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
27 if (highpage == MAP_FAILED)
30 s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
34 addr.sin_family = AF_INET;
35 addr.sin_port = htons(1);
36 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
37 if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) != 0)
40 void *evil = highpage + 4096 - COMPAT_MSGHDR_SIZE;
41 printf("Evil address is %p\n", evil);
43 if (syscall(__NR_sendmmsg, s, evil, 1, MSG_CMSG_COMPAT) < 0)
49 Signed-off-by: Andy Lutomirski <luto@amacapital.net>
50 Cc: David S. Miller <davem@davemloft.net>
51 Signed-off-by: David S. Miller <davem@davemloft.net>
52 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
54 include/linux/socket.h | 3 ++
55 net/compat.c | 13 ++++++++-
56 net/socket.c | 67 ++++++++++++++++++++++++++++++++-----------------
57 3 files changed, 59 insertions(+), 24 deletions(-)
59 --- a/include/linux/socket.h
60 +++ b/include/linux/socket.h
61 @@ -336,6 +336,9 @@ extern int put_cmsg(struct msghdr*, int
65 +/* The __sys_...msg variants allow MSG_CMSG_COMPAT */
66 +extern long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags);
67 +extern long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags);
68 extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
69 unsigned int flags, struct timespec *timeout);
70 extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg,
73 @@ -743,19 +743,25 @@ static unsigned char nas[21] = {
75 asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags)
77 - return sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
78 + if (flags & MSG_CMSG_COMPAT)
80 + return __sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
83 asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg,
84 unsigned vlen, unsigned int flags)
86 + if (flags & MSG_CMSG_COMPAT)
88 return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
89 flags | MSG_CMSG_COMPAT);
92 asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
94 - return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
95 + if (flags & MSG_CMSG_COMPAT)
97 + return __sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
100 asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len, unsigned flags)
101 @@ -777,6 +783,9 @@ asmlinkage long compat_sys_recvmmsg(int
103 struct timespec ktspec;
105 + if (flags & MSG_CMSG_COMPAT)
108 if (COMPAT_USE_64BIT_TIME)
109 return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
110 flags | MSG_CMSG_COMPAT,
113 @@ -1899,9 +1899,9 @@ struct used_address {
114 unsigned int name_len;
117 -static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
118 - struct msghdr *msg_sys, unsigned flags,
119 - struct used_address *used_address)
120 +static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
121 + struct msghdr *msg_sys, unsigned flags,
122 + struct used_address *used_address)
124 struct compat_msghdr __user *msg_compat =
125 (struct compat_msghdr __user *)msg;
126 @@ -2017,22 +2017,30 @@ out:
127 * BSD sendmsg interface
130 -SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags)
131 +long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
133 int fput_needed, err;
134 struct msghdr msg_sys;
135 - struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed);
136 + struct socket *sock;
138 + sock = sockfd_lookup_light(fd, &err, &fput_needed);
142 - err = __sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
143 + err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
145 fput_light(sock->file, fput_needed);
150 +SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags)
152 + if (flags & MSG_CMSG_COMPAT)
154 + return __sys_sendmsg(fd, msg, flags);
158 * Linux sendmmsg interface
160 @@ -2063,15 +2071,16 @@ int __sys_sendmmsg(int fd, struct mmsghd
162 while (datagrams < vlen) {
163 if (MSG_CMSG_COMPAT & flags) {
164 - err = __sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
165 - &msg_sys, flags, &used_address);
166 + err = ___sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
167 + &msg_sys, flags, &used_address);
170 err = __put_user(err, &compat_entry->msg_len);
173 - err = __sys_sendmsg(sock, (struct msghdr __user *)entry,
174 - &msg_sys, flags, &used_address);
175 + err = ___sys_sendmsg(sock,
176 + (struct msghdr __user *)entry,
177 + &msg_sys, flags, &used_address);
180 err = put_user(err, &entry->msg_len);
181 @@ -2095,11 +2104,13 @@ int __sys_sendmmsg(int fd, struct mmsghd
182 SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
183 unsigned int, vlen, unsigned int, flags)
185 + if (flags & MSG_CMSG_COMPAT)
187 return __sys_sendmmsg(fd, mmsg, vlen, flags);
190 -static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
191 - struct msghdr *msg_sys, unsigned flags, int nosec)
192 +static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
193 + struct msghdr *msg_sys, unsigned flags, int nosec)
195 struct compat_msghdr __user *msg_compat =
196 (struct compat_msghdr __user *)msg;
197 @@ -2192,23 +2203,31 @@ out:
198 * BSD recvmsg interface
201 -SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
202 - unsigned int, flags)
203 +long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags)
205 int fput_needed, err;
206 struct msghdr msg_sys;
207 - struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed);
208 + struct socket *sock;
210 + sock = sockfd_lookup_light(fd, &err, &fput_needed);
214 - err = __sys_recvmsg(sock, msg, &msg_sys, flags, 0);
215 + err = ___sys_recvmsg(sock, msg, &msg_sys, flags, 0);
217 fput_light(sock->file, fput_needed);
222 +SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
223 + unsigned int, flags)
225 + if (flags & MSG_CMSG_COMPAT)
227 + return __sys_recvmsg(fd, msg, flags);
231 * Linux recvmmsg interface
233 @@ -2246,17 +2265,18 @@ int __sys_recvmmsg(int fd, struct mmsghd
234 * No need to ask LSM for more than the first datagram.
236 if (MSG_CMSG_COMPAT & flags) {
237 - err = __sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
238 - &msg_sys, flags & ~MSG_WAITFORONE,
240 + err = ___sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
241 + &msg_sys, flags & ~MSG_WAITFORONE,
245 err = __put_user(err, &compat_entry->msg_len);
248 - err = __sys_recvmsg(sock, (struct msghdr __user *)entry,
249 - &msg_sys, flags & ~MSG_WAITFORONE,
251 + err = ___sys_recvmsg(sock,
252 + (struct msghdr __user *)entry,
253 + &msg_sys, flags & ~MSG_WAITFORONE,
257 err = put_user(err, &entry->msg_len);
258 @@ -2323,6 +2343,9 @@ SYSCALL_DEFINE5(recvmmsg, int, fd, struc
260 struct timespec timeout_sys;
262 + if (flags & MSG_CMSG_COMPAT)
266 return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL);