📄 sys_ia32.c
字号:
if(copy_to_user(cm, &cmhdr, sizeof cmhdr)) return; if(copy_to_user(CMSG32_DATA(cm), data, cmlen - sizeof(struct cmsghdr32))) return; cmlen = CMSG32_SPACE(len); kmsg->msg_control += cmlen; kmsg->msg_controllen -= cmlen;}static voidscm_detach_fds32 (struct msghdr *kmsg, struct scm_cookie *scm){ struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control; int fdmax = (kmsg->msg_controllen - sizeof(struct cmsghdr32)) / sizeof(int); int fdnum = scm->fp->count; struct file **fp = scm->fp->fp; int *cmfptr; int err = 0, i; if (fdnum < fdmax) fdmax = fdnum; for (i = 0, cmfptr = (int *) CMSG32_DATA(cm); i < fdmax; i++, cmfptr++) { int new_fd; err = get_unused_fd(); if (err < 0) break; new_fd = err; err = put_user(new_fd, cmfptr); if (err) { put_unused_fd(new_fd); break; } /* Bump the usage count and install the file. */ get_file(fp[i]); current->files->fd[new_fd] = fp[i]; } if (i > 0) { int cmlen = CMSG32_LEN(i * sizeof(int)); if (!err) err = put_user(SOL_SOCKET, &cm->cmsg_level); if (!err) err = put_user(SCM_RIGHTS, &cm->cmsg_type); if (!err) err = put_user(cmlen, &cm->cmsg_len); if (!err) { cmlen = CMSG32_SPACE(i * sizeof(int)); kmsg->msg_control += cmlen; kmsg->msg_controllen -= cmlen; } } if (i < fdnum) kmsg->msg_flags |= MSG_CTRUNC; /* * All of the files that fit in the message have had their * usage counts incremented, so we just free the list. */ __scm_destroy(scm);}/* * In these cases we (currently) can just copy to data over verbatim because all CMSGs * created by the kernel have well defined types which have the same layout in both the * 32-bit and 64-bit API. One must add some special cased conversions here if we start * sending control messages with incompatible types. * * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after * we do our work. The remaining cases are: * * SOL_IP IP_PKTINFO struct in_pktinfo 32-bit clean * IP_TTL int 32-bit clean * IP_TOS __u8 32-bit clean * IP_RECVOPTS variable length 32-bit clean * IP_RETOPTS variable length 32-bit clean * (these last two are clean because the types are defined * by the IPv4 protocol) * IP_RECVERR struct sock_extended_err + * struct sockaddr_in 32-bit clean * SOL_IPV6 IPV6_RECVERR struct sock_extended_err + * struct sockaddr_in6 32-bit clean * IPV6_PKTINFO struct in6_pktinfo 32-bit clean * IPV6_HOPLIMIT int 32-bit clean * IPV6_FLOWINFO u32 32-bit clean * IPV6_HOPOPTS ipv6 hop exthdr 32-bit clean * IPV6_DSTOPTS ipv6 dst exthdr(s) 32-bit clean * IPV6_RTHDR ipv6 routing exthdr 32-bit clean * IPV6_AUTHHDR ipv6 auth exthdr 32-bit clean */static voidcmsg32_recvmsg_fixup (struct msghdr *kmsg, unsigned long orig_cmsg_uptr){ unsigned char *workbuf, *wp; unsigned long bufsz, space_avail; struct cmsghdr *ucmsg; long err; bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr; space_avail = kmsg->msg_controllen + bufsz; wp = workbuf = kmalloc(bufsz, GFP_KERNEL); if (workbuf == NULL) goto fail; /* To make this more sane we assume the kernel sends back properly * formatted control messages. Because of how the kernel will truncate * the cmsg_len for MSG_TRUNC cases, we need not check that case either. */ ucmsg = (struct cmsghdr *) orig_cmsg_uptr; while (((unsigned long)ucmsg) < ((unsigned long)kmsg->msg_control)) { struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp; int clen64, clen32; /* * UCMSG is the 64-bit format CMSG entry in user-space. KCMSG32 is within * the kernel space temporary buffer we use to convert into a 32-bit style * CMSG. */ err = get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len); err |= get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level); err |= get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type); if (err) goto fail2; clen64 = kcmsg32->cmsg_len; copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg), clen64 - CMSG_ALIGN(sizeof(*ucmsg))); clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) + CMSG32_ALIGN(sizeof(struct cmsghdr32))); kcmsg32->cmsg_len = clen32; ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64)); wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32)); } /* Copy back fixed up data, and adjust pointers. */ bufsz = (wp - workbuf); if (copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz)) goto fail2; kmsg->msg_control = (struct cmsghdr *) (((char *)orig_cmsg_uptr) + bufsz); kmsg->msg_controllen = space_avail - bufsz; kfree(workbuf); return; fail2: kfree(workbuf); fail: /* * If we leave the 64-bit format CMSG chunks in there, the application could get * confused and crash. So to ensure greater recovery, we report no CMSGs. */ kmsg->msg_controllen += bufsz; kmsg->msg_control = (void *) orig_cmsg_uptr;}static inline voidsockfd_put (struct socket *sock){ fput(sock->file);}/* XXX This really belongs in some header file... -DaveM */#define MAX_SOCK_ADDR 128 /* 108 for Unix domain - 16 for IP, 16 for IPX, 24 for IPv6, about 80 for AX.25 */extern struct socket *sockfd_lookup (int fd, int *err);/* * BSD sendmsg interface */intsys32_sendmsg (int fd, struct msghdr32 *msg, unsigned flags){ struct socket *sock; char address[MAX_SOCK_ADDR]; struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; unsigned char ctl[sizeof(struct cmsghdr) + 20]; /* 20 is size of ipv6_pktinfo */ unsigned char *ctl_buf = ctl; struct msghdr msg_sys; int err, iov_size, total_len; size_t ctl_len; err = -EFAULT; if (get_msghdr32(&msg_sys, msg)) goto out; sock = sockfd_lookup(fd, &err); if (!sock) goto out; /* do not move before msg_sys is valid */ err = -EINVAL; if (msg_sys.msg_iovlen > UIO_MAXIOV) goto out_put; /* Check whether to allocate the iovec area*/ err = -ENOMEM; iov_size = msg_sys.msg_iovlen * sizeof(struct iovec32); if (msg_sys.msg_iovlen > UIO_FASTIOV) { iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL); if (!iov) goto out_put; } /* This will also move the address data into kernel space */ err = verify_iovec32(&msg_sys, iov, address, VERIFY_READ); if (err < 0) goto out_freeiov; total_len = err; err = -ENOBUFS; if (msg_sys.msg_controllen > INT_MAX) goto out_freeiov; if (msg_sys.msg_controllen) { ctl_len = sizeof(ctl); err = get_cmsghdr32(&msg_sys, ctl_buf, sock->sk, &ctl_len); if (err) goto out_freeiov; ctl_buf = msg_sys.msg_control; } msg_sys.msg_flags = flags; if (sock->file->f_flags & O_NONBLOCK) msg_sys.msg_flags |= MSG_DONTWAIT; err = sock_sendmsg(sock, &msg_sys, total_len); if (ctl_buf != ctl) sock_kfree_s(sock->sk, ctl_buf, ctl_len);out_freeiov: if (iov != iovstack) sock_kfree_s(sock->sk, iov, iov_size);out_put: sockfd_put(sock);out: return err;}/* * BSD recvmsg interface */intsys32_recvmsg (int fd, struct msghdr32 *msg, unsigned int flags){ struct socket *sock; struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov=iovstack; struct msghdr msg_sys; unsigned long cmsg_ptr; int err, iov_size, total_len, len; struct scm_cookie scm; /* kernel mode address */ char addr[MAX_SOCK_ADDR]; /* user mode address pointers */ struct sockaddr *uaddr; int *uaddr_len; err = -EFAULT; if (get_msghdr32(&msg_sys, msg)) goto out; sock = sockfd_lookup(fd, &err); if (!sock) goto out; err = -EINVAL; if (msg_sys.msg_iovlen > UIO_MAXIOV) goto out_put; /* Check whether to allocate the iovec area*/ err = -ENOMEM; iov_size = msg_sys.msg_iovlen * sizeof(struct iovec); if (msg_sys.msg_iovlen > UIO_FASTIOV) { iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL); if (!iov) goto out_put; } /* * Save the user-mode address (verify_iovec will change the * kernel msghdr to use the kernel address space) */ uaddr = msg_sys.msg_name; uaddr_len = &msg->msg_namelen; err = verify_iovec32(&msg_sys, iov, addr, VERIFY_WRITE); if (err < 0) goto out_freeiov; total_len=err; cmsg_ptr = (unsigned long)msg_sys.msg_control; msg_sys.msg_flags = 0; if (sock->file->f_flags & O_NONBLOCK) flags |= MSG_DONTWAIT; memset(&scm, 0, sizeof(scm)); lock_kernel(); { err = sock->ops->recvmsg(sock, &msg_sys, total_len, flags, &scm); if (err < 0) goto out_unlock_freeiov; len = err; if (!msg_sys.msg_control) { if (sock->passcred || scm.fp) msg_sys.msg_flags |= MSG_CTRUNC; if (scm.fp) __scm_destroy(&scm); } else { /* * If recvmsg processing itself placed some control messages into * user space, it's is using 64-bit CMSG processing, so we need to * fix it up before we tack on more stuff. */ if ((unsigned long) msg_sys.msg_control != cmsg_ptr) cmsg32_recvmsg_fixup(&msg_sys, cmsg_ptr); /* Wheee... */ if (sock->passcred) put_cmsg32(&msg_sys, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm.creds), &scm.creds); if (scm.fp != NULL) scm_detach_fds32(&msg_sys, &scm); } } unlock_kernel(); if (uaddr != NULL) { err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len); if (err < 0) goto out_freeiov; } err = __put_user(msg_sys.msg_flags, &msg->msg_flags); if (err) goto out_freeiov; err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, &msg->msg_controllen); if (err) goto out_freeiov; err = len; out_freeiov: if (iov != iovstack) sock_kfree_s(sock->sk, iov, iov_size); out_put: sockfd_put(sock); out: return err; out_unlock_freeiov: goto out_freeiov;}/* Argument list sizes for sys_socketcall */#define AL(x) ((x) * sizeof(u32))static const unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};#undef ALextern asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);extern asmlinkage long sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);extern asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen);extern asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len);extern asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len);extern asmlinkage long sys_send(int fd, void *buff, size_t len, unsigned flags);extern asmlinkage long sys_sendto(int fd, u32 buff, __kernel_size_t32 len, unsigned flags, u32 addr, int addr_len);extern asmlinkage long sys_recv(int fd, void *ubuf, size_t size, unsigned flags);extern asmlinkage long sys_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size, unsigned flags, u32 addr, u32 addr_len);extern asmlinkage long sys_setsockopt(int fd, int level, int optname, char *optval, int optlen);extern asmlinkage long sys_getsockopt(int fd, int level, int optname, u32 optval, u32 optlen);extern asmlinkage long sys_socket(int family, int type, int protocol);extern asmlinkage long sys_socketpair(int family, int type, int protocol, int usockvec[2]);extern asmlinkage long sys_shutdown(int fd, int how);extern asmlinkage long sys_listen(int fd, int backlog);asmlinkage longsys32_socketcall (int call, u32 *args){ int ret; u32 a[6]; u32 a0,a1; if (call<SYS_SOCKET||call>SYS_RECVMSG) return -EINVAL; if (copy_from_user(a, args, nas[call])) return -EFAULT; a0=a[0]; a1=a[1]; switch(call) { case SYS_SOCKET: ret = sys_socket(a0, a1, a[2]); break; case SYS_BIND: ret = sys_bind(a0, (struct sockaddr *)A(a1), a[2]); break; case SYS_CONNECT: ret = sys_connect(a0, (struct sockaddr *)A(a1), a[2]); break; case SYS_LISTEN: ret = sys_listen(a0, a1); break; case SYS_ACCEPT: ret = sys_accept(a0, (struct sockaddr *)A(a1), (int *)A(a[2])); break; case SYS_GETSOCKNAME: ret = sys_getsockname(a0, (struct sockaddr *)A(a1), (int *)A(a[2])); break; case SYS_GETPEERNAME: ret = sys_getpeername(a0, (struct sockaddr *)A(a1), (int *)A(a[2])); break; case SYS_SOCKETPAIR: ret = sys_socketpair(a0, a1, a[2], (int *)A(a[3])); break; case SYS_SEND: ret = sys_send(a0, (void *)A(a1), a[2], a[3]); break; case SYS_SENDTO: ret = sys_sendto(a0, a1, a[2], a[3], a[4], a[5]); break; case SYS_RECV: ret = sys_recv(a0, (void *)A(a1), a[2], a[3]); break; case SYS_RECVFROM: ret = sys_recvfrom(a0, a1, a[2], a[3], a[4], a[5]); break; case SYS_SHUTDOWN: ret = sys_shutdown(a0,a1); break; case SYS_SETSOCKOPT: ret = sys_setsockopt(a0, a1, a[2], (char *)A(a[3]), a[4]); break; case SYS_GETSOCKOPT: ret = sys_getsockopt(a0, a1, a[2], a[3], a[4]); break; case SYS_SENDMSG: ret = sys32_sendmsg(a0, (struct msghdr32 *) A(a1), a[2]); break; case SYS_RECVMSG: ret = sys32_recvmsg(a0, (struct msghdr32 *) A(a1), a[2]); break; default: ret = EINVAL; break; } return ret;}/* * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation.. * * This is really horribly ugly. */struct msgbuf32 { s32 mtype; char mtext[1]; };struct ipc_perm32 { key_t key; __kernel_uid_t32 uid; __kernel_gid_t32 gid; __kernel_uid_t32 cuid; __kernel_gid_t32 cgid; __kernel_mode_t32 mode; unsigned short seq;};struct ipc64_perm32 { key_t key; __kernel_uid32_t32 uid; __kernel_gid32_t32 gid; __kernel_uid32_t32 cuid; __kernel_gid32_t32 cgid; __kernel_mode_t32 mode; unsigned short __pad1; unsigned short seq; unsigned short __pad2; unsigned int unused1; unsigned int unused2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -