2009-11-27 23:09:22

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 01/27] SECURITY: selinux, fix update_rlimit_cpu parameter

From: Jiri Slaby <[email protected]>

Don't pass rlim_cur member of RLIM_NLIMITS-1=RLIMIT_RTTIME limit
to update_rlimit_cpu() in selinux_bprm_committing_creds.

Use proper rlim[RLIMIT_CPU].rlim_cur instead.

Signed-off-by: Jiri Slaby <[email protected]>
Acked-by: James Morris <[email protected]>
Cc: Stephen Smalley <[email protected]>
Cc: Eric Paris <[email protected]>
Cc: David Howells <[email protected]>
---
security/selinux/hooks.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index bb230d5..36d9e25 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2366,7 +2366,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
initrlim = init_task.signal->rlim + i;
rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
}
- update_rlimit_cpu(rlim->rlim_cur);
+ update_rlimit_cpu(current->signal->rlim[RLIMIT_CPU].rlim_cur);
}
}

--
1.6.5.3


2009-11-27 23:06:12

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 02/27] SECURITY: add task_struct to setrlimit

From: Jiri Slaby <[email protected]>

Add task_struct to task_setrlimit of security_operations to be able to set
rlimit of different task than current.

Signed-off-by: Jiri Slaby <[email protected]>
Acked-by: Eric Paris <[email protected]>
Acked-by: James Morris <[email protected]>
---
include/linux/security.h | 9 ++++++---
kernel/sys.c | 2 +-
security/capability.c | 3 ++-
security/security.c | 5 +++--
security/selinux/hooks.c | 7 ++++---
5 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index 239e40d..193b3d9 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1570,7 +1570,8 @@ struct security_operations {
int (*task_setnice) (struct task_struct *p, int nice);
int (*task_setioprio) (struct task_struct *p, int ioprio);
int (*task_getioprio) (struct task_struct *p);
- int (*task_setrlimit) (unsigned int resource, struct rlimit *new_rlim);
+ int (*task_setrlimit) (struct task_struct *p, unsigned int resource,
+ struct rlimit *new_rlim);
int (*task_setscheduler) (struct task_struct *p, int policy,
struct sched_param *lp);
int (*task_getscheduler) (struct task_struct *p);
@@ -1835,7 +1836,8 @@ int security_task_setgroups(struct group_info *group_info);
int security_task_setnice(struct task_struct *p, int nice);
int security_task_setioprio(struct task_struct *p, int ioprio);
int security_task_getioprio(struct task_struct *p);
-int security_task_setrlimit(unsigned int resource, struct rlimit *new_rlim);
+int security_task_setrlimit(struct task_struct *p, unsigned int resource,
+ struct rlimit *new_rlim);
int security_task_setscheduler(struct task_struct *p,
int policy, struct sched_param *lp);
int security_task_getscheduler(struct task_struct *p);
@@ -2451,7 +2453,8 @@ static inline int security_task_getioprio(struct task_struct *p)
return 0;
}

-static inline int security_task_setrlimit(unsigned int resource,
+static inline int security_task_setrlimit(struct task_struct *p,
+ unsigned int resource,
struct rlimit *new_rlim)
{
return 0;
diff --git a/kernel/sys.c b/kernel/sys.c
index ce17760..9898a8a 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1256,7 +1256,7 @@ SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open)
return -EPERM;

- retval = security_task_setrlimit(resource, &new_rlim);
+ retval = security_task_setrlimit(current, resource, &new_rlim);
if (retval)
return retval;

diff --git a/security/capability.c b/security/capability.c
index fce07a7..5882ec0 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -450,7 +450,8 @@ static int cap_task_getioprio(struct task_struct *p)
return 0;
}

-static int cap_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
+static int cap_task_setrlimit(struct task_struct *p, unsigned int resource,
+ struct rlimit *new_rlim)
{
return 0;
}
diff --git a/security/security.c b/security/security.c
index c4c6732..4b23d83 100644
--- a/security/security.c
+++ b/security/security.c
@@ -781,9 +781,10 @@ int security_task_getioprio(struct task_struct *p)
return security_ops->task_getioprio(p);
}

-int security_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
+int security_task_setrlimit(struct task_struct *p, unsigned int resource,
+ struct rlimit *new_rlim)
{
- return security_ops->task_setrlimit(resource, new_rlim);
+ return security_ops->task_setrlimit(p, resource, new_rlim);
}

int security_task_setscheduler(struct task_struct *p,
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 36d9e25..1167f01 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3390,16 +3390,17 @@ static int selinux_task_getioprio(struct task_struct *p)
return current_has_perm(p, PROCESS__GETSCHED);
}

-static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
+static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
+ struct rlimit *new_rlim)
{
- struct rlimit *old_rlim = current->signal->rlim + resource;
+ struct rlimit *old_rlim = p->signal->rlim + resource;

/* Control the ability to change the hard limit (whether
lowering or raising it), so that the hard limit can
later be used as a safe reset point for the soft limit
upon context transitions. See selinux_bprm_committing_creds. */
if (old_rlim->rlim_max != new_rlim->rlim_max)
- return current_has_perm(current, PROCESS__SETRLIMIT);
+ return current_has_perm(p, PROCESS__SETRLIMIT);

return 0;
}
--
1.6.5.3

2009-11-27 23:06:08

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 03/27] core: add task_struct to update_rlimit_cpu

From: Jiri Slaby <[email protected]>

Add task_struct as a parameter to update_rlimit_cpu to be able to set
rlimit_cpu of different task than current.

Signed-off-by: Jiri Slaby <[email protected]>
Acked-by: James Morris <[email protected]>
---
include/linux/posix-timers.h | 2 +-
kernel/posix-cpu-timers.c | 10 +++++-----
kernel/sys.c | 2 +-
security/selinux/hooks.c | 3 ++-
4 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h
index 4f71bf4..3e23844 100644
--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -117,6 +117,6 @@ void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx,

long clock_nanosleep_restart(struct restart_block *restart_block);

-void update_rlimit_cpu(unsigned long rlim_new);
+void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new);

#endif
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index 5c9dc22..102c345 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -13,16 +13,16 @@
/*
* Called after updating RLIMIT_CPU to set timer expiration if necessary.
*/
-void update_rlimit_cpu(unsigned long rlim_new)
+void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new)
{
cputime_t cputime = secs_to_cputime(rlim_new);
- struct signal_struct *const sig = current->signal;
+ struct signal_struct *const sig = task->signal;

if (cputime_eq(sig->it[CPUCLOCK_PROF].expires, cputime_zero) ||
cputime_gt(sig->it[CPUCLOCK_PROF].expires, cputime)) {
- spin_lock_irq(&current->sighand->siglock);
- set_process_cpu_timer(current, CPUCLOCK_PROF, &cputime, NULL);
- spin_unlock_irq(&current->sighand->siglock);
+ spin_lock_irq(&task->sighand->siglock);
+ set_process_cpu_timer(task, CPUCLOCK_PROF, &cputime, NULL);
+ spin_unlock_irq(&task->sighand->siglock);
}
}

diff --git a/kernel/sys.c b/kernel/sys.c
index 9898a8a..71e4eb1 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1286,7 +1286,7 @@ SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
if (new_rlim.rlim_cur == RLIM_INFINITY)
goto out;

- update_rlimit_cpu(new_rlim.rlim_cur);
+ update_rlimit_cpu(current, new_rlim.rlim_cur);
out:
return 0;
}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 1167f01..dac6c88 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2366,7 +2366,8 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
initrlim = init_task.signal->rlim + i;
rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
}
- update_rlimit_cpu(current->signal->rlim[RLIMIT_CPU].rlim_cur);
+ update_rlimit_cpu(current,
+ current->signal->rlim[RLIMIT_CPU].rlim_cur);
}
}

--
1.6.5.3

2009-11-27 23:06:06

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 04/27] sys_setrlimit: make sure ->rlim_max never grows

From: Oleg Nesterov <[email protected]>

Mostly preparation for Jiri's changes, but probably makes sense anyway.

sys_setrlimit() checks new_rlim.rlim_max <= old_rlim->rlim_max, but when
it takes task_lock() old_rlim->rlim_max can be already lowered. Move this
check under task_lock().

Currently this is not important, we can only race with our sub-thread,
this means the application is stupid. But when we change the code to allow
the update of !current task's limits, it becomes important to make sure
->rlim_max can be lowered "reliably" even if we race with the application
doing sys_setrlimit().

Signed-off-by: Oleg Nesterov <[email protected]>
Signed-off-by: Jiri Slaby <[email protected]>
---
kernel/sys.c | 15 ++++++++-------
1 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/kernel/sys.c b/kernel/sys.c
index 71e4eb1..4377cb3 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1249,10 +1249,6 @@ SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
return -EFAULT;
if (new_rlim.rlim_cur > new_rlim.rlim_max)
return -EINVAL;
- old_rlim = current->signal->rlim + resource;
- if ((new_rlim.rlim_max > old_rlim->rlim_max) &&
- !capable(CAP_SYS_RESOURCE))
- return -EPERM;
if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open)
return -EPERM;

@@ -1270,11 +1266,16 @@ SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
new_rlim.rlim_cur = 1;
}

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

- if (resource != RLIMIT_CPU)
+ if (retval || resource != RLIMIT_CPU)
goto out;

/*
@@ -1288,7 +1289,7 @@ SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)

update_rlimit_cpu(current, new_rlim.rlim_cur);
out:
- return 0;
+ return retval;
}

/*
--
1.6.5.3

2009-11-27 23:07:40

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 05/27] core: split sys_setrlimit

From: Jiri Slaby <[email protected]>

Create setrlimit from sys_setrlimit and declare setrlimit in
the resource header. This is to allow rlimits to be changed not
only by syscall, but later from proc code too.

Signed-off-by: Jiri Slaby <[email protected]>
---
include/linux/resource.h | 2 ++
kernel/sys.c | 44 ++++++++++++++++++++++++++------------------
2 files changed, 28 insertions(+), 18 deletions(-)

diff --git a/include/linux/resource.h b/include/linux/resource.h
index 40fc7e6..4301d67 100644
--- a/include/linux/resource.h
+++ b/include/linux/resource.h
@@ -71,5 +71,7 @@ struct rlimit {
#include <asm/resource.h>

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

#endif
diff --git a/kernel/sys.c b/kernel/sys.c
index 4377cb3..398f9e1 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1238,42 +1238,39 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,

#endif

-SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
+int 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, 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))
- *old_rlim = new_rlim;
+ *old_rlim = *new_rlim;
else
retval = -EPERM;
- task_unlock(current->group_leader);
+ task_unlock(tsk->group_leader);

if (retval || resource != RLIMIT_CPU)
goto out;
@@ -1284,14 +1281,25 @@ 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 (resource >= RLIM_NLIMITS)
+ return -EINVAL;
+ if (copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
+ return -EFAULT;
+ return 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
--
1.6.5.3

2009-11-27 23:06:56

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 06/27] core: allow setrlimit to non-current tasks

From: Jiri Slaby <[email protected]>

Add locking to allow setrlimit accept task parameter other than
current.

Namely, lock tasklist_lock for read and check whether the task
structure has sighand non-null. Do all the signal processing under
that lock still held.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: Oleg Nesterov <[email protected]>
---
kernel/sys.c | 11 ++++++++++-
1 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/kernel/sys.c b/kernel/sys.c
index 398f9e1..3082eaf 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1238,6 +1238,7 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,

#endif

+/* make sure you are allowed to change @tsk limits before calling this */
int setrlimit(struct task_struct *tsk, unsigned int resource,
struct rlimit *new_rlim)
{
@@ -1249,9 +1250,16 @@ int setrlimit(struct task_struct *tsk, unsigned int resource,
if (resource == RLIMIT_NOFILE && new_rlim->rlim_max > sysctl_nr_open)
return -EPERM;

+ /* protect tsk->signal and tsk->sighand from disappearing */
+ read_lock(&tasklist_lock);
+ if (!tsk->sighand) {
+ retval = -ESRCH;
+ goto out;
+ }
+
retval = security_task_setrlimit(tsk, resource, new_rlim);
if (retval)
- return retval;
+ goto out;

if (resource == RLIMIT_CPU && new_rlim->rlim_cur == 0) {
/*
@@ -1286,6 +1294,7 @@ int setrlimit(struct task_struct *tsk, unsigned int resource,

update_rlimit_cpu(tsk, new_rlim->rlim_cur);
out:
+ read_unlock(&tasklist_lock);
return retval;
}

--
1.6.5.3

2009-11-27 23:06:13

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 07/27] core: optimize setrlimit for current task

From: Jiri Slaby <[email protected]>

Don't take tasklist lock for 'current'. It's not needed, since
current->sighand/signal can't disappear.

This improves serlimit called especially via sys_setrlimit.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: Oleg Nesterov <[email protected]>
---
kernel/sys.c | 16 ++++++++++------
1 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/kernel/sys.c b/kernel/sys.c
index 3082eaf..605ab9c 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1250,11 +1250,14 @@ int setrlimit(struct task_struct *tsk, unsigned int resource,
if (resource == RLIMIT_NOFILE && new_rlim->rlim_max > sysctl_nr_open)
return -EPERM;

- /* protect tsk->signal and tsk->sighand from disappearing */
- read_lock(&tasklist_lock);
- if (!tsk->sighand) {
- retval = -ESRCH;
- goto out;
+ /* optimization: 'current' doesn't need locking, e.g. setrlimit */
+ if (tsk != current) {
+ /* protect tsk->signal and tsk->sighand from disappearing */
+ read_lock(&tasklist_lock);
+ if (!tsk->sighand) {
+ retval = -ESRCH;
+ goto out;
+ }
}

retval = security_task_setrlimit(tsk, resource, new_rlim);
@@ -1294,7 +1297,8 @@ int setrlimit(struct task_struct *tsk, unsigned int resource,

update_rlimit_cpu(tsk, new_rlim->rlim_cur);
out:
- read_unlock(&tasklist_lock);
+ if (tsk != current)
+ read_unlock(&tasklist_lock);
return retval;
}

--
1.6.5.3

2009-11-27 23:11:30

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 08/27] FS: proc, switch limits reading to fops

From: Jiri Slaby <[email protected]>

Use fops instead of proc_info_read. We will need fops for limits
writing and the code would look ugly if we used
NOD("limits", S_IFREG|S_IRUSR|S_IWUSR, NULL,
&proc_pid_limits_operations, { .proc_read = proc_pid_limits }),

We will just use
REG("limits", S_IRUSR|S_IWUSR, proc_pid_limits_operations),

Signed-off-by: Jiri Slaby <[email protected]>
---
fs/proc/base.c | 37 ++++++++++++++++++++++++++++---------
1 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index af643b5..be4733c 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -477,19 +477,30 @@ static const struct limit_names lnames[RLIM_NLIMITS] = {
};

/* Display limits for a process */
-static int proc_pid_limits(struct task_struct *task, char *buffer)
+static ssize_t limits_read(struct file *file, char __user *buf, size_t rcount,
+ loff_t *ppos)
{
- unsigned int i;
- int count = 0;
- unsigned long flags;
- char *bufptr = buffer;
-
struct rlimit rlim[RLIM_NLIMITS];
+ struct task_struct *task;
+ unsigned long flags;
+ unsigned int i;
+ ssize_t count = 0;
+ char *bufptr;

- if (!lock_task_sighand(task, &flags))
+ task = get_proc_task(file->f_path.dentry->d_inode);
+ if (!task)
+ return -ESRCH;
+ if (!lock_task_sighand(task, &flags)) {
+ put_task_struct(task);
return 0;
+ }
memcpy(rlim, task->signal->rlim, sizeof(struct rlimit) * RLIM_NLIMITS);
unlock_task_sighand(task, &flags);
+ put_task_struct(task);
+
+ bufptr = (char *)__get_free_page(GFP_TEMPORARY);
+ if (!bufptr)
+ return -ENOMEM;

/*
* print the file header
@@ -518,9 +529,17 @@ static int proc_pid_limits(struct task_struct *task, char *buffer)
count += sprintf(&bufptr[count], "\n");
}

+ count = simple_read_from_buffer(buf, rcount, ppos, bufptr, count);
+
+ free_page((unsigned long)bufptr);
+
return count;
}

+static const struct file_operations proc_pid_limits_operations = {
+ .read = limits_read,
+};
+
#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
static int proc_pid_syscall(struct task_struct *task, char *buffer)
{
@@ -2500,7 +2519,7 @@ static const struct pid_entry tgid_base_stuff[] = {
INF("auxv", S_IRUSR, proc_pid_auxv),
ONE("status", S_IRUGO, proc_pid_status),
ONE("personality", S_IRUSR, proc_pid_personality),
- INF("limits", S_IRUSR, proc_pid_limits),
+ REG("limits", S_IRUSR, proc_pid_limits_operations),
#ifdef CONFIG_SCHED_DEBUG
REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations),
#endif
@@ -2834,7 +2853,7 @@ static const struct pid_entry tid_base_stuff[] = {
INF("auxv", S_IRUSR, proc_pid_auxv),
ONE("status", S_IRUGO, proc_pid_status),
ONE("personality", S_IRUSR, proc_pid_personality),
- INF("limits", S_IRUSR, proc_pid_limits),
+ REG("limits", S_IRUSR, proc_pid_limits_operations),
#ifdef CONFIG_SCHED_DEBUG
REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations),
#endif
--
1.6.5.3

2009-11-27 23:11:12

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 09/27] FS: proc, make limits writable

From: Jiri Slaby <[email protected]>

Allow writing strings such as
Max core file size=0:unlimited
to /proc/<pid>/limits to change limits.

Signed-off-by: Jiri Slaby <[email protected]>
---
fs/proc/base.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index be4733c..78c0367 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -536,8 +536,72 @@ static ssize_t limits_read(struct file *file, char __user *buf, size_t rcount,
return count;
}

+static ssize_t limits_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
+ char str[32 + 1 + 16 + 1 + 16 + 1], *delim, *next;
+ struct rlimit new_rlimit;
+ unsigned int i;
+ int ret;
+
+ if (!task) {
+ count = -ESRCH;
+ goto out;
+ }
+ if (copy_from_user(str, buf, min(count, sizeof(str) - 1))) {
+ count = -EFAULT;
+ goto put_task;
+ }
+
+ str[min(count, sizeof(str) - 1)] = 0;
+
+ delim = strchr(str, '=');
+ if (!delim) {
+ count = -EINVAL;
+ goto put_task;
+ }
+ *delim++ = 0; /* for easy 'str' usage */
+ new_rlimit.rlim_cur = simple_strtoul(delim, &next, 0);
+ if (*next != ':') {
+ if (strncmp(delim, "unlimited:", 10)) {
+ count = -EINVAL;
+ goto put_task;
+ }
+ new_rlimit.rlim_cur = RLIM_INFINITY;
+ next = delim + 9; /* move to ':' */
+ }
+ delim = next + 1;
+ new_rlimit.rlim_max = simple_strtoul(delim, &next, 0);
+ if (*next != 0) {
+ if (strcmp(delim, "unlimited")) {
+ count = -EINVAL;
+ goto put_task;
+ }
+ new_rlimit.rlim_max = RLIM_INFINITY;
+ }
+
+ for (i = 0; i < RLIM_NLIMITS; i++)
+ if (!strcmp(str, lnames[i].name))
+ break;
+ if (i >= RLIM_NLIMITS) {
+ count = -EINVAL;
+ goto put_task;
+ }
+
+ ret = setrlimit(task, i, &new_rlimit);
+ if (ret)
+ count = ret;
+
+put_task:
+ put_task_struct(task);
+out:
+ return count;
+}
+
static const struct file_operations proc_pid_limits_operations = {
.read = limits_read,
+ .write = limits_write,
};

#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
@@ -2519,7 +2583,7 @@ static const struct pid_entry tgid_base_stuff[] = {
INF("auxv", S_IRUSR, proc_pid_auxv),
ONE("status", S_IRUGO, proc_pid_status),
ONE("personality", S_IRUSR, proc_pid_personality),
- REG("limits", S_IRUSR, proc_pid_limits_operations),
+ REG("limits", S_IRUSR|S_IWUSR, proc_pid_limits_operations),
#ifdef CONFIG_SCHED_DEBUG
REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations),
#endif
@@ -2853,7 +2917,7 @@ static const struct pid_entry tid_base_stuff[] = {
INF("auxv", S_IRUSR, proc_pid_auxv),
ONE("status", S_IRUGO, proc_pid_status),
ONE("personality", S_IRUSR, proc_pid_personality),
- REG("limits", S_IRUSR, proc_pid_limits_operations),
+ REG("limits", S_IRUSR|S_IWUSR, proc_pid_limits_operations),
#ifdef CONFIG_SCHED_DEBUG
REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations),
#endif
--
1.6.5.3

2009-11-27 23:11:10

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 10/27] core: do security check under task_lock

Do security_task_setrlimit under task_lock. Other tasks may
change limits under our hands while we are checking limits
inside the function. From now on, they can't.

Signed-off-by: Jiri Slaby <[email protected]>
Acked-by: James Morris <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
---
kernel/sys.c | 16 +++++++---------
1 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/kernel/sys.c b/kernel/sys.c
index 605ab9c..0f86199 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1243,7 +1243,7 @@ int setrlimit(struct task_struct *tsk, unsigned int resource,
struct rlimit *new_rlim)
{
struct rlimit *old_rlim;
- int retval;
+ int retval = 0;

if (new_rlim->rlim_cur > new_rlim->rlim_max)
return -EINVAL;
@@ -1260,10 +1260,6 @@ int setrlimit(struct task_struct *tsk, unsigned int resource,
}
}

- retval = security_task_setrlimit(tsk, resource, new_rlim);
- if (retval)
- goto out;
-
if (resource == RLIMIT_CPU && new_rlim->rlim_cur == 0) {
/*
* The caller is asking for an immediate RLIMIT_CPU
@@ -1276,11 +1272,13 @@ int setrlimit(struct task_struct *tsk, unsigned int resource,

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

if (retval || resource != RLIMIT_CPU)
--
1.6.5.3

2009-11-27 23:09:39

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 11/27] core: rename setrlimit to do_setrlimit

Rename it so that it makes more sense in the field of syscalls
(i.e. do_* is used for functions called by syscall wrappers but
also when called from other paths).

Signed-off-by: Jiri Slaby <[email protected]>
Reviewed-by: WANG Cong <[email protected]>
Cc: James Morris <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
---
fs/proc/base.c | 2 +-
include/linux/resource.h | 2 +-
kernel/sys.c | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 78c0367..9fdb990 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -589,7 +589,7 @@ static ssize_t limits_write(struct file *file, const char __user *buf,
goto put_task;
}

- ret = setrlimit(task, i, &new_rlimit);
+ ret = do_setrlimit(task, i, &new_rlimit);
if (ret)
count = ret;

diff --git a/include/linux/resource.h b/include/linux/resource.h
index 4301d67..08beb1a 100644
--- a/include/linux/resource.h
+++ b/include/linux/resource.h
@@ -71,7 +71,7 @@ struct rlimit {
#include <asm/resource.h>

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

#endif
diff --git a/kernel/sys.c b/kernel/sys.c
index 0f86199..fad6010 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1239,7 +1239,7 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
#endif

/* make sure you are allowed to change @tsk limits before calling this */
-int setrlimit(struct task_struct *tsk, unsigned int resource,
+int do_setrlimit(struct task_struct *tsk, unsigned int resource,
struct rlimit *new_rlim)
{
struct rlimit *old_rlim;
@@ -1308,7 +1308,7 @@ SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
return -EINVAL;
if (copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
return -EFAULT;
- return setrlimit(current, resource, &new_rlim);
+ return do_setrlimit(current, resource, &new_rlim);
}

/*
--
1.6.5.3

2009-11-27 23:09:29

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 12/27] resource: move kernel functions inside __KERNEL__

These are internal functions. Move them inside __KERNEL__ ifdef.

This needs also unifdef of resource.h before installing. Change
that too.

Signed-off-by: Jiri Slaby <[email protected]>
---
include/linux/Kbuild | 2 +-
include/linux/resource.h | 8 ++++++--
2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 1feed71..a73a9c2 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -140,7 +140,6 @@ header-y += qnxtypes.h
header-y += qnx4_fs.h
header-y += radeonfb.h
header-y += raw.h
-header-y += resource.h
header-y += romfs_fs.h
header-y += rose.h
header-y += serial_reg.h
@@ -323,6 +322,7 @@ unifdef-y += irqnr.h
unifdef-y += reboot.h
unifdef-y += reiserfs_fs.h
unifdef-y += reiserfs_xattr.h
+unifdef-y += resource.h
unifdef-y += route.h
unifdef-y += rtc.h
unifdef-y += rtnetlink.h
diff --git a/include/linux/resource.h b/include/linux/resource.h
index 08beb1a..cf8dc96 100644
--- a/include/linux/resource.h
+++ b/include/linux/resource.h
@@ -3,8 +3,6 @@

#include <linux/time.h>

-struct task_struct;
-
/*
* Resource control/accounting header file for linux
*/
@@ -70,8 +68,14 @@ struct rlimit {
*/
#include <asm/resource.h>

+#ifdef __KERNEL__
+
+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__ */
+
#endif
--
1.6.5.3

2009-11-27 23:10:39

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 13/27] core: posix-cpu-timers, cleanup rlimits usage

Fetch rlimit (both hard and soft) values only once and work on them.
It removes many accesses through sig structure and makes the code
cleaner.

Mostly a preparation for writable resource limits support.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: James Morris <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Peter Zijlstra <[email protected]>
---
kernel/posix-cpu-timers.c | 32 +++++++++++++++++---------------
1 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index 102c345..a7dcce1 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -983,6 +983,7 @@ static void check_thread_timers(struct task_struct *tsk,
int maxfire;
struct list_head *timers = tsk->cpu_timers;
struct signal_struct *const sig = tsk->signal;
+ unsigned long soft;

maxfire = 20;
tsk->cputime_expires.prof_exp = cputime_zero;
@@ -1031,9 +1032,9 @@ static void check_thread_timers(struct task_struct *tsk,
/*
* Check for the special case thread timers.
*/
- if (sig->rlim[RLIMIT_RTTIME].rlim_cur != RLIM_INFINITY) {
+ soft = sig->rlim[RLIMIT_RTTIME].rlim_cur;
+ if (soft != RLIM_INFINITY) {
unsigned long hard = sig->rlim[RLIMIT_RTTIME].rlim_max;
- unsigned long *soft = &sig->rlim[RLIMIT_RTTIME].rlim_cur;

if (hard != RLIM_INFINITY &&
tsk->rt.timeout > DIV_ROUND_UP(hard, USEC_PER_SEC/HZ)) {
@@ -1044,14 +1045,13 @@ static void check_thread_timers(struct task_struct *tsk,
__group_send_sig_info(SIGKILL, SEND_SIG_PRIV, tsk);
return;
}
- if (tsk->rt.timeout > DIV_ROUND_UP(*soft, USEC_PER_SEC/HZ)) {
+ if (tsk->rt.timeout > DIV_ROUND_UP(soft, USEC_PER_SEC/HZ)) {
/*
* At the soft limit, send a SIGXCPU every second.
*/
- if (sig->rlim[RLIMIT_RTTIME].rlim_cur
- < sig->rlim[RLIMIT_RTTIME].rlim_max) {
- sig->rlim[RLIMIT_RTTIME].rlim_cur +=
- USEC_PER_SEC;
+ if (soft < hard) {
+ soft += USEC_PER_SEC;
+ sig->rlim[RLIMIT_RTTIME].rlim_cur = soft;
}
printk(KERN_INFO
"RT Watchdog Timeout: %s[%d]\n",
@@ -1122,13 +1122,14 @@ static void check_process_timers(struct task_struct *tsk,
unsigned long long sum_sched_runtime, sched_expires;
struct list_head *timers = sig->cpu_timers;
struct task_cputime cputime;
+ unsigned long cpu_cur_lim = sig->rlim[RLIMIT_CPU].rlim_cur;

/*
* Don't sample the current process CPU clocks if there are no timers.
*/
if (list_empty(&timers[CPUCLOCK_PROF]) &&
cputime_eq(sig->it[CPUCLOCK_PROF].expires, cputime_zero) &&
- sig->rlim[RLIMIT_CPU].rlim_cur == RLIM_INFINITY &&
+ cpu_cur_lim == RLIM_INFINITY &&
list_empty(&timers[CPUCLOCK_VIRT]) &&
cputime_eq(sig->it[CPUCLOCK_VIRT].expires, cputime_zero) &&
list_empty(&timers[CPUCLOCK_SCHED])) {
@@ -1195,10 +1196,11 @@ static void check_process_timers(struct task_struct *tsk,
check_cpu_itimer(tsk, &sig->it[CPUCLOCK_VIRT], &virt_expires, utime,
SIGVTALRM);

- if (sig->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) {
+ if (cpu_cur_lim != RLIM_INFINITY) {
unsigned long psecs = cputime_to_secs(ptime);
+ unsigned long hard = sig->rlim[RLIMIT_CPU].rlim_max;
cputime_t x;
- if (psecs >= sig->rlim[RLIMIT_CPU].rlim_max) {
+ if (psecs >= hard) {
/*
* At the hard limit, we just die.
* No need to calculate anything else now.
@@ -1206,17 +1208,17 @@ static void check_process_timers(struct task_struct *tsk,
__group_send_sig_info(SIGKILL, SEND_SIG_PRIV, tsk);
return;
}
- if (psecs >= sig->rlim[RLIMIT_CPU].rlim_cur) {
+ if (psecs >= cpu_cur_lim) {
/*
* At the soft limit, send a SIGXCPU every second.
*/
__group_send_sig_info(SIGXCPU, SEND_SIG_PRIV, tsk);
- if (sig->rlim[RLIMIT_CPU].rlim_cur
- < sig->rlim[RLIMIT_CPU].rlim_max) {
- sig->rlim[RLIMIT_CPU].rlim_cur++;
+ if (cpu_cur_lim < hard) {
+ cpu_cur_lim++;
+ sig->rlim[RLIMIT_CPU].rlim_cur = cpu_cur_lim;
}
}
- x = secs_to_cputime(sig->rlim[RLIMIT_CPU].rlim_cur);
+ x = secs_to_cputime(cpu_cur_lim);
if (cputime_eq(prof_expires, cputime_zero) ||
cputime_lt(x, prof_expires)) {
prof_expires = x;
--
1.6.5.3

2009-11-27 23:09:57

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 14/27] resource: add helpers for fetching rlimits

We want to be sure that compiler fetches the limit variable only
once, so add helpers for fetching current and maximal resource
limits which do that.

Add them to sched.h (instead of resource.h) due to circular dependency
sched.h->resource.h->task_struct
Alternative would be to create a separate res_access.h or similar.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: James Morris <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
---
include/linux/sched.h | 22 ++++++++++++++++++++++
1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/include/linux/sched.h b/include/linux/sched.h
index 75e6e60..cf4205b 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2574,6 +2574,28 @@ static inline void mm_init_owner(struct mm_struct *mm, struct task_struct *p)
}
#endif /* CONFIG_MM_OWNER */

+static inline unsigned long task_rlim_get_cur(const struct task_struct *tsk,
+ unsigned int limit)
+{
+ return ACCESS_ONCE(tsk->signal->rlim[limit].rlim_cur);
+}
+
+static inline unsigned long task_rlim_get_max(const struct task_struct *tsk,
+ unsigned int limit)
+{
+ return ACCESS_ONCE(tsk->signal->rlim[limit].rlim_max);
+}
+
+static inline unsigned long rlim_get_cur(unsigned int limit)
+{
+ return task_rlim_get_cur(current, limit);
+}
+
+static inline unsigned long rlim_get_max(unsigned int limit)
+{
+ return task_rlim_get_max(current, limit);
+}
+
#define TASK_STATE_TO_CHAR_STR "RSDTtZX"

#endif /* __KERNEL__ */
--
1.6.5.3

2009-11-27 23:09:28

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 15/27] IA64: use helpers for rlimits

Make sure compiler won't do weird things with limits. E.g. fetching
them twice may return 2 different values after writable limits are
implemented.

I.e. either use newly added rlimit helpers or ACCESS_ONCE if not
applicable.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: James Morris <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: [email protected]
---
arch/ia64/kernel/perfmon.c | 2 +-
arch/ia64/kernel/sys_ia64.c | 2 +-
arch/ia64/mm/init.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index f178270..82429cc 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -2298,7 +2298,7 @@ pfm_smpl_buffer_alloc(struct task_struct *task, struct file *filp, pfm_context_t
* if ((mm->total_vm << PAGE_SHIFT) + len> task->rlim[RLIMIT_AS].rlim_cur)
* return -ENOMEM;
*/
- if (size > task->signal->rlim[RLIMIT_MEMLOCK].rlim_cur)
+ if (size > task_rlim_get_cur(task, RLIMIT_MEMLOCK))
return -ENOMEM;

/*
diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c
index 92ed83f..ad663c8 100644
--- a/arch/ia64/kernel/sys_ia64.c
+++ b/arch/ia64/kernel/sys_ia64.c
@@ -129,7 +129,7 @@ ia64_brk (unsigned long brk)
goto out;

/* Check against rlimit.. */
- rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur;
+ rlim = rlim_get_cur(RLIMIT_DATA);
if (rlim < RLIM_INFINITY && brk - mm->start_data > rlim)
goto out;

diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 1857766..0995019 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -91,7 +91,7 @@ dma_mark_clean(void *addr, size_t size)
inline void
ia64_set_rbs_bot (void)
{
- unsigned long stack_size = current->signal->rlim[RLIMIT_STACK].rlim_max & -16;
+ unsigned long stack_size = rlim_get_max(RLIMIT_STACK) & -16;

if (stack_size > MAX_USER_STACK_SIZE)
stack_size = MAX_USER_STACK_SIZE;
--
1.6.5.3

2009-11-27 23:09:24

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 16/27] PPC: use helpers for rlimits

Make sure compiler won't do weird things with limits. E.g. fetching
them twice may return 2 different values after writable limits are
implemented.

I.e. either use newly added rlimit helpers or ACCESS_ONCE if not
applicable.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: James Morris <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Benjamin Herrenschmidt <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: [email protected]
---
arch/powerpc/mm/mmap_64.c | 4 ++--
arch/powerpc/platforms/cell/spufs/coredump.c | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/mm/mmap_64.c b/arch/powerpc/mm/mmap_64.c
index 0d957a4..8df1299 100644
--- a/arch/powerpc/mm/mmap_64.c
+++ b/arch/powerpc/mm/mmap_64.c
@@ -47,7 +47,7 @@ static inline int mmap_is_legacy(void)
if (current->personality & ADDR_COMPAT_LAYOUT)
return 1;

- if (current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY)
+ if (rlim_get_cur(RLIMIT_STACK) == RLIM_INFINITY)
return 1;

return sysctl_legacy_va_layout;
@@ -77,7 +77,7 @@ static unsigned long mmap_rnd(void)

static inline unsigned long mmap_base(void)
{
- unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur;
+ unsigned long gap = rlim_get_cur(RLIMIT_STACK);

if (gap < MIN_GAP)
gap = MIN_GAP;
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c
index c4d4a19..4ef1c92 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -54,7 +54,7 @@ static ssize_t do_coredump_read(int num, struct spu_context *ctx, void *buffer,
*/
static int spufs_dump_write(struct file *file, const void *addr, int nr, loff_t *foffset)
{
- unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
+ unsigned long limit = rlim_get_cur(RLIMIT_CORE);
ssize_t written;

if (*foffset + nr > limit)
--
1.6.5.3

2009-11-27 23:08:33

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 17/27] S390: use helpers for rlimits

Make sure compiler won't do weird things with limits. E.g. fetching
them twice may return 2 different values after writable limits are
implemented.

I.e. either use newly added rlimit helpers or ACCESS_ONCE if not
applicable.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: James Morris <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
arch/s390/mm/mmap.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c
index f4558cc..0acf3aa 100644
--- a/arch/s390/mm/mmap.c
+++ b/arch/s390/mm/mmap.c
@@ -40,7 +40,7 @@

static inline unsigned long mmap_base(void)
{
- unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur;
+ unsigned long gap = rlim_get_cur(RLIMIT_STACK);

if (gap < MIN_GAP)
gap = MIN_GAP;
@@ -61,7 +61,7 @@ static inline int mmap_is_legacy(void)
#endif
return sysctl_legacy_va_layout ||
(current->personality & ADDR_COMPAT_LAYOUT) ||
- current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY;
+ rlim_get_cur(RLIMIT_STACK) == RLIM_INFINITY;
}

#ifndef CONFIG_64BIT
--
1.6.5.3

2009-11-27 23:06:31

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 18/27] SPARC: use helpers for rlimits

Make sure compiler won't do weird things with limits. E.g. fetching
them twice may return 2 different values after writable limits are
implemented.

I.e. either use newly added rlimit helpers or ACCESS_ONCE if not
applicable.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: James Morris <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: [email protected]
---
arch/sparc/kernel/sys_sparc_64.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c
index e2d1024..d53870c 100644
--- a/arch/sparc/kernel/sys_sparc_64.c
+++ b/arch/sparc/kernel/sys_sparc_64.c
@@ -361,6 +361,7 @@ EXPORT_SYMBOL(get_fb_unmapped_area);
void arch_pick_mmap_layout(struct mm_struct *mm)
{
unsigned long random_factor = 0UL;
+ unsigned long gap;

if (current->flags & PF_RANDOMIZE) {
random_factor = get_random_int();
@@ -375,9 +376,10 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
* Fall back to the standard layout if the personality
* bit is set, or if the expected stack growth is unlimited:
*/
+ gap = rlim_get_cur(RLIMIT_STACK);
if (!test_thread_flag(TIF_32BIT) ||
(current->personality & ADDR_COMPAT_LAYOUT) ||
- current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY ||
+ gap == RLIM_INFINITY ||
sysctl_legacy_va_layout) {
mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
mm->get_unmapped_area = arch_get_unmapped_area;
@@ -385,9 +387,7 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
} else {
/* We know it's 32-bit */
unsigned long task_size = STACK_TOP32;
- unsigned long gap;

- gap = current->signal->rlim[RLIMIT_STACK].rlim_cur;
if (gap < 128 * 1024 * 1024)
gap = 128 * 1024 * 1024;
if (gap > (task_size / 6 * 5))
--
1.6.5.3

2009-11-27 23:10:53

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 19/27] X86: use helpers for rlimits

Make sure compiler won't do weird things with limits. E.g. fetching
them twice may return 2 different values after writable limits are
implemented.

I.e. either use newly added rlimit helpers or ACCESS_ONCE if not
applicable.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: James Morris <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: [email protected]
---
arch/x86/ia32/ia32_aout.c | 2 +-
arch/x86/mm/mmap.c | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c
index 2a4d073..d311ec5 100644
--- a/arch/x86/ia32/ia32_aout.c
+++ b/arch/x86/ia32/ia32_aout.c
@@ -297,7 +297,7 @@ static int load_aout_binary(struct linux_binprm *bprm, struct pt_regs *regs)
* size limits imposed on them by creating programs with large
* arrays in the data or bss.
*/
- rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur;
+ rlim = rlim_get_cur(RLIMIT_DATA);
if (rlim >= RLIM_INFINITY)
rlim = ~0;
if (ex.a_data + ex.a_bss > rlim)
diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c
index c8191de..6677bf0 100644
--- a/arch/x86/mm/mmap.c
+++ b/arch/x86/mm/mmap.c
@@ -71,7 +71,7 @@ static int mmap_is_legacy(void)
if (current->personality & ADDR_COMPAT_LAYOUT)
return 1;

- if (current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY)
+ if (rlim_get_cur(RLIMIT_STACK) == RLIM_INFINITY)
return 1;

return sysctl_legacy_va_layout;
@@ -96,7 +96,7 @@ static unsigned long mmap_rnd(void)

static unsigned long mmap_base(void)
{
- unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur;
+ unsigned long gap = rlim_get_cur(RLIMIT_STACK);

if (gap < MIN_GAP)
gap = MIN_GAP;
--
1.6.5.3

2009-11-27 23:08:17

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 20/27] FS: use helpers for rlimits

Make sure compiler won't do weird things with limits. E.g. fetching
them twice may return 2 different values after writable limits are
implemented.

I.e. either use newly added rlimit helpers or ACCESS_ONCE if not
applicable.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: James Morris <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Alexander Viro <[email protected]>
Cc: [email protected]
---
fs/attr.c | 2 +-
fs/binfmt_aout.c | 2 +-
fs/binfmt_flat.c | 2 +-
fs/exec.c | 8 ++++----
fs/fcntl.c | 2 +-
fs/file.c | 2 +-
fs/proc/array.c | 4 ++--
fs/select.c | 2 +-
8 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/fs/attr.c b/fs/attr.c
index 96d394b..3554042 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -82,7 +82,7 @@ int inode_newsize_ok(const struct inode *inode, loff_t offset)
if (inode->i_size < offset) {
unsigned long limit;

- limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
+ limit = rlim_get_cur(RLIMIT_FSIZE);
if (limit != RLIM_INFINITY && offset > limit)
goto out_sig;
if (offset > inode->i_sb->s_maxbytes)
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index b639dcf..dc3f316 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -246,7 +246,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
* size limits imposed on them by creating programs with large
* arrays in the data or bss.
*/
- rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur;
+ rlim = rlim_get_cur(RLIMIT_DATA);
if (rlim >= RLIM_INFINITY)
rlim = ~0;
if (ex.a_data + ex.a_bss > rlim)
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index a279665..0161f3c 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -501,7 +501,7 @@ static int load_flat_file(struct linux_binprm * bprm,
* size limits imposed on them by creating programs with large
* arrays in the data or bss.
*/
- rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur;
+ rlim = rlim_get_cur(RLIMIT_DATA);
if (rlim >= RLIM_INFINITY)
rlim = ~0;
if (data_len + bss_len > rlim) {
diff --git a/fs/exec.c b/fs/exec.c
index ba112bd..08dd798 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -196,7 +196,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
* to work from.
*/
rlim = current->signal->rlim;
- if (size > rlim[RLIMIT_STACK].rlim_cur / 4) {
+ if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4) {
put_page(page);
return NULL;
}
@@ -575,7 +575,7 @@ int setup_arg_pages(struct linux_binprm *bprm,

#ifdef CONFIG_STACK_GROWSUP
/* Limit stack size to 1GB */
- stack_base = current->signal->rlim[RLIMIT_STACK].rlim_max;
+ stack_base = rlim_get_max(RLIMIT_STACK);
if (stack_base > (1 << 30))
stack_base = 1 << 30;

@@ -1503,7 +1503,7 @@ static int format_corename(char *corename, long signr)
/* core limit size */
case 'c':
rc = snprintf(out_ptr, out_end - out_ptr,
- "%lu", current->signal->rlim[RLIMIT_CORE].rlim_cur);
+ "%lu", rlim_get_cur(RLIMIT_CORE));
if (rc > out_end - out_ptr)
goto out;
out_ptr += rc;
@@ -1762,7 +1762,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
int retval = 0;
int flag = 0;
int ispipe = 0;
- unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
+ unsigned long core_limit = rlim_get_cur(RLIMIT_CORE);
char **helper_argv = NULL;
int helper_argc = 0;
int dump_count = 0;
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 2cf93ec..8dd4b4f 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -344,7 +344,7 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
switch (cmd) {
case F_DUPFD:
case F_DUPFD_CLOEXEC:
- if (arg >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
+ if (arg >= rlim_get_cur(RLIMIT_NOFILE))
break;
err = alloc_fd(arg, cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0);
if (err >= 0) {
diff --git a/fs/file.c b/fs/file.c
index 87e1290..0a472ff 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -257,7 +257,7 @@ int expand_files(struct files_struct *files, int nr)
* N.B. For clone tasks sharing a files structure, this test
* will limit the total number of files that can be opened.
*/
- if (nr >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
+ if (nr >= rlim_get_cur(RLIMIT_NOFILE))
return -EMFILE;

/* Do we need to expand? */
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 822c2d5..54ba2d6 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -266,7 +266,7 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p)
collect_sigign_sigcatch(p, &ignored, &caught);
num_threads = atomic_read(&p->signal->count);
qsize = atomic_read(&__task_cred(p)->user->sigpending);
- qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur;
+ qlim = task_rlim_get_cur(p, RLIMIT_SIGPENDING);
unlock_task_sighand(p, &flags);
}

@@ -491,7 +491,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
cutime = sig->cutime;
cstime = sig->cstime;
cgtime = sig->cgtime;
- rsslim = sig->rlim[RLIMIT_RSS].rlim_cur;
+ rsslim = ACCESS_ONCE(sig->rlim[RLIMIT_RSS].rlim_cur);

/* add up live thread stats at the group level */
if (whole) {
diff --git a/fs/select.c b/fs/select.c
index fd38ce2..ab34a88 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -821,7 +821,7 @@ int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
struct poll_list *walk = head;
unsigned long todo = nfds;

- if (nfds > current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
+ if (nfds > rlim_get_cur(RLIMIT_NOFILE))
return -EINVAL;

len = min_t(unsigned int, nfds, N_STACK_PPS);
--
1.6.5.3

2009-11-27 23:06:15

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 21/27] MM: use helpers for rlimits

Make sure compiler won't do weird things with limits. E.g. fetching
them twice may return 2 different values after writable limits are
implemented.

I.e. either use newly added rlimit helpers or ACCESS_ONCE if not
applicable.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: James Morris <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: [email protected]
---
mm/filemap.c | 2 +-
mm/mlock.c | 12 ++++++------
mm/mmap.c | 13 +++++++------
mm/mremap.c | 2 +-
4 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/mm/filemap.c b/mm/filemap.c
index ef169f3..8896396 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1971,7 +1971,7 @@ EXPORT_SYMBOL(iov_iter_single_seg_count);
inline int generic_write_checks(struct file *file, loff_t *pos, size_t *count, int isblk)
{
struct inode *inode = file->f_mapping->host;
- unsigned long limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
+ unsigned long limit = rlim_get_cur(RLIMIT_FSIZE);

if (unlikely(*pos < 0))
return -EINVAL;
diff --git a/mm/mlock.c b/mm/mlock.c
index bd6f0e4..a8ee8bf 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -25,7 +25,7 @@ int can_do_mlock(void)
{
if (capable(CAP_IPC_LOCK))
return 1;
- if (current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur != 0)
+ if (rlim_get_cur(RLIMIT_MEMLOCK) != 0)
return 1;
return 0;
}
@@ -490,7 +490,7 @@ SYSCALL_DEFINE2(mlock, unsigned long, start, size_t, len)
locked = len >> PAGE_SHIFT;
locked += current->mm->locked_vm;

- lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
+ lock_limit = rlim_get_cur(RLIMIT_MEMLOCK);
lock_limit >>= PAGE_SHIFT;

/* check against resource limits */
@@ -553,7 +553,7 @@ SYSCALL_DEFINE1(mlockall, int, flags)

down_write(&current->mm->mmap_sem);

- lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
+ lock_limit = rlim_get_cur(RLIMIT_MEMLOCK);
lock_limit >>= PAGE_SHIFT;

ret = -ENOMEM;
@@ -587,7 +587,7 @@ int user_shm_lock(size_t size, struct user_struct *user)
int allowed = 0;

locked = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
- lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
+ lock_limit = rlim_get_cur(RLIMIT_MEMLOCK);
if (lock_limit == RLIM_INFINITY)
allowed = 1;
lock_limit >>= PAGE_SHIFT;
@@ -621,12 +621,12 @@ int account_locked_memory(struct mm_struct *mm, struct rlimit *rlim,

down_write(&mm->mmap_sem);

- lim = rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
+ lim = ACCESS_ONCE(rlim[RLIMIT_AS].rlim_cur) >> PAGE_SHIFT;
vm = mm->total_vm + pgsz;
if (lim < vm)
goto out;

- lim = rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
+ lim = ACCESS_ONCE(rlim[RLIMIT_MEMLOCK].rlim_cur) >> PAGE_SHIFT;
vm = mm->locked_vm + pgsz;
if (lim < vm)
goto out;
diff --git a/mm/mmap.c b/mm/mmap.c
index 73f5e4b..dc49f43 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -266,7 +266,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk)
* segment grow beyond its set limit the in case where the limit is
* not page aligned -Ram Gupta
*/
- rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur;
+ rlim = rlim_get_cur(RLIMIT_DATA);
if (rlim < RLIM_INFINITY && (brk - mm->start_brk) +
(mm->end_data - mm->start_data) > rlim)
goto out;
@@ -990,7 +990,7 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
unsigned long locked, lock_limit;
locked = len >> PAGE_SHIFT;
locked += mm->locked_vm;
- lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
+ lock_limit = rlim_get_cur(RLIMIT_MEMLOCK);
lock_limit >>= PAGE_SHIFT;
if (locked > lock_limit && !capable(CAP_IPC_LOCK))
return -EAGAIN;
@@ -1565,7 +1565,7 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns
return -ENOMEM;

/* Stack limit test */
- if (size > rlim[RLIMIT_STACK].rlim_cur)
+ if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur))
return -ENOMEM;

/* mlock limit tests */
@@ -1573,7 +1573,8 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns
unsigned long locked;
unsigned long limit;
locked = mm->locked_vm + grow;
- limit = rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
+ limit = ACCESS_ONCE(rlim[RLIMIT_MEMLOCK].rlim_cur);
+ limit >>= PAGE_SHIFT;
if (locked > limit && !capable(CAP_IPC_LOCK))
return -ENOMEM;
}
@@ -2026,7 +2027,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
unsigned long locked, lock_limit;
locked = len >> PAGE_SHIFT;
locked += mm->locked_vm;
- lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
+ lock_limit = rlim_get_cur(RLIMIT_MEMLOCK);
lock_limit >>= PAGE_SHIFT;
if (locked > lock_limit && !capable(CAP_IPC_LOCK))
return -EAGAIN;
@@ -2240,7 +2241,7 @@ int may_expand_vm(struct mm_struct *mm, unsigned long npages)
unsigned long cur = mm->total_vm; /* pages */
unsigned long lim;

- lim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
+ lim = rlim_get_cur(RLIMIT_AS) >> PAGE_SHIFT;

if (cur + npages > lim)
return 0;
diff --git a/mm/mremap.c b/mm/mremap.c
index 97bff25..00a384c 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -358,7 +358,7 @@ unsigned long do_mremap(unsigned long addr,
if (vma->vm_flags & VM_LOCKED) {
unsigned long locked, lock_limit;
locked = mm->locked_vm << PAGE_SHIFT;
- lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
+ lock_limit = rlim_get_cur(RLIMIT_MEMLOCK);
locked += new_len - old_len;
ret = -EAGAIN;
if (locked > lock_limit && !capable(CAP_IPC_LOCK))
--
1.6.5.3

2009-11-27 23:08:51

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 22/27] core: use helpers for rlimits

Make sure compiler won't do weird things with limits. E.g. fetching
them twice may return 2 different values after writable limits are
implemented.

I.e. either use newly added rlimit helpers or ACCESS_ONCE if not
applicable.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: James Morris <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Peter Zijlstra <[email protected]>
---
kernel/fork.c | 10 ++++++----
kernel/perf_event.c | 2 +-
kernel/posix-cpu-timers.c | 16 +++++++++-------
kernel/sched.c | 4 ++--
kernel/sched_rt.c | 5 +++--
kernel/signal.c | 2 +-
kernel/sys.c | 3 +--
7 files changed, 23 insertions(+), 19 deletions(-)

diff --git a/kernel/fork.c b/kernel/fork.c
index 166b8c4..9f0773d 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -822,6 +822,8 @@ void __cleanup_sighand(struct sighand_struct *sighand)
*/
static void posix_cpu_timers_init_group(struct signal_struct *sig)
{
+ unsigned long cpu_limit;
+
/* Thread group counters. */
thread_group_cputime_init(sig);

@@ -836,9 +838,9 @@ static void posix_cpu_timers_init_group(struct signal_struct *sig)
sig->cputime_expires.virt_exp = cputime_zero;
sig->cputime_expires.sched_exp = 0;

- if (sig->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) {
- sig->cputime_expires.prof_exp =
- secs_to_cputime(sig->rlim[RLIMIT_CPU].rlim_cur);
+ cpu_limit = ACCESS_ONCE(sig->rlim[RLIMIT_CPU].rlim_cur);
+ if (cpu_limit != RLIM_INFINITY) {
+ sig->cputime_expires.prof_exp = secs_to_cputime(cpu_limit);
sig->cputimer.running = 1;
}

@@ -1028,7 +1030,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
#endif
retval = -EAGAIN;
if (atomic_read(&p->real_cred->user->processes) >=
- p->signal->rlim[RLIMIT_NPROC].rlim_cur) {
+ task_rlim_get_cur(p, RLIMIT_NPROC)) {
if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) &&
p->real_cred->user != INIT_USER)
goto bad_fork_free;
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 7f29643..02ba1e0 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -2420,7 +2420,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
if (user_locked > user_lock_limit)
extra = user_locked - user_lock_limit;

- lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
+ lock_limit = rlim_get_cur(RLIMIT_MEMLOCK);
lock_limit >>= PAGE_SHIFT;
locked = vma->vm_mm->locked_vm + extra;

diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index a7dcce1..79d4cb3 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -640,7 +640,7 @@ static void arm_timer(struct k_itimer *timer, union cpu_time_count now)
if (expires_le(sig->it[CPUCLOCK_PROF].expires,
exp->cpu))
break;
- i = sig->rlim[RLIMIT_CPU].rlim_cur;
+ i = ACCESS_ONCE(sig->rlim[RLIMIT_CPU].rlim_cur);
if (i != RLIM_INFINITY &&
i <= cputime_to_secs(exp->cpu))
break;
@@ -1032,9 +1032,10 @@ static void check_thread_timers(struct task_struct *tsk,
/*
* Check for the special case thread timers.
*/
- soft = sig->rlim[RLIMIT_RTTIME].rlim_cur;
+ soft = ACCESS_ONCE(sig->rlim[RLIMIT_RTTIME].rlim_cur);
if (soft != RLIM_INFINITY) {
- unsigned long hard = sig->rlim[RLIMIT_RTTIME].rlim_max;
+ unsigned long hard = ACCESS_ONCE(sig->rlim[RLIMIT_RTTIME].
+ rlim_max);

if (hard != RLIM_INFINITY &&
tsk->rt.timeout > DIV_ROUND_UP(hard, USEC_PER_SEC/HZ)) {
@@ -1122,7 +1123,7 @@ static void check_process_timers(struct task_struct *tsk,
unsigned long long sum_sched_runtime, sched_expires;
struct list_head *timers = sig->cpu_timers;
struct task_cputime cputime;
- unsigned long cpu_cur_lim = sig->rlim[RLIMIT_CPU].rlim_cur;
+ unsigned long cpu_cur_lim = ACCESS_ONCE(sig->rlim[RLIMIT_CPU].rlim_cur);

/*
* Don't sample the current process CPU clocks if there are no timers.
@@ -1198,7 +1199,8 @@ static void check_process_timers(struct task_struct *tsk,

if (cpu_cur_lim != RLIM_INFINITY) {
unsigned long psecs = cputime_to_secs(ptime);
- unsigned long hard = sig->rlim[RLIMIT_CPU].rlim_max;
+ unsigned long hard =
+ ACCESS_ONCE(sig->rlim[RLIMIT_CPU].rlim_max);
cputime_t x;
if (psecs >= hard) {
/*
@@ -1385,7 +1387,7 @@ static inline int fastpath_timer_check(struct task_struct *tsk)
return 1;
}

- return sig->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY;
+ return ACCESS_ONCE(sig->rlim[RLIMIT_CPU].rlim_cur) != RLIM_INFINITY;
}

/*
@@ -1483,7 +1485,7 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,
* If the RLIMIT_CPU timer will expire before the
* ITIMER_PROF timer, we have nothing else to do.
*/
- if (tsk->signal->rlim[RLIMIT_CPU].rlim_cur
+ if (task_rlim_get_cur(tsk, RLIMIT_CPU)
< cputime_to_secs(*newval))
return;
}
diff --git a/kernel/sched.c b/kernel/sched.c
index 3c11ae0..0e4077d 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -6072,7 +6072,7 @@ int can_nice(const struct task_struct *p, const int nice)
/* convert nice value [19,-20] to rlimit style value [1,40] */
int nice_rlim = 20 - nice;

- return (nice_rlim <= p->signal->rlim[RLIMIT_NICE].rlim_cur ||
+ return (nice_rlim <= task_rlim_get_cur(p, RLIMIT_NICE) ||
capable(CAP_SYS_NICE));
}

@@ -6257,7 +6257,7 @@ recheck:

if (!lock_task_sighand(p, &flags))
return -ESRCH;
- rlim_rtprio = p->signal->rlim[RLIMIT_RTPRIO].rlim_cur;
+ rlim_rtprio = task_rlim_get_cur(p, RLIMIT_RTPRIO);
unlock_task_sighand(p, &flags);

/* can't set/change the rt policy */
diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c
index a4d790c..ab41715 100644
--- a/kernel/sched_rt.c
+++ b/kernel/sched_rt.c
@@ -1683,8 +1683,9 @@ static void watchdog(struct rq *rq, struct task_struct *p)
if (!p->signal)
return;

- soft = p->signal->rlim[RLIMIT_RTTIME].rlim_cur;
- hard = p->signal->rlim[RLIMIT_RTTIME].rlim_max;
+ /* max may change after cur was read, this will be fixed next tick */
+ soft = task_rlim_get_cur(p, RLIMIT_RTTIME);
+ hard = task_rlim_get_max(p, RLIMIT_RTTIME);

if (soft != RLIM_INFINITY) {
unsigned long next;
diff --git a/kernel/signal.c b/kernel/signal.c
index 6705320..34efd79 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -209,7 +209,7 @@ static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
atomic_inc(&user->sigpending);
if (override_rlimit ||
atomic_read(&user->sigpending) <=
- t->signal->rlim[RLIMIT_SIGPENDING].rlim_cur)
+ task_rlim_get_cur(t, RLIMIT_SIGPENDING))
q = kmem_cache_alloc(sigqueue_cachep, flags);
if (unlikely(q == NULL)) {
atomic_dec(&user->sigpending);
diff --git a/kernel/sys.c b/kernel/sys.c
index fad6010..c4065c5 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -572,8 +572,7 @@ static int set_user(struct cred *new)
return -EINVAL;
}

- if (atomic_read(&new_user->processes) >=
- current->signal->rlim[RLIMIT_NPROC].rlim_cur &&
+ if (atomic_read(&new_user->processes) >= rlim_get_cur(RLIMIT_NPROC) &&
new_user != INIT_USER) {
free_uid(new_user);
return -EAGAIN;
--
1.6.5.3

2009-11-27 23:06:15

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 23/27] misc: use helpers for rlimits

Make sure compiler won't do weird things with limits. E.g. fetching
them twice may return 2 different values after writable limits are
implemented.

I.e. either use newly added rlimit helpers or ACCESS_ONCE if not
applicable.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: James Morris <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Roland Dreier <[email protected]>
Cc: Sean Hefty <[email protected]>
Cc: Hal Rosenstock <[email protected]>
Cc: [email protected]
---
drivers/infiniband/core/umem.c | 2 +-
drivers/infiniband/hw/ipath/ipath_user_pages.c | 3 +--
ipc/mqueue.c | 2 +-
ipc/shm.c | 3 +--
4 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index 6f7c096..2a8338a 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -136,7 +136,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
down_write(&current->mm->mmap_sem);

locked = npages + current->mm->locked_vm;
- lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
+ lock_limit = rlim_get_cur(RLIMIT_MEMLOCK) >> PAGE_SHIFT;

if ((locked > lock_limit) && !capable(CAP_IPC_LOCK)) {
ret = -ENOMEM;
diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/infiniband/hw/ipath/ipath_user_pages.c
index 82878e3..431ec61 100644
--- a/drivers/infiniband/hw/ipath/ipath_user_pages.c
+++ b/drivers/infiniband/hw/ipath/ipath_user_pages.c
@@ -59,8 +59,7 @@ static int __get_user_pages(unsigned long start_page, size_t num_pages,
size_t got;
int ret;

- lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >>
- PAGE_SHIFT;
+ lock_limit = rlim_get_cur(RLIMIT_MEMLOCK) >> PAGE_SHIFT;

if (num_pages > lock_limit) {
ret = -ENOMEM;
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index ee9d697..0e18cde 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -153,7 +153,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
spin_lock(&mq_lock);
if (u->mq_bytes + mq_bytes < u->mq_bytes ||
u->mq_bytes + mq_bytes >
- p->signal->rlim[RLIMIT_MSGQUEUE].rlim_cur) {
+ task_rlim_get_cur(p, RLIMIT_MSGQUEUE)) {
spin_unlock(&mq_lock);
goto out_inode;
}
diff --git a/ipc/shm.c b/ipc/shm.c
index 464694e..abd1ebd 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -761,8 +761,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
if (euid != shp->shm_perm.uid &&
euid != shp->shm_perm.cuid)
goto out_unlock;
- if (cmd == SHM_LOCK &&
- !current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur)
+ if (cmd == SHM_LOCK && !rlim_get_cur(RLIMIT_MEMLOCK))
goto out_unlock;
}

--
1.6.5.3

2009-11-27 23:07:54

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 24/27] core: implement getprlimit and setprlimit syscalls

This patch adds the code to support the sys_setprlimit and set_getprlimit
syscalls which modify the rlim values of a selected process.

All rlim users now either use newly added accessors or doesn't need them
due to
- locking
- a process was just forked and nobody else knows about it yet (and
nobody can't thus read/write limits)

Based on Neil's work. Thank him.

Signed-off-by: Jiri Slaby <[email protected]>
Acked-by: Neil Horman <[email protected]>
Cc: James Morris <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
---
include/linux/syscalls.h | 4 ++
kernel/sys.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 90 insertions(+), 0 deletions(-)

diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index a990ace..6fd7ba6 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -702,11 +702,15 @@ asmlinkage long sys_newuname(struct new_utsname __user *name);

asmlinkage long sys_getrlimit(unsigned int resource,
struct rlimit __user *rlim);
+asmlinkage long sys_getprlimit(pid_t pid, unsigned int resource,
+ struct rlimit __user *rlim);
#if defined(COMPAT_RLIM_OLD_INFINITY) || !(defined(CONFIG_IA64))
asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit __user *rlim);
#endif
asmlinkage long sys_setrlimit(unsigned int resource,
struct rlimit __user *rlim);
+asmlinkage long sys_setprlimit(pid_t pid, unsigned int resource,
+ struct rlimit __user *rlim);
asmlinkage long sys_getrusage(int who, struct rusage __user *ru);
asmlinkage long sys_umask(int mask);

diff --git a/kernel/sys.c b/kernel/sys.c
index c4065c5..626148f 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1212,6 +1212,61 @@ SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim)
}
}

+static int check_prlimit_permission(struct task_struct *task)
+{
+ const struct cred *cred = current_cred(), *tcred;
+ int ret = 0;
+
+ rcu_read_lock();
+ tcred = __task_cred(task);
+ if ((cred->uid != tcred->euid ||
+ cred->uid != tcred->suid ||
+ cred->uid != tcred->uid ||
+ cred->gid != tcred->egid ||
+ cred->gid != tcred->sgid ||
+ cred->gid != tcred->gid) &&
+ !capable(CAP_SYS_RESOURCE)) {
+ ret = -EPERM;
+ }
+ rcu_read_unlock();
+ return ret;
+}
+
+SYSCALL_DEFINE3(getprlimit, pid_t, pid, unsigned int, resource,
+ struct rlimit __user *, rlim)
+{
+ struct rlimit val;
+ struct task_struct *tsk;
+ int ret;
+
+ if (resource >= RLIM_NLIMITS)
+ return -EINVAL;
+
+ read_lock(&tasklist_lock);
+
+ tsk = find_task_by_vpid(pid);
+ if (!tsk || !tsk->sighand) {
+ ret = -ESRCH;
+ goto err_unlock;
+ }
+
+ ret = check_prlimit_permission(tsk);
+ if (ret)
+ goto err_unlock;
+
+ task_lock(tsk->group_leader);
+ val = tsk->signal->rlim[resource];
+ task_unlock(tsk->group_leader);
+
+ read_unlock(&tasklist_lock);
+
+ return copy_to_user(rlim, &val, sizeof(*rlim)) ? -EFAULT : 0;
+err_unlock:
+ read_unlock(&tasklist_lock);
+ return ret;
+}
+
+
#ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT

/*
@@ -1310,6 +1365,37 @@ SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
return do_setrlimit(current, resource, &new_rlim);
}

+SYSCALL_DEFINE3(setprlimit, pid_t, pid, unsigned int, resource,
+ struct rlimit __user *, rlim)
+{
+ struct task_struct *tsk;
+ struct rlimit new_rlim;
+ int ret;
+
+ if (resource >= RLIM_NLIMITS)
+ return -EINVAL;
+
+ if (copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
+ return -EFAULT;
+
+ rcu_read_lock();
+ tsk = find_task_by_vpid(pid);
+ if (!tsk) {
+ rcu_read_unlock();
+ return -ESRCH;
+ }
+ get_task_struct(tsk);
+ rcu_read_unlock();
+
+ ret = check_prlimit_permission(tsk);
+ if (!ret)
+ ret = do_setrlimit(tsk, resource, &new_rlim);
+
+ put_task_struct(tsk);
+
+ return ret;
+}
+
/*
* It would make sense to put struct rusage in the task_struct,
* except that would make the task_struct be *really big*. After
--
1.6.5.3

2009-11-27 23:08:18

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 25/27] unistd: add __NR_[get|set]prlimit syscall numbers

From: Neil Horman <[email protected]>

Add __NR_[get|set]prlimit syscall numbers to asm-generic. Add them
also to asm-x86.

Signed-off-by: Neil Horman <[email protected]>
Signed-off-by: Jiri Slaby <[email protected]>
Cc: James Morris <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
---
arch/x86/include/asm/unistd_32.h | 4 +++-
arch/x86/include/asm/unistd_64.h | 4 ++++
arch/x86/kernel/syscall_table_32.S | 2 ++
include/asm-generic/unistd.h | 6 +++++-
4 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/unistd_32.h b/arch/x86/include/asm/unistd_32.h
index 6fb3c20..06dbb34 100644
--- a/arch/x86/include/asm/unistd_32.h
+++ b/arch/x86/include/asm/unistd_32.h
@@ -342,10 +342,12 @@
#define __NR_pwritev 334
#define __NR_rt_tgsigqueueinfo 335
#define __NR_perf_event_open 336
+#define __NR_getprlimit 337
+#define __NR_setprlimit 338

#ifdef __KERNEL__

-#define NR_syscalls 337
+#define NR_syscalls 339

#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/arch/x86/include/asm/unistd_64.h b/arch/x86/include/asm/unistd_64.h
index 8d3ad0a..48ea56c 100644
--- a/arch/x86/include/asm/unistd_64.h
+++ b/arch/x86/include/asm/unistd_64.h
@@ -661,6 +661,10 @@ __SYSCALL(__NR_pwritev, sys_pwritev)
__SYSCALL(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo)
#define __NR_perf_event_open 298
__SYSCALL(__NR_perf_event_open, sys_perf_event_open)
+#define __NR_getprlimit 299
+__SYSCALL(__NR_getprlimit, sys_getprlimit)
+#define __NR_setprlimit 300
+__SYSCALL(__NR_setprlimit, sys_setprlimit)

#ifndef __NO_STUBS
#define __ARCH_WANT_OLD_READDIR
diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S
index 0157cd2..2dd45cd 100644
--- a/arch/x86/kernel/syscall_table_32.S
+++ b/arch/x86/kernel/syscall_table_32.S
@@ -336,3 +336,5 @@ ENTRY(sys_call_table)
.long sys_pwritev
.long sys_rt_tgsigqueueinfo /* 335 */
.long sys_perf_event_open
+ .long sys_getprlimit
+ .long sys_setprlimit
diff --git a/include/asm-generic/unistd.h b/include/asm-generic/unistd.h
index d76b66a..950587d 100644
--- a/include/asm-generic/unistd.h
+++ b/include/asm-generic/unistd.h
@@ -622,9 +622,13 @@ __SYSCALL(__NR_move_pages, sys_move_pages)
__SYSCALL(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo)
#define __NR_perf_event_open 241
__SYSCALL(__NR_perf_event_open, sys_perf_event_open)
+#define __NR_getprlimit 242
+__SYSCALL(__NR_getprlimit, sys_getprlimit)
+#define __NR_setprlimit 243
+__SYSCALL(__NR_setprlimit, sys_setprlimit)

#undef __NR_syscalls
-#define __NR_syscalls 242
+#define __NR_syscalls 244

/*
* All syscalls below here should go away really,
--
1.6.5.3

2009-11-27 23:08:20

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 26/27] COMPAT: add get/put_compat_rlimit

Extract those functions from compat_sys_[gs]etrlimit for later
use with newly added rlimit syscalls.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: James Morris <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
---
kernel/compat.c | 61 ++++++++++++++++++++++++++++++++++++-------------------
1 files changed, 40 insertions(+), 21 deletions(-)

diff --git a/kernel/compat.c b/kernel/compat.c
index f6c204f..af15719 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -274,6 +274,39 @@ asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set,
return ret;
}

+static int get_compat_rlimit(struct rlimit *dst,
+ const struct compat_rlimit __user *src)
+{
+ if (!access_ok(VERIFY_READ, src, sizeof(*src)) ||
+ __get_user(dst->rlim_cur, &src->rlim_cur) ||
+ __get_user(dst->rlim_max, &src->rlim_max))
+ return -EFAULT;
+
+ if (dst->rlim_cur == COMPAT_RLIM_INFINITY)
+ dst->rlim_cur = RLIM_INFINITY;
+ if (dst->rlim_max == COMPAT_RLIM_INFINITY)
+ dst->rlim_max = RLIM_INFINITY;
+ return 0;
+}
+
+static int put_compat_rlimit(const struct rlimit *src,
+ struct compat_rlimit __user *dst)
+{
+ struct rlimit r = *src;
+
+ if (r.rlim_cur > COMPAT_RLIM_INFINITY)
+ r.rlim_cur = COMPAT_RLIM_INFINITY;
+ if (r.rlim_max > COMPAT_RLIM_INFINITY)
+ r.rlim_max = COMPAT_RLIM_INFINITY;
+
+ if (!access_ok(VERIFY_WRITE, dst, sizeof(*dst)) ||
+ __put_user(r.rlim_cur, &dst->rlim_cur) ||
+ __put_user(r.rlim_max, &dst->rlim_max))
+ return -EFAULT;
+
+ return 0;
+}
+
asmlinkage long compat_sys_setrlimit(unsigned int resource,
struct compat_rlimit __user *rlim)
{
@@ -284,17 +317,12 @@ asmlinkage long compat_sys_setrlimit(unsigned int resource,
if (resource >= RLIM_NLIMITS)
return -EINVAL;

- if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) ||
- __get_user(r.rlim_cur, &rlim->rlim_cur) ||
- __get_user(r.rlim_max, &rlim->rlim_max))
- return -EFAULT;
+ ret = get_compat_rlimit(&r, rlim);
+ if (ret)
+ return ret;

- if (r.rlim_cur == COMPAT_RLIM_INFINITY)
- r.rlim_cur = RLIM_INFINITY;
- if (r.rlim_max == COMPAT_RLIM_INFINITY)
- r.rlim_max = RLIM_INFINITY;
set_fs(KERNEL_DS);
- ret = sys_setrlimit(resource, (struct rlimit __user *) &r);
+ ret = sys_setrlimit(resource, (struct rlimit __force __user *)&r);
set_fs(old_fs);
return ret;
}
@@ -336,19 +364,10 @@ asmlinkage long compat_sys_getrlimit (unsigned int resource,
mm_segment_t old_fs = get_fs();

set_fs(KERNEL_DS);
- ret = sys_getrlimit(resource, (struct rlimit __user *) &r);
+ ret = sys_getrlimit(resource, (struct rlimit __force __user *)&r);
set_fs(old_fs);
- if (!ret) {
- if (r.rlim_cur > COMPAT_RLIM_INFINITY)
- r.rlim_cur = COMPAT_RLIM_INFINITY;
- if (r.rlim_max > COMPAT_RLIM_INFINITY)
- r.rlim_max = COMPAT_RLIM_INFINITY;
-
- if (!access_ok(VERIFY_WRITE, rlim, sizeof(*rlim)) ||
- __put_user(r.rlim_cur, &rlim->rlim_cur) ||
- __put_user(r.rlim_max, &rlim->rlim_max))
- return -EFAULT;
- }
+ if (!ret)
+ ret = put_compat_rlimit(&r, rlim);
return ret;
}

--
1.6.5.3

2009-11-27 23:07:43

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 27/27] x86: add ia32 compat prlimit syscalls

To support 32/64-bit compatibility (rlimit structure contains 2 longs)
for prlimit syscalls, add compat wrappers for them.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: James Morris <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
---
arch/x86/ia32/ia32entry.S | 2 ++
kernel/compat.c | 32 ++++++++++++++++++++++++++++++++
2 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index 581b056..c61ced2 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -841,4 +841,6 @@ ia32_sys_call_table:
.quad compat_sys_pwritev
.quad compat_sys_rt_tgsigqueueinfo /* 335 */
.quad sys_perf_event_open
+ .quad compat_sys_getprlimit
+ .quad compat_sys_setprlimit
ia32_syscall_end:
diff --git a/kernel/compat.c b/kernel/compat.c
index af15719..c1d5704 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -371,6 +371,38 @@ asmlinkage long compat_sys_getrlimit (unsigned int resource,
return ret;
}

+asmlinkage long compat_sys_setprlimit(pid_t pid, unsigned int resource,
+ struct compat_rlimit __user *rlim)
+{
+ mm_segment_t old_fs = get_fs();
+ struct rlimit r;
+ int ret;
+
+ ret = get_compat_rlimit(&r, rlim);
+ if (ret)
+ return ret;
+
+ set_fs(KERNEL_DS);
+ ret = sys_setprlimit(pid, resource, (struct rlimit __force __user *)&r);
+ set_fs(old_fs);
+ return ret;
+}
+
+asmlinkage long compat_sys_getprlimit(pid_t pid, unsigned int resource,
+ struct compat_rlimit __user *rlim)
+{
+ mm_segment_t old_fs = get_fs();
+ struct rlimit r;
+ int ret;
+
+ set_fs(KERNEL_DS);
+ ret = sys_getprlimit(pid, resource, (struct rlimit __force __user *)&r);
+ set_fs(old_fs);
+ if (!ret)
+ ret = put_compat_rlimit(&r, rlim);
+ return ret;
+}
+
int put_compat_rusage(const struct rusage *r, struct compat_rusage __user *ru)
{
if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru)) ||
--
1.6.5.3

2009-11-27 23:41:25

by Jiri Slaby

[permalink] [raw]
Subject: [PATCH v3 00/27] writable limits

Hi,

I broke the threading to not mess up with the long thread.

In this version I got rid of the rlim access_only ugliness.

There are two things:
1)
<quote from=Ingo>
A prominent example would be the stack limit - we base address layout
decisions on it. Check arch/x86/mm/mmap.c. RLIM_INFINITY has a special
meaning plus we also set mmap_base() based on the rlim.
</quote>
Should there be some special handling of that? In standard setrlimit
there is none.

2)
<quote from=Oleg>
Hmm. you are right. Do you know why acct_file_reopen() does
if (old_acct)
do_acct_process();
???
</quote>
As I expressed myself before, I don't know why it is there (it doesn't
make sense to me either). But I took a look at when it was added. From
the very first merge of acct.c (2.1.68pre1) it was just in (name ==
NULL) path (turning acct off). Then in 2.1.126 it was switched to
account on every accounting file change.

I fear if we changed this, something would break.

thanks,
--
js

2009-11-28 00:20:31

by Benjamin Herrenschmidt

[permalink] [raw]
Subject: Re: [PATCH v3 16/27] PPC: use helpers for rlimits

On Sat, 2009-11-28 at 00:05 +0100, Jiri Slaby wrote:
> Make sure compiler won't do weird things with limits. E.g. fetching
> them twice may return 2 different values after writable limits are
> implemented.
>
> I.e. either use newly added rlimit helpers or ACCESS_ONCE if not
> applicable.

Thanks. I have that already queued up.

Cheers,
Ben.

> Signed-off-by: Jiri Slaby <[email protected]>
> Cc: James Morris <[email protected]>
> Cc: Heiko Carstens <[email protected]>
> Cc: Andrew Morton <[email protected]>
> Cc: Ingo Molnar <[email protected]>
> Cc: Benjamin Herrenschmidt <[email protected]>
> Cc: Paul Mackerras <[email protected]>
> Cc: [email protected]
> ---
> arch/powerpc/mm/mmap_64.c | 4 ++--
> arch/powerpc/platforms/cell/spufs/coredump.c | 2 +-
> 2 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/arch/powerpc/mm/mmap_64.c b/arch/powerpc/mm/mmap_64.c
> index 0d957a4..8df1299 100644
> --- a/arch/powerpc/mm/mmap_64.c
> +++ b/arch/powerpc/mm/mmap_64.c
> @@ -47,7 +47,7 @@ static inline int mmap_is_legacy(void)
> if (current->personality & ADDR_COMPAT_LAYOUT)
> return 1;
>
> - if (current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY)
> + if (rlim_get_cur(RLIMIT_STACK) == RLIM_INFINITY)
> return 1;
>
> return sysctl_legacy_va_layout;
> @@ -77,7 +77,7 @@ static unsigned long mmap_rnd(void)
>
> static inline unsigned long mmap_base(void)
> {
> - unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur;
> + unsigned long gap = rlim_get_cur(RLIMIT_STACK);
>
> if (gap < MIN_GAP)
> gap = MIN_GAP;
> diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c
> index c4d4a19..4ef1c92 100644
> --- a/arch/powerpc/platforms/cell/spufs/coredump.c
> +++ b/arch/powerpc/platforms/cell/spufs/coredump.c
> @@ -54,7 +54,7 @@ static ssize_t do_coredump_read(int num, struct spu_context *ctx, void *buffer,
> */
> static int spufs_dump_write(struct file *file, const void *addr, int nr, loff_t *foffset)
> {
> - unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
> + unsigned long limit = rlim_get_cur(RLIMIT_CORE);
> ssize_t written;
>
> if (*foffset + nr > limit)

2009-11-28 11:10:26

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH v3 00/27] writable limits


* Jiri Slaby <[email protected]> wrote:

> Hi,
>
> I broke the threading to not mess up with the long thread.
>
> In this version I got rid of the rlim access_only ugliness.

Thanks Jiri - this series looks very clean already and the helpers make
the various usage sites easier to understand as well.

One (very small) naming suggestion, please rename:

rlim_get_cur()
rlim_get_max()
task_rlim_get_cur()
task_rlim_get_max()

To a more natural sounding scheme like:

rlimit()
rlimit_max()
task_rlimit()
task_rlimit_max()

Reasons:

- 'cur' is a misnomer that came a decade+ ago from an ABI and there's
no need to continue that bad tradition in helper functions. It can
also be confused with 'curr' which we often use for the current task.

- 'rlimit' is general meme, plus there's no need to say it out aloud
that we 'get' it - rlimit() is obvious enough.

Beyond solving these issues it makes it shorter and more logical as
well.

Thanks,

Ingo

2009-11-28 08:47:00

by Jiri Slaby

[permalink] [raw]
Subject: Re: [PATCH v3 16/27] PPC: use helpers for rlimits

On 11/28/2009 01:19 AM, Benjamin Herrenschmidt wrote:
> On Sat, 2009-11-28 at 00:05 +0100, Jiri Slaby wrote:
>> Make sure compiler won't do weird things with limits. E.g. fetching
>> them twice may return 2 different values after writable limits are
>> implemented.
>>
>> I.e. either use newly added rlimit helpers or ACCESS_ONCE if not
>> applicable.
>
> Thanks. I have that already queued up.

Are you sure? The previous version with ACCESS_ONCE was generally
NACKed. This one uses a newly added helper which is much more cleaner
way to do it.

thanks,
--
js

2009-11-28 21:17:19

by Benjamin Herrenschmidt

[permalink] [raw]
Subject: Re: [PATCH v3 16/27] PPC: use helpers for rlimits

On Sat, 2009-11-28 at 09:47 +0100, Jiri Slaby wrote:
> Are you sure? The previous version with ACCESS_ONCE was generally
> NACKed. This one uses a newly added helper which is much more cleaner
> way to do it.

I haven't seen a nack, but then I haven't pushed out yet so I can easily
back it off and replace it with this one.

Cheers,
Ben.

2009-11-29 11:06:23

by Stephen Rothwell

[permalink] [raw]
Subject: Re: [PATCH v3 16/27] PPC: use helpers for rlimits

Hi Ben,

On Sun, 29 Nov 2009 08:16:03 +1100 Benjamin Herrenschmidt <[email protected]> wrote:
>
> On Sat, 2009-11-28 at 09:47 +0100, Jiri Slaby wrote:
> > Are you sure? The previous version with ACCESS_ONCE was generally
> > NACKed. This one uses a newly added helper which is much more cleaner
> > way to do it.
>
> I haven't seen a nack, but then I haven't pushed out yet so I can easily
> back it off and replace it with this one.

You need to hold off adding this to your tree until after patch 14/27
("resource: add helpers for fetching rlimits") of this series (or a
modified version of it) reaches Linus' tree.

--
Cheers,
Stephen Rothwell [email protected]
http://www.canb.auug.org.au/~sfr/


Attachments:
(No filename) (730.00 B)
(No filename) (198.00 B)
Download all attachments

2009-12-09 23:59:17

by Roland Dreier

[permalink] [raw]
Subject: Re: [PATCH v3 23/27] misc: use helpers for rlimits

Not sure it matters at this part, but for the drivers/infiniband part,
you can add:

Acked-by: Roland Dreier <[email protected]>

wrapping all the current->signal->rlim[] stuff in a helper function
looks like a nice cleanup independent of the writable limit stuff.

- R.