rlimits: split sys_setrlimit
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 <jslaby@suse.cz>
This commit is contained in:
parent
eb2d55a32b
commit
7855c35da7
2 changed files with 26 additions and 16 deletions
|
@ -73,6 +73,8 @@ struct rlimit {
|
||||||
struct task_struct;
|
struct task_struct;
|
||||||
|
|
||||||
int getrusage(struct task_struct *p, int who, struct rusage __user *ru);
|
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__ */
|
#endif /* __KERNEL__ */
|
||||||
|
|
||||||
|
|
40
kernel/sys.c
40
kernel/sys.c
|
@ -1272,42 +1272,41 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
|
||||||
|
|
||||||
#endif
|
#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;
|
int retval;
|
||||||
|
|
||||||
if (resource >= RLIM_NLIMITS)
|
if (resource >= RLIM_NLIMITS)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
|
if (new_rlim->rlim_cur > new_rlim->rlim_max)
|
||||||
return -EFAULT;
|
|
||||||
if (new_rlim.rlim_cur > new_rlim.rlim_max)
|
|
||||||
return -EINVAL;
|
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;
|
return -EPERM;
|
||||||
|
|
||||||
retval = security_task_setrlimit(current, resource, &new_rlim);
|
retval = security_task_setrlimit(tsk->group_leader, resource, new_rlim);
|
||||||
if (retval)
|
if (retval)
|
||||||
return 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
|
* The caller is asking for an immediate RLIMIT_CPU
|
||||||
* expiry. But we use the zero value to mean "it was
|
* expiry. But we use the zero value to mean "it was
|
||||||
* never set". So let's cheat and make it one second
|
* never set". So let's cheat and make it one second
|
||||||
* instead
|
* instead
|
||||||
*/
|
*/
|
||||||
new_rlim.rlim_cur = 1;
|
new_rlim->rlim_cur = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
old_rlim = current->signal->rlim + resource;
|
old_rlim = tsk->signal->rlim + resource;
|
||||||
task_lock(current->group_leader);
|
task_lock(tsk->group_leader);
|
||||||
if (new_rlim.rlim_max > old_rlim->rlim_max &&
|
if (new_rlim->rlim_max > old_rlim->rlim_max &&
|
||||||
!capable(CAP_SYS_RESOURCE))
|
!capable(CAP_SYS_RESOURCE))
|
||||||
retval = -EPERM;
|
retval = -EPERM;
|
||||||
else
|
else
|
||||||
*old_rlim = new_rlim;
|
*old_rlim = *new_rlim;
|
||||||
task_unlock(current->group_leader);
|
task_unlock(tsk->group_leader);
|
||||||
|
|
||||||
if (retval || resource != RLIMIT_CPU)
|
if (retval || resource != RLIMIT_CPU)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -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
|
* very long-standing error, and fixing it now risks breakage of
|
||||||
* applications, so we live with it
|
* applications, so we live with it
|
||||||
*/
|
*/
|
||||||
if (new_rlim.rlim_cur == RLIM_INFINITY)
|
if (new_rlim->rlim_cur == RLIM_INFINITY)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
update_rlimit_cpu(current, new_rlim.rlim_cur);
|
update_rlimit_cpu(tsk, new_rlim->rlim_cur);
|
||||||
out:
|
out:
|
||||||
return retval;
|
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,
|
* It would make sense to put struct rusage in the task_struct,
|
||||||
* except that would make the task_struct be *really big*. After
|
* except that would make the task_struct be *really big*. After
|
||||||
|
|
Loading…
Reference in a new issue