Commit message: None
CVE: CVE-2015-6640
CWE: CWE-264
Vulnerability description: The prctl_set_vma_anon_name function in kernel/sys.c in Android before 5.1.1 LMY49F and 6.0 before 2016-01-01 does not ensure that only one vma is accessed in a certain update action, which allows attackers to gain privileges or cause a denial of service (vma list corruption) via a crafted application, aka internal bug 20017123.

Project: Android

SYSCALL_DEFINE1(setgid, gid_t, gid)
{
 const struct cred *old;
 struct cred *new;
 int retval;

 new = prepare_creds();
 if (!new)
 return -ENOMEM;
	old = current_cred();

	retval = -EPERM;
 if (nsown_capable(CAP_SETGID))
 new->gid = new->egid = new->sgid = new->fsgid = gid;
 else if (gid == old->gid || gid == old->sgid)
 new->egid = new->fsgid = gid;
 else
 goto error;

 return commit_creds(new);

error:
	abort_creds(new);
 return retval;
}

Project: Android

SYSCALL_DEFINE1(setuid, uid_t, uid)
{
 const struct cred *old;
 struct cred *new;
 int retval;

 new = prepare_creds();
 if (!new)
 return -ENOMEM;
	old = current_cred();

	retval = -EPERM;
 if (nsown_capable(CAP_SETUID)) {
 new->suid = new->uid = uid;
 if (uid != old->uid) {
			retval = set_user(new);
 if (retval < 0)
 goto error;
 }
 } else if (uid != old->uid && uid != new->suid) {
 goto error;
 }

 new->fsuid = new->euid = uid;

	retval = security_task_fix_setuid(new, old, LSM_SETID_ID);
 if (retval < 0)
 goto error;

 return commit_creds(new);

error:
	abort_creds(new);
 return retval;
}

Project: Android

SYSCALL_DEFINE1(setfsuid, uid_t, uid)
{
 const struct cred *old;
 struct cred *new;
 uid_t old_fsuid;

 new = prepare_creds();
 if (!new)
 return current_fsuid();
	old = current_cred();
	old_fsuid = old->fsuid;

 if (uid == old->uid  || uid == old->euid  ||
	    uid == old->suid || uid == old->fsuid ||
	    nsown_capable(CAP_SETUID)) {
 if (uid != old_fsuid) {
 new->fsuid = uid;
 if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
 goto change_okay;
 }
 }

	abort_creds(new);
 return old_fsuid;

change_okay:
	commit_creds(new);
 return old_fsuid;
}

Project: Android

SYSCALL_DEFINE1(setfsgid, gid_t, gid)
{
 const struct cred *old;
 struct cred *new;
 gid_t old_fsgid;

 new = prepare_creds();
 if (!new)
 return current_fsgid();
	old = current_cred();
	old_fsgid = old->fsgid;

 if (gid == old->gid  || gid == old->egid  ||
	    gid == old->sgid || gid == old->fsgid ||
	    nsown_capable(CAP_SETGID)) {
 if (gid != old_fsgid) {
 new->fsgid = gid;
 goto change_okay;
 }
 }

	abort_creds(new);
 return old_fsgid;

change_okay:
	commit_creds(new);
 return old_fsgid;
}

Project: Android

SYSCALL_DEFINE2(getpriority, int, which, int, who)
{
 struct task_struct *g, *p;
 struct user_struct *user;
 const struct cred *cred = current_cred();
 long niceval, retval = -ESRCH;
 struct pid *pgrp;

 if (which > PRIO_USER || which < PRIO_PROCESS)
 return -EINVAL;

	rcu_read_lock();
	read_lock(&tasklist_lock);
 switch (which) {
 case PRIO_PROCESS:
 if (who)
				p = find_task_by_vpid(who);
 else
				p = current;
 if (p) {
				niceval = 20 - 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 = 20 - task_nice(p);
 if (niceval > retval)
					retval = niceval;
 } while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
 break;
 case PRIO_USER:
			user = (struct user_struct *) cred->user;
 if (!who)
				who = cred->uid;
 else if ((who != cred->uid) &&
 !(user = find_user(who)))
 goto out_unlock; /* No processes for this user */

			do_each_thread(g, p) {
 if (__task_cred(p)->uid == who) {
					niceval = 20 - task_nice(p);
 if (niceval > retval)
						retval = niceval;
 }
 } while_each_thread(g, p);
 if (who != cred->uid)
				free_uid(user); /* for find_user() */
 break;
 }
out_unlock:
	read_unlock(&tasklist_lock);
	rcu_read_unlock();

 return retval;
}

