Re: 4096 byte limit to /proc/PID/environ ?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux