linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [PATCH] proc: maps protection
       [not found]     ` <20070306185942.585e7cd1.akpm@linux-foundation.org>
@ 2007-03-07  3:14       ` Kees Cook
  2007-03-07  4:22         ` Arjan van de Ven
  0 siblings, 1 reply; 14+ messages in thread
From: Kees Cook @ 2007-03-07  3:14 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Arjan van de Ven, linux-kernel

On Tue, Mar 06, 2007 at 06:59:42PM -0800, Andrew Morton wrote:
> On Tue, 6 Mar 2007 18:13:35 -0800 Kees Cook <kees@outflux.net> wrote:
> 
> > On Tue, Mar 06, 2007 at 05:56:09PM -0800, Andrew Morton wrote:
> > > On Tue, 6 Mar 2007 17:22:34 -0800
> > > Kees Cook <kees@outflux.net> wrote:
> > > 
> > > > This is a continuation of a much earlier discussion[1].  As I 
> > > > understand, the problem is:
> > > 
> > > This sounds like a really good way of breaking lots and lots of people's
> > > expensively-developed stuff.  In ways which we won't discover until a year
> > > after we shipped it.
> > > 
> > > So nope, sorry.  Need to find a compatible way of doing this.  Perhaps a
> > > kernel boot parameter or a /proc knob.
> > 
> > Do you have examples of things in the kernel that I can use as a 
> > starting point?
> 
> No, I don't think this has precedent.
> 
> >  Would something like /proc/sys/kernel/maps_protect be 
> > reasonable?
> 
> Yes, that sounds reasonable.
> 
> An alternative is to do it with elf headers, perhaps - let the process
> specify what protections it wants in some manner.
> 
> > If an acceptable toggle is made, would you consider it being enabled by 
> > default (i.e. "tighter security by default")?
> 
> Again, that sounds risky.

[Adding Cc:lkml]

How about using a reduced check, as is done for fd and environ?  This 
would allow root-running system monitors to still do their job.  
Effectively, this changes the test from "is ptracing" to just "can 
ptrace".

If this still isn't considered safe, I'll add the maps_protect file...

--- 
task_mmu.c   |   16 +++++++++++++++-
 task_nommu.c |    6 ++++++
 2 files changed, 21 insertions(+), 1 deletion(-)
---
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 7445980..7c9aad3 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -134,6 +134,9 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats
 	dev_t dev = 0;
 	int len;
 
+	if (!ptrace_may_attach(task))
+		return -EACCES;
+
 	if (file) {
 		struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
 		dev = inode->i_sb->s_dev;
@@ -444,11 +447,22 @@ const struct file_operations proc_maps_operations = {
 #ifdef CONFIG_NUMA
 extern int show_numa_map(struct seq_file *m, void *v);
 
+static int show_numa_map_checked(struct seq_file *m, void *v)
+{
+	struct proc_maps_private *priv = m->private;
+	struct task_struct *task = priv->task;
+
+	if (!ptrace_may_attach(task))
+		return -EACCES;
+	
+	return show_numa_map(m, v);
+}
+
 static struct seq_operations proc_pid_numa_maps_op = {
         .start  = m_start,
         .next   = m_next,
         .stop   = m_stop,
-        .show   = show_numa_map
+        .show   = show_numa_map_checked
 };
 
 static int numa_maps_open(struct inode *inode, struct file *file)
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 7cddf6b..c5783b7 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -143,6 +143,12 @@ out:
 static int show_map(struct seq_file *m, void *_vml)
 {
 	struct vm_list_struct *vml = _vml;
+	struct proc_maps_private *priv = m->private;
+	struct task_struct *task = priv->task;
+	
+	if (!ptrace_may_attach(task))
+		return -EACCES;
+
 	return nommu_vma_show(m, vml->vma);
 }
 



-- 
Kees Cook                                            @outflux.net

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

* Re: [PATCH] proc: maps protection
  2007-03-07  3:14       ` [PATCH] proc: maps protection Kees Cook
@ 2007-03-07  4:22         ` Arjan van de Ven
  2007-03-08 20:55           ` Kees Cook
  2007-03-10  1:37           ` [PATCH] proc: maps protection Andy Isaacson
  0 siblings, 2 replies; 14+ messages in thread
From: Arjan van de Ven @ 2007-03-07  4:22 UTC (permalink / raw)
  To: Kees Cook; +Cc: Andrew Morton, linux-kernel


> [Adding Cc:lkml]

> How about using a reduced check, as is done for fd and environ?  This 
> would allow root-running system monitors to still do their job.  
> Effectively, this changes the test from "is ptracing" to just "can 
> ptrace".
> 
> If this still isn't considered safe, I'll add the maps_protect file...


btw I consider it an information leak that any user can see which
files/libraries any other user and root has mmap'd. (and with glibc's
stdio mmap feature that goes even beyond direct mmap to fopen()'d).

If root or some other user wants to watch
hillary-vs-obama-in-the-mud.avi, no other user has ANY business even
seeing that. So at minimum it's a privacy issue showing the filenames...

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

* Re: [PATCH] proc: maps protection
  2007-03-07  4:22         ` Arjan van de Ven
@ 2007-03-08 20:55           ` Kees Cook
  2007-03-10  2:30             ` Andrew Morton
  2007-03-10  1:37           ` [PATCH] proc: maps protection Andy Isaacson
  1 sibling, 1 reply; 14+ messages in thread
From: Kees Cook @ 2007-03-08 20:55 UTC (permalink / raw)
  To: Arjan van de Ven; +Cc: Andrew Morton, linux-kernel

On Tue, Mar 06, 2007 at 08:22:11PM -0800, Arjan van de Ven wrote:
> > [Adding Cc:lkml]
> 
> > How about using a reduced check, as is done for fd and environ?  This 
> > would allow root-running system monitors to still do their job.  
> > Effectively, this changes the test from "is ptracing" to just "can 
> > ptrace".
> > 
> > If this still isn't considered safe, I'll add the maps_protect file...
> 
> btw I consider it an information leak that any user can see which
> files/libraries any other user and root has mmap'd. (and with glibc's
> stdio mmap feature that goes even beyond direct mmap to fopen()'d).
> 
> If root or some other user wants to watch
> hillary-vs-obama-in-the-mud.avi, no other user has ANY business even
> seeing that. So at minimum it's a privacy issue showing the filenames...

So, what's the state of this?  Is the reduced "allowed to ptrace" check 
good enough for inclusion?  What is needed for some form of this patch 
to be included?  I'm happy to try new approaches if I can get some 
further input.

Another suggestion was to make this an ELF header toggle, and I'm 
generally against that idea.  If a toggle is needed, I'd rather it be a 
system-wide one.

-- 
Kees Cook

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

* Re: [PATCH] proc: maps protection
  2007-03-07  4:22         ` Arjan van de Ven
  2007-03-08 20:55           ` Kees Cook
@ 2007-03-10  1:37           ` Andy Isaacson
  1 sibling, 0 replies; 14+ messages in thread
From: Andy Isaacson @ 2007-03-10  1:37 UTC (permalink / raw)
  To: Arjan van de Ven; +Cc: Kees Cook, Andrew Morton, linux-kernel

On Tue, Mar 06, 2007 at 08:22:11PM -0800, Arjan van de Ven wrote:
> > How about using a reduced check, as is done for fd and environ?  This 
> > would allow root-running system monitors to still do their job.  
> > Effectively, this changes the test from "is ptracing" to just "can 
> > ptrace".
> > 
> > If this still isn't considered safe, I'll add the maps_protect file...
> 
> btw I consider it an information leak that any user can see which
> files/libraries any other user and root has mmap'd. (and with glibc's
> stdio mmap feature that goes even beyond direct mmap to fopen()'d).
> 
> If root or some other user wants to watch
> hillary-vs-obama-in-the-mud.avi, no other user has ANY business even
> seeing that. So at minimum it's a privacy issue showing the filenames...

Sure, I would be fine with making /proc/<pid>/maps mode 0400 (so long as
root can still read it).  But please don't take away my ability to debug
applications using pmap(1).  It's so incredibly useful to be able to say
"ah, look, he mapped nss_nis.so rather than nss_nisplus.so".

-andy

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

* Re: [PATCH] proc: maps protection
  2007-03-08 20:55           ` Kees Cook
@ 2007-03-10  2:30             ` Andrew Morton
  2007-03-10  5:01               ` Arjan van de Ven
  0 siblings, 1 reply; 14+ messages in thread
From: Andrew Morton @ 2007-03-10  2:30 UTC (permalink / raw)
  To: Kees Cook; +Cc: arjan, linux-kernel

> On Thu, 8 Mar 2007 12:55:25 -0800 Kees Cook <kees@outflux.net> wrote:
> On Tue, Mar 06, 2007 at 08:22:11PM -0800, Arjan van de Ven wrote:
> > > [Adding Cc:lkml]
> > 
> > > How about using a reduced check, as is done for fd and environ?  This 
> > > would allow root-running system monitors to still do their job.  
> > > Effectively, this changes the test from "is ptracing" to just "can 
> > > ptrace".
> > > 
> > > If this still isn't considered safe, I'll add the maps_protect file...
> > 
> > btw I consider it an information leak that any user can see which
> > files/libraries any other user and root has mmap'd. (and with glibc's
> > stdio mmap feature that goes even beyond direct mmap to fopen()'d).
> > 
> > If root or some other user wants to watch
> > hillary-vs-obama-in-the-mud.avi, no other user has ANY business even
> > seeing that. So at minimum it's a privacy issue showing the filenames...
> 
> So, what's the state of this?  Is the reduced "allowed to ptrace" check 
> good enough for inclusion?  What is needed for some form of this patch 
> to be included?  I'm happy to try new approaches if I can get some 
> further input.

I just don't know what it will break - we're changing things so that user A
cannot monitor user B's memory maps.  I feel that it's sure to break
various people's fancy custom system activity monitoring/logging setups,
and the sort of users who will be affected are, alas, the sort of people
who won't run a kernel with this change in it for another couple of years
yet.

> Another suggestion was to make this an ELF header toggle, and I'm 
> generally against that idea.  If a toggle is needed, I'd rather it be a 
> system-wide one.

A global /proc knob probably isn't too bad.

Do we actually need to disable the whole interface?  If all you're
concerned about is the pathname then perhaps the knob could cause that
pathname to be replaced with "<hidden>".  That'll cause things to
break less seriously and still allows somewhat useful info to be gathered.


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

* Re: [PATCH] proc: maps protection
  2007-03-10  2:30             ` Andrew Morton
