Sophie

Sophie

distrib > CentOS > 5 > x86_64 > by-pkgid > ea32411352494358b8d75a78402a4713 > files > 1191

kernel-2.6.18-238.19.1.el5.centos.plus.src.rpm

From: Oleg Nesterov <oleg@redhat.com>
Date: Thu, 23 Jun 2011 12:26:12 -0400
Subject: [fs] proc: fix signedness issue in next_pidmap
Message-id: <20110623122612.GA8446@redhat.com>
Patchwork-id: 36990
O-Subject: [RHEL5.7 PATCH] bz697827: proc: signedness issue in next_pidmap()
Bugzilla: 697827
CVE: CVE-2011-1593
RH-Acked-by: Petr Matousek <pmatouse@redhat.com>
RH-Acked-by: Prarit Bhargava <prarit@redhat.com>
RH-Acked-by: Jerome Marchand <jmarchan@redhat.com>

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

upstream commit c78193e9c7bcbf25b8237ad0dec82f805c4ea69b
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date:   Mon Apr 18 10:35:30 2011 -0700

    next_pidmap: fix overflow condition

    next_pidmap() just quietly accepted whatever 'last' pid that was passed
    in, which is not all that safe when one of the users is /proc.

    Admittedly the proc code should do some sanity checking on the range
    (and that will be the next commit), but that doesn't mean that the
    helper functions should just do that pidmap pointer arithmetic without
    checking the range of its arguments.

commit d8bdc59f215e62098bc5b4256fd9928bf27053a1
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date:   Mon Apr 18 10:36:54 2011 -0700

    proc: do proper range check on readdir offset

    Rather than pass in some random truncated offset to the pid-related
    functions, check that the offset is in range up-front.

    This is just cleanup, the previous commit fixed the real problem.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 6fdcc52..c84105f 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2609,10 +2609,14 @@ retry:
 int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
 	char buf[PROC_NUMBUF];
-	unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY;
+	unsigned int nr;
 	struct task_struct *task;
 	int tgid;
 
+	if (filp->f_pos >= PID_MAX_LIMIT + TGID_OFFSET)
+		goto out;
+	nr = filp->f_pos - FIRST_PROCESS_ENTRY;
+
 	if (!nr) {
 		ino_t ino = fake_ino(0,PROC_TGID_INO);
 		if (filldir(dirent, "self", 4, filp->f_pos, ino, DT_LNK) < 0)
diff --git a/kernel/pid.c b/kernel/pid.c
index e22e056..c2c9174 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -183,11 +183,14 @@ static int alloc_pidmap(void)
 	return -1;
 }
 
-static int next_pidmap(int last)
+static int next_pidmap(unsigned int last)
 {
 	int offset;
 	pidmap_t *map;
 
+	if (last >= PID_MAX_LIMIT)
+		return -1;
+
 	offset = (last + 1) & BITS_PER_PAGE_MASK;
 	map = &pidmap_array[(last + 1)/BITS_PER_PAGE];
 	for (; map < &pidmap_array[PIDMAP_ENTRIES]; map++, offset = 0) {