linux32.c
来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 2,612 行 · 第 1/5 页
C
2,612 行
case IPC_STAT: case SHM_STAT: old_fs = get_fs(); set_fs(KERNEL_DS); err = sys_shmctl(first, second | IPC_64, (void *) &s64); set_fs(old_fs); if (err < 0) break; if (second & IPC_64) { if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) { err = -EFAULT; break; } err2 = __put_user(s64.shm_perm.key, &up64->shm_perm.key); err2 |= __put_user(s64.shm_perm.uid, &up64->shm_perm.uid); err2 |= __put_user(s64.shm_perm.gid, &up64->shm_perm.gid); err2 |= __put_user(s64.shm_perm.cuid, &up64->shm_perm.cuid); err2 |= __put_user(s64.shm_perm.cgid, &up64->shm_perm.cgid); err2 |= __put_user(s64.shm_perm.mode, &up64->shm_perm.mode); err2 |= __put_user(s64.shm_perm.seq, &up64->shm_perm.seq); err2 |= __put_user(s64.shm_atime, &up64->shm_atime); err2 |= __put_user(s64.shm_dtime, &up64->shm_dtime); err2 |= __put_user(s64.shm_ctime, &up64->shm_ctime); err2 |= __put_user(s64.shm_segsz, &up64->shm_segsz); err2 |= __put_user(s64.shm_nattch, &up64->shm_nattch); err2 |= __put_user(s64.shm_cpid, &up64->shm_cpid); err2 |= __put_user(s64.shm_lpid, &up64->shm_lpid); } else { if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) { err = -EFAULT; break; } err2 = __put_user(s64.shm_perm.key, &up32->shm_perm.key); err2 |= __put_user(s64.shm_perm.uid, &up32->shm_perm.uid); err2 |= __put_user(s64.shm_perm.gid, &up32->shm_perm.gid); err2 |= __put_user(s64.shm_perm.cuid, &up32->shm_perm.cuid); err2 |= __put_user(s64.shm_perm.cgid, &up32->shm_perm.cgid); err2 |= __put_user(s64.shm_perm.mode, &up32->shm_perm.mode); err2 |= __put_user(s64.shm_perm.seq, &up32->shm_perm.seq); err2 |= __put_user(s64.shm_atime, &up32->shm_atime); err2 |= __put_user(s64.shm_dtime, &up32->shm_dtime); err2 |= __put_user(s64.shm_ctime, &up32->shm_ctime); err2 |= __put_user(s64.shm_segsz, &up32->shm_segsz); err2 |= __put_user(s64.shm_nattch, &up32->shm_nattch); err2 |= __put_user(s64.shm_cpid, &up32->shm_cpid); err2 |= __put_user(s64.shm_lpid, &up32->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; default: err = -EINVAL; break; } return err;}static inline void *alloc_user_space(long len){ struct pt_regs *regs = (struct pt_regs *) ((unsigned long) current + THREAD_SIZE - 32) - 1; return (void *) (regs->regs[29] - len);}static int sys32_semtimedop(int semid, struct sembuf *tsems, int nsems, const struct timespec32 *timeout32){ struct timespec32 t32; struct timespec *t64 = alloc_user_space(sizeof(*t64)); if (copy_from_user(&t32, timeout32, sizeof(t32))) return -EFAULT; if (put_user(t32.tv_sec, &t64->tv_sec) || put_user(t32.tv_nsec, &t64->tv_nsec)) return -EFAULT; return sys_semtimedop(semid, tsems, nsems, t64);}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_semtimedop (first, (struct sembuf *)AA(ptr), second, NULL); break; case SEMTIMEDOP: err = sys32_semtimedop(first, (struct sembuf *)AA(ptr), second, (const struct timespec32 *) AA(fifth)); 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];};#ifdef CONFIG_SYSCTLasmlinkage long sys32_sysctl(struct sysctl_args32 *args){ struct sysctl_args32 tmp; int error; size_t oldlen, *oldlenp = NULL; unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7; if (copy_from_user(&tmp, args, sizeof(tmp))) return -EFAULT; if (tmp.oldval && tmp.oldlenp) { /* Duh, this is ugly and might not work if sysctl_args is in read-only memory, but do_sysctl does indirectly a lot of uaccess in both directions and we'd have to basically copy the whole sysctl.c here, and glibc's __sysctl uses rw memory for the structure anyway. */ if (get_user(oldlen, (u32 *)A(tmp.oldlenp)) || put_user(oldlen, (size_t *)addr)) return -EFAULT; oldlenp = (size_t *)addr; } lock_kernel(); error = do_sysctl((int *)A(tmp.name), tmp.nlen, (void *)A(tmp.oldval), oldlenp, (void *)A(tmp.newval), tmp.newlen); unlock_kernel(); if (oldlenp) { if (!error) { if (get_user(oldlen, (size_t *)addr) || put_user(oldlen, (u32 *)A(tmp.oldlenp))) error = -EFAULT; } copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)); } return error;}#else /* CONFIG_SYSCTL */asmlinkage long sys32_sysctl(struct sysctl_args32 *args){ return -ENOSYS;}#endif /* CONFIG_SYSCTL */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;}/* ustat compatibility */struct ustat32 { __kernel_daddr_t32 f_tfree; __kernel_ino_t32 f_tinode; char f_fname[6]; char f_fpack[6];};extern asmlinkage long sys_ustat(dev_t dev, struct ustat * ubuf);asmlinkage int sys32_ustat(dev_t dev, struct ustat32 * ubuf32){ int err; struct ustat tmp; struct ustat32 tmp32; mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); err = sys_ustat(dev, &tmp); set_fs (old_fs); if (err) goto out; memset(&tmp32,0,sizeof(struct ustat32)); tmp32.f_tfree = tmp.f_tfree; tmp32.f_tinode = tmp.f_tinode; err = copy_to_user(ubuf32,&tmp32,sizeof(struct ustat32)) ? -EFAULT : 0;out: return err;}/* 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;};struct cmsghdr32 { __kernel_size_t32 cmsg_len; int cmsg_level; int cmsg_type;};/* Bleech... */#define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen))#define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) cmsg32_nxthdr((mhdr), (cmsg), (cmsglen))#define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) )#define CMSG32_DATA(cmsg) ((void *)((char *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr32))))#define CMSG32_SPACE(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + CMSG32_ALIGN(len))#define CMSG32_LEN(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + (len))#define __CMSG32_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr32) ? \ (struct cmsghdr32 *)(ctl) : \ (struct cmsghdr32 *)NULL)#define CMSG32_FIRSTHDR(msg) __CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)#define CMSG32_OK(ucmlen, ucmsg, mhdr) \ ((ucmlen) >= sizeof(struct cmsghdr32) && \ (ucmlen) <= (unsigned long) \ ((mhdr)->msg_controllen - \ ((char *)(ucmsg) - (char *)(mhdr)->msg_control)))__inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size, struct cmsghdr32 *__cmsg, int __cmsg_len){ struct cmsghdr32 * __ptr; __ptr = (struct cmsghdr32 *)(((unsigned char *) __cmsg) + CMSG32_ALIGN(__cmsg_len)); if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size) return NULL; return __ptr;}__inline__ struct cmsghdr32 *cmsg32_nxthdr (struct msghdr *__msg, struct cmsghdr32 *__cmsg, int __cmsg_len){ return __cmsg32_nxthdr(__msg->msg_control, __msg->msg_controllen, __cmsg, __cmsg_len);}static inline int iov_from_user32_to_kern(struct iovec *kiov, struct iovec32 *uiov32, int niov){ int tot_len = 0; while(niov > 0) { u32 len, buf; if(get_user(len, &uiov32->iov_len) || get_user(buf, &uiov32->iov_base)) { tot_len = -EFAULT; break; } tot_len += len; kiov->iov_base = (void *)AA(buf); kiov->iov_len = (__kernel_size_t) len; uiov32++; kiov++; niov--; } return tot_len;}static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg, struct msghdr32 *umsg){ u32 tmp1, tmp2, tmp3; int err; err = get_user(tmp1, &umsg->msg_name); err |= __get_user(tmp2, &umsg->msg_iov); err |= __get_user(tmp3, &umsg->msg_control); if (err) return -EFAULT; kmsg->msg_name = (void *)AA(tmp1); kmsg->msg_iov = (struct iovec *)AA(tmp2); kmsg->msg_control = (void *)AA(tmp3); err = get_user(kmsg->msg_namelen, &umsg->msg_namelen); err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen); err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen); err |= get_user(kmsg->msg_flags, &umsg->msg_flags); return err;}/* I've named the args so it is easy to tell whose space the pointers are in. */static int verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov, char *kern_address, int mode){ int tot_len; if(kern_msg->msg_namelen) { if(mode==VERIFY_READ) { int err = move_addr_to_kernel(kern_msg->msg_name, kern_msg->msg_namelen, kern_address); if(err < 0) return err; } kern_msg->msg_name = kern_address; } else kern_msg->msg_name = NULL; if(kern_msg->msg_iovlen > UIO_FASTIOV) { kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec), GFP_KERNEL); if(!kern_iov) return -ENOMEM; } tot_len = iov_from_user32_to_kern(kern_iov, (struct iovec32 *)kern_msg->msg_iov, kern_msg->msg_iovlen); if(tot_len >= 0) kern_msg->msg_iov = kern_iov; else if(kern_msg->msg_iovlen > UIO_FASTIOV) kfree(kern_iov); return tot_len;}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);/* There is a lot of hair here because the
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?