sys.c 58 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6
/*
 *  linux/kernel/sys.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */

7
#include <linux/export.h>
Linus Torvalds's avatar
Linus Torvalds committed
8 9 10 11 12 13 14
#include <linux/mm.h>
#include <linux/utsname.h>
#include <linux/mman.h>
#include <linux/reboot.h>
#include <linux/prctl.h>
#include <linux/highuid.h>
#include <linux/fs.h>
15
#include <linux/kmod.h>
16
#include <linux/perf_event.h>
17
#include <linux/resource.h>
18
#include <linux/kernel.h>
Linus Torvalds's avatar
Linus Torvalds committed
19
#include <linux/workqueue.h>
20
#include <linux/capability.h>
Linus Torvalds's avatar
Linus Torvalds committed
21 22 23 24 25 26 27 28
#include <linux/device.h>
#include <linux/key.h>
#include <linux/times.h>
#include <linux/posix-timers.h>
#include <linux/security.h>
#include <linux/dcookies.h>
#include <linux/suspend.h>
#include <linux/tty.h>
29
#include <linux/signal.h>
30
#include <linux/cn_proc.h>
31
#include <linux/getcpu.h>
32
#include <linux/task_io_accounting_ops.h>
33
#include <linux/seccomp.h>
Mark Lord's avatar
Mark Lord committed
34
#include <linux/cpu.h>
35
#include <linux/personality.h>
36
#include <linux/ptrace.h>
37
#include <linux/fs_struct.h>
38 39
#include <linux/file.h>
#include <linux/mount.h>
40
#include <linux/gfp.h>
41
#include <linux/syscore_ops.h>
42 43
#include <linux/version.h>
#include <linux/ctype.h>
Linus Torvalds's avatar
Linus Torvalds committed
44 45 46

#include <linux/compat.h>
#include <linux/syscalls.h>
47
#include <linux/kprobes.h>
48
#include <linux/user_namespace.h>
49
#include <linux/binfmts.h>
Linus Torvalds's avatar
Linus Torvalds committed
50

51
#include <linux/sched.h>
52
#include <linux/sched/autogroup.h>
53
#include <linux/sched/loadavg.h>
54
#include <linux/sched/stat.h>
55
#include <linux/sched/mm.h>
56
#include <linux/sched/coredump.h>
57
#include <linux/sched/task.h>
58
#include <linux/sched/cputime.h>
59 60 61 62
#include <linux/rcupdate.h>
#include <linux/uidgid.h>
#include <linux/cred.h>

63
#include <linux/kmsg_dump.h>
64 65
/* Move somewhere else to avoid recompiling? */
#include <generated/utsrelease.h>
66

67
#include <linux/uaccess.h>
Linus Torvalds's avatar
Linus Torvalds committed
68 69 70 71
#include <asm/io.h>
#include <asm/unistd.h>

#ifndef SET_UNALIGN_CTL
vishnu.ps's avatar
vishnu.ps committed
72
# define SET_UNALIGN_CTL(a, b)	(-EINVAL)
Linus Torvalds's avatar
Linus Torvalds committed
73 74
#endif
#ifndef GET_UNALIGN_CTL
vishnu.ps's avatar
vishnu.ps committed
75
# define GET_UNALIGN_CTL(a, b)	(-EINVAL)
Linus Torvalds's avatar
Linus Torvalds committed
76 77
#endif
#ifndef SET_FPEMU_CTL
vishnu.ps's avatar
vishnu.ps committed
78
# define SET_FPEMU_CTL(a, b)	(-EINVAL)
Linus Torvalds's avatar
Linus Torvalds committed
79 80
#endif
#ifndef GET_FPEMU_CTL
vishnu.ps's avatar
vishnu.ps committed
81
# define GET_FPEMU_CTL(a, b)	(-EINVAL)
Linus Torvalds's avatar
Linus Torvalds committed
82 83
#endif
#ifndef SET_FPEXC_CTL
vishnu.ps's avatar
vishnu.ps committed
84
# define SET_FPEXC_CTL(a, b)	(-EINVAL)
Linus Torvalds's avatar
Linus Torvalds committed
85 86
#endif
#ifndef GET_FPEXC_CTL
vishnu.ps's avatar
vishnu.ps committed
87
# define GET_FPEXC_CTL(a, b)	(-EINVAL)
Linus Torvalds's avatar
Linus Torvalds committed
88
#endif
89
#ifndef GET_ENDIAN
vishnu.ps's avatar
vishnu.ps committed
90
# define GET_ENDIAN(a, b)	(-EINVAL)
91 92
#endif
#ifndef SET_ENDIAN
vishnu.ps's avatar
vishnu.ps committed
93
# define SET_ENDIAN(a, b)	(-EINVAL)
94
#endif
95 96 97 98 99 100
#ifndef GET_TSC_CTL
# define GET_TSC_CTL(a)		(-EINVAL)
#endif
#ifndef SET_TSC_CTL
# define SET_TSC_CTL(a)		(-EINVAL)
#endif
101
#ifndef MPX_ENABLE_MANAGEMENT
102
# define MPX_ENABLE_MANAGEMENT()	(-EINVAL)
103 104
#endif
#ifndef MPX_DISABLE_MANAGEMENT
105
# define MPX_DISABLE_MANAGEMENT()	(-EINVAL)
106
#endif
107 108 109 110 111 112
#ifndef GET_FP_MODE
# define GET_FP_MODE(a)		(-EINVAL)
#endif
#ifndef SET_FP_MODE
# define SET_FP_MODE(a,b)	(-EINVAL)
#endif
Linus Torvalds's avatar
Linus Torvalds committed
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135

/*
 * this is where the system-wide overflow UID and GID are defined, for
 * architectures that now have 32-bit UID/GID but didn't in the past
 */

int overflowuid = DEFAULT_OVERFLOWUID;
int overflowgid = DEFAULT_OVERFLOWGID;

EXPORT_SYMBOL(overflowuid);
EXPORT_SYMBOL(overflowgid);

/*
 * the same as above, but for filesystems which can only store a 16-bit
 * UID and GID. as such, this is needed on all architectures
 */

int fs_overflowuid = DEFAULT_FS_OVERFLOWUID;
int fs_overflowgid = DEFAULT_FS_OVERFLOWUID;

EXPORT_SYMBOL(fs_overflowuid);
EXPORT_SYMBOL(fs_overflowgid);