Project: Android

SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
{
 const struct cred *old;
 struct cred *new;
 int retval;

 new = prepare_creds();
 if (!new)
 return -ENOMEM;
	old = current_cred();

	retval = -EPERM;
 if (rgid != (gid_t) -1) {
 if (old->gid == rgid ||
		    old->egid == rgid ||
		    nsown_capable(CAP_SETGID))
 new->gid = rgid;
 else
 goto error;
 }
 if (egid != (gid_t) -1) {
 if (old->gid == egid ||
		    old->egid == egid ||
		    old->sgid == egid ||
		    nsown_capable(CAP_SETGID))
 new->egid = egid;
 else
 goto error;
 }

 if (rgid != (gid_t) -1 ||
 (egid != (gid_t) -1 && egid != old->gid))
 new->sgid = new->egid;
 new->fsgid = new->egid;

 return commit_creds(new);

error:
	abort_creds(new);
 return retval;
}

Project: Android

SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
{
 const struct cred *old;
 struct cred *new;
 int retval;

 new = prepare_creds();
 if (!new)
 return -ENOMEM;
	old = current_cred();

	retval = -EPERM;
 if (ruid != (uid_t) -1) {
 new->uid = ruid;
 if (old->uid != ruid &&
		    old->euid != ruid &&
 !nsown_capable(CAP_SETUID))
 goto error;
 }

 if (euid != (uid_t) -1) {
 new->euid = euid;
 if (old->uid != euid &&
		    old->euid != euid &&
		    old->suid != euid &&
 !nsown_capable(CAP_SETUID))
 goto error;
 }

 if (new->uid != old->uid) {
		retval = set_user(new);
 if (retval < 0)
 goto error;
 }
 if (ruid != (uid_t) -1 ||
 (euid != (uid_t) -1 && euid != old->uid))
 new->suid = new->euid;
 new->fsuid = new->euid;

	retval = security_task_fix_setuid(new, old, LSM_SETID_RE);
 if (retval < 0)
 goto error;

 return commit_creds(new);

error:
	abort_creds(new);
 return retval;
}

Project: Android

SYSCALL_DEFINE2(sethostname, char __user *, name, int, len)
{
 int errno;
 char tmp[__NEW_UTS_LEN];

 if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN))
 return -EPERM;

 if (len < 0 || len > __NEW_UTS_LEN)
 return -EINVAL;
	down_write(&uts_sem);
	errno = -EFAULT;
 if (!copy_from_user(tmp, name, len)) {
 struct new_utsname *u = utsname();

		memcpy(u->nodename, tmp, len);
		memset(u->nodename + len, 0, sizeof(u->nodename) - len);
		errno = 0;
 }
	uts_proc_notify(UTS_PROC_HOSTNAME);
	up_write(&uts_sem);
 return errno;
}

Project: Android

SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len)
{
 int errno;
 char tmp[__NEW_UTS_LEN];

 if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN))
 return -EPERM;
 if (len < 0 || len > __NEW_UTS_LEN)
 return -EINVAL;

	down_write(&uts_sem);
	errno = -EFAULT;
 if (!copy_from_user(tmp, name, len)) {
 struct new_utsname *u = utsname();

		memcpy(u->domainname, tmp, len);
		memset(u->domainname + len, 0, sizeof(u->domainname) - len);
		errno = 0;
 }
	uts_proc_notify(UTS_PROC_DOMAINNAME);
	up_write(&uts_sem);
 return errno;
}

Project: Android

SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
{
 struct task_struct *g, *p;
 struct user_struct *user;
 const struct cred *cred = current_cred();
 int error = -EINVAL;
 struct pid *pgrp;

 if (which > PRIO_USER || which < PRIO_PROCESS)
 goto out;

 /* normalize: avoid signed division (rounding problems) */
	error = -ESRCH;
 if (niceval < -20)
		niceval = -20;
 if (niceval > 19)
		niceval = 19;

	rcu_read_lock();
	read_lock(&tasklist_lock);
 switch (which) {
 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:
			user = (struct user_struct *) cred->user;
 if (!who)
				who = cred->uid;
 else if ((who != cred->uid) &&
 !(user = find_user(who)))
 goto out_unlock; /* No processes for this user */

			do_each_thread(g, p) {
 if (__task_cred(p)->uid == who)
					error = set_one_prio(p, niceval, error);
 } while_each_thread(g, p);
 if (who != cred->uid)
				free_uid(user); /* For find_user() */
 break;
 }
out_unlock:
	read_unlock(&tasklist_lock);
	rcu_read_unlock();
out:
 return error;
}

Project: Android

SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
{
 const struct cred *old;
 struct cred *new;
 int retval;

 new = prepare_creds();
 if (!new)
 return -ENOMEM;
	old = current_cred();

	retval = -EPERM;
 if (!nsown_capable(CAP_SETGID)) {
 if (rgid != (gid_t) -1 && rgid != old->gid &&
		    rgid != old->egid  && rgid != old->sgid)
 goto error;
 if (egid != (gid_t) -1 && egid != old->gid &&
		    egid != old->egid  && egid != old->sgid)
 goto error;
 if (sgid != (gid_t) -1 && sgid != old->gid &&
		    sgid != old->egid  && sgid != old->sgid)
 goto error;
 }

 if (rgid != (gid_t) -1)
 new->gid = rgid;
 if (egid != (gid_t) -1)
 new->egid = egid;
 if (sgid != (gid_t) -1)
 new->sgid = sgid;
 new->fsgid = new->egid;

 return commit_creds(new);

error:
	abort_creds(new);
 return retval;
}

Project: Android

SYSCALL_DEFINE3(getresgid, gid_t __user *, rgid, gid_t __user *, egid, gid_t __user *, sgid)
{
 const struct cred *cred = current_cred();
 int retval;

 if (!(retval   = put_user(cred->gid,  rgid)) &&
 !(retval   = put_user(cred->egid, egid)))
		retval = put_user(cred->sgid, sgid);

 return retval;
}

Project: Android
File: sys.c

SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
 void __user *, arg)
{
 char buffer[256];
 int ret = 0;

 /* We only trust the superuser with rebooting the system. */
 if (!capable(CAP_SYS_BOOT))
 return -EPERM;

 /* For safety, we require "magic" arguments. */
 if (magic1 != LINUX_REBOOT_MAGIC1 ||
 (magic2 != LINUX_REBOOT_MAGIC2 &&
	                magic2 != LINUX_REBOOT_MAGIC2A &&
			magic2 != LINUX_REBOOT_MAGIC2B &&
	                magic2 != LINUX_REBOOT_MAGIC2C))
 return -EINVAL;

 /*
	 * If pid namespaces are enabled and the current task is in a child
	 * pid_namespace, the command is handled by reboot_pid_ns() which will
	 * call do_exit().
	 */
	ret = reboot_pid_ns(task_active_pid_ns(current), cmd);
 if (ret)
 return ret;

 /* Instead of trying to make the power_off code look like
	 * halt when pm_power_off is not set do it the easy way.
	 */
 if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
		cmd = LINUX_REBOOT_CMD_HALT;

	mutex_lock(&reboot_mutex);
 switch (cmd) {
 case LINUX_REBOOT_CMD_RESTART:
		kernel_restart(NULL);
 break;

 case LINUX_REBOOT_CMD_CAD_ON:
		C_A_D = 1;
 break;

 case LINUX_REBOOT_CMD_CAD_OFF:
		C_A_D = 0;
 break;

 case LINUX_REBOOT_CMD_HALT:
		kernel_halt();
		do_exit(0);
		panic("cannot halt");

 case LINUX_REBOOT_CMD_POWER_OFF:
		kernel_power_off();
		do_exit(0);
 break;

 case LINUX_REBOOT_CMD_RESTART2:
 if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {
			ret = -EFAULT;
 break;
 }
		buffer[sizeof(buffer) - 1] = '\0';

		kernel_restart(buffer);
 break;

#ifdef CONFIG_KEXEC
 case LINUX_REBOOT_CMD_KEXEC:
		ret = kernel_kexec();
 break;
#endif

#ifdef CONFIG_HIBERNATION
 case LINUX_REBOOT_CMD_SW_SUSPEND:
		ret = hibernate();
 break;
#endif

 default:
		ret = -EINVAL;
 break;
 }
	mutex_unlock(&reboot_mutex);
 return ret;
}

Project: Android

SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
 unsigned long, arg4, unsigned long, arg5)
{
 struct task_struct *me = current;
 struct task_struct *tsk;
 unsigned char comm[sizeof(me->comm)];
 long error;

	error = security_task_prctl(option, arg2, arg3, arg4, arg5);
 if (error != -ENOSYS)
 return error;

	error = 0;
 switch (option) {
 case PR_SET_PDEATHSIG:
 if (!valid_signal(arg2)) {
				error = -EINVAL;
 break;
 }
			me->pdeath_signal = arg2;
			error = 0;
 break;
 case PR_GET_PDEATHSIG:
			error = put_user(me->pdeath_signal, (int __user *)arg2);
 break;
 case PR_GET_DUMPABLE:
			error = get_dumpable(me->mm);
 break;
 case PR_SET_DUMPABLE:
 if (arg2 < 0 || arg2 > 1) {
				error = -EINVAL;
 break;
 }
			set_dumpable(me->mm, arg2);
			error = 0;
 break;

 case PR_SET_UNALIGN:
			error = SET_UNALIGN_CTL(me, arg2);
 break;
 case PR_GET_UNALIGN:
			error = GET_UNALIGN_CTL(me, arg2);
 break;
 case PR_SET_FPEMU:
			error = SET_FPEMU_CTL(me, arg2);
 break;
 case PR_GET_FPEMU:
			error = GET_FPEMU_CTL(me, arg2);
 break;
 case PR_SET_FPEXC:
			error = SET_FPEXC_CTL(me, arg2);
 break;
 case PR_GET_FPEXC:
			error = GET_FPEXC_CTL(me, arg2);
 break;
 case PR_GET_TIMING:
			error = PR_TIMING_STATISTICAL;
 break;
 case PR_SET_TIMING:
 if (arg2 != PR_TIMING_STATISTICAL)
				error = -EINVAL;
 else
				error = 0;
 break;

 case PR_SET_NAME:
			comm[sizeof(me->comm)-1] = 0;
 if (strncpy_from_user(comm, (char __user *)arg2,
 sizeof(me->comm) - 1) < 0)
 return -EFAULT;
			set_task_comm(me, comm);
			proc_comm_connector(me);
 return 0;
 case PR_GET_NAME:
			get_task_comm(comm, me);
 if (copy_to_user((char __user *)arg2, comm,
 sizeof(comm)))
 return -EFAULT;
 return 0;
 case PR_GET_ENDIAN:
			error = GET_ENDIAN(me, arg2);
 break;
 case PR_SET_ENDIAN:
			error = SET_ENDIAN(me, arg2);
 break;

 case PR_GET_SECCOMP:
			error = prctl_get_seccomp();
 break;
 case PR_SET_SECCOMP:
			error = prctl_set_seccomp(arg2);
 break;
 case PR_GET_TSC:
			error = GET_TSC_CTL(arg2);
 break;
 case PR_SET_TSC:
			error = SET_TSC_CTL(arg2);
 break;
 case PR_TASK_PERF_EVENTS_DISABLE:
			error = perf_event_task_disable();
 break;
 case PR_TASK_PERF_EVENTS_ENABLE:
			error = perf_event_task_enable();
 break;
 case PR_GET_TIMERSLACK:
			error = current->timer_slack_ns;
 break;
 case PR_SET_TIMERSLACK:
 if (arg2 <= 0)
				current->timer_slack_ns =
					current->default_timer_slack_ns;
 else
				current->timer_slack_ns = arg2;
			error = 0;
 break;
 case PR_MCE_KILL:
 if (arg4 | arg5)
 return -EINVAL;
 switch (arg2) {
 case PR_MCE_KILL_CLEAR:
 if (arg3 != 0)
 return -EINVAL;
				current->flags &= ~PF_MCE_PROCESS;
 break;
 case PR_MCE_KILL_SET:
				current->flags |= PF_MCE_PROCESS;
 if (arg3 == PR_MCE_KILL_EARLY)
					current->flags |= PF_MCE_EARLY;
 else if (arg3 == PR_MCE_KILL_LATE)
					current->flags &= ~PF_MCE_EARLY;
 else if (arg3 == PR_MCE_KILL_DEFAULT)
					current->flags &=
 ~(PF_MCE_EARLY|PF_MCE_PROCESS);
 else
 return -EINVAL;
 break;
 default:
 return -EINVAL;
 }
			error = 0;
 break;
 case PR_MCE_KILL_GET:
 if (arg2 | arg3 | arg4 | arg5)
 return -EINVAL;
 if (current->flags & PF_MCE_PROCESS)
				error = (current->flags & PF_MCE_EARLY) ?
					PR_MCE_KILL_EARLY : PR_MCE_KILL_LATE;
 else
				error = PR_MCE_KILL_DEFAULT;
 break;
 case PR_SET_MM:
			error = prctl_set_mm(arg2, arg3, arg4, arg5);
 break;
 case PR_SET_CHILD_SUBREAPER:
			me->signal->is_child_subreaper = !!arg2;
			error = 0;
 break;
 case PR_GET_CHILD_SUBREAPER:
			error = put_user(me->signal->is_child_subreaper,
 (int __user *) arg2);
 break;
 case PR_SET_VMA:
			error = prctl_set_vma(arg2, arg3, arg4, arg5);
 break;
 case PR_SET_TIMERSLACK_PID:
 if (current->pid != (pid_t)arg3 &&
 !capable(CAP_SYS_NICE))
 return -EPERM;
			rcu_read_lock();
			tsk = find_task_by_pid_ns((pid_t)arg3, &init_pid_ns);
 if (tsk == NULL) {
				rcu_read_unlock();
 return -EINVAL;
 }
			get_task_struct(tsk);
			rcu_read_unlock();
 if (arg2 <= 0)
				tsk->timer_slack_ns =
					tsk->default_timer_slack_ns;
 else
				tsk->timer_slack_ns = arg2;
			put_task_struct(tsk);
			error = 0;
 break;
 default:
			error = -EINVAL;
 break;
 }
 return error;
}

