Patchwork [hardy,CVE,1/2] proc: avoid information leaks to non-privileged processes

login
register
mail settings
Submitter Andy Whitcroft
Date June 21, 2011, 9:35 a.m.
Message ID <1308648925-13204-2-git-send-email-apw@canonical.com>
Download mbox | patch
Permalink /patch/101262/
State New
Headers show

Comments

Andy Whitcroft - June 21, 2011, 9:35 a.m.
From: Jake Edge <jake@lwn.net>

By using the same test as is used for /proc/pid/maps and /proc/pid/smaps,
only allow processes that can ptrace() a given process to see information
that might be used to bypass address space layout randomization (ASLR).
These include eip, esp, wchan, and start_stack in /proc/pid/stat as well
as the non-symbolic output from /proc/pid/wchan.

ASLR can be bypassed by sampling eip as shown by the proof-of-concept
code at http://code.google.com/p/fuzzyaslr/ As part of a presentation
(http://www.cr0.org/paper/to-jt-linux-alsr-leak.pdf) esp and wchan were
also noted as possibly usable information leaks as well.  The
start_stack address also leaks potentially useful information.

Cc: Stable Team <stable@kernel.org>
Signed-off-by: Jake Edge <jake@lwn.net>
Acked-by: Arjan van de Ven <arjan@linux.intel.com>
Acked-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

(backported from commit f83ce3e6b02d5e48b3a43b001390e2b58820389d)
CVE-2011-0726
BugLink: http://bugs.launchpad.net/bugs/799906
Signed-off-by: Andy Whitcroft <apw@canonical.com>
---
 fs/proc/array.c |   13 +++++++++----
 fs/proc/base.c  |    5 ++++-
 2 files changed, 13 insertions(+), 5 deletions(-)

Patch

diff --git a/fs/proc/array.c b/fs/proc/array.c
index eb97f28..87902dd 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -78,6 +78,7 @@ 
 #include <linux/rcupdate.h>
 #include <linux/delayacct.h>
 #include <linux/pid_namespace.h>
+#include <linux/ptrace.h>
 
 #include <asm/pgtable.h>
 #include <asm/processor.h>
@@ -396,6 +397,7 @@  static int do_task_stat(struct task_struct *task, char *buffer, int whole)
 	int res;
 	pid_t ppid = 0, pgid = -1, sid = -1;
 	int num_threads = 0;
+	int permitted;
 	struct mm_struct *mm;
 	unsigned long long start_time;
 	unsigned long cmin_flt = 0, cmaj_flt = 0;
@@ -411,11 +413,14 @@  static int do_task_stat(struct task_struct *task, char *buffer, int whole)
 
 	state = *get_task_state(task);
 	vsize = eip = esp = 0;
+	permitted = ptrace_may_attach(task);
 	mm = get_task_mm(task);
 	if (mm) {
 		vsize = task_vsize(mm);
-		eip = KSTK_EIP(task);
-		esp = KSTK_ESP(task);
+		if (permitted) {
+			eip = KSTK_EIP(task);
+			esp = KSTK_ESP(task);
+		}
 	}
 
 	get_task_comm(tcomm, task);
@@ -471,7 +476,7 @@  static int do_task_stat(struct task_struct *task, char *buffer, int whole)
 	}
 	rcu_read_unlock();
 
-	if (!whole || num_threads < 2)
+	if (permitted && (!whole || num_threads < 2))
 		wchan = get_wchan(task);
 	if (!whole) {
 		min_flt = task->min_flt;
@@ -523,7 +528,7 @@  static int do_task_stat(struct task_struct *task, char *buffer, int whole)
 		rsslim,
 		mm ? mm->start_code : 0,
 		mm ? mm->end_code : 0,
-		mm ? mm->start_stack : 0,
+		(permitted && mm) ? mm->start_stack : 0,
 		esp,
 		eip,
 		/* The signal information here is obsolete.
diff --git a/fs/proc/base.c b/fs/proc/base.c
index a91dc82..338097a 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -291,7 +291,10 @@  static int proc_pid_wchan(struct task_struct *task, char *buffer)
 	wchan = get_wchan(task);
 
 	if (lookup_symbol_name(wchan, symname) < 0)
-		return sprintf(buffer, "%lu", wchan);
+		if (!ptrace_may_attach(task))
+			return 0;
+		else
+			return sprintf(buffer, "%lu", wchan);
 	else
 		return sprintf(buffer, "%s", symname);
 }