summaryrefslogtreecommitdiffstats
path: root/fs/proc
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-01-04 16:03:48 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-01-04 16:03:48 +0000
commit78c388aed2b7184182c08428db1de6c872d815f5 (patch)
tree4b2003b1b4ceb241a17faa995da8dd1004bb8e45 /fs/proc
parenteb7a5bf93aaa4be1d7c6181100ab7639e74d67f7 (diff)
Merge with Linux 2.1.131 and more MIPS goodies.
(Did I mention that CVS is buggy ...)
Diffstat (limited to 'fs/proc')
-rw-r--r--fs/proc/array.c109
-rw-r--r--fs/proc/fd.c1
-rw-r--r--fs/proc/kmsg.c8
-rw-r--r--fs/proc/link.c7
-rw-r--r--fs/proc/mem.c6
-rw-r--r--fs/proc/openpromfs.c124
-rw-r--r--fs/proc/proc_devtree.c7
-rw-r--r--fs/proc/procfs_syms.c2
-rw-r--r--fs/proc/root.c18
9 files changed, 231 insertions, 51 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c
index eeb933628..632d7137c 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -24,11 +24,11 @@
* <Jeff_Tranter@Mitel.COM>
*
* Bruno Haible : remove 4K limit for the maps file
- * <haible@ma2s2.mathematik.uni-karlsruhe.de>
+ * <haible@ma2s2.mathematik.uni-karlsruhe.de>
*
* Yves Arrouye : remove removal of trailing spaces in get_array.
* <Yves.Arrouye@marin.fdn.fr>
-
+ *
* Jerome Forissier : added per-CPU time information to /proc/stat
* and /proc/<pid>/cpu extension
* <forissier@isia.cma.fr>
@@ -37,6 +37,11 @@
* Hans Marcus <crowbar@concepts.nl>
*
* aeb@cwi.nl : /proc/partitions
+ *
+ *
+ * Alan Cox : security fixes.
+ * <Alan.Cox@linux.org>
+ *
*/
#include <linux/types.h>
@@ -578,6 +583,29 @@ static unsigned long get_wchan(struct task_struct *p)
fp = *(unsigned long *) (fp - 12);
} while (count ++ < 16);
}
+#elif defined (__sparc__)
+ {
+ unsigned long pc, fp, bias = 0;
+ unsigned long task_base = (unsigned long) p;
+ struct reg_window *rw;
+ int count = 0;
+
+#ifdef __sparc_v9__
+ bias = STACK_BIAS;
+#endif
+ fp = p->tss.ksp + bias;
+ do {
+ /* Bogus frame pointer? */
+ if (fp < (task_base + sizeof(struct task_struct)) ||
+ fp >= (task_base + (2 * PAGE_SIZE)))
+ break;
+ rw = (struct reg_window *) fp;
+ pc = rw->ins[7];
+ if (pc < first_sched || pc >= last_sched)
+ return pc;
+ fp = rw->ins[6] + bias;
+ } while (++count < 16);
+ }
#endif
return 0;
@@ -605,7 +633,7 @@ static unsigned long get_wchan(struct task_struct *p)
if ((tsk)->tss.esp0 > PAGE_SIZE && \
MAP_NR((tsk)->tss.esp0) < max_mapnr) \
eip = ((struct pt_regs *) (tsk)->tss.esp0)->pc; \
- eip; })
+ eip; })
#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp)
#elif defined(__powerpc__)
#define KSTK_EIP(tsk) ((tsk)->tss.regs->nip)
@@ -695,16 +723,24 @@ static inline const char * get_task_state(struct task_struct *tsk)
static inline char * task_state(struct task_struct *p, char *buffer)
{
+ int g;
+
buffer += sprintf(buffer,
"State:\t%s\n"
"Pid:\t%d\n"
"PPid:\t%d\n"
"Uid:\t%d\t%d\t%d\t%d\n"
- "Gid:\t%d\t%d\t%d\t%d\n",
+ "Gid:\t%d\t%d\t%d\t%d\n"
+ "Groups:\t",
get_task_state(p),
p->pid, p->p_pptr->pid,
p->uid, p->euid, p->suid, p->fsuid,
p->gid, p->egid, p->sgid, p->fsgid);
+
+ for (g = 0; g < p->ngroups; g++)
+ buffer += sprintf(buffer, "%d ", p->groups[g]);
+
+ buffer += sprintf(buffer, "\n");
return buffer;
}
@@ -798,9 +834,9 @@ extern inline char *task_cap(struct task_struct *p, char *buffer)
return buffer + sprintf(buffer, "CapInh:\t%016x\n"
"CapPrm:\t%016x\n"
"CapEff:\t%016x\n",
- p->cap_inheritable.cap,
- p->cap_permitted.cap,
- p->cap_effective.cap);
+ cap_t(p->cap_inheritable),
+ cap_t(p->cap_permitted),
+ cap_t(p->cap_effective));
}
@@ -866,7 +902,7 @@ static int get_stat(int pid, char * buffer)
return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu\n",
+%lu %lu %lu %lu %lu %lu %lu %lu %d\n",
pid,
tsk->comm,
state,
@@ -886,7 +922,7 @@ static int get_stat(int pid, char * buffer)
tsk->times.tms_cstime,
priority,
nice,
- tsk->timeout,
+ 0UL /* removed */,
tsk->it_real_value,
tsk->start_time,
vsize,
@@ -907,7 +943,8 @@ static int get_stat(int pid, char * buffer)
sigcatch .sig[0] & 0x7fffffffUL,
wchan,
tsk->nswap,
- tsk->cnswap);
+ tsk->cnswap,
+ tsk->exit_signal);
}
static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
@@ -1246,6 +1283,11 @@ static long get_root_array(char * page, int type, char **start,
case PROC_PCI:
return get_pci_list(page);
#endif
+
+#ifdef CONFIG_NUBUS
+ case PROC_NUBUS:
+ return get_nubus_list(page);
+#endif
case PROC_CPUINFO:
return get_cpuinfo(page);
@@ -1323,6 +1365,46 @@ static long get_root_array(char * page, int type, char **start,
return -EBADF;
}
+static int process_unauthorized(int type, int pid)
+{
+ struct task_struct *p;
+ uid_t euid; /* Save the euid keep the lock short */
+
+ read_lock(&tasklist_lock);
+
+ /*
+ * Grab the lock, find the task, save the uid and
+ * check it has an mm still (ie its not dead)
+ */
+
+ p = find_task_by_pid(pid);
+ if(p)
+ {
+ euid=p->euid;
+ if(!p->mm) /* Scooby scooby doo where are you ? */
+ p=NULL;
+ }
+
+ read_unlock(&tasklist_lock);
+
+ if (!p)
+ return 1;
+
+ switch(type)
+ {
+ case PROC_PID_STATUS:
+ case PROC_PID_STATM:
+ case PROC_PID_STAT:
+ case PROC_PID_MAPS:
+ case PROC_PID_CMDLINE:
+ return 0;
+ }
+ if(capable(CAP_DAC_OVERRIDE) || current->fsuid == euid)
+ return 0;
+ return 1;
+}
+
+
static int get_process_array(char * page, int pid, int type)
{
switch (type) {
@@ -1374,6 +1456,13 @@ static ssize_t array_read(struct file * file, char * buf,
type &= 0x0000ffff;
start = NULL;
dp = (struct proc_dir_entry *) inode->u.generic_ip;
+
+ if (pid && process_unauthorized(type, pid))
+ {
+ free_page(page);
+ return -EIO;
+ }
+
if (dp->get_info)
length = dp->get_info((char *)page, &start, *ppos,
count, 0);
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 5409e2d67..8db99f7f4 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -119,6 +119,7 @@ static int proc_lookupfd(struct inode * dir, struct dentry * dentry)
ino = (pid << 16) + PROC_PID_FD_DIR + fd;
inode = proc_get_inode(dir->i_sb, ino, NULL);
if (inode) {
+ dentry->d_op = &proc_dentry_operations;
d_add(dentry, inode);
err = 0;
}
diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c
index ff8ec4877..71c5316a9 100644
--- a/fs/proc/kmsg.c
+++ b/fs/proc/kmsg.c
@@ -17,23 +17,23 @@
extern unsigned long log_size;
extern struct wait_queue * log_wait;
-asmlinkage int sys_syslog(int type, char * bug, int count);
+extern int do_syslog(int type, char * bug, int count);
static int kmsg_open(struct inode * inode, struct file * file)
{
- return sys_syslog(1,NULL,0);
+ return do_syslog(1,NULL,0);
}
static int kmsg_release(struct inode * inode, struct file * file)
{
- (void) sys_syslog(0,NULL,0);
+ (void) do_syslog(0,NULL,0);
return 0;
}
static ssize_t kmsg_read(struct file * file, char * buf,
size_t count, loff_t *ppos)
{
- return sys_syslog(2,buf,count);
+ return do_syslog(2,buf,count);
}
static unsigned int kmsg_poll(struct file *file, poll_table * wait)
diff --git a/fs/proc/link.c b/fs/proc/link.c
index df5ea85e6..70c31f21a 100644
--- a/fs/proc/link.c
+++ b/fs/proc/link.c
@@ -17,7 +17,7 @@
#include <linux/stat.h>
static int proc_readlink(struct dentry *, char *, int);
-static struct dentry * proc_follow_link(struct dentry *, struct dentry *);
+static struct dentry * proc_follow_link(struct dentry *, struct dentry *, unsigned int);
/*
* links can't do much...
@@ -57,7 +57,8 @@ struct inode_operations proc_link_inode_operations = {
};
static struct dentry * proc_follow_link(struct dentry *dentry,
- struct dentry *base)
+ struct dentry *base,
+ unsigned int follow)
{
struct inode *inode = dentry->d_inode;
struct task_struct *p;
@@ -172,7 +173,7 @@ static int proc_readlink(struct dentry * dentry, char * buffer, int buflen)
{
int error;
- dentry = proc_follow_link(dentry, NULL);
+ dentry = proc_follow_link(dentry, NULL, 1);
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
error = -ENOENT;
diff --git a/fs/proc/mem.c b/fs/proc/mem.c
index 8a8ec9bc0..117587d8d 100644
--- a/fs/proc/mem.c
+++ b/fs/proc/mem.c
@@ -215,7 +215,7 @@ int mem_mmap(struct file * file, struct vm_area_struct * vma)
pgd_t *src_dir, *dest_dir;
pmd_t *src_middle, *dest_middle;
pte_t *src_table, *dest_table;
- unsigned long stmp, dtmp;
+ unsigned long stmp, dtmp, mapnr;
struct vm_area_struct *src_vma = NULL;
struct inode *inode = file->f_dentry->d_inode;
@@ -296,7 +296,9 @@ int mem_mmap(struct file * file, struct vm_area_struct * vma)
set_pte(src_table, pte_mkdirty(*src_table));
set_pte(dest_table, *src_table);
- atomic_inc(&mem_map[MAP_NR(pte_page(*src_table))].count);
+ mapnr = MAP_NR(pte_page(*src_table));
+ if (mapnr < max_mapnr)
+ atomic_inc(&mem_map[MAP_NR(pte_page(*src_table))].count);
stmp += PAGE_SIZE;
dtmp += PAGE_SIZE;
diff --git a/fs/proc/openpromfs.c b/fs/proc/openpromfs.c
index b3871059e..2c2c84784 100644
--- a/fs/proc/openpromfs.c
+++ b/fs/proc/openpromfs.c
@@ -1,7 +1,8 @@
-/* $Id: openpromfs.c,v 1.26 1998/01/28 09:55:32 ecd Exp $
+/* $Id: openpromfs.c,v 1.32 1998/11/18 06:15:20 davem Exp $
* openpromfs.c: /proc/openprom handling routines
*
- * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996-1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
*/
#include <linux/module.h>
@@ -27,7 +28,9 @@ typedef struct {
typedef struct {
#define OPP_STRING 0x10
-#define OPP_BINARY 0x20
+#define OPP_STRINGLIST 0x20
+#define OPP_BINARY 0x40
+#define OPP_HEXSTRING 0x80
#define OPP_DIRTY 0x01
#define OPP_QUOTED 0x02
#define OPP_NOTQUOTED 0x04
@@ -83,7 +86,7 @@ static ssize_t property_read(struct file *filp, char *buf,
struct inode *inode = filp->f_dentry->d_inode;
int i, j, k;
u32 node;
- char *p;
+ char *p, *s;
u32 *q;
openprom_property *op;
char buffer[64];
@@ -129,28 +132,51 @@ static ssize_t property_read(struct file *filp, char *buf,
return -EIO;
op->value [k] = 0;
if (k) {
- for (p = op->value; *p >= ' ' && *p <= '~'; p++);
- if (p >= op->value + k - 1 && !*p) {
- op->flag |= OPP_STRING;
- if (p == op->value + k - 1) {
- op->flag |= OPP_ASCIIZ;
- op->len--;
+ for (s = 0, p = op->value; p < op->value + k; p++) {
+ if ((*p >= ' ' && *p <= '~') || *p == '\n') {
+ op->flag |= OPP_STRING;
+ s = p;
+ continue;
}
- } else if (!(k & 3))
- op->flag |= OPP_BINARY;
- else {
- printk ("/proc/openprom: Strange property "
- "size %d\n", i);
- return -EIO;
+ if (p > op->value && !*p && s == p - 1) {
+ if (p < op->value + k - 1)
+ op->flag |= OPP_STRINGLIST;
+ else
+ op->flag |= OPP_ASCIIZ;
+ continue;
+ }
+ if (k == 1 && !*p) {
+ op->flag |= (OPP_STRING|OPP_ASCIIZ);
+ break;
+ }
+ op->flag &= ~(OPP_STRING|OPP_STRINGLIST);
+ if (k & 3)
+ op->flag |= OPP_HEXSTRING;
+ else
+ op->flag |= OPP_BINARY;
+ break;
}
+ if (op->flag & OPP_STRINGLIST)
+ op->flag &= ~(OPP_STRING);
+ if (op->flag & OPP_ASCIIZ)
+ op->len--;
}
} else
op = (openprom_property *)filp->private_data;
- if (!count || !op->len) return 0;
- if (op->flag & OPP_STRING)
+ if (!count || !(op->len || (op->flag & OPP_ASCIIZ)))
+ return 0;
+ if (op->flag & OPP_STRINGLIST) {
+ for (k = 0, p = op->value; p < op->value + op->len; p++)
+ if (!*p)
+ k++;
+ i = op->len + 4 * k + 3;
+ } else if (op->flag & OPP_STRING) {
i = op->len + 3;
- else
- i = (op->len * 9)>>2;
+ } else if (op->flag & OPP_BINARY) {
+ i = (op->len * 9) >> 2;
+ } else {
+ i = (op->len << 1) + 1;
+ }
k = filp->f_pos;
if (k >= i) return 0;
if (count > i - k) count = i - k;
@@ -160,20 +186,48 @@ static ssize_t property_read(struct file *filp, char *buf,
k++;
count--;
}
+
if (k + count >= i - 2)
j = i - 2 - k;
else
j = count;
+
if (j >= 0) {
copy_to_user(buf + k - filp->f_pos,
op->value + k - 1, j);
count -= j;
k += j;
}
+
if (count)
__put_user('\'', &buf [k++ - filp->f_pos]);
if (count > 1)
__put_user('\n', &buf [k++ - filp->f_pos]);
+
+ } else if (op->flag & OPP_STRINGLIST) {
+ char *tmp;
+
+ tmp = kmalloc (i, GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ s = tmp;
+ *s++ = '\'';
+ for (p = op->value; p < op->value + op->len; p++) {
+ if (!*p) {
+ strcpy(s, "' + '");
+ s += 5;
+ continue;
+ }
+ *s++ = *p;
+ }
+ strcpy(s, "'\n");
+
+ copy_to_user(buf, tmp + k, count);
+
+ kfree(tmp);
+ k += count;
+
} else if (op->flag & OPP_BINARY) {
char buffer[10];
u32 *first, *last;
@@ -205,9 +259,35 @@ static ssize_t property_read(struct file *filp, char *buf,
}
}
}
+
if (last == (u32 *)(op->value + op->len - 4) && last_cnt == 9)
__put_user('\n', (buf - 1));
+
k += count;
+
+ } else if (op->flag & OPP_HEXSTRING) {
+ char buffer[2];
+
+ if ((k < i - 1) && (k & 1)) {
+ sprintf (buffer, "%02x", *(op->value + (k >> 1)));
+ __put_user(buffer[1], &buf[k++ - filp->f_pos]);
+ count--;
+ }
+
+ for (; (count > 1) && (k < i - 1); k += 2) {
+ sprintf (buffer, "%02x", *(op->value + (k >> 1)));
+ copy_to_user (buf + k - filp->f_pos, buffer, 2);
+ count -= 2;
+ }
+
+ if (count && (k < i - 1)) {
+ sprintf (buffer, "%02x", *(op->value + (k >> 1)));
+ __put_user(buffer[0], &buf[k++ - filp->f_pos]);
+ count--;
+ }
+
+ if (count)
+ __put_user('\n', &buf [k++ - filp->f_pos]);
}
count = k - filp->f_pos;
filp->f_pos = k;
@@ -742,6 +822,10 @@ static int openpromfs_lookup(struct inode * dir, struct dentry *dentry)
inode->i_rdev = d->rdev;
break;
}
+
+ inode->i_gid = 0;
+ inode->i_uid = 0;
+
d_add(dentry, inode);
return 0;
}
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
index c53a440fe..cd4aca324 100644
--- a/fs/proc/proc_devtree.c
+++ b/fs/proc/proc_devtree.c
@@ -42,7 +42,7 @@ static int property_read_proc(char *page, char **start, off_t off,
*/
static int devtree_readlink(struct dentry *, char *, int);
-static struct dentry *devtree_follow_link(struct dentry *, struct dentry *);
+static struct dentry *devtree_follow_link(struct dentry *, struct dentry *, unsigned int);
struct inode_operations devtree_symlink_inode_operations = {
NULL, /* no file-operations */
@@ -66,7 +66,8 @@ struct inode_operations devtree_symlink_inode_operations = {
};
static struct dentry *devtree_follow_link(struct dentry *dentry,
- struct dentry *base)
+ struct dentry *base,
+ unsigned int follow)
{
struct inode *inode = dentry->d_inode;
struct proc_dir_entry * de;
@@ -74,7 +75,7 @@ static struct dentry *devtree_follow_link(struct dentry *dentry,
de = (struct proc_dir_entry *) inode->u.generic_ip;
link = (char *) de->data;
- return lookup_dentry(link, base, 1);
+ return lookup_dentry(link, base, follow);
}
static int devtree_readlink(struct dentry *dentry, char *buffer, int buflen)
diff --git a/fs/proc/procfs_syms.c b/fs/proc/procfs_syms.c
index 6a6ef687e..5537a35e6 100644
--- a/fs/proc/procfs_syms.c
+++ b/fs/proc/procfs_syms.c
@@ -13,7 +13,9 @@ extern int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
extern struct inode_operations proc_scsi_inode_operations;
extern struct proc_dir_entry proc_sys_root;
+#ifdef CONFIG_SYSCTL
EXPORT_SYMBOL(proc_sys_root);
+#endif
EXPORT_SYMBOL(proc_register);
EXPORT_SYMBOL(proc_unregister);
EXPORT_SYMBOL(create_proc_entry);
diff --git a/fs/proc/root.c b/fs/proc/root.c
index e2889d123..5f3044f1f 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -55,9 +55,6 @@ static struct file_operations proc_dir_operations = {
NULL /* can't fsync */
};
-int proc_readlink(struct dentry * dentry, char * buffer, int buflen);
-struct dentry * proc_follow_link(struct dentry *dentry, struct dentry *base);
-
/*
* proc directories can do almost nothing..
*/
@@ -388,12 +385,13 @@ static int proc_self_readlink(struct dentry *dentry, char *buffer, int buflen)
}
static struct dentry * proc_self_follow_link(struct dentry *dentry,
- struct dentry *base)
+ struct dentry *base,
+ unsigned int follow)
{
char tmp[30];
sprintf(tmp, "%d", current->pid);
- return lookup_dentry(tmp, base, 1);
+ return lookup_dentry(tmp, base, follow);
}
int proc_readlink(struct dentry * dentry, char * buffer, int buflen)
@@ -420,7 +418,7 @@ int proc_readlink(struct dentry * dentry, char * buffer, int buflen)
return len;
}
-struct dentry * proc_follow_link(struct dentry * dentry, struct dentry *base)
+struct dentry * proc_follow_link(struct dentry * dentry, struct dentry *base, unsigned int follow)
{
struct inode *inode = dentry->d_inode;
struct proc_dir_entry * de;
@@ -435,7 +433,7 @@ struct dentry * proc_follow_link(struct dentry * dentry, struct dentry *base)
if (de->readlink_proc)
len = de->readlink_proc(de, page);
- d = lookup_dentry(page, base, 1);
+ d = lookup_dentry(page, base, follow);
free_page((unsigned long) page);
return d;
}
@@ -742,7 +740,7 @@ proc_delete_dentry(struct dentry * dentry)
d_drop(dentry);
}
-static struct dentry_operations proc_dentry_operations =
+struct dentry_operations proc_dentry_operations =
{
NULL, /* revalidate */
NULL, /* d_hash */
@@ -839,6 +837,7 @@ static int proc_root_lookup(struct inode * dir, struct dentry * dentry)
inode = proc_get_inode(dir->i_sb, ino, &proc_pid);
if (!inode)
return -EINVAL;
+ inode->i_flags|=S_IMMUTABLE;
}
dentry->d_op = &proc_dentry_operations;
@@ -955,6 +954,7 @@ static int proc_root_readdir(struct file * filp,
for (i = 0; i < nr_pids; i++) {
int pid = pid_array[i];
+ ino_t ino = (pid << 16) + PROC_PID_INO;
unsigned long j = PROC_NUMBUF;
do {
@@ -963,7 +963,7 @@ static int proc_root_readdir(struct file * filp,
pid /= 10;
} while (pid);
- if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, (pid << 16) + PROC_PID_INO) < 0)
+ if (filldir(dirent, buf+j, PROC_NUMBUF-j, filp->f_pos, ino) < 0)
break;
filp->f_pos++;
}