136 137 138 139 140 141 142 143 144 145
/*
 * Returns true if current's euid is same as p's uid or euid,
 * or has CAP_SYS_NICE to p's user_ns.
 *
 * Called with rcu_read_lock, creds are safe
 */
static bool set_one_prio_perm(struct task_struct *p)
{
	const struct cred *cred = current_cred(), *pcred = __task_cred(p);

146 147
	if (uid_eq(pcred->uid,  cred->euid) ||
	    uid_eq(pcred->euid, cred->euid))
148
		return true;
149
	if (ns_capable(pcred->user_ns, CAP_SYS_NICE))
150 151 152 153
		return true;
	return false;
}

154 155 156 157
/*
 * set the priority of a task
 * - the caller must hold the RCU read lock
 */
Linus Torvalds's avatar
Linus Torvalds committed
158 159 160 161
static int set_one_prio(struct task_struct *p, int niceval, int error)
{
	int no_nice;

162
	if (!set_one_prio_perm(p)) {
Linus Torvalds's avatar
Linus Torvalds committed
163 164 165
		error = -EPERM;
		goto out;
	}
166
	if (niceval < task_nice(p) && !can_nice(p, niceval)) {
Linus Torvalds's avatar
Linus Torvalds committed
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
		error = -EACCES;
		goto out;
	}
	no_nice = security_task_setnice(p, niceval);
	if (no_nice) {
		error = no_nice;
		goto out;
	}
	if (error == -ESRCH)
		error = 0;
	set_user_nice(p, niceval);
out:
	return error;
}

182
SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
Linus Torvalds's avatar
Linus Torvalds committed
183 184 185
{
	struct task_struct *g, *p;
	struct user_struct *user;
186
	const struct cred *cred = current_cred();
Linus Torvalds's avatar
Linus Torvalds committed
187
	int error = -EINVAL;
188
	struct pid *pgrp;
189
	kuid_t uid;
Linus Torvalds's avatar
Linus Torvalds committed
190

191
	if (which > PRIO_USER || which < PRIO_PROCESS)
Linus Torvalds's avatar
Linus Torvalds committed
192 193 194 195
		goto out;

	/* normalize: avoid signed division (rounding problems) */
	error = -ESRCH;
196 197 198 199
	if (niceval < MIN_NICE)
		niceval = MIN_NICE;
	if (niceval > MAX_NICE)
		niceval = MAX_NICE;
Linus Torvalds's avatar
Linus Torvalds committed
200

201
	rcu_read_lock();
Linus Torvalds's avatar
Linus Torvalds committed
202 203
	read_lock(&tasklist_lock);
	switch (which) {
vishnu.ps's avatar
vishnu.ps committed
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
	case PRIO_PROCESS:
		if (who)
			p = find_task_by_vpid(who);
		else
			p = current;
		if (p)
			error = set_one_prio(p, niceval, error);
		break;
	case PRIO_PGRP:
		if (who)
			pgrp = find_vpid(who);
		else
			pgrp = task_pgrp(current);
		do_each_pid_thread(pgrp, PIDTYPE_PGID, p) {
			error = set_one_prio(p, niceval, error);
		} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
		break;
	case PRIO_USER:
		uid = make_kuid(cred->user_ns, who);
		user = cred->user;
		if (!who)
			uid = cred->uid;
		else if (!uid_eq(uid, cred->uid)) {
			user = find_user(uid);
			if (!user)
229
				goto out_unlock;	/* No processes for this user */
vishnu.ps's avatar
vishnu.ps committed
230 231
		}
		do_each_thread(g, p) {
232
			if (uid_eq(task_uid(p), uid) && task_pid_vnr(p))
vishnu.ps's avatar
vishnu.ps committed
233 234 235 236 237
				error = set_one_prio(p, niceval, error);
		} while_each_thread(g, p);
		if (!uid_eq(uid, cred->uid))
			free_uid(user);		/* For find_user() */
		break;
Linus Torvalds's avatar
Linus Torvalds committed
238 239 240
	}
out_unlock:
	read_unlock(&tasklist_lock);
241
	rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
242 243 244 245 246 247 248 249 250 251
out:
	return error;
}

/*
 * Ugh. To avoid negative return values, "getpriority()" will
 * not return the normal nice-value, but a negated value that
 * has been offset by 20 (ie it returns 40..1 instead of -20..19)
 * to stay compatible.
 */
252
SYSCALL_DEFINE2(getpriority, int, which, int, who)
Linus Torvalds's avatar
Linus Torvalds committed
253 254 255
{
	struct task_struct *g, *p;
	struct user_struct *user;
256
	const struct cred *cred = current_cred();
Linus Torvalds's avatar
Linus Torvalds committed
257
	long niceval, retval = -ESRCH;
258
	struct pid *pgrp;
259
	kuid_t uid;
Linus Torvalds's avatar
Linus Torvalds committed
260

261
	if (which > PRIO_USER || which < PRIO_PROCESS)
Linus Torvalds's avatar
Linus Torvalds committed
262 263
		return -EINVAL;

264
	rcu_read_lock();
Linus Torvalds's avatar
Linus Torvalds committed
265 266
	read_lock(&tasklist_lock);
	switch (which) {
vishnu.ps's avatar
vishnu.ps committed
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
	case PRIO_PROCESS:
		if (who)
			p = find_task_by_vpid(who);
		else
			p = current;
		if (p) {
			niceval = nice_to_rlimit(task_nice(p));
			if (niceval > retval)
				retval = niceval;
		}
		break;
	case PRIO_PGRP:
		if (who)
			pgrp = find_vpid(who);
		else
			pgrp = task_pgrp(current);
		do_each_pid_thread(pgrp, PIDTYPE_PGID, p) {
			niceval = nice_to_rlimit(task_nice(p));
			if (niceval > retval)
				retval = niceval;
		} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
		break;
	case PRIO_USER:
		uid = make_kuid(cred->user_ns, who);
		user = cred->user;
		if (!who)
			uid = cred->uid;
		else if (!uid_eq(uid, cred->uid)) {
			user = find_user(uid);
			if (!user)
				goto out_unlock;	/* No processes for this user */
		}
		do_each_thread(g, p) {
300
			if (uid_eq(task_uid(p), uid) && task_pid_vnr(p)) {
301
				niceval = nice_to_rlimit(task_nice(p));
Linus Torvalds's avatar
Linus Torvalds committed
302 303 304
				if (niceval > retval)
					retval = niceval;
			}
vishnu.ps's avatar
vishnu.ps committed
305 306 307 308
		} while_each_thread(g, p);
		if (!uid_eq(uid, cred->uid))
			free_uid(user);		/* for find_user() */
		break;
Linus Torvalds's avatar
Linus Torvalds committed
309 310 311
	}
out_unlock:
	read_unlock(&tasklist_lock);
312
	rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329

	return retval;
}

