.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * 32bit Socket syscall emulation. Based on arch/sparc64/kernel/sys_sparc32.c. |
---|
3 | 4 | * |
---|
.. | .. |
---|
32 | 33 | #include <linux/uaccess.h> |
---|
33 | 34 | #include <net/compat.h> |
---|
34 | 35 | |
---|
35 | | -int get_compat_msghdr(struct msghdr *kmsg, |
---|
36 | | - struct compat_msghdr __user *umsg, |
---|
37 | | - struct sockaddr __user **save_addr, |
---|
38 | | - struct iovec **iov) |
---|
| 36 | +int __get_compat_msghdr(struct msghdr *kmsg, |
---|
| 37 | + struct compat_msghdr __user *umsg, |
---|
| 38 | + struct sockaddr __user **save_addr, |
---|
| 39 | + compat_uptr_t *ptr, compat_size_t *len) |
---|
39 | 40 | { |
---|
40 | 41 | struct compat_msghdr msg; |
---|
41 | 42 | ssize_t err; |
---|
.. | .. |
---|
55 | 56 | if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) |
---|
56 | 57 | kmsg->msg_namelen = sizeof(struct sockaddr_storage); |
---|
57 | 58 | |
---|
58 | | - kmsg->msg_control = compat_ptr(msg.msg_control); |
---|
| 59 | + kmsg->msg_control_is_user = true; |
---|
| 60 | + kmsg->msg_control_user = compat_ptr(msg.msg_control); |
---|
59 | 61 | kmsg->msg_controllen = msg.msg_controllen; |
---|
60 | 62 | |
---|
61 | 63 | if (save_addr) |
---|
.. | .. |
---|
78 | 80 | return -EMSGSIZE; |
---|
79 | 81 | |
---|
80 | 82 | kmsg->msg_iocb = NULL; |
---|
| 83 | + *ptr = msg.msg_iov; |
---|
| 84 | + *len = msg.msg_iovlen; |
---|
| 85 | + return 0; |
---|
| 86 | +} |
---|
81 | 87 | |
---|
82 | | - return compat_import_iovec(save_addr ? READ : WRITE, |
---|
83 | | - compat_ptr(msg.msg_iov), msg.msg_iovlen, |
---|
84 | | - UIO_FASTIOV, iov, &kmsg->msg_iter); |
---|
| 88 | +int get_compat_msghdr(struct msghdr *kmsg, |
---|
| 89 | + struct compat_msghdr __user *umsg, |
---|
| 90 | + struct sockaddr __user **save_addr, |
---|
| 91 | + struct iovec **iov) |
---|
| 92 | +{ |
---|
| 93 | + compat_uptr_t ptr; |
---|
| 94 | + compat_size_t len; |
---|
| 95 | + ssize_t err; |
---|
| 96 | + |
---|
| 97 | + err = __get_compat_msghdr(kmsg, umsg, save_addr, &ptr, &len); |
---|
| 98 | + if (err) |
---|
| 99 | + return err; |
---|
| 100 | + |
---|
| 101 | + err = import_iovec(save_addr ? READ : WRITE, compat_ptr(ptr), len, |
---|
| 102 | + UIO_FASTIOV, iov, &kmsg->msg_iter); |
---|
| 103 | + return err < 0 ? err : 0; |
---|
85 | 104 | } |
---|
86 | 105 | |
---|
87 | 106 | /* Bleech... */ |
---|
.. | .. |
---|
103 | 122 | ((ucmlen) >= sizeof(struct compat_cmsghdr) && \ |
---|
104 | 123 | (ucmlen) <= (unsigned long) \ |
---|
105 | 124 | ((mhdr)->msg_controllen - \ |
---|
106 | | - ((char *)(ucmsg) - (char *)(mhdr)->msg_control))) |
---|
| 125 | + ((char __user *)(ucmsg) - (char __user *)(mhdr)->msg_control_user))) |
---|
107 | 126 | |
---|
108 | 127 | static inline struct compat_cmsghdr __user *cmsg_compat_nxthdr(struct msghdr *msg, |
---|
109 | 128 | struct compat_cmsghdr __user *cmsg, int cmsg_len) |
---|
.. | .. |
---|
164 | 183 | memset(kcmsg, 0, kcmlen); |
---|
165 | 184 | ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg); |
---|
166 | 185 | while (ucmsg != NULL) { |
---|
167 | | - if (__get_user(ucmlen, &ucmsg->cmsg_len)) |
---|
| 186 | + struct compat_cmsghdr cmsg; |
---|
| 187 | + if (copy_from_user(&cmsg, ucmsg, sizeof(cmsg))) |
---|
168 | 188 | goto Efault; |
---|
169 | | - if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg)) |
---|
| 189 | + if (!CMSG_COMPAT_OK(cmsg.cmsg_len, ucmsg, kmsg)) |
---|
170 | 190 | goto Einval; |
---|
171 | | - tmp = ((ucmlen - sizeof(*ucmsg)) + sizeof(struct cmsghdr)); |
---|
| 191 | + tmp = ((cmsg.cmsg_len - sizeof(*ucmsg)) + sizeof(struct cmsghdr)); |
---|
172 | 192 | if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp)) |
---|
173 | 193 | goto Einval; |
---|
174 | 194 | kcmsg->cmsg_len = tmp; |
---|
| 195 | + kcmsg->cmsg_level = cmsg.cmsg_level; |
---|
| 196 | + kcmsg->cmsg_type = cmsg.cmsg_type; |
---|
175 | 197 | tmp = CMSG_ALIGN(tmp); |
---|
176 | | - if (__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level) || |
---|
177 | | - __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type) || |
---|
178 | | - copy_from_user(CMSG_DATA(kcmsg), |
---|
| 198 | + if (copy_from_user(CMSG_DATA(kcmsg), |
---|
179 | 199 | CMSG_COMPAT_DATA(ucmsg), |
---|
180 | | - (ucmlen - sizeof(*ucmsg)))) |
---|
| 200 | + (cmsg.cmsg_len - sizeof(*ucmsg)))) |
---|
181 | 201 | goto Efault; |
---|
182 | 202 | |
---|
183 | 203 | /* Advance. */ |
---|
184 | 204 | kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp); |
---|
185 | | - ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen); |
---|
| 205 | + ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, cmsg.cmsg_len); |
---|
186 | 206 | } |
---|
187 | 207 | |
---|
188 | 208 | /* |
---|
.. | .. |
---|
209 | 229 | { |
---|
210 | 230 | struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control; |
---|
211 | 231 | struct compat_cmsghdr cmhdr; |
---|
212 | | - struct compat_timeval ctv; |
---|
213 | | - struct compat_timespec cts[3]; |
---|
| 232 | + struct old_timeval32 ctv; |
---|
| 233 | + struct old_timespec32 cts[3]; |
---|
214 | 234 | int cmlen; |
---|
215 | 235 | |
---|
216 | 236 | if (cm == NULL || kmsg->msg_controllen < sizeof(*cm)) { |
---|
.. | .. |
---|
219 | 239 | } |
---|
220 | 240 | |
---|
221 | 241 | if (!COMPAT_USE_64BIT_TIME) { |
---|
222 | | - if (level == SOL_SOCKET && type == SCM_TIMESTAMP) { |
---|
223 | | - struct timeval *tv = (struct timeval *)data; |
---|
| 242 | + if (level == SOL_SOCKET && type == SO_TIMESTAMP_OLD) { |
---|
| 243 | + struct __kernel_old_timeval *tv = (struct __kernel_old_timeval *)data; |
---|
224 | 244 | ctv.tv_sec = tv->tv_sec; |
---|
225 | 245 | ctv.tv_usec = tv->tv_usec; |
---|
226 | 246 | data = &ctv; |
---|
227 | 247 | len = sizeof(ctv); |
---|
228 | 248 | } |
---|
229 | 249 | if (level == SOL_SOCKET && |
---|
230 | | - (type == SCM_TIMESTAMPNS || type == SCM_TIMESTAMPING)) { |
---|
231 | | - int count = type == SCM_TIMESTAMPNS ? 1 : 3; |
---|
| 250 | + (type == SO_TIMESTAMPNS_OLD || type == SO_TIMESTAMPING_OLD)) { |
---|
| 251 | + int count = type == SO_TIMESTAMPNS_OLD ? 1 : 3; |
---|
232 | 252 | int i; |
---|
233 | | - struct timespec *ts = (struct timespec *)data; |
---|
| 253 | + struct __kernel_old_timespec *ts = data; |
---|
234 | 254 | for (i = 0; i < count; i++) { |
---|
235 | 255 | cts[i].tv_sec = ts[i].tv_sec; |
---|
236 | 256 | cts[i].tv_nsec = ts[i].tv_nsec; |
---|
.. | .. |
---|
261 | 281 | return 0; |
---|
262 | 282 | } |
---|
263 | 283 | |
---|
264 | | -void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm) |
---|
| 284 | +static int scm_max_fds_compat(struct msghdr *msg) |
---|
265 | 285 | { |
---|
266 | | - struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control; |
---|
267 | | - int fdmax = (kmsg->msg_controllen - sizeof(struct compat_cmsghdr)) / sizeof(int); |
---|
268 | | - int fdnum = scm->fp->count; |
---|
269 | | - struct file **fp = scm->fp->fp; |
---|
270 | | - int __user *cmfptr; |
---|
| 286 | + if (msg->msg_controllen <= sizeof(struct compat_cmsghdr)) |
---|
| 287 | + return 0; |
---|
| 288 | + return (msg->msg_controllen - sizeof(struct compat_cmsghdr)) / sizeof(int); |
---|
| 289 | +} |
---|
| 290 | + |
---|
| 291 | +void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm) |
---|
| 292 | +{ |
---|
| 293 | + struct compat_cmsghdr __user *cm = |
---|
| 294 | + (struct compat_cmsghdr __user *)msg->msg_control; |
---|
| 295 | + unsigned int o_flags = (msg->msg_flags & MSG_CMSG_CLOEXEC) ? O_CLOEXEC : 0; |
---|
| 296 | + int fdmax = min_t(int, scm_max_fds_compat(msg), scm->fp->count); |
---|
| 297 | + int __user *cmsg_data = CMSG_COMPAT_DATA(cm); |
---|
271 | 298 | int err = 0, i; |
---|
272 | 299 | |
---|
273 | | - if (fdnum < fdmax) |
---|
274 | | - fdmax = fdnum; |
---|
275 | | - |
---|
276 | | - for (i = 0, cmfptr = (int __user *) CMSG_COMPAT_DATA(cm); i < fdmax; i++, cmfptr++) { |
---|
277 | | - int new_fd; |
---|
278 | | - err = security_file_receive(fp[i]); |
---|
279 | | - if (err) |
---|
280 | | - break; |
---|
281 | | - err = get_unused_fd_flags(MSG_CMSG_CLOEXEC & kmsg->msg_flags |
---|
282 | | - ? O_CLOEXEC : 0); |
---|
| 300 | + for (i = 0; i < fdmax; i++) { |
---|
| 301 | + err = receive_fd_user(scm->fp->fp[i], cmsg_data + i, o_flags); |
---|
283 | 302 | if (err < 0) |
---|
284 | 303 | break; |
---|
285 | | - new_fd = err; |
---|
286 | | - err = put_user(new_fd, cmfptr); |
---|
287 | | - if (err) { |
---|
288 | | - put_unused_fd(new_fd); |
---|
289 | | - break; |
---|
290 | | - } |
---|
291 | | - /* Bump the usage count and install the file. */ |
---|
292 | | - __receive_sock(fp[i]); |
---|
293 | | - fd_install(new_fd, get_file(fp[i])); |
---|
294 | 304 | } |
---|
295 | 305 | |
---|
296 | 306 | if (i > 0) { |
---|
297 | 307 | int cmlen = CMSG_COMPAT_LEN(i * sizeof(int)); |
---|
| 308 | + |
---|
298 | 309 | err = put_user(SOL_SOCKET, &cm->cmsg_level); |
---|
299 | 310 | if (!err) |
---|
300 | 311 | err = put_user(SCM_RIGHTS, &cm->cmsg_type); |
---|
.. | .. |
---|
302 | 313 | err = put_user(cmlen, &cm->cmsg_len); |
---|
303 | 314 | if (!err) { |
---|
304 | 315 | cmlen = CMSG_COMPAT_SPACE(i * sizeof(int)); |
---|
305 | | - kmsg->msg_control += cmlen; |
---|
306 | | - kmsg->msg_controllen -= cmlen; |
---|
| 316 | + if (msg->msg_controllen < cmlen) |
---|
| 317 | + cmlen = msg->msg_controllen; |
---|
| 318 | + msg->msg_control += cmlen; |
---|
| 319 | + msg->msg_controllen -= cmlen; |
---|
307 | 320 | } |
---|
308 | 321 | } |
---|
309 | | - if (i < fdnum) |
---|
310 | | - kmsg->msg_flags |= MSG_CTRUNC; |
---|
| 322 | + |
---|
| 323 | + if (i < scm->fp->count || (scm->fp->count && fdmax <= 0)) |
---|
| 324 | + msg->msg_flags |= MSG_CTRUNC; |
---|
311 | 325 | |
---|
312 | 326 | /* |
---|
313 | | - * All of the files that fit in the message have had their |
---|
314 | | - * usage counts incremented, so we just free the list. |
---|
| 327 | + * All of the files that fit in the message have had their usage counts |
---|
| 328 | + * incremented, so we just free the list. |
---|
315 | 329 | */ |
---|
316 | 330 | __scm_destroy(scm); |
---|
317 | 331 | } |
---|
318 | | - |
---|
319 | | -/* allocate a 64-bit sock_fprog on the user stack for duration of syscall. */ |
---|
320 | | -struct sock_fprog __user *get_compat_bpf_fprog(char __user *optval) |
---|
321 | | -{ |
---|
322 | | - struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval; |
---|
323 | | - struct sock_fprog __user *kfprog = compat_alloc_user_space(sizeof(struct sock_fprog)); |
---|
324 | | - struct compat_sock_fprog f32; |
---|
325 | | - struct sock_fprog f; |
---|
326 | | - |
---|
327 | | - if (copy_from_user(&f32, fprog32, sizeof(*fprog32))) |
---|
328 | | - return NULL; |
---|
329 | | - memset(&f, 0, sizeof(f)); |
---|
330 | | - f.len = f32.len; |
---|
331 | | - f.filter = compat_ptr(f32.filter); |
---|
332 | | - if (copy_to_user(kfprog, &f, sizeof(struct sock_fprog))) |
---|
333 | | - return NULL; |
---|
334 | | - |
---|
335 | | - return kfprog; |
---|
336 | | -} |
---|
337 | | -EXPORT_SYMBOL_GPL(get_compat_bpf_fprog); |
---|
338 | | - |
---|
339 | | -static int do_set_attach_filter(struct socket *sock, int level, int optname, |
---|
340 | | - char __user *optval, unsigned int optlen) |
---|
341 | | -{ |
---|
342 | | - struct sock_fprog __user *kfprog; |
---|
343 | | - |
---|
344 | | - kfprog = get_compat_bpf_fprog(optval); |
---|
345 | | - if (!kfprog) |
---|
346 | | - return -EFAULT; |
---|
347 | | - |
---|
348 | | - return sock_setsockopt(sock, level, optname, (char __user *)kfprog, |
---|
349 | | - sizeof(struct sock_fprog)); |
---|
350 | | -} |
---|
351 | | - |
---|
352 | | -static int do_set_sock_timeout(struct socket *sock, int level, |
---|
353 | | - int optname, char __user *optval, unsigned int optlen) |
---|
354 | | -{ |
---|
355 | | - struct compat_timeval __user *up = (struct compat_timeval __user *)optval; |
---|
356 | | - struct timeval ktime; |
---|
357 | | - mm_segment_t old_fs; |
---|
358 | | - int err; |
---|
359 | | - |
---|
360 | | - if (optlen < sizeof(*up)) |
---|
361 | | - return -EINVAL; |
---|
362 | | - if (!access_ok(VERIFY_READ, up, sizeof(*up)) || |
---|
363 | | - __get_user(ktime.tv_sec, &up->tv_sec) || |
---|
364 | | - __get_user(ktime.tv_usec, &up->tv_usec)) |
---|
365 | | - return -EFAULT; |
---|
366 | | - old_fs = get_fs(); |
---|
367 | | - set_fs(KERNEL_DS); |
---|
368 | | - err = sock_setsockopt(sock, level, optname, (char *)&ktime, sizeof(ktime)); |
---|
369 | | - set_fs(old_fs); |
---|
370 | | - |
---|
371 | | - return err; |
---|
372 | | -} |
---|
373 | | - |
---|
374 | | -static int compat_sock_setsockopt(struct socket *sock, int level, int optname, |
---|
375 | | - char __user *optval, unsigned int optlen) |
---|
376 | | -{ |
---|
377 | | - if (optname == SO_ATTACH_FILTER || |
---|
378 | | - optname == SO_ATTACH_REUSEPORT_CBPF) |
---|
379 | | - return do_set_attach_filter(sock, level, optname, |
---|
380 | | - optval, optlen); |
---|
381 | | - if (!COMPAT_USE_64BIT_TIME && |
---|
382 | | - (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) |
---|
383 | | - return do_set_sock_timeout(sock, level, optname, optval, optlen); |
---|
384 | | - |
---|
385 | | - return sock_setsockopt(sock, level, optname, optval, optlen); |
---|
386 | | -} |
---|
387 | | - |
---|
388 | | -static int __compat_sys_setsockopt(int fd, int level, int optname, |
---|
389 | | - char __user *optval, unsigned int optlen) |
---|
390 | | -{ |
---|
391 | | - int err; |
---|
392 | | - struct socket *sock = sockfd_lookup(fd, &err); |
---|
393 | | - |
---|
394 | | - if (sock) { |
---|
395 | | - err = security_socket_setsockopt(sock, level, optname); |
---|
396 | | - if (err) { |
---|
397 | | - sockfd_put(sock); |
---|
398 | | - return err; |
---|
399 | | - } |
---|
400 | | - |
---|
401 | | - if (level == SOL_SOCKET) |
---|
402 | | - err = compat_sock_setsockopt(sock, level, |
---|
403 | | - optname, optval, optlen); |
---|
404 | | - else if (sock->ops->compat_setsockopt) |
---|
405 | | - err = sock->ops->compat_setsockopt(sock, level, |
---|
406 | | - optname, optval, optlen); |
---|
407 | | - else |
---|
408 | | - err = sock->ops->setsockopt(sock, level, |
---|
409 | | - optname, optval, optlen); |
---|
410 | | - sockfd_put(sock); |
---|
411 | | - } |
---|
412 | | - return err; |
---|
413 | | -} |
---|
414 | | - |
---|
415 | | -COMPAT_SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname, |
---|
416 | | - char __user *, optval, unsigned int, optlen) |
---|
417 | | -{ |
---|
418 | | - return __compat_sys_setsockopt(fd, level, optname, optval, optlen); |
---|
419 | | -} |
---|
420 | | - |
---|
421 | | -static int do_get_sock_timeout(struct socket *sock, int level, int optname, |
---|
422 | | - char __user *optval, int __user *optlen) |
---|
423 | | -{ |
---|
424 | | - struct compat_timeval __user *up; |
---|
425 | | - struct timeval ktime; |
---|
426 | | - mm_segment_t old_fs; |
---|
427 | | - int len, err; |
---|
428 | | - |
---|
429 | | - up = (struct compat_timeval __user *) optval; |
---|
430 | | - if (get_user(len, optlen)) |
---|
431 | | - return -EFAULT; |
---|
432 | | - if (len < sizeof(*up)) |
---|
433 | | - return -EINVAL; |
---|
434 | | - len = sizeof(ktime); |
---|
435 | | - old_fs = get_fs(); |
---|
436 | | - set_fs(KERNEL_DS); |
---|
437 | | - err = sock_getsockopt(sock, level, optname, (char *) &ktime, &len); |
---|
438 | | - set_fs(old_fs); |
---|
439 | | - |
---|
440 | | - if (!err) { |
---|
441 | | - if (put_user(sizeof(*up), optlen) || |
---|
442 | | - !access_ok(VERIFY_WRITE, up, sizeof(*up)) || |
---|
443 | | - __put_user(ktime.tv_sec, &up->tv_sec) || |
---|
444 | | - __put_user(ktime.tv_usec, &up->tv_usec)) |
---|
445 | | - err = -EFAULT; |
---|
446 | | - } |
---|
447 | | - return err; |
---|
448 | | -} |
---|
449 | | - |
---|
450 | | -static int compat_sock_getsockopt(struct socket *sock, int level, int optname, |
---|
451 | | - char __user *optval, int __user *optlen) |
---|
452 | | -{ |
---|
453 | | - if (!COMPAT_USE_64BIT_TIME && |
---|
454 | | - (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) |
---|
455 | | - return do_get_sock_timeout(sock, level, optname, optval, optlen); |
---|
456 | | - return sock_getsockopt(sock, level, optname, optval, optlen); |
---|
457 | | -} |
---|
458 | | - |
---|
459 | | -int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp) |
---|
460 | | -{ |
---|
461 | | - struct compat_timeval __user *ctv; |
---|
462 | | - int err; |
---|
463 | | - struct timeval tv; |
---|
464 | | - |
---|
465 | | - if (COMPAT_USE_64BIT_TIME) |
---|
466 | | - return sock_get_timestamp(sk, userstamp); |
---|
467 | | - |
---|
468 | | - ctv = (struct compat_timeval __user *) userstamp; |
---|
469 | | - err = -ENOENT; |
---|
470 | | - sock_enable_timestamp(sk, SOCK_TIMESTAMP); |
---|
471 | | - tv = ktime_to_timeval(sock_read_timestamp(sk)); |
---|
472 | | - |
---|
473 | | - if (tv.tv_sec == -1) |
---|
474 | | - return err; |
---|
475 | | - if (tv.tv_sec == 0) { |
---|
476 | | - ktime_t kt = ktime_get_real(); |
---|
477 | | - sock_write_timestamp(sk, kt); |
---|
478 | | - tv = ktime_to_timeval(kt); |
---|
479 | | - } |
---|
480 | | - err = 0; |
---|
481 | | - if (put_user(tv.tv_sec, &ctv->tv_sec) || |
---|
482 | | - put_user(tv.tv_usec, &ctv->tv_usec)) |
---|
483 | | - err = -EFAULT; |
---|
484 | | - return err; |
---|
485 | | -} |
---|
486 | | -EXPORT_SYMBOL(compat_sock_get_timestamp); |
---|
487 | | - |
---|
488 | | -int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp) |
---|
489 | | -{ |
---|
490 | | - struct compat_timespec __user *ctv; |
---|
491 | | - int err; |
---|
492 | | - struct timespec ts; |
---|
493 | | - |
---|
494 | | - if (COMPAT_USE_64BIT_TIME) |
---|
495 | | - return sock_get_timestampns (sk, userstamp); |
---|
496 | | - |
---|
497 | | - ctv = (struct compat_timespec __user *) userstamp; |
---|
498 | | - err = -ENOENT; |
---|
499 | | - sock_enable_timestamp(sk, SOCK_TIMESTAMP); |
---|
500 | | - ts = ktime_to_timespec(sock_read_timestamp(sk)); |
---|
501 | | - if (ts.tv_sec == -1) |
---|
502 | | - return err; |
---|
503 | | - if (ts.tv_sec == 0) { |
---|
504 | | - ktime_t kt = ktime_get_real(); |
---|
505 | | - sock_write_timestamp(sk, kt); |
---|
506 | | - ts = ktime_to_timespec(kt); |
---|
507 | | - } |
---|
508 | | - err = 0; |
---|
509 | | - if (put_user(ts.tv_sec, &ctv->tv_sec) || |
---|
510 | | - put_user(ts.tv_nsec, &ctv->tv_nsec)) |
---|
511 | | - err = -EFAULT; |
---|
512 | | - return err; |
---|
513 | | -} |
---|
514 | | -EXPORT_SYMBOL(compat_sock_get_timestampns); |
---|
515 | | - |
---|
516 | | -static int __compat_sys_getsockopt(int fd, int level, int optname, |
---|
517 | | - char __user *optval, |
---|
518 | | - int __user *optlen) |
---|
519 | | -{ |
---|
520 | | - int err; |
---|
521 | | - struct socket *sock = sockfd_lookup(fd, &err); |
---|
522 | | - |
---|
523 | | - if (sock) { |
---|
524 | | - err = security_socket_getsockopt(sock, level, optname); |
---|
525 | | - if (err) { |
---|
526 | | - sockfd_put(sock); |
---|
527 | | - return err; |
---|
528 | | - } |
---|
529 | | - |
---|
530 | | - if (level == SOL_SOCKET) |
---|
531 | | - err = compat_sock_getsockopt(sock, level, |
---|
532 | | - optname, optval, optlen); |
---|
533 | | - else if (sock->ops->compat_getsockopt) |
---|
534 | | - err = sock->ops->compat_getsockopt(sock, level, |
---|
535 | | - optname, optval, optlen); |
---|
536 | | - else |
---|
537 | | - err = sock->ops->getsockopt(sock, level, |
---|
538 | | - optname, optval, optlen); |
---|
539 | | - sockfd_put(sock); |
---|
540 | | - } |
---|
541 | | - return err; |
---|
542 | | -} |
---|
543 | | - |
---|
544 | | -COMPAT_SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname, |
---|
545 | | - char __user *, optval, int __user *, optlen) |
---|
546 | | -{ |
---|
547 | | - return __compat_sys_getsockopt(fd, level, optname, optval, optlen); |
---|
548 | | -} |
---|
549 | | - |
---|
550 | | -struct compat_group_req { |
---|
551 | | - __u32 gr_interface; |
---|
552 | | - struct __kernel_sockaddr_storage gr_group |
---|
553 | | - __aligned(4); |
---|
554 | | -} __packed; |
---|
555 | | - |
---|
556 | | -struct compat_group_source_req { |
---|
557 | | - __u32 gsr_interface; |
---|
558 | | - struct __kernel_sockaddr_storage gsr_group |
---|
559 | | - __aligned(4); |
---|
560 | | - struct __kernel_sockaddr_storage gsr_source |
---|
561 | | - __aligned(4); |
---|
562 | | -} __packed; |
---|
563 | | - |
---|
564 | | -struct compat_group_filter { |
---|
565 | | - __u32 gf_interface; |
---|
566 | | - struct __kernel_sockaddr_storage gf_group |
---|
567 | | - __aligned(4); |
---|
568 | | - __u32 gf_fmode; |
---|
569 | | - __u32 gf_numsrc; |
---|
570 | | - struct __kernel_sockaddr_storage gf_slist[1] |
---|
571 | | - __aligned(4); |
---|
572 | | -} __packed; |
---|
573 | | - |
---|
574 | | -#define __COMPAT_GF0_SIZE (sizeof(struct compat_group_filter) - \ |
---|
575 | | - sizeof(struct __kernel_sockaddr_storage)) |
---|
576 | | - |
---|
577 | | - |
---|
578 | | -int compat_mc_setsockopt(struct sock *sock, int level, int optname, |
---|
579 | | - char __user *optval, unsigned int optlen, |
---|
580 | | - int (*setsockopt)(struct sock *, int, int, char __user *, unsigned int)) |
---|
581 | | -{ |
---|
582 | | - char __user *koptval = optval; |
---|
583 | | - int koptlen = optlen; |
---|
584 | | - |
---|
585 | | - switch (optname) { |
---|
586 | | - case MCAST_JOIN_GROUP: |
---|
587 | | - case MCAST_LEAVE_GROUP: |
---|
588 | | - { |
---|
589 | | - struct compat_group_req __user *gr32 = (void *)optval; |
---|
590 | | - struct group_req __user *kgr = |
---|
591 | | - compat_alloc_user_space(sizeof(struct group_req)); |
---|
592 | | - u32 interface; |
---|
593 | | - |
---|
594 | | - if (!access_ok(VERIFY_READ, gr32, sizeof(*gr32)) || |
---|
595 | | - !access_ok(VERIFY_WRITE, kgr, sizeof(struct group_req)) || |
---|
596 | | - __get_user(interface, &gr32->gr_interface) || |
---|
597 | | - __put_user(interface, &kgr->gr_interface) || |
---|
598 | | - copy_in_user(&kgr->gr_group, &gr32->gr_group, |
---|
599 | | - sizeof(kgr->gr_group))) |
---|
600 | | - return -EFAULT; |
---|
601 | | - koptval = (char __user *)kgr; |
---|
602 | | - koptlen = sizeof(struct group_req); |
---|
603 | | - break; |
---|
604 | | - } |
---|
605 | | - case MCAST_JOIN_SOURCE_GROUP: |
---|
606 | | - case MCAST_LEAVE_SOURCE_GROUP: |
---|
607 | | - case MCAST_BLOCK_SOURCE: |
---|
608 | | - case MCAST_UNBLOCK_SOURCE: |
---|
609 | | - { |
---|
610 | | - struct compat_group_source_req __user *gsr32 = (void *)optval; |
---|
611 | | - struct group_source_req __user *kgsr = compat_alloc_user_space( |
---|
612 | | - sizeof(struct group_source_req)); |
---|
613 | | - u32 interface; |
---|
614 | | - |
---|
615 | | - if (!access_ok(VERIFY_READ, gsr32, sizeof(*gsr32)) || |
---|
616 | | - !access_ok(VERIFY_WRITE, kgsr, |
---|
617 | | - sizeof(struct group_source_req)) || |
---|
618 | | - __get_user(interface, &gsr32->gsr_interface) || |
---|
619 | | - __put_user(interface, &kgsr->gsr_interface) || |
---|
620 | | - copy_in_user(&kgsr->gsr_group, &gsr32->gsr_group, |
---|
621 | | - sizeof(kgsr->gsr_group)) || |
---|
622 | | - copy_in_user(&kgsr->gsr_source, &gsr32->gsr_source, |
---|
623 | | - sizeof(kgsr->gsr_source))) |
---|
624 | | - return -EFAULT; |
---|
625 | | - koptval = (char __user *)kgsr; |
---|
626 | | - koptlen = sizeof(struct group_source_req); |
---|
627 | | - break; |
---|
628 | | - } |
---|
629 | | - case MCAST_MSFILTER: |
---|
630 | | - { |
---|
631 | | - struct compat_group_filter __user *gf32 = (void *)optval; |
---|
632 | | - struct group_filter __user *kgf; |
---|
633 | | - u32 interface, fmode, numsrc; |
---|
634 | | - |
---|
635 | | - if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) || |
---|
636 | | - __get_user(interface, &gf32->gf_interface) || |
---|
637 | | - __get_user(fmode, &gf32->gf_fmode) || |
---|
638 | | - __get_user(numsrc, &gf32->gf_numsrc)) |
---|
639 | | - return -EFAULT; |
---|
640 | | - koptlen = optlen + sizeof(struct group_filter) - |
---|
641 | | - sizeof(struct compat_group_filter); |
---|
642 | | - if (koptlen < GROUP_FILTER_SIZE(numsrc)) |
---|
643 | | - return -EINVAL; |
---|
644 | | - kgf = compat_alloc_user_space(koptlen); |
---|
645 | | - if (!access_ok(VERIFY_WRITE, kgf, koptlen) || |
---|
646 | | - __put_user(interface, &kgf->gf_interface) || |
---|
647 | | - __put_user(fmode, &kgf->gf_fmode) || |
---|
648 | | - __put_user(numsrc, &kgf->gf_numsrc) || |
---|
649 | | - copy_in_user(&kgf->gf_group, &gf32->gf_group, |
---|
650 | | - sizeof(kgf->gf_group)) || |
---|
651 | | - (numsrc && copy_in_user(kgf->gf_slist, gf32->gf_slist, |
---|
652 | | - numsrc * sizeof(kgf->gf_slist[0])))) |
---|
653 | | - return -EFAULT; |
---|
654 | | - koptval = (char __user *)kgf; |
---|
655 | | - break; |
---|
656 | | - } |
---|
657 | | - |
---|
658 | | - default: |
---|
659 | | - break; |
---|
660 | | - } |
---|
661 | | - return setsockopt(sock, level, optname, koptval, koptlen); |
---|
662 | | -} |
---|
663 | | -EXPORT_SYMBOL(compat_mc_setsockopt); |
---|
664 | | - |
---|
665 | | -int compat_mc_getsockopt(struct sock *sock, int level, int optname, |
---|
666 | | - char __user *optval, int __user *optlen, |
---|
667 | | - int (*getsockopt)(struct sock *, int, int, char __user *, int __user *)) |
---|
668 | | -{ |
---|
669 | | - struct compat_group_filter __user *gf32 = (void *)optval; |
---|
670 | | - struct group_filter __user *kgf; |
---|
671 | | - int __user *koptlen; |
---|
672 | | - u32 interface, fmode, numsrc; |
---|
673 | | - int klen, ulen, err; |
---|
674 | | - |
---|
675 | | - if (optname != MCAST_MSFILTER) |
---|
676 | | - return getsockopt(sock, level, optname, optval, optlen); |
---|
677 | | - |
---|
678 | | - koptlen = compat_alloc_user_space(sizeof(*koptlen)); |
---|
679 | | - if (!access_ok(VERIFY_READ, optlen, sizeof(*optlen)) || |
---|
680 | | - __get_user(ulen, optlen)) |
---|
681 | | - return -EFAULT; |
---|
682 | | - |
---|
683 | | - /* adjust len for pad */ |
---|
684 | | - klen = ulen + sizeof(*kgf) - sizeof(*gf32); |
---|
685 | | - |
---|
686 | | - if (klen < GROUP_FILTER_SIZE(0)) |
---|
687 | | - return -EINVAL; |
---|
688 | | - |
---|
689 | | - if (!access_ok(VERIFY_WRITE, koptlen, sizeof(*koptlen)) || |
---|
690 | | - __put_user(klen, koptlen)) |
---|
691 | | - return -EFAULT; |
---|
692 | | - |
---|
693 | | - /* have to allow space for previous compat_alloc_user_space, too */ |
---|
694 | | - kgf = compat_alloc_user_space(klen+sizeof(*optlen)); |
---|
695 | | - |
---|
696 | | - if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) || |
---|
697 | | - __get_user(interface, &gf32->gf_interface) || |
---|
698 | | - __get_user(fmode, &gf32->gf_fmode) || |
---|
699 | | - __get_user(numsrc, &gf32->gf_numsrc) || |
---|
700 | | - __put_user(interface, &kgf->gf_interface) || |
---|
701 | | - __put_user(fmode, &kgf->gf_fmode) || |
---|
702 | | - __put_user(numsrc, &kgf->gf_numsrc) || |
---|
703 | | - copy_in_user(&kgf->gf_group, &gf32->gf_group, sizeof(kgf->gf_group))) |
---|
704 | | - return -EFAULT; |
---|
705 | | - |
---|
706 | | - err = getsockopt(sock, level, optname, (char __user *)kgf, koptlen); |
---|
707 | | - if (err) |
---|
708 | | - return err; |
---|
709 | | - |
---|
710 | | - if (!access_ok(VERIFY_READ, koptlen, sizeof(*koptlen)) || |
---|
711 | | - __get_user(klen, koptlen)) |
---|
712 | | - return -EFAULT; |
---|
713 | | - |
---|
714 | | - ulen = klen - (sizeof(*kgf)-sizeof(*gf32)); |
---|
715 | | - |
---|
716 | | - if (!access_ok(VERIFY_WRITE, optlen, sizeof(*optlen)) || |
---|
717 | | - __put_user(ulen, optlen)) |
---|
718 | | - return -EFAULT; |
---|
719 | | - |
---|
720 | | - if (!access_ok(VERIFY_READ, kgf, klen) || |
---|
721 | | - !access_ok(VERIFY_WRITE, gf32, ulen) || |
---|
722 | | - __get_user(interface, &kgf->gf_interface) || |
---|
723 | | - __get_user(fmode, &kgf->gf_fmode) || |
---|
724 | | - __get_user(numsrc, &kgf->gf_numsrc) || |
---|
725 | | - __put_user(interface, &gf32->gf_interface) || |
---|
726 | | - __put_user(fmode, &gf32->gf_fmode) || |
---|
727 | | - __put_user(numsrc, &gf32->gf_numsrc)) |
---|
728 | | - return -EFAULT; |
---|
729 | | - if (numsrc) { |
---|
730 | | - int copylen; |
---|
731 | | - |
---|
732 | | - klen -= GROUP_FILTER_SIZE(0); |
---|
733 | | - copylen = numsrc * sizeof(gf32->gf_slist[0]); |
---|
734 | | - if (copylen > klen) |
---|
735 | | - copylen = klen; |
---|
736 | | - if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen)) |
---|
737 | | - return -EFAULT; |
---|
738 | | - } |
---|
739 | | - return err; |
---|
740 | | -} |
---|
741 | | -EXPORT_SYMBOL(compat_mc_getsockopt); |
---|
742 | | - |
---|
743 | 332 | |
---|
744 | 333 | /* Argument list sizes for compat_sys_socketcall */ |
---|
745 | 334 | #define AL(x) ((x) * sizeof(u32)) |
---|
.. | .. |
---|
814 | 403 | return __compat_sys_recvfrom(fd, buf, len, flags, addr, addrlen); |
---|
815 | 404 | } |
---|
816 | 405 | |
---|
817 | | -static int __compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg, |
---|
818 | | - unsigned int vlen, unsigned int flags, |
---|
819 | | - struct compat_timespec __user *timeout) |
---|
820 | | -{ |
---|
821 | | - int datagrams; |
---|
822 | | - struct timespec ktspec; |
---|
823 | | - |
---|
824 | | - if (timeout == NULL) |
---|
825 | | - return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, |
---|
826 | | - flags | MSG_CMSG_COMPAT, NULL); |
---|
827 | | - |
---|
828 | | - if (compat_get_timespec(&ktspec, timeout)) |
---|
829 | | - return -EFAULT; |
---|
830 | | - |
---|
831 | | - datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, |
---|
832 | | - flags | MSG_CMSG_COMPAT, &ktspec); |
---|
833 | | - if (datagrams > 0 && compat_put_timespec(&ktspec, timeout)) |
---|
834 | | - datagrams = -EFAULT; |
---|
835 | | - |
---|
836 | | - return datagrams; |
---|
837 | | -} |
---|
838 | | - |
---|
839 | | -COMPAT_SYSCALL_DEFINE5(recvmmsg, int, fd, struct compat_mmsghdr __user *, mmsg, |
---|
| 406 | +COMPAT_SYSCALL_DEFINE5(recvmmsg_time64, int, fd, struct compat_mmsghdr __user *, mmsg, |
---|
840 | 407 | unsigned int, vlen, unsigned int, flags, |
---|
841 | | - struct compat_timespec __user *, timeout) |
---|
| 408 | + struct __kernel_timespec __user *, timeout) |
---|
842 | 409 | { |
---|
843 | | - return __compat_sys_recvmmsg(fd, mmsg, vlen, flags, timeout); |
---|
| 410 | + return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, |
---|
| 411 | + flags | MSG_CMSG_COMPAT, timeout, NULL); |
---|
844 | 412 | } |
---|
| 413 | + |
---|
| 414 | +#ifdef CONFIG_COMPAT_32BIT_TIME |
---|
| 415 | +COMPAT_SYSCALL_DEFINE5(recvmmsg_time32, int, fd, struct compat_mmsghdr __user *, mmsg, |
---|
| 416 | + unsigned int, vlen, unsigned int, flags, |
---|
| 417 | + struct old_timespec32 __user *, timeout) |
---|
| 418 | +{ |
---|
| 419 | + return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen, |
---|
| 420 | + flags | MSG_CMSG_COMPAT, NULL, timeout); |
---|
| 421 | +} |
---|
| 422 | +#endif |
---|
845 | 423 | |
---|
846 | 424 | COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args) |
---|
847 | 425 | { |
---|
.. | .. |
---|
911 | 489 | ret = __sys_shutdown(a0, a1); |
---|
912 | 490 | break; |
---|
913 | 491 | case SYS_SETSOCKOPT: |
---|
914 | | - ret = __compat_sys_setsockopt(a0, a1, a[2], |
---|
915 | | - compat_ptr(a[3]), a[4]); |
---|
| 492 | + ret = __sys_setsockopt(a0, a1, a[2], compat_ptr(a[3]), a[4]); |
---|
916 | 493 | break; |
---|
917 | 494 | case SYS_GETSOCKOPT: |
---|
918 | | - ret = __compat_sys_getsockopt(a0, a1, a[2], |
---|
919 | | - compat_ptr(a[3]), |
---|
920 | | - compat_ptr(a[4])); |
---|
| 495 | + ret = __sys_getsockopt(a0, a1, a[2], compat_ptr(a[3]), |
---|
| 496 | + compat_ptr(a[4])); |
---|
921 | 497 | break; |
---|
922 | 498 | case SYS_SENDMSG: |
---|
923 | 499 | ret = __compat_sys_sendmsg(a0, compat_ptr(a1), a[2]); |
---|
.. | .. |
---|
929 | 505 | ret = __compat_sys_recvmsg(a0, compat_ptr(a1), a[2]); |
---|
930 | 506 | break; |
---|
931 | 507 | case SYS_RECVMMSG: |
---|
932 | | - ret = __compat_sys_recvmmsg(a0, compat_ptr(a1), a[2], a[3], |
---|
933 | | - compat_ptr(a[4])); |
---|
| 508 | + ret = __sys_recvmmsg(a0, compat_ptr(a1), a[2], |
---|
| 509 | + a[3] | MSG_CMSG_COMPAT, NULL, |
---|
| 510 | + compat_ptr(a[4])); |
---|
934 | 511 | break; |
---|
935 | 512 | case SYS_ACCEPT4: |
---|
936 | 513 | ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]); |
---|