diff options
Diffstat (limited to 'kernel/sys.c')
| -rw-r--r-- | kernel/sys.c | 202 | 
1 files changed, 158 insertions, 44 deletions
| diff --git a/kernel/sys.c b/kernel/sys.c index e83ddbbaf89d..e9ad44489828 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
| @@ -1236,15 +1236,14 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len) | |||
| 1236 | 1236 | ||
| 1237 | SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim) | 1237 | SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim) | 
| 1238 | { | 1238 | { | 
| 1239 | if (resource >= RLIM_NLIMITS) | 1239 | struct rlimit value; | 
| 1240 | return -EINVAL; | 1240 | int ret; | 
| 1241 | else { | 1241 | |
| 1242 | struct rlimit value; | 1242 | ret = do_prlimit(current, resource, NULL, &value); | 
| 1243 | task_lock(current->group_leader); | 1243 | if (!ret) | 
| 1244 | value = current->signal->rlim[resource]; | 1244 | ret = copy_to_user(rlim, &value, sizeof(*rlim)) ? -EFAULT : 0; | 
| 1245 | task_unlock(current->group_leader); | 1245 | |
| 1246 | return copy_to_user(rlim, &value, sizeof(*rlim)) ? -EFAULT : 0; | 1246 | return ret; | 
| 1247 | } | ||
| 1248 | } | 1247 | } | 
| 1249 | 1248 | ||
| 1250 | #ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT | 1249 | #ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT | 
| @@ -1272,44 +1271,89 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource, | |||
| 1272 | 1271 | ||
| 1273 | #endif | 1272 | #endif | 
| 1274 | 1273 | ||
| 1275 | SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim) | 1274 | static inline bool rlim64_is_infinity(__u64 rlim64) | 
| 1276 | { | 1275 | { | 
| 1277 | struct rlimit new_rlim, *old_rlim; | 1276 | #if BITS_PER_LONG < 64 | 
| 1278 | 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; | ||
| 1279 | 1313 | ||
| 1280 | if (resource >= RLIM_NLIMITS) | 1314 | if (resource >= RLIM_NLIMITS) | 
| 1281 | return -EINVAL; | 1315 | return -EINVAL; | 
| 1282 | if (copy_from_user(&new_rlim, rlim, sizeof(*rlim))) | 1316 | if (new_rlim) { | 
| 1283 | return -EFAULT; | 1317 | if (new_rlim->rlim_cur > new_rlim->rlim_max) | 
| 1284 | if (new_rlim.rlim_cur > new_rlim.rlim_max) | 1318 | return -EINVAL; | 
| 1285 | return -EINVAL; | 1319 | if (resource == RLIMIT_NOFILE && | 
| 1286 | old_rlim = current->signal->rlim + resource; | 1320 | new_rlim->rlim_max > sysctl_nr_open) | 
| 1287 | if ((new_rlim.rlim_max > old_rlim->rlim_max) && | 1321 | return -EPERM; | 
| 1288 | !capable(CAP_SYS_RESOURCE)) | ||
| 1289 | return -EPERM; | ||
| 1290 | if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open) | ||
| 1291 | return -EPERM; | ||
| 1292 | |||
| 1293 | retval = security_task_setrlimit(resource, &new_rlim); | ||
| 1294 | if (retval) | ||
| 1295 | return retval; | ||
| 1296 | |||
| 1297 | if (resource == RLIMIT_CPU && new_rlim.rlim_cur == 0) { | ||
| 1298 | /* | ||
| 1299 | * The caller is asking for an immediate RLIMIT_CPU | ||
| 1300 | * expiry. But we use the zero value to mean "it was | ||
| 1301 | * never set". So let's cheat and make it one second | ||
| 1302 | * instead | ||
| 1303 | */ | ||
| 1304 | new_rlim.rlim_cur = 1; | ||
| 1305 | } | 1322 | } | 
| 1306 | 1323 | ||
| 1307 | task_lock(current->group_leader); | 1324 | /* protect tsk->signal and tsk->sighand from disappearing */ | 
| 1308 | *old_rlim = new_rlim; | 1325 | read_lock(&tasklist_lock); | 
| 1309 | task_unlock(current->group_leader); | 1326 | if (!tsk->sighand) { | 
| 1310 | 1327 | retval = -ESRCH; | |
| 1311 | if (resource != RLIMIT_CPU) | ||
| 1312 | 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); | ||
| 1313 | 1357 | ||
| 1314 | /* | 1358 | /* | 
| 1315 | * 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 | 
| @@ -1317,14 +1361,84 @@ SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim) | |||
| 1317 | * very long-standing error, and fixing it now risks breakage of | 1361 | * very long-standing error, and fixing it now risks breakage of | 
| 1318 | * applications, so we live with it | 1362 | * applications, so we live with it | 
| 1319 | */ | 1363 | */ | 
| 1320 | if (new_rlim.rlim_cur == RLIM_INFINITY) | 1364 | if (!retval && new_rlim && resource == RLIMIT_CPU && | 
| 1321 | goto out; | 1365 | new_rlim->rlim_cur != RLIM_INFINITY) | 
| 1322 | 1366 | update_rlimit_cpu(tsk, new_rlim->rlim_cur); | |
| 1323 | update_rlimit_cpu(new_rlim.rlim_cur); | ||
| 1324 | 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 | |||
| 1325 | return 0; | 1388 | return 0; | 
| 1326 | } | 1389 | } | 
| 1327 | 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 | |||
| 1328 | /* | 1442 | /* | 
| 1329 | * 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, | 
| 1330 | * except that would make the task_struct be *really big*. After | 1444 | * except that would make the task_struct be *really big*. After | 
