📄 compat.c
字号:
oldfs = get_fs(); set_fs(KERNEL_DS); err = sys_timer_gettime(timer_id, (struct itimerspec __user *) &ts); set_fs(oldfs); if (!err && put_compat_itimerspec(setting, &ts)) return -EFAULT; return err;} long compat_sys_clock_settime(clockid_t which_clock, struct compat_timespec __user *tp){ long err; mm_segment_t oldfs; struct timespec ts; if (get_compat_timespec(&ts, tp)) return -EFAULT; oldfs = get_fs(); set_fs(KERNEL_DS); err = sys_clock_settime(which_clock, (struct timespec __user *) &ts); set_fs(oldfs); return err;} long compat_sys_clock_gettime(clockid_t which_clock, struct compat_timespec __user *tp){ long err; mm_segment_t oldfs; struct timespec ts; oldfs = get_fs(); set_fs(KERNEL_DS); err = sys_clock_gettime(which_clock, (struct timespec __user *) &ts); set_fs(oldfs); if (!err && put_compat_timespec(&ts, tp)) return -EFAULT; return err;} long compat_sys_clock_getres(clockid_t which_clock, struct compat_timespec __user *tp){ long err; mm_segment_t oldfs; struct timespec ts; oldfs = get_fs(); set_fs(KERNEL_DS); err = sys_clock_getres(which_clock, (struct timespec __user *) &ts); set_fs(oldfs); if (!err && tp && put_compat_timespec(&ts, tp)) return -EFAULT; return err;} static long compat_clock_nanosleep_restart(struct restart_block *restart){ long err; mm_segment_t oldfs; struct timespec tu; struct compat_timespec *rmtp = (struct compat_timespec *)(restart->arg1); restart->arg1 = (unsigned long) &tu; oldfs = get_fs(); set_fs(KERNEL_DS); err = clock_nanosleep_restart(restart); set_fs(oldfs); if ((err == -ERESTART_RESTARTBLOCK) && rmtp && put_compat_timespec(&tu, rmtp)) return -EFAULT; if (err == -ERESTART_RESTARTBLOCK) { restart->fn = compat_clock_nanosleep_restart; restart->arg1 = (unsigned long) rmtp; } return err;}long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, struct compat_timespec __user *rqtp, struct compat_timespec __user *rmtp){ long err; mm_segment_t oldfs; struct timespec in, out; struct restart_block *restart; if (get_compat_timespec(&in, rqtp)) return -EFAULT; oldfs = get_fs(); set_fs(KERNEL_DS); err = sys_clock_nanosleep(which_clock, flags, (struct timespec __user *) &in, (struct timespec __user *) &out); set_fs(oldfs); if ((err == -ERESTART_RESTARTBLOCK) && rmtp && put_compat_timespec(&out, rmtp)) return -EFAULT; if (err == -ERESTART_RESTARTBLOCK) { restart = ¤t_thread_info()->restart_block; restart->fn = compat_clock_nanosleep_restart; restart->arg1 = (unsigned long) rmtp; } return err; } /* * We currently only need the following fields from the sigevent * structure: sigev_value, sigev_signo, sig_notify and (sometimes * sigev_notify_thread_id). The others are handled in user mode. * We also assume that copying sigev_value.sival_int is sufficient * to keep all the bits of sigev_value.sival_ptr intact. */int get_compat_sigevent(struct sigevent *event, const struct compat_sigevent __user *u_event){ memset(event, 0, sizeof(*event)); return (!access_ok(VERIFY_READ, u_event, sizeof(*u_event)) || __get_user(event->sigev_value.sival_int, &u_event->sigev_value.sival_int) || __get_user(event->sigev_signo, &u_event->sigev_signo) || __get_user(event->sigev_notify, &u_event->sigev_notify) || __get_user(event->sigev_notify_thread_id, &u_event->sigev_notify_thread_id)) ? -EFAULT : 0;}long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, unsigned long bitmap_size){ int i, j; unsigned long m; compat_ulong_t um; unsigned long nr_compat_longs; /* align bitmap up to nearest compat_long_t boundary */ bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG); if (!access_ok(VERIFY_READ, umask, bitmap_size / 8)) return -EFAULT; nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) { m = 0; for (j = 0; j < sizeof(m)/sizeof(um); j++) { /* * We dont want to read past the end of the userspace * bitmap. We must however ensure the end of the * kernel bitmap is zeroed. */ if (nr_compat_longs-- > 0) { if (__get_user(um, umask)) return -EFAULT; } else { um = 0; } umask++; m |= (long)um << (j * BITS_PER_COMPAT_LONG); } *mask++ = m; } return 0;}long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask, unsigned long bitmap_size){ int i, j; unsigned long m; compat_ulong_t um; unsigned long nr_compat_longs; /* align bitmap up to nearest compat_long_t boundary */ bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG); if (!access_ok(VERIFY_WRITE, umask, bitmap_size / 8)) return -EFAULT; nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size); for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) { m = *mask++; for (j = 0; j < sizeof(m)/sizeof(um); j++) { um = m; /* * We dont want to write past the end of the userspace * bitmap. */ if (nr_compat_longs-- > 0) { if (__put_user(um, umask)) return -EFAULT; } umask++; m >>= 4*sizeof(um); m >>= 4*sizeof(um); } } return 0;}voidsigset_from_compat (sigset_t *set, compat_sigset_t *compat){ switch (_NSIG_WORDS) { case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32 ); case 3: set->sig[2] = compat->sig[4] | (((long)compat->sig[5]) << 32 ); case 2: set->sig[1] = compat->sig[2] | (((long)compat->sig[3]) << 32 ); case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 32 ); }}asmlinkage longcompat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese, struct compat_siginfo __user *uinfo, struct compat_timespec __user *uts, compat_size_t sigsetsize){ compat_sigset_t s32; sigset_t s; int sig; struct timespec t; siginfo_t info; long ret, timeout = 0; if (sigsetsize != sizeof(sigset_t)) return -EINVAL; if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t))) return -EFAULT; sigset_from_compat(&s, &s32); sigdelsetmask(&s,sigmask(SIGKILL)|sigmask(SIGSTOP)); signotset(&s); if (uts) { if (get_compat_timespec (&t, uts)) return -EFAULT; if (t.tv_nsec >= 1000000000L || t.tv_nsec < 0 || t.tv_sec < 0) return -EINVAL; } spin_lock_irq(¤t->sighand->siglock); sig = dequeue_signal(current, &s, &info); if (!sig) { timeout = MAX_SCHEDULE_TIMEOUT; if (uts) timeout = timespec_to_jiffies(&t) +(t.tv_sec || t.tv_nsec); if (timeout) { current->real_blocked = current->blocked; sigandsets(¤t->blocked, ¤t->blocked, &s); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); timeout = schedule_timeout_interruptible(timeout); spin_lock_irq(¤t->sighand->siglock); sig = dequeue_signal(current, &s, &info); current->blocked = current->real_blocked; siginitset(¤t->real_blocked, 0); recalc_sigpending(); } } spin_unlock_irq(¤t->sighand->siglock); if (sig) { ret = sig; if (uinfo) { if (copy_siginfo_to_user32(uinfo, &info)) ret = -EFAULT; } }else { ret = timeout?-EINTR:-EAGAIN; } return ret;}#ifdef __ARCH_WANT_COMPAT_SYS_TIME/* compat_time_t is a 32 bit "long" and needs to get converted. */asmlinkage long compat_sys_time(compat_time_t __user * tloc){ compat_time_t i; struct timeval tv; do_gettimeofday(&tv); i = tv.tv_sec; if (tloc) { if (put_user(i,tloc)) i = -EFAULT; } return i;}asmlinkage long compat_sys_stime(compat_time_t __user *tptr){ struct timespec tv; int err; if (get_user(tv.tv_sec, tptr)) return -EFAULT; tv.tv_nsec = 0; err = security_settime(&tv, NULL); if (err) return err; do_settimeofday(&tv); return 0;}#endif /* __ARCH_WANT_COMPAT_SYS_TIME */#ifdef __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPENDasmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat_size_t sigsetsize){ sigset_t newset; compat_sigset_t newset32; /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset_t)) return -EINVAL; if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t))) return -EFAULT; sigset_from_compat(&newset, &newset32); sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP)); spin_lock_irq(¤t->sighand->siglock); current->saved_sigmask = current->blocked; current->blocked = newset; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); current->state = TASK_INTERRUPTIBLE; schedule(); set_thread_flag(TIF_RESTORE_SIGMASK); return -ERESTARTNOHAND;}#endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp){ struct timex txc; int ret; memset(&txc, 0, sizeof(struct timex)); if (!access_ok(VERIFY_READ, utp, sizeof(struct compat_timex)) || __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 (!access_ok(VERIFY_WRITE, utp, sizeof(struct compat_timex)) || __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;}#ifdef CONFIG_NUMAasmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_pages, compat_uptr_t __user *pages32, const int __user *nodes, int __user *status, int flags){ const void __user * __user *pages; int i; pages = compat_alloc_user_space(nr_pages * sizeof(void *)); for (i = 0; i < nr_pages; i++) { compat_uptr_t p; if (get_user(p, pages32 + i) || put_user(compat_ptr(p), pages + i)) return -EFAULT; } return sys_move_pages(pid, nr_pages, pages, nodes, status, flags);}asmlinkage long compat_sys_migrate_pages(compat_pid_t pid, compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes, const compat_ulong_t __user *new_nodes){ unsigned long __user *old = NULL; unsigned long __user *new = NULL; nodemask_t tmp_mask; unsigned long nr_bits; unsigned long size; nr_bits = min_t(unsigned long, maxnode - 1, MAX_NUMNODES); size = ALIGN(nr_bits, BITS_PER_LONG) / 8; if (old_nodes) { if (compat_get_bitmap(nodes_addr(tmp_mask), old_nodes, nr_bits)) return -EFAULT; old = compat_alloc_user_space(new_nodes ? size * 2 : size); if (new_nodes) new = old + size / sizeof(unsigned long); if (copy_to_user(old, nodes_addr(tmp_mask), size)) return -EFAULT; } if (new_nodes) { if (compat_get_bitmap(nodes_addr(tmp_mask), new_nodes, nr_bits)) return -EFAULT; if (new == NULL) new = compat_alloc_user_space(size); if (copy_to_user(new, nodes_addr(tmp_mask), size)) return -EFAULT; } return sys_migrate_pages(pid, nr_bits + 1, old, new);}#endifstruct compat_sysinfo { s32 uptime; u32 loads[3]; u32 totalram; u32 freeram; u32 sharedram; u32 bufferram; u32 totalswap; u32 freeswap; u16 procs; u16 pad; u32 totalhigh; u32 freehigh; u32 mem_unit; char _f[20-2*sizeof(u32)-sizeof(int)];};asmlinkage longcompat_sys_sysinfo(struct compat_sysinfo __user *info){ struct sysinfo s; do_sysinfo(&s); /* 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)) { int bitcount = 0; 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 (!access_ok(VERIFY_WRITE, info, sizeof(struct compat_sysinfo)) || __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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -