root/net/compat.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_compat_msghdr
  2. cmsg_compat_nxthdr
  3. cmsghdr_from_user_compat_to_kern
  4. put_cmsg_compat
  5. scm_detach_fds_compat
  6. get_compat_bpf_fprog
  7. do_set_attach_filter
  8. compat_sock_setsockopt
  9. __compat_sys_setsockopt
  10. COMPAT_SYSCALL_DEFINE5
  11. __compat_sys_getsockopt
  12. COMPAT_SYSCALL_DEFINE5
  13. compat_mc_getsockopt
  14. __compat_sys_sendmsg
  15. COMPAT_SYSCALL_DEFINE3
  16. __compat_sys_sendmmsg
  17. COMPAT_SYSCALL_DEFINE4
  18. __compat_sys_recvmsg
  19. COMPAT_SYSCALL_DEFINE3
  20. __compat_sys_recvfrom
  21. COMPAT_SYSCALL_DEFINE4
  22. COMPAT_SYSCALL_DEFINE6
  23. COMPAT_SYSCALL_DEFINE5
  24. COMPAT_SYSCALL_DEFINE5
  25. COMPAT_SYSCALL_DEFINE2

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * 32bit Socket syscall emulation. Based on arch/sparc64/kernel/sys_sparc32.c.
   4  *
   5  * Copyright (C) 2000           VA Linux Co
   6  * Copyright (C) 2000           Don Dugger <n0ano@valinux.com>
   7  * Copyright (C) 1999           Arun Sharma <arun.sharma@intel.com>
   8  * Copyright (C) 1997,1998      Jakub Jelinek (jj@sunsite.mff.cuni.cz)
   9  * Copyright (C) 1997           David S. Miller (davem@caip.rutgers.edu)
  10  * Copyright (C) 2000           Hewlett-Packard Co.
  11  * Copyright (C) 2000           David Mosberger-Tang <davidm@hpl.hp.com>
  12  * Copyright (C) 2000,2001      Andi Kleen, SuSE Labs
  13  */
  14 
  15 #include <linux/kernel.h>
  16 #include <linux/gfp.h>
  17 #include <linux/fs.h>
  18 #include <linux/types.h>
  19 #include <linux/file.h>
  20 #include <linux/icmpv6.h>
  21 #include <linux/socket.h>
  22 #include <linux/syscalls.h>
  23 #include <linux/filter.h>
  24 #include <linux/compat.h>
  25 #include <linux/security.h>
  26 #include <linux/audit.h>
  27 #include <linux/export.h>
  28 
  29 #include <net/scm.h>
  30 #include <net/sock.h>
  31 #include <net/ip.h>
  32 #include <net/ipv6.h>
  33 #include <linux/uaccess.h>
  34 #include <net/compat.h>
  35 
  36 int get_compat_msghdr(struct msghdr *kmsg,
  37                       struct compat_msghdr __user *umsg,
  38                       struct sockaddr __user **save_addr,
  39                       struct iovec **iov)
  40 {
  41         struct compat_msghdr msg;
  42         ssize_t err;
  43 
  44         if (copy_from_user(&msg, umsg, sizeof(*umsg)))
  45                 return -EFAULT;
  46 
  47         kmsg->msg_flags = msg.msg_flags;
  48         kmsg->msg_namelen = msg.msg_namelen;
  49 
  50         if (!msg.msg_name)
  51                 kmsg->msg_namelen = 0;
  52 
  53         if (kmsg->msg_namelen < 0)
  54                 return -EINVAL;
  55 
  56         if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
  57                 kmsg->msg_namelen = sizeof(struct sockaddr_storage);
  58 
  59         kmsg->msg_control = compat_ptr(msg.msg_control);
  60         kmsg->msg_controllen = msg.msg_controllen;
  61 
  62         if (save_addr)
  63                 *save_addr = compat_ptr(msg.msg_name);
  64 
  65         if (msg.msg_name && kmsg->msg_namelen) {
  66                 if (!save_addr) {
  67                         err = move_addr_to_kernel(compat_ptr(msg.msg_name),
  68                                                   kmsg->msg_namelen,
  69                                                   kmsg->msg_name);
  70                         if (err < 0)
  71                                 return err;
  72                 }
  73         } else {
  74                 kmsg->msg_name = NULL;
  75                 kmsg->msg_namelen = 0;
  76         }
  77 
  78         if (msg.msg_iovlen > UIO_MAXIOV)
  79                 return -EMSGSIZE;
  80 
  81         kmsg->msg_iocb = NULL;
  82 
  83         err = compat_import_iovec(save_addr ? READ : WRITE,
  84                                    compat_ptr(msg.msg_iov), msg.msg_iovlen,
  85                                    UIO_FASTIOV, iov, &kmsg->msg_iter);
  86         return err < 0 ? err : 0;
  87 }
  88 
  89 /* Bleech... */
  90 #define CMSG_COMPAT_ALIGN(len)  ALIGN((len), sizeof(s32))
  91 
  92 #define CMSG_COMPAT_DATA(cmsg)                          \
  93         ((void __user *)((char __user *)(cmsg) + sizeof(struct compat_cmsghdr)))
  94 #define CMSG_COMPAT_SPACE(len)                          \
  95         (sizeof(struct compat_cmsghdr) + CMSG_COMPAT_ALIGN(len))
  96 #define CMSG_COMPAT_LEN(len)                            \
  97         (sizeof(struct compat_cmsghdr) + (len))
  98 
  99 #define CMSG_COMPAT_FIRSTHDR(msg)                       \
 100         (((msg)->msg_controllen) >= sizeof(struct compat_cmsghdr) ?     \
 101          (struct compat_cmsghdr __user *)((msg)->msg_control) :         \
 102          (struct compat_cmsghdr __user *)NULL)
 103 
 104 #define CMSG_COMPAT_OK(ucmlen, ucmsg, mhdr) \
 105         ((ucmlen) >= sizeof(struct compat_cmsghdr) && \
 106          (ucmlen) <= (unsigned long) \
 107          ((mhdr)->msg_controllen - \
 108           ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))
 109 
 110 static inline struct compat_cmsghdr __user *cmsg_compat_nxthdr(struct msghdr *msg,
 111                 struct compat_cmsghdr __user *cmsg, int cmsg_len)
 112 {
 113         char __user *ptr = (char __user *)cmsg + CMSG_COMPAT_ALIGN(cmsg_len);
 114         if ((unsigned long)(ptr + 1 - (char __user *)msg->msg_control) >
 115                         msg->msg_controllen)
 116                 return NULL;
 117         return (struct compat_cmsghdr __user *)ptr;
 118 }
 119 
 120 /* There is a lot of hair here because the alignment rules (and
 121  * thus placement) of cmsg headers and length are different for
 122  * 32-bit apps.  -DaveM
 123  */
 124 int cmsghdr_from_user_compat_to_kern(struct msghdr *kmsg, struct sock *sk,
 125                                unsigned char *stackbuf, int stackbuf_size)
 126 {
 127         struct compat_cmsghdr __user *ucmsg;
 128         struct cmsghdr *kcmsg, *kcmsg_base;
 129         compat_size_t ucmlen;
 130         __kernel_size_t kcmlen, tmp;
 131         int err = -EFAULT;
 132 
 133         BUILD_BUG_ON(sizeof(struct compat_cmsghdr) !=
 134                      CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr)));
 135 
 136         kcmlen = 0;
 137         kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
 138         ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg);
 139         while (ucmsg != NULL) {
 140                 if (get_user(ucmlen, &ucmsg->cmsg_len))
 141                         return -EFAULT;
 142 
 143                 /* Catch bogons. */
 144                 if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg))
 145                         return -EINVAL;
 146 
 147                 tmp = ((ucmlen - sizeof(*ucmsg)) + sizeof(struct cmsghdr));
 148                 tmp = CMSG_ALIGN(tmp);
 149                 kcmlen += tmp;
 150                 ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
 151         }
 152         if (kcmlen == 0)
 153                 return -EINVAL;
 154 
 155         /* The kcmlen holds the 64-bit version of the control length.
 156          * It may not be modified as we do not stick it into the kmsg
 157          * until we have successfully copied over all of the data
 158          * from the user.
 159          */
 160         if (kcmlen > stackbuf_size)
 161                 kcmsg_base = kcmsg = sock_kmalloc(sk, kcmlen, GFP_KERNEL);
 162         if (kcmsg == NULL)
 163                 return -ENOBUFS;
 164 
 165         /* Now copy them over neatly. */
 166         memset(kcmsg, 0, kcmlen);
 167         ucmsg = CMSG_COMPAT_FIRSTHDR(kmsg);
 168         while (ucmsg != NULL) {
 169                 if (__get_user(ucmlen, &ucmsg->cmsg_len))
 170                         goto Efault;
 171                 if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg))
 172                         goto Einval;
 173                 tmp = ((ucmlen - sizeof(*ucmsg)) + sizeof(struct cmsghdr));
 174                 if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp))
 175                         goto Einval;
 176                 kcmsg->cmsg_len = tmp;
 177                 tmp = CMSG_ALIGN(tmp);
 178                 if (__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level) ||
 179                     __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type) ||
 180                     copy_from_user(CMSG_DATA(kcmsg),
 181                                    CMSG_COMPAT_DATA(ucmsg),
 182                                    (ucmlen - sizeof(*ucmsg))))
 183                         goto Efault;
 184 
 185                 /* Advance. */
 186                 kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp);
 187                 ucmsg = cmsg_compat_nxthdr(kmsg, ucmsg, ucmlen);
 188         }
 189 
 190         /*
 191          * check the length of messages copied in is the same as the
 192          * what we get from the first loop
 193          */
 194         if ((char *)kcmsg - (char *)kcmsg_base != kcmlen)
 195                 goto Einval;
 196 
 197         /* Ok, looks like we made it.  Hook it up and return success. */
 198         kmsg->msg_control = kcmsg_base;
 199         kmsg->msg_controllen = kcmlen;
 200         return 0;
 201 
 202 Einval:
 203         err = -EINVAL;
 204 Efault:
 205         if (kcmsg_base != (struct cmsghdr *)stackbuf)
 206                 sock_kfree_s(sk, kcmsg_base, kcmlen);
 207         return err;
 208 }
 209 
 210 int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data)
 211 {
 212         struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
 213         struct compat_cmsghdr cmhdr;
 214         struct old_timeval32 ctv;
 215         struct old_timespec32 cts[3];
 216         int cmlen;
 217 
 218         if (cm == NULL || kmsg->msg_controllen < sizeof(*cm)) {
 219                 kmsg->msg_flags |= MSG_CTRUNC;
 220                 return 0; /* XXX: return error? check spec. */
 221         }
 222 
 223         if (!COMPAT_USE_64BIT_TIME) {
 224                 if (level == SOL_SOCKET && type == SO_TIMESTAMP_OLD) {
 225                         struct __kernel_old_timeval *tv = (struct __kernel_old_timeval *)data;
 226                         ctv.tv_sec = tv->tv_sec;
 227                         ctv.tv_usec = tv->tv_usec;
 228                         data = &ctv;
 229                         len = sizeof(ctv);
 230                 }
 231                 if (level == SOL_SOCKET &&
 232                     (type == SO_TIMESTAMPNS_OLD || type == SO_TIMESTAMPING_OLD)) {
 233                         int count = type == SO_TIMESTAMPNS_OLD ? 1 : 3;
 234                         int i;
 235                         struct timespec *ts = (struct timespec *)data;
 236                         for (i = 0; i < count; i++) {
 237                                 cts[i].tv_sec = ts[i].tv_sec;
 238                                 cts[i].tv_nsec = ts[i].tv_nsec;
 239                         }
 240                         data = &cts;
 241                         len = sizeof(cts[0]) * count;
 242                 }
 243         }
 244 
 245         cmlen = CMSG_COMPAT_LEN(len);
 246         if (kmsg->msg_controllen < cmlen) {
 247                 kmsg->msg_flags |= MSG_CTRUNC;
 248                 cmlen = kmsg->msg_controllen;
 249         }
 250         cmhdr.cmsg_level = level;
 251         cmhdr.cmsg_type = type;
 252         cmhdr.cmsg_len = cmlen;
 253 
 254         if (copy_to_user(cm, &cmhdr, sizeof cmhdr))
 255                 return -EFAULT;
 256         if (copy_to_user(CMSG_COMPAT_DATA(cm), data, cmlen - sizeof(struct compat_cmsghdr)))
 257                 return -EFAULT;
 258         cmlen = CMSG_COMPAT_SPACE(len);
 259         if (kmsg->msg_controllen < cmlen)
 260                 cmlen = kmsg->msg_controllen;
 261         kmsg->msg_control += cmlen;
 262         kmsg->msg_controllen -= cmlen;
 263         return 0;
 264 }
 265 
 266 void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm)
 267 {
 268         struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
 269         int fdmax = (kmsg->msg_controllen - sizeof(struct compat_cmsghdr)) / sizeof(int);
 270         int fdnum = scm->fp->count;
 271         struct file **fp = scm->fp->fp;
 272         int __user *cmfptr;
 273         int err = 0, i;
 274 
 275         if (fdnum < fdmax)
 276                 fdmax = fdnum;
 277 
 278         for (i = 0, cmfptr = (int __user *) CMSG_COMPAT_DATA(cm); i < fdmax; i++, cmfptr++) {
 279                 int new_fd;
 280                 err = security_file_receive(fp[i]);
 281                 if (err)
 282                         break;
 283                 err = get_unused_fd_flags(MSG_CMSG_CLOEXEC & kmsg->msg_flags
 284                                           ? O_CLOEXEC : 0);
 285                 if (err < 0)
 286                         break;
 287                 new_fd = err;
 288                 err = put_user(new_fd, cmfptr);
 289                 if (err) {
 290                         put_unused_fd(new_fd);
 291                         break;
 292                 }
 293                 /* Bump the usage count and install the file. */
 294                 fd_install(new_fd, get_file(fp[i]));
 295         }
 296 
 297         if (i > 0) {
 298                 int cmlen = CMSG_COMPAT_LEN(i * sizeof(int));
 299                 err = put_user(SOL_SOCKET, &cm->cmsg_level);
 300                 if (!err)
 301                         err = put_user(SCM_RIGHTS, &cm->cmsg_type);
 302                 if (!err)
 303                         err = put_user(cmlen, &cm->cmsg_len);
 304                 if (!err) {
 305                         cmlen = CMSG_COMPAT_SPACE(i * sizeof(int));
 306                         kmsg->msg_control += cmlen;
 307                         kmsg->msg_controllen -= cmlen;
 308                 }
 309         }
 310         if (i < fdnum)
 311                 kmsg->msg_flags |= MSG_CTRUNC;
 312 
 313         /*
 314          * All of the files that fit in the message have had their
 315          * usage counts incremented, so we just free the list.
 316          */
 317         __scm_destroy(scm);
 318 }
 319 
 320 /* allocate a 64-bit sock_fprog on the user stack for duration of syscall. */
 321 struct sock_fprog __user *get_compat_bpf_fprog(char __user *optval)
 322 {
 323         struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval;
 324         struct sock_fprog __user *kfprog = compat_alloc_user_space(sizeof(struct sock_fprog));
 325         struct compat_sock_fprog f32;
 326         struct sock_fprog f;
 327 
 328         if (copy_from_user(&f32, fprog32, sizeof(*fprog32)))
 329                 return NULL;
 330         memset(&f, 0, sizeof(f));
 331         f.len = f32.len;
 332         f.filter = compat_ptr(f32.filter);
 333         if (copy_to_user(kfprog, &f, sizeof(struct sock_fprog)))
 334                 return NULL;
 335 
 336         return kfprog;
 337 }
 338 EXPORT_SYMBOL_GPL(get_compat_bpf_fprog);
 339 
 340 static int do_set_attach_filter(struct socket *sock, int level, int optname,
 341                                 char __user *optval, unsigned int optlen)
 342 {
 343         struct sock_fprog __user *kfprog;
 344 
 345         kfprog = get_compat_bpf_fprog(optval);
 346         if (!kfprog)
 347                 return -EFAULT;
 348 
 349         return sock_setsockopt(sock, level, optname, (char __user *)kfprog,
 350                               sizeof(struct sock_fprog));
 351 }
 352 
 353 static int compat_sock_setsockopt(struct socket *sock, int level, int optname,
 354                                 char __user *optval, unsigned int optlen)
 355 {
 356         if (optname == SO_ATTACH_FILTER ||
 357             optname == SO_ATTACH_REUSEPORT_CBPF)
 358                 return do_set_attach_filter(sock, level, optname,
 359                                             optval, optlen);
 360         return sock_setsockopt(sock, level, optname, optval, optlen);
 361 }
 362 
 363 static int __compat_sys_setsockopt(int fd, int level, int optname,
 364                                    char __user *optval, unsigned int optlen)
 365 {
 366         int err;
 367         struct socket *sock;
 368 
 369         if (optlen > INT_MAX)
 370                 return -EINVAL;
 371 
 372         sock = sockfd_lookup(fd, &err);
 373         if (sock) {
 374                 err = security_socket_setsockopt(sock, level, optname);
 375                 if (err) {
 376                         sockfd_put(sock);
 377                         return err;
 378                 }
 379 
 380                 if (level == SOL_SOCKET)
 381                         err = compat_sock_setsockopt(sock, level,
 382                                         optname, optval, optlen);
 383                 else if (sock->ops->compat_setsockopt)
 384                         err = sock->ops->compat_setsockopt(sock, level,
 385                                         optname, optval, optlen);
 386                 else
 387                         err = sock->ops->setsockopt(sock, level,
 388                                         optname, optval, optlen);
 389                 sockfd_put(sock);
 390         }
 391         return err;
 392 }
 393 
 394 COMPAT_SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
 395                        char __user *, optval, unsigned int, optlen)
 396 {
 397         return __compat_sys_setsockopt(fd, level, optname, optval, optlen);
 398 }
 399 
 400 static int __compat_sys_getsockopt(int fd, int level, int optname,
 401                                    char __user *optval,
 402                                    int __user *optlen)
 403 {
 404         int err;
 405         struct socket *sock = sockfd_lookup(fd, &err);
 406 
 407         if (sock) {
 408                 err = security_socket_getsockopt(sock, level, optname);
 409                 if (err) {
 410                         sockfd_put(sock);
 411                         return err;
 412                 }
 413 
 414                 if (level == SOL_SOCKET)
 415                         err = sock_getsockopt(sock, level,
 416                                         optname, optval, optlen);
 417                 else if (sock->ops->compat_getsockopt)
 418                         err = sock->ops->compat_getsockopt(sock, level,
 419                                         optname, optval, optlen);
 420                 else
 421                         err = sock->ops->getsockopt(sock, level,
 422                                         optname, optval, optlen);
 423                 sockfd_put(sock);
 424         }
 425         return err;
 426 }
 427 
 428 COMPAT_SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname,
 429                        char __user *, optval, int __user *, optlen)
 430 {
 431         return __compat_sys_getsockopt(fd, level, optname, optval, optlen);
 432 }
 433 
 434 struct compat_group_req {
 435         __u32                            gr_interface;
 436         struct __kernel_sockaddr_storage gr_group
 437                 __aligned(4);
 438 } __packed;
 439 
 440 struct compat_group_source_req {
 441         __u32                            gsr_interface;
 442         struct __kernel_sockaddr_storage gsr_group
 443                 __aligned(4);
 444         struct __kernel_sockaddr_storage gsr_source
 445                 __aligned(4);
 446 } __packed;
 447 
 448 struct compat_group_filter {
 449         __u32                            gf_interface;
 450         struct __kernel_sockaddr_storage gf_group
 451                 __aligned(4);
 452         __u32                            gf_fmode;
 453         __u32                            gf_numsrc;
 454         struct __kernel_sockaddr_storage gf_slist[1]
 455                 __aligned(4);
 456 } __packed;
 457 
 458 #define __COMPAT_GF0_SIZE (sizeof(struct compat_group_filter) - \
 459                         sizeof(struct __kernel_sockaddr_storage))
 460 
 461 
 462 int compat_mc_setsockopt(struct sock *sock, int level, int optname,
 463         char __user *optval, unsigned int optlen,
 464         int (*setsockopt)(struct sock *, int, int, char __user *, unsigned int))
 465 {
 466         char __user     *koptval = optval;
 467         int             koptlen = optlen;
 468 
 469         switch (optname) {
 470         case MCAST_JOIN_GROUP:
 471         case MCAST_LEAVE_GROUP:
 472         {
 473                 struct compat_group_req __user *gr32 = (void __user *)optval;
 474                 struct group_req __user *kgr =
 475                         compat_alloc_user_space(sizeof(struct group_req));
 476                 u32 interface;
 477 
 478                 if (!access_ok(gr32, sizeof(*gr32)) ||
 479                     !access_ok(kgr, sizeof(struct group_req)) ||
 480                     __get_user(interface, &gr32->gr_interface) ||
 481                     __put_user(interface, &kgr->gr_interface) ||
 482                     copy_in_user(&kgr->gr_group, &gr32->gr_group,
 483                                 sizeof(kgr->gr_group)))
 484                         return -EFAULT;
 485                 koptval = (char __user *)kgr;
 486                 koptlen = sizeof(struct group_req);
 487                 break;
 488         }
 489         case MCAST_JOIN_SOURCE_GROUP:
 490         case MCAST_LEAVE_SOURCE_GROUP:
 491         case MCAST_BLOCK_SOURCE:
 492         case MCAST_UNBLOCK_SOURCE:
 493         {
 494                 struct compat_group_source_req __user *gsr32 = (void __user *)optval;
 495                 struct group_source_req __user *kgsr = compat_alloc_user_space(
 496                         sizeof(struct group_source_req));
 497                 u32 interface;
 498 
 499                 if (!access_ok(gsr32, sizeof(*gsr32)) ||
 500                     !access_ok(kgsr,
 501                         sizeof(struct group_source_req)) ||
 502                     __get_user(interface, &gsr32->gsr_interface) ||
 503                     __put_user(interface, &kgsr->gsr_interface) ||
 504                     copy_in_user(&kgsr->gsr_group, &gsr32->gsr_group,
 505                                 sizeof(kgsr->gsr_group)) ||
 506                     copy_in_user(&kgsr->gsr_source, &gsr32->gsr_source,
 507                                 sizeof(kgsr->gsr_source)))
 508                         return -EFAULT;
 509                 koptval = (char __user *)kgsr;
 510                 koptlen = sizeof(struct group_source_req);
 511                 break;
 512         }
 513         case MCAST_MSFILTER:
 514         {
 515                 struct compat_group_filter __user *gf32 = (void __user *)optval;
 516                 struct group_filter __user *kgf;
 517                 u32 interface, fmode, numsrc;
 518 
 519                 if (!access_ok(gf32, __COMPAT_GF0_SIZE) ||
 520                     __get_user(interface, &gf32->gf_interface) ||
 521                     __get_user(fmode, &gf32->gf_fmode) ||
 522                     __get_user(numsrc, &gf32->gf_numsrc))
 523                         return -EFAULT;
 524                 koptlen = optlen + sizeof(struct group_filter) -
 525                                 sizeof(struct compat_group_filter);
 526                 if (koptlen < GROUP_FILTER_SIZE(numsrc))
 527                         return -EINVAL;
 528                 kgf = compat_alloc_user_space(koptlen);
 529                 if (!access_ok(kgf, koptlen) ||
 530                     __put_user(interface, &kgf->gf_interface) ||
 531                     __put_user(fmode, &kgf->gf_fmode) ||
 532                     __put_user(numsrc, &kgf->gf_numsrc) ||
 533                     copy_in_user(&kgf->gf_group, &gf32->gf_group,
 534                                 sizeof(kgf->gf_group)) ||
 535                     (numsrc && copy_in_user(kgf->gf_slist, gf32->gf_slist,
 536                                 numsrc * sizeof(kgf->gf_slist[0]))))
 537                         return -EFAULT;
 538                 koptval = (char __user *)kgf;
 539                 break;
 540         }
 541 
 542         default:
 543                 break;
 544         }
 545         return setsockopt(sock, level, optname, koptval, koptlen);
 546 }
 547 EXPORT_SYMBOL(compat_mc_setsockopt);
 548 
 549 int compat_mc_getsockopt(struct sock *sock, int level, int optname,
 550         char __user *optval, int __user *optlen,
 551         int (*getsockopt)(struct sock *, int, int, char __user *, int __user *))
 552 {
 553         struct compat_group_filter __user *gf32 = (void __user *)optval;
 554         struct group_filter __user *kgf;
 555         int __user      *koptlen;
 556         u32 interface, fmode, numsrc;
 557         int klen, ulen, err;
 558 
 559         if (optname != MCAST_MSFILTER)
 560                 return getsockopt(sock, level, optname, optval, optlen);
 561 
 562         koptlen = compat_alloc_user_space(sizeof(*koptlen));
 563         if (!access_ok(optlen, sizeof(*optlen)) ||
 564             __get_user(ulen, optlen))
 565                 return -EFAULT;
 566 
 567         /* adjust len for pad */
 568         klen = ulen + sizeof(*kgf) - sizeof(*gf32);
 569 
 570         if (klen < GROUP_FILTER_SIZE(0))
 571                 return -EINVAL;
 572 
 573         if (!access_ok(koptlen, sizeof(*koptlen)) ||
 574             __put_user(klen, koptlen))
 575                 return -EFAULT;
 576 
 577         /* have to allow space for previous compat_alloc_user_space, too */
 578         kgf = compat_alloc_user_space(klen+sizeof(*optlen));
 579 
 580         if (!access_ok(gf32, __COMPAT_GF0_SIZE) ||
 581             __get_user(interface, &gf32->gf_interface) ||
 582             __get_user(fmode, &gf32->gf_fmode) ||
 583             __get_user(numsrc, &gf32->gf_numsrc) ||
 584             __put_user(interface, &kgf->gf_interface) ||
 585             __put_user(fmode, &kgf->gf_fmode) ||
 586             __put_user(numsrc, &kgf->gf_numsrc) ||
 587             copy_in_user(&kgf->gf_group, &gf32->gf_group, sizeof(kgf->gf_group)))
 588                 return -EFAULT;
 589 
 590         err = getsockopt(sock, level, optname, (char __user *)kgf, koptlen);
 591         if (err)
 592                 return err;
 593 
 594         if (!access_ok(koptlen, sizeof(*koptlen)) ||
 595             __get_user(klen, koptlen))
 596                 return -EFAULT;
 597 
 598         ulen = klen - (sizeof(*kgf)-sizeof(*gf32));
 599 
 600         if (!access_ok(optlen, sizeof(*optlen)) ||
 601             __put_user(ulen, optlen))
 602                 return -EFAULT;
 603 
 604         if (!access_ok(kgf, klen) ||
 605             !access_ok(gf32, ulen) ||
 606             __get_user(interface, &kgf->gf_interface) ||
 607             __get_user(fmode, &kgf->gf_fmode) ||
 608             __get_user(numsrc, &kgf->gf_numsrc) ||
 609             __put_user(interface, &gf32->gf_interface) ||
 610             __put_user(fmode, &gf32->gf_fmode) ||
 611             __put_user(numsrc, &gf32->gf_numsrc))
 612                 return -EFAULT;
 613         if (numsrc) {
 614                 int copylen;
 615 
 616                 klen -= GROUP_FILTER_SIZE(0);
 617                 copylen = numsrc * sizeof(gf32->gf_slist[0]);
 618                 if (copylen > klen)
 619                         copylen = klen;
 620                 if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen))
 621                         return -EFAULT;
 622         }
 623         return err;
 624 }
 625 EXPORT_SYMBOL(compat_mc_getsockopt);
 626 
 627 
 628 /* Argument list sizes for compat_sys_socketcall */
 629 #define AL(x) ((x) * sizeof(u32))
 630 static unsigned char nas[21] = {
 631         AL(0), AL(3), AL(3), AL(3), AL(2), AL(3),
 632         AL(3), AL(3), AL(4), AL(4), AL(4), AL(6),
 633         AL(6), AL(2), AL(5), AL(5), AL(3), AL(3),
 634         AL(4), AL(5), AL(4)
 635 };
 636 #undef AL
 637 
 638 static inline long __compat_sys_sendmsg(int fd,
 639                                         struct compat_msghdr __user *msg,
 640                                         unsigned int flags)
 641 {
 642         return __sys_sendmsg(fd, (struct user_msghdr __user *)msg,
 643                              flags | MSG_CMSG_COMPAT, false);
 644 }
 645 
 646 COMPAT_SYSCALL_DEFINE3(sendmsg, int, fd, struct compat_msghdr __user *, msg,
 647                        unsigned int, flags)
 648 {
 649         return __compat_sys_sendmsg(fd, msg, flags);
 650 }
 651 
 652 static inline long __compat_sys_sendmmsg(int fd,
 653                                          struct compat_mmsghdr __user *mmsg,
 654                                          unsigned int vlen, unsigned int flags)
 655 {
 656         return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
 657                               flags | MSG_CMSG_COMPAT, false);
 658 }
 659 
 660 COMPAT_SYSCALL_DEFINE4(sendmmsg, int, fd, struct compat_mmsghdr __user *, mmsg,
 661                        unsigned int, vlen, unsigned int, flags)
 662 {
 663         return __compat_sys_sendmmsg(fd, mmsg, vlen, flags);
 664 }
 665 
 666 static inline long __compat_sys_recvmsg(int fd,
 667                                         struct compat_msghdr __user *msg,
 668                                         unsigned int flags)
 669 {
 670         return __sys_recvmsg(fd, (struct user_msghdr __user *)msg,
 671                              flags | MSG_CMSG_COMPAT, false);
 672 }
 673 
 674 COMPAT_SYSCALL_DEFINE3(recvmsg, int, fd, struct compat_msghdr __user *, msg,
 675                        unsigned int, flags)
 676 {
 677         return __compat_sys_recvmsg(fd, msg, flags);
 678 }
 679 
 680 static inline long __compat_sys_recvfrom(int fd, void __user *buf,
 681                                          compat_size_t len, unsigned int flags,
 682                                          struct sockaddr __user *addr,
 683                                          int __user *addrlen)
 684 {
 685         return __sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr,
 686                               addrlen);
 687 }
 688 
 689 COMPAT_SYSCALL_DEFINE4(recv, int, fd, void __user *, buf, compat_size_t, len, unsigned int, flags)
 690 {
 691         return __compat_sys_recvfrom(fd, buf, len, flags, NULL, NULL);
 692 }
 693 
 694 COMPAT_SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, buf, compat_size_t, len,
 695                        unsigned int, flags, struct sockaddr __user *, addr,
 696                        int __user *, addrlen)
 697 {
 698         return __compat_sys_recvfrom(fd, buf, len, flags, addr, addrlen);
 699 }
 700 
 701 COMPAT_SYSCALL_DEFINE5(recvmmsg_time64, int, fd, struct compat_mmsghdr __user *, mmsg,
 702                        unsigned int, vlen, unsigned int, flags,
 703                        struct __kernel_timespec __user *, timeout)
 704 {
 705         return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
 706                               flags | MSG_CMSG_COMPAT, timeout, NULL);
 707 }
 708 
 709 #ifdef CONFIG_COMPAT_32BIT_TIME
 710 COMPAT_SYSCALL_DEFINE5(recvmmsg_time32, int, fd, struct compat_mmsghdr __user *, mmsg,
 711                        unsigned int, vlen, unsigned int, flags,
 712                        struct old_timespec32 __user *, timeout)
 713 {
 714         return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
 715                               flags | MSG_CMSG_COMPAT, NULL, timeout);
 716 }
 717 #endif
 718 
 719 COMPAT_SYSCALL_DEFINE2(socketcall, int, call, u32 __user *, args)
 720 {
 721         u32 a[AUDITSC_ARGS];
 722         unsigned int len;
 723         u32 a0, a1;
 724         int ret;
 725 
 726         if (call < SYS_SOCKET || call > SYS_SENDMMSG)
 727                 return -EINVAL;
 728         len = nas[call];
 729         if (len > sizeof(a))
 730                 return -EINVAL;
 731 
 732         if (copy_from_user(a, args, len))
 733                 return -EFAULT;
 734 
 735         ret = audit_socketcall_compat(len / sizeof(a[0]), a);
 736         if (ret)
 737                 return ret;
 738 
 739         a0 = a[0];
 740         a1 = a[1];
 741 
 742         switch (call) {
 743         case SYS_SOCKET:
 744                 ret = __sys_socket(a0, a1, a[2]);
 745                 break;
 746         case SYS_BIND:
 747                 ret = __sys_bind(a0, compat_ptr(a1), a[2]);
 748                 break;
 749         case SYS_CONNECT:
 750                 ret = __sys_connect(a0, compat_ptr(a1), a[2]);
 751                 break;
 752         case SYS_LISTEN:
 753                 ret = __sys_listen(a0, a1);
 754                 break;
 755         case SYS_ACCEPT:
 756                 ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), 0);
 757                 break;
 758         case SYS_GETSOCKNAME:
 759                 ret = __sys_getsockname(a0, compat_ptr(a1), compat_ptr(a[2]));
 760                 break;
 761         case SYS_GETPEERNAME:
 762                 ret = __sys_getpeername(a0, compat_ptr(a1), compat_ptr(a[2]));
 763                 break;
 764         case SYS_SOCKETPAIR:
 765                 ret = __sys_socketpair(a0, a1, a[2], compat_ptr(a[3]));
 766                 break;
 767         case SYS_SEND:
 768                 ret = __sys_sendto(a0, compat_ptr(a1), a[2], a[3], NULL, 0);
 769                 break;
 770         case SYS_SENDTO:
 771                 ret = __sys_sendto(a0, compat_ptr(a1), a[2], a[3],
 772                                    compat_ptr(a[4]), a[5]);
 773                 break;
 774         case SYS_RECV:
 775                 ret = __compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3],
 776                                             NULL, NULL);
 777                 break;
 778         case SYS_RECVFROM:
 779                 ret = __compat_sys_recvfrom(a0, compat_ptr(a1), a[2], a[3],
 780                                             compat_ptr(a[4]),
 781                                             compat_ptr(a[5]));
 782                 break;
 783         case SYS_SHUTDOWN:
 784                 ret = __sys_shutdown(a0, a1);
 785                 break;
 786         case SYS_SETSOCKOPT:
 787                 ret = __compat_sys_setsockopt(a0, a1, a[2],
 788                                               compat_ptr(a[3]), a[4]);
 789                 break;
 790         case SYS_GETSOCKOPT:
 791                 ret = __compat_sys_getsockopt(a0, a1, a[2],
 792                                               compat_ptr(a[3]),
 793                                               compat_ptr(a[4]));
 794                 break;
 795         case SYS_SENDMSG:
 796                 ret = __compat_sys_sendmsg(a0, compat_ptr(a1), a[2]);
 797                 break;
 798         case SYS_SENDMMSG:
 799                 ret = __compat_sys_sendmmsg(a0, compat_ptr(a1), a[2], a[3]);
 800                 break;
 801         case SYS_RECVMSG:
 802                 ret = __compat_sys_recvmsg(a0, compat_ptr(a1), a[2]);
 803                 break;
 804         case SYS_RECVMMSG:
 805                 ret = __sys_recvmmsg(a0, compat_ptr(a1), a[2],
 806                                      a[3] | MSG_CMSG_COMPAT, NULL,
 807                                      compat_ptr(a[4]));
 808                 break;
 809         case SYS_ACCEPT4:
 810                 ret = __sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]);
 811                 break;
 812         default:
 813                 ret = -EINVAL;
 814                 break;
 815         }
 816         return ret;
 817 }

/* [<][>][^][v][top][bottom][index][help] */