diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 239 |
1 files changed, 161 insertions, 78 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 7cb426a58965..e9ad44489828 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -492,10 +492,6 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) | |||
492 | return -ENOMEM; | 492 | return -ENOMEM; |
493 | old = current_cred(); | 493 | old = current_cred(); |
494 | 494 | ||
495 | retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); | ||
496 | if (retval) | ||
497 | goto error; | ||
498 | |||
499 | retval = -EPERM; | 495 | retval = -EPERM; |
500 | if (rgid != (gid_t) -1) { | 496 | if (rgid != (gid_t) -1) { |
501 | if (old->gid == rgid || | 497 | if (old->gid == rgid || |
@@ -543,10 +539,6 @@ SYSCALL_DEFINE1(setgid, gid_t, gid) | |||
543 | return -ENOMEM; | 539 | return -ENOMEM; |
544 | old = current_cred(); | 540 | old = current_cred(); |
545 | 541 | ||
546 | retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); | ||
547 | if (retval) | ||
548 | goto error; | ||
549 | |||
550 | retval = -EPERM; | 542 | retval = -EPERM; |
551 | if (capable(CAP_SETGID)) | 543 | if (capable(CAP_SETGID)) |
552 | new->gid = new->egid = new->sgid = new->fsgid = gid; | 544 | new->gid = new->egid = new->sgid = new->fsgid = gid; |
@@ -610,10 +602,6 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) | |||
610 | return -ENOMEM; | 602 | return -ENOMEM; |
611 | old = current_cred(); | 603 | old = current_cred(); |
612 | 604 | ||
613 | retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE); | ||
614 | if (retval) | ||
615 | goto error; | ||
616 | |||
617 | retval = -EPERM; | 605 | retval = -EPERM; |
618 | if (ruid != (uid_t) -1) { | 606 | if (ruid != (uid_t) -1) { |
619 | new->uid = ruid; | 607 | new->uid = ruid; |
@@ -675,10 +663,6 @@ SYSCALL_DEFINE1(setuid, uid_t, uid) | |||
675 | return -ENOMEM; | 663 | return -ENOMEM; |
676 | old = current_cred(); | 664 | old = current_cred(); |
677 | 665 | ||
678 | retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID); | ||
679 | if (retval) | ||
680 | goto error; | ||
681 | |||
682 | retval = -EPERM; | 666 | retval = -EPERM; |
683 | if (capable(CAP_SETUID)) { | 667 | if (capable(CAP_SETUID)) { |
684 | new->suid = new->uid = uid; | 668 | new->suid = new->uid = uid; |
@@ -719,9 +703,6 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) | |||
719 | if (!new) | 703 | if (!new) |
720 | return -ENOMEM; | 704 | return -ENOMEM; |
721 | 705 | ||
722 | retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES); | ||
723 | if (retval) | ||
724 | goto error; | ||
725 | old = current_cred(); | 706 | old = current_cred(); |
726 | 707 | ||
727 | retval = -EPERM; | 708 | retval = -EPERM; |
@@ -788,10 +769,6 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) | |||
788 | return -ENOMEM; | 769 | return -ENOMEM; |
789 | old = current_cred(); | 770 | old = current_cred(); |
790 | 771 | ||
791 | retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES); | ||
792 | if (retval) | ||
793 | goto error; | ||
794 | |||
795 | retval = -EPERM; | 772 | retval = -EPERM; |
796 | if (!capable(CAP_SETGID)) { | 773 | if (!capable(CAP_SETGID)) { |
797 | if (rgid != (gid_t) -1 && rgid != old->gid && | 774 | if (rgid != (gid_t) -1 && rgid != old->gid && |
@@ -851,9 +828,6 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid) | |||
851 | old = current_cred(); | 828 | old = current_cred(); |
852 | old_fsuid = old->fsuid; | 829 | old_fsuid = old->fsuid; |
853 | 830 | ||
854 | if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS) < 0) | ||
855 | goto error; | ||
856 | |||
857 | if (uid == old->uid || uid == old->euid || | 831 | if (uid == old->uid || uid == old->euid || |
858 | uid == old->suid || uid == old->fsuid || | 832 | uid == old->suid || uid == old->fsuid || |
859 | capable(CAP_SETUID)) { | 833 | capable(CAP_SETUID)) { |
@@ -864,7 +838,6 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid) | |||
864 | } | 838 | } |
865 | } | 839 | } |
866 | 840 | ||
867 | error: | ||
868 | abort_creds(new); | 841 | abort_creds(new); |
869 | return old_fsuid; | 842 | return old_fsuid; |
870 | 843 | ||
@@ -888,9 +861,6 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid) | |||
888 | old = current_cred(); | 861 | old = current_cred(); |
889 | old_fsgid = old->fsgid; | 862 | old_fsgid = old->fsgid; |
890 | 863 | ||
891 | if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS)) | ||
892 | goto error; | ||
893 | |||
894 | if (gid == old->gid || gid == old->egid || | 864 | if (gid == old->gid || gid == old->egid || |
895 | gid == old->sgid || gid == old->fsgid || | 865 | gid == old->sgid || gid == old->fsgid || |
896 | capable(CAP_SETGID)) { | 866 | capable(CAP_SETGID)) { |
@@ -900,7 +870,6 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid) | |||
900 | } | 870 | } |
901 | } | 871 | } |
902 | 872 | ||
903 | error: | ||
904 | abort_creds(new); | 873 | abort_creds(new); |
905 | return old_fsgid; | 874 | return old_fsgid; |
906 | 875 | ||
@@ -1267,15 +1236,14 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len) | |||
1267 | 1236 | ||
1268 | SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim) | 1237 | SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim) |
1269 | { | 1238 | { |
1270 | if (resource >= RLIM_NLIMITS) | 1239 | struct rlimit value; |
1271 | return -EINVAL; | 1240 | int ret; |
1272 | else { | 1241 | |
1273 | struct rlimit value; | 1242 | ret = do_prlimit(current, resource, NULL, &value); |
1274 | task_lock(current->group_leader); | 1243 | if (!ret) |
1275 | value = current->signal->rlim[resource]; | 1244 | ret = copy_to_user(rlim, &value, sizeof(*rlim)) ? -EFAULT : 0; |
1276 | task_unlock(current->group_leader); | 1245 | |
1277 | return copy_to_user(rlim, &value, sizeof(*rlim)) ? -EFAULT : 0; | 1246 | return ret; |
1278 | } | ||
1279 | } | 1247 | } |
1280 | 1248 | ||
1281 | #ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT | 1249 | #ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT |
@@ -1303,44 +1271,89 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource, | |||
1303 | 1271 | ||
1304 | #endif | 1272 | #endif |
1305 | 1273 | ||
1306 | SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim) | 1274 | static inline bool rlim64_is_infinity(__u64 rlim64) |
1307 | { | 1275 | { |
1308 | struct rlimit new_rlim, *old_rlim; | 1276 | #if BITS_PER_LONG < 64 |
1309 | int retval; | 1277 | return rlim64 >= ULONG_MAX; |
1278 | #else | ||
1279 | return rlim64 == RLIM64_INFINITY; | ||
1280 | #endif | ||
1281 | } | ||
1282 | |||
1283 | static void rlim_to_rlim64(const struct rlimit *rlim, struct rlimit64 *rlim64) | ||
1284 | { | ||
1285 | if (rlim->rlim_cur == RLIM_INFINITY) | ||
1286 | rlim64->rlim_cur = RLIM64_INFINITY; | ||
1287 | else | ||
1288 | rlim64->rlim_cur = rlim->rlim_cur; | ||
1289 | if (rlim->rlim_max == RLIM_INFINITY) | ||
1290 | rlim64->rlim_max = RLIM64_INFINITY; | ||
1291 | else | ||
1292 | rlim64->rlim_max = rlim->rlim_max; | ||
1293 | } | ||
1294 | |||
1295 | static void rlim64_to_rlim(const struct rlimit64 *rlim64, struct rlimit *rlim) | ||
1296 | { | ||
1297 | if (rlim64_is_infinity(rlim64->rlim_cur)) | ||
1298 | rlim->rlim_cur = RLIM_INFINITY; | ||
1299 | else | ||
1300 | rlim->rlim_cur = (unsigned long)rlim64->rlim_cur; | ||
1301 | if (rlim64_is_infinity(rlim64->rlim_max)) | ||
1302 | rlim->rlim_max = RLIM_INFINITY; | ||
1303 | else | ||
1304 | rlim->rlim_max = (unsigned long)rlim64->rlim_max; | ||
1305 | } | ||
1306 | |||
1307 | /* make sure you are allowed to change @tsk limits before calling this */ | ||
1308 | int do_prlimit(struct task_struct *tsk, unsigned int resource, | ||
1309 | struct rlimit *new_rlim, struct rlimit *old_rlim) | ||
1310 | { | ||
1311 | struct rlimit *rlim; | ||
1312 | int retval = 0; | ||
1310 | 1313 | ||
1311 | if (resource >= RLIM_NLIMITS) | 1314 | if (resource >= RLIM_NLIMITS) |
1312 | return -EINVAL; | 1315 | return -EINVAL; |
1313 | if (copy_from_user(&new_rlim, rlim, sizeof(*rlim))) | 1316 | if (new_rlim) { |
1314 | return -EFAULT; | 1317 | if (new_rlim->rlim_cur > new_rlim->rlim_max) |
1315 | if (new_rlim.rlim_cur > new_rlim.rlim_max) | 1318 | return -EINVAL; |
1316 | return -EINVAL; | 1319 | if (resource == RLIMIT_NOFILE && |
1317 | old_rlim = current->signal->rlim + resource; | 1320 | new_rlim->rlim_max > sysctl_nr_open) |
1318 | if ((new_rlim.rlim_max > old_rlim->rlim_max) && | 1321 | return -EPERM; |
1319 | !capable(CAP_SYS_RESOURCE)) | ||
1320 | return -EPERM; | ||
1321 | if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open) | ||
1322 | return -EPERM; | ||
1323 | |||
1324 | retval = security_task_setrlimit(resource, &new_rlim); | ||
1325 | if (retval) | ||
1326 | return retval; | ||
1327 | |||
1328 | if (resource == RLIMIT_CPU && new_rlim.rlim_cur == 0) { | ||
1329 | /* | ||
1330 | * The caller is asking for an immediate RLIMIT_CPU | ||
1331 | * expiry. But we use the zero value to mean "it was | ||
1332 | * never set". So let's cheat and make it one second | ||
1333 | * instead | ||
1334 | */ | ||
1335 | new_rlim.rlim_cur = 1; | ||
1336 | } | 1322 | } |
1337 | 1323 | ||
1338 | task_lock(current->group_leader); | 1324 | /* protect tsk->signal and tsk->sighand from disappearing */ |
1339 | *old_rlim = new_rlim; | 1325 | read_lock(&tasklist_lock); |
1340 | task_unlock(current->group_leader); | 1326 | if (!tsk->sighand) { |
1341 | 1327 | retval = -ESRCH; | |
1342 | if (resource != RLIMIT_CPU) | ||
1343 | goto out; | 1328 | goto out; |
1329 | } | ||
1330 | |||
1331 | rlim = tsk->signal->rlim + resource; | ||
1332 | task_lock(tsk->group_leader); | ||
1333 | if (new_rlim) { | ||
1334 | if (new_rlim->rlim_max > rlim->rlim_max && | ||
1335 | !capable(CAP_SYS_RESOURCE)) | ||
1336 | retval = -EPERM; | ||
1337 | if (!retval) | ||
1338 | retval = security_task_setrlimit(tsk->group_leader, | ||
1339 | resource, new_rlim); | ||
1340 | if (resource == RLIMIT_CPU && new_rlim->rlim_cur == 0) { | ||
1341 | /* | ||
1342 | * The caller is asking for an immediate RLIMIT_CPU | ||
1343 | * expiry. But we use the zero value to mean "it was | ||
1344 | * never set". So let's cheat and make it one second | ||
1345 | * instead | ||
1346 | */ | ||
1347 | new_rlim->rlim_cur = 1; | ||
1348 | } | ||
1349 | } | ||
1350 | if (!retval) { | ||
1351 | if (old_rlim) | ||
1352 | *old_rlim = *rlim; | ||
1353 | if (new_rlim) | ||
1354 | *rlim = *new_rlim; | ||
1355 | } | ||
1356 | task_unlock(tsk->group_leader); | ||
1344 | 1357 | ||
1345 | /* | 1358 | /* |
1346 | * RLIMIT_CPU handling. Note that the kernel fails to return an error | 1359 | * RLIMIT_CPU handling. Note that the kernel fails to return an error |
@@ -1348,14 +1361,84 @@ SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim) | |||
1348 | * very long-standing error, and fixing it now risks breakage of | 1361 | * very long-standing error, and fixing it now risks breakage of |
1349 | * applications, so we live with it | 1362 | * applications, so we live with it |
1350 | */ | 1363 | */ |
1351 | if (new_rlim.rlim_cur == RLIM_INFINITY) | 1364 | if (!retval && new_rlim && resource == RLIMIT_CPU && |
1352 | goto out; | 1365 | new_rlim->rlim_cur != RLIM_INFINITY) |
1353 | 1366 | update_rlimit_cpu(tsk, new_rlim->rlim_cur); | |
1354 | update_rlimit_cpu(new_rlim.rlim_cur); | ||
1355 | out: | 1367 | out: |
1368 | read_unlock(&tasklist_lock); | ||
1369 | return retval; | ||
1370 | } | ||
1371 | |||
1372 | /* rcu lock must be held */ | ||
1373 | static int check_prlimit_permission(struct task_struct *task) | ||
1374 | { | ||
1375 | const struct cred *cred = current_cred(), *tcred; | ||
1376 | |||
1377 | tcred = __task_cred(task); | ||
1378 | if ((cred->uid != tcred->euid || | ||
1379 | cred->uid != tcred->suid || | ||
1380 | cred->uid != tcred->uid || | ||
1381 | cred->gid != tcred->egid || | ||
1382 | cred->gid != tcred->sgid || | ||
1383 | cred->gid != tcred->gid) && | ||
1384 | !capable(CAP_SYS_RESOURCE)) { | ||
1385 | return -EPERM; | ||
1386 | } | ||
1387 | |||
1356 | return 0; | 1388 | return 0; |
1357 | } | 1389 | } |
1358 | 1390 | ||
1391 | SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, | ||
1392 | const struct rlimit64 __user *, new_rlim, | ||
1393 | struct rlimit64 __user *, old_rlim) | ||
1394 | { | ||
1395 | struct rlimit64 old64, new64; | ||
1396 | struct rlimit old, new; | ||
1397 | struct task_struct *tsk; | ||
1398 | int ret; | ||
1399 | |||
1400 | if (new_rlim) { | ||
1401 | if (copy_from_user(&new64, new_rlim, sizeof(new64))) | ||
1402 | return -EFAULT; | ||
1403 | rlim64_to_rlim(&new64, &new); | ||
1404 | } | ||
1405 | |||
1406 | rcu_read_lock(); | ||
1407 | tsk = pid ? find_task_by_vpid(pid) : current; | ||
1408 | if (!tsk) { | ||
1409 | rcu_read_unlock(); | ||
1410 | return -ESRCH; | ||
1411 | } | ||
1412 | ret = check_prlimit_permission(tsk); | ||
1413 | if (ret) { | ||
1414 | rcu_read_unlock(); | ||
1415 | return ret; | ||
1416 | } | ||
1417 | get_task_struct(tsk); | ||
1418 | rcu_read_unlock(); | ||
1419 | |||
1420 | ret = do_prlimit(tsk, resource, new_rlim ? &new : NULL, | ||
1421 | old_rlim ? &old : NULL); | ||
1422 | |||
1423 | if (!ret && old_rlim) { | ||
1424 | rlim_to_rlim64(&old, &old64); | ||
1425 | if (copy_to_user(old_rlim, &old64, sizeof(old64))) | ||
1426 | ret = -EFAULT; | ||
1427 | } | ||
1428 | |||
1429 | put_task_struct(tsk); | ||
1430 | return ret; | ||
1431 | } | ||
1432 | |||
1433 | SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim) | ||
1434 | { | ||
1435 | struct rlimit new_rlim; | ||
1436 | |||
1437 | if (copy_from_user(&new_rlim, rlim, sizeof(*rlim))) | ||
1438 | return -EFAULT; | ||
1439 | return do_prlimit(current, resource, &new_rlim, NULL); | ||
1440 | } | ||
1441 | |||
1359 | /* | 1442 | /* |
1360 | * It would make sense to put struct rusage in the task_struct, | 1443 | * It would make sense to put struct rusage in the task_struct, |
1361 | * except that would make the task_struct be *really big*. After | 1444 | * except that would make the task_struct be *really big*. After |
@@ -1663,9 +1746,9 @@ SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep, | |||
1663 | 1746 | ||
1664 | char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff"; | 1747 | char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff"; |
1665 | 1748 | ||
1666 | static void argv_cleanup(char **argv, char **envp) | 1749 | static void argv_cleanup(struct subprocess_info *info) |
1667 | { | 1750 | { |
1668 | argv_free(argv); | 1751 | argv_free(info->argv); |
1669 | } | 1752 | } |
1670 | 1753 | ||
1671 | /** | 1754 | /** |
@@ -1699,7 +1782,7 @@ int orderly_poweroff(bool force) | |||
1699 | goto out; | 1782 | goto out; |
1700 | } | 1783 | } |
1701 | 1784 | ||
1702 | call_usermodehelper_setcleanup(info, argv_cleanup); | 1785 | call_usermodehelper_setfns(info, NULL, argv_cleanup, NULL); |
1703 | 1786 | ||
1704 | ret = call_usermodehelper_exec(info, UMH_NO_WAIT); | 1787 | ret = call_usermodehelper_exec(info, UMH_NO_WAIT); |
1705 | 1788 | ||