linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC][PATCH] /proc/<pid>/rlimit
@ 2005-01-18 20:44 Bill Rugolsky Jr.
  2005-01-19  7:11 ` Chris Wright
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Bill Rugolsky Jr. @ 2005-01-18 20:44 UTC (permalink / raw)
  To: linux-kernel

This patch against 2.6.11-rc1-bk6 adds /proc/<pid>/rlimit to export
per-process resource limit settings.  It was written to help analyze
daemon core dump size settings, but may be more generally useful.
Tested on 2.6.10. Sample output:

	root@tiny ~ # cat /proc/$$/rlimit
	cpu unlimited unlimited
	fsize unlimited unlimited
	data unlimited unlimited
	stack 8388608 unlimited
	core 0 unlimited
	rss unlimited unlimited
	nproc 111 111
	nofile 1024 1024
	memlock 32768 32768
	as unlimited unlimited
	locks unlimited unlimited
	sigpending 1024 1024
	msgqueue 819200 819200

Feedback welcome.

Signed-off-by: Bill Rugolsky <brugolsky@telemetry-investments.com>

--- linux-2.6.11-rc1-bk6/fs/proc/base.c.rlimit	2005-01-18 15:01:10.120960254 -0500
+++ linux-2.6.11-rc1-bk6/fs/proc/base.c	2005-01-18 15:07:28.102661832 -0500
@@ -32,6 +32,7 @@
 #include <linux/mount.h>
 #include <linux/security.h>
 #include <linux/ptrace.h>
+#include <linux/resource.h>
 #include "internal.h"
 
 /*
@@ -61,6 +62,7 @@
 	PROC_TGID_MAPS,
 	PROC_TGID_MOUNTS,
 	PROC_TGID_WCHAN,
+	PROC_TGID_RLIMIT,
 #ifdef CONFIG_SCHEDSTATS
 	PROC_TGID_SCHEDSTAT,
 #endif
@@ -87,6 +89,7 @@
 	PROC_TID_MAPS,
 	PROC_TID_MOUNTS,
 	PROC_TID_WCHAN,
+	PROC_TID_RLIMIT,
 #ifdef CONFIG_SCHEDSTATS
 	PROC_TID_SCHEDSTAT,
 #endif
@@ -124,6 +127,7 @@
 	E(PROC_TGID_ROOT,      "root",    S_IFLNK|S_IRWXUGO),
 	E(PROC_TGID_EXE,       "exe",     S_IFLNK|S_IRWXUGO),
 	E(PROC_TGID_MOUNTS,    "mounts",  S_IFREG|S_IRUGO),
+	E(PROC_TGID_RLIMIT,    "rlimit",  S_IFREG|S_IRUGO),
 #ifdef CONFIG_SECURITY
 	E(PROC_TGID_ATTR,      "attr",    S_IFDIR|S_IRUGO|S_IXUGO),
 #endif
@@ -149,6 +153,7 @@
 	E(PROC_TID_ROOT,       "root",    S_IFLNK|S_IRWXUGO),
 	E(PROC_TID_EXE,        "exe",     S_IFLNK|S_IRWXUGO),
 	E(PROC_TID_MOUNTS,     "mounts",  S_IFREG|S_IRUGO),
+	E(PROC_TID_RLIMIT,     "rlimit",  S_IFREG|S_IRUGO),
 #ifdef CONFIG_SECURITY
 	E(PROC_TID_ATTR,       "attr",    S_IFDIR|S_IRUGO|S_IXUGO),
 #endif
@@ -496,6 +501,107 @@
 	.release	= mounts_release,
 };
 
+const char * const rlim_name[RLIM_NLIMITS] = {
+#ifdef RLIMIT_CPU
+	[RLIMIT_CPU] = "cpu",
+#endif
+#ifdef RLIMIT_FSIZE
+	[RLIMIT_FSIZE] = "fsize",
+#endif
+#ifdef RLIMIT_DATA
+	[RLIMIT_DATA] =  "data",
+#endif
+#ifdef RLIMIT_STACK
+	[RLIMIT_STACK] = "stack",
+#endif
+#ifdef RLIMIT_CORE
+	[RLIMIT_CORE] = "core",
+#endif
+#ifdef RLIMIT_RSS
+	[RLIMIT_RSS] = "rss",
+#endif
+#ifdef RLIMIT_NPROC
+	[RLIMIT_NPROC] = "nproc",
+#endif
+#ifdef RLIMIT_NOFILE
+	[RLIMIT_NOFILE] = "nofile",
+#endif
+#ifdef RLIMIT_MEMLOCK
+	[RLIMIT_MEMLOCK] = "memlock",
+#endif
+#ifdef RLIMIT_AS
+	[RLIMIT_AS] = "as",
+#endif
+#ifdef RLIMIT_LOCKS
+	[RLIMIT_LOCKS] = "locks",
+#endif
+#ifdef RLIMIT_SIGPENDING
+	[RLIMIT_SIGPENDING] = "sigpending",
+#endif
+#ifdef RLIMIT_MSGQUEUE
+	[RLIMIT_MSGQUEUE] = "msgqueue",
+#endif
+};
+
+static int rlimit_show(struct seq_file *s, void *v)
+{
+	struct rlimit *rlim = (struct rlimit *) s->private;
+	int i;
+
+	for (i = 0 ; i < RLIM_NLIMITS ; i++) {
+		if (rlim_name[i] != NULL)
+			seq_puts(s, rlim_name[i]);
+		else
+			seq_printf(s, "rlimit-%d", i);
+
+		if (rlim[i].rlim_cur == RLIM_INFINITY)
+			seq_puts(s, " unlimited");
+		else
+			seq_printf(s, " %lu", (unsigned long)rlim[i].rlim_cur);
+
+		if (rlim[i].rlim_max == RLIM_INFINITY)
+			seq_puts(s, " unlimited\n");
+		else
+			seq_printf(s, " %lu\n", (unsigned long)rlim[i].rlim_max);
+	}
+		return 0;
+}
+
+static int rlimit_open(struct inode *inode, struct file *file)
+{
+	struct task_struct *task = proc_task(inode);
+	struct rlimit *rlim = kmalloc(RLIM_NLIMITS * sizeof (struct rlimit), GFP_KERNEL);
+	int ret;
+
+	if (!rlim)
+		return -ENOMEM;
+
+	task_lock(task->group_leader);
+	memcpy(rlim, task->signal->rlim, RLIM_NLIMITS * sizeof (struct rlimit));
+	task_unlock(task->group_leader);
+
+	ret = single_open(file, rlimit_show, rlim);
+
+	if (ret)
+		kfree(rlim);
+
+	return ret;
+}
+
+static int rlimit_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *s = file->private_data;
+	kfree(s->private);
+	return single_release(inode, file);
+}
+
+static struct file_operations proc_rlimit_operations = {
+	.open		= rlimit_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= rlimit_release,
+};
+
 #define PROC_BLOCK_SIZE	(3*1024)		/* 4K page size but our output routines use some slack for overruns */
 
 static ssize_t proc_info_read(struct file * file, char __user * buf,
@@ -1300,6 +1406,10 @@
 		case PROC_TGID_MOUNTS:
 			inode->i_fop = &proc_mounts_operations;
 			break;
+		case PROC_TID_RLIMIT:
+		case PROC_TGID_RLIMIT:
+			inode->i_fop = &proc_rlimit_operations;
+			break;
 #ifdef CONFIG_SECURITY
 		case PROC_TID_ATTR:
 			inode->i_nlink = 2;

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

* Re: [RFC][PATCH] /proc/<pid>/rlimit
  2005-01-18 20:44 [RFC][PATCH] /proc/<pid>/rlimit Bill Rugolsky Jr.
@ 2005-01-19  7:11 ` Chris Wright
  2005-01-19 19:31 ` Jan Knutar
  2005-01-20 14:43 ` Pavel Machek
  2 siblings, 0 replies; 8+ messages in thread
From: Chris Wright @ 2005-01-19  7:11 UTC (permalink / raw)
  To: Bill Rugolsky Jr., linux-kernel

* Bill Rugolsky Jr. (brugolsky@telemetry-investments.com) wrote:
> This patch against 2.6.11-rc1-bk6 adds /proc/<pid>/rlimit to export
> per-process resource limit settings.  It was written to help analyze
> daemon core dump size settings, but may be more generally useful.
> Tested on 2.6.10. Sample output:

I can certainly see how it could be useful for debugging.  Perhaps it
should be available to only oneself (like getrlimit restriction) or
CAP_SYS_RESOURCE processes?  (Though, I'm not sure how useful the data
would be to a malicious user).  Also, since the format is both arch
dependent and release dependent I guess it's not ideal for anything that
depends on the format.

> +const char * const rlim_name[RLIM_NLIMITS] = {
> +#ifdef RLIMIT_CPU
> +	[RLIMIT_CPU] = "cpu",
> +#endif

BTW, when I went through the resource.h files, I didn't notice any that
leftout rlimits, it was only about ordering.  So I don't think those
ifdefs are necessary.

thanks,
-chris
-- 
Linux Security Modules     http://lsm.immunix.org     http://lsm.bkbits.net

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

* Re: [RFC][PATCH] /proc/<pid>/rlimit
  2005-01-18 20:44 [RFC][PATCH] /proc/<pid>/rlimit Bill Rugolsky Jr.
  2005-01-19  7:11 ` Chris Wright
@ 2005-01-19 19:31 ` Jan Knutar
  2005-01-19 19:38   ` Chris Wright
  2005-01-20 14:43 ` Pavel Machek
  2 siblings, 1 reply; 8+ messages in thread
From: Jan Knutar @ 2005-01-19 19:31 UTC (permalink / raw)
  To: Bill Rugolsky Jr., linux-kernel

On Tuesday 18 January 2005 22:44, Bill Rugolsky Jr. wrote:
> This patch against 2.6.11-rc1-bk6 adds /proc/<pid>/rlimit to export
> per-process resource limit settings.  It was written to help analyze
> daemon core dump size settings, but may be more generally useful.
> Tested on 2.6.10. Sample output:

A "cool feature" would be if you could do
echo nofile 8192 8192 >/proc/`pidof thatserverproess`/rlimit
:-)

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

