blob: f2a2975042871ee8607803bd5eca47acdbda005f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/kernel/compat.c
3 *
4 * Kernel compatibililty routines for e.g. 32 bit syscall support
5 * on 64 bit kernels.
6 *
7 * Copyright (C) 2002-2003 Stephen Rothwell, IBM Corporation
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/linkage.h>
15#include <linux/compat.h>
16#include <linux/errno.h>
17#include <linux/time.h>
18#include <linux/signal.h>
19#include <linux/sched.h> /* for MAX_SCHEDULE_TIMEOUT */
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <linux/syscalls.h>
21#include <linux/unistd.h>
22#include <linux/security.h>
Stephen Rothwell3158e942006-03-26 01:37:29 -080023#include <linux/timex.h>
Christoph Lameter1b2db9f2006-06-23 02:03:56 -070024#include <linux/migrate.h>
Toyo Abe1711ef32006-09-29 02:00:28 -070025#include <linux/posix-timers.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
27#include <asm/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
29int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts)
30{
31 return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) ||
32 __get_user(ts->tv_sec, &cts->tv_sec) ||
33 __get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
34}
35
36int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user *cts)
37{
38 return (!access_ok(VERIFY_WRITE, cts, sizeof(*cts)) ||
39 __put_user(ts->tv_sec, &cts->tv_sec) ||
40 __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
41}
42
Oleg Nesterov41652932008-02-01 20:35:31 +030043static long compat_nanosleep_restart(struct restart_block *restart)
44{
45 struct compat_timespec __user *rmtp;
46 struct timespec rmt;
47 mm_segment_t oldfs;
48 long ret;
49
50 rmtp = (struct compat_timespec __user *)(restart->arg1);
51 restart->arg1 = (unsigned long)&rmt;
52 oldfs = get_fs();
53 set_fs(KERNEL_DS);
54 ret = hrtimer_nanosleep_restart(restart);
55 set_fs(oldfs);
56
57 if (ret) {
58 restart->fn = compat_nanosleep_restart;
59 restart->arg1 = (unsigned long)rmtp;
60
61 if (rmtp && put_compat_timespec(&rmt, rmtp))
62 return -EFAULT;
63 }
64
65 return ret;
66}
67
Linus Torvalds1da177e2005-04-16 15:20:36 -070068asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp,
Anton Blanchardc70878b2007-10-15 16:13:56 -050069 struct compat_timespec __user *rmtp)
Linus Torvalds1da177e2005-04-16 15:20:36 -070070{
Anton Blanchardc70878b2007-10-15 16:13:56 -050071 struct timespec tu, rmt;
Oleg Nesterov41652932008-02-01 20:35:31 +030072 mm_segment_t oldfs;
Anton Blanchardc70878b2007-10-15 16:13:56 -050073 long ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Anton Blanchardc70878b2007-10-15 16:13:56 -050075 if (get_compat_timespec(&tu, rqtp))
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 return -EFAULT;
77
Anton Blanchardc70878b2007-10-15 16:13:56 -050078 if (!timespec_valid(&tu))
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 return -EINVAL;
80
Oleg Nesterov41652932008-02-01 20:35:31 +030081 oldfs = get_fs();
82 set_fs(KERNEL_DS);
83 ret = hrtimer_nanosleep(&tu,
84 rmtp ? (struct timespec __user *)&rmt : NULL,
85 HRTIMER_MODE_REL, CLOCK_MONOTONIC);
86 set_fs(oldfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
Oleg Nesterov41652932008-02-01 20:35:31 +030088 if (ret) {
89 struct restart_block *restart
90 = &current_thread_info()->restart_block;
91
92 restart->fn = compat_nanosleep_restart;
93 restart->arg1 = (unsigned long)rmtp;
94
95 if (rmtp && put_compat_timespec(&rmt, rmtp))
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 return -EFAULT;
97 }
Anton Blanchardc70878b2007-10-15 16:13:56 -050098
99 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100}
101
102static inline long get_compat_itimerval(struct itimerval *o,
103 struct compat_itimerval __user *i)
104{
105 return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
106 (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
107 __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
108 __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
109 __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
110}
111
112static inline long put_compat_itimerval(struct compat_itimerval __user *o,
113 struct itimerval *i)
114{
115 return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
116 (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
117 __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
118 __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
119 __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
120}
121
122asmlinkage long compat_sys_getitimer(int which,
123 struct compat_itimerval __user *it)
124{
125 struct itimerval kit;
126 int error;
127
128 error = do_getitimer(which, &kit);
129 if (!error && put_compat_itimerval(it, &kit))
130 error = -EFAULT;
131 return error;
132}
133
134asmlinkage long compat_sys_setitimer(int which,
135 struct compat_itimerval __user *in,
136 struct compat_itimerval __user *out)
137{
138 struct itimerval kin, kout;
139 int error;
140
141 if (in) {
142 if (get_compat_itimerval(&kin, in))
143 return -EFAULT;
144 } else
145 memset(&kin, 0, sizeof(kin));
146
147 error = do_setitimer(which, &kin, out ? &kout : NULL);
148 if (error || !out)
149 return error;
150 if (put_compat_itimerval(out, &kout))
151 return -EFAULT;
152 return 0;
153}
154
155asmlinkage long compat_sys_times(struct compat_tms __user *tbuf)
156{
157 /*
158 * In the SMP world we might just be unlucky and have one of
159 * the times increment as we use it. Since the value is an
160 * atomically safe type this is just fine. Conceptually its
161 * as if the syscall took an instant longer to occur.
162 */
163 if (tbuf) {
164 struct compat_tms tmp;
165 struct task_struct *tsk = current;
166 struct task_struct *t;
167 cputime_t utime, stime, cutime, cstime;
168
169 read_lock(&tasklist_lock);
170 utime = tsk->signal->utime;
171 stime = tsk->signal->stime;
172 t = tsk;
173 do {
174 utime = cputime_add(utime, t->utime);
175 stime = cputime_add(stime, t->stime);
176 t = next_thread(t);
177 } while (t != tsk);
178
179 /*
180 * While we have tasklist_lock read-locked, no dying thread
181 * can be updating current->signal->[us]time. Instead,
182 * we got their counts included in the live thread loop.
183 * However, another thread can come in right now and
184 * do a wait call that updates current->signal->c[us]time.
185 * To make sure we always see that pair updated atomically,
186 * we take the siglock around fetching them.
187 */
188 spin_lock_irq(&tsk->sighand->siglock);
189 cutime = tsk->signal->cutime;
190 cstime = tsk->signal->cstime;
191 spin_unlock_irq(&tsk->sighand->siglock);
192 read_unlock(&tasklist_lock);
193
194 tmp.tms_utime = compat_jiffies_to_clock_t(cputime_to_jiffies(utime));
195 tmp.tms_stime = compat_jiffies_to_clock_t(cputime_to_jiffies(stime));
196 tmp.tms_cutime = compat_jiffies_to_clock_t(cputime_to_jiffies(cutime));
197 tmp.tms_cstime = compat_jiffies_to_clock_t(cputime_to_jiffies(cstime));
198 if (copy_to_user(tbuf, &tmp, sizeof(tmp)))
199 return -EFAULT;
200 }
201 return compat_jiffies_to_clock_t(jiffies);
202}
203
204/*
205 * Assumption: old_sigset_t and compat_old_sigset_t are both
206 * types that can be passed to put_user()/get_user().
207 */
208
209asmlinkage long compat_sys_sigpending(compat_old_sigset_t __user *set)
210{
211 old_sigset_t s;
212 long ret;
213 mm_segment_t old_fs = get_fs();
214
215 set_fs(KERNEL_DS);
216 ret = sys_sigpending((old_sigset_t __user *) &s);
217 set_fs(old_fs);
218 if (ret == 0)
219 ret = put_user(s, set);
220 return ret;
221}
222
223asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set,
224 compat_old_sigset_t __user *oset)
225{
226 old_sigset_t s;
227 long ret;
228 mm_segment_t old_fs;
229
230 if (set && get_user(s, set))
231 return -EFAULT;
232 old_fs = get_fs();
233 set_fs(KERNEL_DS);
234 ret = sys_sigprocmask(how,
235 set ? (old_sigset_t __user *) &s : NULL,
236 oset ? (old_sigset_t __user *) &s : NULL);
237 set_fs(old_fs);
238 if (ret == 0)
239 if (oset)
240 ret = put_user(s, oset);
241 return ret;
242}
243
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244asmlinkage long compat_sys_setrlimit(unsigned int resource,
245 struct compat_rlimit __user *rlim)
246{
247 struct rlimit r;
248 int ret;
249 mm_segment_t old_fs = get_fs ();
250
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700251 if (resource >= RLIM_NLIMITS)
252 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
254 if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) ||
255 __get_user(r.rlim_cur, &rlim->rlim_cur) ||
256 __get_user(r.rlim_max, &rlim->rlim_max))
257 return -EFAULT;
258
259 if (r.rlim_cur == COMPAT_RLIM_INFINITY)
260 r.rlim_cur = RLIM_INFINITY;
261 if (r.rlim_max == COMPAT_RLIM_INFINITY)
262 r.rlim_max = RLIM_INFINITY;
263 set_fs(KERNEL_DS);
264 ret = sys_setrlimit(resource, (struct rlimit __user *) &r);
265 set_fs(old_fs);
266 return ret;
267}
268
269#ifdef COMPAT_RLIM_OLD_INFINITY
270
271asmlinkage long compat_sys_old_getrlimit(unsigned int resource,
272 struct compat_rlimit __user *rlim)
273{
274 struct rlimit r;
275 int ret;
276 mm_segment_t old_fs = get_fs();
277
278 set_fs(KERNEL_DS);
279 ret = sys_old_getrlimit(resource, &r);
280 set_fs(old_fs);
281
282 if (!ret) {
283 if (r.rlim_cur > COMPAT_RLIM_OLD_INFINITY)
284 r.rlim_cur = COMPAT_RLIM_INFINITY;
285 if (r.rlim_max > COMPAT_RLIM_OLD_INFINITY)
286 r.rlim_max = COMPAT_RLIM_INFINITY;
287
288 if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) ||
289 __put_user(r.rlim_cur, &rlim->rlim_cur) ||
290 __put_user(r.rlim_max, &rlim->rlim_max))
291 return -EFAULT;
292 }
293 return ret;
294}
295
296#endif
297
298asmlinkage long compat_sys_getrlimit (unsigned int resource,
299 struct compat_rlimit __user *rlim)
300{
301 struct rlimit r;
302 int ret;
303 mm_segment_t old_fs = get_fs();
304
305 set_fs(KERNEL_DS);
306 ret = sys_getrlimit(resource, (struct rlimit __user *) &r);
307 set_fs(old_fs);
308 if (!ret) {
309 if (r.rlim_cur > COMPAT_RLIM_INFINITY)
310 r.rlim_cur = COMPAT_RLIM_INFINITY;
311 if (r.rlim_max > COMPAT_RLIM_INFINITY)
312 r.rlim_max = COMPAT_RLIM_INFINITY;
313
314 if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) ||
315 __put_user(r.rlim_cur, &rlim->rlim_cur) ||
316 __put_user(r.rlim_max, &rlim->rlim_max))
317 return -EFAULT;
318 }
319 return ret;
320}
321
322int put_compat_rusage(const struct rusage *r, struct compat_rusage __user *ru)
323{
324 if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru)) ||
325 __put_user(r->ru_utime.tv_sec, &ru->ru_utime.tv_sec) ||
326 __put_user(r->ru_utime.tv_usec, &ru->ru_utime.tv_usec) ||
327 __put_user(r->ru_stime.tv_sec, &ru->ru_stime.tv_sec) ||
328 __put_user(r->ru_stime.tv_usec, &ru->ru_stime.tv_usec) ||
329 __put_user(r->ru_maxrss, &ru->ru_maxrss) ||
330 __put_user(r->ru_ixrss, &ru->ru_ixrss) ||
331 __put_user(r->ru_idrss, &ru->ru_idrss) ||
332 __put_user(r->ru_isrss, &ru->ru_isrss) ||
333 __put_user(r->ru_minflt, &ru->ru_minflt) ||
334 __put_user(r->ru_majflt, &ru->ru_majflt) ||
335 __put_user(r->ru_nswap, &ru->ru_nswap) ||
336 __put_user(r->ru_inblock, &ru->ru_inblock) ||
337 __put_user(r->ru_oublock, &ru->ru_oublock) ||
338 __put_user(r->ru_msgsnd, &ru->ru_msgsnd) ||
339 __put_user(r->ru_msgrcv, &ru->ru_msgrcv) ||
340 __put_user(r->ru_nsignals, &ru->ru_nsignals) ||
341 __put_user(r->ru_nvcsw, &ru->ru_nvcsw) ||
342 __put_user(r->ru_nivcsw, &ru->ru_nivcsw))
343 return -EFAULT;
344 return 0;
345}
346
347asmlinkage long compat_sys_getrusage(int who, struct compat_rusage __user *ru)
348{
349 struct rusage r;
350 int ret;
351 mm_segment_t old_fs = get_fs();
352
353 set_fs(KERNEL_DS);
354 ret = sys_getrusage(who, (struct rusage __user *) &r);
355 set_fs(old_fs);
356
357 if (ret)
358 return ret;
359
360 if (put_compat_rusage(&r, ru))
361 return -EFAULT;
362
363 return 0;
364}
365
366asmlinkage long
367compat_sys_wait4(compat_pid_t pid, compat_uint_t __user *stat_addr, int options,
368 struct compat_rusage __user *ru)
369{
370 if (!ru) {
371 return sys_wait4(pid, stat_addr, options, NULL);
372 } else {
373 struct rusage r;
374 int ret;
375 unsigned int status;
376 mm_segment_t old_fs = get_fs();
377
378 set_fs (KERNEL_DS);
379 ret = sys_wait4(pid,
380 (stat_addr ?
381 (unsigned int __user *) &status : NULL),
382 options, (struct rusage __user *) &r);
383 set_fs (old_fs);
384
385 if (ret > 0) {
386 if (put_compat_rusage(&r, ru))
387 return -EFAULT;
388 if (stat_addr && put_user(status, stat_addr))
389 return -EFAULT;
390 }
391 return ret;
392 }
393}
394
395asmlinkage long compat_sys_waitid(int which, compat_pid_t pid,
396 struct compat_siginfo __user *uinfo, int options,
397 struct compat_rusage __user *uru)
398{
399 siginfo_t info;
400 struct rusage ru;
401 long ret;
402 mm_segment_t old_fs = get_fs();
403
404 memset(&info, 0, sizeof(info));
405
406 set_fs(KERNEL_DS);
407 ret = sys_waitid(which, pid, (siginfo_t __user *)&info, options,
408 uru ? (struct rusage __user *)&ru : NULL);
409 set_fs(old_fs);
410
411 if ((ret < 0) || (info.si_signo == 0))
412 return ret;
413
414 if (uru) {
415 ret = put_compat_rusage(&ru, uru);
416 if (ret)
417 return ret;
418 }
419
420 BUG_ON(info.si_code & __SI_MASK);
421 info.si_code |= __SI_CHLD;
422 return copy_siginfo_to_user32(uinfo, &info);
423}
424
425static int compat_get_user_cpu_mask(compat_ulong_t __user *user_mask_ptr,
426 unsigned len, cpumask_t *new_mask)
427{
428 unsigned long *k;
429
430 if (len < sizeof(cpumask_t))
431 memset(new_mask, 0, sizeof(cpumask_t));
432 else if (len > sizeof(cpumask_t))
433 len = sizeof(cpumask_t);
434
435 k = cpus_addr(*new_mask);
436 return compat_get_bitmap(k, user_mask_ptr, len * 8);
437}
438
439asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid,
440 unsigned int len,
441 compat_ulong_t __user *user_mask_ptr)
442{
443 cpumask_t new_mask;
444 int retval;
445
446 retval = compat_get_user_cpu_mask(user_mask_ptr, len, &new_mask);
447 if (retval)
448 return retval;
449
450 return sched_setaffinity(pid, new_mask);
451}
452
453asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len,
454 compat_ulong_t __user *user_mask_ptr)
455{
456 int ret;
457 cpumask_t mask;
458 unsigned long *k;
459 unsigned int min_length = sizeof(cpumask_t);
460
461 if (NR_CPUS <= BITS_PER_COMPAT_LONG)
462 min_length = sizeof(compat_ulong_t);
463
464 if (len < min_length)
465 return -EINVAL;
466
467 ret = sched_getaffinity(pid, &mask);
468 if (ret < 0)
469 return ret;
470
471 k = cpus_addr(mask);
472 ret = compat_put_bitmap(user_mask_ptr, k, min_length * 8);
473 if (ret)
474 return ret;
475
476 return min_length;
477}
478
Davide Libenzi83f5d122007-05-10 22:23:18 -0700479int get_compat_itimerspec(struct itimerspec *dst,
480 const struct compat_itimerspec __user *src)
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700481{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 if (get_compat_timespec(&dst->it_interval, &src->it_interval) ||
483 get_compat_timespec(&dst->it_value, &src->it_value))
484 return -EFAULT;
485 return 0;
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700486}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
Davide Libenzi83f5d122007-05-10 22:23:18 -0700488int put_compat_itimerspec(struct compat_itimerspec __user *dst,
489 const struct itimerspec *src)
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700490{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 if (put_compat_timespec(&src->it_interval, &dst->it_interval) ||
492 put_compat_timespec(&src->it_value, &dst->it_value))
493 return -EFAULT;
494 return 0;
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700495}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
Christoph Hellwig3a0f69d2006-01-09 20:52:08 -0800497long compat_sys_timer_create(clockid_t which_clock,
498 struct compat_sigevent __user *timer_event_spec,
499 timer_t __user *created_timer_id)
500{
501 struct sigevent __user *event = NULL;
502
503 if (timer_event_spec) {
504 struct sigevent kevent;
505
506 event = compat_alloc_user_space(sizeof(*event));
507 if (get_compat_sigevent(&kevent, timer_event_spec) ||
508 copy_to_user(event, &kevent, sizeof(*event)))
509 return -EFAULT;
510 }
511
512 return sys_timer_create(which_clock, event, created_timer_id);
513}
514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515long compat_sys_timer_settime(timer_t timer_id, int flags,
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700516 struct compat_itimerspec __user *new,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 struct compat_itimerspec __user *old)
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700518{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 long err;
520 mm_segment_t oldfs;
521 struct itimerspec newts, oldts;
522
523 if (!new)
524 return -EINVAL;
525 if (get_compat_itimerspec(&newts, new))
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700526 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 oldfs = get_fs();
528 set_fs(KERNEL_DS);
529 err = sys_timer_settime(timer_id, flags,
530 (struct itimerspec __user *) &newts,
531 (struct itimerspec __user *) &oldts);
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700532 set_fs(oldfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 if (!err && old && put_compat_itimerspec(old, &oldts))
534 return -EFAULT;
535 return err;
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700536}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
538long compat_sys_timer_gettime(timer_t timer_id,
539 struct compat_itimerspec __user *setting)
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700540{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 long err;
542 mm_segment_t oldfs;
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700543 struct itimerspec ts;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
545 oldfs = get_fs();
546 set_fs(KERNEL_DS);
547 err = sys_timer_gettime(timer_id,
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700548 (struct itimerspec __user *) &ts);
549 set_fs(oldfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 if (!err && put_compat_itimerspec(setting, &ts))
551 return -EFAULT;
552 return err;
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700553}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555long compat_sys_clock_settime(clockid_t which_clock,
556 struct compat_timespec __user *tp)
557{
558 long err;
559 mm_segment_t oldfs;
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700560 struct timespec ts;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
562 if (get_compat_timespec(&ts, tp))
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700563 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 oldfs = get_fs();
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700565 set_fs(KERNEL_DS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 err = sys_clock_settime(which_clock,
567 (struct timespec __user *) &ts);
568 set_fs(oldfs);
569 return err;
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700570}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
572long compat_sys_clock_gettime(clockid_t which_clock,
573 struct compat_timespec __user *tp)
574{
575 long err;
576 mm_segment_t oldfs;
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700577 struct timespec ts;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
579 oldfs = get_fs();
580 set_fs(KERNEL_DS);
581 err = sys_clock_gettime(which_clock,
582 (struct timespec __user *) &ts);
583 set_fs(oldfs);
584 if (!err && put_compat_timespec(&ts, tp))
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700585 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 return err;
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700587}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
589long compat_sys_clock_getres(clockid_t which_clock,
590 struct compat_timespec __user *tp)
591{
592 long err;
593 mm_segment_t oldfs;
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700594 struct timespec ts;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596 oldfs = get_fs();
597 set_fs(KERNEL_DS);
598 err = sys_clock_getres(which_clock,
599 (struct timespec __user *) &ts);
600 set_fs(oldfs);
601 if (!err && tp && put_compat_timespec(&ts, tp))
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700602 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 return err;
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700604}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
Toyo Abe1711ef32006-09-29 02:00:28 -0700606static long compat_clock_nanosleep_restart(struct restart_block *restart)
607{
608 long err;
609 mm_segment_t oldfs;
610 struct timespec tu;
611 struct compat_timespec *rmtp = (struct compat_timespec *)(restart->arg1);
612
613 restart->arg1 = (unsigned long) &tu;
614 oldfs = get_fs();
615 set_fs(KERNEL_DS);
616 err = clock_nanosleep_restart(restart);
617 set_fs(oldfs);
618
619 if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
620 put_compat_timespec(&tu, rmtp))
621 return -EFAULT;
622
623 if (err == -ERESTART_RESTARTBLOCK) {
624 restart->fn = compat_clock_nanosleep_restart;
625 restart->arg1 = (unsigned long) rmtp;
626 }
627 return err;
628}
629
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,
631 struct compat_timespec __user *rqtp,
632 struct compat_timespec __user *rmtp)
633{
634 long err;
635 mm_segment_t oldfs;
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700636 struct timespec in, out;
Toyo Abe1711ef32006-09-29 02:00:28 -0700637 struct restart_block *restart;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700639 if (get_compat_timespec(&in, rqtp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 return -EFAULT;
641
642 oldfs = get_fs();
643 set_fs(KERNEL_DS);
644 err = sys_clock_nanosleep(which_clock, flags,
645 (struct timespec __user *) &in,
646 (struct timespec __user *) &out);
647 set_fs(oldfs);
Toyo Abe1711ef32006-09-29 02:00:28 -0700648
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
650 put_compat_timespec(&out, rmtp))
651 return -EFAULT;
Toyo Abe1711ef32006-09-29 02:00:28 -0700652
653 if (err == -ERESTART_RESTARTBLOCK) {
654 restart = &current_thread_info()->restart_block;
655 restart->fn = compat_clock_nanosleep_restart;
656 restart->arg1 = (unsigned long) rmtp;
657 }
Daniel Walkerbd3a8492007-10-18 03:06:09 -0700658 return err;
659}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
661/*
662 * We currently only need the following fields from the sigevent
663 * structure: sigev_value, sigev_signo, sig_notify and (sometimes
664 * sigev_notify_thread_id). The others are handled in user mode.
665 * We also assume that copying sigev_value.sival_int is sufficient
666 * to keep all the bits of sigev_value.sival_ptr intact.
667 */
668int get_compat_sigevent(struct sigevent *event,
669 const struct compat_sigevent __user *u_event)
670{
David S. Miller51410d32005-04-16 15:24:01 -0700671 memset(event, 0, sizeof(*event));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 return (!access_ok(VERIFY_READ, u_event, sizeof(*u_event)) ||
673 __get_user(event->sigev_value.sival_int,
674 &u_event->sigev_value.sival_int) ||
675 __get_user(event->sigev_signo, &u_event->sigev_signo) ||
676 __get_user(event->sigev_notify, &u_event->sigev_notify) ||
677 __get_user(event->sigev_notify_thread_id,
678 &u_event->sigev_notify_thread_id))
679 ? -EFAULT : 0;
680}
681
Stephen Rothwell5fa38392006-10-28 10:38:46 -0700682long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 unsigned long bitmap_size)
684{
685 int i, j;
686 unsigned long m;
687 compat_ulong_t um;
688 unsigned long nr_compat_longs;
689
690 /* align bitmap up to nearest compat_long_t boundary */
691 bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
692
693 if (!access_ok(VERIFY_READ, umask, bitmap_size / 8))
694 return -EFAULT;
695
696 nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
697
698 for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) {
699 m = 0;
700
701 for (j = 0; j < sizeof(m)/sizeof(um); j++) {
702 /*
703 * We dont want to read past the end of the userspace
704 * bitmap. We must however ensure the end of the
705 * kernel bitmap is zeroed.
706 */
707 if (nr_compat_longs-- > 0) {
708 if (__get_user(um, umask))
709 return -EFAULT;
710 } else {
711 um = 0;
712 }
713
714 umask++;
715 m |= (long)um << (j * BITS_PER_COMPAT_LONG);
716 }
717 *mask++ = m;
718 }
719
720 return 0;
721}
722
723long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
724 unsigned long bitmap_size)
725{
726 int i, j;
727 unsigned long m;
728 compat_ulong_t um;
729 unsigned long nr_compat_longs;
730
731 /* align bitmap up to nearest compat_long_t boundary */
732 bitmap_size = ALIGN(bitmap_size, BITS_PER_COMPAT_LONG);
733
734 if (!access_ok(VERIFY_WRITE, umask, bitmap_size / 8))
735 return -EFAULT;
736
737 nr_compat_longs = BITS_TO_COMPAT_LONGS(bitmap_size);
738
739 for (i = 0; i < BITS_TO_LONGS(bitmap_size); i++) {
740 m = *mask++;
741
742 for (j = 0; j < sizeof(m)/sizeof(um); j++) {
743 um = m;
744
745 /*
746 * We dont want to write past the end of the userspace
747 * bitmap.
748 */
749 if (nr_compat_longs-- > 0) {
750 if (__put_user(um, umask))
751 return -EFAULT;
752 }
753
754 umask++;
755 m >>= 4*sizeof(um);
756 m >>= 4*sizeof(um);
757 }
758 }
759
760 return 0;
761}
762
763void
764sigset_from_compat (sigset_t *set, compat_sigset_t *compat)
765{
766 switch (_NSIG_WORDS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32 );
768 case 3: set->sig[2] = compat->sig[4] | (((long)compat->sig[5]) << 32 );
769 case 2: set->sig[1] = compat->sig[2] | (((long)compat->sig[3]) << 32 );
770 case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 32 );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 }
772}
773
774asmlinkage long
775compat_sys_rt_sigtimedwait (compat_sigset_t __user *uthese,
776 struct compat_siginfo __user *uinfo,
777 struct compat_timespec __user *uts, compat_size_t sigsetsize)
778{
779 compat_sigset_t s32;
780 sigset_t s;
781 int sig;
782 struct timespec t;
783 siginfo_t info;
784 long ret, timeout = 0;
785
786 if (sigsetsize != sizeof(sigset_t))
787 return -EINVAL;
788
789 if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t)))
790 return -EFAULT;
791 sigset_from_compat(&s, &s32);
792 sigdelsetmask(&s,sigmask(SIGKILL)|sigmask(SIGSTOP));
793 signotset(&s);
794
795 if (uts) {
796 if (get_compat_timespec (&t, uts))
797 return -EFAULT;
798 if (t.tv_nsec >= 1000000000L || t.tv_nsec < 0
799 || t.tv_sec < 0)
800 return -EINVAL;
801 }
802
803 spin_lock_irq(&current->sighand->siglock);
804 sig = dequeue_signal(current, &s, &info);
805 if (!sig) {
806 timeout = MAX_SCHEDULE_TIMEOUT;
807 if (uts)
808 timeout = timespec_to_jiffies(&t)
809 +(t.tv_sec || t.tv_nsec);
810 if (timeout) {
811 current->real_blocked = current->blocked;
812 sigandsets(&current->blocked, &current->blocked, &s);
813
814 recalc_sigpending();
815 spin_unlock_irq(&current->sighand->siglock);
816
Nishanth Aravamudan75bcc8c2005-09-10 00:27:24 -0700817 timeout = schedule_timeout_interruptible(timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
819 spin_lock_irq(&current->sighand->siglock);
820 sig = dequeue_signal(current, &s, &info);
821 current->blocked = current->real_blocked;
822 siginitset(&current->real_blocked, 0);
823 recalc_sigpending();
824 }
825 }
826 spin_unlock_irq(&current->sighand->siglock);
827
828 if (sig) {
829 ret = sig;
830 if (uinfo) {
831 if (copy_siginfo_to_user32(uinfo, &info))
832 ret = -EFAULT;
833 }
834 }else {
835 ret = timeout?-EINTR:-EAGAIN;
836 }
837 return ret;
838
839}
840
841#ifdef __ARCH_WANT_COMPAT_SYS_TIME
842
843/* compat_time_t is a 32 bit "long" and needs to get converted. */
844
845asmlinkage long compat_sys_time(compat_time_t __user * tloc)
846{
847 compat_time_t i;
848 struct timeval tv;
849
850 do_gettimeofday(&tv);
851 i = tv.tv_sec;
852
853 if (tloc) {
854 if (put_user(i,tloc))
855 i = -EFAULT;
856 }
857 return i;
858}
859
860asmlinkage long compat_sys_stime(compat_time_t __user *tptr)
861{
862 struct timespec tv;
863 int err;
864
865 if (get_user(tv.tv_sec, tptr))
866 return -EFAULT;
867
868 tv.tv_nsec = 0;
869
870 err = security_settime(&tv, NULL);
871 if (err)
872 return err;
873
874 do_settimeofday(&tv);
875 return 0;
876}
877
878#endif /* __ARCH_WANT_COMPAT_SYS_TIME */
David Woodhouse150256d2006-01-18 17:43:57 -0800879
880#ifdef __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
881asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat_size_t sigsetsize)
882{
883 sigset_t newset;
884 compat_sigset_t newset32;
885
886 /* XXX: Don't preclude handling different sized sigset_t's. */
887 if (sigsetsize != sizeof(sigset_t))
888 return -EINVAL;
889
890 if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t)))
891 return -EFAULT;
892 sigset_from_compat(&newset, &newset32);
893 sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
894
895 spin_lock_irq(&current->sighand->siglock);
896 current->saved_sigmask = current->blocked;
897 current->blocked = newset;
898 recalc_sigpending();
899 spin_unlock_irq(&current->sighand->siglock);
900
901 current->state = TASK_INTERRUPTIBLE;
902 schedule();
903 set_thread_flag(TIF_RESTORE_SIGMASK);
904 return -ERESTARTNOHAND;
905}
906#endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */
Stephen Rothwell3158e942006-03-26 01:37:29 -0800907
908asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp)
909{
910 struct timex txc;
911 int ret;
912
913 memset(&txc, 0, sizeof(struct timex));
914
915 if (!access_ok(VERIFY_READ, utp, sizeof(struct compat_timex)) ||
916 __get_user(txc.modes, &utp->modes) ||
917 __get_user(txc.offset, &utp->offset) ||
918 __get_user(txc.freq, &utp->freq) ||
919 __get_user(txc.maxerror, &utp->maxerror) ||
920 __get_user(txc.esterror, &utp->esterror) ||
921 __get_user(txc.status, &utp->status) ||
922 __get_user(txc.constant, &utp->constant) ||
923 __get_user(txc.precision, &utp->precision) ||
924 __get_user(txc.tolerance, &utp->tolerance) ||
925 __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
926 __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
927 __get_user(txc.tick, &utp->tick) ||
928 __get_user(txc.ppsfreq, &utp->ppsfreq) ||
929 __get_user(txc.jitter, &utp->jitter) ||
930 __get_user(txc.shift, &utp->shift) ||
931 __get_user(txc.stabil, &utp->stabil) ||
932 __get_user(txc.jitcnt, &utp->jitcnt) ||
933 __get_user(txc.calcnt, &utp->calcnt) ||
934 __get_user(txc.errcnt, &utp->errcnt) ||
935 __get_user(txc.stbcnt, &utp->stbcnt))
936 return -EFAULT;
937
938 ret = do_adjtimex(&txc);
939
940 if (!access_ok(VERIFY_WRITE, utp, sizeof(struct compat_timex)) ||
941 __put_user(txc.modes, &utp->modes) ||
942 __put_user(txc.offset, &utp->offset) ||
943 __put_user(txc.freq, &utp->freq) ||
944 __put_user(txc.maxerror, &utp->maxerror) ||
945 __put_user(txc.esterror, &utp->esterror) ||
946 __put_user(txc.status, &utp->status) ||
947 __put_user(txc.constant, &utp->constant) ||
948 __put_user(txc.precision, &utp->precision) ||
949 __put_user(txc.tolerance, &utp->tolerance) ||
950 __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
951 __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
952 __put_user(txc.tick, &utp->tick) ||
953 __put_user(txc.ppsfreq, &utp->ppsfreq) ||
954 __put_user(txc.jitter, &utp->jitter) ||
955 __put_user(txc.shift, &utp->shift) ||
956 __put_user(txc.stabil, &utp->stabil) ||
957 __put_user(txc.jitcnt, &utp->jitcnt) ||
958 __put_user(txc.calcnt, &utp->calcnt) ||
959 __put_user(txc.errcnt, &utp->errcnt) ||
960 __put_user(txc.stbcnt, &utp->stbcnt))
961 ret = -EFAULT;
962
963 return ret;
964}
Christoph Lameter1b2db9f2006-06-23 02:03:56 -0700965
966#ifdef CONFIG_NUMA
967asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_pages,
Christoph Lameter9216dfa2006-06-23 02:03:57 -0700968 compat_uptr_t __user *pages32,
Christoph Lameter1b2db9f2006-06-23 02:03:56 -0700969 const int __user *nodes,
970 int __user *status,
971 int flags)
972{
973 const void __user * __user *pages;
974 int i;
975
976 pages = compat_alloc_user_space(nr_pages * sizeof(void *));
977 for (i = 0; i < nr_pages; i++) {
978 compat_uptr_t p;
979
Christoph Lameter9216dfa2006-06-23 02:03:57 -0700980 if (get_user(p, pages32 + i) ||
Christoph Lameter1b2db9f2006-06-23 02:03:56 -0700981 put_user(compat_ptr(p), pages + i))
982 return -EFAULT;
983 }
984 return sys_move_pages(pid, nr_pages, pages, nodes, status, flags);
985}
Stephen Rothwell3fd59392006-11-02 22:07:24 -0800986
987asmlinkage long compat_sys_migrate_pages(compat_pid_t pid,
988 compat_ulong_t maxnode,
989 const compat_ulong_t __user *old_nodes,
990 const compat_ulong_t __user *new_nodes)
991{
992 unsigned long __user *old = NULL;
993 unsigned long __user *new = NULL;
994 nodemask_t tmp_mask;
995 unsigned long nr_bits;
996 unsigned long size;
997
998 nr_bits = min_t(unsigned long, maxnode - 1, MAX_NUMNODES);
999 size = ALIGN(nr_bits, BITS_PER_LONG) / 8;
1000 if (old_nodes) {
1001 if (compat_get_bitmap(nodes_addr(tmp_mask), old_nodes, nr_bits))
1002 return -EFAULT;
1003 old = compat_alloc_user_space(new_nodes ? size * 2 : size);
1004 if (new_nodes)
1005 new = old + size / sizeof(unsigned long);
1006 if (copy_to_user(old, nodes_addr(tmp_mask), size))
1007 return -EFAULT;
1008 }
1009 if (new_nodes) {
1010 if (compat_get_bitmap(nodes_addr(tmp_mask), new_nodes, nr_bits))
1011 return -EFAULT;
1012 if (new == NULL)
1013 new = compat_alloc_user_space(size);
1014 if (copy_to_user(new, nodes_addr(tmp_mask), size))
1015 return -EFAULT;
1016 }
1017 return sys_migrate_pages(pid, nr_bits + 1, old, new);
1018}
Christoph Lameter1b2db9f2006-06-23 02:03:56 -07001019#endif
Kyle McMartind4d23ad2007-02-10 01:46:00 -08001020
1021struct compat_sysinfo {
1022 s32 uptime;
1023 u32 loads[3];
1024 u32 totalram;
1025 u32 freeram;
1026 u32 sharedram;
1027 u32 bufferram;
1028 u32 totalswap;
1029 u32 freeswap;
1030 u16 procs;
1031 u16 pad;
1032 u32 totalhigh;
1033 u32 freehigh;
1034 u32 mem_unit;
1035 char _f[20-2*sizeof(u32)-sizeof(int)];
1036};
1037
1038asmlinkage long
1039compat_sys_sysinfo(struct compat_sysinfo __user *info)
1040{
1041 struct sysinfo s;
1042
1043 do_sysinfo(&s);
1044
1045 /* Check to see if any memory value is too large for 32-bit and scale
1046 * down if needed
1047 */
1048 if ((s.totalram >> 32) || (s.totalswap >> 32)) {
1049 int bitcount = 0;
1050
1051 while (s.mem_unit < PAGE_SIZE) {
1052 s.mem_unit <<= 1;
1053 bitcount++;
1054 }
1055
1056 s.totalram >>= bitcount;
1057 s.freeram >>= bitcount;
1058 s.sharedram >>= bitcount;
1059 s.bufferram >>= bitcount;
1060 s.totalswap >>= bitcount;
1061 s.freeswap >>= bitcount;
1062 s.totalhigh >>= bitcount;
1063 s.freehigh >>= bitcount;
1064 }
1065
1066 if (!access_ok(VERIFY_WRITE, info, sizeof(struct compat_sysinfo)) ||
1067 __put_user (s.uptime, &info->uptime) ||
1068 __put_user (s.loads[0], &info->loads[0]) ||
1069 __put_user (s.loads[1], &info->loads[1]) ||
1070 __put_user (s.loads[2], &info->loads[2]) ||
1071 __put_user (s.totalram, &info->totalram) ||
1072 __put_user (s.freeram, &info->freeram) ||
1073 __put_user (s.sharedram, &info->sharedram) ||
1074 __put_user (s.bufferram, &info->bufferram) ||
1075 __put_user (s.totalswap, &info->totalswap) ||
1076 __put_user (s.freeswap, &info->freeswap) ||
1077 __put_user (s.procs, &info->procs) ||
1078 __put_user (s.totalhigh, &info->totalhigh) ||
1079 __put_user (s.freehigh, &info->freehigh) ||
1080 __put_user (s.mem_unit, &info->mem_unit))
1081 return -EFAULT;
1082
1083 return 0;
1084}
1085