diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/sys.c | 71 |
1 files changed, 37 insertions, 34 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index c762eebdebf7..bc7d1be0960e 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -1273,18 +1273,21 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource, | |||
1273 | #endif | 1273 | #endif |
1274 | 1274 | ||
1275 | /* make sure you are allowed to change @tsk limits before calling this */ | 1275 | /* make sure you are allowed to change @tsk limits before calling this */ |
1276 | int do_setrlimit(struct task_struct *tsk, unsigned int resource, | 1276 | int do_prlimit(struct task_struct *tsk, unsigned int resource, |
1277 | struct rlimit *new_rlim) | 1277 | struct rlimit *new_rlim, struct rlimit *old_rlim) |
1278 | { | 1278 | { |
1279 | struct rlimit *old_rlim; | 1279 | struct rlimit *rlim; |
1280 | int retval = 0; | 1280 | int retval = 0; |
1281 | 1281 | ||
1282 | if (resource >= RLIM_NLIMITS) | 1282 | if (resource >= RLIM_NLIMITS) |
1283 | return -EINVAL; | 1283 | return -EINVAL; |
1284 | if (new_rlim->rlim_cur > new_rlim->rlim_max) | 1284 | if (new_rlim) { |
1285 | return -EINVAL; | 1285 | if (new_rlim->rlim_cur > new_rlim->rlim_max) |
1286 | if (resource == RLIMIT_NOFILE && new_rlim->rlim_max > sysctl_nr_open) | 1286 | return -EINVAL; |
1287 | return -EPERM; | 1287 | if (resource == RLIMIT_NOFILE && |
1288 | new_rlim->rlim_max > sysctl_nr_open) | ||
1289 | return -EPERM; | ||
1290 | } | ||
1288 | 1291 | ||
1289 | /* protect tsk->signal and tsk->sighand from disappearing */ | 1292 | /* protect tsk->signal and tsk->sighand from disappearing */ |
1290 | read_lock(&tasklist_lock); | 1293 | read_lock(&tasklist_lock); |
@@ -1293,42 +1296,42 @@ int do_setrlimit(struct task_struct *tsk, unsigned int resource, | |||
1293 | goto out; | 1296 | goto out; |
1294 | } | 1297 | } |
1295 | 1298 | ||
1296 | old_rlim = tsk->signal->rlim + resource; | 1299 | rlim = tsk->signal->rlim + resource; |
1297 | task_lock(tsk->group_leader); | 1300 | task_lock(tsk->group_leader); |
1298 | if (new_rlim->rlim_max > old_rlim->rlim_max && | 1301 | if (new_rlim) { |
1299 | !capable(CAP_SYS_RESOURCE)) | 1302 | if (new_rlim->rlim_max > rlim->rlim_max && |
1300 | retval = -EPERM; | 1303 | !capable(CAP_SYS_RESOURCE)) |
1301 | if (!retval) | 1304 | retval = -EPERM; |
1302 | retval = security_task_setrlimit(tsk->group_leader, resource, | 1305 | if (!retval) |
1303 | new_rlim); | 1306 | retval = security_task_setrlimit(tsk->group_leader, |
1304 | 1307 | resource, new_rlim); | |
1305 | if (resource == RLIMIT_CPU && new_rlim->rlim_cur == 0) { | 1308 | if (resource == RLIMIT_CPU && new_rlim->rlim_cur == 0) { |
1306 | /* | 1309 | /* |
1307 | * The caller is asking for an immediate RLIMIT_CPU | 1310 | * The caller is asking for an immediate RLIMIT_CPU |
1308 | * expiry. But we use the zero value to mean "it was | 1311 | * expiry. But we use the zero value to mean "it was |
1309 | * never set". So let's cheat and make it one second | 1312 | * never set". So let's cheat and make it one second |
1310 | * instead | 1313 | * instead |
1311 | */ | 1314 | */ |
1312 | new_rlim->rlim_cur = 1; | 1315 | new_rlim->rlim_cur = 1; |
1316 | } | ||
1317 | } | ||
1318 | if (!retval) { | ||
1319 | if (old_rlim) | ||
1320 | *old_rlim = *rlim; | ||
1321 | if (new_rlim) | ||
1322 | *rlim = *new_rlim; | ||
1313 | } | 1323 | } |
1314 | |||
1315 | if (!retval) | ||
1316 | *old_rlim = *new_rlim; | ||
1317 | task_unlock(tsk->group_leader); | 1324 | task_unlock(tsk->group_leader); |
1318 | 1325 | ||
1319 | if (retval || resource != RLIMIT_CPU) | ||
1320 | goto out; | ||
1321 | |||
1322 | /* | 1326 | /* |
1323 | * RLIMIT_CPU handling. Note that the kernel fails to return an error | 1327 | * RLIMIT_CPU handling. Note that the kernel fails to return an error |
1324 | * code if it rejected the user's attempt to set RLIMIT_CPU. This is a | 1328 | * code if it rejected the user's attempt to set RLIMIT_CPU. This is a |
1325 | * very long-standing error, and fixing it now risks breakage of | 1329 | * very long-standing error, and fixing it now risks breakage of |
1326 | * applications, so we live with it | 1330 | * applications, so we live with it |
1327 | */ | 1331 | */ |
1328 | if (new_rlim->rlim_cur == RLIM_INFINITY) | 1332 | if (!retval && new_rlim && resource == RLIMIT_CPU && |
1329 | goto out; | 1333 | new_rlim->rlim_cur != RLIM_INFINITY) |
1330 | 1334 | update_rlimit_cpu(tsk, new_rlim->rlim_cur); | |
1331 | update_rlimit_cpu(tsk, new_rlim->rlim_cur); | ||
1332 | out: | 1335 | out: |
1333 | read_unlock(&tasklist_lock); | 1336 | read_unlock(&tasklist_lock); |
1334 | return retval; | 1337 | return retval; |
@@ -1340,7 +1343,7 @@ SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim) | |||
1340 | 1343 | ||
1341 | if (copy_from_user(&new_rlim, rlim, sizeof(*rlim))) | 1344 | if (copy_from_user(&new_rlim, rlim, sizeof(*rlim))) |
1342 | return -EFAULT; | 1345 | return -EFAULT; |
1343 | return do_setrlimit(current, resource, &new_rlim); | 1346 | return do_prlimit(current, resource, &new_rlim, NULL); |
1344 | } | 1347 | } |
1345 | 1348 | ||
1346 | /* | 1349 | /* |