* Re: [RFC][PATCH] /proc/<pid>/rlimit
  2005-01-19 19:31 ` Jan Knutar
@ 2005-01-19 19:38   ` Chris Wright
  2005-01-19 20:13     ` Bill Rugolsky Jr.
  0 siblings, 1 reply; 8+ messages in thread
From: Chris Wright @ 2005-01-19 19:38 UTC (permalink / raw)
  To: Jan Knutar; +Cc: Bill Rugolsky Jr., linux-kernel

* Jan Knutar (jk-lkml@sci.fi) wrote:
> On Tuesday 18 January 2005 22:44, Bill Rugolsky Jr. wrote:
> > This patch against 2.6.11-rc1-bk6 adds /proc/<pid>/rlimit to export
> > per-process resource limit settings.  It was written to help analyze
> > daemon core dump size settings, but may be more generally useful.
> > Tested on 2.6.10. Sample output:
> 
> A "cool feature" would be if you could do
> echo nofile 8192 8192 >/proc/`pidof thatserverproess`/rlimit
> :-)

This is security sensitive, and is currently only expected to be changed
by current.

thanks,
-chris
-- 
Linux Security Modules     http://lsm.immunix.org     http://lsm.bkbits.net

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

* Re: [RFC][PATCH] /proc/<pid>/rlimit
  2005-01-19 19:38   ` Chris Wright
@ 2005-01-19 20:13     ` Bill Rugolsky Jr.
  2005-01-19 20:47       ` Chris Wright
  0 siblings, 1 reply; 8+ messages in thread
From: Bill Rugolsky Jr. @ 2005-01-19 20:13 UTC (permalink / raw)
  To: Chris Wright; +Cc: Jan Knutar, linux-kernel

On Wed, Jan 19, 2005 at 11:38:03AM -0800, Chris Wright wrote:
> * Jan Knutar (jk-lkml@sci.fi) wrote:
> > A "cool feature" would be if you could do
> > echo nofile 8192 8192 >/proc/`pidof thatserverproess`/rlimit
> > :-)
> 
> This is security sensitive, and is currently only expected to be changed
> by current.

Sure, I had thought of implementing it, paused to consider the security
implications, and then punted.

Chris, on the other point that you made regarding UGO read access to "rlimit",
the same is true of "maps" (at least sans SELinux policy), so I don't
see an issue.  Certainly the map information is more security sensitive.

Regards,

	-Bill

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

* Re: [RFC][PATCH] /proc/<pid>/rlimit
  2005-01-19 20:13     ` Bill Rugolsky Jr.
@ 2005-01-19 20:47       ` Chris Wright
  0 siblings, 0 replies; 8+ messages in thread
From: Chris Wright @ 2005-01-19 20:47 UTC (permalink / raw)
  To: Bill Rugolsky Jr., Chris Wright, Jan Knutar, linux-kernel

* Bill Rugolsky Jr. (brugolsky@yahoo.com) wrote:
> Chris, on the other point that you made regarding UGO read access to "rlimit",
> the same is true of "maps" (at least sans SELinux policy), so I don't
> see an issue.  Certainly the map information is more security sensitive.

Yeah, I can't think of any offhand, just defaulting to paranoid ;-)

thanks,
-chris
-- 
Linux Security Modules     http://lsm.immunix.org     http://lsm.bkbits.net

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

* Re: [RFC][PATCH] /proc/<pid>/rlimit
  2005-01-18 20:44 [RFC][PATCH] /proc/<pid>/rlimit Bill Rugolsky Jr.
  2005-01-19  7:11 ` Chris Wright
  2005-01-19 19:31 ` Jan Knutar
@ 2005-01-20 14:43 ` Pavel Machek
  2005-01-21  2:19   ` Bill Rugolsky Jr.
  2 siblings, 1 reply; 8+ messages in thread
From: Pavel Machek @ 2005-01-20 14:43 UTC (permalink / raw)
  To: Bill Rugolsky Jr., linux-kernel

Hi!

> This patch against 2.6.11-rc1-bk6 adds /proc/<pid>/rlimit to export
> per-process resource limit settings.  It was written to help analyze
> daemon core dump size settings, but may be more generally useful.
> Tested on 2.6.10. Sample output:
> 
> 	root@tiny ~ # cat /proc/__/rlimit
> 	cpu unlimited unlimited
> 	fsize unlimited unlimited
> 	data unlimited unlimited
> 	stack 8388608 unlimited
> 	core 0 unlimited
> 	rss unlimited unlimited
> 	nproc 111 111
> 	nofile 1024 1024
> 	memlock 32768 32768
> 	as unlimited unlimited
> 	locks unlimited unlimited
> 	sigpending 1024 1024
> 	msgqueue 819200 819200
> 
> Feedback welcome.

It would be nice if you could make it "value-per-file". That way,
it could become writable in future. If "max nice level" ever becomes rlimit,
this would be very usefull.

				Pavel
-- 
64 bytes from 195.113.31.123: icmp_seq=28 ttl=51 time=448769.1 ms         


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

* Re: [RFC][PATCH] /proc/<pid>/rlimit
  2005-01-20 14:43 ` Pavel Machek
@ 2005-01-21  2:19   ` Bill Rugolsky Jr.
  0 siblings, 0 replies; 8+ messages in thread
From: Bill Rugolsky Jr. @ 2005-01-21  2:19 UTC (permalink / raw)
  To: Pavel Machek; +Cc: linux-kernel, Chris Wright, Jan Knutar

On Thu, Jan 20, 2005 at 03:43:58PM +0100, Pavel Machek wrote:
> It would be nice if you could make it "value-per-file". That way,
> it could become writable in future. If "max nice level" ever becomes rlimit,
> this would be very usefull.

Agreed, though write support present difficulties.

My principal concern is that we don't want users changing resource limits
of privileged processes.  If we want an ordinary user to be allowed to
change limits, the rules would have to be similar to those allowed for
ptrace(), e.g., no-setuid processes, etc.  [With ptrace(), one can of
course attach to the process and invoke the setrlimit() syscall directly].
Additionally, sys_setrlimit() has an LSM hook:

	security_task_setrlimit(unsigned int resource, struct rlimit *)

One would need to take account of changing the limit from a different
context.  It's a bit of a mess, and outside of the standard API; that's
why I didn't bother.

Anyway, for Jan, here's my incomplete and unmergeable cut-n-paste hack
to implement write on top of my previous patch.  Format is as was
suggested by Jan:

	<name|[rlimit-]%u> <%u|unlimited> <%u|unlimited>

E.g.,
	echo  memlock 65536 65536 > /proc/1/rlimit

Writing is limited to root (i.e. CAP_SYS_PTRACE), though see
fs/proc/base.c:may_ptrace_attach() for an idea of how to change that.

	-Bill


--- linux-2.6.11-rc1-bk6/fs/proc/base.c.proc-pid-rlimit-write
+++ linux-2.6.11-rc1-bk6/fs/proc/base.c
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/file.h>
 #include <linux/string.h>
+#include <linux/ctype.h>
 #include <linux/seq_file.h>
 #include <linux/namei.h>
 #include <linux/namespace.h>
@@ -127,7 +128,7 @@
 	E(PROC_TGID_ROOT,      "root",    S_IFLNK|S_IRWXUGO),
 	E(PROC_TGID_EXE,       "exe",     S_IFLNK|S_IRWXUGO),
 	E(PROC_TGID_MOUNTS,    "mounts",  S_IFREG|S_IRUGO),
-	E(PROC_TGID_RLIMIT,    "rlimit",  S_IFREG|S_IRUGO),
+	E(PROC_TGID_RLIMIT,    "rlimit",  S_IFREG|S_IRUGO|S_IWUSR),
 #ifdef CONFIG_SECURITY
 	E(PROC_TGID_ATTR,      "attr",    S_IFDIR|S_IRUGO|S_IXUGO),
 #endif
@@ -153,7 +154,7 @@
 	E(PROC_TID_ROOT,       "root",    S_IFLNK|S_IRWXUGO),
 	E(PROC_TID_EXE,        "exe",     S_IFLNK|S_IRWXUGO),
 	E(PROC_TID_MOUNTS,     "mounts",  S_IFREG|S_IRUGO),
-	E(PROC_TID_RLIMIT,     "rlimit",  S_IFREG|S_IRUGO),
+	E(PROC_TID_RLIMIT,     "rlimit",  S_IFREG|S_IRUGO|S_IWUSR),
 #ifdef CONFIG_SECURITY
 	E(PROC_TID_ATTR,       "attr",    S_IFDIR|S_IRUGO|S_IXUGO),
 #endif
@@ -595,9 +596,99 @@
 	return single_release(inode, file);
 }
 