@ 2007-03-10  5:01               ` Arjan van de Ven
  2007-03-10 18:33                 ` Kees Cook
  0 siblings, 1 reply; 14+ messages in thread
From: Arjan van de Ven @ 2007-03-10  5:01 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Kees Cook, linux-kernel

Andrew Morton wrote:
>> On Thu, 8 Mar 2007 12:55:25 -0800 Kees Cook <kees@outflux.net> wrote:
>> On Tue, Mar 06, 2007 at 08:22:11PM -0800, Arjan van de Ven wrote:
>>>> [Adding Cc:lkml]
>>>> How about using a reduced check, as is done for fd and environ?  This 
>>>> would allow root-running system monitors to still do their job.  
>>>> Effectively, this changes the test from "is ptracing" to just "can 
>>>> ptrace".
>>>>
>>>> If this still isn't considered safe, I'll add the maps_protect file...
>>> btw I consider it an information leak that any user can see which
>>> files/libraries any other user and root has mmap'd. (and with glibc's
>>> stdio mmap feature that goes even beyond direct mmap to fopen()'d).
>>>
>>> If root or some other user wants to watch
>>> hillary-vs-obama-in-the-mud.avi, no other user has ANY business even
>>> seeing that. So at minimum it's a privacy issue showing the filenames...
>> So, what's the state of this?  Is the reduced "allowed to ptrace" check 
>> good enough for inclusion?  What is needed for some form of this patch 
>> to be included?  I'm happy to try new approaches if I can get some 
>> further input.
> 
> I just don't know what it will break - we're changing things so that user A
> cannot monitor user B's memory maps.  I feel that it's sure to break
> various people's fancy custom system activity monitoring/logging setups,
> and the sort of users who will be affected are, alas, the sort of people
> who won't run a kernel with this change in it for another couple of years
> yet.

except if they run RHEL or FC kernels, in which case they already have 
that change

> Do we actually need to disable the whole interface?  If all you're
> concerned about is the pathname then perhaps the knob could cause that
> pathname to be replaced with "<hidden>".  That'll cause things to
> break less seriously and still allows somewhat useful info to be gathered.

the problem part is that you can see EXACLTY where glibc is loaded in 
memory, which effectively defeats address space randomization for 
local users....

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

* Re: [PATCH] proc: maps protection
  2007-03-10  5:01               ` Arjan van de Ven
@ 2007-03-10 18:33                 ` Kees Cook
  2007-03-11  0:21                   ` Andrew Morton
  0 siblings, 1 reply; 14+ messages in thread
From: Kees Cook @ 2007-03-10 18:33 UTC (permalink / raw)
  To: Arjan van de Ven; +Cc: Andrew Morton, linux-kernel

On Fri, Mar 09, 2007 at 09:01:41PM -0800, Arjan van de Ven wrote:
> >I just don't know what it will break - we're changing things so that user A
> >cannot monitor user B's memory maps.  I feel that it's sure to break
> >various people's fancy custom system activity monitoring/logging setups,
> >and the sort of users who will be affected are, alas, the sort of people
> >who won't run a kernel with this change in it for another couple of years
> >yet.
> 
> except if they run RHEL or FC kernels, in which case they already have 
> that change

Right, this is a "gentler" version of just slapping 0400 perms on the 
maps files, which already has the same effect.  I think tightening this 
bit of security is worth some possible breakage.

> >Do we actually need to disable the whole interface?  If all you're
> >concerned about is the pathname then perhaps the knob could cause that
> >pathname to be replaced with "<hidden>".  That'll cause things to
> >break less seriously and still allows somewhat useful info to be gathered.
> 
> the problem part is that you can see EXACLTY where glibc is loaded in 
> memory, which effectively defeats address space randomization for 
> local users....

Right; and since the maps are loaded in a specific order, just dropping 
the filename isn't going to help in protecting the ASLR.  e.g. I can get 
apache's library list from its ELF, and it's very easy to line that up 
with the maps file even if the filenames are missing.

Here's another revision, with both the "can ptrace" and the global /proc 
knob; and I'll beg for defaulting the knob to "on".  :)

Signed-off-by: Kees Cook <kees@outflux.net>

---
 fs/proc/base.c         |    3 +++
 fs/proc/internal.h     |    2 ++
 fs/proc/task_mmu.c     |   16 +++++++++++++++-
 fs/proc/task_nommu.c   |    6 ++++++
 include/linux/sysctl.h |    1 +
 kernel/sysctl.c        |    9 +++++++++
 6 files changed, 36 insertions(+), 1 deletion(-)
---
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 1a979ea..9b6e731 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -123,6 +123,9 @@ struct pid_entry {
 		NULL, &proc_info_file_operations,	\
 		{ .proc_read = &proc_##OTYPE } )
 
+int maps_protect = 1;
+EXPORT_SYMBOL(maps_protect);
+
 static struct fs_struct *get_fs_struct(struct task_struct *task)
 {
 	struct fs_struct *fs;
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 987c773..596d925 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -31,6 +31,8 @@ do {						\
 extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
 #endif
 
+extern int maps_protect;
+
 extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f);
 extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **);
 extern int proc_tid_stat(struct task_struct *,  char *);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 55ade0d..2e43c12 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -134,6 +134,9 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats
 	dev_t dev = 0;
 	int len;
 
+	if (maps_protect && !ptrace_may_attach(task))
+		return -EACCES;
+
 	if (file) {
 		struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
 		dev = inode->i_sb->s_dev;
@@ -444,11 +447,22 @@ struct file_operations proc_maps_operations = {
 #ifdef CONFIG_NUMA
 extern int show_numa_map(struct seq_file *m, void *v);
 
+static int show_numa_map_checked(struct seq_file *m, void *v)
+{
+	struct proc_maps_private *priv = m->private;
+	struct task_struct *task = priv->task;
+
+	if (maps_protect && !ptrace_may_attach(task))
+		return -EACCES;
+	
+	return show_numa_map(m, v);
+}
+
 static struct seq_operations proc_pid_numa_maps_op = {
         .start  = m_start,
         .next   = m_next,
         .stop   = m_stop,
-        .show   = show_numa_map
+        .show   = show_numa_map_checked
 };
 
 static int numa_maps_open(struct inode *inode, struct file *file)
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index fcc5caf..fb36c6a 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -143,6 +143,12 @@ out:
 static int show_map(struct seq_file *m, void *_vml)
 {
 	struct vm_list_struct *vml = _vml;
+	struct proc_maps_private *priv = m->private;
+	struct task_struct *task = priv->task;
+	
+	if (maps_protect && !ptrace_may_attach(task))
+		return -EACCES;
+
 	return nommu_vma_show(m, vml->vma);
 }
 
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 81480e6..743d63d 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -160,6 +160,7 @@ enum
 	KERN_MAX_LOCK_DEPTH=74,
 	KERN_NMI_WATCHDOG=75, /* int: enable/disable nmi watchdog */
 	KERN_PANIC_ON_NMI=76, /* int: whether we will panic on an unrecovered */
+	KERN_MAPS_PROTECT=77, /* int: whether we protect maps from public visibility */
 };
 
 
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index b01e767..653a6ad 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -76,6 +76,7 @@ extern int pid_max_min, pid_max_max;
 extern int sysctl_drop_caches;
 extern int percpu_pagelist_fraction;
 extern int compat_log;
+extern int maps_protect;
 
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
 static int maxolduid = 65535;
@@ -782,6 +783,14 @@ static ctl_table kern_table[] = {
 		.proc_handler	= &proc_dointvec,
 	},
 #endif
+	{
+		.ctl_name       = KERN_MAPS_PROTECT,
+		.procname       = "maps_protect",
+		.data           = &maps_protect,
+		.maxlen         = sizeof(int),
+		.mode           = 0644,
+		.proc_handler   = &proc_dointvec,
+	},
 
 	{ .ctl_name = 0 }
 };


-- 
Kees Cook

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

* Re: [PATCH] proc: maps protection
  2007-03-10 18:33                 ` Kees Cook
