Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 1164

kernel-2.6.18-238.el5.src.rpm

From: Amerigo Wang <amwang@redhat.com>
Date: Mon, 11 May 2009 06:22:03 -0400
Subject: [fs] proc: avoid info leaks to non-privileged processes
Message-id: 20090511102253.2662.24493.sendpatchset@localhost.localdomain
O-Subject: [RHEL5 PATCH] BZ499541: kernel: proc: avoid information leaks to non-privileged processes
Bugzilla: 499541
RH-Acked-by: Rik van Riel <riel@redhat.com>
RH-Acked-by: Dave Anderson <anderson@redhat.com>
RH-Acked-by: Chuck Ebbert <cebbert@redhat.com>

BZ499541:
https://bugzilla.redhat.com/show_bug.cgi?id=499541

Description of problem:
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.

Upstream commit:
http://git.kernel.org/linus/f83ce3e6b02d5e48b3a43b001390e2b58820389d

Test status:
I backport that patch to rhel5, and test it on x86_64, it is very fine.
A sample test result is this:

diff --git a/fs/proc/array.c b/fs/proc/array.c
index fbb1718..e0c38b0 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -77,6 +77,7 @@
 #include <linux/rcupdate.h>
 #include <linux/delayacct.h>
 #include <linux/resource.h>
+#include <linux/ptrace.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -331,6 +332,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
 	int res;
  	pid_t ppid, 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;
@@ -342,11 +344,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);
@@ -399,7 +404,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
 	read_unlock(&tasklist_lock);
 	mutex_unlock(&tty_mutex);
 
-	if (!whole || num_threads<2) {
+	if (permitted && (!whole || num_threads<2)) {
 		wchan = 0;
 		if (current->uid == task->uid || current->euid == task->uid ||
 				capable(CAP_SYS_NICE))
@@ -453,7 +458,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 5e1f772..55daa0a 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -562,7 +562,10 @@ static int proc_pid_wchan(struct task_struct *task, char *buffer)
 	sym_name = kallsyms_lookup(wchan, &size, &offset, &modname, namebuf);
 	if (sym_name)
 		return sprintf(buffer, "%s", sym_name);
-	return sprintf(buffer, "%lu", wchan);
+	if (!ptrace_may_attach(task))
+		return 0;
+	else
+		return sprintf(buffer, "%lu", wchan);
 }
 #endif /* CONFIG_KALLSYMS */