📄 socket32.c
字号:
/* Copy back fixed up data, and adjust pointers. */ bufsz = (wp - workbuf); copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz); kmsg->msg_control = (struct cmsghdr *) (((char *)orig_cmsg_uptr) + bufsz); kmsg->msg_controllen = space_avail - bufsz; kfree(workbuf); return;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;}asmlinkage long sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags){ struct socket *sock; char address[MAX_SOCK_ADDR]; struct iovec iov[UIO_FASTIOV]; unsigned char ctl[sizeof(struct cmsghdr) + 20]; unsigned char *ctl_buf = ctl; struct msghdr kern_msg; int err, total_len; if(msghdr_from_user32_to_kern(&kern_msg, user_msg)) return -EFAULT; if(kern_msg.msg_iovlen > UIO_MAXIOV) return -EINVAL; err = verify_iovec32(&kern_msg, iov, address, VERIFY_READ); if (err < 0) goto out; total_len = err; if(kern_msg.msg_controllen) { err = cmsghdr_from_user32_to_kern(&kern_msg, ctl, sizeof(ctl)); if(err) goto out_freeiov; ctl_buf = kern_msg.msg_control; } kern_msg.msg_flags = user_flags; sock = sockfd_lookup(fd, &err); if (sock != NULL) { if (sock->file->f_flags & O_NONBLOCK) kern_msg.msg_flags |= MSG_DONTWAIT; err = sock_sendmsg(sock, &kern_msg, total_len); sockfd_put(sock); } /* N.B. Use kfree here, as kern_msg.msg_controllen might change? */ if(ctl_buf != ctl) kfree(ctl_buf);out_freeiov: if(kern_msg.msg_iov != iov) kfree(kern_msg.msg_iov);out: return err;}asmlinkage long sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags){ struct iovec iovstack[UIO_FASTIOV]; struct msghdr kern_msg; char addr[MAX_SOCK_ADDR]; struct socket *sock; struct iovec *iov = iovstack; struct sockaddr *uaddr; int *uaddr_len; unsigned long cmsg_ptr; int err, total_len, len = 0; if(msghdr_from_user32_to_kern(&kern_msg, user_msg)) return -EFAULT; if(kern_msg.msg_iovlen > UIO_MAXIOV) return -EINVAL; uaddr = kern_msg.msg_name; uaddr_len = &user_msg->msg_namelen; err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE); if (err < 0) goto out; total_len = err; cmsg_ptr = (unsigned long) kern_msg.msg_control; kern_msg.msg_flags = 0; sock = sockfd_lookup(fd, &err); if (sock != NULL) { struct scm_cookie scm; if (sock->file->f_flags & O_NONBLOCK) user_flags |= MSG_DONTWAIT; memset(&scm, 0, sizeof(scm)); err = sock->ops->recvmsg(sock, &kern_msg, total_len, user_flags, &scm); if(err >= 0) { len = err; if(!kern_msg.msg_control) { if(sock->passcred || scm.fp) kern_msg.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) kern_msg.msg_control != cmsg_ptr) cmsg32_recvmsg_fixup(&kern_msg, cmsg_ptr); /* Wheee... */ if(sock->passcred) put_cmsg32(&kern_msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm.creds), &scm.creds); if(scm.fp != NULL) scm_detach_fds32(&kern_msg, &scm); } } sockfd_put(sock); } if(uaddr != NULL && err >= 0) err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len); if(cmsg_ptr != 0 && err >= 0) { unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control); __kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr - cmsg_ptr); err |= __put_user(uclen, &user_msg->msg_controllen); } if(err >= 0) err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags); if(kern_msg.msg_iov != iov) kfree(kern_msg.msg_iov);out: if(err < 0) return err; return len;}extern asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen);static int do_set_attach_filter(int fd, int level, int optname, char *optval, int optlen){ struct sock_fprog32 { __u16 len; __u32 filter; } *fprog32 = (struct sock_fprog32 *)optval; struct sock_fprog kfprog; struct sock_filter *kfilter; unsigned int fsize; mm_segment_t old_fs; __u32 uptr; int ret; if (get_user(kfprog.len, &fprog32->len) || __get_user(uptr, &fprog32->filter)) return -EFAULT; kfprog.filter = (struct sock_filter *)A(uptr); fsize = kfprog.len * sizeof(struct sock_filter); kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL); if (kfilter == NULL) return -ENOMEM; if (copy_from_user(kfilter, kfprog.filter, fsize)) { kfree(kfilter); return -EFAULT; } kfprog.filter = kfilter; old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_setsockopt(fd, level, optname, (char *)&kfprog, sizeof(kfprog)); set_fs(old_fs); kfree(kfilter); return ret;}static int do_set_icmpv6_filter(int fd, int level, int optname, char *optval, int optlen){ struct icmp6_filter kfilter; mm_segment_t old_fs; int ret, i; if (copy_from_user(&kfilter, optval, sizeof(kfilter))) return -EFAULT; for (i = 0; i < 8; i += 2) { u32 tmp = kfilter.data[i]; kfilter.data[i] = kfilter.data[i + 1]; kfilter.data[i + 1] = tmp; } old_fs = get_fs(); set_fs(KERNEL_DS); ret = sys_setsockopt(fd, level, optname, (char *) &kfilter, sizeof(kfilter)); set_fs(old_fs); return ret;}asmlinkage long sys32_setsockopt(int fd, int level, int optname, char *optval, int optlen){ if (optname == SO_ATTACH_FILTER) return do_set_attach_filter(fd, level, optname, optval, optlen); if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER) return do_set_icmpv6_filter(fd, level, optname, optval, optlen); return sys_setsockopt(fd, level, optname, optval, optlen);}/* Argument list sizes for sys_socketcall */#define AL(x) ((x) * sizeof(u32))static 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_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 long sys32_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 = sys32_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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -