Blame view

kernel/compat.c 28.3 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  /*
   *  linux/kernel/compat.c
   *
   *  Kernel compatibililty routines for e.g. 32 bit syscall support
   *  on 64 bit kernels.
   *
   *  Copyright (C) 2002-2003 Stephen Rothwell, IBM Corporation
   *
   *  This program is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License version 2 as
   *  published by the Free Software Foundation.
   */
  
  #include <linux/linkage.h>
  #include <linux/compat.h>
  #include <linux/errno.h>
  #include <linux/time.h>
  #include <linux/signal.h>
  #include <linux/sched.h>	/* for MAX_SCHEDULE_TIMEOUT */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
  #include <linux/syscalls.h>
  #include <linux/unistd.h>
  #include <linux/security.h>
3158e9411   Stephen Rothwell   [PATCH] consolida...
23
  #include <linux/timex.h>
1b2db9fb7   Christoph Lameter   [PATCH] sys_move_...
24
  #include <linux/migrate.h>
1711ef386   Toyo Abe   [PATCH] posix-tim...
25
  #include <linux/posix-timers.h>
f06febc96   Frank Mayhar   timers: fix itime...
26
  #include <linux/times.h>
e3d5a27d5   Paul Mackerras   Allow times and t...
27
  #include <linux/ptrace.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
28
  #include <linux/gfp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
  
  #include <asm/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31

b418da16d   Christoph Hellwig   compat: generic c...
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  /*
   * Note that the native side is already converted to a timespec, because
   * that's what we want anyway.
   */
  static int compat_get_timeval(struct timespec *o,
  		struct compat_timeval __user *i)
  {
  	long usec;
  
  	if (get_user(o->tv_sec, &i->tv_sec) ||
  	    get_user(usec, &i->tv_usec))
  		return -EFAULT;
  	o->tv_nsec = usec * 1000;
  	return 0;
  }
  
  static int compat_put_timeval(struct compat_timeval __user *o,
  		struct timeval *i)
  {
  	return (put_user(i->tv_sec, &o->tv_sec) ||
  		put_user(i->tv_usec, &o->tv_usec)) ? -EFAULT : 0;
  }
65f5d80bd   Richard Cochran   time: Splitout co...
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  static int compat_get_timex(struct timex *txc, struct compat_timex __user *utp)
  {
  	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;
  
  	return 0;
  }
  
  static int compat_put_timex(struct compat_timex __user *utp, struct timex *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) ||
  			__put_user(txc->tai, &utp->tai))
  		return -EFAULT;
  	return 0;
  }
b418da16d   Christoph Hellwig   compat: generic c...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
  asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv,
  		struct timezone __user *tz)
  {
  	if (tv) {
  		struct timeval ktv;
  		do_gettimeofday(&ktv);
  		if (compat_put_timeval(tv, &ktv))
  			return -EFAULT;
  	}
  	if (tz) {
  		if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
  			return -EFAULT;
  	}
  
  	return 0;
  }
  
  asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv,
  		struct timezone __user *tz)
  {
  	struct timespec kts;
  	struct timezone ktz;
  
  	if (tv) {
  		if (compat_get_timeval(&kts, tv))
  			return -EFAULT;
  	}
  	if (tz) {
  		if (copy_from_user(&ktz, tz, sizeof(ktz)))
  			return -EFAULT;
  	}
  
  	return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
148
149
150
151
152
153
154
155
156
157
  int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts)
  {
  	return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) ||
  			__get_user(ts->tv_sec, &cts->tv_sec) ||
  			__get_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
  }
  
  int put_compat_timespec(const struct timespec *ts, struct compat_timespec __user *cts)
  {
  	return (!access_ok(VERIFY_WRITE, cts, sizeof(*cts)) ||
  			__put_user(ts->tv_sec, &cts->tv_sec) ||
  			__put_user(ts->tv_nsec, &cts->tv_nsec)) ? -EFAULT : 0;
  }
416529374   Oleg Nesterov   hrtimer: fix *rmt...
158
159
160
161
162
163
  static long compat_nanosleep_restart(struct restart_block *restart)
  {
  	struct compat_timespec __user *rmtp;
  	struct timespec rmt;
  	mm_segment_t oldfs;
  	long ret;
029a07e03   Thomas Gleixner   hrtimer: use nano...
164
  	restart->nanosleep.rmtp = (struct timespec __user *) &rmt;
416529374   Oleg Nesterov   hrtimer: fix *rmt...
165
166
167
168
169
170
  	oldfs = get_fs();
  	set_fs(KERNEL_DS);
  	ret = hrtimer_nanosleep_restart(restart);
  	set_fs(oldfs);
  
  	if (ret) {
029a07e03   Thomas Gleixner   hrtimer: use nano...
171
  		rmtp = restart->nanosleep.compat_rmtp;
416529374   Oleg Nesterov   hrtimer: fix *rmt...
172
173
174
175
176
177
178
  
  		if (rmtp && put_compat_timespec(&rmt, rmtp))
  			return -EFAULT;
  	}
  
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp,
c70878b4e   Anton Blanchard   hrtimer: hook com...
180
  				     struct compat_timespec __user *rmtp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  {
c70878b4e   Anton Blanchard   hrtimer: hook com...
182
  	struct timespec tu, rmt;
416529374   Oleg Nesterov   hrtimer: fix *rmt...
183
  	mm_segment_t oldfs;
c70878b4e   Anton Blanchard   hrtimer: hook com...
184
  	long ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185

c70878b4e   Anton Blanchard   hrtimer: hook com...
186
  	if (get_compat_timespec(&tu, rqtp))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  		return -EFAULT;
c70878b4e   Anton Blanchard   hrtimer: hook com...
188
  	if (!timespec_valid(&tu))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
  		return -EINVAL;
416529374   Oleg Nesterov   hrtimer: fix *rmt...
190
191
192
193
194
195
196
197
198
199
200
201
  	oldfs = get_fs();
  	set_fs(KERNEL_DS);
  	ret = hrtimer_nanosleep(&tu,
  				rmtp ? (struct timespec __user *)&rmt : NULL,
  				HRTIMER_MODE_REL, CLOCK_MONOTONIC);
  	set_fs(oldfs);
  
  	if (ret) {
  		struct restart_block *restart
  			= &current_thread_info()->restart_block;
  
  		restart->fn = compat_nanosleep_restart;
029a07e03   Thomas Gleixner   hrtimer: use nano...
202
  		restart->nanosleep.compat_rmtp = rmtp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203

416529374   Oleg Nesterov   hrtimer: fix *rmt...
204
  		if (rmtp && put_compat_timespec(&rmt, rmtp))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
  			return -EFAULT;
  	}
c70878b4e   Anton Blanchard   hrtimer: hook com...
207
208
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
  }
  
  static inline long get_compat_itimerval(struct itimerval *o,
  		struct compat_itimerval __user *i)
  {
  	return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
  		(__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
  		 __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
  		 __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
  		 __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
  }
  
  static inline long put_compat_itimerval(struct compat_itimerval __user *o,
  		struct itimerval *i)
  {
  	return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
  		(__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
  		 __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
  		 __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
  		 __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
  }
  
  asmlinkage long compat_sys_getitimer(int which,
  		struct compat_itimerval __user *it)
  {
  	struct itimerval kit;
  	int error;
  
  	error = do_getitimer(which, &kit);
  	if (!error && put_compat_itimerval(it, &kit))
  		error = -EFAULT;
  	return error;
  }
  
  asmlinkage long compat_sys_setitimer(int which,
  		struct compat_itimerval __user *in,
  		struct compat_itimerval __user *out)
  {
  	struct itimerval kin, kout;
  	int error;
  
  	if (in) {
  		if (get_compat_itimerval(&kin, in))
  			return -EFAULT;
  	} else
  		memset(&kin, 0, sizeof(kin));
  
  	error = do_setitimer(which, &kin, out ? &kout : NULL);
  	if (error || !out)
  		return error;
  	if (put_compat_itimerval(out, &kout))
  		return -EFAULT;
  	return 0;
  }
f06febc96   Frank Mayhar   timers: fix itime...
263
264
265
266
  static compat_clock_t clock_t_to_compat_clock_t(clock_t x)
  {
  	return compat_jiffies_to_clock_t(clock_t_to_jiffies(x));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
268
  asmlinkage long compat_sys_times(struct compat_tms __user *tbuf)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
  	if (tbuf) {
f06febc96   Frank Mayhar   timers: fix itime...
270
  		struct tms tms;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
  		struct compat_tms tmp;
f06febc96   Frank Mayhar   timers: fix itime...
272
273
274
275
276
277
278
  
  		do_sys_times(&tms);
  		/* Convert our struct tms to the compat version. */
  		tmp.tms_utime = clock_t_to_compat_clock_t(tms.tms_utime);
  		tmp.tms_stime = clock_t_to_compat_clock_t(tms.tms_stime);
  		tmp.tms_cutime = clock_t_to_compat_clock_t(tms.tms_cutime);
  		tmp.tms_cstime = clock_t_to_compat_clock_t(tms.tms_cstime);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
  		if (copy_to_user(tbuf, &tmp, sizeof(tmp)))
  			return -EFAULT;
  	}
e3d5a27d5   Paul Mackerras   Allow times and t...
282
  	force_successful_syscall_return();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
  	return compat_jiffies_to_clock_t(jiffies);
  }
  
  /*
   * Assumption: old_sigset_t and compat_old_sigset_t are both
   * types that can be passed to put_user()/get_user().
   */
  
  asmlinkage long compat_sys_sigpending(compat_old_sigset_t __user *set)
  {
  	old_sigset_t s;
  	long ret;
  	mm_segment_t old_fs = get_fs();
  
  	set_fs(KERNEL_DS);
  	ret = sys_sigpending((old_sigset_t __user *) &s);
  	set_fs(old_fs);
  	if (ret == 0)
  		ret = put_user(s, set);
  	return ret;
  }
  
  asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set,
  		compat_old_sigset_t __user *oset)
  {
  	old_sigset_t s;
  	long ret;
  	mm_segment_t old_fs;
  
  	if (set && get_user(s, set))
  		return -EFAULT;
  	old_fs = get_fs();
  	set_fs(KERNEL_DS);
  	ret = sys_sigprocmask(how,
  			      set ? (old_sigset_t __user *) &s : NULL,
  			      oset ? (old_sigset_t __user *) &s : NULL);
  	set_fs(old_fs);
  	if (ret == 0)
  		if (oset)
  			ret = put_user(s, oset);
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
326
327
328
  asmlinkage long compat_sys_setrlimit(unsigned int resource,
  		struct compat_rlimit __user *rlim)
  {
  	struct rlimit r;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
330
331
332
333
334
335
336
337
338
  
  	if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) ||
  	    __get_user(r.rlim_cur, &rlim->rlim_cur) ||
  	    __get_user(r.rlim_max, &rlim->rlim_max))
  		return -EFAULT;
  
  	if (r.rlim_cur == COMPAT_RLIM_INFINITY)
  		r.rlim_cur = RLIM_INFINITY;
  	if (r.rlim_max == COMPAT_RLIM_INFINITY)
  		r.rlim_max = RLIM_INFINITY;
b95183453   Jiri Slaby   rlimits: switch m...
339
  	return do_prlimit(current, resource, &r, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
  }
  
  #ifdef COMPAT_RLIM_OLD_INFINITY
  
  asmlinkage long compat_sys_old_getrlimit(unsigned int resource,
  		struct compat_rlimit __user *rlim)
  {
  	struct rlimit r;
  	int ret;
  	mm_segment_t old_fs = get_fs();
  
  	set_fs(KERNEL_DS);
  	ret = sys_old_getrlimit(resource, &r);
  	set_fs(old_fs);
  
  	if (!ret) {
  		if (r.rlim_cur > COMPAT_RLIM_OLD_INFINITY)
  			r.rlim_cur = COMPAT_RLIM_INFINITY;
  		if (r.rlim_max > COMPAT_RLIM_OLD_INFINITY)
  			r.rlim_max = COMPAT_RLIM_INFINITY;
  
  		if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) ||
  		    __put_user(r.rlim_cur, &rlim->rlim_cur) ||
  		    __put_user(r.rlim_max, &rlim->rlim_max))
  			return -EFAULT;
  	}
  	return ret;
  }
  
  #endif