@ 2007-03-11  0:21                   ` Andrew Morton
  2007-03-11  0:55                     ` Matt Mackall
                                       ` (3 more replies)
  0 siblings, 4 replies; 14+ messages in thread
From: Andrew Morton @ 2007-03-11  0:21 UTC (permalink / raw)
  To: Kees Cook; +Cc: arjan, linux-kernel

> On Sat, 10 Mar 2007 10:33:41 -0800 Kees Cook <kees@outflux.net> wrote:
> Here's another revision, with both the "can ptrace" and the global /proc 
> knob;

We'd be needing a changelog for that.

Please update the procfs documentation.

Does the patch also cover /proc/pid/smaps?

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

* Re: [PATCH] proc: maps protection
  2007-03-11  0:21                   ` Andrew Morton
@ 2007-03-11  0:55                     ` Matt Mackall
  2007-03-11  1:43                     ` Kees Cook
                                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 14+ messages in thread
From: Matt Mackall @ 2007-03-11  0:55 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Kees Cook, arjan, linux-kernel

On Sat, Mar 10, 2007 at 04:21:01PM -0800, Andrew Morton wrote:
> > On Sat, 10 Mar 2007 10:33:41 -0800 Kees Cook <kees@outflux.net> wrote:
> > Here's another revision, with both the "can ptrace" and the global /proc 
> > knob;
> 
> We'd be needing a changelog for that.
> 
> Please update the procfs documentation.
> 
> Does the patch also cover /proc/pid/smaps?

Also, we ought to revisit /proc/pid/mem write, which is currently disabled.
Either drop the code, fix it, or make it root only.

-- 
Mathematics is the supreme nostalgia of our time.

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

* Re: [PATCH] proc: maps protection
  2007-03-11  0:21                   ` Andrew Morton
  2007-03-11  0:55                     ` Matt Mackall
@ 2007-03-11  1:43                     ` Kees Cook
  2007-03-11  1:55                     ` Kees Cook
  2007-03-12 17:20                     ` [PATCH] getrusage() : Fill ru_inblock and ru_oublock fields if possible Eric Dumazet
  3 siblings, 0 replies; 14+ messages in thread
From: Kees Cook @ 2007-03-11  1:43 UTC (permalink / raw)
  To: Andrew Morton; +Cc: arjan, linux-kernel

The /proc/pid/ "maps", "smaps", and "numa_maps" files contain sensitive 
information about the memory location and usage of processes.  Issues:

- maps should not be world-readable, especially if programs expect any 
  kind of ASLR protection from local attackers.
- maps cannot just be 0400 because "-D_FORTIFY_SOURCE=2 -O2" makes glibc
  check the maps when %n is in a *printf call, and a setuid(getuid()) 
  process wouldn't be able to read its own maps file.  (For reference
  see http://lkml.org/lkml/2006/1/22/150)
- a system-wide toggle is needed to allow prior behavior in the case of
  non-root applications that depend on access to the maps contents.

This change implements a check using "ptrace_may_attach" before allowing 
access to read the maps contents.  To control this protection, the new 
knob /proc/sys/kernel/maps_protect has been added, with corresponding 
updates to the procfs documentation.

Signed-off-by: Kees Cook <kees@outflux.net>
---
 CREDITS                            |    2 +-
 Documentation/filesystems/proc.txt |    7 +++++++
 fs/proc/base.c                     |    3 +++
 fs/proc/internal.h                 |    2 ++
 fs/proc/task_mmu.c                 |   16 +++++++++++++++-
 fs/proc/task_nommu.c               |    6 ++++++
 include/linux/sysctl.h             |    1 +
 kernel/sysctl.c                    |    9 +++++++++
 8 files changed, 44 insertions(+), 2 deletions(-)
---
diff --git a/CREDITS b/CREDITS
index 6bd8ab8..38c3ada 100644
--- a/CREDITS
+++ b/CREDITS
@@ -655,7 +655,7 @@ N: Kees Cook
 E: kees@outflux.net
 W: http://outflux.net/
 P: 1024D/17063E6D 9FA3 C49C 23C9 D1BC 2E30  1975 1FFF 4BA9 1706 3E6D
-D: Minor updates to SCSI code for the Communications type
+D: Minor updates to SCSI types, added /proc/pid/maps protection
 S: (ask for current address)
 S: USA
 
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 5484ab5..d9b06b5 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -1137,6 +1137,13 @@ determine whether or not they are still functioning properly.
 Because the NMI watchdog shares registers with oprofile, by disabling the NMI
 watchdog, oprofile may have more registers to utilize.
 
+maps_protect
+------------
+
+Enables/Disables the protection of the per-process proc entries "maps" and
+"smaps".  When enabled, the contents of these files are visible only to
+readers that are allowed to ptrace() the given process.
+
 
 2.4 /proc/sys/vm - The virtual memory subsystem
 -----------------------------------------------
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 01f7769..6feccbc 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -123,6 +123,9 @@ struct pid_entry {
 		NULL, &proc_info_file_operations,	\
 		{ .proc_read = &proc_##OTYPE } )
 
+int maps_protect = 0;
+EXPORT_SYMBOL(maps_protect);
+
 static struct fs_struct *get_fs_struct(struct task_struct *task)
 {
 	struct fs_struct *fs;
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index c932aa6..2c65b6e 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -33,6 +33,8 @@ do {						\
 extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
 #endif
 
+extern int maps_protect;
+
 extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f);
 extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **);
 extern int proc_tid_stat(struct task_struct *,  char *);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 7445980..45a0f3e 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -134,6 +134,9 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats
 	dev_t dev = 0;
 	int len;
 
+	if (maps_protect && !ptrace_may_attach(task))
+		return -EACCES;
+
 	if (file) {
 		struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
 		dev = inode->i_sb->s_dev;
@@ -444,11 +447,22 @@ const struct file_operations proc_maps_operations = {
 #ifdef CONFIG_NUMA
 extern int show_numa_map(struct seq_file *m, void *v);
 
+static int show_numa_map_checked(struct seq_file *m, void *v)
+{
+	struct proc_maps_private *priv = m->private;
+	struct task_struct *task = priv->task;
+
+	if (maps_protect && !ptrace_may_attach(task))
+		return -EACCES;
+	
+	return show_numa_map(m, v);
+}
+
 static struct seq_operations proc_pid_numa_maps_op = {
         .start  = m_start,
         .next   = m_next,
         .stop   = m_stop,
-        .show   = show_numa_map
+        .show   = show_numa_map_checked
 };
 
 static int numa_maps_open(struct inode *inode, struct file *file)
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 7cddf6b..c2747c9 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -143,6 +143,12 @@ out:
 static int show_map(struct seq_file *m, void *_vml)
 {
 	struct vm_list_struct *vml = _vml;
+	struct proc_maps_private *priv = m->private;
+	struct task_struct *task = priv->task;
+	
+	if (maps_protect && !ptrace_may_attach(task))
+		return -EACCES;
+
 	return nommu_vma_show(m, vml->vma);
 }
 
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 2c5fb38..608a331 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -165,6 +165,7 @@ enum
 	KERN_MAX_LOCK_DEPTH=74,
 	KERN_NMI_WATCHDOG=75, /* int: enable/disable nmi watchdog */
 	KERN_PANIC_ON_NMI=76, /* int: whether we will panic on an unrecovered */
+	KERN_MAPS_PROTECT=77, /* int: whether we protect maps from public visibility */
 };
 
 
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 1b255df..ca4d69f 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -76,6 +76,7 @@ extern int pid_max_min, pid_max_max;
 extern int sysctl_drop_caches;
 extern int percpu_pagelist_fraction;
 extern int compat_log;
+extern int maps_protect;
 
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
 static int maxolduid = 65535;
@@ -603,6 +604,14 @@ static ctl_table kern_table[] = {
 		.proc_handler	= &proc_dointvec,
 	},
 #endif
+	{,
+		.ctl_name       = KERN_MAPS_PROTECT,
+		.procname       = "maps_protect",
+		.data           = &maps_protect,
+		.maxlen         = sizeof(int),
+		.mode           = 0644,
+		.proc_handler   = &proc_dointvec,
+	},
 
 	{ .ctl_name = 0 }
 };



-- 
Kees Cook

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

* Re: [PATCH] proc: maps protection
  2007-03-11  0:21                   ` Andrew Morton
  2007-03-11  0:55                     ` Matt Mackall
  2007-03-11  1:43                     ` Kees Cook