/*
 * Unprivileged users may change the real gid to the effective gid
 * or vice versa.  (BSD-style)
 *
 * If you set the real gid at all, or set the effective gid to a value not
 * equal to the real gid, then the saved gid is set to the new effective gid.
 *
 * This makes it possible for a setgid program to completely drop its
 * privileges, which is often a useful assertion to make when you are doing
 * a security audit over a program.
 *
 * The general idea is that a program which uses just setregid() will be
 * 100% compatible with BSD.  A program which uses just setgid() will be
vishnu.ps's avatar
vishnu.ps committed
330
 * 100% compatible with POSIX with saved IDs.
Linus Torvalds's avatar
Linus Torvalds committed
331 332 333 334
 *
 * SMP: There are not races, the GIDs are checked only by filesystem
 *      operations (as far as semantic preservation is concerned).
 */
335
#ifdef CONFIG_MULTIUSER
336
SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
Linus Torvalds's avatar
Linus Torvalds committed
337
{
338
	struct user_namespace *ns = current_user_ns();
339 340
	const struct cred *old;
	struct cred *new;
Linus Torvalds's avatar
Linus Torvalds committed
341
	int retval;
342 343 344 345 346 347 348 349 350
	kgid_t krgid, kegid;

	krgid = make_kgid(ns, rgid);
	kegid = make_kgid(ns, egid);

	if ((rgid != (gid_t) -1) && !gid_valid(krgid))
		return -EINVAL;
	if ((egid != (gid_t) -1) && !gid_valid(kegid))
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
351

352 353 354 355 356 357
	new = prepare_creds();
	if (!new)
		return -ENOMEM;
	old = current_cred();

	retval = -EPERM;
Linus Torvalds's avatar
Linus Torvalds committed
358
	if (rgid != (gid_t) -1) {
359 360
		if (gid_eq(old->gid, krgid) ||
		    gid_eq(old->egid, krgid) ||
361
		    ns_capable(old->user_ns, CAP_SETGID))
362
			new->gid = krgid;
Linus Torvalds's avatar
Linus Torvalds committed
363
		else
364
			goto error;
Linus Torvalds's avatar
Linus Torvalds committed
365 366
	}
	if (egid != (gid_t) -1) {
367 368 369
		if (gid_eq(old->gid, kegid) ||
		    gid_eq(old->egid, kegid) ||
		    gid_eq(old->sgid, kegid) ||
370
		    ns_capable(old->user_ns, CAP_SETGID))
371
			new->egid = kegid;
372
		else
373
			goto error;
Linus Torvalds's avatar
Linus Torvalds committed
374
	}
375

Linus Torvalds's avatar
Linus Torvalds committed
376
	if (rgid != (gid_t) -1 ||
377
	    (egid != (gid_t) -1 && !gid_eq(kegid, old->gid)))
378 379 380 381 382 383 384 385
		new->sgid = new->egid;
	new->fsgid = new->egid;

	return commit_creds(new);

error:
	abort_creds(new);
	return retval;
Linus Torvalds's avatar
Linus Torvalds committed
386 387 388
}

/*
vishnu.ps's avatar
vishnu.ps committed
389
 * setgid() is implemented like SysV w/ SAVED_IDS
Linus Torvalds's avatar
Linus Torvalds committed
390 391 392
 *
 * SMP: Same implicit races as above.
 */
393
SYSCALL_DEFINE1(setgid, gid_t, gid)
Linus Torvalds's avatar
Linus Torvalds committed
394
{
395
	struct user_namespace *ns = current_user_ns();
396 397
	const struct cred *old;
	struct cred *new;
Linus Torvalds's avatar
Linus Torvalds committed
398
	int retval;
399 400 401 402 403
	kgid_t kgid;

	kgid = make_kgid(ns, gid);
	if (!gid_valid(kgid))
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
404

405 406 407 408 409 410
	new = prepare_creds();
	if (!new)
		return -ENOMEM;
	old = current_cred();

	retval = -EPERM;
411
	if (ns_capable(old->user_ns, CAP_SETGID))
412 413 414
		new->gid = new->egid = new->sgid = new->fsgid = kgid;
	else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid))
		new->egid = new->fsgid = kgid;
Linus Torvalds's avatar
Linus Torvalds committed
415
	else
416
		goto error;
Linus Torvalds's avatar
Linus Torvalds committed
417

418 419 420 421 422
	return commit_creds(new);

error:
	abort_creds(new);
	return retval;
Linus Torvalds's avatar
Linus Torvalds committed
423
}
424

425 426 427 428
/*
 * change the user struct in a credentials set to match the new UID
 */
static int set_user(struct cred *new)
Linus Torvalds's avatar
Linus Torvalds committed
429 430 431
{
	struct user_struct *new_user;

432
	new_user = alloc_uid(new->uid);
Linus Torvalds's avatar
Linus Torvalds committed
433 434 435
	if (!new_user)
		return -EAGAIN;

436 437 438 439 440 441 442
	/*
	 * We don't fail in case of NPROC limit excess here because too many
	 * poorly written programs don't check set*uid() return code, assuming
	 * it never fails if called by root.  We may still enforce NPROC limit
	 * for programs doing set*uid()+execve() by harmlessly deferring the
	 * failure to the execve() stage.
	 */
443
	if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) &&
444 445 446 447
			new_user != INIT_USER)
		current->flags |= PF_NPROC_EXCEEDED;
	else
		current->flags &= ~PF_NPROC_EXCEEDED;
Linus Torvalds's avatar
Linus Torvalds committed
448

449 450
	free_uid(new->user);
	new->user = new_user;
Linus Torvalds's avatar
Linus Torvalds committed
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
	return 0;
}

/*
 * Unprivileged users may change the real uid to the effective uid
 * or vice versa.  (BSD-style)
 *
 * If you set the real uid at all, or set the effective uid to a value not
 * equal to the real uid, then the saved uid is set to the new effective uid.
 *
 * This makes it possible for a setuid program to completely drop its
 * privileges, which is often a useful assertion to make when you are doing
 * a security audit over a program.
 *
 * The general idea is that a program which uses just setreuid() will be
 * 100% compatible with BSD.  A program which uses just setuid() will be
vishnu.ps's avatar
vishnu.ps committed
467
 * 100% compatible with POSIX with saved IDs.
Linus Torvalds's avatar
Linus Torvalds committed
468
 */
469
SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
Linus Torvalds's avatar
Linus Torvalds committed
470
{
471
	struct user_namespace *ns = current_user_ns();
472 473
	const struct cred *old;
	struct cred *new;
Linus Torvalds's avatar
Linus Torvalds committed
474
	int retval;
475 476 477 478 479 480 481 482 483
	kuid_t kruid, keuid;

	kruid = make_kuid(ns, ruid);
	keuid = make_kuid(ns, euid);

	if ((ruid != (uid_t) -1) && !uid_valid(kruid))
		return -EINVAL;
	if ((euid != (uid_t) -1) && !uid_valid(keuid))
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
484

485 486 487 488 489 490
	new = prepare_creds();
	if (!new)
		return -ENOMEM;
	old = current_cred();

	retval = -EPERM;
Linus Torvalds's avatar
Linus Torvalds committed
491
	if (ruid != (uid_t) -1) {
492 493 494
		new->uid = kruid;
		if (!uid_eq(old->uid, kruid) &&
		    !uid_eq(old->euid, kruid) &&
495
		    !ns_capable(old->user_ns, CAP_SETUID))
496
			goto error;
Linus Torvalds's avatar
Linus Torvalds committed
497 498 499
	}

	if (euid != (uid_t) -1) {
500 501 502 503
		new->euid = keuid;
		if (!uid_eq(old->uid, keuid) &&
		    !uid_eq(old->euid, keuid) &&
		    !uid_eq(old->suid, keuid) &&
504
		    !ns_capable(old->user_ns, CAP_SETUID))
505
			goto error;
Linus Torvalds's avatar
Linus Torvalds committed
506 507
	}

508
	if (!uid_eq(new->uid, old->uid)) {
509 510 511 512
		retval = set_user(new);
		if (retval < 0)
			goto error;
	}
Linus Torvalds's avatar
Linus Torvalds committed
513
	if (ruid != (uid_t) -1 ||
514
	    (euid != (uid_t) -1 && !uid_eq(keuid, old->uid)))
515 516
		new->suid = new->euid;
	new->fsuid = new->euid;
Linus Torvalds's avatar
Linus Torvalds committed
517

518 519 520
	retval = security_task_fix_setuid(new, old, LSM_SETID_RE);
	if (retval < 0)
		goto error;
Linus Torvalds's avatar
Linus Torvalds committed
521

522
	return commit_creds(new);
Linus Torvalds's avatar
Linus Torvalds committed
523

524 525 526 527
error:
	abort_creds(new);
	return retval;
}
vishnu.ps's avatar
vishnu.ps committed
528

Linus Torvalds's avatar
Linus Torvalds committed
529
/*
vishnu.ps's avatar
vishnu.ps committed
530 531
 * setuid() is implemented like SysV with SAVED_IDS
 *
Linus Torvalds's avatar
Linus Torvalds committed
532
 * Note that SAVED_ID's is deficient in that a setuid root program
vishnu.ps's avatar
vishnu.ps committed
533
 * like sendmail, for example, cannot set its uid to be a normal
Linus Torvalds's avatar
Linus Torvalds committed
534 535 536 537
 * user and then switch back, because if you're root, setuid() sets
 * the saved uid too.  If you don't like this, blame the bright people
 * in the POSIX committee and/or USG.  Note that the BSD-style setreuid()
 * will allow a root program to temporarily drop privileges and be able to
vishnu.ps's avatar
vishnu.ps committed
538
 * regain them by swapping the real and effective uid.
Linus Torvalds's avatar
Linus Torvalds committed
539
 */
540
SYSCALL_DEFINE1(setuid, uid_t, uid)
Linus Torvalds's avatar
Linus Torvalds committed
541
{
542
	struct user_namespace *ns = current_user_ns();
543 544
	const struct cred *old;
	struct cred *new;
Linus Torvalds's avatar
Linus Torvalds committed
545
	int retval;
546 547 548 549 550
	kuid_t kuid;

	kuid = make_kuid(ns, uid);
	if (!uid_valid(kuid))
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
551

552 553 554 555 556 557
	new = prepare_creds();
	if (!new)
		return -ENOMEM;
	old = current_cred();

	retval = -EPERM;
558
	if (ns_capable(old->user_ns, CAP_SETUID)) {
559 560
		new->suid = new->uid = kuid;
		if (!uid_eq(kuid, old->uid)) {
561 562 563
			retval = set_user(new);
			if (retval < 0)
				goto error;
564
		}
565
	} else if (!uid_eq(kuid, old->uid) && !uid_eq(kuid, new->suid)) {
566
		goto error;
Linus Torvalds's avatar
Linus Torvalds committed
567 568
	}

569
	new->fsuid = new->euid = kuid;
570 571 572 573

	retval = security_task_fix_setuid(new, old, LSM_SETID_ID);
	if (retval < 0)
		goto error;
Linus Torvalds's avatar
Linus Torvalds committed
574

575
	return commit_creds(new);
Linus Torvalds's avatar
Linus Torvalds committed
576

577 578 579
error:
	abort_creds(new);
	return retval;
Linus Torvalds's avatar
Linus Torvalds committed
580 581 582 583 584 585 586
}


/*
 * This function implements a generic ability to update ruid, euid,
 * and suid.  This allows you to implement the 4.4 compatible seteuid().
 */
587
SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
Linus Torvalds's avatar
Linus Torvalds committed
588
{
589
	struct user_namespace *ns = current_user_ns();
590 591
	const struct cred *old;
	struct cred *new;
Linus Torvalds's avatar
Linus Torvalds committed
592
	int retval;
593 594 595 596 597 598 599 600 601 602 603 604 605 606
	kuid_t kruid, keuid, ksuid;

	kruid = make_kuid(ns, ruid);
	keuid = make_kuid(ns, euid);
	ksuid = make_kuid(ns, suid);

	if ((ruid != (uid_t) -1) && !uid_valid(kruid))
		return -EINVAL;

	if ((euid != (uid_t) -1) && !uid_valid(keuid))
		return -EINVAL;

	if ((suid != (uid_t) -1) && !uid_valid(ksuid))
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
607

608 609 610 611 612
	new = prepare_creds();
	if (!new)
		return -ENOMEM;

	old = current_cred();
Linus Torvalds's avatar
Linus Torvalds committed
613

614
	retval = -EPERM;
615
	if (!ns_capable(old->user_ns, CAP_SETUID)) {
616 617
		if (ruid != (uid_t) -1        && !uid_eq(kruid, old->uid) &&
		    !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid))
618
			goto error;
619 620
		if (euid != (uid_t) -1        && !uid_eq(keuid, old->uid) &&
		    !uid_eq(keuid, old->euid) && !uid_eq(keuid, old->suid))
621
			goto error;
622 623
		if (suid != (uid_t) -1        && !uid_eq(ksuid, old->uid) &&
		    !uid_eq(ksuid, old->euid) && !uid_eq(ksuid, old->suid))
624
			goto error;
Linus Torvalds's avatar
Linus Torvalds committed
625
	}
626

Linus Torvalds's avatar
Linus Torvalds committed
627
	if (ruid != (uid_t) -1) {
628 629
		new->uid = kruid;
		if (!uid_eq(kruid, old->uid)) {
630 631 632 633
			retval = set_user(new);
			if (retval < 0)
				goto error;
		}
Linus Torvalds's avatar
Linus Torvalds committed
634
	}
635
	if (euid != (uid_t) -1)
636
		new->euid = keuid;
Linus Torvalds's avatar
Linus Torvalds committed
637
	if (suid != (uid_t) -1)
638
		new->suid = ksuid;
639
	new->fsuid = new->euid;
Linus Torvalds's avatar
Linus Torvalds committed
640

641 642 643
	retval = security_task_fix_setuid(new, old, LSM_SETID_RES);
	if (retval < 0)
		goto error;
Linus Torvalds's avatar
Linus Torvalds committed
644

645
	return commit_creds(new);
Linus Torvalds's avatar
Linus Torvalds committed
646

647 648 649
error:
	abort_creds(new);
	return retval;
Linus Torvalds's avatar
Linus Torvalds committed
650 651
}

652
SYSCALL_DEFINE3(getresuid, uid_t __user *, ruidp, uid_t __user *, euidp, uid_t __user *, suidp)
Linus Torvalds's avatar
Linus Torvalds committed
653
{
654
	const struct cred *cred = current_cred();
Linus Torvalds's avatar
Linus Torvalds committed
655
	int retval;
656 657 658 659 660
	uid_t ruid, euid, suid;

	ruid = from_kuid_munged(cred->user_ns, cred->uid);
	euid = from_kuid_munged(cred->user_ns, cred->euid);
	suid = from_kuid_munged(cred->user_ns, cred->suid);
Linus Torvalds's avatar
Linus Torvalds committed
661

vishnu.ps's avatar
vishnu.ps committed
662 663 664 665 666 667
	retval = put_user(ruid, ruidp);
	if (!retval) {
		retval = put_user(euid, euidp);
		if (!retval)
			return put_user(suid, suidp);
	}
Linus Torvalds's avatar
Linus Torvalds committed
668 669 670 671 672 673
	return retval;
}

/*
 * Same as above, but for rgid, egid, sgid.
 */
674
SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
Linus Torvalds's avatar
Linus Torvalds committed
675
{
676
	struct user_namespace *ns = current_user_ns();
677 678
	const struct cred *old;
	struct cred *new;
Linus Torvalds's avatar
Linus Torvalds committed
679
	int retval;
680 681 682 683 684 685 686 687 688 689 690 691
	kgid_t krgid, kegid, ksgid;

	krgid = make_kgid(ns, rgid);
	kegid = make_kgid(ns, egid);
	ksgid = make_kgid(ns, sgid);

	if ((rgid != (gid_t) -1) && !gid_valid(krgid))
		return -EINVAL;
	if ((egid != (gid_t) -1) && !gid_valid(kegid))
		return -EINVAL;
	if ((sgid != (gid_t) -1) && !gid_valid(ksgid))
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
692

693 694 695 696 697 698
	new = prepare_creds();
	if (!new)
		return -ENOMEM;
	old = current_cred();

	retval = -EPERM;
699
	if (!ns_capable(old->user_ns, CAP_SETGID)) {
700 701
		if (rgid != (gid_t) -1        && !gid_eq(krgid, old->gid) &&
		    !gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid))
702
			goto error;
703 704
		if (egid != (gid_t) -1        && !gid_eq(kegid, old->gid) &&
		    !gid_eq(kegid, old->egid) && !gid_eq(kegid, old->sgid))
705
			goto error;
706 707
		if (sgid != (gid_t) -1        && !gid_eq(ksgid, old->gid) &&
		    !gid_eq(ksgid, old->egid) && !gid_eq(ksgid, old->sgid))
708
			goto error;
Linus Torvalds's avatar
Linus Torvalds committed
709
	}
710

Linus Torvalds's avatar
Linus Torvalds committed
711
	if (rgid != (gid_t) -1)
712
		new->gid = krgid;
713
	if (egid != (gid_t) -1)
714
		new->egid = kegid;
Linus Torvalds's avatar
Linus Torvalds committed
715
	if (sgid != (gid_t) -1)
716
		new->sgid = ksgid;
717
	new->fsgid = new->egid;
Linus Torvalds's avatar
Linus Torvalds committed
718

719 720 721 722 723
	return commit_creds(new);

error:
	abort_creds(new);
	return retval;
Linus Torvalds's avatar
Linus Torvalds committed
724 725
}

726
SYSCALL_DEFINE3(getresgid, gid_t __user *, rgidp, gid_t __user *, egidp, gid_t __user *, sgidp)
Linus Torvalds's avatar
Linus Torvalds committed
727
{
728
	const struct cred *cred = current_cred();
Linus Torvalds's avatar
Linus Torvalds committed
729
	int retval;
730 731 732 733 734
	gid_t rgid, egid, sgid;

	rgid = from_kgid_munged(cred->user_ns, cred->gid);
	egid = from_kgid_munged(cred->user_ns, cred->egid);
	sgid = from_kgid_munged(cred->user_ns, cred->sgid);
Linus Torvalds's avatar
Linus Torvalds committed
735

vishnu.ps's avatar
vishnu.ps committed
736 737 738 739 740 741
	retval = put_user(rgid, rgidp);
	if (!retval) {
		retval = put_user(egid, egidp);
		if (!retval)
			retval = put_user(sgid, sgidp);
	}
Linus Torvalds's avatar
Linus Torvalds committed
742 743 744 745 746 747 748 749 750 751 752

	return retval;
}


/*
 * "setfsuid()" sets the fsuid - the uid used for filesystem checks. This
 * is used for "access()" and for the NFS daemon (letting nfsd stay at
 * whatever uid it wants to). It normally shadows "euid", except when
 * explicitly set by setfsuid() or for access..
 */
753
SYSCALL_DEFINE1(setfsuid, uid_t, uid)
Linus Torvalds's avatar
Linus Torvalds committed
754
{
755 756 757
	const struct cred *old;
	struct cred *new;
	uid_t old_fsuid;
758 759 760 761 762 763 764 765
	kuid_t kuid;

	old = current_cred();
	old_fsuid = from_kuid_munged(old->user_ns, old->fsuid);

	kuid = make_kuid(old->user_ns, uid);
	if (!uid_valid(kuid))
		return old_fsuid;
Linus Torvalds's avatar
Linus Torvalds committed
766

767 768
	new = prepare_creds();
	if (!new)
769
		return old_fsuid;
Linus Torvalds's avatar
Linus Torvalds committed
770

771 772
	if (uid_eq(kuid, old->uid)  || uid_eq(kuid, old->euid)  ||
	    uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) ||
773
	    ns_capable(old->user_ns, CAP_SETUID)) {
774 775
		if (!uid_eq(kuid, old->fsuid)) {
			new->fsuid = kuid;
776 777
			if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
				goto change_okay;
Linus Torvalds's avatar
Linus Torvalds committed
778 779 780
		}
	}

781 782
	abort_creds(new);
	return old_fsuid;
Linus Torvalds's avatar
Linus Torvalds committed
783

784 785
change_okay:
	commit_creds(new);
Linus Torvalds's avatar
Linus Torvalds committed
786 787 788 789
	return old_fsuid;
}

/*
790
 * Samma på svenska..
Linus Torvalds's avatar
Linus Torvalds committed
791
 */
792
SYSCALL_DEFINE1(setfsgid, gid_t, gid)
Linus Torvalds's avatar
Linus Torvalds committed
793
{
794 795 796
	const struct cred *old;
	struct cred *new;
	gid_t old_fsgid;
797 798 799 800 801 802 803 804
	kgid_t kgid;

	old = current_cred();
	old_fsgid = from_kgid_munged(old->user_ns, old->fsgid);

	kgid = make_kgid(old->user_ns, gid);
	if (!gid_valid(kgid))
		return old_fsgid;
805 806 807

	new = prepare_creds();
	if (!new)
808
		return old_fsgid;
Linus Torvalds's avatar
Linus Torvalds committed
809

810 811
	if (gid_eq(kgid, old->gid)  || gid_eq(kgid, old->egid)  ||
	    gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) ||
812
	    ns_capable(old->user_ns, CAP_SETGID)) {
813 814
		if (!gid_eq(kgid, old->fsgid)) {
			new->fsgid = kgid;
815
			goto change_okay;
Linus Torvalds's avatar
Linus Torvalds committed
816 817
		}
	}
818 819 820 821 822 823

	abort_creds(new);
	return old_fsgid;

change_okay:
	commit_creds(new);
Linus Torvalds's avatar
Linus Torvalds committed
824 825
	return old_fsgid;
}
826
#endif /* CONFIG_MULTIUSER */
Linus Torvalds's avatar
Linus Torvalds committed
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 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888
/**
 * sys_getpid - return the thread group id of the current process
 *
 * Note, despite the name, this returns the tgid not the pid.  The tgid and
 * the pid are identical unless CLONE_THREAD was specified on clone() in
 * which case the tgid is the same in all threads of the same group.
 *
 * This is SMP safe as current->tgid does not change.
 */
SYSCALL_DEFINE0(getpid)
{
	return task_tgid_vnr(current);
}

/* Thread ID - the internal kernel "pid" */
SYSCALL_DEFINE0(gettid)
{
	return task_pid_vnr(current);
}

/*
 * Accessing ->real_parent is not SMP-safe, it could
 * change from under us. However, we can use a stale
 * value of ->real_parent under rcu_read_lock(), see
 * release_task()->call_rcu(delayed_put_task_struct).
 */
SYSCALL_DEFINE0(getppid)
{
	int pid;

	rcu_read_lock();
	pid = task_tgid_vnr(rcu_dereference(current->real_parent));
	rcu_read_unlock();

	return pid;
}

SYSCALL_DEFINE0(getuid)
{
	/* Only we change this so SMP safe */
	return from_kuid_munged(current_user_ns(), current_uid());
}

SYSCALL_DEFINE0(geteuid)
{
	/* Only we change this so SMP safe */
	return from_kuid_munged(current_user_ns(), current_euid());
}

SYSCALL_DEFINE0(getgid)
{
	/* Only we change this so SMP safe */
	return from_kgid_munged(current_user_ns(), current_gid());
}

SYSCALL_DEFINE0(getegid)
{
	/* Only we change this so SMP safe */
	return from_kgid_munged(current_user_ns(), current_egid());
}

889 890
void do_sys_times(struct tms *tms)
{
891
	u64 tgutime, tgstime, cutime, cstime;
892

893
	thread_group_cputime_adjusted(current, &tgutime, &tgstime);
894 895
	cutime = current->signal->cutime;
	cstime = current->signal->cstime;
896 897 898 899
	tms->tms_utime = nsec_to_clock_t(tgutime);
	tms->tms_stime = nsec_to_clock_t(tgstime);
	tms->tms_cutime = nsec_to_clock_t(cutime);
	tms->tms_cstime = nsec_to_clock_t(cstime);
900 901
}

902
SYSCALL_DEFINE1(times, struct tms __user *, tbuf)
Linus Torvalds's avatar
Linus Torvalds committed
903 904 905
{
	if (tbuf) {
		struct tms tmp;
906 907

		do_sys_times(&tmp);
Linus Torvalds's avatar
Linus Torvalds committed
908 909 910
		if (copy_to_user(tbuf, &tmp, sizeof(struct tms)))
			return -EFAULT;
	}
911
	force_successful_syscall_return();
Linus Torvalds's avatar
Linus Torvalds committed
912 913 914 915 916 917 918 919 920 921 922 923
	return (long) jiffies_64_to_clock_t(get_jiffies_64());
}

/*
 * This needs some heavy checking ...
 * I just haven't the stomach for it. I also don't fully
 * understand sessions/pgrp etc. Let somebody who does explain it.
 *
 * OK, I think I have the protection semantics right.... this is really
 * only important on a multi-user system anyway, to make sure one user
 * can't send a signal to a process owned by another.  -TYT, 12/12/91
 *
924
 * !PF_FORKNOEXEC check to conform completely to POSIX.
Linus Torvalds's avatar
Linus Torvalds committed
925
 */
926
SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid)
Linus Torvalds's avatar
Linus Torvalds committed
927 928
{
	struct task_struct *p;
929
	struct task_struct *group_leader = current->group_leader;
930 931
	struct pid *pgrp;
	int err;
Linus Torvalds's avatar
Linus Torvalds committed
932 933

	if (!pid)
934
		pid = task_pid_vnr(group_leader);
Linus Torvalds's avatar
Linus Torvalds committed
935 936 937 938
	if (!pgid)
		pgid = pid;
	if (pgid < 0)
		return -EINVAL;
939
	rcu_read_lock();
Linus Torvalds's avatar
Linus Torvalds committed
940 941 942 943 944 945 946

	/* From this point forward we keep holding onto the tasklist lock
	 * so that our parent does not change from under us. -DaveM
	 */
	write_lock_irq(&tasklist_lock);

	err = -ESRCH;
947
	p = find_task_by_vpid(pid);
Linus Torvalds's avatar
Linus Torvalds committed
948 949 950 951 952 953 954
	if (!p)
		goto out;

	err = -EINVAL;
	if (!thread_group_leader(p))
		goto out;

955
	if (same_thread_group(p->real_parent, group_leader)) {
Linus Torvalds's avatar
Linus Torvalds committed
956
		err = -EPERM;
957
		if (task_session(p) != task_session(group_leader))
Linus Torvalds's avatar
Linus Torvalds committed
958 959
			goto out;
		err = -EACCES;
960
		if (!(p->flags & PF_FORKNOEXEC))
Linus Torvalds's avatar
Linus Torvalds committed
961 962 963
			goto out;
	} else {
		err = -ESRCH;
964
		if (p != group_leader)
Linus Torvalds's avatar
Linus Torvalds committed
965 966 967 968 969 970 971
			goto out;
	}

	err = -EPERM;
	if (p->signal->leader)
		goto out;

972
	pgrp = task_pid(p);
Linus Torvalds's avatar
Linus Torvalds committed
973
	if (pgid != pid) {
974
		struct task_struct *g;
Linus Torvalds's avatar
Linus Torvalds committed
975

976 977
		pgrp = find_vpid(pgid);
		g = pid_task(pgrp, PIDTYPE_PGID);
978
		if (!g || task_session(g) != task_session(group_leader))
979
			goto out;
Linus Torvalds's avatar
Linus Torvalds committed
980 981 982 983 984 985
	}

	err = security_task_setpgid(p, pgid);
	if (err)
		goto out;

986
	if (task_pgrp(p) != pgrp)
987
		change_pid(p, PIDTYPE_PGID, pgrp);
Linus Torvalds's avatar
Linus Torvalds committed
988 989 990 991 992

	err = 0;
out:
	/* All paths lead to here, thus we are safe. -DaveM */
	write_unlock_irq(&tasklist_lock);
993
	rcu_read_unlock();
Linus Torvalds's avatar
Linus Torvalds committed
994 995 996
	return err;
}

997
SYSCALL_DEFINE1(getpgid, pid_t, pid)
Linus Torvalds's avatar
Linus Torvalds committed
998
{
999 1000 1001 1002 1003
	struct task_struct *p;
	struct pid *grp;
	int retval;

	rcu_read_lock();
1004
	if (!pid)
1005
		grp = task_pgrp(current);
1006
	else {
Linus Torvalds's avatar
Linus Torvalds committed
1007
		retval = -ESRCH;
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
		p = find_task_by_vpid(pid);
		if (!p)
			goto out;
		grp = task_pgrp(p);
		if (!grp)
			goto out;

		retval = security_task_getpgid(p);
		if (retval)
			goto out;
Linus Torvalds's avatar
Linus Torvalds committed
1018
	}
1019 1020 1021 1022
	retval = pid_vnr(grp);
out:
	rcu_read_unlock();
	return retval;
Linus Torvalds's avatar
Linus Torvalds committed
1023 1024 1025 1026
}

#ifdef __ARCH_WANT_SYS_GETPGRP

1027
SYSCALL_DEFINE0(getpgrp)
Linus Torvalds's avatar
Linus Torvalds committed
1028
{
1029
	return sys_getpgid(0);
Linus Torvalds's avatar
Linus Torvalds committed
1030 1031 1032 1033
}

#endif

1034
SYSCALL_DEFINE1(getsid, pid_t, pid)
Linus Torvalds's avatar
Linus Torvalds committed
1035
{
1036 1037 1038 1039 1040
	struct task_struct *p;
	struct pid *sid;
	int retval;

	rcu_read_lock();
1041
	if (!pid)
1042
		sid = task_session(current);
1043
	else {
Linus Torvalds's avatar
Linus Torvalds committed
1044
		retval = -ESRCH;
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054
		p = find_task_by_vpid(pid);
		if (!p)
			goto out;
		sid = task_session(p);
		if (!sid)
			goto out;

		retval = security_task_getsid(p);
		if (retval)
			goto out;
Linus Torvalds's avatar
Linus Torvalds committed
1055
	}
1056 1057 1058 1059
	retval = pid_vnr(sid);
out:
	rcu_read_unlock();
	return retval;
Linus Torvalds's avatar
Linus Torvalds committed
1060 1061
}

1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
static void set_special_pids(struct pid *pid)
{
	struct task_struct *curr = current->group_leader;

	if (task_session(curr) != pid)
		change_pid(curr, PIDTYPE_SID, pid);

	if (task_pgrp(curr) != pid)
		change_pid(curr, PIDTYPE_PGID, pid);
}