+static inline char *skip_ws(char *s)
+{
+	while (isspace(*s))
+		s++;
+	return s;
+}
+
+static inline char *find_ws(char *s)
+{
+	while (!isspace(*s) && *s != '\0')
+		s++;
+	return s;
+}
+
+#define MAX_RLIMIT_WRITE 79
+static ssize_t rlimit_write(struct file * file, const char * buf,
+                         size_t count, loff_t *ppos)
+{
+	struct task_struct *task = proc_task(file->f_dentry->d_inode);
+	struct rlimit new_rlim, *old_rlim;
+	unsigned int i;
+	char *s, *t, kbuf[MAX_RLIMIT_WRITE+1];
+
+	/* changing resources limits can crash or subvert a process */
+	if (!capable(CAP_SYS_PTRACE) || security_ptrace(current,task))
+		return -ESRCH;
+
+        if (count > MAX_RLIMIT_WRITE)
+                return -EINVAL;
+        if (copy_from_user(&kbuf, buf, count))
+                return -EFAULT;
+        kbuf[MAX_RLIMIT_WRITE] = '\0'; 
+
+	/* parse the resource id */
+	s = skip_ws(kbuf);
+	t = find_ws(s);
+	if (*t == '\0')
+		return -EINVAL;
+	*t++ = '\0';
+	for (i = 0 ; i < RLIM_NLIMITS ; i++)
+		if (rlim_name[i] && !strcmp(s,rlim_name[i]))
+			break;
+	if (i >= RLIM_NLIMITS) {
+		if (!strncmp(s, "rlimit-",7))
+			s += 7;
+		if (sscanf(s, "%u", &i) != 1 || i >= RLIM_NLIMITS)
+			return -EINVAL;
+	}
+
+	/* parse the soft limit */
+	s = skip_ws(t);
+	t = find_ws(s);
+	if (*t == '\0')
+		return -EINVAL;
+	*t++ = '\0';
+	if (!strcmp(s, "unlimited")) 
+		new_rlim.rlim_cur = RLIM_INFINITY;
+	else if (sscanf(s, "%lu", &new_rlim.rlim_cur) != 1)
+		return -EINVAL;
+
+	/* parse the hard limit */
+	s = skip_ws(t);
+	t = find_ws(s);
+	*t = '\0';
+	if (!strcmp(s, "unlimited")) 
+		new_rlim.rlim_max = RLIM_INFINITY;
+	else if (sscanf(s, "%lu", &new_rlim.rlim_max) != 1)
+		return -EINVAL;
+
+	/* validate the values; copied from sys_setrlimit() */
+	if (new_rlim.rlim_cur > new_rlim.rlim_max)
+		return -EINVAL;
+        old_rlim = task->signal->rlim + i;
+	if ((new_rlim.rlim_max > old_rlim->rlim_max) &&
+	    !capable(CAP_SYS_RESOURCE))
+		return -EPERM;
+	if (i == RLIMIT_NOFILE && new_rlim.rlim_max > NR_OPEN)
+		return -EPERM;
+
+	/* SECURITY: missing security_task_setrlimit() equivalent */
+
+	/* set the limits */
+        task_lock(task->group_leader);
+        *old_rlim = new_rlim;
+        task_unlock(task->group_leader);
+
+	return count;
+}
+
 static struct file_operations proc_rlimit_operations = {
 	.open		= rlimit_open,
 	.read		= seq_read,
+	.write		= rlimit_write,
 	.llseek		= seq_lseek,
 	.release	= rlimit_release,
 };

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

end of thread, other threads:[~2005-01-21  2:20 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-01-18 20:44 [RFC][PATCH] /proc/<pid>/rlimit Bill Rugolsky Jr.
2005-01-19  7:11 ` Chris Wright
2005-01-19 19:31 ` Jan Knutar
2005-01-19 19:38   ` Chris Wright
2005-01-19 20:13     ` Bill Rugolsky Jr.
2005-01-19 20:47       ` Chris Wright
2005-01-20 14:43 ` Pavel Machek
2005-01-21  2:19   ` Bill Rugolsky Jr.

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).