proc: maps protection
authorKees Cook <kees@outflux.net>
Tue, 8 May 2007 07:26:04 +0000 (00:26 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Tue, 8 May 2007 18:15:02 +0000 (11:15 -0700)
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.

[akpm@linux-foundation.org: build fixes]
[akpm@linux-foundation.org: New sysctl numbers are old hat]
Signed-off-by: Kees Cook <kees@outflux.net>
Cc: Arjan van de Ven <arjan@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
CREDITS
Documentation/filesystems/proc.txt
fs/proc/base.c
fs/proc/internal.h
fs/proc/task_mmu.c
fs/proc/task_nommu.c
kernel/sysctl.c

diff --git a/CREDITS b/CREDITS
index c5f819bacda3e28322c391af965558dd37ab2dd8..e71fdce0dc2f241468c470db142cca48b13769a3 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -661,7 +661,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
 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
 
 S: (ask for current address)
 S: USA
 
index 3f4b226572e7fd39cea5cd6547dd80a2627f928b..4f3e84c520a5cd844f602ad4e2b8c18c02c48aec 100644 (file)
@@ -1138,6 +1138,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.
 
 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
 -----------------------------------------------
 
 2.4 /proc/sys/vm - The virtual memory subsystem
 -----------------------------------------------
index a721acfd4fdcd3a008befe2a8a185a863b5e0903..17f7a7ee6c5e14aa00e2b9b8a999a8cfa89d21d9 100644 (file)
@@ -64,6 +64,7 @@
 #include <linux/smp_lock.h>
 #include <linux/rcupdate.h>
 #include <linux/kallsyms.h>
 #include <linux/smp_lock.h>
 #include <linux/rcupdate.h>
 #include <linux/kallsyms.h>
+#include <linux/module.h>
 #include <linux/mount.h>
 #include <linux/security.h>
 #include <linux/ptrace.h>
 #include <linux/mount.h>
 #include <linux/security.h>
 #include <linux/ptrace.h>
@@ -123,6 +124,9 @@ struct pid_entry {
                NULL, &proc_info_file_operations,       \
                { .proc_read = &proc_##OTYPE } )
 
                NULL, &proc_info_file_operations,       \
                { .proc_read = &proc_##OTYPE } )
 
+int maps_protect;
+EXPORT_SYMBOL(maps_protect);
+
 static struct fs_struct *get_fs_struct(struct task_struct *task)
 {
        struct fs_struct *fs;
 static struct fs_struct *get_fs_struct(struct task_struct *task)
 {
        struct fs_struct *fs;
index f771889183c36fe52062267ffde5d139ca18c76b..b215c3524fa685c572c874966128241d6747e9dd 100644 (file)
@@ -37,6 +37,8 @@ do {                                          \
 extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
 #endif
 
 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 *);
 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 *);
index 4008c060f7ef1b2b9ddc51154d30e1ec865906a5..c24d81a5a040e2a91825673434339e3c2f1dcdda 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/mount.h>
 #include <linux/seq_file.h>
 #include <linux/highmem.h>
 #include <linux/mount.h>
 #include <linux/seq_file.h>
 #include <linux/highmem.h>
+#include <linux/ptrace.h>
 #include <linux/pagemap.h>
 #include <linux/mempolicy.h>
 
 #include <linux/pagemap.h>
 #include <linux/mempolicy.h>
 
@@ -142,6 +143,9 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats
        dev_t dev = 0;
        int len;
 
        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;
        if (file) {
                struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
                dev = inode->i_sb->s_dev;
@@ -512,11 +516,22 @@ const struct file_operations proc_maps_operations = {
 #ifdef CONFIG_NUMA
 extern int show_numa_map(struct seq_file *m, void *v);
 
 #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,
 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)
 };
 
 static int numa_maps_open(struct inode *inode, struct file *file)
index 7cddf6b8635aa612362042e4b3609a270a61555c..d8b8c7183c243d86455390f1246da6c12891d396 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/mm.h>
 #include <linux/file.h>
 #include <linux/mount.h>
 #include <linux/mm.h>
 #include <linux/file.h>
 #include <linux/mount.h>
+#include <linux/ptrace.h>
 #include <linux/seq_file.h>
 #include "internal.h"
 
 #include <linux/seq_file.h>
 #include "internal.h"
 
@@ -143,6 +144,12 @@ out:
 static int show_map(struct seq_file *m, void *_vml)
 {
        struct vm_list_struct *vml = _vml;
 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);
 }
 
        return nommu_vma_show(m, vml->vma);
 }
 
index c904748f2290d8c48edca2dd451e1d71f4593b49..f0664bd5011c5633fda89e87bcdace3dad6e3de0 100644 (file)
@@ -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 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;
 
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
 static int maxolduid = 65535;
@@ -603,6 +604,16 @@ static ctl_table kern_table[] = {
                .proc_handler   = &proc_dointvec,
        },
 #endif
                .proc_handler   = &proc_dointvec,
        },
 #endif
+#ifdef CONFIG_PROC_FS
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "maps_protect",
+               .data           = &maps_protect,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+#endif
 
        { .ctl_name = 0 }
 };
 
        { .ctl_name = 0 }
 };
This page took 0.110347 seconds and 5 git commands to generate.