aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKees Cook <kees@outflux.net>2007-05-08 03:26:04 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-08 14:15:02 -0400
commit5096add84b9e96e2e0a9c72675c442fe5433388a (patch)
treef0444013cb7db32596d2b6febafc1ee4c2a4ea1f
parent4a1ccb5b1eff949a90ab830869cb23d6609c3d5f (diff)
proc: maps protection
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>
-rw-r--r--CREDITS2
-rw-r--r--Documentation/filesystems/proc.txt7
-rw-r--r--fs/proc/base.c4
-rw-r--r--fs/proc/internal.h2
-rw-r--r--fs/proc/task_mmu.c17
-rw-r--r--fs/proc/task_nommu.c7
-rw-r--r--kernel/sysctl.c11
7 files changed, 48 insertions, 2 deletions
diff --git a/CREDITS b/CREDITS
index c5f819bacda3..e71fdce0dc2f 100644
--- a/CREDITS
+++ b/CREDITS
@@ -661,7 +661,7 @@ N: Kees Cook
661E: kees@outflux.net 661E: kees@outflux.net
662W: http://outflux.net/ 662W: http://outflux.net/
663P: 1024D/17063E6D 9FA3 C49C 23C9 D1BC 2E30 1975 1FFF 4BA9 1706 3E6D 663P: 1024D/17063E6D 9FA3 C49C 23C9 D1BC 2E30 1975 1FFF 4BA9 1706 3E6D
664D: Minor updates to SCSI code for the Communications type 664D: Minor updates to SCSI types, added /proc/pid/maps protection
665S: (ask for current address) 665S: (ask for current address)
666S: USA 666S: USA
667 667
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 3f4b226572e7..4f3e84c520a5 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -1138,6 +1138,13 @@ determine whether or not they are still functioning properly.
1138Because the NMI watchdog shares registers with oprofile, by disabling the NMI 1138Because the NMI watchdog shares registers with oprofile, by disabling the NMI
1139watchdog, oprofile may have more registers to utilize. 1139watchdog, oprofile may have more registers to utilize.
1140 1140
1141maps_protect
1142------------
1143
1144Enables/Disables the protection of the per-process proc entries "maps" and
1145"smaps". When enabled, the contents of these files are visible only to
1146readers that are allowed to ptrace() the given process.
1147
1141 1148
11422.4 /proc/sys/vm - The virtual memory subsystem 11492.4 /proc/sys/vm - The virtual memory subsystem
1143----------------------------------------------- 1150-----------------------------------------------
diff --git a/fs/proc/base.c b/fs/proc/base.c
index a721acfd4fdc..17f7a7ee6c5e 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -64,6 +64,7 @@
64#include <linux/smp_lock.h> 64#include <linux/smp_lock.h>
65#include <linux/rcupdate.h> 65#include <linux/rcupdate.h>
66#include <linux/kallsyms.h> 66#include <linux/kallsyms.h>
67#include <linux/module.h>
67#include <linux/mount.h> 68#include <linux/mount.h>
68#include <linux/security.h> 69#include <linux/security.h>
69#include <linux/ptrace.h> 70#include <linux/ptrace.h>
@@ -123,6 +124,9 @@ struct pid_entry {
123 NULL, &proc_info_file_operations, \ 124 NULL, &proc_info_file_operations, \
124 { .proc_read = &proc_##OTYPE } ) 125 { .proc_read = &proc_##OTYPE } )
125 126
127int maps_protect;
128EXPORT_SYMBOL(maps_protect);
129
126static struct fs_struct *get_fs_struct(struct task_struct *task) 130static struct fs_struct *get_fs_struct(struct task_struct *task)
127{ 131{
128 struct fs_struct *fs; 132 struct fs_struct *fs;
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index f771889183c3..b215c3524fa6 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -37,6 +37,8 @@ do { \
37extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *); 37extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
38#endif 38#endif
39 39
40extern int maps_protect;
41
40extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f); 42extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f);
41extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **); 43extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **);
42extern int proc_tid_stat(struct task_struct *, char *); 44extern int proc_tid_stat(struct task_struct *, char *);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 4008c060f7ef..c24d81a5a040 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -3,6 +3,7 @@
3#include <linux/mount.h> 3#include <linux/mount.h>
4#include <linux/seq_file.h> 4#include <linux/seq_file.h>
5#include <linux/highmem.h> 5#include <linux/highmem.h>
6#include <linux/ptrace.h>
6#include <linux/pagemap.h> 7#include <linux/pagemap.h>
7#include <linux/mempolicy.h> 8#include <linux/mempolicy.h>
8 9
@@ -142,6 +143,9 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats
142 dev_t dev = 0; 143 dev_t dev = 0;
143 int len; 144 int len;
144 145
146 if (maps_protect && !ptrace_may_attach(task))
147 return -EACCES;
148
145 if (file) { 149 if (file) {
146 struct inode *inode = vma->vm_file->f_path.dentry->d_inode; 150 struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
147 dev = inode->i_sb->s_dev; 151 dev = inode->i_sb->s_dev;
@@ -512,11 +516,22 @@ const struct file_operations proc_maps_operations = {
512#ifdef CONFIG_NUMA 516#ifdef CONFIG_NUMA
513extern int show_numa_map(struct seq_file *m, void *v); 517extern int show_numa_map(struct seq_file *m, void *v);
514 518
519static int show_numa_map_checked(struct seq_file *m, void *v)
520{
521 struct proc_maps_private *priv = m->private;
522 struct task_struct *task = priv->task;
523
524 if (maps_protect && !ptrace_may_attach(task))
525 return -EACCES;
526
527 return show_numa_map(m, v);
528}
529
515static struct seq_operations proc_pid_numa_maps_op = { 530static struct seq_operations proc_pid_numa_maps_op = {
516 .start = m_start, 531 .start = m_start,
517 .next = m_next, 532 .next = m_next,
518 .stop = m_stop, 533 .stop = m_stop,
519 .show = show_numa_map 534 .show = show_numa_map_checked
520}; 535};
521 536
522static int numa_maps_open(struct inode *inode, struct file *file) 537static 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 7cddf6b8635a..d8b8c7183c24 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -2,6 +2,7 @@
2#include <linux/mm.h> 2#include <linux/mm.h>
3#include <linux/file.h> 3#include <linux/file.h>
4#include <linux/mount.h> 4#include <linux/mount.h>
5#include <linux/ptrace.h>
5#include <linux/seq_file.h> 6#include <linux/seq_file.h>
6#include "internal.h" 7#include "internal.h"
7 8
@@ -143,6 +144,12 @@ out:
143static int show_map(struct seq_file *m, void *_vml) 144static int show_map(struct seq_file *m, void *_vml)
144{ 145{
145 struct vm_list_struct *vml = _vml; 146 struct vm_list_struct *vml = _vml;
147 struct proc_maps_private *priv = m->private;
148 struct task_struct *task = priv->task;
149
150 if (maps_protect && !ptrace_may_attach(task))
151 return -EACCES;
152
146 return nommu_vma_show(m, vml->vma); 153 return nommu_vma_show(m, vml->vma);
147} 154}
148 155
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index c904748f2290..f0664bd5011c 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -76,6 +76,7 @@ extern int pid_max_min, pid_max_max;
76extern int sysctl_drop_caches; 76extern int sysctl_drop_caches;
77extern int percpu_pagelist_fraction; 77extern int percpu_pagelist_fraction;
78extern int compat_log; 78extern int compat_log;
79extern int maps_protect;
79 80
80/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ 81/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
81static int maxolduid = 65535; 82static int maxolduid = 65535;
@@ -603,6 +604,16 @@ static ctl_table kern_table[] = {
603 .proc_handler = &proc_dointvec, 604 .proc_handler = &proc_dointvec,
604 }, 605 },
605#endif 606#endif
607#ifdef CONFIG_PROC_FS
608 {
609 .ctl_name = CTL_UNNUMBERED,
610 .procname = "maps_protect",
611 .data = &maps_protect,
612 .maxlen = sizeof(int),
613 .mode = 0644,
614 .proc_handler = &proc_dointvec,
615 },
616#endif
606 617
607 { .ctl_name = 0 } 618 { .ctl_name = 0 }
608}; 619};