1073
SYSCALL_DEFINE0(setsid)
Linus Torvalds's avatar
Linus Torvalds committed
1074
{
1075
	struct task_struct *group_leader = current->group_leader;
1076 1077
	struct pid *sid = task_pid(group_leader);
	pid_t session = pid_vnr(sid);
Linus Torvalds's avatar
Linus Torvalds committed
1078 1079 1080
	int err = -EPERM;

	write_lock_irq(&tasklist_lock);
1081 1082 1083 1084
	/* Fail if I am already a session leader */
	if (group_leader->signal->leader)
		goto out;

1085 1086
	/* Fail if a process group id already exists that equals the
	 * proposed session id.
1087
	 */
1088
	if (pid_task(sid, PIDTYPE_PGID))
Linus Torvalds's avatar
Linus Torvalds committed
1089 1090
		goto out;

1091
	group_leader->signal->leader = 1;
1092
	set_special_pids(sid);
1093

Alan Cox's avatar
Alan Cox committed
1094
	proc_clear_tty(group_leader);
1095

1096
	err = session;
Linus Torvalds's avatar
Linus Torvalds committed
1097 1098
out:
	write_unlock_irq(&tasklist_lock);
1099
	if (err > 0) {
1100
		proc_sid_connector(group_leader);
1101 1102
		sched_autogroup_create_attach(group_leader);
	}
Linus Torvalds's avatar
Linus Torvalds committed
1103 1104 1105 1106 1107
	return err;
}

DECLARE_RWSEM(uts_sem);

1108 1109
#ifdef COMPAT_UTS_MACHINE
#define override_architecture(name) \
1110
	(personality(current->personality) == PER_LINUX32 && \
1111 1112 1113 1114 1115 1116
	 copy_to_user(name->machine, COMPAT_UTS_MACHINE, \
		      sizeof(COMPAT_UTS_MACHINE)))
#else
#define override_architecture(name)	0
#endif

1117 1118 1119
/*
 * Work around broken programs that cannot handle "Linux 3.0".
 * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40
1120
 * And we map 4.x to 2.6.60+x, so 4.0 would be 2.6.60.
1121
 */
1122
static int override_release(char __user *release, size_t len)
1123 1124 1125 1126
{
	int ret = 0;

	if (current->personality & UNAME26) {
1127 1128
		const char *rest = UTS_RELEASE;
		char buf[65] = { 0 };
1129 1130
		int ndots = 0;
		unsigned v;
1131
		size_t copy;
1132 1133 1134 1135 1136 1137 1138 1139

		while (*rest) {
			if (*rest == '.' && ++ndots >= 3)
				break;
			if (!isdigit(*rest) && *rest != '.')
				break;
			rest++;
		}
1140
		v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 60;
Kees Cook's avatar
Kees Cook committed
1141
		copy = clamp_t(size_t, len, 1, sizeof(buf));
1142 1143
		copy = scnprintf(buf, copy, "2.6.%u%s", v, rest);
		ret = copy_to_user(release, buf, copy + 1);
1144 1145 1146 1147
	}
	return ret;
}

1148
SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
Linus Torvalds's avatar
Linus Torvalds committed
1149 1150 1151 1152
{
	int errno = 0;

	down_read(&uts_sem);
1153
	if (copy_to_user(name, utsname(), sizeof *name))
Linus Torvalds's avatar
Linus Torvalds committed
1154 1155
		errno = -EFAULT;
	up_read(&uts_sem);
1156

1157 1158
	if (!errno && override_release(name->release, sizeof(name->release)))
		errno = -EFAULT;
1159 1160
	if (!errno && override_architecture(name))
		errno = -EFAULT;
Linus Torvalds's avatar
Linus Torvalds committed
1161 1162 1163
	return errno;
}

1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179
#ifdef __ARCH_WANT_SYS_OLD_UNAME
/*
 * Old cruft
 */
SYSCALL_DEFINE1(uname, struct old_utsname __user *, name)
{
	int error = 0;

	if (!name)
		return -EFAULT;

	down_read(&uts_sem);
	if (copy_to_user(name, utsname(), sizeof(*name)))
		error = -EFAULT;
	up_read(&uts_sem);

1180 1181
	if (!error && override_release(name->release, sizeof(name->release)))
		error = -EFAULT;
1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215
	if (!error && override_architecture(name))
		error = -EFAULT;
	return error;
}

SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name)
{
	int error;

	if (!name)
		return -EFAULT;
	if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
		return -EFAULT;

	down_read(&uts_sem);
	error = __copy_to_user(&name->sysname, &utsname()->sysname,
			       __OLD_UTS_LEN);
	error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
	error |= __copy_to_user(&name->nodename, &utsname()->nodename,
				__OLD_UTS_LEN);
	error |= __put_user(0, name->nodename + __OLD_UTS_LEN);
	error |= __copy_to_user(&name->release, &utsname()->release,
				__OLD_UTS_LEN);
	error |= __put_user(0, name->release + __OLD_UTS_LEN);
	error |= __copy_to_user(&name->version, &utsname()->version,
				__OLD_UTS_LEN);
	error |= __put_user(0, name->version + __OLD_UTS_LEN);
	error |= __copy_to_user(&name->machine, &utsname()->machine,
				__OLD_UTS_LEN);
	error |= __put_user(0, name->machine + __OLD_UTS_LEN);
	up_read(&uts_sem);

	if (!error && override_architecture(name))
		error = -EFAULT;
1216 1217
	if (!error && override_release(name->release, sizeof(name->release)))
		error = -EFAULT;
1218 1219 1220 1221
	return error ? -EFAULT : 0;
}
#endif

1222
SYSCALL_DEFINE2(sethostname, char __user *, name, int, len)
Linus Torvalds's avatar
Linus Torvalds committed
1223 1224 1225 1226
{
	int errno;
	char tmp[__NEW_UTS_LEN];

1227
	if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN))
Linus Torvalds's avatar
Linus Torvalds committed
1228
		return -EPERM;
1229

Linus Torvalds's avatar
Linus Torvalds committed
1230 1231 1232 1233 1234
	if (len < 0 || len > __NEW_UTS_LEN)
		return -EINVAL;
	down_write(&uts_sem);
	errno = -EFAULT;
	if (!copy_from_user(tmp, name, len)) {
1235 1236 1237 1238
		struct new_utsname *u = utsname();

		memcpy(u->nodename, tmp, len);
		memset(u->nodename +</