|
@@ -119,17 +119,34 @@ EXPORT_SYMBOL(cad_pid);
|
|
|
|
|
|
void (*pm_power_off_prepare)(void);
|
|
|
|
|
|
+/*
|
|
|
+ * 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);
|
|
|
+
|
|
|
+ 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;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* 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 (pcred->uid != cred->euid &&
|
|
|
- pcred->euid != cred->euid && !capable(CAP_SYS_NICE)) {
|
|
|
+ if (!set_one_prio_perm(p)) {
|
|
|
error = -EPERM;
|
|
|
goto out;
|
|
|
}
|
|
@@ -506,7 +523,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
|
|
|
if (rgid != (gid_t) -1) {
|
|
|
if (old->gid == rgid ||
|
|
|
old->egid == rgid ||
|
|
|
- capable(CAP_SETGID))
|
|
|
+ nsown_capable(CAP_SETGID))
|
|
|
new->gid = rgid;
|
|
|
else
|
|
|
goto error;
|
|
@@ -515,7 +532,7 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
|
|
|
if (old->gid == egid ||
|
|
|
old->egid == egid ||
|
|
|
old->sgid == egid ||
|
|
|
- capable(CAP_SETGID))
|
|
|
+ nsown_capable(CAP_SETGID))
|
|
|
new->egid = egid;
|
|
|
else
|
|
|
goto error;
|
|
@@ -550,7 +567,7 @@ SYSCALL_DEFINE1(setgid, gid_t, gid)
|
|
|
old = current_cred();
|
|
|
|
|
|
retval = -EPERM;
|
|
|
- if (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;
|
|
@@ -617,7 +634,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
|
|
|
new->uid = ruid;
|
|
|
if (old->uid != ruid &&
|
|
|
old->euid != ruid &&
|
|
|
- !capable(CAP_SETUID))
|
|
|
+ !nsown_capable(CAP_SETUID))
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
@@ -626,7 +643,7 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
|
|
|
if (old->uid != euid &&
|
|
|
old->euid != euid &&
|
|
|
old->suid != euid &&
|
|
|
- !capable(CAP_SETUID))
|
|
|
+ !nsown_capable(CAP_SETUID))
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
@@ -674,7 +691,7 @@ SYSCALL_DEFINE1(setuid, uid_t, uid)
|
|
|
old = current_cred();
|
|
|
|
|
|
retval = -EPERM;
|
|
|
- if (capable(CAP_SETUID)) {
|
|
|
+ if (nsown_capable(CAP_SETUID)) {
|
|
|
new->suid = new->uid = uid;
|
|
|
if (uid != old->uid) {
|
|
|
retval = set_user(new);
|
|
@@ -716,7 +733,7 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
|
|
|
old = current_cred();
|
|
|
|
|
|
retval = -EPERM;
|
|
|
- if (!capable(CAP_SETUID)) {
|
|
|
+ if (!nsown_capable(CAP_SETUID)) {
|
|
|
if (ruid != (uid_t) -1 && ruid != old->uid &&
|
|
|
ruid != old->euid && ruid != old->suid)
|
|
|
goto error;
|
|
@@ -780,7 +797,7 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
|
|
|
old = current_cred();
|
|
|
|
|
|
retval = -EPERM;
|
|
|
- if (!capable(CAP_SETGID)) {
|
|
|
+ if (!nsown_capable(CAP_SETGID)) {
|
|
|
if (rgid != (gid_t) -1 && rgid != old->gid &&
|
|
|
rgid != old->egid && rgid != old->sgid)
|
|
|
goto error;
|
|
@@ -840,7 +857,7 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid)
|
|
|
|
|
|
if (uid == old->uid || uid == old->euid ||
|
|
|
uid == old->suid || uid == old->fsuid ||
|
|
|
- capable(CAP_SETUID)) {
|
|
|
+ nsown_capable(CAP_SETUID)) {
|
|
|
if (uid != old_fsuid) {
|
|
|
new->fsuid = uid;
|
|
|
if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
|
|
@@ -873,7 +890,7 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid)
|
|
|
|
|
|
if (gid == old->gid || gid == old->egid ||
|
|
|
gid == old->sgid || gid == old->fsgid ||
|
|
|
- capable(CAP_SETGID)) {
|
|
|
+ nsown_capable(CAP_SETGID)) {
|
|
|
if (gid != old_fsgid) {
|
|
|
new->fsgid = gid;
|
|
|
goto change_okay;
|
|
@@ -1183,6 +1200,7 @@ SYSCALL_DEFINE2(sethostname, char __user *, name, int, 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);
|
|
@@ -1230,7 +1248,7 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len)
|
|
|
int errno;
|
|
|
char tmp[__NEW_UTS_LEN];
|
|
|
|
|
|
- if (!capable(CAP_SYS_ADMIN))
|
|
|
+ if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN))
|
|
|
return -EPERM;
|
|
|
if (len < 0 || len > __NEW_UTS_LEN)
|
|
|
return -EINVAL;
|
|
@@ -1345,6 +1363,8 @@ int do_prlimit(struct task_struct *tsk, unsigned int resource,
|
|
|
rlim = tsk->signal->rlim + resource;
|
|
|
task_lock(tsk->group_leader);
|
|
|
if (new_rlim) {
|
|
|
+ /* Keep the capable check against init_user_ns until
|
|
|
+ cgroups can contain all limits */
|
|
|
if (new_rlim->rlim_max > rlim->rlim_max &&
|
|
|
!capable(CAP_SYS_RESOURCE))
|
|
|
retval = -EPERM;
|
|
@@ -1388,19 +1408,22 @@ static int check_prlimit_permission(struct task_struct *task)
|
|
|
{
|
|
|
const struct cred *cred = current_cred(), *tcred;
|
|
|
|
|
|
- tcred = __task_cred(task);
|
|
|
- if (current != task &&
|
|
|
- (cred->uid != tcred->euid ||
|
|
|
- cred->uid != tcred->suid ||
|
|
|
- cred->uid != tcred->uid ||
|
|
|
- cred->gid != tcred->egid ||
|
|
|
- cred->gid != tcred->sgid ||
|
|
|
- cred->gid != tcred->gid) &&
|
|
|
- !capable(CAP_SYS_RESOURCE)) {
|
|
|
- return -EPERM;
|
|
|
- }
|
|
|
+ if (current == task)
|
|
|
+ return 0;
|
|
|
|
|
|
- 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;
|
|
|
}
|
|
|
|
|
|
SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource,
|