public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* 4096 byte limit to /proc/PID/environ ?
@ 2006-05-24 15:54 James Pearson
  2006-05-24 16:46 ` linux-os (Dick Johnson)
  0 siblings, 1 reply; 25+ messages in thread
From: James Pearson @ 2006-05-24 15:54 UTC (permalink / raw)
  To: linux-kernel

It appears that /proc/PID/environ only returns the first 4096 bytes of a 
processes' environment.

Is there any other way via userland to get the whole environment for a 
process?

Thanks

James Pearson


^ permalink raw reply	[flat|nested] 25+ messages in thread
* Re: 4096 byte limit to /proc/PID/environ ?
@ 2006-05-24 19:45 James Pearson
  2006-05-24 20:29 ` H. Peter Anvin
       [not found] ` <200605242029.k4OKTn9C031700@terminus.zytor.com>
  0 siblings, 2 replies; 25+ messages in thread
From: James Pearson @ 2006-05-24 19:45 UTC (permalink / raw)
  To: linux-kernel

H. Peter Anvin wrote:
>> 
>> I'm not worried about that - more the fact that when I do:
>> 
>> % cat /proc/$$/environ | wc -c
>> 4096
>> % env | wc -c
>> 7329
>> 
>> /proc/PID/environ is truncated ...
>> 
> 
> Funny enough, I was looking at this yesterday.  I think there is a
> pretty clean solution for it, I just haven't had a chance to attack it
> yet.

Having a poke about in fs/proc/, I came up with this - probably isn't 
pretty or clean, but it works ...

James Pearson

--- ./include/linux/proc_fs.h.dist      2006-05-11 02:56:24.000000000 +0100
+++ ./include/linux/proc_fs.h   2006-05-24 13:43:55.964159897 +0100
@@ -250,7 +250,7 @@
         int type;
         union {
                 int (*proc_get_link)(struct inode *, struct dentry **, 
struct vfsmount **);
-               int (*proc_read)(struct task_struct *task, char *page);
+               int (*proc_read)(struct task_struct *task, char *page, 
loff_t *pos);
         } op;
         struct proc_dir_entry *pde;
         struct inode vfs_inode;
--- ./fs/proc/base.c.dist       2006-05-11 02:56:24.000000000 +0100
+++ ./fs/proc/base.c    2006-05-24 13:54:26.370965292 +0100
@@ -409,15 +409,27 @@
          (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \
          security_ptrace(current,task) == 0))

-static int proc_pid_environ(struct task_struct *task, char * buffer)
+static int proc_pid_environ(struct task_struct *task, char * buffer, 
loff_t *pos)
  {
         int res = 0;
+       int p = *pos;
         struct mm_struct *mm = get_task_mm(task);
+
+       /* proc_pid_environ is a 'special case' - the required data could
+          be larger than a page, so we read sequential chunks of the
+          environment data into the buffer using the supplied offset */
+       if (p < 0)
+               return -EINVAL;
+
         if (mm) {
-               unsigned int len = mm->env_end - mm->env_start;
+               unsigned int len = mm->env_end - (mm->env_start + p);
                 if (len > PAGE_SIZE)
                         len = PAGE_SIZE;
-               res = access_process_vm(task, mm->env_start, buffer, 
len, 0);
+               res = access_process_vm(task, (mm->env_start + p), 
buffer, len, 0);
+               /* the calling routine (proc_info_read) needs to know we've
+                  used the offset to read the pid data */
+               *pos += res;
+
                 if (!ptrace_may_attach(task))
                         res = -ESRCH;
                 mmput(mm);
@@ -425,7 +437,7 @@
         return res;
  }

-static int proc_pid_cmdline(struct task_struct *task, char * buffer)
+static int proc_pid_cmdline(struct task_struct *task, char * buffer, 
loff_t *pos)
  {
         int res = 0;
         unsigned int len;
@@ -462,7 +474,7 @@
         return res;
  }

-static int proc_pid_auxv(struct task_struct *task, char *buffer)
+static int proc_pid_auxv(struct task_struct *task, char *buffer, loff_t 
*pos)
  {
         int res = 0;
         struct mm_struct *mm = get_task_mm(task);
@@ -486,7 +498,7 @@
   * Provides a wchan file via kallsyms in a proper one-value-per-file 
format.
   * Returns the resolved symbol.  If that fails, simply return the address.
   */
-static int proc_pid_wchan(struct task_struct *task, char *buffer)
+static int proc_pid_wchan(struct task_struct *task, char *buffer, 
loff_t *pos)
  {
         char *modname;
         const char *sym_name;
@@ -506,7 +518,7 @@
  /*
   * Provides /proc/PID/schedstat
   */
-static int proc_pid_schedstat(struct task_struct *task, char *buffer)
+static int proc_pid_schedstat(struct task_struct *task, char *buffer, 
loff_t *pos)
  {
         return sprintf(buffer, "%lu %lu %lu\n",
                         task->sched_info.cpu_time,
@@ -517,7 +529,7 @@

  /* The badness from the OOM killer */
  unsigned long badness(struct task_struct *p, unsigned long uptime);
-static int proc_oom_score(struct task_struct *task, char *buffer)
+static int proc_oom_score(struct task_struct *task, char *buffer, 
loff_t *pos)
  {
         unsigned long points;
         struct timespec uptime;
@@ -745,16 +757,30 @@
         unsigned long page;
         ssize_t length;
         struct task_struct *task = proc_task(inode);
+       loff_t pos = *ppos;

         if (count > PROC_BLOCK_SIZE)
                 count = PROC_BLOCK_SIZE;
         if (!(page = __get_free_page(GFP_KERNEL)))
                 return -ENOMEM;

-       length = PROC_I(inode)->op.proc_read(task, (char*)page);
+       length = PROC_I(inode)->op.proc_read(task, (char*)page, &pos);

-       if (length >= 0)
-               length = simple_read_from_buffer(buf, count, ppos, (char 
*)page, length);
+       if (length >= 0) {
+               if (pos != *ppos) {
+                       /* we are using the buffer to store subsequent 
sections
+                          of the proc_pid data - so the offset into the 
buffer
+                          will always be 0 - the offset is used to get the
+                          original data */
+                       pos = 0;
+                       length = simple_read_from_buffer(buf, count, 
&pos, (char *)page, length);
+                       /* need to update the 'real' offset into the data we
+                          are reading ... */
+                       *ppos += length;
+               }
+               else
+                       length = simple_read_from_buffer(buf, count, 
ppos, (char *)page, length);
+       }
         free_page(page);
         return length;
  }
--- ./fs/proc/internal.h.dist   2006-05-11 02:56:24.000000000 +0100
+++ ./fs/proc/internal.h        2006-05-24 13:52:53.568391757 +0100
@@ -32,10 +32,10 @@

  extern void create_seq_entry(char *name, mode_t mode, struct 
file_operations *f);
  extern int proc_exe_link(struct inode *, struct dentry **, struct 
vfsmount **);
-extern int proc_tid_stat(struct task_struct *,  char *);
-extern int proc_tgid_stat(struct task_struct *, char *);
-extern int proc_pid_status(struct task_struct *, char *);
-extern int proc_pid_statm(struct task_struct *, char *);
+extern int proc_tid_stat(struct task_struct *,  char *, loff_t *);
+extern int proc_tgid_stat(struct task_struct *, char *, loff_t *);
+extern int proc_pid_status(struct task_struct *, char *, loff_t *);
+extern int proc_pid_statm(struct task_struct *, char *, loff_t *);

  void free_proc_entry(struct proc_dir_entry *de);

--- ./fs/proc/array.c.dist      2006-05-11 02:56:24.000000000 +0100
+++ ./fs/proc/array.c   2006-05-24 13:43:09.327905203 +0100
@@ -293,7 +293,7 @@
                             cap_t(p->cap_effective));
  }

-int proc_pid_status(struct task_struct *task, char * buffer)
+int proc_pid_status(struct task_struct *task, char * buffer, loff_t *pos)
  {
         char * orig = buffer;
         struct mm_struct *mm = get_task_mm(task);
@@ -465,17 +465,17 @@
         return res;
  }

-int proc_tid_stat(struct task_struct *task, char * buffer)
+int proc_tid_stat(struct task_struct *task, char * buffer, loff_t *pos)
  {
         return do_task_stat(task, buffer, 0);
  }

-int proc_tgid_stat(struct task_struct *task, char * buffer)
+int proc_tgid_stat(struct task_struct *task, char * buffer, loff_t *pos)
  {
         return do_task_stat(task, buffer, 1);
  }

-int proc_pid_statm(struct task_struct *task, char *buffer)
+int proc_pid_statm(struct task_struct *task, char *buffer, loff_t *pos)
  {
         int size = 0, resident = 0, shared = 0, text = 0, lib = 0, data 
= 0;
         struct mm_struct *mm = get_task_mm(task);


^ permalink raw reply	[flat|nested] 25+ messages in thread
* Re: 4096 byte limit to /proc/PID/environ ?
@ 2007-09-06 16:38 James Pearson
  2007-09-18 14:09 ` Anton Arapov
  0 siblings, 1 reply; 25+ messages in thread
From: James Pearson @ 2007-09-06 16:38 UTC (permalink / raw)
  To: linux-kernel; +Cc: aarapov, adobriyan, hpa

H. Peter Anvin wrote:
> 
> Right, also please use use checkpatch.pl.
> 

OK - how about:


/proc/PID/environ currently truncates at 4096 characters, patch based on 
the /proc/PID/mem code.

Patch against 2.6.23-rc5

Signed-off-by: James Pearson <james-p@moving-picture.com>

--- ./fs/proc/base.c.dist	2007-09-01 07:08:24.000000000 +0100
+++ ./fs/proc/base.c	2007-09-06 14:29:46.413680554 +0100
@@ -199,27 +199,6 @@ static int proc_root_link(struct inode *
 	 (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \
 	 security_ptrace(current,task) == 0))
 
-static int proc_pid_environ(struct task_struct *task, char * buffer)
-{
-	int res = 0;
-	struct mm_struct *mm = get_task_mm(task);
-	if (mm) {
-		unsigned int len;
-
-		res = -ESRCH;
-		if (!ptrace_may_attach(task))
-			goto out;
-
-		len  = mm->env_end - mm->env_start;
-		if (len > PAGE_SIZE)
-			len = PAGE_SIZE;
-		res = access_process_vm(task, mm->env_start, buffer, len, 0);
-out:
-		mmput(mm);
-	}
-	return res;
-}
-
 static int proc_pid_cmdline(struct task_struct *task, char * buffer)
 {
 	int res = 0;
@@ -658,6 +637,79 @@ static const struct file_operations proc
 	.open		= mem_open,
 };
 
