[549] in linux-security and linux-alert archive
Re: /proc insecurity
daemon@ATHENA.MIT.EDU (Ian Jackson)
Fri Jan 5 15:04:07 1996
Date: Fri, 5 Jan 96 14:25 GMT
From: Ian Jackson <ian@chiark.chu.cam.ac.uk>
To: linux-kernel@vger.rutgers.edu, linux-security@tarsier.cv.nrao.edu
In-Reply-To: <199601032033.VAA13830@i17linuxb.ists.pwr.wroc.pl>
Marek Michalkiewicz writes ("/proc insecurity"):
> As we probably already know, the /proc filesystem still has security
> problems. [...]
>
> 1.2.xx
> ======
>
> For 1.2.xx, there is an additional problem with /proc permissions
> getting out of sync with reality. This has been fixed somewhere in
> 1.3.xx, but probably requires too many changes to put it 1.2.xx.
>
> The only simple fix I can see for 1.2.xx is to make /proc/<pid>/*
> owned by root for all processes.
I have done this, and it works. My patch is below. You have to mount
the procfs with -o paranoid for it to take effect.
I've also prevented /proc/<pid>/fd from working, as you can otherwise
steal filedescriptors in much the same way as you describe.
> This may break some things (strace will not show data passed to system
> calls using pointers, it will only show the pointers), but at least
> you can have a choice: less insecure /proc (default) and a few things
> broken slightly, or the old behaviour (using the "insecure" /proc mount
> option) if you don't care about security.
>
> BTW: strace is not a Linux-specific program (the source says it works
> on sunos4 too, which has no /proc filesystem) - it should be possible
> to modify it so that it does not assume /proc/<pid>/mem is available.
> If it isn't, fall back to using the ptrace system call. Possible?
Yes, possible - I even tried it. Unfortunately I couldn't get even
the unmodified Debian strace source package to compile on my system.
So, in the meantime strace doesn't work properly. *sigh*
Ian.
diff -ru --exclude=*.o --exclude=.depend linux-1.2.13/fs/proc/base.c linux-1.2.13-procpar/fs/proc/base.c
--- linux-1.2.13/fs/proc/base.c Sat Oct 22 15:41:18 1994
+++ linux-1.2.13-procpar/fs/proc/base.c Wed Sep 27 21:35:29 1995
@@ -67,6 +67,13 @@
#define NR_BASE_DIRENTRY ((sizeof (base_dir))/(sizeof (base_dir[0])))
+int proc_paranoid(struct inode *i) {
+ if (i->i_sb->s_mounted->i_mode & S_ISVTX)
+ return 1;
+ else
+ return 0;
+}
+
int proc_match(int len,const char * name,struct proc_dir_entry * de)
{
if (!de || !de->low_ino)
diff -ru --exclude=*.o --exclude=.depend linux-1.2.13/fs/proc/inode.c linux-1.2.13-procpar/fs/proc/inode.c
--- linux-1.2.13/fs/proc/inode.c Tue Aug 1 11:06:57 1995
+++ linux-1.2.13-procpar/fs/proc/inode.c Thu Sep 28 01:52:26 1995
@@ -45,7 +45,7 @@
};
-static int parse_options(char *options,uid_t *uid,gid_t *gid)
+static int parse_options(char *options,uid_t *uid,gid_t *gid,mode_t *mode)
{
char *this_char,*value;
@@ -69,6 +69,11 @@
if (*value)
return 0;
}
+ else if (!strcmp(this_char,"paranoid")) {
+ if (value)
+ return 0;
+ *mode |= S_ISVTX; /* sticky bit represents paranoia */
+ }
else return 0;
}
return 1;
@@ -89,7 +94,8 @@
printk("get root inode failed\n");
return NULL;
}
- parse_options(data, &s->s_mounted->i_uid, &s->s_mounted->i_gid);
+ parse_options(data, &s->s_mounted->i_uid, &s->s_mounted->i_gid,
+ &s->s_mounted->i_mode);
return s;
}
@@ -206,22 +212,34 @@
return;
case PROC_PID_MEM:
inode->i_op = &proc_mem_inode_operations;
- inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
+ if (proc_paranoid(inode))
+ inode->i_mode = S_IFREG;
+ else
+ inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
return;
case PROC_PID_CWD:
case PROC_PID_ROOT:
case PROC_PID_EXE:
inode->i_op = &proc_link_inode_operations;
inode->i_size = 64;
- inode->i_mode = S_IFLNK | S_IRWXU;
+ if (proc_paranoid(inode))
+ inode->i_mode = S_IFLNK;
+ else
+ inode->i_mode = S_IFLNK | S_IRWXU;
return;
case PROC_PID_FD:
- inode->i_mode = S_IFDIR | S_IRUSR | S_IXUSR;
+ if (proc_paranoid(inode))
+ inode->i_mode = S_IFDIR;
+ else
+ inode->i_mode = S_IFDIR | S_IRUSR | S_IXUSR;
inode->i_op = &proc_fd_inode_operations;
inode->i_nlink = 2;
return;
case PROC_PID_ENVIRON:
- inode->i_mode = S_IFREG | S_IRUSR;
+ if (proc_paranoid(inode))
+ inode->i_mode = S_IFREG;
+ else
+ inode->i_mode = S_IFREG | S_IRUSR;
inode->i_op = &proc_array_inode_operations;
return;
case PROC_PID_CMDLINE:
@@ -243,10 +261,12 @@
inode->i_op = &proc_link_inode_operations;
inode->i_size = 64;
inode->i_mode = S_IFLNK;
- if (p->files->fd[ino]->f_mode & 1)
- inode->i_mode |= S_IRUSR | S_IXUSR;
- if (p->files->fd[ino]->f_mode & 2)
- inode->i_mode |= S_IWUSR | S_IXUSR;
+ if (!proc_paranoid(inode)) {
+ if (p->files->fd[ino]->f_mode & 1)
+ inode->i_mode |= S_IRUSR | S_IXUSR;
+ if (p->files->fd[ino]->f_mode & 2)
+ inode->i_mode |= S_IWUSR | S_IXUSR;
+ }
return;
}
return;
diff -ru --exclude=*.o --exclude=.depend linux-1.2.13/fs/proc/link.c linux-1.2.13-procpar/fs/proc/link.c
--- linux-1.2.13/fs/proc/link.c Mon Jan 23 21:04:10 1995
+++ linux-1.2.13-procpar/fs/proc/link.c Wed Sep 27 20:29:52 1995
@@ -76,6 +76,10 @@
if (fd>=NR_OPEN)
return -ENOENT; /* should never happen */
+ if (proc_paranoid(inode) && !suser()) {
+ return -EPERM;
+ }
+
ino = inode->i_ino;
pid = ino >> 16;
ino &= 0x0000ffff;
diff -ru --exclude=*.o --exclude=.depend linux-1.2.13/include/linux/proc_fs.h linux-1.2.13-procpar/include/linux/proc_fs.h
--- linux-1.2.13/include/linux/proc_fs.h Sun Feb 12 19:11:02 1995
+++ linux-1.2.13-procpar/include/linux/proc_fs.h Wed Sep 27 21:35:29 1995
@@ -129,4 +129,6 @@
extern struct inode_operations proc_link_inode_operations;
extern struct inode_operations proc_fd_inode_operations;
+extern int proc_paranoid(struct inode *i);
+
#endif