aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Slaby <jslaby@suse.cz>2010-03-24 11:11:29 -0400
committerJiri Slaby <jirislaby@gmail.com>2010-07-16 03:48:48 -0400
commit5b41535aac0c07135ff6a4c5c2ae115d1c20c0bc (patch)
treef8db7ec9e07d33aa2af061b49895a0baebafd4cc
parent6a1d5e2c85d06da35cdfd93f1a27675bfdc3ad8c (diff)
rlimits: redo do_setrlimit to more generic do_prlimit
It now allows also reading of limits. I.e. all read and writes will later use this function. It takes two parameters, new and old limits which can be both NULL. If new is non-NULL, the value in it is set to rlimits. If old is non-NULL, current rlimits are stored there. If both are non-NULL, old are stored prior to setting the new ones, atomically. (Similar to sigaction.) Signed-off-by: Jiri Slaby <jslaby@suse.cz>
-rw-r--r--include/linux/resource.h4
-rw-r--r--kernel/sys.c71
2 files changed, 39 insertions, 36 deletions
diff --git a/include/linux/resource.h b/include/linux/resource.h
index 037aa7e6335d..88d36f9145ba 100644
--- a/include/linux/resource.h
+++ b/include/linux/resource.h
@@ -80,8 +80,8 @@ struct rlimit64 {
80struct task_struct; 80struct task_struct;
81 81
82int getrusage(struct task_struct *p, int who, struct rusage __user *ru); 82int getrusage(struct task_struct *p, int who, struct rusage __user *ru);
83int do_setrlimit(struct task_struct *tsk, unsigned int resource, 83int do_prlimit(struct task_struct *tsk, unsigned int resource,
84 struct rlimit *new_rlim); 84 struct rlimit *new_rlim, struct rlimit *old_rlim);
85 85
86#endif /* __KERNEL__ */ 86#endif /* __KERNEL__ */
87 87
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 */
1276int do_setrlimit(struct task_struct *tsk, unsigned int resource, 1276int 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);
1332out: 1335out:
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/*