@ 2007-03-11  1:55                     ` Kees Cook
  2007-03-12 17:20                     ` [PATCH] getrusage() : Fill ru_inblock and ru_oublock fields if possible Eric Dumazet
  3 siblings, 0 replies; 14+ messages in thread
From: Kees Cook @ 2007-03-11  1:55 UTC (permalink / raw)
  To: Andrew Morton; +Cc: arjan, linux-kernel

On Sat, Mar 10, 2007 at 04:21:01PM -0800, Andrew Morton wrote:
> We'd be needing a changelog for that.

Done; sent separately from this email.

> Please update the procfs documentation.

Done.

> Does the patch also cover /proc/pid/smaps?

Yes, and numa_maps.

Thanks!

-- 
Kees Cook

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

* [PATCH] getrusage() : Fill ru_inblock and ru_oublock fields if possible
  2007-03-11  0:21                   ` Andrew Morton
                                       ` (2 preceding siblings ...)
  2007-03-11  1:55                     ` Kees Cook
@ 2007-03-12 17:20                     ` Eric Dumazet
  3 siblings, 0 replies; 14+ messages in thread
From: Eric Dumazet @ 2007-03-12 17:20 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1105 bytes --]

if CONFIG_TASK_IO_ACCOUNTING is defined, we update io accounting counters for 
each task.

This patch permits reporting of values using the well known getrusage() 
syscall, filling ru_inblock and ru_oublock instead of null values.

As TASK_IO_ACCOUNTING currently counts bytes counts, we approximate blocks 
count doing : nr_blocks = nr_bytes / 512

Example of use :
----------------------
After patch is applied, /usr/bin/time command can now give a good 
approximation of IO that the process had to do.

$ /usr/bin/time grep tototo /usr/include/*
Command exited with non-zero status 1
0.00user 0.02system 0:02.11elapsed 1%CPU (0avgtext+0avgdata 0maxresident)k
24288inputs+0outputs (0major+259minor)pagefaults 0swaps

$ /usr/bin/time dd if=/dev/zero of=/tmp/testfile count=1000
1000+0 enregistrements lus
1000+0 enregistrements écrits
512000 octets (512 kB) copiés, 0,00326601 seconde, 157 MB/s
0.00user 0.00system 0:00.00elapsed 80%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+3000outputs (0major+299minor)pagefaults 0swaps

Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>

[-- Attachment #2: getrusage_add_inblock_and_oublock.patch --]
[-- Type: text/plain, Size: 2673 bytes --]

--- linux-2.6.21-rc3/kernel/sys.c	2007-03-12 17:30:34.000000000 +0100
+++ linux-2.6.21-rc3-ed/kernel/sys.c	2007-03-12 17:50:15.000000000 +0100
@@ -29,6 +29,7 @@
 #include <linux/signal.h>
 #include <linux/cn_proc.h>
 #include <linux/getcpu.h>
+#include <linux/task_io_accounting_ops.h>
 
 #include <linux/compat.h>
 #include <linux/syscalls.h>
@@ -2021,6 +2022,8 @@ static void k_getrusage(struct task_stru
 			r->ru_nivcsw = p->signal->cnivcsw;
 			r->ru_minflt = p->signal->cmin_flt;
 			r->ru_majflt = p->signal->cmaj_flt;
+			r->ru_inblock = task_io_get_inblock(p);
+			r->ru_oublock = task_io_get_oublock(p);
 
 			if (who == RUSAGE_CHILDREN)
 				break;
@@ -2032,6 +2035,8 @@ static void k_getrusage(struct task_stru
 			r->ru_nivcsw += p->signal->nivcsw;
 			r->ru_minflt += p->signal->min_flt;
 			r->ru_majflt += p->signal->maj_flt;
+			r->ru_inblock += task_io_get_inblock(p);
+			r->ru_oublock += task_io_get_oublock(p);
 			t = p;
 			do {
 				utime = cputime_add(utime, t->utime);
@@ -2040,6 +2045,8 @@ static void k_getrusage(struct task_stru
 				r->ru_nivcsw += t->nivcsw;
 				r->ru_minflt += t->min_flt;
 				r->ru_majflt += t->maj_flt;
+				r->ru_inblock += task_io_get_inblock(t);
+				r->ru_oublock += task_io_get_oublock(t);
 				t = next_thread(t);
 			} while (t != p);
 			break;
--- linux-2.6.21-rc3/include/linux/task_io_accounting_ops.h	2007-03-12 17:30:34.000000000 +0100
+++ linux-2.6.21-rc3-ed/include/linux/task_io_accounting_ops.h	2007-03-12 17:50:15.000000000 +0100
@@ -10,11 +10,29 @@ static inline void task_io_account_read(
 	current->ioac.read_bytes += bytes;
 }
 
+/*
+ * We approximate number of blocks, because we account bytes only.
+ * A 'block' is 512 bytes
+ */
+static inline unsigned long task_io_get_inblock(const struct task_struct *p)
+{
+	return p->ioac.read_bytes >> 9;
+}
+
 static inline void task_io_account_write(size_t bytes)
 {
 	current->ioac.write_bytes += bytes;
 }
 
+/*
+ * We approximate number of blocks, because we account bytes only.
+ * A 'block' is 512 bytes
+ */
+static inline unsigned long task_io_get_oublock(const struct task_struct *p)
+{
+	return p->ioac.write_bytes >> 9;
+}
+
 static inline void task_io_account_cancelled_write(size_t bytes)
 {
 	current->ioac.cancelled_write_bytes += bytes;
@@ -31,10 +49,20 @@ static inline void task_io_account_read(
 {
 }
 
+static inline unsigned long task_io_get_inblock(const struct task_struct *p)
+{
+	return 0;
+}
+
 static inline void task_io_account_write(size_t bytes)
 {
 }
 
+static inline unsigned long task_io_get_oublock(const struct task_struct *p)
+{
+	return 0;
+}
+
 static inline void task_io_account_cancelled_write(size_t bytes)
 {
 }

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

* Re: [PATCH] proc: maps protection
  2007-03-05 20:15 Kees Cook
@ 2007-03-06  0:23 ` Kees Cook
  0 siblings, 0 replies; 14+ messages in thread
From: Kees Cook @ 2007-03-06  0:23 UTC (permalink / raw)
  To: linux-kernel

Implement the same logic for the checks done on /proc/$pid/mem, but 
extend them to /proc/$pid/{maps,smaps,numa_maps}.  This means that only 
processes and their ptrace parents can read their maps files.

Signed-off-by: Kees Cook <kees@outflux.net>
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
---
On Mon, Mar 05, 2007 at 12:15:11PM -0800, Kees Cook wrote:
> What do others think of this?

Whoops, Arjan caught a mistake, new patch included, using -EACCES 
everywhere.  (I had a straggling -EPERM from an earlier version.)

---
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 1a979ea..9bf7585 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -65,8 +65,6 @@
 #include <linux/rcupdate.h>
 #include <linux/kallsyms.h>
 #include <linux/mount.h>
-#include <linux/security.h>
-#include <linux/ptrace.h>
 #include <linux/seccomp.h>
 #include <linux/cpuset.h>
 #include <linux/audit.h>
@@ -189,13 +187,6 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf
 	return result;
 }
 
-#define MAY_PTRACE(task) \
-	(task == current || \
-	(task->parent == current && \
-	(task->ptrace & PT_PTRACED) && \
-	 (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;
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 987c773..3c5ccc9 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -10,6 +10,8 @@
  */
 
 #include <linux/proc_fs.h>
+#include <linux/security.h>
+#include <linux/ptrace.h>
 
 struct vmalloc_info {
 	unsigned long	used;
@@ -31,6 +33,13 @@ do {						\
 extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
 #endif
 
+#define MAY_PTRACE(task) \
+        (task == current || \
+        (task->parent == current && \
+         (task->ptrace & PT_PTRACED) && \
+         (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \
+         security_ptrace(current,task) == 0))
+
 extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f);
 extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **);
 extern int proc_tid_stat(struct task_struct *,  char *);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 55ade0d..85486d4 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -134,6 +134,9 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats
 	dev_t dev = 0;
 	int len;
 
+	if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
+		return -EACCES;
+
 	if (file) {
 		struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
 		dev = inode->i_sb->s_dev;
@@ -444,11 +447,22 @@ struct file_operations proc_maps_operations = {
 #ifdef CONFIG_NUMA
 extern int show_numa_map(struct seq_file *m, void *v);
 
+static int show_numa_map_checked(struct seq_file *m, void *v)
+{
+	struct proc_maps_private *priv = m->private;
+	struct task_struct *task = priv->task;
+
+	if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
+		return -EACCES;
+	
+	return show_numa_map(m, v);
+}
+
 static struct seq_operations proc_pid_numa_maps_op = {
         .start  = m_start,
         .next   = m_next,
         .stop   = m_stop,
-        .show   = show_numa_map
+        .show   = show_numa_map_checked
 };
 
 static int numa_maps_open(struct inode *inode, struct file *file)
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index fcc5caf..985a6ff 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -143,6 +143,12 @@ out:
 static int show_map(struct seq_file *m, void *_vml)
 {
 	struct vm_list_struct *vml = _vml;
+	struct proc_maps_private *priv = m->private;
+	struct task_struct *task = priv->task;
+	
+	if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
+		return -EACCES;
+
 	return nommu_vma_show(m, vml->vma);
 }
 

-- 
Kees Cook

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

* [PATCH] proc: maps protection
@ 2007-03-05 20:15 Kees Cook
  2007-03-06  0:23 ` Kees Cook
  0 siblings, 1 reply; 14+ messages in thread
From: Kees Cook @ 2007-03-05 20:15 UTC (permalink / raw)
  To: linux-kernel

Implement the same logic for the checks done on /proc/$pid/mem, but 
extend them to /proc/$pid/{maps,smaps,numa_maps}.  This means that only 
processes and their ptrace parents can read their maps files.

Signed-off-by: Kees Cook <kees@outflux.net>
---

This is a continuation of a much earlier discussion[1].  As I 
understand, the problem is:

- "maps" should not be world-readable, especially if programs expect any 
  kind of ASLR protection from local attackers.
- "maps" cannot just be 0400 because "-D_FORTIFY_SOURCE=2 -O2" makes glibc
  check the maps when %n is in a *printf call, and a setuid(getuid()) 
  process wouldn't be able to read its own maps file.

It seemed that one solution would be to protect the maps file in the 
same way that the mem file is.  So, that's what this patch does.

Running this patch locally, gdb and the setuid glibc tests appear happy.  
What do others think of this?

[1] http://marc.theaimsgroup.com/?l=linux-kernel&m=113796842515034&w=2

---
 base.c       |    9 ---------
 internal.h   |    9 +++++++++
 task_mmu.c   |   16 +++++++++++++++-
 task_nommu.c |    6 ++++++
 4 files changed, 30 insertions(+), 10 deletions(-)
---
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 1a979ea..9bf7585 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -65,8 +65,6 @@
 #include <linux/rcupdate.h>
 #include <linux/kallsyms.h>
 #include <linux/mount.h>
-#include <linux/security.h>
-#include <linux/ptrace.h>
 #include <linux/seccomp.h>
 #include <linux/cpuset.h>
 #include <linux/audit.h>
@@ -189,13 +187,6 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf
 	return result;
 }
 
-#define MAY_PTRACE(task) \
-	(task == current || \
-	(task->parent == current && \
-	(task->ptrace & PT_PTRACED) && \
-	 (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;
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 987c773..3c5ccc9 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -10,6 +10,8 @@
  */
 
 #include <linux/proc_fs.h>
+#include <linux/security.h>
+#include <linux/ptrace.h>
 
 struct vmalloc_info {
 	unsigned long	used;
@@ -31,6 +33,13 @@ do {						\
 extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
 #endif
 
+#define MAY_PTRACE(task) \
+        (task == current || \
+        (task->parent == current && \
+         (task->ptrace & PT_PTRACED) && \
+         (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \
+         security_ptrace(current,task) == 0))
+
 extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f);
 extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **);
 extern int proc_tid_stat(struct task_struct *,  char *);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 55ade0d..85486d4 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -134,6 +134,9 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats
 	dev_t dev = 0;
 	int len;
 
+	if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
+		return -EACCES;
+
 	if (file) {
 		struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
 		dev = inode->i_sb->s_dev;
@@ -444,11 +447,22 @@ struct file_operations proc_maps_operations = {
 #ifdef CONFIG_NUMA
 extern int show_numa_map(struct seq_file *m, void *v);
 
+static int show_numa_map_checked(struct seq_file *m, void *v)
+{
+	struct proc_maps_private *priv = m->private;
+	struct task_struct *task = priv->task;
+
+	if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
+		return -EACCES;
+	
+	return show_numa_map(m, v);
+}
+
 static struct seq_operations proc_pid_numa_maps_op = {
         .start  = m_start,
         .next   = m_next,
         .stop   = m_stop,
-        .show   = show_numa_map
+        .show   = show_numa_map_checked
 };
 
 static int numa_maps_open(struct inode *inode, struct file *file)
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index fcc5caf..985a6ff 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -143,6 +143,12 @@ out:
 static int show_map(struct seq_file *m, void *_vml)
 {
 	struct vm_list_struct *vml = _vml;
+	struct proc_maps_private *priv = m->private;
+	struct task_struct *task = priv->task;
+	
+	if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
+		return -EPERM;
+
 	return nommu_vma_show(m, vml->vma);
 }
 


-- 
Kees Cook

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

end of thread, other threads:[~2007-03-12 17:20 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20070307012234.GN9621@outflux.net>
     [not found] ` <20070306175609.267bd7a9.akpm@linux-foundation.org>
     [not found]   ` <20070307021335.GR9621@outflux.net>
     [not found]     ` <20070306185942.585e7cd1.akpm@linux-foundation.org>
2007-03-07  3:14       ` [PATCH] proc: maps protection Kees Cook
2007-03-07  4:22         ` Arjan van de Ven
2007-03-08 20:55           ` Kees Cook
2007-03-10  2:30             ` Andrew Morton
2007-03-10  5:01               ` Arjan van de Ven
2007-03-10 18:33                 ` Kees Cook
2007-03-11  0:21                   ` Andrew Morton
2007-03-11  0:55                     ` Matt Mackall
2007-03-11  1:43                     ` Kees Cook
2007-03-11  1:55                     ` Kees Cook
2007-03-12 17:20                     ` [PATCH] getrusage() : Fill ru_inblock and ru_oublock fields if possible Eric Dumazet
2007-03-10  1:37           ` [PATCH] proc: maps protection Andy Isaacson
2007-03-05 20:15 Kees Cook
2007-03-06  0:23 ` Kees Cook

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