+static ssize_t environ_read(struct file *file, char __user *buf,
+			size_t count, loff_t *ppos)
+{
+	struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+	char *page;
+	unsigned long src = *ppos;
+	int ret = -ESRCH;
+	struct mm_struct *mm;
+	size_t max_len;
+
+	if (!task)
+		goto out_no_task;
+
+	if (!ptrace_may_attach(task))
+		goto out;
+
+	ret = -ENOMEM;
+	page = (char *)__get_free_page(GFP_USER);
+	if (!page)
+		goto out;
+
+	ret = 0;
+
+	mm = get_task_mm(task);
+	if (!mm)
+		goto out_free;
+
+	max_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+
+	while (count > 0) {
+		int this_len, retval;
+
+		this_len = mm->env_end - (mm->env_start + src);
+
+		if (this_len <= 0)
+			break;
+
+		if (this_len > max_len)
+			this_len = max_len;
+
+		retval = access_process_vm(task, (mm->env_start + src),
+			page, this_len, 0);
+
+		if (retval <= 0) {
+			ret = retval;
+			break;
+		}
+
+		if (copy_to_user(buf, page, retval)) {
+			ret = -EFAULT;
+			break;
+		}
+
+		ret += retval;
+		src += retval;
+		buf += retval;
+		count -= retval;
+	}
+	*ppos = src;
+
+	mmput(mm);
+out_free:
+	free_page((unsigned long) page);
+out:
+	put_task_struct(task);
+out_no_task:
+	return ret;
+}
+
+static const struct file_operations proc_environ_operations = {
+	.read		= environ_read,
+};
+
 static ssize_t oom_adjust_read(struct file *file, char __user *buf,
 				size_t count, loff_t *ppos)
 {
@@ -2048,7 +2100,7 @@ static const struct pid_entry tgid_base_
 	DIR("task",       S_IRUGO|S_IXUGO, task),
 	DIR("fd",         S_IRUSR|S_IXUSR, fd),
 	DIR("fdinfo",     S_IRUSR|S_IXUSR, fdinfo),
-	INF("environ",    S_IRUSR, pid_environ),
+	REG("environ",    S_IRUSR, environ),
 	INF("auxv",       S_IRUSR, pid_auxv),
 	INF("status",     S_IRUGO, pid_status),
 #ifdef CONFIG_SCHED_DEBUG
@@ -2335,7 +2387,7 @@ out_no_task:
 static const struct pid_entry tid_base_stuff[] = {
 	DIR("fd",        S_IRUSR|S_IXUSR, fd),
 	DIR("fdinfo",    S_IRUSR|S_IXUSR, fdinfo),
-	INF("environ",   S_IRUSR, pid_environ),
+	REG("environ",   S_IRUSR, environ),
 	INF("auxv",      S_IRUSR, pid_auxv),
 	INF("status",    S_IRUGO, pid_status),
 #ifdef CONFIG_SCHED_DEBUG

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

end of thread, other threads:[~2007-09-18 17:10 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-05-24 15:54 4096 byte limit to /proc/PID/environ ? James Pearson
2006-05-24 16:46 ` linux-os (Dick Johnson)
2006-05-24 16:59   ` James Pearson
2006-05-24 17:56     ` H. Peter Anvin
  -- strict thread matches above, loose matches on Subject: below --
2006-05-24 19:45 James Pearson
2006-05-24 20:29 ` H. Peter Anvin
     [not found] ` <200605242029.k4OKTn9C031700@terminus.zytor.com>
2006-06-01 14:11   ` James Pearson
2007-08-15 16:54     ` Guy Streeter
2007-08-15 17:25       ` H. Peter Anvin
2007-08-21 14:40         ` Guy Streeter
2007-08-30 13:53         ` James Pearson
2007-09-03  8:17           ` Anton Arapov
2007-09-05  7:49           ` Anton Arapov
2007-09-05  7:58             ` H. Peter Anvin
2007-09-05 17:00               ` James Pearson
2007-09-05 17:18                 ` Randy Dunlap
2007-09-06  9:23                   ` James Pearson
2007-09-05 17:22                 ` Alexey Dobriyan
2007-09-06  9:31                   ` James Pearson
2007-09-06 12:31                 ` Jan Engelhardt
2007-09-06 12:34                   ` H. Peter Anvin
2007-09-06 12:34                   ` Anton Arapov
2007-09-06 16:38 James Pearson
2007-09-18 14:09 ` Anton Arapov
2007-09-18 17:09   ` H. Peter Anvin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox