Commit 5b41535aac0c07135ff6a4c5c2ae115d1c20c0bc

Authored by Jiri Slaby
Committed by Jiri Slaby
1 parent 6a1d5e2c85

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>

Showing 2 changed files with 39 additions and 36 deletions Side-by-side Diff

include/linux/resource.h
... ... @@ -80,8 +80,8 @@
80 80 struct task_struct;
81 81  
82 82 int getrusage(struct task_struct *p, int who, struct rusage __user *ru);
83   -int do_setrlimit(struct task_struct *tsk, unsigned int resource,
84   - struct rlimit *new_rlim);
  83 +int do_prlimit(struct task_struct *tsk, unsigned int resource,
  84 + struct rlimit *new_rlim, struct rlimit *old_rlim);
85 85  
86 86 #endif /* __KERNEL__ */
87 87  
... ... @@ -1273,18 +1273,21 @@
1273 1273 #endif
1274 1274  
1275 1275 /* make sure you are allowed to change @tsk limits before calling this */
1276   -int do_setrlimit(struct task_struct *tsk, unsigned int resource,
1277   - struct rlimit *new_rlim)
  1276 +int do_prlimit(struct task_struct *tsk, unsigned int resource,
  1277 + struct rlimit *new_rlim, struct rlimit *old_rlim)
1278 1278 {
1279   - struct rlimit *old_rlim;
  1279 + struct rlimit *rlim;
1280 1280 int retval = 0;
1281 1281  
1282 1282 if (resource >= RLIM_NLIMITS)
1283 1283 return -EINVAL;
1284   - if (new_rlim->rlim_cur > new_rlim->rlim_max)
1285   - return -EINVAL;
1286   - if (resource == RLIMIT_NOFILE && new_rlim->rlim_max > sysctl_nr_open)
1287   - return -EPERM;
  1284 + if (new_rlim) {
  1285 + if (new_rlim->rlim_cur > new_rlim->rlim_max)
  1286 + return -EINVAL;
  1287 + if (resource == RLIMIT_NOFILE &&
  1288 + new_rlim->rlim_max > sysctl_nr_open)
  1289 + return -EPERM;
  1290 + }
1288 1291  
1289 1292 /* protect tsk->signal and tsk->sighand from disappearing */
1290 1293 read_lock(&tasklist_lock);
1291 1294  
1292 1295  
1293 1296  
1294 1297  
... ... @@ -1293,42 +1296,42 @@
1293 1296 goto out;
1294 1297 }
1295 1298  
1296   - old_rlim = tsk->signal->rlim + resource;
  1299 + rlim = tsk->signal->rlim + resource;
1297 1300 task_lock(tsk->group_leader);
1298   - if (new_rlim->rlim_max > old_rlim->rlim_max &&
1299   - !capable(CAP_SYS_RESOURCE))
1300   - retval = -EPERM;
1301   - if (!retval)
1302   - retval = security_task_setrlimit(tsk->group_leader, resource,
1303   - new_rlim);
1304   -
1305   - if (resource == RLIMIT_CPU && new_rlim->rlim_cur == 0) {
1306   - /*
1307   - * The caller is asking for an immediate RLIMIT_CPU
1308   - * expiry. But we use the zero value to mean "it was
1309   - * never set". So let's cheat and make it one second
1310   - * instead
1311   - */
1312   - new_rlim->rlim_cur = 1;
  1301 + if (new_rlim) {
  1302 + if (new_rlim->rlim_max > rlim->rlim_max &&
  1303 + !capable(CAP_SYS_RESOURCE))
  1304 + retval = -EPERM;
  1305 + if (!retval)
  1306 + retval = security_task_setrlimit(tsk->group_leader,
  1307 + resource, new_rlim);
  1308 + if (resource == RLIMIT_CPU && new_rlim->rlim_cur == 0) {
  1309 + /*
  1310 + * The caller is asking for an immediate RLIMIT_CPU
  1311 + * expiry. But we use the zero value to mean "it was
  1312 + * never set". So let's cheat and make it one second
  1313 + * instead
  1314 + */
  1315 + new_rlim->rlim_cur = 1;
  1316 + }
1313 1317 }
1314   -
1315   - if (!retval)
1316   - *old_rlim = *new_rlim;
  1318 + if (!retval) {
  1319 + if (old_rlim)
  1320 + *old_rlim = *rlim;
  1321 + if (new_rlim)
  1322 + *rlim = *new_rlim;
  1323 + }
1317 1324 task_unlock(tsk->group_leader);
1318 1325  
1319   - if (retval || resource != RLIMIT_CPU)
1320   - goto out;
1321   -
1322 1326 /*
1323 1327 * RLIMIT_CPU handling. Note that the kernel fails to return an error
1324 1328 * code if it rejected the user's attempt to set RLIMIT_CPU. This is a
1325 1329 * very long-standing error, and fixing it now risks breakage of
1326 1330 * applications, so we live with it
1327 1331 */
1328   - if (new_rlim->rlim_cur == RLIM_INFINITY)
1329   - goto out;
1330   -
1331   - update_rlimit_cpu(tsk, new_rlim->rlim_cur);
  1332 + if (!retval && new_rlim && resource == RLIMIT_CPU &&
  1333 + new_rlim->rlim_cur != RLIM_INFINITY)
  1334 + update_rlimit_cpu(tsk, new_rlim->rlim_cur);
1332 1335 out:
1333 1336 read_unlock(&tasklist_lock);
1334 1337 return retval;
... ... @@ -1340,7 +1343,7 @@
1340 1343  
1341 1344 if (copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
1342 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 /*