Project: Android

static int check_prlimit_permission(struct task_struct *task)
{
 const struct cred *cred = current_cred(), *tcred;

 if (current == task)
 return 0;

	tcred = __task_cred(task);
 if (cred->user->user_ns == tcred->user->user_ns &&
 (cred->uid == tcred->euid &&
	     cred->uid == tcred->suid &&
	     cred->uid == tcred->uid  &&
	     cred->gid == tcred->egid &&
	     cred->gid == tcred->sgid &&
	     cred->gid == tcred->gid))
 return 0;
 if (ns_capable(tcred->user->user_ns, CAP_SYS_RESOURCE))
 return 0;

 return -EPERM;
}

Project: Android

void kernel_halt(void)
{
	kernel_shutdown_prepare(SYSTEM_HALT);
	migrate_to_reboot_cpu();
	syscore_shutdown();
	printk(KERN_EMERG "System halted.\n");
	kmsg_dump(KMSG_DUMP_HALT);
	machine_halt();
}

Project: Android

void kernel_restart(char *cmd)
{
	kernel_restart_prepare(cmd);
	migrate_to_reboot_cpu();
	syscore_shutdown();
 if (!cmd)
		printk(KERN_EMERG "Restarting system.\n");
 else
		printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);
	kmsg_dump(KMSG_DUMP_RESTART);
	machine_restart(cmd);
}

Project: Android

void kernel_restart_prepare(char *cmd)
{
	blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
	system_state = SYSTEM_RESTART;
	usermodehelper_disable();
	device_shutdown();
}

Project: Android

static void migrate_to_reboot_cpu(void)
{
 /* The boot cpu is always logical cpu 0 */
 int cpu = 0;

	cpu_hotplug_disable();

 /* Make certain the cpu I'm about to reboot on is online */
 if (!cpu_online(cpu))
		cpu = cpumask_first(cpu_online_mask);

 /* Prevent races with other tasks migrating this task */
	current->flags |= PF_NO_SETAFFINITY;

 /* Make certain I only run on the appropriate processor */
	set_cpus_allowed_ptr(current, cpumask_of(cpu));
}

