linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit
@ 2010-06-23 21:52 Jiri Slaby
  2010-06-23 21:52 ` [PATCH v4 02/12] rlimits: add task_struct to update_rlimit_cpu Jiri Slaby
                   ` (11 more replies)
  0 siblings, 12 replies; 15+ messages in thread
From: Jiri Slaby @ 2010-06-23 21:52 UTC (permalink / raw)
  To: jirislaby
  Cc: Oleg Nesterov, akpm, adobriyan, nhorman, Stephen Smalley,
	James Morris, Eric Paris, linux-kernel

From: Jiri Slaby <jirislaby@gmail.com>

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

Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Acked-by: Eric Paris <eparis@redhat.com>
Acked-by: James Morris <jmorris@namei.org>
---
 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 5bcb395..a22219a 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1499,7 +1499,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);
@@ -1749,7 +1750,8 @@ void security_task_getsecid(struct task_struct *p, u32 *secid);
 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);
@@ -2311,7 +2313,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 e83ddbb..1ba4522 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1290,7 +1290,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 4aeb699..830a213 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -411,7 +411,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 7461b1b..c53949f 100644
--- a/security/security.c
+++ b/security/security.c
@@ -780,9 +780,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 5c9f25b..e3ce6b4 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3371,16 +3371,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.7.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 02/12] rlimits: add task_struct to update_rlimit_cpu
  2010-06-23 21:52 [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit Jiri Slaby
@ 2010-06-23 21:52 ` Jiri Slaby
  2010-06-23 21:52 ` [PATCH v4 03/12] rlimits: make sure ->rlim_max never grows in sys_setrlimit Jiri Slaby
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Jiri Slaby @ 2010-06-23 21:52 UTC (permalink / raw)
  To: jirislaby
  Cc: Oleg Nesterov, akpm, adobriyan, nhorman, Stephen Smalley,
	James Morris, Eric Paris, linux-kernel

From: Jiri Slaby <jirislaby@gmail.com>

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 <jirislaby@gmail.com>
Acked-by: James Morris <jmorris@namei.org>
---
 include/linux/posix-timers.h |    2 +-
 kernel/posix-cpu-timers.c    |    8 ++++----
 kernel/sys.c                 |    2 +-
 security/selinux/hooks.c     |    3 ++-
 4 files changed, 8 insertions(+), 7 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 9829646..0513900 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -16,13 +16,13 @@
  * siglock protection since other code may update expiration cache as
  * well.
  */
-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);
 
-	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);
 }
 
 static int check_clock(const clockid_t which_clock)
