sys_ia32.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 1,352 行 · 第 1/3 页
C
1,352 行
} if (tz) { if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) return -EFAULT; } return 0;}asmlinkage longsys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz){ struct timeval ktv; struct timespec kts; struct timezone ktz; if (tv) { if (get_tv32(&ktv, tv)) return -EFAULT; kts.tv_sec = ktv.tv_sec; kts.tv_nsec = ktv.tv_usec * NSEC_PER_USEC; } if (tz) { if (copy_from_user(&ktz, tz, sizeof(ktz))) return -EFAULT; } return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);}struct linux32_dirent { u32 d_ino; u32 d_off; u16 d_reclen; char d_name[1];};struct old_linux32_dirent { u32 d_ino; u32 d_offset; u16 d_namlen; char d_name[1];};struct getdents32_callback { struct linux32_dirent __user * current_dir; struct linux32_dirent __user * previous; int count; int error;};struct readdir32_callback { struct old_linux32_dirent __user * dirent; int count;};static intfilldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino, unsigned int d_type){ struct linux32_dirent __user * dirent; struct getdents32_callback * buf = (struct getdents32_callback *) __buf; int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2, 4); buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; dirent = buf->previous; if (dirent) put_user(offset, &dirent->d_off); dirent = buf->current_dir; buf->previous = dirent; put_user(ino, &dirent->d_ino); put_user(reclen, &dirent->d_reclen); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); put_user(d_type, (char __user *)dirent + reclen - 1); dirent = ((void __user *)dirent) + reclen; buf->current_dir = dirent; buf->count -= reclen; return 0;}asmlinkage longsys32_getdents (unsigned int fd, void __user * dirent, unsigned int count){ struct file * file; struct linux32_dirent __user * lastdirent; struct getdents32_callback buf; int error; error = -EBADF; file = fget(fd); if (!file) goto out; buf.current_dir = (struct linux32_dirent __user *) dirent; buf.previous = NULL; buf.count = count; buf.error = 0; error = vfs_readdir(file, filldir32, &buf); if (error < 0) goto out_putf; error = buf.error; lastdirent = buf.previous; if (lastdirent) { put_user(file->f_pos, &lastdirent->d_off); error = count - buf.count; }out_putf: fput(file);out: return error;}static intfillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t ino, unsigned d_type){ struct readdir32_callback * buf = (struct readdir32_callback *) __buf; struct old_linux32_dirent __user * dirent; if (buf->count) return -EINVAL; buf->count++; dirent = buf->dirent; put_user(ino, &dirent->d_ino); put_user(offset, &dirent->d_offset); put_user(namlen, &dirent->d_namlen); copy_to_user(dirent->d_name, name, namlen); put_user(0, dirent->d_name + namlen); return 0;}asmlinkage longsys32_oldreaddir (unsigned int fd, void __user * dirent, unsigned int count){ int error; struct file * file; struct readdir32_callback buf; error = -EBADF; file = fget(fd); if (!file) goto out; buf.count = 0; buf.dirent = dirent; error = vfs_readdir(file, fillonedir32, &buf); if (error >= 0) error = buf.count; fput(file);out: return error;}struct sel_arg_struct { unsigned int n; unsigned int inp; unsigned int outp; unsigned int exp; unsigned int tvp;};asmlinkage longsys32_old_select(struct sel_arg_struct __user *arg){ struct sel_arg_struct a; if (copy_from_user(&a, arg, sizeof(a))) return -EFAULT; return compat_sys_select(a.n, compat_ptr(a.inp), compat_ptr(a.outp), compat_ptr(a.exp), compat_ptr(a.tvp));}/* * sys_time() can be implemented in user-level using * sys_gettimeofday(). x86-64 did this but i386 Linux did not * so we have to implement this system call here. */asmlinkage long sys32_time(int __user * tloc){ int i; struct timeval tv; do_gettimeofday(&tv); i = tv.tv_sec; if (tloc) { if (put_user(i,tloc)) i = -EFAULT; } return i;}extern asmlinkage longcompat_sys_wait4(compat_pid_t pid, compat_uint_t * stat_addr, int options, struct compat_rusage *ru);asmlinkage longsys32_waitpid(compat_pid_t pid, unsigned int *stat_addr, int options){ return compat_sys_wait4(pid, stat_addr, options, NULL);}int sys32_ni_syscall(int call){ struct task_struct *me = current; static char lastcomm[8]; if (strcmp(lastcomm, me->comm)) { printk(KERN_INFO "IA32 syscall %d from %s not implemented\n", call, current->comm); strcpy(lastcomm, me->comm); } return -ENOSYS; } /* 32-bit timeval and related flotsam. */asmlinkage longsys32_sysfs(int option, u32 arg1, u32 arg2){ return sys_sysfs(option, arg1, arg2);}struct sysinfo32 { s32 uptime; u32 loads[3]; u32 totalram; u32 freeram; u32 sharedram; u32 bufferram; u32 totalswap; u32 freeswap; unsigned short procs; unsigned short pad; u32 totalhigh; u32 freehigh; u32 mem_unit; char _f[20-2*sizeof(u32)-sizeof(int)];};asmlinkage longsys32_sysinfo(struct sysinfo32 __user *info){ struct sysinfo s; int ret; mm_segment_t old_fs = get_fs (); int bitcount = 0; set_fs (KERNEL_DS); ret = sys_sysinfo(&s); set_fs (old_fs); /* Check to see if any memory value is too large for 32-bit and scale * down if needed */ if ((s.totalram >> 32) || (s.totalswap >> 32)) { while (s.mem_unit < PAGE_SIZE) { s.mem_unit <<= 1; bitcount++; } s.totalram >>= bitcount; s.freeram >>= bitcount; s.sharedram >>= bitcount; s.bufferram >>= bitcount; s.totalswap >>= bitcount; s.freeswap >>= bitcount; s.totalhigh >>= bitcount; s.freehigh >>= bitcount; } if (verify_area(VERIFY_WRITE, info, sizeof(struct sysinfo32)) || __put_user (s.uptime, &info->uptime) || __put_user (s.loads[0], &info->loads[0]) || __put_user (s.loads[1], &info->loads[1]) || __put_user (s.loads[2], &info->loads[2]) || __put_user (s.totalram, &info->totalram) || __put_user (s.freeram, &info->freeram) || __put_user (s.sharedram, &info->sharedram) || __put_user (s.bufferram, &info->bufferram) || __put_user (s.totalswap, &info->totalswap) || __put_user (s.freeswap, &info->freeswap) || __put_user (s.procs, &info->procs) || __put_user (s.totalhigh, &info->totalhigh) || __put_user (s.freehigh, &info->freehigh) || __put_user (s.mem_unit, &info->mem_unit)) return -EFAULT; return 0;} asmlinkage longsys32_sched_rr_get_interval(compat_pid_t pid, struct compat_timespec __user *interval){ struct timespec t; int ret; mm_segment_t old_fs = get_fs (); set_fs (KERNEL_DS); ret = sys_sched_rr_get_interval(pid, &t); set_fs (old_fs); if (put_compat_timespec(&t, interval)) return -EFAULT; return ret;}asmlinkage longsys32_rt_sigpending(compat_sigset_t __user *set, compat_size_t sigsetsize){ sigset_t s; compat_sigset_t s32; int ret; mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_rt_sigpending(&s, sigsetsize); set_fs (old_fs); if (!ret) { switch (_NSIG_WORDS) { case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3]; case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2]; case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1]; case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0]; } if (copy_to_user (set, &s32, sizeof(compat_sigset_t))) return -EFAULT; } return ret;}asmlinkage longsys32_rt_sigtimedwait(compat_sigset_t __user *uthese, siginfo_t32 __user *uinfo, struct compat_timespec __user *uts, compat_size_t sigsetsize){ sigset_t s; compat_sigset_t s32; struct timespec t; int ret; mm_segment_t old_fs = get_fs(); siginfo_t info; if (copy_from_user (&s32, uthese, sizeof(compat_sigset_t))) return -EFAULT; switch (_NSIG_WORDS) { case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32); case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32); case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32); case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); } if (uts && get_compat_timespec(&t, uts)) return -EFAULT; if (uinfo) { /* stop data leak to user space in case of structure fill mismatch * between sys_rt_sigtimedwait & ia32_copy_siginfo_to_user. */ memset(&info, 0, sizeof(info)); } set_fs (KERNEL_DS); ret = sys_rt_sigtimedwait(&s, uinfo ? &info : NULL, uts ? &t : NULL, sigsetsize); set_fs (old_fs); if (ret >= 0 && uinfo) { if (ia32_copy_siginfo_to_user(uinfo, &info)) return -EFAULT; } return ret;}asmlinkage longsys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 __user *uinfo){ siginfo_t info; int ret; mm_segment_t old_fs = get_fs(); if (ia32_copy_siginfo_from_user(&info, uinfo)) return -EFAULT; set_fs (KERNEL_DS); ret = sys_rt_sigqueueinfo(pid, sig, &info); set_fs (old_fs); return ret;}/* These are here just in case some old ia32 binary calls it. */asmlinkage longsys32_pause(void){ current->state = TASK_INTERRUPTIBLE; schedule(); return -ERESTARTNOHAND;}struct sysctl_ia32 { unsigned int name; int nlen; unsigned int oldval; unsigned int oldlenp; unsigned int newval; unsigned int newlen; unsigned int __unused[4];};asmlinkage longsys32_sysctl(struct sysctl_ia32 __user *args32){#ifndef CONFIG_SYSCTL return -ENOSYS; #else struct sysctl_ia32 a32; mm_segment_t old_fs = get_fs (); void *oldvalp, *newvalp; size_t oldlen; int *namep; long ret; extern int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen); if (copy_from_user(&a32, args32, sizeof (a32))) return -EFAULT; /* * We need to pre-validate these because we have to disable address checking * before calling do_sysctl() because of OLDLEN but we can't run the risk of the * user specifying bad addresses here. Well, since we're dealing with 32 bit * addresses, we KNOW that access_ok() will always succeed, so this is an * expensive NOP, but so what... */ namep = (int *) A(a32.name); oldvalp = (void *) A(a32.oldval); newvalp = (void *) A(a32.newval); if ((oldvalp && get_user(oldlen, (int __user *)compat_ptr(a32.oldlenp))) || !access_ok(VERIFY_WRITE, namep, 0) || !access_ok(VERIFY_WRITE, oldvalp, 0) || !access_ok(VERIFY_WRITE, newvalp, 0)) return -EFAULT; set_fs(KERNEL_DS); lock_kernel(); ret = do_sysctl(namep, a32.nlen, oldvalp, &oldlen, newvalp, (size_t) a32.newlen); unlock_kernel(); set_fs(old_fs); if (oldvalp && put_user (oldlen, (int __user *)compat_ptr(a32.oldlenp))) return -EFAULT;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?