📄 sys_ia32.c
字号:
set_fs (KERNEL_DS); ret = sys_getrlimit(resource, &r); set_fs (old_fs); if (!ret) { ret = put_user (RESOURCE32(r.rlim_cur), &rlim->rlim_cur); ret |= __put_user (RESOURCE32(r.rlim_max), &rlim->rlim_max); } return ret;}extern asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim);asmlinkage longsys32_setrlimit(unsigned int resource, struct rlimit32 *rlim){ struct rlimit r; int ret; mm_segment_t old_fs = get_fs (); if (resource >= RLIM_NLIMITS) return -EINVAL; if (get_user (r.rlim_cur, &rlim->rlim_cur) || __get_user (r.rlim_max, &rlim->rlim_max)) return -EFAULT; if (r.rlim_cur == RLIM_INFINITY32) r.rlim_cur = RLIM_INFINITY; if (r.rlim_max == RLIM_INFINITY32) r.rlim_max = RLIM_INFINITY; set_fs (KERNEL_DS); ret = sys_setrlimit(resource, &r); set_fs (old_fs); return ret;}/* * Declare the IA32 version of the msghdr */ struct msghdr32 { unsigned int msg_name; /* Socket name */ int msg_namelen; /* Length of name */ unsigned int msg_iov; /* Data blocks */ unsigned int msg_iovlen; /* Number of blocks */ unsigned int msg_control; /* Per protocol magic (eg BSD file descriptor passing) */ unsigned int msg_controllen; /* Length of cmsg list */ unsigned msg_flags;};static inline intshape_msg(struct msghdr *mp, struct msghdr32 *mp32){ int ret; unsigned int i; if (!access_ok(VERIFY_READ, mp32, sizeof(*mp32))) return(-EFAULT); ret = __get_user(i, &mp32->msg_name); mp->msg_name = (void *)A(i); ret |= __get_user(mp->msg_namelen, &mp32->msg_namelen); ret |= __get_user(i, &mp32->msg_iov); mp->msg_iov = (struct iovec *)A(i); ret |= __get_user(mp->msg_iovlen, &mp32->msg_iovlen); ret |= __get_user(i, &mp32->msg_control); mp->msg_control = (void *)A(i); ret |= __get_user(mp->msg_controllen, &mp32->msg_controllen); ret |= __get_user(mp->msg_flags, &mp32->msg_flags); return(ret ? -EFAULT : 0);}/* * Verify & re-shape IA32 iovec. The caller must ensure that the * iovec is big enough to hold the re-shaped message iovec. * * Save time not doing verify_area. copy_*_user will make this work * in any case. * * Don't need to check the total size for overflow (cf net/core/iovec.c), * 32-bit sizes can't overflow a 64-bit count. */static inline intverify_iovec32(struct msghdr *m, struct iovec *iov, char *address, int mode){ int size, err, ct; struct iovec32 *iov32; if(m->msg_namelen) { if(mode==VERIFY_READ) { err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address); if(err<0) goto out; } m->msg_name = address; } else m->msg_name = NULL; err = -EFAULT; size = m->msg_iovlen * sizeof(struct iovec32); if (copy_from_user(iov, m->msg_iov, size)) goto out; m->msg_iov=iov; err = 0; iov32 = (struct iovec32 *)iov; for (ct = m->msg_iovlen; ct-- > 0; ) { iov[ct].iov_len = (__kernel_size_t)iov32[ct].iov_len; iov[ct].iov_base = (void *) A(iov32[ct].iov_base); err += iov[ct].iov_len; }out: return err;}extern __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 */int sys32_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, ctl_len, iov_size, total_len; err = -EFAULT; if (shape_msg(&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; ctl_len = msg_sys.msg_controllen; if (ctl_len) { if (ctl_len > sizeof(ctl)) { err = -ENOBUFS; ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); if (ctl_buf == NULL) goto out_freeiov; } err = -EFAULT; if (copy_from_user(ctl_buf, msg_sys.msg_control, ctl_len)) goto out_freectl; msg_sys.msg_control = ctl_buf; } 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);out_freectl: 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; /* kernel mode address */ char addr[MAX_SOCK_ADDR]; /* user mode address pointers */ struct sockaddr *uaddr; int *uaddr_len; err=-EFAULT; if (shape_msg(&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; err = sock_recvmsg(sock, &msg_sys, total_len, flags); if (err < 0) goto out_freeiov; len = err; 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;}/* 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_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 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 = 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 semid_ds32 { struct ipc_perm32 sem_perm; /* permissions .. see ipc.h */ __kernel_time_t32 sem_otime; /* last semop time */ __kernel_time_t32 sem_ctime; /* last change time */ u32 sem_base; /* ptr to first semaphore in array */ u32 sem_pending; /* pending operations to be processed */ u32 sem_pending_last; /* last pending operation */ u32 undo; /* undo requests on this array */ unsigned short sem_nsems; /* no. of semaphores in array */};struct msqid_ds32{ struct ipc_perm32 msg_perm; u32 msg_first; u32 msg_last; __kernel_time_t32 msg_stime; __kernel_time_t32 msg_rtime; __kernel_time_t32 msg_ctime; u32 wwait; u32 rwait; unsigned short msg_cbytes; unsigned short msg_qnum; unsigned short msg_qbytes; __kernel_ipc_pid_t32 msg_lspid; __kernel_ipc_pid_t32 msg_lrpid;};struct shmid_ds32 { struct ipc_perm32 shm_perm; int shm_segsz; __kernel_time_t32 shm_atime; __kernel_time_t32 shm_dtime; __kernel_time_t32 shm_ctime; __kernel_ipc_pid_t32 shm_cpid; __kernel_ipc_pid_t32 shm_lpid; unsigned short shm_nattch;};#define IPCOP_MASK(__x) (1UL << (__x))static intdo_sys32_semctl(int first, int second, int third, void *uptr){ union semun fourth; u32 pad; int err, err2; struct semid64_ds s; struct semid_ds32 *usp; mm_segment_t old_fs; if (!uptr) return -EINVAL; err = -EFAULT; if (get_user (pad, (u32 *)uptr)) return err; if(third == SETVAL) fourth.val = (int)pad; else fourth.__pad = (void *)A(pad); switch (third) { case IPC_INFO: case IPC_RMID: case IPC_SET: case SEM_INFO: case GETVAL: case GETPID: case GETNCNT: case GETZCNT: case GETALL: case SETVAL: case SETALL: err = sys_semctl (first, second, third, fourth); break; case IPC_STAT: case SEM_STAT: usp = (struct semid_ds32 *)A(pad); fourth.__pad = &s; old_fs = get_fs (); set_fs (KERNEL_DS); err = sys_semctl (first, second, third, fourth); set_fs (old_fs); err2 = put_user(s.sem_perm.key, &usp->sem_perm.key); err2 |= __put_user(s.sem_perm.uid, &usp->sem_perm.uid); err2 |= __put_user(s.sem_perm.gid, &usp->sem_perm.gid); err2 |= __put_user(s.sem_perm.cuid, &usp->sem_perm.cuid); err2 |= __put_user (s.sem_perm.cgid, &usp->sem_perm.cgid); err2 |= __put_user (s.sem_perm.mode, &usp->sem_perm.mode); err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq); err2 |= __put_user (s.sem_otime, &usp->sem_otime); err2 |= __put_user (s.sem_ctime, &usp->sem_ctime); err2 |= __put_user (s.sem_nsems, &usp->sem_nsems); if (err2) err = -EFAULT; break; } return err;}static intdo_sys32_msgsnd (int first, int second, int third, void *uptr){ struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -