| .. | .. |
|---|
| 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]); |
|---|