Project: Android

int orderly_poweroff(bool force)
{
 int argc;
 char **argv = argv_split(GFP_ATOMIC, poweroff_cmd, &argc);
 static char *envp[] = {
 "HOME=/",
 "PATH=/sbin:/bin:/usr/sbin:/usr/bin",
		NULL
 };
 int ret = -ENOMEM;
 struct subprocess_info *info;

 if (argv == NULL) {
		printk(KERN_WARNING "%s failed to allocate memory for \"%s\"\n",
		       __func__, poweroff_cmd);
 goto out;
 }

	info = call_usermodehelper_setup(argv[0], argv, envp, GFP_ATOMIC);
 if (info == NULL) {
		argv_free(argv);
 goto out;
 }

	call_usermodehelper_setfns(info, NULL, argv_cleanup, NULL);

	ret = call_usermodehelper_exec(info, UMH_NO_WAIT);

  out:
 if (ret && force) {
		printk(KERN_WARNING "Failed to start orderly shutdown: "
 "forcing the issue\n");

 /* I guess this should try to kick off some daemon to
		   sync and poweroff asap.  Or not even bother syncing
		   if we're doing an emergency shutdown? */
		emergency_sync();
		kernel_power_off();
 }

 return ret;
}

Project: Android

static int override_release(char __user *release, size_t len)
{
 int ret = 0;

 if (current->personality & UNAME26) {
 const char *rest = UTS_RELEASE;
 char buf[65] = { 0 };
 int ndots = 0;
 unsigned v;
 size_t copy;

 while (*rest) {
 if (*rest == '.' && ++ndots >= 3)
 break;
 if (!isdigit(*rest) && *rest != '.')
 break;
			rest++;
 }
		v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 40;
		copy = clamp_t(size_t, len, 1, sizeof(buf));
		copy = scnprintf(buf, copy, "2.6.%u%s", v, rest);
		ret = copy_to_user(release, buf, copy + 1);
 }
 return ret;
}

Project: Android

static int prctl_set_mm(int opt, unsigned long addr,
 unsigned long arg4, unsigned long arg5)
{
 unsigned long rlim = rlimit(RLIMIT_DATA);
 unsigned long vm_req_flags;
 unsigned long vm_bad_flags;
 struct vm_area_struct *vma;
 int error = 0;
 struct mm_struct *mm = current->mm;

 if (arg4 | arg5)
 return -EINVAL;

 if (!capable(CAP_SYS_RESOURCE))
 return -EPERM;

 if (addr >= TASK_SIZE)
 return -EINVAL;

	down_read(&mm->mmap_sem);
	vma = find_vma(mm, addr);

 if (opt != PR_SET_MM_START_BRK && opt != PR_SET_MM_BRK) {
 /* It must be existing VMA */
 if (!vma || vma->vm_start > addr)
 goto out;
 }

	error = -EINVAL;
 switch (opt) {
 case PR_SET_MM_START_CODE:
 case PR_SET_MM_END_CODE:
		vm_req_flags = VM_READ | VM_EXEC;
		vm_bad_flags = VM_WRITE | VM_MAYSHARE;

 if ((vma->vm_flags & vm_req_flags) != vm_req_flags ||
 (vma->vm_flags & vm_bad_flags))
 goto out;

 if (opt == PR_SET_MM_START_CODE)
			mm->start_code = addr;
 else
			mm->end_code = addr;
 break;

 case PR_SET_MM_START_DATA:
 case PR_SET_MM_END_DATA:
		vm_req_flags = VM_READ | VM_WRITE;
		vm_bad_flags = VM_EXEC | VM_MAYSHARE;

 if ((vma->vm_flags & vm_req_flags) != vm_req_flags ||
 (vma->vm_flags & vm_bad_flags))
 goto out;

 if (opt == PR_SET_MM_START_DATA)
			mm->start_data = addr;
 else
			mm->end_data = addr;
 break;

 case PR_SET_MM_START_STACK:

#ifdef CONFIG_STACK_GROWSUP
		vm_req_flags = VM_READ | VM_WRITE | VM_GROWSUP;
#else
		vm_req_flags = VM_READ | VM_WRITE | VM_GROWSDOWN;
#endif
 if ((vma->vm_flags & vm_req_flags) != vm_req_flags)
 goto out;

		mm->start_stack = addr;
 break;

 case PR_SET_MM_START_BRK:
 if (addr <= mm->end_data)
 goto out;

 if (rlim < RLIM_INFINITY &&
 (mm->brk - addr) +
 (mm->end_data - mm->start_data) > rlim)
 goto out;

		mm->start_brk = addr;
 break;

 case PR_SET_MM_BRK:
 if (addr <= mm->end_data)
 goto out;

 if (rlim < RLIM_INFINITY &&
 (addr - mm->start_brk) +
 (mm->end_data - mm->start_data) > rlim)
 goto out;

		mm->brk = addr;
 break;

 default:
		error = -EINVAL;
 goto out;
 }

	error = 0;

out:
	up_read(&mm->mmap_sem);

 return error;
}

Project: Android

static int prctl_set_vma(unsigned long opt, unsigned long start,
 unsigned long len_in, unsigned long arg)
{
 struct mm_struct *mm = current->mm;
 int error;
 unsigned long len;
 unsigned long end;

 if (start & ~PAGE_MASK)
 return -EINVAL;
	len = (len_in + ~PAGE_MASK) & PAGE_MASK;

 /* Check to see whether len was rounded up from small -ve to zero */
 if (len_in && !len)
 return -EINVAL;

	end = start + len;
 if (end < start)
 return -EINVAL;

 if (end == start)
 return 0;

	down_write(&mm->mmap_sem);

 switch (opt) {
 case PR_SET_VMA_ANON_NAME:
		error = prctl_set_vma_anon_name(start, end, arg);
 break;
 default:
		error = -EINVAL;
 }

	up_write(&mm->mmap_sem);

 return error;
}

Project: Android

static int prctl_update_vma_anon_name(struct vm_area_struct *vma,
 struct vm_area_struct **prev,
 unsigned long start, unsigned long end,
 const char __user *name_addr)
{
 struct mm_struct * mm = vma->vm_mm;
 int error = 0;
 pgoff_t pgoff;

 if (name_addr == vma_get_anon_name(vma)) {
 *prev = vma;
 goto out;
 }

	pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
 *prev = vma_merge(mm, *prev, start, end, vma->vm_flags, vma->anon_vma,
				vma->vm_file, pgoff, vma_policy(vma),
				name_addr);
 if (*prev) {
		vma = *prev;
 goto success;
 }

 *prev = vma;

 if (start != vma->vm_start) {
		error = split_vma(mm, vma, start, 1);
 if (error)
 goto out;
 }

 if (end != vma->vm_end) {
		error = split_vma(mm, vma, end, 0);
 if (error)
 goto out;
 }

success:
 if (!vma->vm_file)
		vma->shared.anon_name = name_addr;

out:
 if (error == -ENOMEM)
		error = -EAGAIN;
 return error;
}

Project: Android
File: sys.c

int register_reboot_notifier(struct notifier_block *nb)
{
 return blocking_notifier_chain_register(&reboot_notifier_list, nb);
}

Project: Android

static bool set_one_prio_perm(struct task_struct *p)
{
 const struct cred *cred = current_cred(), *pcred = __task_cred(p);

 if (pcred->user->user_ns == cred->user->user_ns &&
 (pcred->uid  == cred->euid ||
	     pcred->euid == cred->euid))
 return true;
 if (ns_capable(pcred->user->user_ns, CAP_SYS_NICE))
 return true;
 return false;
}

Project: Android

static int set_user(struct cred *new)
{
 struct user_struct *new_user;

	new_user = alloc_uid(current_user_ns(), new->uid);
 if (!new_user)
 return -EAGAIN;

 /*
	 * 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.
	 */
 if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) &&
			new_user != INIT_USER)
		current->flags |= PF_NPROC_EXCEEDED;
 else
		current->flags &= ~PF_NPROC_EXCEEDED;

	free_uid(new->user);
 new->user = new_user;
 return 0;
}