b95183453   Jiri Slaby   rlimits: switch m...
370
  asmlinkage long compat_sys_getrlimit(unsigned int resource,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
374
  		struct compat_rlimit __user *rlim)
  {
  	struct rlimit r;
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375

b95183453   Jiri Slaby   rlimits: switch m...
376
  	ret = do_prlimit(current, resource, NULL, &r);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
  	if (!ret) {
  		if (r.rlim_cur > COMPAT_RLIM_INFINITY)
  			r.rlim_cur = COMPAT_RLIM_INFINITY;
  		if (r.rlim_max > COMPAT_RLIM_INFINITY)
  			r.rlim_max = COMPAT_RLIM_INFINITY;
  
  		if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) ||
  		    __put_user(r.rlim_cur, &rlim->rlim_cur) ||
  		    __put_user(r.rlim_max, &rlim->rlim_max))
  			return -EFAULT;
  	}
  	return ret;
  }
  
  int put_compat_rusage(const struct rusage *r, struct compat_rusage __user *ru)
  {
  	if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru)) ||
  	    __put_user(r->ru_utime.tv_sec, &ru->ru_utime.tv_sec) ||
  	    __put_user(r->ru_utime.tv_usec, &ru->ru_utime.tv_usec) ||
  	    __put_user(r->ru_stime.tv_sec, &ru->ru_stime.tv_sec) ||
  	    __put_user(r->ru_stime.tv_usec, &ru->ru_stime.tv_usec) ||
  	    __put_user(r->ru_maxrss, &ru->ru_maxrss) ||
  	    __put_user(r->ru_ixrss, &ru->ru_ixrss) ||
  	    __put_user(r->ru_idrss, &ru->ru_idrss) ||
  	    __put_user(r->ru_isrss, &ru->ru_isrss) ||
  	    __put_user(r->ru_minflt, &ru->ru_minflt) ||
  	    __put_user(r->ru_majflt, &ru->ru_majflt) ||
  	    __put_user(r->ru_nswap, &ru->ru_nswap) ||
  	    __put_user(r->ru_inblock, &ru->ru_inblock) ||
  	    __put_user(r->ru_oublock, &ru->ru_oublock) ||
  	    __put_user(r->ru_msgsnd, &ru->ru_msgsnd) ||
  	    __put_user(r->ru_msgrcv, &ru->ru_msgrcv) ||
  	    __put_user(r->ru_nsignals, &ru->ru_nsignals) ||
  	    __put_user(r->ru_nvcsw, &ru->ru_nvcsw) ||
  	    __put_user(r->ru_nivcsw, &ru->ru_nivcsw))
  		return -EFAULT;
  	return 0;
  }
  
  asmlinkage long compat_sys_getrusage(int who, struct compat_rusage __user *ru)
  {
  	struct rusage r;
  	int ret;
  	mm_segment_t old_fs = get_fs();
  
  	set_fs(KERNEL_DS);
  	ret = sys_getrusage(who, (struct rusage __user *) &r);
  	set_fs(old_fs);
  
  	if (ret)
  		return ret;
  
  	if (put_compat_rusage(&r, ru))
  		return -EFAULT;
  
  	return 0;
  }
  
  asmlinkage long
  compat_sys_wait4(compat_pid_t pid, compat_uint_t __user *stat_addr, int options,
  	struct compat_rusage __user *ru)
  {
  	if (!ru) {
  		return sys_wait4(pid, stat_addr, options, NULL);
  	} else {
  		struct rusage r;
  		int ret;
  		unsigned int status;
  		mm_segment_t old_fs = get_fs();
  
  		set_fs (KERNEL_DS);
  		ret = sys_wait4(pid,
  				(stat_addr ?
  				 (unsigned int __user *) &status : NULL),
  				options, (struct rusage __user *) &r);
  		set_fs (old_fs);
  
  		if (ret > 0) {
  			if (put_compat_rusage(&r, ru))
  				return -EFAULT;
  			if (stat_addr && put_user(status, stat_addr))
  				return -EFAULT;
  		}
  		return ret;
  	}
  }
  
  asmlinkage long compat_sys_waitid(int which, compat_pid_t pid,
  		struct compat_siginfo __user *uinfo, int options,
  		struct compat_rusage __user *uru)
  {
  	siginfo_t info;
  	struct rusage ru;
  	long ret;
  	mm_segment_t old_fs = get_fs();
  
  	memset(&info, 0, sizeof(info));
  
  	set_fs(KERNEL_DS);
  	ret = sys_waitid(which, pid, (siginfo_t __user *)&info, options,
  			 uru ? (struct rusage __user *)&ru : NULL);
  	set_fs(old_fs);
  
  	if ((ret < 0) || (info.si_signo == 0))
  		return ret;
  
  	if (uru) {
  		ret = put_compat_rusage(&ru, uru);
  		if (ret)
  			return ret;
  	}
  
  	BUG_ON(info.si_code & __SI_MASK);
  	info.si_code |= __SI_CHLD;
  	return copy_siginfo_to_user32(uinfo, &info);
  }
  
  static int compat_get_user_cpu_mask(compat_ulong_t __user *user_mask_ptr,
a45185d2d   Rusty Russell   cpumask: convert ...
495
  				    unsigned len, struct cpumask *new_mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
497
  {
  	unsigned long *k;
a45185d2d   Rusty Russell   cpumask: convert ...
498
499
500
501
  	if (len < cpumask_size())
  		memset(new_mask, 0, cpumask_size());
  	else if (len > cpumask_size())
  		len = cpumask_size();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502

a45185d2d   Rusty Russell   cpumask: convert ...
503
  	k = cpumask_bits(new_mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
505
506
507
508
509
510
  	return compat_get_bitmap(k, user_mask_ptr, len * 8);
  }
  
  asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid,
  					     unsigned int len,
  					     compat_ulong_t __user *user_mask_ptr)
  {
a45185d2d   Rusty Russell   cpumask: convert ...
511
  	cpumask_var_t new_mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
  	int retval;
a45185d2d   Rusty Russell   cpumask: convert ...
513
514
515
516
  	if (!alloc_cpumask_var(&new_mask, GFP_KERNEL))
  		return -ENOMEM;
  
  	retval = compat_get_user_cpu_mask(user_mask_ptr, len, new_mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
  	if (retval)
a45185d2d   Rusty Russell   cpumask: convert ...
518
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519

a45185d2d   Rusty Russell   cpumask: convert ...
520
521
522
523
  	retval = sched_setaffinity(pid, new_mask);
  out:
  	free_cpumask_var(new_mask);
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
526
527
528
529
  }
  
  asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len,
  					     compat_ulong_t __user *user_mask_ptr)
  {
  	int ret;
a45185d2d   Rusty Russell   cpumask: convert ...
530
  	cpumask_var_t mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531

fa9dc265a   KOSAKI Motohiro   cpumask: fix comp...
532
533
534
  	if ((len * BITS_PER_BYTE) < nr_cpu_ids)
  		return -EINVAL;
  	if (len & (sizeof(compat_ulong_t)-1))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
  		return -EINVAL;
a45185d2d   Rusty Russell   cpumask: convert ...
536
537
538
539
  	if (!alloc_cpumask_var(&mask, GFP_KERNEL))
  		return -ENOMEM;
  
  	ret = sched_getaffinity(pid, mask);
fa9dc265a   KOSAKI Motohiro   cpumask: fix comp...
540
541
  	if (ret == 0) {
  		size_t retlen = min_t(size_t, len, cpumask_size());
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542

fa9dc265a   KOSAKI Motohiro   cpumask: fix comp...
543
544
545
546
547
  		if (compat_put_bitmap(user_mask_ptr, cpumask_bits(mask), retlen * 8))
  			ret = -EFAULT;
  		else
  			ret = retlen;
  	}
a45185d2d   Rusty Russell   cpumask: convert ...
548
  	free_cpumask_var(mask);
fa9dc265a   KOSAKI Motohiro   cpumask: fix comp...
549

a45185d2d   Rusty Russell   cpumask: convert ...
550
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
  }
83f5d1266   Davide Libenzi   signal/timer/even...
552
553
  int get_compat_itimerspec(struct itimerspec *dst,
  			  const struct compat_itimerspec __user *src)
bd3a8492b   Daniel Walker   whitespace fixes:...
554
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
557
558
  	if (get_compat_timespec(&dst->it_interval, &src->it_interval) ||
  	    get_compat_timespec(&dst->it_value, &src->it_value))
  		return -EFAULT;
  	return 0;
bd3a8492b   Daniel Walker   whitespace fixes:...
559
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560

83f5d1266   Davide Libenzi   signal/timer/even...
561
562
  int put_compat_itimerspec(struct compat_itimerspec __user *dst,
  			  const struct itimerspec *src)
bd3a8492b   Daniel Walker   whitespace fixes:...
563
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
565
566
567
  	if (put_compat_timespec(&src->it_interval, &dst->it_interval) ||
  	    put_compat_timespec(&src->it_value, &dst->it_value))
  		return -EFAULT;
  	return 0;
bd3a8492b   Daniel Walker   whitespace fixes:...
568
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569

3a0f69d59   Christoph Hellwig   [PATCH] common co...
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
  long compat_sys_timer_create(clockid_t which_clock,
  			struct compat_sigevent __user *timer_event_spec,
  			timer_t __user *created_timer_id)
  {
  	struct sigevent __user *event = NULL;
  
  	if (timer_event_spec) {
  		struct sigevent kevent;
  
  		event = compat_alloc_user_space(sizeof(*event));
  		if (get_compat_sigevent(&kevent, timer_event_spec) ||
  		    copy_to_user(event, &kevent, sizeof(*event)))
  			return -EFAULT;
  	}
  
  	return sys_timer_create(which_clock, event, created_timer_id);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
  long compat_sys_timer_settime(timer_t timer_id, int flags,
bd3a8492b   Daniel Walker   whitespace fixes:...
588
  			  struct compat_itimerspec __user *new,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
  			  struct compat_itimerspec __user *old)
bd3a8492b   Daniel Walker   whitespace fixes:...
590
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
592
593
594
595
596
597
  	long err;
  	mm_segment_t oldfs;
  	struct itimerspec newts, oldts;
  
  	if (!new)
  		return -EINVAL;
  	if (get_compat_itimerspec(&newts, new))
bd3a8492b   Daniel Walker   whitespace fixes:...
598
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
601
602
603
  	oldfs = get_fs();
  	set_fs(KERNEL_DS);
  	err = sys_timer_settime(timer_id, flags,
  				(struct itimerspec __user *) &newts,
  				(struct itimerspec __user *) &oldts);
bd3a8492b   Daniel Walker   whitespace fixes:...
604
  	set_fs(oldfs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
607
  	if (!err && old && put_compat_itimerspec(old, &oldts))
  		return -EFAULT;
  	return err;
bd3a8492b   Daniel Walker   whitespace fixes:...
608
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
610
611
  
  long compat_sys_timer_gettime(timer_t timer_id,
  		struct compat_itimerspec __user *setting)
bd3a8492b   Daniel Walker   whitespace fixes:...
612
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
614
  	long err;
  	mm_segment_t oldfs;
bd3a8492b   Daniel Walker   whitespace fixes:...
615
  	struct itimerspec ts;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
617
618
619
  
  	oldfs = get_fs();
  	set_fs(KERNEL_DS);
  	err = sys_timer_gettime(timer_id,
bd3a8492b   Daniel Walker   whitespace fixes:...
620
621
  				(struct itimerspec __user *) &ts);
  	set_fs(oldfs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
623
624
  	if (!err && put_compat_itimerspec(setting, &ts))
  		return -EFAULT;
  	return err;
bd3a8492b   Daniel Walker   whitespace fixes:...
625
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626
627
628
629
630
631
  
  long compat_sys_clock_settime(clockid_t which_clock,
  		struct compat_timespec __user *tp)
  {
  	long err;
  	mm_segment_t oldfs;
bd3a8492b   Daniel Walker   whitespace fixes:...
632
  	struct timespec ts;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
634
  
  	if (get_compat_timespec(&ts, tp))
bd3a8492b   Daniel Walker   whitespace fixes:...
635
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
  	oldfs = get_fs();
bd3a8492b   Daniel Walker   whitespace fixes:...
637
  	set_fs(KERNEL_DS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
639
640
641
  	err = sys_clock_settime(which_clock,
  				(struct timespec __user *) &ts);
  	set_fs(oldfs);
  	return err;
bd3a8492b   Daniel Walker   whitespace fixes:...
642
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
644
645
646
647
648
  
  long compat_sys_clock_gettime(clockid_t which_clock,
  		struct compat_timespec __user *tp)
  {
  	long err;
  	mm_segment_t oldfs;
bd3a8492b   Daniel Walker   whitespace fixes:...
649
  	struct timespec ts;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
651
652
653
654
655
656
  
  	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))
bd3a8492b   Daniel Walker   whitespace fixes:...
657
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
658
  	return err;
bd3a8492b   Daniel Walker   whitespace fixes:...
659
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660

f1f1d5ebd   Richard Cochran   posix-timers: Int...
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
  long compat_sys_clock_adjtime(clockid_t which_clock,
  		struct compat_timex __user *utp)
  {
  	struct timex txc;
  	mm_segment_t oldfs;
  	int err, ret;
  
  	err = compat_get_timex(&txc, utp);
  	if (err)
  		return err;
  
  	oldfs = get_fs();
  	set_fs(KERNEL_DS);
  	ret = sys_clock_adjtime(which_clock, (struct timex __user *) &txc);
  	set_fs(oldfs);
  
  	err = compat_put_timex(utp, &txc);
  	if (err)
  		return err;
  
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
685
686
687
  long compat_sys_clock_getres(clockid_t which_clock,
  		struct compat_timespec __user *tp)
  {
  	long err;
  	mm_segment_t oldfs;
bd3a8492b   Daniel Walker   whitespace fixes:...
688
  	struct timespec ts;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
690
691
692
693
694
695
  
  	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))
bd3a8492b   Daniel Walker   whitespace fixes:...
696
  		return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
  	return err;
bd3a8492b   Daniel Walker   whitespace fixes:...
698
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699

1711ef386   Toyo Abe   [PATCH] posix-tim...
700
701
702
703
704
  static long compat_clock_nanosleep_restart(struct restart_block *restart)
  {
  	long err;
  	mm_segment_t oldfs;
  	struct timespec tu;
029a07e03   Thomas Gleixner   hrtimer: use nano...
705
  	struct compat_timespec *rmtp = restart->nanosleep.compat_rmtp;
1711ef386   Toyo Abe   [PATCH] posix-tim...
706

029a07e03   Thomas Gleixner   hrtimer: use nano...
707
  	restart->nanosleep.rmtp = (struct timespec __user *) &tu;
1711ef386   Toyo Abe   [PATCH] posix-tim...
708
709
710
711
712
713
714
715
716
717
718
  	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;
029a07e03   Thomas Gleixner   hrtimer: use nano...
719
  		restart->nanosleep.compat_rmtp = rmtp;
1711ef386   Toyo Abe   [PATCH] posix-tim...
720
721
722
  	}
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723
724
725
726
727
728
  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;
bd3a8492b   Daniel Walker   whitespace fixes:...
729
  	struct timespec in, out;
1711ef386   Toyo Abe   [PATCH] posix-tim...
730
  	struct restart_block *restart;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731

bd3a8492b   Daniel Walker   whitespace fixes:...
732
  	if (get_compat_timespec(&in, rqtp))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
734
735
736
737
738
739
740
  		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);
1711ef386   Toyo Abe   [PATCH] posix-tim...
741

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
743
744
  	if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
  	    put_compat_timespec(&out, rmtp))
  		return -EFAULT;
1711ef386   Toyo Abe   [PATCH] posix-tim...
745
746
747
748
  
  	if (err == -ERESTART_RESTARTBLOCK) {
  		restart = &current_thread_info()->restart_block;
  		restart->fn = compat_clock_nanosleep_restart;
029a07e03   Thomas Gleixner   hrtimer: use nano...
749
  		restart->nanosleep.compat_rmtp = rmtp;
1711ef386   Toyo Abe   [PATCH] posix-tim...
750
  	}
bd3a8492b   Daniel Walker   whitespace fixes:...
751
752
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
756
757
758
759
760
761
762
763
  
  /*
   * 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)
  {
51410d3c5   David S. Miller   [PATCH] Fix get_c...
764
  	memset(event, 0, sizeof(*event));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
766
767
768
769
770
771
772
773
  	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;
  }
5fa3839a6   Stephen Rothwell   [PATCH] Constify ...
774
  long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
  		       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;
  }
  
  void
  sigset_from_compat (sigset_t *set, compat_sigset_t *compat)
  {
  	switch (_NSIG_WORDS) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
860
861
862
  	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 );
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
864
865
866
867
868
869
870
871
872
  	}
  }
  
  asmlinkage long
  compat_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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873
874
  	struct timespec t;
  	siginfo_t info;
943df1485   Oleg Nesterov   signal: introduce...
875
  	long ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
877
878
879
880
881
882
  
  	if (sigsetsize != sizeof(sigset_t))
  		return -EINVAL;
  
  	if (copy_from_user(&s32, uthese, sizeof(compat_sigset_t)))
  		return -EFAULT;
  	sigset_from_compat(&s, &s32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
884
  
  	if (uts) {
943df1485   Oleg Nesterov   signal: introduce...
885
  		if (get_compat_timespec(&t, uts))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887
  	}
943df1485   Oleg Nesterov   signal: introduce...
888
  	ret = do_sigtimedwait(&s, &info, uts ? &t : NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889

943df1485   Oleg Nesterov   signal: introduce...
890
891
892
  	if (ret > 0 && uinfo) {
  		if (copy_siginfo_to_user32(uinfo, &info))
  			ret = -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
  	}
943df1485   Oleg Nesterov   signal: introduce...
894

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
896
897
  	return ret;
  
  }
62ab4505e   Thomas Gleixner   signals: implemen...
898
899
900
901
902
903
904
905
906
907
  asmlinkage long
  compat_sys_rt_tgsigqueueinfo(compat_pid_t tgid, compat_pid_t pid, int sig,
  			     struct compat_siginfo __user *uinfo)
  {
  	siginfo_t info;
  
  	if (copy_siginfo_from_user32(&info, uinfo))
  		return -EFAULT;
  	return do_rt_tgsigqueueinfo(tgid, pid, sig, &info);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
909
910
911
912
913
914
915
916
917
918
919
920
921
  #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))
e3d5a27d5   Paul Mackerras   Allow times and t...
922
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
  	}
e3d5a27d5   Paul Mackerras   Allow times and t...
924
  	force_successful_syscall_return();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
  	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 */
150256d8a   David Woodhouse   [PATCH] Generic s...
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
  
  #ifdef __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
  asmlinkage 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(&current->sighand->siglock);
  	current->saved_sigmask = current->blocked;
  	current->blocked = newset;
  	recalc_sigpending();
  	spin_unlock_irq(&current->sighand->siglock);
  
  	current->state = TASK_INTERRUPTIBLE;
  	schedule();
4e4c22c71   Roland McGrath   signals: add set_...
971
  	set_restore_sigmask();
150256d8a   David Woodhouse   [PATCH] Generic s...
972
973
974
  	return -ERESTARTNOHAND;
  }
  #endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */
3158e9411   Stephen Rothwell   [PATCH] consolida...
975
976
977
978
  
  asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp)
  {
  	struct timex txc;
65f5d80bd   Richard Cochran   time: Splitout co...
979
  	int err, ret;
3158e9411   Stephen Rothwell   [PATCH] consolida...
980

65f5d80bd   Richard Cochran   time: Splitout co...
981
982
983
  	err = compat_get_timex(&txc, utp);
  	if (err)
  		return err;
3158e9411   Stephen Rothwell   [PATCH] consolida...
984
985
  
  	ret = do_adjtimex(&txc);
65f5d80bd   Richard Cochran   time: Splitout co...
986
987
988
  	err = compat_put_timex(utp, &txc);
  	if (err)
  		return err;
3158e9411   Stephen Rothwell   [PATCH] consolida...
989
990
991
  
  	return ret;
  }
1b2db9fb7   Christoph Lameter   [PATCH] sys_move_...
992
993
994
  
  #ifdef CONFIG_NUMA
  asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_pages,
9216dfad4   Christoph Lameter   [PATCH] move_page...
995
  		compat_uptr_t __user *pages32,
1b2db9fb7   Christoph Lameter   [PATCH] sys_move_...
996
997
998
999
1000
1001
1002
1003
1004
1005
  		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;
9216dfad4   Christoph Lameter   [PATCH] move_page...
1006
  		if (get_user(p, pages32 + i) ||
1b2db9fb7   Christoph Lameter   [PATCH] sys_move_...
1007
1008
1009
1010
1011
  			put_user(compat_ptr(p), pages + i))
  			return -EFAULT;
  	}
  	return sys_move_pages(pid, nr_pages, pages, nodes, status, flags);
  }
3fd593979   Stephen Rothwell   [PATCH] Create co...
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
  
  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);
  }
1b2db9fb7   Christoph Lameter   [PATCH] sys_move_...
1045
  #endif
d4d23add3   Kyle McMartin   [PATCH] Common co...
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
  
  struct 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 long
  compat_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;
  }
c41d68a51   H. Peter Anvin   compat: Make comp...
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
  
  /*
   * Allocate user-space memory for the duration of a single system call,
   * in order to marshall parameters inside a compat thunk.
   */
  void __user *compat_alloc_user_space(unsigned long len)
  {
  	void __user *ptr;
  
  	/* If len would occupy more than half of the entire compat space... */
  	if (unlikely(len > (((compat_uptr_t)~0) >> 1)))
  		return NULL;
  
  	ptr = arch_compat_alloc_user_space(len);
  
  	if (unlikely(!access_ok(VERIFY_WRITE, ptr, len)))
  		return NULL;
  
  	return ptr;
  }
  EXPORT_SYMBOL_GPL(compat_alloc_user_space);