aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/agp
diff options
context:
space:
mode:
authorVasiliy Kulikov <segoon@openwall.com>2011-04-14 12:55:16 -0400
committerDave Airlie <airlied@redhat.com>2011-04-20 22:16:55 -0400
commit194b3da873fd334ef183806db751473512af29ce (patch)
treecb6ac3d05ba2e0a07c02ea1cef0e41477ea29d2b /drivers/char/agp
parentb522f02184b413955f3bc952e3776ce41edc6355 (diff)
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>
Diffstat (limited to 'drivers/char/agp')
-rw-r--r--drivers/char/agp/generic.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 850a643ad694..b072648dc3f6 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -1095,8 +1095,8 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
1095 return -EINVAL; 1095 return -EINVAL;
1096 } 1096 }
1097 1097
1098 /* AK: could wrap */ 1098 if (((pg_start + mem->page_count) > num_entries) ||
1099 if ((pg_start + mem->page_count) > num_entries) 1099 ((pg_start + mem->page_count) < pg_start))
1100 return -EINVAL; 1100 return -EINVAL;
1101 1101
1102 j = pg_start; 1102 j = pg_start;
@@ -1130,7 +1130,7 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
1130{ 1130{
1131 size_t i; 1131 size_t i;
1132 struct agp_bridge_data *bridge; 1132 struct agp_bridge_data *bridge;
1133 int mask_type; 1133 int mask_type, num_entries;
1134 1134
1135 bridge = mem->bridge; 1135 bridge = mem->bridge;
1136 if (!bridge) 1136 if (!bridge)
@@ -1142,6 +1142,11 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
1142 if (type != mem->type) 1142 if (type != mem->type)
1143 return -EINVAL; 1143 return -EINVAL;
1144 1144
1145 num_entries = agp_num_entries();
1146 if (((pg_start + mem->page_count) > num_entries) ||
1147 ((pg_start + mem->page_count) < pg_start))
1148 return -EINVAL;
1149
1145 mask_type = bridge->driver->agp_type_to_mask_type(bridge, type); 1150 mask_type = bridge->driver->agp_type_to_mask_type(bridge, type);
1146 if (mask_type != 0) { 1151 if (mask_type != 0) {
1147 /* The generic routines know nothing of memory types */ 1152 /* The generic routines know nothing of memory types */