Skip to content

Commit

Permalink
rlimits: split sys_setrlimit
Browse files Browse the repository at this point in the history
Create do_setrlimit from sys_setrlimit and declare do_setrlimit
in the resource header. This is the first phase to have generic
do_prlimit which allows to be called from read, write and compat
rlimits code.

The new do_setrlimit also accepts a task pointer to change the limits
of. Currently, it cannot be other than current, but this will change
with locking later.

Also pass tsk->group_leader to security_task_setrlimit to check
whether current is allowed to change rlimits of the process and not
its arbitrary thread because it makes more sense given that rlimit are
per process and not per-thread.

Signed-off-by: Jiri Slaby <[email protected]>
  • Loading branch information
jirislaby committed Jul 16, 2010
1 parent eb2d55a commit 7855c35
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 16 deletions.
2 changes: 2 additions & 0 deletions include/linux/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ struct rlimit {
struct task_struct;

int getrusage(struct task_struct *p, int who, struct rusage __user *ru);
int do_setrlimit(struct task_struct *tsk, unsigned int resource,
struct rlimit *new_rlim);

#endif /* __KERNEL__ */

Expand Down
40 changes: 24 additions & 16 deletions kernel/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -1272,42 +1272,41 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,

#endif

SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
int do_setrlimit(struct task_struct *tsk, unsigned int resource,
struct rlimit *new_rlim)
{
struct rlimit new_rlim, *old_rlim;
struct rlimit *old_rlim;
int retval;

if (resource >= RLIM_NLIMITS)
return -EINVAL;
if (copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
return -EFAULT;
if (new_rlim.rlim_cur > new_rlim.rlim_max)
if (new_rlim->rlim_cur > new_rlim->rlim_max)
return -EINVAL;
if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open)
if (resource == RLIMIT_NOFILE && new_rlim->rlim_max > sysctl_nr_open)
return -EPERM;

retval = security_task_setrlimit(current, resource, &new_rlim);
retval = security_task_setrlimit(tsk->group_leader, resource, new_rlim);
if (retval)
return retval;

if (resource == RLIMIT_CPU && new_rlim.rlim_cur == 0) {
if (resource == RLIMIT_CPU && new_rlim->rlim_cur == 0) {
/*
* The caller is asking for an immediate RLIMIT_CPU
* expiry. But we use the zero value to mean "it was
* never set". So let's cheat and make it one second
* instead
*/
new_rlim.rlim_cur = 1;
new_rlim->rlim_cur = 1;
}

old_rlim = current->signal->rlim + resource;
task_lock(current->group_leader);
if (new_rlim.rlim_max > old_rlim->rlim_max &&
old_rlim = tsk->signal->rlim + resource;
task_lock(tsk->group_leader);
if (new_rlim->rlim_max > old_rlim->rlim_max &&
!capable(CAP_SYS_RESOURCE))
retval = -EPERM;
else
*old_rlim = new_rlim;
task_unlock(current->group_leader);
*old_rlim = *new_rlim;
task_unlock(tsk->group_leader);

if (retval || resource != RLIMIT_CPU)
goto out;
Expand All @@ -1318,14 +1317,23 @@ SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
* very long-standing error, and fixing it now risks breakage of
* applications, so we live with it
*/
if (new_rlim.rlim_cur == RLIM_INFINITY)
if (new_rlim->rlim_cur == RLIM_INFINITY)
goto out;

update_rlimit_cpu(current, new_rlim.rlim_cur);
update_rlimit_cpu(tsk, new_rlim->rlim_cur);
out:
return retval;
}

SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
{
struct rlimit new_rlim;

if (copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
return -EFAULT;
return do_setrlimit(current, resource, &new_rlim);
}

/*
* It would make sense to put struct rusage in the task_struct,
* except that would make the task_struct be *really big*. After
Expand Down

0 comments on commit 7855c35

Please sign in to comment.