|
@@ -93,10 +93,8 @@
|
|
int overflowuid = DEFAULT_OVERFLOWUID;
|
|
int overflowuid = DEFAULT_OVERFLOWUID;
|
|
int overflowgid = DEFAULT_OVERFLOWGID;
|
|
int overflowgid = DEFAULT_OVERFLOWGID;
|
|
|
|
|
|
-#ifdef CONFIG_UID16
|
|
|
|
EXPORT_SYMBOL(overflowuid);
|
|
EXPORT_SYMBOL(overflowuid);
|
|
EXPORT_SYMBOL(overflowgid);
|
|
EXPORT_SYMBOL(overflowgid);
|
|
-#endif
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
* the same as above, but for filesystems which can only store a 16-bit
|
|
* the same as above, but for filesystems which can only store a 16-bit
|
|
@@ -133,11 +131,10 @@ static bool set_one_prio_perm(struct task_struct *p)
|
|
{
|
|
{
|
|
const struct cred *cred = current_cred(), *pcred = __task_cred(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))
|
|
|
|
|
|
+ if (uid_eq(pcred->uid, cred->euid) ||
|
|
|
|
+ uid_eq(pcred->euid, cred->euid))
|
|
return true;
|
|
return true;
|
|
- if (ns_capable(pcred->user->user_ns, CAP_SYS_NICE))
|
|
|
|
|
|
+ if (ns_capable(pcred->user_ns, CAP_SYS_NICE))
|
|
return true;
|
|
return true;
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
@@ -177,6 +174,7 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
|
|
const struct cred *cred = current_cred();
|
|
const struct cred *cred = current_cred();
|
|
int error = -EINVAL;
|
|
int error = -EINVAL;
|
|
struct pid *pgrp;
|
|
struct pid *pgrp;
|
|
|
|
+ kuid_t uid;
|
|
|
|
|
|
if (which > PRIO_USER || which < PRIO_PROCESS)
|
|
if (which > PRIO_USER || which < PRIO_PROCESS)
|
|
goto out;
|
|
goto out;
|
|
@@ -209,18 +207,19 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
|
|
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
|
|
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
|
|
break;
|
|
break;
|
|
case PRIO_USER:
|
|
case PRIO_USER:
|
|
- user = (struct user_struct *) cred->user;
|
|
|
|
|
|
+ uid = make_kuid(cred->user_ns, who);
|
|
|
|
+ user = cred->user;
|
|
if (!who)
|
|
if (!who)
|
|
- who = cred->uid;
|
|
|
|
- else if ((who != cred->uid) &&
|
|
|
|
- !(user = find_user(who)))
|
|
|
|
|
|
+ uid = cred->uid;
|
|
|
|
+ else if (!uid_eq(uid, cred->uid) &&
|
|
|
|
+ !(user = find_user(uid)))
|
|
goto out_unlock; /* No processes for this user */
|
|
goto out_unlock; /* No processes for this user */
|
|
|
|
|
|
do_each_thread(g, p) {
|
|
do_each_thread(g, p) {
|
|
- if (__task_cred(p)->uid == who)
|
|
|
|
|
|
+ if (uid_eq(task_uid(p), uid))
|
|
error = set_one_prio(p, niceval, error);
|
|
error = set_one_prio(p, niceval, error);
|
|
} while_each_thread(g, p);
|
|
} while_each_thread(g, p);
|
|
- if (who != cred->uid)
|
|
|
|
|
|
+ if (!uid_eq(uid, cred->uid))
|
|
free_uid(user); /* For find_user() */
|
|
free_uid(user); /* For find_user() */
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -244,6 +243,7 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
|
|
const struct cred *cred = current_cred();
|
|
const struct cred *cred = current_cred();
|
|
long niceval, retval = -ESRCH;
|
|
long niceval, retval = -ESRCH;
|
|
struct pid *pgrp;
|
|
struct pid *pgrp;
|
|
|
|
+ kuid_t uid;
|
|
|
|
|
|
if (which > PRIO_USER || which < PRIO_PROCESS)
|
|
if (which > PRIO_USER || which < PRIO_PROCESS)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
@@ -274,21 +274,22 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
|
|
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
|
|
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
|
|
break;
|
|
break;
|
|
case PRIO_USER:
|
|
case PRIO_USER:
|
|
- user = (struct user_struct *) cred->user;
|
|
|
|
|
|
+ uid = make_kuid(cred->user_ns, who);
|
|
|
|
+ user = cred->user;
|
|
if (!who)
|
|
if (!who)
|
|
- who = cred->uid;
|
|
|
|
- else if ((who != cred->uid) &&
|
|
|
|
- !(user = find_user(who)))
|
|
|
|
|
|
+ uid = cred->uid;
|
|
|
|
+ else if (!uid_eq(uid, cred->uid) &&
|
|
|
|
+ !(user = find_user(uid)))
|
|
goto out_unlock; /* No processes for this user */
|
|
goto out_unlock; /* No processes for this user */
|
|
|
|
|
|
do_each_thread(g, p) {
|
|
do_each_thread(g, p) {
|
|
- if (__task_cred(p)->uid == who) {
|
|
|
|
|
|
+ if (uid_eq(task_uid(p), uid)) {
|
|
niceval = 20 - task_nice(p);
|
|
niceval = 20 - task_nice(p);
|
|
if (niceval > retval)
|
|
if (niceval > retval)
|
|
retval = niceval;
|
|
retval = niceval;
|
|
}
|
|
}
|
|
} while_each_thread(g, p);
|
|
} while_each_thread(g, p);
|
|
- if (who != cred->uid)
|
|
|
|
|
|
+ if (!uid_eq(uid, cred->uid))
|
|
free_uid(user); /* for find_user() */
|
|
free_uid(user); /* for find_user() */
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -553,9 +554,19 @@ void ctrl_alt_del(void)
|
|
*/
|
|
*/
|
|
SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
|
|
SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
|
|
{
|
|
{
|
|
|
|
+ struct user_namespace *ns = current_user_ns();
|
|
const struct cred *old;
|
|
const struct cred *old;
|
|
struct cred *new;
|
|
struct cred *new;
|
|
int retval;
|
|
int retval;
|
|
|
|
+ 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;
|
|
|
|
|
|
new = prepare_creds();
|
|
new = prepare_creds();
|
|
if (!new)
|
|
if (!new)
|
|
@@ -564,25 +575,25 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
|
|
|
|
|
|
retval = -EPERM;
|
|
retval = -EPERM;
|
|
if (rgid != (gid_t) -1) {
|
|
if (rgid != (gid_t) -1) {
|
|
- if (old->gid == rgid ||
|
|
|
|
- old->egid == rgid ||
|
|
|
|
|
|
+ if (gid_eq(old->gid, krgid) ||
|
|
|
|
+ gid_eq(old->egid, krgid) ||
|
|
nsown_capable(CAP_SETGID))
|
|
nsown_capable(CAP_SETGID))
|
|
- new->gid = rgid;
|
|
|
|
|
|
+ new->gid = krgid;
|
|
else
|
|
else
|
|
goto error;
|
|
goto error;
|
|
}
|
|
}
|
|
if (egid != (gid_t) -1) {
|
|
if (egid != (gid_t) -1) {
|
|
- if (old->gid == egid ||
|
|
|
|
- old->egid == egid ||
|
|
|
|
- old->sgid == egid ||
|
|
|
|
|
|
+ if (gid_eq(old->gid, kegid) ||
|
|
|
|
+ gid_eq(old->egid, kegid) ||
|
|
|
|
+ gid_eq(old->sgid, kegid) ||
|
|
nsown_capable(CAP_SETGID))
|
|
nsown_capable(CAP_SETGID))
|
|
- new->egid = egid;
|
|
|
|
|
|
+ new->egid = kegid;
|
|
else
|
|
else
|
|
goto error;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
|
|
if (rgid != (gid_t) -1 ||
|
|
if (rgid != (gid_t) -1 ||
|
|
- (egid != (gid_t) -1 && egid != old->gid))
|
|
|
|
|
|
+ (egid != (gid_t) -1 && !gid_eq(kegid, old->gid)))
|
|
new->sgid = new->egid;
|
|
new->sgid = new->egid;
|
|
new->fsgid = new->egid;
|
|
new->fsgid = new->egid;
|
|
|
|
|
|
@@ -600,9 +611,15 @@ error:
|
|
*/
|
|
*/
|
|
SYSCALL_DEFINE1(setgid, gid_t, gid)
|
|
SYSCALL_DEFINE1(setgid, gid_t, gid)
|
|
{
|
|
{
|
|
|
|
+ struct user_namespace *ns = current_user_ns();
|
|
const struct cred *old;
|
|
const struct cred *old;
|
|
struct cred *new;
|
|
struct cred *new;
|
|
int retval;
|
|
int retval;
|
|
|
|
+ kgid_t kgid;
|
|
|
|
+
|
|
|
|
+ kgid = make_kgid(ns, gid);
|
|
|
|
+ if (!gid_valid(kgid))
|
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
new = prepare_creds();
|
|
new = prepare_creds();
|
|
if (!new)
|
|
if (!new)
|
|
@@ -611,9 +628,9 @@ SYSCALL_DEFINE1(setgid, gid_t, gid)
|
|
|
|
|
|
retval = -EPERM;
|
|
retval = -EPERM;
|
|
if (nsown_capable(CAP_SETGID))
|
|
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;
|
|
|
|
|
|
+ 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;
|
|
else
|
|
else
|
|
goto error;
|
|
goto error;
|
|
|
|
|
|
@@ -631,7 +648,7 @@ static int set_user(struct cred *new)
|
|
{
|
|
{
|
|
struct user_struct *new_user;
|
|
struct user_struct *new_user;
|
|
|
|
|
|
- new_user = alloc_uid(current_user_ns(), new->uid);
|
|
|
|
|
|
+ new_user = alloc_uid(new->uid);
|
|
if (!new_user)
|
|
if (!new_user)
|
|
return -EAGAIN;
|
|
return -EAGAIN;
|
|
|
|
|
|
@@ -670,9 +687,19 @@ static int set_user(struct cred *new)
|
|
*/
|
|
*/
|
|
SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
|
|
SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
|
|
{
|
|
{
|
|
|
|
+ struct user_namespace *ns = current_user_ns();
|
|
const struct cred *old;
|
|
const struct cred *old;
|
|
struct cred *new;
|
|
struct cred *new;
|
|
int retval;
|
|
int retval;
|
|
|
|
+ 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;
|
|
|
|
|
|
new = prepare_creds();
|
|
new = prepare_creds();
|
|
if (!new)
|
|
if (!new)
|
|
@@ -681,29 +708,29 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
|
|
|
|
|
|
retval = -EPERM;
|
|
retval = -EPERM;
|
|
if (ruid != (uid_t) -1) {
|
|
if (ruid != (uid_t) -1) {
|
|
- new->uid = ruid;
|
|
|
|
- if (old->uid != ruid &&
|
|
|
|
- old->euid != ruid &&
|
|
|
|
|
|
+ new->uid = kruid;
|
|
|
|
+ if (!uid_eq(old->uid, kruid) &&
|
|
|
|
+ !uid_eq(old->euid, kruid) &&
|
|
!nsown_capable(CAP_SETUID))
|
|
!nsown_capable(CAP_SETUID))
|
|
goto error;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
|
|
if (euid != (uid_t) -1) {
|
|
if (euid != (uid_t) -1) {
|
|
- new->euid = euid;
|
|
|
|
- if (old->uid != euid &&
|
|
|
|
- old->euid != euid &&
|
|
|
|
- old->suid != euid &&
|
|
|
|
|
|
+ new->euid = keuid;
|
|
|
|
+ if (!uid_eq(old->uid, keuid) &&
|
|
|
|
+ !uid_eq(old->euid, keuid) &&
|
|
|
|
+ !uid_eq(old->suid, keuid) &&
|
|
!nsown_capable(CAP_SETUID))
|
|
!nsown_capable(CAP_SETUID))
|
|
goto error;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
|
|
- if (new->uid != old->uid) {
|
|
|
|
|
|
+ if (!uid_eq(new->uid, old->uid)) {
|
|
retval = set_user(new);
|
|
retval = set_user(new);
|
|
if (retval < 0)
|
|
if (retval < 0)
|
|
goto error;
|
|
goto error;
|
|
}
|
|
}
|
|
if (ruid != (uid_t) -1 ||
|
|
if (ruid != (uid_t) -1 ||
|
|
- (euid != (uid_t) -1 && euid != old->uid))
|
|
|
|
|
|
+ (euid != (uid_t) -1 && !uid_eq(keuid, old->uid)))
|
|
new->suid = new->euid;
|
|
new->suid = new->euid;
|
|
new->fsuid = new->euid;
|
|
new->fsuid = new->euid;
|
|
|
|
|
|
@@ -731,9 +758,15 @@ error:
|
|
*/
|
|
*/
|
|
SYSCALL_DEFINE1(setuid, uid_t, uid)
|
|
SYSCALL_DEFINE1(setuid, uid_t, uid)
|
|
{
|
|
{
|
|
|
|
+ struct user_namespace *ns = current_user_ns();
|
|
const struct cred *old;
|
|
const struct cred *old;
|
|
struct cred *new;
|
|
struct cred *new;
|
|
int retval;
|
|
int retval;
|
|
|
|
+ kuid_t kuid;
|
|
|
|
+
|
|
|
|
+ kuid = make_kuid(ns, uid);
|
|
|
|
+ if (!uid_valid(kuid))
|
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
new = prepare_creds();
|
|
new = prepare_creds();
|
|
if (!new)
|
|
if (!new)
|
|
@@ -742,17 +775,17 @@ SYSCALL_DEFINE1(setuid, uid_t, uid)
|
|
|
|
|
|
retval = -EPERM;
|
|
retval = -EPERM;
|
|
if (nsown_capable(CAP_SETUID)) {
|
|
if (nsown_capable(CAP_SETUID)) {
|
|
- new->suid = new->uid = uid;
|
|
|
|
- if (uid != old->uid) {
|
|
|
|
|
|
+ new->suid = new->uid = kuid;
|
|
|
|
+ if (!uid_eq(kuid, old->uid)) {
|
|
retval = set_user(new);
|
|
retval = set_user(new);
|
|
if (retval < 0)
|
|
if (retval < 0)
|
|
goto error;
|
|
goto error;
|
|
}
|
|
}
|
|
- } else if (uid != old->uid && uid != new->suid) {
|
|
|
|
|
|
+ } else if (!uid_eq(kuid, old->uid) && !uid_eq(kuid, new->suid)) {
|
|
goto error;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
|
|
- new->fsuid = new->euid = uid;
|
|
|
|
|
|
+ new->fsuid = new->euid = kuid;
|
|
|
|
|
|
retval = security_task_fix_setuid(new, old, LSM_SETID_ID);
|
|
retval = security_task_fix_setuid(new, old, LSM_SETID_ID);
|
|
if (retval < 0)
|
|
if (retval < 0)
|
|
@@ -772,9 +805,24 @@ error:
|
|
*/
|
|
*/
|
|
SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
|
|
SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
|
|
{
|
|
{
|
|
|
|
+ struct user_namespace *ns = current_user_ns();
|
|
const struct cred *old;
|
|
const struct cred *old;
|
|
struct cred *new;
|
|
struct cred *new;
|
|
int retval;
|
|
int retval;
|
|
|
|
+ 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;
|
|
|
|
|
|
new = prepare_creds();
|
|
new = prepare_creds();
|
|
if (!new)
|
|
if (!new)
|
|
@@ -784,29 +832,29 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
|
|
|
|
|
|
retval = -EPERM;
|
|
retval = -EPERM;
|
|
if (!nsown_capable(CAP_SETUID)) {
|
|
if (!nsown_capable(CAP_SETUID)) {
|
|
- if (ruid != (uid_t) -1 && ruid != old->uid &&
|
|
|
|
- ruid != old->euid && ruid != old->suid)
|
|
|
|
|
|
+ if (ruid != (uid_t) -1 && !uid_eq(kruid, old->uid) &&
|
|
|
|
+ !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid))
|
|
goto error;
|
|
goto error;
|
|
- if (euid != (uid_t) -1 && euid != old->uid &&
|
|
|
|
- euid != old->euid && euid != old->suid)
|
|
|
|
|
|
+ if (euid != (uid_t) -1 && !uid_eq(keuid, old->uid) &&
|
|
|
|
+ !uid_eq(keuid, old->euid) && !uid_eq(keuid, old->suid))
|
|
goto error;
|
|
goto error;
|
|
- if (suid != (uid_t) -1 && suid != old->uid &&
|
|
|
|
- suid != old->euid && suid != old->suid)
|
|
|
|
|
|
+ if (suid != (uid_t) -1 && !uid_eq(ksuid, old->uid) &&
|
|
|
|
+ !uid_eq(ksuid, old->euid) && !uid_eq(ksuid, old->suid))
|
|
goto error;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
|
|
if (ruid != (uid_t) -1) {
|
|
if (ruid != (uid_t) -1) {
|
|
- new->uid = ruid;
|
|
|
|
- if (ruid != old->uid) {
|
|
|
|
|
|
+ new->uid = kruid;
|
|
|
|
+ if (!uid_eq(kruid, old->uid)) {
|
|
retval = set_user(new);
|
|
retval = set_user(new);
|
|
if (retval < 0)
|
|
if (retval < 0)
|
|
goto error;
|
|
goto error;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (euid != (uid_t) -1)
|
|
if (euid != (uid_t) -1)
|
|
- new->euid = euid;
|
|
|
|
|
|
+ new->euid = keuid;
|
|
if (suid != (uid_t) -1)
|
|
if (suid != (uid_t) -1)
|
|
- new->suid = suid;
|
|
|
|
|
|
+ new->suid = ksuid;
|
|
new->fsuid = new->euid;
|
|
new->fsuid = new->euid;
|
|
|
|
|
|
retval = security_task_fix_setuid(new, old, LSM_SETID_RES);
|
|
retval = security_task_fix_setuid(new, old, LSM_SETID_RES);
|
|
@@ -820,14 +868,19 @@ error:
|
|
return retval;
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
|
|
-SYSCALL_DEFINE3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __user *, suid)
|
|
|
|
|
|
+SYSCALL_DEFINE3(getresuid, uid_t __user *, ruidp, uid_t __user *, euidp, uid_t __user *, suidp)
|
|
{
|
|
{
|
|
const struct cred *cred = current_cred();
|
|
const struct cred *cred = current_cred();
|
|
int retval;
|
|
int retval;
|
|
|
|
+ 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);
|
|
|
|
|
|
- if (!(retval = put_user(cred->uid, ruid)) &&
|
|
|
|
- !(retval = put_user(cred->euid, euid)))
|
|
|
|
- retval = put_user(cred->suid, suid);
|
|
|
|
|
|
+ if (!(retval = put_user(ruid, ruidp)) &&
|
|
|
|
+ !(retval = put_user(euid, euidp)))
|
|
|
|
+ retval = put_user(suid, suidp);
|
|
|
|
|
|
return retval;
|
|
return retval;
|
|
}
|
|
}
|
|
@@ -837,9 +890,22 @@ SYSCALL_DEFINE3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __u
|
|
*/
|
|
*/
|
|
SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
|
|
SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
|
|
{
|
|
{
|
|
|
|
+ struct user_namespace *ns = current_user_ns();
|
|
const struct cred *old;
|
|
const struct cred *old;
|
|
struct cred *new;
|
|
struct cred *new;
|
|
int retval;
|
|
int retval;
|
|
|
|
+ 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;
|
|
|
|
|
|
new = prepare_creds();
|
|
new = prepare_creds();
|
|
if (!new)
|
|
if (!new)
|
|
@@ -848,23 +914,23 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
|
|
|
|
|
|
retval = -EPERM;
|
|
retval = -EPERM;
|
|
if (!nsown_capable(CAP_SETGID)) {
|
|
if (!nsown_capable(CAP_SETGID)) {
|
|
- if (rgid != (gid_t) -1 && rgid != old->gid &&
|
|
|
|
- rgid != old->egid && rgid != old->sgid)
|
|
|
|
|
|
+ if (rgid != (gid_t) -1 && !gid_eq(krgid, old->gid) &&
|
|
|
|
+ !gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid))
|
|
goto error;
|
|
goto error;
|
|
- if (egid != (gid_t) -1 && egid != old->gid &&
|
|
|
|
- egid != old->egid && egid != old->sgid)
|
|
|
|
|
|
+ if (egid != (gid_t) -1 && !gid_eq(kegid, old->gid) &&
|
|
|
|
+ !gid_eq(kegid, old->egid) && !gid_eq(kegid, old->sgid))
|
|
goto error;
|
|
goto error;
|
|
- if (sgid != (gid_t) -1 && sgid != old->gid &&
|
|
|
|
- sgid != old->egid && sgid != old->sgid)
|
|
|
|
|
|
+ if (sgid != (gid_t) -1 && !gid_eq(ksgid, old->gid) &&
|
|
|
|
+ !gid_eq(ksgid, old->egid) && !gid_eq(ksgid, old->sgid))
|
|
goto error;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
|
|
if (rgid != (gid_t) -1)
|
|
if (rgid != (gid_t) -1)
|
|
- new->gid = rgid;
|
|
|
|
|
|
+ new->gid = krgid;
|
|
if (egid != (gid_t) -1)
|
|
if (egid != (gid_t) -1)
|
|
- new->egid = egid;
|
|
|
|
|
|
+ new->egid = kegid;
|
|
if (sgid != (gid_t) -1)
|
|
if (sgid != (gid_t) -1)
|
|
- new->sgid = sgid;
|
|
|
|
|
|
+ new->sgid = ksgid;
|
|
new->fsgid = new->egid;
|
|
new->fsgid = new->egid;
|
|
|
|
|
|
return commit_creds(new);
|
|
return commit_creds(new);
|
|
@@ -874,14 +940,19 @@ error:
|
|
return retval;
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
|
|
-SYSCALL_DEFINE3(getresgid, gid_t __user *, rgid, gid_t __user *, egid, gid_t __user *, sgid)
|
|
|
|
|
|
+SYSCALL_DEFINE3(getresgid, gid_t __user *, rgidp, gid_t __user *, egidp, gid_t __user *, sgidp)
|
|
{
|
|
{
|
|
const struct cred *cred = current_cred();
|
|
const struct cred *cred = current_cred();
|
|
int retval;
|
|
int retval;
|
|
|
|
+ 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);
|
|
|
|
|
|
- if (!(retval = put_user(cred->gid, rgid)) &&
|
|
|
|
- !(retval = put_user(cred->egid, egid)))
|
|
|
|
- retval = put_user(cred->sgid, sgid);
|
|
|
|
|
|
+ if (!(retval = put_user(rgid, rgidp)) &&
|
|
|
|
+ !(retval = put_user(egid, egidp)))
|
|
|
|
+ retval = put_user(sgid, sgidp);
|
|
|
|
|
|
return retval;
|
|
return retval;
|
|
}
|
|
}
|
|
@@ -898,18 +969,24 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid)
|
|
const struct cred *old;
|
|
const struct cred *old;
|
|
struct cred *new;
|
|
struct cred *new;
|
|
uid_t old_fsuid;
|
|
uid_t old_fsuid;
|
|
|
|
+ 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;
|
|
|
|
|
|
new = prepare_creds();
|
|
new = prepare_creds();
|
|
if (!new)
|
|
if (!new)
|
|
- return current_fsuid();
|
|
|
|
- old = current_cred();
|
|
|
|
- old_fsuid = old->fsuid;
|
|
|
|
|
|
+ return old_fsuid;
|
|
|
|
|
|
- if (uid == old->uid || uid == old->euid ||
|
|
|
|
- uid == old->suid || uid == old->fsuid ||
|
|
|
|
|
|
+ if (uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) ||
|
|
|
|
+ uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) ||
|
|
nsown_capable(CAP_SETUID)) {
|
|
nsown_capable(CAP_SETUID)) {
|
|
- if (uid != old_fsuid) {
|
|
|
|
- new->fsuid = uid;
|
|
|
|
|
|
+ if (!uid_eq(kuid, old->fsuid)) {
|
|
|
|
+ new->fsuid = kuid;
|
|
if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
|
|
if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
|
|
goto change_okay;
|
|
goto change_okay;
|
|
}
|
|
}
|
|
@@ -931,18 +1008,24 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid)
|
|
const struct cred *old;
|
|
const struct cred *old;
|
|
struct cred *new;
|
|
struct cred *new;
|
|
gid_t old_fsgid;
|
|
gid_t old_fsgid;
|
|
|
|
+ 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;
|
|
|
|
|
|
new = prepare_creds();
|
|
new = prepare_creds();
|
|
if (!new)
|
|
if (!new)
|
|
- return current_fsgid();
|
|
|
|
- old = current_cred();
|
|
|
|
- old_fsgid = old->fsgid;
|
|
|
|
|
|
+ return old_fsgid;
|
|
|
|
|
|
- if (gid == old->gid || gid == old->egid ||
|
|
|
|
- gid == old->sgid || gid == old->fsgid ||
|
|
|
|
|
|
+ if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->egid) ||
|
|
|
|
+ gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) ||
|
|
nsown_capable(CAP_SETGID)) {
|
|
nsown_capable(CAP_SETGID)) {
|
|
- if (gid != old_fsgid) {
|
|
|
|
- new->fsgid = gid;
|
|
|
|
|
|
+ if (!gid_eq(kgid, old->fsgid)) {
|
|
|
|
+ new->fsgid = kgid;
|
|
goto change_okay;
|
|
goto change_okay;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1498,15 +1581,14 @@ static int check_prlimit_permission(struct task_struct *task)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
tcred = __task_cred(task);
|
|
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))
|
|
|
|
|
|
+ if (uid_eq(cred->uid, tcred->euid) &&
|
|
|
|
+ uid_eq(cred->uid, tcred->suid) &&
|
|
|
|
+ uid_eq(cred->uid, tcred->uid) &&
|
|
|
|
+ gid_eq(cred->gid, tcred->egid) &&
|
|
|
|
+ gid_eq(cred->gid, tcred->sgid) &&
|
|
|
|
+ gid_eq(cred->gid, tcred->gid))
|
|
return 0;
|
|
return 0;
|
|
- if (ns_capable(tcred->user->user_ns, CAP_SYS_RESOURCE))
|
|
|
|
|
|
+ if (ns_capable(tcred->user_ns, CAP_SYS_RESOURCE))
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
return -EPERM;
|
|
return -EPERM;
|