📄 linux32.c
字号:
case IPC_INFO: case IPC_RMID: case SHM_LOCK: case SHM_UNLOCK: err = sys_shmctl (first, second, (struct shmid_ds *)uptr); break; case IPC_SET: err = get_user (s.shm_perm.uid, &up->shm_perm.uid); err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid); err |= __get_user (s.shm_perm.mode, &up->shm_perm.mode); if (err) break; old_fs = get_fs (); set_fs (KERNEL_DS); err = sys_shmctl (first, second, &s); set_fs (old_fs); break; case IPC_STAT: case SHM_STAT: old_fs = get_fs (); set_fs (KERNEL_DS); err = sys_shmctl (first, second, (void *) &s64); set_fs (old_fs); if (err < 0) break; err2 = put_user (s64.shm_perm.key, &up->shm_perm.key); err2 |= __put_user (s64.shm_perm.uid, &up->shm_perm.uid); err2 |= __put_user (s64.shm_perm.gid, &up->shm_perm.gid); err2 |= __put_user (s64.shm_perm.cuid, &up->shm_perm.cuid); err2 |= __put_user (s64.shm_perm.cgid, &up->shm_perm.cgid); err2 |= __put_user (s64.shm_perm.mode, &up->shm_perm.mode); err2 |= __put_user (s64.shm_perm.seq, &up->shm_perm.seq); err2 |= __put_user (s64.shm_atime, &up->shm_atime); err2 |= __put_user (s64.shm_dtime, &up->shm_dtime); err2 |= __put_user (s64.shm_ctime, &up->shm_ctime); err2 |= __put_user (s64.shm_segsz, &up->shm_segsz); err2 |= __put_user (s64.shm_nattch, &up->shm_nattch); err2 |= __put_user (s64.shm_cpid, &up->shm_cpid); err2 |= __put_user (s64.shm_lpid, &up->shm_lpid); if (err2) err = -EFAULT; break; case SHM_INFO: old_fs = get_fs (); set_fs (KERNEL_DS); err = sys_shmctl (first, second, (void *)&si); set_fs (old_fs); if (err < 0) break; err2 = put_user (si.used_ids, &uip->used_ids); err2 |= __put_user (si.shm_tot, &uip->shm_tot); err2 |= __put_user (si.shm_rss, &uip->shm_rss); err2 |= __put_user (si.shm_swp, &uip->shm_swp); err2 |= __put_user (si.swap_attempts, &uip->swap_attempts); err2 |= __put_user (si.swap_successes, &uip->swap_successes); if (err2) err = -EFAULT; break; } return err;}asmlinkage longsys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth){ int version, err; version = call >> 16; /* hack for backward compatibility */ call &= 0xffff; switch (call) { case SEMOP: /* struct sembuf is the same on 32 and 64bit :)) */ err = sys_semop (first, (struct sembuf *)AA(ptr), second); break; case SEMGET: err = sys_semget (first, second, third); break; case SEMCTL: err = do_sys32_semctl (first, second, third, (void *)AA(ptr)); break; case MSGSND: err = do_sys32_msgsnd (first, second, third, (void *)AA(ptr)); break; case MSGRCV: err = do_sys32_msgrcv (first, second, fifth, third, version, (void *)AA(ptr)); break; case MSGGET: err = sys_msgget ((key_t) first, second); break; case MSGCTL: err = do_sys32_msgctl (first, second, (void *)AA(ptr)); break; case SHMAT: err = do_sys32_shmat (first, second, third, version, (void *)AA(ptr)); break; case SHMDT: err = sys_shmdt ((char *)A(ptr)); break; case SHMGET: err = sys_shmget (first, second, third); break; case SHMCTL: err = do_sys32_shmctl (first, second, (void *)AA(ptr)); break; default: err = -EINVAL; break; } return err;}struct sysctl_args32{ __kernel_caddr_t32 name; int nlen; __kernel_caddr_t32 oldval; __kernel_caddr_t32 oldlenp; __kernel_caddr_t32 newval; __kernel_size_t32 newlen; unsigned int __unused[4];};asmlinkage long sys32_sysctl(struct sysctl_args32 *uargs32){ struct __sysctl_args kargs; struct sysctl_args32 kargs32; mm_segment_t old_fs; int name[CTL_MAXNAME]; size_t oldlen[1]; int err, ret; ret = -EFAULT; memset(&kargs, 0, sizeof (kargs)); err = get_user(kargs32.name, &uargs32->name); err |= __get_user(kargs32.nlen, &uargs32->nlen); err |= __get_user(kargs32.oldval, &uargs32->oldval); err |= __get_user(kargs32.oldlenp, &uargs32->oldlenp); err |= __get_user(kargs32.newval, &uargs32->newval); err |= __get_user(kargs32.newlen, &uargs32->newlen); if (err) goto out; if (kargs32.nlen == 0 || kargs32.nlen >= CTL_MAXNAME) { ret = -ENOTDIR; goto out; } kargs.name = name; kargs.nlen = kargs32.nlen; if (copy_from_user(kargs.name, (int *)A(kargs32.name), kargs32.nlen * sizeof(name) / sizeof(name[0]))) goto out; if (kargs32.oldval) { if (!kargs32.oldlenp || get_user(oldlen[0], (int *)A(kargs32.oldlenp))) return -EFAULT; kargs.oldlenp = oldlen; kargs.oldval = kmalloc(oldlen[0], GFP_KERNEL); if (!kargs.oldval) { ret = -ENOMEM; goto out; } } if (kargs32.newval && kargs32.newlen) { kargs.newval = kmalloc(kargs32.newlen, GFP_KERNEL); if (!kargs.newval) { ret = -ENOMEM; goto out; } if (copy_from_user(kargs.newval, (int *)A(kargs32.newval), kargs32.newlen)) goto out; } old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_sysctl(&kargs); set_fs (old_fs); if (ret) goto out; if (kargs.oldval) { if (put_user(oldlen[0], (int *)A(kargs32.oldlenp)) || copy_to_user((int *)A(kargs32.oldval), kargs.oldval, oldlen[0])) ret = -EFAULT; }out: if (kargs.oldval) kfree(kargs.oldval); if (kargs.newval) kfree(kargs.newval); return ret;}asmlinkage long sys32_newuname(struct new_utsname * name){ int ret = 0; down_read(&uts_sem); if (copy_to_user(name,&system_utsname,sizeof *name)) ret = -EFAULT; up_read(&uts_sem); if (current->personality == PER_LINUX32 && !ret) if (copy_to_user(name->machine, "mips\0\0\0", 8)) ret = -EFAULT; return ret;}extern asmlinkage long sys_personality(unsigned long);asmlinkage int sys32_personality(unsigned long personality){ int ret; if (current->personality == PER_LINUX32 && personality == PER_LINUX) personality = PER_LINUX32; ret = sys_personality(personality); if (ret == PER_LINUX32) ret = PER_LINUX; return ret;}/* Handle adjtimex compatability. */struct timex32 { u32 modes; s32 offset, freq, maxerror, esterror; s32 status, constant, precision, tolerance; struct timeval32 time; s32 tick; s32 ppsfreq, jitter, shift, stabil; s32 jitcnt, calcnt, errcnt, stbcnt; s32 :32; s32 :32; s32 :32; s32 :32; s32 :32; s32 :32; s32 :32; s32 :32; s32 :32; s32 :32; s32 :32; s32 :32;};extern int do_adjtimex(struct timex *);asmlinkage int sys32_adjtimex(struct timex32 *utp){ struct timex txc; int ret; memset(&txc, 0, sizeof(struct timex)); if(get_user(txc.modes, &utp->modes) || __get_user(txc.offset, &utp->offset) || __get_user(txc.freq, &utp->freq) || __get_user(txc.maxerror, &utp->maxerror) || __get_user(txc.esterror, &utp->esterror) || __get_user(txc.status, &utp->status) || __get_user(txc.constant, &utp->constant) || __get_user(txc.precision, &utp->precision) || __get_user(txc.tolerance, &utp->tolerance) || __get_user(txc.time.tv_sec, &utp->time.tv_sec) || __get_user(txc.time.tv_usec, &utp->time.tv_usec) || __get_user(txc.tick, &utp->tick) || __get_user(txc.ppsfreq, &utp->ppsfreq) || __get_user(txc.jitter, &utp->jitter) || __get_user(txc.shift, &utp->shift) || __get_user(txc.stabil, &utp->stabil) || __get_user(txc.jitcnt, &utp->jitcnt) || __get_user(txc.calcnt, &utp->calcnt) || __get_user(txc.errcnt, &utp->errcnt) || __get_user(txc.stbcnt, &utp->stbcnt)) return -EFAULT; ret = do_adjtimex(&txc); if(put_user(txc.modes, &utp->modes) || __put_user(txc.offset, &utp->offset) || __put_user(txc.freq, &utp->freq) || __put_user(txc.maxerror, &utp->maxerror) || __put_user(txc.esterror, &utp->esterror) || __put_user(txc.status, &utp->status) || __put_user(txc.constant, &utp->constant) || __put_user(txc.precision, &utp->precision) || __put_user(txc.tolerance, &utp->tolerance) || __put_user(txc.time.tv_sec, &utp->time.tv_sec) || __put_user(txc.time.tv_usec, &utp->time.tv_usec) || __put_user(txc.tick, &utp->tick) || __put_user(txc.ppsfreq, &utp->ppsfreq) || __put_user(txc.jitter, &utp->jitter) || __put_user(txc.shift, &utp->shift) || __put_user(txc.stabil, &utp->stabil) || __put_user(txc.jitcnt, &utp->jitcnt) || __put_user(txc.calcnt, &utp->calcnt) || __put_user(txc.errcnt, &utp->errcnt) || __put_user(txc.stbcnt, &utp->stbcnt)) ret = -EFAULT; return ret;}/* * Declare the 32-bit 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;}asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count);asmlinkage ssize_t sys32_readahead(int fd, u32 pad0, u64 a2, u64 a3, size_t count){ return sys_readahead(fd, merge_64(a2, a3), count);}#ifdef CONFIG_MODULES/* From sparc64 */struct kernel_sym32 { u32 value; char name[60];};extern asmlinkage int sys_get_kernel_syms(struct kernel_sym *table);asmlinkage int sys32_get_kernel_syms(struct kernel_sym32 *table){ int len, i; struct kernel_sym *tbl; mm_segment_t old_fs; len = sys_get_kernel_syms(NULL); if (!table) return len; tbl = kmalloc (len * sizeof (struct kernel_sym), GFP_KERNEL); if (!tbl) return -ENOMEM; old_fs = get_fs(); set_fs (KERNEL_DS); sys_get_kernel_syms(tbl); set_fs (old_fs); for (i = 0; i < len; i++, table++) { if (put_user (tbl[i].value, &table->value) || copy_to_user (table->name, tbl[i].name, 60)) break; } kfree (tbl); return i;}#elseasmlinkage longsys32_get_kernel_syms(struct kernel_sym *table){ return -ENOSYS;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -