Sophie

Sophie

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

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

From: Jerome Marchand <jmarchan@redhat.com>
Date: Thu, 23 Jun 2011 13:04:06 -0400
Subject: [char] agp: fix arbitrary kernel memory writes
Message-id: <4E0339C6.2060902@redhat.com>
Patchwork-id: 36993
O-Subject: [RHEL5.7 PATCH] CVE-2011-1745, CVE-2011-2022: agp: fix arbitrary kernel memory writes
Bugzilla: 699006
CVE: CVE-2011-1745 CVE-2011-2022
RH-Acked-by: Petr Matousek <pmatouse@redhat.com>
RH-Acked-by: Dave Airlie <airlied@redhat.com>

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

This is a backport of the following commit:

commit 194b3da873fd334ef183806db751473512af29ce
Author: Vasiliy Kulikov <segoon@openwall.com>
Date:   Thu Apr 14 20:55:16 2011 +0400

    agp: fix arbitrary kernel memory writes

    pg_start is copied from userspace on AGPIOC_BIND and AGPIOC_UNBIND ioctl
    cmds of agp_ioctl() and passed to agpioc_bind_wrap().  As said in the
    comment, (pg_start + mem->page_count) may wrap in case of AGPIOC_BIND,
    and it is not checked at all in case of AGPIOC_UNBIND.  As a result, user
    with sufficient privileges (usually "video" group) may generate either
    local DoS or privilege escalation.

    Signed-off-by: Vasiliy Kulikov <segoon@openwall.com>
    Signed-off-by: Dave Airlie <airlied@redhat.com>

This patch fixes both  CVE-2011-1745 and CVE-2011-2022.

I haven't tested it yet, for lack of hardware.

Regards,
Jerome


diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 57af6cd..563feab 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -975,8 +975,8 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
 		return -EINVAL;
 	}
 
-	/* AK: could wrap */
-	if ((pg_start + mem->page_count) > num_entries)
+	if (((pg_start + mem->page_count) > num_entries) ||
+	    ((pg_start + mem->page_count) < pg_start))
 		return -EINVAL;
 
 	j = pg_start;
@@ -1007,6 +1007,7 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
 {
 	size_t i;
 	struct agp_bridge_data *bridge;
+	int num_entries;
 
 	bridge = mem->bridge;
 	if (!bridge)
@@ -1017,6 +1018,11 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
 		return -EINVAL;
 	}
 
+	num_entries = agp_num_entries();
+	if (((pg_start + mem->page_count) > num_entries) ||
+	    ((pg_start + mem->page_count) < pg_start))
+		return -EINVAL;
+
 	/* AK: bogus, should encode addresses > 4GB */
 	for (i = pg_start; i < (mem->page_count + pg_start); i++) {
 		writel(bridge->scratch_page, bridge->gatt_table+i);