diff --git a/kernel/sys.c b/kernel/sys.c
index 1ba4522..f5183b0 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1320,7 +1320,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 e3ce6b4..afb18a9 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2338,7 +2338,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.7.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 03/12] rlimits: make sure ->rlim_max never grows in sys_setrlimit
  2010-06-23 21:52 [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit Jiri Slaby
  2010-06-23 21:52 ` [PATCH v4 02/12] rlimits: add task_struct to update_rlimit_cpu Jiri Slaby
@ 2010-06-23 21:52 ` Jiri Slaby
  2010-06-23 21:52 ` [PATCH v4 04/12] rlimits: selinux, do rlimits changes under task_lock Jiri Slaby
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Jiri Slaby @ 2010-06-23 21:52 UTC (permalink / raw)
  To: jirislaby
  Cc: Oleg Nesterov, akpm, adobriyan, nhorman, Stephen Smalley,
	James Morris, Eric Paris, linux-kernel

From: Oleg Nesterov <oleg@redhat.com>

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 <oleg@redhat.com>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
---
 kernel/sys.c |   15 ++++++++-------
 1 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/kernel/sys.c b/kernel/sys.c
index f5183b0..f2b2d7a 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1283,10 +1283,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;
 
@@ -1304,11 +1300,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))
+		retval = -EPERM;
+	else
+		*old_rlim = new_rlim;
 	task_unlock(current->group_leader);
 
-	if (resource != RLIMIT_CPU)
+	if (retval || resource != RLIMIT_CPU)
 		goto out;
 
 	/*
@@ -1322,7 +1323,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.7.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 04/12] rlimits: selinux, do rlimits changes under task_lock
  2010-06-23 21:52 [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit Jiri Slaby
  2010-06-23 21:52 ` [PATCH v4 02/12] rlimits: add task_struct to update_rlimit_cpu Jiri Slaby
  2010-06-23 21:52 ` [PATCH v4 03/12] rlimits: make sure ->rlim_max never grows in sys_setrlimit Jiri Slaby
@ 2010-06-23 21:52 ` Jiri Slaby
  2010-06-23 21:52 ` [PATCH v4 05/12] rlimits: split sys_setrlimit Jiri Slaby
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Jiri Slaby @ 2010-06-23 21:52 UTC (permalink / raw)
  To: jirislaby
  Cc: Oleg Nesterov, akpm, adobriyan, nhorman, Stephen Smalley,
	James Morris, Eric Paris, linux-kernel

From: Oleg Nesterov <oleg@redhat.com>

When doing an exec, selinux updates rlimits in its code of current
process depending on current max. Make sure max or cur doesn't change
in the meantime by grabbing task_lock which do_prlimit needs for
changing limits too.

While at it, use rlimit helper for accessing CPU rlimit a line below.
To have a volatile access too.

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Cc: Oleg Nesterov <oleg@redhat.com>
---
 security/selinux/hooks.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index afb18a9..2a8a0a9 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2333,13 +2333,15 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
 	rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
 			  PROCESS__RLIMITINH, NULL);
 	if (rc) {
+		/* protect against do_prlimit() */
+		task_lock(current);
 		for (i = 0; i < RLIM_NLIMITS; i++) {
 			rlim = current->signal->rlim + i;
 			initrlim = init_task.signal->rlim + i;
 			rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
 		}
-		update_rlimit_cpu(current,
-				current->signal->rlim[RLIMIT_CPU].rlim_cur);
+		task_unlock(current);
+		update_rlimit_cpu(current, rlimit(RLIMIT_CPU));
 	}
 }
 
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 05/12] rlimits: split sys_setrlimit
  2010-06-23 21:52 [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit Jiri Slaby
                   ` (2 preceding siblings ...)
  2010-06-23 21:52 ` [PATCH v4 04/12] rlimits: selinux, do rlimits changes under task_lock Jiri Slaby
@ 2010-06-23 21:52 ` Jiri Slaby
  2010-06-23 21:52 ` [PATCH v4 06/12] rlimits: allow setrlimit to non-current tasks Jiri Slaby
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Jiri Slaby @ 2010-06-23 21:52 UTC (permalink / raw)
  To: jirislaby
  Cc: Oleg Nesterov, akpm, adobriyan, nhorman, Stephen Smalley,
	James Morris, Eric Paris, linux-kernel

From: Jiri Slaby <jirislaby@gmail.com>

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>
---
 include/linux/resource.h |    2 ++
 kernel/sys.c             |   40 ++++++++++++++++++++++++----------------
 2 files changed, 26 insertions(+), 16 deletions(-)

diff --git a/include/linux/resource.h b/include/linux/resource.h
index f1e914e..cf8dc96 100644
--- a/include/linux/resource.h
+++ b/include/linux/resource.h
@@ -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__ */
 
diff --git a/kernel/sys.c b/kernel/sys.c
index f2b2d7a..b5b96e3 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -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;
@@ -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
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 06/12] rlimits: allow setrlimit to non-current tasks
  2010-06-23 21:52 [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit Jiri Slaby
                   ` (3 preceding siblings ...)
  2010-06-23 21:52 ` [PATCH v4 05/12] rlimits: split sys_setrlimit Jiri Slaby
@ 2010-06-23 21:52 ` Jiri Slaby
  2010-06-23 21:52 ` [PATCH v4 07/12] rlimits: do security check under task_lock Jiri Slaby
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Jiri Slaby @ 2010-06-23 21:52 UTC (permalink / raw)
  To: jirislaby
  Cc: Oleg Nesterov, akpm, adobriyan, nhorman, Stephen Smalley,
	James Morris, Eric Paris, linux-kernel

From: Jiri Slaby <jirislaby@gmail.com>

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.

There are some points:
1) security_task_setrlimit is now called with that lock held. This is
   not new, many security_* functions are called with this lock held
   already so it doesn't harm (all this security_* stuff does almost
   the same).
2) task->sighand->siglock (in update_rlimit_cpu) is nested in
   tasklist_lock. This dependence is already existing.
3) tsk->alloc_lock is nested in tasklist_lock. This is OK too, already
   existing dependence.

Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Oleg Nesterov <oleg@redhat.com>
---
 kernel/sys.c |   11 ++++++++++-
 1 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/kernel/sys.c b/kernel/sys.c
index b5b96e3..9dbcbbc 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1272,6 +1272,7 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
 
 #endif
 
+/* make sure you are allowed to change @tsk limits before calling this */
 int do_setrlimit(struct task_struct *tsk, unsigned int resource,
 		struct rlimit *new_rlim)
 {
@@ -1285,9 +1286,16 @@ int do_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->group_leader, resource, new_rlim);
 	if (retval)
-		return retval;
+		goto out;
 
 	if (resource == RLIMIT_CPU && new_rlim->rlim_cur == 0) {
 		/*
@@ -1322,6 +1330,7 @@ int do_setrlimit(struct task_struct *tsk, unsigned int resource,
 
 	update_rlimit_cpu(tsk, new_rlim->rlim_cur);
 out:
+	read_unlock(&tasklist_lock);
 	return retval;
 }
 
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 07/12] rlimits: do security check under task_lock
  2010-06-23 21:52 [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit Jiri Slaby
                   ` (4 preceding siblings ...)
  2010-06-23 21:52 ` [PATCH v4 06/12] rlimits: allow setrlimit to non-current tasks Jiri Slaby
@ 2010-06-23 21:52 ` Jiri Slaby
  2010-06-23 21:52 ` [PATCH v4 08/12] rlimits: add rlimit64 structure Jiri Slaby
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Jiri Slaby @ 2010-06-23 21:52 UTC (permalink / raw)
  To: jirislaby
  Cc: Oleg Nesterov, akpm, adobriyan, nhorman, Stephen Smalley,
	James Morris, Eric Paris, linux-kernel, Heiko Carstens

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.

Note that all the security work is done under a spinlock here now.
Security hooks count with that, they are called from interrupt context
(like security_task_kill) and with spinlocks already held (e.g.
capable->security_capable).

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Acked-by: James Morris <jmorris@namei.org>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
---
 kernel/sys.c |   20 ++++++++++----------
 1 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/kernel/sys.c b/kernel/sys.c
index 9dbcbbc..c762eeb 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1277,7 +1277,7 @@ int do_setrlimit(struct task_struct *tsk, unsigned int resource,
 		struct rlimit *new_rlim)
 {
 	struct rlimit *old_rlim;
-	int retval;
+	int retval = 0;
 
 	if (resource >= RLIM_NLIMITS)
 		return -EINVAL;
@@ -1293,9 +1293,14 @@ int do_setrlimit(struct task_struct *tsk, unsigned int resource,
 		goto out;
 	}
 
-	retval = security_task_setrlimit(tsk->group_leader, resource, new_rlim);
-	if (retval)
-		goto out;
+	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;
+	if (!retval)
+		retval = security_task_setrlimit(tsk->group_leader, resource,
+				new_rlim);
 
 	if (resource == RLIMIT_CPU && new_rlim->rlim_cur == 0) {
 		/*
@@ -1307,12 +1312,7 @@ int do_setrlimit(struct task_struct *tsk, unsigned int resource,
 		new_rlim->rlim_cur = 1;
 	}
 
-	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
+	if (!retval)
 		*old_rlim = *new_rlim;
 	task_unlock(tsk->group_leader);
 
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 08/12] rlimits: add rlimit64 structure
  2010-06-23 21:52 [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit Jiri Slaby
                   ` (5 preceding siblings ...)
  2010-06-23 21:52 ` [PATCH v4 07/12] rlimits: do security check under task_lock Jiri Slaby
@ 2010-06-23 21:52 ` Jiri Slaby
  2010-06-23 21:52 ` [PATCH v4 09/12] rlimits: redo do_setrlimit to more generic do_prlimit Jiri Slaby
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Jiri Slaby @ 2010-06-23 21:52 UTC (permalink / raw)
  To: jirislaby
  Cc: Oleg Nesterov, akpm, adobriyan, nhorman, Stephen Smalley,
	James Morris, Eric Paris, linux-kernel

Add a platform independent structure for resource limits to use with
a new prlimit64 syscall. This structure is the same which uses glibc
for 64-bit limits.

Also add corresponding infinity which is a 64-bit full of bit-ones.

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
---
 include/linux/resource.h |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/include/linux/resource.h b/include/linux/resource.h
index cf8dc96..037aa7e 100644
--- a/include/linux/resource.h
+++ b/include/linux/resource.h
@@ -43,6 +43,13 @@ struct rlimit {
 	unsigned long	rlim_max;
 };
 
+#define RLIM64_INFINITY		(~0ULL)
+
+struct rlimit64 {
+	__u64 rlim_cur;
+	__u64 rlim_max;
+};
+
 #define	PRIO_MIN	(-20)
 #define	PRIO_MAX	20
 
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 09/12] rlimits: redo do_setrlimit to more generic do_prlimit
  2010-06-23 21:52 [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit Jiri Slaby
                   ` (6 preceding siblings ...)
  2010-06-23 21:52 ` [PATCH v4 08/12] rlimits: add rlimit64 structure Jiri Slaby
@ 2010-06-23 21:52 ` Jiri Slaby
  2010-06-23 21:52 ` [PATCH v4 10/12] rlimits: switch more rlimit syscalls to do_prlimit Jiri Slaby
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Jiri Slaby @ 2010-06-23 21:52 UTC (permalink / raw)
  To: jirislaby
  Cc: Oleg Nesterov, akpm, adobriyan, nhorman, Stephen Smalley,
	James Morris, Eric Paris, linux-kernel

It now allows also reading of limits. I.e. all read and writes will
later use this function.

It takes two parameters, new and old limits which can be both NULL.
If new is non-NULL, the value in it is set to rlimits.
If old is non-NULL, current rlimits are stored there.
If both are non-NULL, old are stored prior to setting the new ones,
atomically.
(Similar to sigaction.)

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
---
 include/linux/resource.h |    4 +-
 kernel/sys.c             |   71 ++++++++++++++++++++++++----------------------
 2 files changed, 39 insertions(+), 36 deletions(-)

diff --git a/include/linux/resource.h b/include/linux/resource.h
index 037aa7e..88d36f9 100644
--- a/include/linux/resource.h
+++ b/include/linux/resource.h
@@ -80,8 +80,8 @@ struct rlimit64 {
 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);
+int do_prlimit(struct task_struct *tsk, unsigned int resource,
+		struct rlimit *new_rlim, struct rlimit *old_rlim);
 
 #endif /* __KERNEL__ */
 
diff --git a/kernel/sys.c b/kernel/sys.c
index c762eeb..bc7d1be 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1273,18 +1273,21 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
 #endif
 
 /* make sure you are allowed to change @tsk limits before calling this */
-int do_setrlimit(struct task_struct *tsk, unsigned int resource,
-		struct rlimit *new_rlim)
+int do_prlimit(struct task_struct *tsk, unsigned int resource,
+		struct rlimit *new_rlim, struct rlimit *old_rlim)
 {
-	struct rlimit *old_rlim;
+	struct rlimit *rlim;
 	int retval = 0;
 
 	if (resource >= RLIM_NLIMITS)
 		return -EINVAL;
-	if (new_rlim->rlim_cur > new_rlim->rlim_max)
-		return -EINVAL;
-	if (resource == RLIMIT_NOFILE && new_rlim->rlim_max > sysctl_nr_open)
-		return -EPERM;
+	if (new_rlim) {
+		if (new_rlim->rlim_cur > new_rlim->rlim_max)
+			return -EINVAL;
+		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);
@@ -1293,42 +1296,42 @@ int do_setrlimit(struct task_struct *tsk, unsigned int resource,
 		goto out;
 	}
 
-	old_rlim = tsk->signal->rlim + resource;
+	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;
-	if (!retval)
-		retval = security_task_setrlimit(tsk->group_leader, resource,
-				new_rlim);
-
-	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;
+	if (new_rlim) {
+		if (new_rlim->rlim_max > rlim->rlim_max &&
+				!capable(CAP_SYS_RESOURCE))
+			retval = -EPERM;
+		if (!retval)
+			retval = security_task_setrlimit(tsk->group_leader,
+					resource, new_rlim);
+		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;
+		}
+	}
+	if (!retval) {
+		if (old_rlim)
+			*old_rlim = *rlim;
+		if (new_rlim)
+			*rlim = *new_rlim;
 	}
-
-	if (!retval)
-		*old_rlim = *new_rlim;
 	task_unlock(tsk->group_leader);
 
-	if (retval || resource != RLIMIT_CPU)
-		goto out;
-
 	/*
 	 * RLIMIT_CPU handling.   Note that the kernel fails to return an error
 	 * code if it rejected the user's attempt to set RLIMIT_CPU.  This is a
 	 * very long-standing error, and fixing it now risks breakage of
 	 * applications, so we live with it
 	 */
-	if (new_rlim->rlim_cur == RLIM_INFINITY)
-		goto out;
-
-	update_rlimit_cpu(tsk, new_rlim->rlim_cur);
+	 if (!retval && new_rlim && resource == RLIMIT_CPU &&
+			 new_rlim->rlim_cur != RLIM_INFINITY)
+		update_rlimit_cpu(tsk, new_rlim->rlim_cur);
 out:
 	read_unlock(&tasklist_lock);
 	return retval;
@@ -1340,7 +1343,7 @@ SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
 
 	if (copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
 		return -EFAULT;
-	return do_setrlimit(current, resource, &new_rlim);
+	return do_prlimit(current, resource, &new_rlim, NULL);
 }
 
 /*
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 10/12] rlimits: switch more rlimit syscalls to do_prlimit
  2010-06-23 21:52 [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit Jiri Slaby
                   ` (7 preceding siblings ...)
  2010-06-23 21:52 ` [PATCH v4 09/12] rlimits: redo do_setrlimit to more generic do_prlimit Jiri Slaby
@ 2010-06-23 21:52 ` Jiri Slaby
  2010-06-23 21:52 ` [PATCH v4 11/12] rlimits: implement prlimit64 syscall Jiri Slaby
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Jiri Slaby @ 2010-06-23 21:52 UTC (permalink / raw)
  To: jirislaby
  Cc: Oleg Nesterov, akpm, adobriyan, nhorman, Stephen Smalley,
	James Morris, Eric Paris, linux-kernel

From: Jiri Slaby <jirislaby@gmail.com>

After we added more generic do_prlimit, switch sys_getrlimit to that.
Also switch compat handling, so we can get rid of ugly __user casts
and avoid setting process' address limit to kernel data and back.

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
---
 kernel/compat.c |   17 +++--------------
 kernel/sys.c    |   17 ++++++++---------
 2 files changed, 11 insertions(+), 23 deletions(-)

diff --git a/kernel/compat.c b/kernel/compat.c
index 5adab05..e167efc 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -279,11 +279,6 @@ asmlinkage long compat_sys_setrlimit(unsigned int resource,
 		struct compat_rlimit __user *rlim)
 {
 	struct rlimit r;
-	int ret;
-	mm_segment_t old_fs = get_fs ();
-
-	if (resource >= RLIM_NLIMITS)
-		return -EINVAL;
 
 	if (!access_ok(VERIFY_READ, rlim, sizeof(*rlim)) ||
 	    __get_user(r.rlim_cur, &rlim->rlim_cur) ||
@@ -294,10 +289,7 @@ asmlinkage long compat_sys_setrlimit(unsigned int resource,
 		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);
-	set_fs(old_fs);
-	return ret;
+	return do_prlimit(current, resource, &r, NULL);
 }
 
 #ifdef COMPAT_RLIM_OLD_INFINITY
@@ -329,16 +321,13 @@ asmlinkage long compat_sys_old_getrlimit(unsigned int resource,
 
 #endif
 
-asmlinkage long compat_sys_getrlimit (unsigned int resource,
+asmlinkage long compat_sys_getrlimit(unsigned int resource,
 		struct compat_rlimit __user *rlim)
 {
 	struct rlimit r;
 	int ret;
-	mm_segment_t old_fs = get_fs();
 
-	set_fs(KERNEL_DS);
-	ret = sys_getrlimit(resource, (struct rlimit __user *) &r);
-	set_fs(old_fs);
+	ret = do_prlimit(current, resource, NULL, &r);
 	if (!ret) {
 		if (r.rlim_cur > COMPAT_RLIM_INFINITY)
 			r.rlim_cur = COMPAT_RLIM_INFINITY;
diff --git a/kernel/sys.c b/kernel/sys.c
index bc7d1be..9da98dd 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1236,15 +1236,14 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len)
 
 SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim)
 {
-	if (resource >= RLIM_NLIMITS)
-		return -EINVAL;
-	else {
-		struct rlimit value;
-		task_lock(current->group_leader);
-		value = current->signal->rlim[resource];
-		task_unlock(current->group_leader);
-		return copy_to_user(rlim, &value, sizeof(*rlim)) ? -EFAULT : 0;
-	}
+	struct rlimit value;
+	int ret;
+
+	ret = do_prlimit(current, resource, NULL, &value);
+	if (!ret)
+		ret = copy_to_user(rlim, &value, sizeof(*rlim)) ? -EFAULT : 0;
+
+	return ret;
 }
 
 #ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 11/12] rlimits: implement prlimit64 syscall
  2010-06-23 21:52 [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit Jiri Slaby
                   ` (8 preceding siblings ...)
  2010-06-23 21:52 ` [PATCH v4 10/12] rlimits: switch more rlimit syscalls to do_prlimit Jiri Slaby
@ 2010-06-23 21:52 ` Jiri Slaby
  2010-06-23 21:52 ` [PATCH v4 12/12] unistd: add __NR_prlimit64 syscall numbers Jiri Slaby
  2010-06-23 23:58 ` [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit James Morris
  11 siblings, 0 replies; 15+ messages in thread
From: Jiri Slaby @ 2010-06-23 21:52 UTC (permalink / raw)
  To: jirislaby
  Cc: Oleg Nesterov, akpm, adobriyan, nhorman, Stephen Smalley,
	James Morris, Eric Paris, linux-kernel

This patch adds the code to support the sys_prlimit64 syscall which
modifies-and-returns the rlim values of a selected process atomically.
The first parameter, pid, being 0 means current process.

Unlike the current implementation, it is a generic interface,
architecture indepentent so that we needn't handle compat stuff
anymore. In the future, after glibc start to use this we can deprecate
sys_setrlimit and sys_getrlimit in favor to clean up the code finally.

It also adds a possibility of changing limits of other processes. We
check the user's permissions to do that and if it succeeds, the new
limits are propagated online. This is good for large scale
applications such as SAP or databases where administrators need to
change limits time by time (e.g. on crashes increase core size). And
it is unacceptable to restart the service.

For safety, all rlim users now either use accessors or doesn't need
them due to
- locking
- the fact a process was just forked and nobody else knows about it
  yet (and nobody can't thus read/write limits)
hence it is safe to modify limits now.

The limitation is that we currently stay at ulong internal
representation. So the rlim64_is_infinity check is used where value is
compared against ULONG_MAX on 32-bit which is the maximum value there.

And since internally the limits are held in struct rlimit, converters
which are used before and after do_prlimit call in sys_prlimit64 are
introduced.

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
---
 include/linux/syscalls.h |    4 ++
 kernel/sys.c             |   94 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 98 insertions(+), 0 deletions(-)

diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 3c7620c..0e3dd06 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -35,6 +35,7 @@ struct oldold_utsname;
 struct old_utsname;
 struct pollfd;
 struct rlimit;
+struct rlimit64;
 struct rusage;
 struct sched_param;
 struct sel_arg_struct;
@@ -644,6 +645,9 @@ asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit __user *r
 #endif
 asmlinkage long sys_setrlimit(unsigned int resource,
 				struct rlimit __user *rlim);
+asmlinkage long sys_prlimit64(pid_t pid, unsigned int resource,
+				const struct rlimit64 __user *new_rlim,
+				struct rlimit64 __user *old_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 9da98dd..e9ad444 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1271,6 +1271,39 @@ SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
 
 #endif
 
+static inline bool rlim64_is_infinity(__u64 rlim64)
+{
+#if BITS_PER_LONG < 64
+	return rlim64 >= ULONG_MAX;
+#else
+	return rlim64 == RLIM64_INFINITY;
+#endif
+}
+
+static void rlim_to_rlim64(const struct rlimit *rlim, struct rlimit64 *rlim64)
+{
+	if (rlim->rlim_cur == RLIM_INFINITY)
+		rlim64->rlim_cur = RLIM64_INFINITY;
+	else
+		rlim64->rlim_cur = rlim->rlim_cur;
+	if (rlim->rlim_max == RLIM_INFINITY)
+		rlim64->rlim_max = RLIM64_INFINITY;
+	else
+		rlim64->rlim_max = rlim->rlim_max;
+}
+
+static void rlim64_to_rlim(const struct rlimit64 *rlim64, struct rlimit *rlim)
+{
+	if (rlim64_is_infinity(rlim64->rlim_cur))
+		rlim->rlim_cur = RLIM_INFINITY;
+	else
+		rlim->rlim_cur = (unsigned long)rlim64->rlim_cur;
+	if (rlim64_is_infinity(rlim64->rlim_max))
+		rlim->rlim_max = RLIM_INFINITY;
+	else
+		rlim->rlim_max = (unsigned long)rlim64->rlim_max;
+}
+
 /* make sure you are allowed to change @tsk limits before calling this */
 int do_prlimit(struct task_struct *tsk, unsigned int resource,
 		struct rlimit *new_rlim, struct rlimit *old_rlim)
@@ -1336,6 +1369,67 @@ out:
 	return retval;
 }
 
+/* rcu lock must be held */
+static int check_prlimit_permission(struct task_struct *task)
+{
+	const struct cred *cred = current_cred(), *tcred;
+
+	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)) {
+		return -EPERM;
+	}
+
+	return 0;
+}
+
+SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource,
+		const struct rlimit64 __user *, new_rlim,
+		struct rlimit64 __user *, old_rlim)
+{
+	struct rlimit64 old64, new64;
+	struct rlimit old, new;
+	struct task_struct *tsk;
+	int ret;
+
+	if (new_rlim) {
+		if (copy_from_user(&new64, new_rlim, sizeof(new64)))
+			return -EFAULT;
+		rlim64_to_rlim(&new64, &new);
+	}
+
+	rcu_read_lock();
+	tsk = pid ? find_task_by_vpid(pid) : current;
+	if (!tsk) {
+		rcu_read_unlock();
+		return -ESRCH;
+	}
+	ret = check_prlimit_permission(tsk);
+	if (ret) {
+		rcu_read_unlock();
+		return ret;
+	}
+	get_task_struct(tsk);
+	rcu_read_unlock();
+
+	ret = do_prlimit(tsk, resource, new_rlim ? &new : NULL,
+			old_rlim ? &old : NULL);
+
+	if (!ret && old_rlim) {
+		rlim_to_rlim64(&old, &old64);
+		if (copy_to_user(old_rlim, &old64, sizeof(old64)))
+			ret = -EFAULT;
+	}
+
+	put_task_struct(tsk);
+	return ret;
+}
+
 SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
 {
 	struct rlimit new_rlim;
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 12/12] unistd: add __NR_prlimit64 syscall numbers
  2010-06-23 21:52 [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit Jiri Slaby
                   ` (9 preceding siblings ...)
  2010-06-23 21:52 ` [PATCH v4 11/12] rlimits: implement prlimit64 syscall Jiri Slaby
@ 2010-06-23 21:52 ` Jiri Slaby
  2010-06-23 23:58 ` [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit James Morris
  11 siblings, 0 replies; 15+ messages in thread
From: Jiri Slaby @ 2010-06-23 21:52 UTC (permalink / raw)
  To: jirislaby
  Cc: Oleg Nesterov, akpm, adobriyan, nhorman, Stephen Smalley,
	James Morris, Eric Paris, linux-kernel, Thomas Gleixner,
	Ingo Molnar, H. Peter Anvin

Add __NR_prlimit64 syscall numbers to asm-generic. Add them also to
asm-x86, both 32 and 64-bit.

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: "H. Peter Anvin" <hpa@zytor.com>
---
 arch/x86/ia32/ia32entry.S          |    1 +
 arch/x86/include/asm/unistd_32.h   |    3 ++-
 arch/x86/include/asm/unistd_64.h   |    2 ++
 arch/x86/kernel/syscall_table_32.S |    1 +
 include/asm-generic/unistd.h       |    6 ++++--
 5 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index 17cf65c..b9472ec 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -844,4 +844,5 @@ ia32_sys_call_table:
 	.quad compat_sys_recvmmsg
 	.quad sys_fanotify_init
 	.quad sys32_fanotify_mark
+	.quad sys_prlimit64			/* 340 */
 ia32_syscall_end:
diff --git a/arch/x86/include/asm/unistd_32.h b/arch/x86/include/asm/unistd_32.h
index 80b799c..b766a5e 100644
--- a/arch/x86/include/asm/unistd_32.h
+++ b/arch/x86/include/asm/unistd_32.h
@@ -345,10 +345,11 @@
 #define __NR_recvmmsg		337
 #define __NR_fanotify_init	338
 #define __NR_fanotify_mark	339
+#define __NR_prlimit64		340
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 340
+#define NR_syscalls 341
 
 #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 5b7b1d5..363e9b8 100644
--- a/arch/x86/include/asm/unistd_64.h
+++ b/arch/x86/include/asm/unistd_64.h
@@ -667,6 +667,8 @@ __SYSCALL(__NR_recvmmsg, sys_recvmmsg)
 __SYSCALL(__NR_fanotify_init, sys_fanotify_init)
 #define __NR_fanotify_mark			301
 __SYSCALL(__NR_fanotify_mark, sys_fanotify_mark)
+#define __NR_prlimit64				302
+__SYSCALL(__NR_prlimit64, sys_prlimit64)
 
 #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 07ad5eb..b35786d 100644
--- a/arch/x86/kernel/syscall_table_32.S
+++ b/arch/x86/kernel/syscall_table_32.S
@@ -339,3 +339,4 @@ ENTRY(sys_call_table)
 	.long sys_recvmmsg
 	.long sys_fanotify_init
 	.long sys_fanotify_mark
+	.long sys_prlimit64		/* 340 */
diff --git a/include/asm-generic/unistd.h b/include/asm-generic/unistd.h
index 30218b4..3d1375d 100644
--- a/include/asm-generic/unistd.h
+++ b/include/asm-generic/unistd.h
@@ -631,15 +631,17 @@ __SYSCALL(__NR_perf_event_open, sys_perf_event_open)
 __SYSCALL(__NR_accept4, sys_accept4)
 #define __NR_recvmmsg 243
 __SYSCALL(__NR_recvmmsg, sys_recvmmsg)
+#define __NR_prlimit64 244
+__SYSCALL(__NR_prlimit64, sys_prlimit64)
 
 /*
  * Architectures may provide up to 16 syscalls of their own
  * starting with this value.
  */
-#define __NR_arch_specific_syscall 244
+#define __NR_arch_specific_syscall 245
 
 #undef __NR_syscalls
-#define __NR_syscalls 260
+#define __NR_syscalls 261
 
 /*
  * All syscalls below here should go away really,
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit
  2010-06-23 21:52 [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit Jiri Slaby
                   ` (10 preceding siblings ...)
  2010-06-23 21:52 ` [PATCH v4 12/12] unistd: add __NR_prlimit64 syscall numbers Jiri Slaby
@ 2010-06-23 23:58 ` James Morris
  2010-07-02 11:30   ` Jiri Slaby
  11 siblings, 1 reply; 15+ messages in thread
From: James Morris @ 2010-06-23 23:58 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: jirislaby, Oleg Nesterov, akpm, adobriyan, nhorman,
	Stephen Smalley, Eric Paris, linux-kernel

On Wed, 23 Jun 2010, Jiri Slaby wrote:

> From: Jiri Slaby <jirislaby@gmail.com>
> 
> Add task_struct to task_setrlimit of security_operations to be able to set
> rlimit of task other than current.

Given the scope of the changes, I'm not sure which tree these should go 
into.  They affect the security API, so possibly mine.


> 
> Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
> Acked-by: Eric Paris <eparis@redhat.com>
> Acked-by: James Morris <jmorris@namei.org>
> ---
>  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 5bcb395..a22219a 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -1499,7 +1499,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);
> @@ -1749,7 +1750,8 @@ void security_task_getsecid(struct task_struct *p, u32 *secid);
>  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);
> @@ -2311,7 +2313,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 e83ddbb..1ba4522 100644
> --- a/kernel/sys.c
> +++ b/kernel/sys.c
> @@ -1290,7 +1290,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 4aeb699..830a213 100644
> --- a/security/capability.c
> +++ b/security/capability.c
> @@ -411,7 +411,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 7461b1b..c53949f 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -780,9 +780,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 5c9f25b..e3ce6b4 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -3371,16 +3371,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.7.1
> 
> 

-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit
  2010-06-23 23:58 ` [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit James Morris
@ 2010-07-02 11:30   ` Jiri Slaby
  2010-07-05  0:32     ` James Morris
  0 siblings, 1 reply; 15+ messages in thread
From: Jiri Slaby @ 2010-07-02 11:30 UTC (permalink / raw)
  To: James Morris
  Cc: Oleg Nesterov, akpm, adobriyan, nhorman, Stephen Smalley,
	Eric Paris, linux-kernel

On 06/24/2010 01:58 AM, James Morris wrote:
> On Wed, 23 Jun 2010, Jiri Slaby wrote:
>> Add task_struct to task_setrlimit of security_operations to be able to set
>> rlimit of task other than current.
> 
> Given the scope of the changes, I'm not sure which tree these should go 
> into.  They affect the security API, so possibly mine.

If there are no objections, could you take it? Or maybe Andrew, if we
persuaded him?

thanks,
-- 
js
suse labs

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit
  2010-07-02 11:30   ` Jiri Slaby
@ 2010-07-05  0:32     ` James Morris
  0 siblings, 0 replies; 15+ messages in thread
From: James Morris @ 2010-07-05  0:32 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Oleg Nesterov, akpm, adobriyan, nhorman, Stephen Smalley,
	Eric Paris, linux-kernel

On Fri, 2 Jul 2010, Jiri Slaby wrote:

> On 06/24/2010 01:58 AM, James Morris wrote:
> > On Wed, 23 Jun 2010, Jiri Slaby wrote:
> >> Add task_struct to task_setrlimit of security_operations to be able to set
> >> rlimit of task other than current.
> > 
> > Given the scope of the changes, I'm not sure which tree these should go 
> > into.  They affect the security API, so possibly mine.
> 
> If there are no objections, could you take it? Or maybe Andrew, if we
> persuaded him?

A bunch of these patches have no acked-by or reviewed-by, which means 
they still need to be reviewed.



- James
-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2010-07-05  0:32 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-06-23 21:52 [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit Jiri Slaby
2010-06-23 21:52 ` [PATCH v4 02/12] rlimits: add task_struct to update_rlimit_cpu Jiri Slaby
2010-06-23 21:52 ` [PATCH v4 03/12] rlimits: make sure ->rlim_max never grows in sys_setrlimit Jiri Slaby
2010-06-23 21:52 ` [PATCH v4 04/12] rlimits: selinux, do rlimits changes under task_lock Jiri Slaby
2010-06-23 21:52 ` [PATCH v4 05/12] rlimits: split sys_setrlimit Jiri Slaby
2010-06-23 21:52 ` [PATCH v4 06/12] rlimits: allow setrlimit to non-current tasks Jiri Slaby
2010-06-23 21:52 ` [PATCH v4 07/12] rlimits: do security check under task_lock Jiri Slaby
2010-06-23 21:52 ` [PATCH v4 08/12] rlimits: add rlimit64 structure Jiri Slaby
2010-06-23 21:52 ` [PATCH v4 09/12] rlimits: redo do_setrlimit to more generic do_prlimit Jiri Slaby
2010-06-23 21:52 ` [PATCH v4 10/12] rlimits: switch more rlimit syscalls to do_prlimit Jiri Slaby
2010-06-23 21:52 ` [PATCH v4 11/12] rlimits: implement prlimit64 syscall Jiri Slaby
2010-06-23 21:52 ` [PATCH v4 12/12] unistd: add __NR_prlimit64 syscall numbers Jiri Slaby
2010-06-23 23:58 ` [PATCH v4 01/12] rlimits: security, add task_struct to setrlimit James Morris
2010-07-02 11:30   ` Jiri Slaby
2010-07-05  0:32     ` James Morris

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).