diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 30 |
1 files changed, 18 insertions, 12 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 7ff6d1b10cec..196c7134bee6 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -1432,25 +1432,26 @@ out: | |||
1432 | } | 1432 | } |
1433 | 1433 | ||
1434 | /* rcu lock must be held */ | 1434 | /* rcu lock must be held */ |
1435 | static int check_prlimit_permission(struct task_struct *task) | 1435 | static int check_prlimit_permission(struct task_struct *task, |
1436 | unsigned int flags) | ||
1436 | { | 1437 | { |
1437 | const struct cred *cred = current_cred(), *tcred; | 1438 | const struct cred *cred = current_cred(), *tcred; |
1439 | bool id_match; | ||
1438 | 1440 | ||
1439 | if (current == task) | 1441 | if (current == task) |
1440 | return 0; | 1442 | return 0; |
1441 | 1443 | ||
1442 | tcred = __task_cred(task); | 1444 | tcred = __task_cred(task); |
1443 | if (uid_eq(cred->uid, tcred->euid) && | 1445 | id_match = (uid_eq(cred->uid, tcred->euid) && |
1444 | uid_eq(cred->uid, tcred->suid) && | 1446 | uid_eq(cred->uid, tcred->suid) && |
1445 | uid_eq(cred->uid, tcred->uid) && | 1447 | uid_eq(cred->uid, tcred->uid) && |
1446 | gid_eq(cred->gid, tcred->egid) && | 1448 | gid_eq(cred->gid, tcred->egid) && |
1447 | gid_eq(cred->gid, tcred->sgid) && | 1449 | gid_eq(cred->gid, tcred->sgid) && |
1448 | gid_eq(cred->gid, tcred->gid)) | 1450 | gid_eq(cred->gid, tcred->gid)); |
1449 | return 0; | 1451 | if (!id_match && !ns_capable(tcred->user_ns, CAP_SYS_RESOURCE)) |
1450 | if (ns_capable(tcred->user_ns, CAP_SYS_RESOURCE)) | 1452 | return -EPERM; |
1451 | return 0; | ||
1452 | 1453 | ||
1453 | return -EPERM; | 1454 | return security_task_prlimit(cred, tcred, flags); |
1454 | } | 1455 | } |
1455 | 1456 | ||
1456 | SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, | 1457 | SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, |
@@ -1460,12 +1461,17 @@ SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, | |||
1460 | struct rlimit64 old64, new64; | 1461 | struct rlimit64 old64, new64; |
1461 | struct rlimit old, new; | 1462 | struct rlimit old, new; |
1462 | struct task_struct *tsk; | 1463 | struct task_struct *tsk; |
1464 | unsigned int checkflags = 0; | ||
1463 | int ret; | 1465 | int ret; |
1464 | 1466 | ||
1467 | if (old_rlim) | ||
1468 | checkflags |= LSM_PRLIMIT_READ; | ||
1469 | |||
1465 | if (new_rlim) { | 1470 | if (new_rlim) { |
1466 | if (copy_from_user(&new64, new_rlim, sizeof(new64))) | 1471 | if (copy_from_user(&new64, new_rlim, sizeof(new64))) |
1467 | return -EFAULT; | 1472 | return -EFAULT; |
1468 | rlim64_to_rlim(&new64, &new); | 1473 | rlim64_to_rlim(&new64, &new); |
1474 | checkflags |= LSM_PRLIMIT_WRITE; | ||
1469 | } | 1475 | } |
1470 | 1476 | ||
1471 | rcu_read_lock(); | 1477 | rcu_read_lock(); |
@@ -1474,7 +1480,7 @@ SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, | |||
1474 | rcu_read_unlock(); | 1480 | rcu_read_unlock(); |
1475 | return -ESRCH; | 1481 | return -ESRCH; |
1476 | } | 1482 | } |
1477 | ret = check_prlimit_permission(tsk); | 1483 | ret = check_prlimit_permission(tsk, checkflags); |
1478 | if (ret) { | 1484 | if (ret) { |
1479 | rcu_read_unlock(); | 1485 | rcu_read_unlock(); |
1480 | return ret; | 1486 | return ret; |