[PATCH] hlist constification
[linux-2.6/history.git] / kernel / compat.c
blob44d3ab9bc668ad4dd3ea0a395d2624e1cbd45598
1 /*
2 * linux/kernel/compat.c
4 * Kernel compatibililty routines for e.g. 32 bit syscall support
5 * on 64 bit kernels.
7 * Copyright (C) 2002-2003 Stephen Rothwell, IBM Corporation
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.
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 */
20 #include <linux/futex.h> /* for FUTEX_WAIT */
21 #include <linux/unistd.h>
23 #include <asm/uaccess.h>
25 int get_compat_timespec(struct timespec *ts, struct compat_timespec *cts)
27 return (verify_area(VERIFY_READ, cts, sizeof(*cts)) ||
28 __get_user(ts->tv_sec, &cts->tv_sec) ||
29 __get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
32 int put_compat_timespec(struct timespec *ts, struct compat_timespec *cts)
34 return (verify_area(VERIFY_WRITE, cts, sizeof(*cts)) ||
35 __put_user(ts->tv_sec, &cts->tv_sec) ||
36 __put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
39 static long compat_nanosleep_restart(struct restart_block *restart)
41 unsigned long expire = restart->arg0, now = jiffies;
42 struct compat_timespec *rmtp;
44 /* Did it expire while we handled signals? */
45 if (!time_after(expire, now))
46 return 0;
48 current->state = TASK_INTERRUPTIBLE;
49 expire = schedule_timeout(expire - now);
50 if (expire == 0)
51 return 0;
53 rmtp = (struct compat_timespec *)restart->arg1;
54 if (rmtp) {
55 struct compat_timespec ct;
56 struct timespec t;
58 jiffies_to_timespec(expire, &t);
59 ct.tv_sec = t.tv_sec;
60 ct.tv_nsec = t.tv_nsec;
61 if (copy_to_user(rmtp, &ct, sizeof(ct)))
62 return -EFAULT;
64 /* The 'restart' block is already filled in */
65 return -ERESTART_RESTARTBLOCK;
68 asmlinkage long compat_sys_nanosleep(struct compat_timespec *rqtp,
69 struct compat_timespec *rmtp)
71 struct timespec t;
72 struct restart_block *restart;
73 unsigned long expire;
75 if (get_compat_timespec(&t, rqtp))
76 return -EFAULT;
78 if ((t.tv_nsec >= 1000000000L) || (t.tv_nsec < 0) || (t.tv_sec < 0))
79 return -EINVAL;
81 expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec);
82 current->state = TASK_INTERRUPTIBLE;
83 expire = schedule_timeout(expire);
84 if (expire == 0)
85 return 0;
87 if (rmtp) {
88 jiffies_to_timespec(expire, &t);
89 if (put_compat_timespec(&t, rmtp))
90 return -EFAULT;
92 restart = &current_thread_info()->restart_block;
93 restart->fn = compat_nanosleep_restart;
94 restart->arg0 = jiffies + expire;
95 restart->arg1 = (unsigned long) rmtp;
96 return -ERESTART_RESTARTBLOCK;
99 static inline long get_compat_itimerval(struct itimerval *o,
100 struct compat_itimerval *i)
102 return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
103 (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
104 __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
105 __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
106 __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
109 static inline long put_compat_itimerval(struct compat_itimerval *o,
110 struct itimerval *i)
112 return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
113 (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
114 __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
115 __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
116 __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
119 asmlinkage long compat_sys_getitimer(int which, struct compat_itimerval *it)
121 struct itimerval kit;
122 int error;
124 error = do_getitimer(which, &kit);
125 if (!error && put_compat_itimerval(it, &kit))
126 error = -EFAULT;
127 return error;
130 asmlinkage long compat_sys_setitimer(int which, struct compat_itimerval *in,
131 struct compat_itimerval *out)
133 struct itimerval kin, kout;
134 int error;
136 if (in) {
137 if (get_compat_itimerval(&kin, in))
138 return -EFAULT;
139 } else
140 memset(&kin, 0, sizeof(kin));
142 error = do_setitimer(which, &kin, out ? &kout : NULL);
143 if (error || !out)
144 return error;
145 if (put_compat_itimerval(out, &kout))
146 return -EFAULT;
147 return 0;
150 asmlinkage long compat_sys_times(struct compat_tms *tbuf)
153 * In the SMP world we might just be unlucky and have one of
154 * the times increment as we use it. Since the value is an
155 * atomically safe type this is just fine. Conceptually its
156 * as if the syscall took an instant longer to occur.
158 if (tbuf) {
159 struct compat_tms tmp;
160 tmp.tms_utime = compat_jiffies_to_clock_t(current->utime);
161 tmp.tms_stime = compat_jiffies_to_clock_t(current->stime);
162 tmp.tms_cutime = compat_jiffies_to_clock_t(current->cutime);
163 tmp.tms_cstime = compat_jiffies_to_clock_t(current->cstime);
164 if (copy_to_user(tbuf, &tmp, sizeof(tmp)))
165 return -EFAULT;
167 return compat_jiffies_to_clock_t(jiffies);
171 * Assumption: old_sigset_t and compat_old_sigset_t are both
172 * types that can be passed to put_user()/get_user().
175 extern asmlinkage long sys_sigpending(old_sigset_t *);
177 asmlinkage long compat_sys_sigpending(compat_old_sigset_t *set)
179 old_sigset_t s;
180 long ret;
181 mm_segment_t old_fs = get_fs();
183 set_fs(KERNEL_DS);
184 ret = sys_sigpending(&s);
185 set_fs(old_fs);
186 if (ret == 0)
187 ret = put_user(s, set);
188 return ret;
191 extern asmlinkage long sys_sigprocmask(int, old_sigset_t *, old_sigset_t *);
193 asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t *set,
194 compat_old_sigset_t *oset)
196 old_sigset_t s;
197 long ret;
198 mm_segment_t old_fs;
200 if (set && get_user(s, set))
201 return -EFAULT;
202 old_fs = get_fs();
203 set_fs(KERNEL_DS);
204 ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL);
205 set_fs(old_fs);
206 if (ret == 0)
207 ret = put_user(s, oset);
208 return ret;
211 #ifdef CONFIG_FUTEX
212 asmlinkage long compat_sys_futex(u32 *uaddr, int op, int val,
213 struct compat_timespec *utime, u32 *uaddr2)
215 struct timespec t;
216 unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
217 int val2 = 0;
219 if ((op == FUTEX_WAIT) && utime) {
220 if (get_compat_timespec(&t, utime))
221 return -EFAULT;
222 timeout = timespec_to_jiffies(&t) + 1;
224 if (op == FUTEX_REQUEUE)
225 val2 = (int) (long) utime;
227 return do_futex((unsigned long)uaddr, op, val, timeout,
228 (unsigned long)uaddr2, val2);
230 #endif
232 asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim);
234 asmlinkage long compat_sys_setrlimit(unsigned int resource, struct compat_rlimit *rlim)
236 struct rlimit r;
237 int ret;
238 mm_segment_t old_fs = get_fs ();
240 if (resource >= RLIM_NLIMITS)
241 return -EINVAL;
243 if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) ||
244 __get_user(r.rlim_cur, &rlim->rlim_cur) ||
245 __get_user(r.rlim_max, &rlim->rlim_max))
246 return -EFAULT;
248 if (r.rlim_cur == COMPAT_RLIM_INFINITY)
249 r.rlim_cur = RLIM_INFINITY;
250 if (r.rlim_max == COMPAT_RLIM_INFINITY)
251 r.rlim_max = RLIM_INFINITY;
252 set_fs(KERNEL_DS);
253 ret = sys_setrlimit(resource, &r);
254 set_fs(old_fs);
255 return ret;
258 #ifdef COMPAT_RLIM_OLD_INFINITY
259 asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit *rlim);
261 asmlinkage long compat_sys_old_getrlimit(unsigned int resource, struct compat_rlimit *rlim)
263 struct rlimit r;
264 int ret;
265 mm_segment_t old_fs = get_fs();
267 set_fs(KERNEL_DS);
268 ret = sys_old_getrlimit(resource, &r);
269 set_fs(old_fs);
271 if (!ret) {
272 if (r.rlim_cur > COMPAT_RLIM_OLD_INFINITY)
273 r.rlim_cur = COMPAT_RLIM_INFINITY;
274 if (r.rlim_max > COMPAT_RLIM_OLD_INFINITY)
275 r.rlim_max = COMPAT_RLIM_INFINITY;
277 if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) ||
278 __put_user(r.rlim_cur, &rlim->rlim_cur) ||
279 __put_user(r.rlim_max, &rlim->rlim_max))
280 return -EFAULT;
282 return ret;
284 #endif
286 asmlinkage long sys_getrlimit (unsigned int resource, struct rlimit *rlim);
288 asmlinkage long compat_sys_getrlimit (unsigned int resource, struct compat_rlimit *rlim)
290 struct rlimit r;
291 int ret;
292 mm_segment_t old_fs = get_fs();
294 set_fs(KERNEL_DS);
295 ret = sys_getrlimit(resource, &r);
296 set_fs(old_fs);
297 if (!ret) {
298 if (r.rlim_cur > COMPAT_RLIM_INFINITY)
299 r.rlim_cur = COMPAT_RLIM_INFINITY;
300 if (r.rlim_max > COMPAT_RLIM_INFINITY)
301 r.rlim_max = COMPAT_RLIM_INFINITY;
303 if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) ||
304 __put_user(r.rlim_cur, &rlim->rlim_cur) ||
305 __put_user(r.rlim_max, &rlim->rlim_max))
306 return -EFAULT;
308 return ret;
311 static long put_compat_rusage (struct compat_rusage *ru, struct rusage *r)
313 if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru)) ||
314 __put_user(r->ru_utime.tv_sec, &ru->ru_utime.tv_sec) ||
315 __put_user(r->ru_utime.tv_usec, &ru->ru_utime.tv_usec) ||
316 __put_user(r->ru_stime.tv_sec, &ru->ru_stime.tv_sec) ||
317 __put_user(r->ru_stime.tv_usec, &ru->ru_stime.tv_usec) ||
318 __put_user(r->ru_maxrss, &ru->ru_maxrss) ||
319 __put_user(r->ru_ixrss, &ru->ru_ixrss) ||
320 __put_user(r->ru_idrss, &ru->ru_idrss) ||
321 __put_user(r->ru_isrss, &ru->ru_isrss) ||
322 __put_user(r->ru_minflt, &ru->ru_minflt) ||
323 __put_user(r->ru_majflt, &ru->ru_majflt) ||
324 __put_user(r->ru_nswap, &ru->ru_nswap) ||
325 __put_user(r->ru_inblock, &ru->ru_inblock) ||
326 __put_user(r->ru_oublock, &ru->ru_oublock) ||
327 __put_user(r->ru_msgsnd, &ru->ru_msgsnd) ||
328 __put_user(r->ru_msgrcv, &ru->ru_msgrcv) ||
329 __put_user(r->ru_nsignals, &ru->ru_nsignals) ||
330 __put_user(r->ru_nvcsw, &ru->ru_nvcsw) ||
331 __put_user(r->ru_nivcsw, &ru->ru_nivcsw))
332 return -EFAULT;
333 return 0;
336 asmlinkage long sys_getrusage(int who, struct rusage *ru);
338 asmlinkage long compat_sys_getrusage(int who, struct compat_rusage *ru)
340 struct rusage r;
341 int ret;
342 mm_segment_t old_fs = get_fs();
344 set_fs(KERNEL_DS);
345 ret = sys_getrusage(who, &r);
346 set_fs(old_fs);
348 if (ret)
349 return ret;
351 if (put_compat_rusage(ru, &r))
352 return -EFAULT;
354 return 0;
357 asmlinkage long
358 compat_sys_wait4(compat_pid_t pid, compat_uint_t * stat_addr, int options,
359 struct compat_rusage *ru)
361 if (!ru) {
362 return sys_wait4(pid, stat_addr, options, NULL);
363 } else {
364 struct rusage r;
365 int ret;
366 unsigned int status;
367 mm_segment_t old_fs = get_fs();
369 set_fs (KERNEL_DS);
370 ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
371 set_fs (old_fs);
373 if (ret > 0) {
374 if (put_compat_rusage(ru, &r))
375 return -EFAULT;
376 if (stat_addr && put_user(status, stat_addr))
377 return -EFAULT;
379 return ret;
383 extern asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len,
384 unsigned long *user_mask_ptr);
386 asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid,
387 unsigned int len,
388 compat_ulong_t *user_mask_ptr)
390 unsigned long kernel_mask;
391 mm_segment_t old_fs;
392 int ret;
394 if (get_user(kernel_mask, user_mask_ptr))
395 return -EFAULT;
397 old_fs = get_fs();
398 set_fs(KERNEL_DS);
399 ret = sys_sched_setaffinity(pid,
400 sizeof(kernel_mask),
401 &kernel_mask);
402 set_fs(old_fs);
404 return ret;
407 extern asmlinkage long sys_sched_getaffinity(pid_t pid, unsigned int len,
408 unsigned long *user_mask_ptr);
410 asmlinkage int compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len,
411 compat_ulong_t *user_mask_ptr)
413 unsigned long kernel_mask;
414 mm_segment_t old_fs;
415 int ret;
417 old_fs = get_fs();
418 set_fs(KERNEL_DS);
419 ret = sys_sched_getaffinity(pid,
420 sizeof(kernel_mask),
421 &kernel_mask);
422 set_fs(old_fs);
424 if (ret > 0) {
425 ret = sizeof(compat_ulong_t);
426 if (put_user(kernel_mask, user_mask_ptr))
427 return -EFAULT;
430 return ret;
433 static int get_compat_itimerspec(struct itimerspec *dst,
434 struct compat_itimerspec *src)
436 if (get_compat_timespec(&dst->it_interval, &src->it_interval) ||
437 get_compat_timespec(&dst->it_value, &src->it_value))
438 return -EFAULT;
439 return 0;
442 static int put_compat_itimerspec(struct compat_itimerspec *dst,
443 struct itimerspec *src)
445 if (put_compat_timespec(&src->it_interval, &dst->it_interval) ||
446 put_compat_timespec(&src->it_value, &dst->it_value))
447 return -EFAULT;
448 return 0;
451 extern asmlinkage long sys_timer_settime(timer_t timer_id, int flags,
452 struct itimerspec __user *new_setting,
453 struct itimerspec __user *old_setting);
454 extern asmlinkage long sys_timer_gettime(timer_t timer_id,
455 struct itimerspec __user *setting);
457 long compat_timer_settime(timer_t timer_id, int flags,
458 struct compat_itimerspec *new,
459 struct compat_itimerspec *old)
461 long err;
462 mm_segment_t oldfs;
463 struct itimerspec newts, oldts;
464 if (get_compat_itimerspec(&newts, new))
465 return -EFAULT;
466 oldfs = get_fs();
467 set_fs(KERNEL_DS);
468 err = sys_timer_settime(timer_id, flags, &newts, &oldts);
469 set_fs(oldfs);
470 if (!err && old && put_compat_itimerspec(old, &oldts))
471 return -EFAULT;
472 return err;
475 long compat_timer_gettime(timer_t timer_id, struct compat_itimerspec *setting)
477 long err;
478 mm_segment_t oldfs;
479 struct itimerspec ts;
480 oldfs = get_fs();
481 set_fs(KERNEL_DS);
482 err = sys_timer_gettime(timer_id, &ts);
483 set_fs(oldfs);
484 if (!err && put_compat_itimerspec(setting, &ts))
485 return -EFAULT;
486 return err;
489 extern asmlinkage long
490 sys_clock_settime(clockid_t which_clock, struct timespec __user *tp);
492 long compat_clock_settime(clockid_t which_clock, struct compat_timespec *tp)
494 long err;
495 mm_segment_t oldfs;
496 struct timespec ts;
497 if (get_compat_timespec(&ts, tp))
498 return -EFAULT;
499 oldfs = get_fs();
500 set_fs(KERNEL_DS);
501 err = sys_clock_settime(which_clock, &ts);
502 set_fs(oldfs);
503 return err;
506 extern asmlinkage long
507 sys_clock_gettime(clockid_t which_clock, struct timespec __user *tp);
509 long compat_clock_gettime(clockid_t which_clock, struct compat_timespec *tp)
511 long err;
512 mm_segment_t oldfs;
513 struct timespec ts;
514 oldfs = get_fs();
515 set_fs(KERNEL_DS);
516 err = sys_clock_gettime(which_clock, &ts);
517 set_fs(oldfs);
518 if (!err && put_compat_timespec(&ts, tp))
519 return -EFAULT;
520 return err;
523 extern asmlinkage long
524 sys_clock_getres(clockid_t which_clock, struct timespec __user *tp);
526 long compat_clock_getres(clockid_t which_clock, struct compat_timespec *tp)
528 long err;
529 mm_segment_t oldfs;
530 struct timespec ts;
531 oldfs = get_fs();
532 set_fs(KERNEL_DS);
533 err = sys_clock_getres(which_clock, &ts);
534 set_fs(oldfs);
535 if (!err && put_compat_timespec(&ts, tp))
536 return -EFAULT;
537 return err;
540 extern asmlinkage long
541 sys_clock_nanosleep(clockid_t which_clock, int flags,
542 struct timespec __user *rqtp,
543 struct timespec __user *rmtp);
545 long compat_clock_nanosleep(clockid_t which_clock, int flags,
546 struct compat_timespec __user *rqtp,
547 struct compat_timespec __user *rmtp)
549 long err;
550 mm_segment_t oldfs;
551 struct timespec in, out;
552 if (get_compat_timespec(&in, rqtp))
553 return -EFAULT;
554 oldfs = get_fs();
555 set_fs(KERNEL_DS);
556 err = sys_clock_nanosleep(which_clock, flags, &in, &out);
557 set_fs(oldfs);
558 if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
559 put_compat_timespec(&out, rmtp))
560 return -EFAULT;
561 return err;
564 /* timer_create is architecture specific because it needs sigevent conversion */