diff options
author | Vasiliy Kulikov <segoon@openwall.com> | 2011-04-14 12:55:19 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2011-04-20 21:51:04 -0400 |
commit | b522f02184b413955f3bc952e3776ce41edc6355 (patch) | |
tree | 3141d04c93d5342c06e54bbba389b646a005cb04 /drivers/char | |
parent | 204ae24dc71f794aaad4df48a0083dfedc711afb (diff) |
agp: fix OOM and buffer overflow
page_count is copied from userspace. agp_allocate_memory() tries to
check whether this number is too big, but doesn't take into account the
wrap case. Also agp_create_user_memory() doesn't check whether
alloc_size is calculated from num_agp_pages variable without overflow.
This may lead to allocation of too small buffer with following buffer
overflow.
Another problem in agp code is not addressed in the patch - kernel memory
exhaustion (AGPIOC_RESERVE and AGPIOC_ALLOCATE ioctls). It is not checked
whether requested pid is a pid of the caller (no check in agpioc_reserve_wrap()).
Each allocation is limited to 16KB, though, there is no per-process limit.
This might lead to OOM situation, which is not even solved in case of the
caller death by OOM killer - the memory is allocated for another (faked) process.
Signed-off-by: Vasiliy Kulikov <segoon@openwall.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/agp/generic.c | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 012cba0d6d96..850a643ad694 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c | |||
@@ -115,6 +115,9 @@ static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages) | |||
115 | struct agp_memory *new; | 115 | struct agp_memory *new; |
116 | unsigned long alloc_size = num_agp_pages*sizeof(struct page *); | 116 | unsigned long alloc_size = num_agp_pages*sizeof(struct page *); |
117 | 117 | ||
118 | if (INT_MAX/sizeof(struct page *) < num_agp_pages) | ||
119 | return NULL; | ||
120 | |||
118 | new = kzalloc(sizeof(struct agp_memory), GFP_KERNEL); | 121 | new = kzalloc(sizeof(struct agp_memory), GFP_KERNEL); |
119 | if (new == NULL) | 122 | if (new == NULL) |
120 | return NULL; | 123 | return NULL; |
@@ -234,11 +237,14 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge, | |||
234 | int scratch_pages; | 237 | int scratch_pages; |
235 | struct agp_memory *new; | 238 | struct agp_memory *new; |
236 | size_t i; | 239 | size_t i; |
240 | int cur_memory; | ||
237 | 241 | ||
238 | if (!bridge) | 242 | if (!bridge) |
239 | return NULL; | 243 | return NULL; |
240 | 244 | ||
241 | if ((atomic_read(&bridge->current_memory_agp) + page_count) > bridge->max_memory_agp) | 245 | cur_memory = atomic_read(&bridge->current_memory_agp); |
246 | if ((cur_memory + page_count > bridge->max_memory_agp) || | ||
247 | (cur_memory + page_count < page_count)) | ||
242 | return NULL; | 248 | return NULL; |
243 | 249 | ||
244 | if (type >= AGP_USER_TYPES) { | 250 | if (type >= AGP_USER_TYPES) { |