Merge branch 'linus' into perfcounters/core
Conflicts: fs/exec.c include/linux/init_task.h Simple context conflicts.
This commit is contained in:
commit
e1df957670
2949 changed files with 143576 additions and 80290 deletions
594
kernel/sys.c
594
kernel/sys.c
|
@ -113,12 +113,17 @@ EXPORT_SYMBOL(cad_pid);
|
|||
|
||||
void (*pm_power_off_prepare)(void);
|
||||
|
||||
/*
|
||||
* set the priority of a task
|
||||
* - the caller must hold the RCU read lock
|
||||
*/
|
||||
static int set_one_prio(struct task_struct *p, int niceval, int error)
|
||||
{
|
||||
const struct cred *cred = current_cred(), *pcred = __task_cred(p);
|
||||
int no_nice;
|
||||
|
||||
if (p->uid != current->euid &&
|
||||
p->euid != current->euid && !capable(CAP_SYS_NICE)) {
|
||||
if (pcred->uid != cred->euid &&
|
||||
pcred->euid != cred->euid && !capable(CAP_SYS_NICE)) {
|
||||
error = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
@ -142,6 +147,7 @@ asmlinkage long sys_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;
|
||||
|
||||
|
@ -175,18 +181,18 @@ asmlinkage long sys_setpriority(int which, int who, int niceval)
|
|||
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
|
||||
break;
|
||||
case PRIO_USER:
|
||||
user = current->user;
|
||||
user = (struct user_struct *) cred->user;
|
||||
if (!who)
|
||||
who = current->uid;
|
||||
else
|
||||
if ((who != current->uid) && !(user = find_user(who)))
|
||||
goto out_unlock; /* No processes for this user */
|
||||
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 (p->uid == who)
|
||||
if (__task_cred(p)->uid == who)
|
||||
error = set_one_prio(p, niceval, error);
|
||||
while_each_thread(g, p);
|
||||
if (who != current->uid)
|
||||
if (who != cred->uid)
|
||||
free_uid(user); /* For find_user() */
|
||||
break;
|
||||
}
|
||||
|
@ -206,6 +212,7 @@ asmlinkage long sys_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;
|
||||
|
||||
|
@ -237,21 +244,21 @@ asmlinkage long sys_getpriority(int which, int who)
|
|||
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
|
||||
break;
|
||||
case PRIO_USER:
|
||||
user = current->user;
|
||||
user = (struct user_struct *) cred->user;
|
||||
if (!who)
|
||||
who = current->uid;
|
||||
else
|
||||
if ((who != current->uid) && !(user = find_user(who)))
|
||||
goto out_unlock; /* No processes for this user */
|
||||
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 (p->uid == who) {
|
||||
if (__task_cred(p)->uid == who) {
|
||||
niceval = 20 - task_nice(p);
|
||||
if (niceval > retval)
|
||||
retval = niceval;
|
||||
}
|
||||
while_each_thread(g, p);
|
||||
if (who != current->uid)
|
||||
if (who != cred->uid)
|
||||
free_uid(user); /* for find_user() */
|
||||
break;
|
||||
}
|
||||
|
@ -473,46 +480,48 @@ void ctrl_alt_del(void)
|
|||
*/
|
||||
asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
|
||||
{
|
||||
int old_rgid = current->gid;
|
||||
int old_egid = current->egid;
|
||||
int new_rgid = old_rgid;
|
||||
int new_egid = old_egid;
|
||||
const struct cred *old;
|
||||
struct cred *new;
|
||||
int retval;
|
||||
|
||||
new = prepare_creds();
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
old = current_cred();
|
||||
|
||||
retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE);
|
||||
if (retval)
|
||||
return retval;
|
||||
goto error;
|
||||
|
||||
retval = -EPERM;
|
||||
if (rgid != (gid_t) -1) {
|
||||
if ((old_rgid == rgid) ||
|
||||
(current->egid==rgid) ||
|
||||
if (old->gid == rgid ||
|
||||
old->egid == rgid ||
|
||||
capable(CAP_SETGID))
|
||||
new_rgid = rgid;
|
||||
new->gid = rgid;
|
||||
else
|
||||
return -EPERM;
|
||||
goto error;
|
||||
}
|
||||
if (egid != (gid_t) -1) {
|
||||
if ((old_rgid == egid) ||
|
||||
(current->egid == egid) ||
|
||||
(current->sgid == egid) ||
|
||||
if (old->gid == egid ||
|
||||
old->egid == egid ||
|
||||
old->sgid == egid ||
|
||||
capable(CAP_SETGID))
|
||||
new_egid = egid;
|
||||
new->egid = egid;
|
||||
else
|
||||
return -EPERM;
|
||||
}
|
||||
if (new_egid != old_egid) {
|
||||
set_dumpable(current->mm, suid_dumpable);
|
||||
smp_wmb();
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (rgid != (gid_t) -1 ||
|
||||
(egid != (gid_t) -1 && egid != old_rgid))
|
||||
current->sgid = new_egid;
|
||||
current->fsgid = new_egid;
|
||||
current->egid = new_egid;
|
||||
current->gid = new_rgid;
|
||||
key_fsgid_changed(current);
|
||||
proc_id_connector(current, PROC_EVENT_GID);
|
||||
return 0;
|
||||
(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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -522,56 +531,54 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
|
|||
*/
|
||||
asmlinkage long sys_setgid(gid_t gid)
|
||||
{
|
||||
int old_egid = current->egid;
|
||||
const struct cred *old;
|
||||
struct cred *new;
|
||||
int retval;
|
||||
|
||||
new = prepare_creds();
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
old = current_cred();
|
||||
|
||||
retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID);
|
||||
if (retval)
|
||||
return retval;
|
||||
goto error;
|
||||
|
||||
if (capable(CAP_SETGID)) {
|
||||
if (old_egid != gid) {
|
||||
set_dumpable(current->mm, suid_dumpable);
|
||||
smp_wmb();
|
||||
}
|
||||
current->gid = current->egid = current->sgid = current->fsgid = gid;
|
||||
} else if ((gid == current->gid) || (gid == current->sgid)) {
|
||||
if (old_egid != gid) {
|
||||
set_dumpable(current->mm, suid_dumpable);
|
||||
smp_wmb();
|
||||
}
|
||||
current->egid = current->fsgid = gid;
|
||||
}
|
||||
retval = -EPERM;
|
||||
if (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
|
||||
return -EPERM;
|
||||
goto error;
|
||||
|
||||
key_fsgid_changed(current);
|
||||
proc_id_connector(current, PROC_EVENT_GID);
|
||||
return 0;
|
||||
return commit_creds(new);
|
||||
|
||||
error:
|
||||
abort_creds(new);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int set_user(uid_t new_ruid, int dumpclear)
|
||||
/*
|
||||
* change the user struct in a credentials set to match the new UID
|
||||
*/
|
||||
static int set_user(struct cred *new)
|
||||
{
|
||||
struct user_struct *new_user;
|
||||
|
||||
new_user = alloc_uid(current->nsproxy->user_ns, new_ruid);
|
||||
new_user = alloc_uid(current_user_ns(), new->uid);
|
||||
if (!new_user)
|
||||
return -EAGAIN;
|
||||
|
||||
if (atomic_read(&new_user->processes) >=
|
||||
current->signal->rlim[RLIMIT_NPROC].rlim_cur &&
|
||||
new_user != current->nsproxy->user_ns->root_user) {
|
||||
new_user != INIT_USER) {
|
||||
free_uid(new_user);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
switch_uid(new_user);
|
||||
|
||||
if (dumpclear) {
|
||||
set_dumpable(current->mm, suid_dumpable);
|
||||
smp_wmb();
|
||||
}
|
||||
current->uid = new_ruid;
|
||||
free_uid(new->user);
|
||||
new->user = new_user;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -592,54 +599,56 @@ static int set_user(uid_t new_ruid, int dumpclear)
|
|||
*/
|
||||
asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
|
||||
{
|
||||
int old_ruid, old_euid, old_suid, new_ruid, new_euid;
|
||||
const struct cred *old;
|
||||
struct cred *new;
|
||||
int retval;
|
||||
|
||||
new = prepare_creds();
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
old = current_cred();
|
||||
|
||||
retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
new_ruid = old_ruid = current->uid;
|
||||
new_euid = old_euid = current->euid;
|
||||
old_suid = current->suid;
|
||||
goto error;
|
||||
|
||||
retval = -EPERM;
|
||||
if (ruid != (uid_t) -1) {
|
||||
new_ruid = ruid;
|
||||
if ((old_ruid != ruid) &&
|
||||
(current->euid != ruid) &&
|
||||
new->uid = ruid;
|
||||
if (old->uid != ruid &&
|
||||
old->euid != ruid &&
|
||||
!capable(CAP_SETUID))
|
||||
return -EPERM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (euid != (uid_t) -1) {
|
||||
new_euid = euid;
|
||||
if ((old_ruid != euid) &&
|
||||
(current->euid != euid) &&
|
||||
(current->suid != euid) &&
|
||||
new->euid = euid;
|
||||
if (old->uid != euid &&
|
||||
old->euid != euid &&
|
||||
old->suid != euid &&
|
||||
!capable(CAP_SETUID))
|
||||
return -EPERM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0)
|
||||
return -EAGAIN;
|
||||
retval = -EAGAIN;
|
||||
if (new->uid != old->uid && set_user(new) < 0)
|
||||
goto error;
|
||||
|
||||
if (new_euid != old_euid) {
|
||||
set_dumpable(current->mm, suid_dumpable);
|
||||
smp_wmb();
|
||||
}
|
||||
current->fsuid = current->euid = new_euid;
|
||||
if (ruid != (uid_t) -1 ||
|
||||
(euid != (uid_t) -1 && euid != old_ruid))
|
||||
current->suid = current->euid;
|
||||
current->fsuid = current->euid;
|
||||
(euid != (uid_t) -1 && euid != old->uid))
|
||||
new->suid = new->euid;
|
||||
new->fsuid = new->euid;
|
||||
|
||||
key_fsuid_changed(current);
|
||||
proc_id_connector(current, PROC_EVENT_UID);
|
||||
retval = security_task_fix_setuid(new, old, LSM_SETID_RE);
|
||||
if (retval < 0)
|
||||
goto error;
|
||||
|
||||
return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE);
|
||||
return commit_creds(new);
|
||||
|
||||
error:
|
||||
abort_creds(new);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* setuid() is implemented like SysV with SAVED_IDS
|
||||
|
@ -654,36 +663,41 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
|
|||
*/
|
||||
asmlinkage long sys_setuid(uid_t uid)
|
||||
{
|
||||
int old_euid = current->euid;
|
||||
int old_ruid, old_suid, new_suid;
|
||||
const struct cred *old;
|
||||
struct cred *new;
|
||||
int retval;
|
||||
|
||||
new = prepare_creds();
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
old = current_cred();
|
||||
|
||||
retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID);
|
||||
if (retval)
|
||||
return retval;
|
||||
goto error;
|
||||
|
||||
old_ruid = current->uid;
|
||||
old_suid = current->suid;
|
||||
new_suid = old_suid;
|
||||
|
||||
retval = -EPERM;
|
||||
if (capable(CAP_SETUID)) {
|
||||
if (uid != old_ruid && set_user(uid, old_euid != uid) < 0)
|
||||
return -EAGAIN;
|
||||
new_suid = uid;
|
||||
} else if ((uid != current->uid) && (uid != new_suid))
|
||||
return -EPERM;
|
||||
|
||||
if (old_euid != uid) {
|
||||
set_dumpable(current->mm, suid_dumpable);
|
||||
smp_wmb();
|
||||
new->suid = new->uid = uid;
|
||||
if (uid != old->uid && set_user(new) < 0) {
|
||||
retval = -EAGAIN;
|
||||
goto error;
|
||||
}
|
||||
} else if (uid != old->uid && uid != new->suid) {
|
||||
goto error;
|
||||
}
|
||||
current->fsuid = current->euid = uid;
|
||||
current->suid = new_suid;
|
||||
|
||||
key_fsuid_changed(current);
|
||||
proc_id_connector(current, PROC_EVENT_UID);
|
||||
new->fsuid = new->euid = uid;
|
||||
|
||||
return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -693,54 +707,63 @@ asmlinkage long sys_setuid(uid_t uid)
|
|||
*/
|
||||
asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
|
||||
{
|
||||
int old_ruid = current->uid;
|
||||
int old_euid = current->euid;
|
||||
int old_suid = current->suid;
|
||||
const struct cred *old;
|
||||
struct cred *new;
|
||||
int retval;
|
||||
|
||||
new = prepare_creds();
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES);
|
||||
if (retval)
|
||||
return retval;
|
||||
goto error;
|
||||
old = current_cred();
|
||||
|
||||
retval = -EPERM;
|
||||
if (!capable(CAP_SETUID)) {
|
||||
if ((ruid != (uid_t) -1) && (ruid != current->uid) &&
|
||||
(ruid != current->euid) && (ruid != current->suid))
|
||||
return -EPERM;
|
||||
if ((euid != (uid_t) -1) && (euid != current->uid) &&
|
||||
(euid != current->euid) && (euid != current->suid))
|
||||
return -EPERM;
|
||||
if ((suid != (uid_t) -1) && (suid != current->uid) &&
|
||||
(suid != current->euid) && (suid != current->suid))
|
||||
return -EPERM;
|
||||
if (ruid != (uid_t) -1 && ruid != old->uid &&
|
||||
ruid != old->euid && ruid != old->suid)
|
||||
goto error;
|
||||
if (euid != (uid_t) -1 && euid != old->uid &&
|
||||
euid != old->euid && euid != old->suid)
|
||||
goto error;
|
||||
if (suid != (uid_t) -1 && suid != old->uid &&
|
||||
suid != old->euid && suid != old->suid)
|
||||
goto error;
|
||||
}
|
||||
|
||||
retval = -EAGAIN;
|
||||
if (ruid != (uid_t) -1) {
|
||||
if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0)
|
||||
return -EAGAIN;
|
||||
new->uid = ruid;
|
||||
if (ruid != old->uid && set_user(new) < 0)
|
||||
goto error;
|
||||
}
|
||||
if (euid != (uid_t) -1) {
|
||||
if (euid != current->euid) {
|
||||
set_dumpable(current->mm, suid_dumpable);
|
||||
smp_wmb();
|
||||
}
|
||||
current->euid = euid;
|
||||
}
|
||||
current->fsuid = current->euid;
|
||||
if (euid != (uid_t) -1)
|
||||
new->euid = euid;
|
||||
if (suid != (uid_t) -1)
|
||||
current->suid = suid;
|
||||
new->suid = suid;
|
||||
new->fsuid = new->euid;
|
||||
|
||||
key_fsuid_changed(current);
|
||||
proc_id_connector(current, PROC_EVENT_UID);
|
||||
retval = security_task_fix_setuid(new, old, LSM_SETID_RES);
|
||||
if (retval < 0)
|
||||
goto error;
|
||||
|
||||
return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES);
|
||||
return commit_creds(new);
|
||||
|
||||
error:
|
||||
abort_creds(new);
|
||||
return retval;
|
||||
}
|
||||
|
||||
asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
int retval;
|
||||
|
||||
if (!(retval = put_user(current->uid, ruid)) &&
|
||||
!(retval = put_user(current->euid, euid)))
|
||||
retval = put_user(current->suid, suid);
|
||||
if (!(retval = put_user(cred->uid, ruid)) &&
|
||||
!(retval = put_user(cred->euid, euid)))
|
||||
retval = put_user(cred->suid, suid);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -750,48 +773,55 @@ asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __us
|
|||
*/
|
||||
asmlinkage long sys_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 = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES);
|
||||
if (retval)
|
||||
return retval;
|
||||
goto error;
|
||||
|
||||
retval = -EPERM;
|
||||
if (!capable(CAP_SETGID)) {
|
||||
if ((rgid != (gid_t) -1) && (rgid != current->gid) &&
|
||||
(rgid != current->egid) && (rgid != current->sgid))
|
||||
return -EPERM;
|
||||
if ((egid != (gid_t) -1) && (egid != current->gid) &&
|
||||
(egid != current->egid) && (egid != current->sgid))
|
||||
return -EPERM;
|
||||
if ((sgid != (gid_t) -1) && (sgid != current->gid) &&
|
||||
(sgid != current->egid) && (sgid != current->sgid))
|
||||
return -EPERM;
|
||||
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 (egid != (gid_t) -1) {
|
||||
if (egid != current->egid) {
|
||||
set_dumpable(current->mm, suid_dumpable);
|
||||
smp_wmb();
|
||||
}
|
||||
current->egid = egid;
|
||||
}
|
||||
current->fsgid = current->egid;
|
||||
if (rgid != (gid_t) -1)
|
||||
current->gid = rgid;
|
||||
if (sgid != (gid_t) -1)
|
||||
current->sgid = sgid;
|
||||
|
||||
key_fsgid_changed(current);
|
||||
proc_id_connector(current, PROC_EVENT_GID);
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
|
||||
asmlinkage long sys_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(current->gid, rgid)) &&
|
||||
!(retval = put_user(current->egid, egid)))
|
||||
retval = put_user(current->sgid, sgid);
|
||||
if (!(retval = put_user(cred->gid, rgid)) &&
|
||||
!(retval = put_user(cred->egid, egid)))
|
||||
retval = put_user(cred->sgid, sgid);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -805,27 +835,35 @@ asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __us
|
|||
*/
|
||||
asmlinkage long sys_setfsuid(uid_t uid)
|
||||
{
|
||||
int old_fsuid;
|
||||
const struct cred *old;
|
||||
struct cred *new;
|
||||
uid_t old_fsuid;
|
||||
|
||||
old_fsuid = current->fsuid;
|
||||
if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS))
|
||||
return old_fsuid;
|
||||
new = prepare_creds();
|
||||
if (!new)
|
||||
return current_fsuid();
|
||||
old = current_cred();
|
||||
old_fsuid = old->fsuid;
|
||||
|
||||
if (uid == current->uid || uid == current->euid ||
|
||||
uid == current->suid || uid == current->fsuid ||
|
||||
if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS) < 0)
|
||||
goto error;
|
||||
|
||||
if (uid == old->uid || uid == old->euid ||
|
||||
uid == old->suid || uid == old->fsuid ||
|
||||
capable(CAP_SETUID)) {
|
||||
if (uid != old_fsuid) {
|
||||
set_dumpable(current->mm, suid_dumpable);
|
||||
smp_wmb();
|
||||
new->fsuid = uid;
|
||||
if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
|
||||
goto change_okay;
|
||||
}
|
||||
current->fsuid = uid;
|
||||
}
|
||||
|
||||
key_fsuid_changed(current);
|
||||
proc_id_connector(current, PROC_EVENT_UID);
|
||||
|
||||
security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS);
|
||||
error:
|
||||
abort_creds(new);
|
||||
return old_fsuid;
|
||||
|
||||
change_okay:
|
||||
commit_creds(new);
|
||||
return old_fsuid;
|
||||
}
|
||||
|
||||
|
@ -834,23 +872,34 @@ asmlinkage long sys_setfsuid(uid_t uid)
|
|||
*/
|
||||
asmlinkage long sys_setfsgid(gid_t gid)
|
||||
{
|
||||
int old_fsgid;
|
||||
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;
|
||||
|
||||
old_fsgid = current->fsgid;
|
||||
if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS))
|
||||
return old_fsgid;
|
||||
goto error;
|
||||
|
||||
if (gid == current->gid || gid == current->egid ||
|
||||
gid == current->sgid || gid == current->fsgid ||
|
||||
if (gid == old->gid || gid == old->egid ||
|
||||
gid == old->sgid || gid == old->fsgid ||
|
||||
capable(CAP_SETGID)) {
|
||||
if (gid != old_fsgid) {
|
||||
set_dumpable(current->mm, suid_dumpable);
|
||||
smp_wmb();
|
||||
new->fsgid = gid;
|
||||
goto change_okay;
|
||||
}
|
||||
current->fsgid = gid;
|
||||
key_fsgid_changed(current);
|
||||
proc_id_connector(current, PROC_EVENT_GID);
|
||||
}
|
||||
|
||||
error:
|
||||
abort_creds(new);
|
||||
return old_fsgid;
|
||||
|
||||
change_okay:
|
||||
commit_creds(new);
|
||||
return old_fsgid;
|
||||
}
|
||||
|
||||
|
@ -1119,7 +1168,7 @@ EXPORT_SYMBOL(groups_free);
|
|||
|
||||
/* export the group_info to a user-space array */
|
||||
static int groups_to_user(gid_t __user *grouplist,
|
||||
struct group_info *group_info)
|
||||
const struct group_info *group_info)
|
||||
{
|
||||
int i;
|
||||
unsigned int count = group_info->ngroups;
|
||||
|
@ -1187,7 +1236,7 @@ static void groups_sort(struct group_info *group_info)
|
|||
}
|
||||
|
||||
/* a simple bsearch */
|
||||
int groups_search(struct group_info *group_info, gid_t grp)
|
||||
int groups_search(const struct group_info *group_info, gid_t grp)
|
||||
{
|
||||
unsigned int left, right;
|
||||
|
||||
|
@ -1209,51 +1258,74 @@ int groups_search(struct group_info *group_info, gid_t grp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* validate and set current->group_info */
|
||||
int set_current_groups(struct group_info *group_info)
|
||||
/**
|
||||
* set_groups - Change a group subscription in a set of credentials
|
||||
* @new: The newly prepared set of credentials to alter
|
||||
* @group_info: The group list to install
|
||||
*
|
||||
* Validate a group subscription and, if valid, insert it into a set
|
||||
* of credentials.
|
||||
*/
|
||||
int set_groups(struct cred *new, struct group_info *group_info)
|
||||
{
|
||||
int retval;
|
||||
struct group_info *old_info;
|
||||
|
||||
retval = security_task_setgroups(group_info);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
put_group_info(new->group_info);
|
||||
groups_sort(group_info);
|
||||
get_group_info(group_info);
|
||||
|
||||
task_lock(current);
|
||||
old_info = current->group_info;
|
||||
current->group_info = group_info;
|
||||
task_unlock(current);
|
||||
|
||||
put_group_info(old_info);
|
||||
|
||||
new->group_info = group_info;
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(set_groups);
|
||||
|
||||
/**
|
||||
* set_current_groups - Change current's group subscription
|
||||
* @group_info: The group list to impose
|
||||
*
|
||||
* Validate a group subscription and, if valid, impose it upon current's task
|
||||
* security record.
|
||||
*/
|
||||
int set_current_groups(struct group_info *group_info)
|
||||
{
|
||||
struct cred *new;
|
||||
int ret;
|
||||
|
||||
new = prepare_creds();
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = set_groups(new, group_info);
|
||||
if (ret < 0) {
|
||||
abort_creds(new);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return commit_creds(new);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(set_current_groups);
|
||||
|
||||
asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/*
|
||||
* SMP: Nobody else can change our grouplist. Thus we are
|
||||
* safe.
|
||||
*/
|
||||
const struct cred *cred = current_cred();
|
||||
int i;
|
||||
|
||||
if (gidsetsize < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* no need to grab task_lock here; it cannot change */
|
||||
i = current->group_info->ngroups;
|
||||
i = cred->group_info->ngroups;
|
||||
if (gidsetsize) {
|
||||
if (i > gidsetsize) {
|
||||
i = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (groups_to_user(grouplist, current->group_info)) {
|
||||
if (groups_to_user(grouplist, cred->group_info)) {
|
||||
i = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
@ -1297,9 +1369,11 @@ asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist)
|
|||
*/
|
||||
int in_group_p(gid_t grp)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
int retval = 1;
|
||||
if (grp != current->fsgid)
|
||||
retval = groups_search(current->group_info, grp);
|
||||
|
||||
if (grp != cred->fsgid)
|
||||
retval = groups_search(cred->group_info, grp);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -1307,9 +1381,11 @@ EXPORT_SYMBOL(in_group_p);
|
|||
|
||||
int in_egroup_p(gid_t grp)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
int retval = 1;
|
||||
if (grp != current->egid)
|
||||
retval = groups_search(current->group_info, grp);
|
||||
|
||||
if (grp != cred->egid)
|
||||
retval = groups_search(cred->group_info, grp);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -1625,50 +1701,56 @@ asmlinkage long sys_umask(int mask)
|
|||
asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
|
||||
unsigned long arg4, unsigned long arg5)
|
||||
{
|
||||
long error = 0;
|
||||
struct task_struct *me = current;
|
||||
unsigned char comm[sizeof(me->comm)];
|
||||
long error;
|
||||
|
||||
if (security_task_prctl(option, arg2, arg3, arg4, arg5, &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;
|
||||
}
|
||||
current->pdeath_signal = arg2;
|
||||
me->pdeath_signal = arg2;
|
||||
error = 0;
|
||||
break;
|
||||
case PR_GET_PDEATHSIG:
|
||||
error = put_user(current->pdeath_signal, (int __user *)arg2);
|
||||
error = put_user(me->pdeath_signal, (int __user *)arg2);
|
||||
break;
|
||||
case PR_GET_DUMPABLE:
|
||||
error = get_dumpable(current->mm);
|
||||
error = get_dumpable(me->mm);
|
||||
break;
|
||||
case PR_SET_DUMPABLE:
|
||||
if (arg2 < 0 || arg2 > 1) {
|
||||
error = -EINVAL;
|
||||
break;
|
||||
}
|
||||
set_dumpable(current->mm, arg2);
|
||||
set_dumpable(me->mm, arg2);
|
||||
error = 0;
|
||||
break;
|
||||
|
||||
case PR_SET_UNALIGN:
|
||||
error = SET_UNALIGN_CTL(current, arg2);
|
||||
error = SET_UNALIGN_CTL(me, arg2);
|
||||
break;
|
||||
case PR_GET_UNALIGN:
|
||||
error = GET_UNALIGN_CTL(current, arg2);
|
||||
error = GET_UNALIGN_CTL(me, arg2);
|
||||
break;
|
||||
case PR_SET_FPEMU:
|
||||
error = SET_FPEMU_CTL(current, arg2);
|
||||
error = SET_FPEMU_CTL(me, arg2);
|
||||
break;
|
||||
case PR_GET_FPEMU:
|
||||
error = GET_FPEMU_CTL(current, arg2);
|
||||
error = GET_FPEMU_CTL(me, arg2);
|
||||
break;
|
||||
case PR_SET_FPEXC:
|
||||
error = SET_FPEXC_CTL(current, arg2);
|
||||
error = SET_FPEXC_CTL(me, arg2);
|
||||
break;
|
||||
case PR_GET_FPEXC:
|
||||
error = GET_FPEXC_CTL(current, arg2);
|
||||
error = GET_FPEXC_CTL(me, arg2);
|
||||
break;
|
||||
case PR_GET_TIMING:
|
||||
error = PR_TIMING_STATISTICAL;
|
||||
|
@ -1676,33 +1758,28 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
|
|||
case PR_SET_TIMING:
|
||||
if (arg2 != PR_TIMING_STATISTICAL)
|
||||
error = -EINVAL;
|
||||
else
|
||||
error = 0;
|
||||
break;
|
||||
|
||||
case PR_SET_NAME: {
|
||||
struct task_struct *me = current;
|
||||
unsigned char ncomm[sizeof(me->comm)];
|
||||
|
||||
ncomm[sizeof(me->comm)-1] = 0;
|
||||
if (strncpy_from_user(ncomm, (char __user *)arg2,
|
||||
sizeof(me->comm)-1) < 0)
|
||||
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, ncomm);
|
||||
set_task_comm(me, comm);
|
||||
return 0;
|
||||
}
|
||||
case PR_GET_NAME: {
|
||||
struct task_struct *me = current;
|
||||
unsigned char tcomm[sizeof(me->comm)];
|
||||
|
||||
get_task_comm(tcomm, me);
|
||||
if (copy_to_user((char __user *)arg2, tcomm, sizeof(tcomm)))
|
||||
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(current, arg2);
|
||||
error = GET_ENDIAN(me, arg2);
|
||||
break;
|
||||
case PR_SET_ENDIAN:
|
||||
error = SET_ENDIAN(current, arg2);
|
||||
error = SET_ENDIAN(me, arg2);
|
||||
break;
|
||||
|
||||
case PR_GET_SECCOMP:
|
||||
|
@ -1732,6 +1809,7 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
|
|||
current->default_timer_slack_ns;
|
||||
else
|
||||
current->timer_slack_ns = arg2;
|
||||
error = 0;
|
||||
break;
|
||||
default:
|
||||
error = -EINVAL;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue