diff options
author | Bjorn Helgaas <bjorn.helgaas@hp.com> | 2010-10-26 17:41:28 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2010-10-26 18:33:28 -0400 |
commit | a1862e31079149a52b6223776228c3aee493d4a7 (patch) | |
tree | f70f7e3f33f63dcf77428b745f0dd01ecbee8e24 /kernel/resource.c | |
parent | 6909ba14c25b4db6be2ff89f4fa0fac2d70151a0 (diff) |
resources: handle overflow when aligning start of available area
If tmp.start is near ~0, ALIGN(tmp.start) may overflow, which would
make us think there's more available space than there really is. We
would likely return something that conflicts with a previous resource,
which would cause a failure when allocate_resource() requests the newly-
allocated region.
Reference: https://bugzilla.redhat.com/show_bug.cgi?id=646027
Reported-by: Fabrice Bellet <fabrice@bellet.info>
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'kernel/resource.c')
-rw-r--r-- | kernel/resource.c | 21 |
1 files changed, 13 insertions, 8 deletions
diff --git a/kernel/resource.c b/kernel/resource.c index 89d50412508c..e15b922d4ba4 100644 --- a/kernel/resource.c +++ b/kernel/resource.c | |||
@@ -392,7 +392,7 @@ static int find_resource(struct resource *root, struct resource *new, | |||
392 | void *alignf_data) | 392 | void *alignf_data) |
393 | { | 393 | { |
394 | struct resource *this = root->child; | 394 | struct resource *this = root->child; |
395 | struct resource tmp = *new, alloc; | 395 | struct resource tmp = *new, avail, alloc; |
396 | 396 | ||
397 | tmp.start = root->start; | 397 | tmp.start = root->start; |
398 | /* | 398 | /* |
@@ -410,14 +410,19 @@ static int find_resource(struct resource *root, struct resource *new, | |||
410 | tmp.end = root->end; | 410 | tmp.end = root->end; |
411 | 411 | ||
412 | resource_clip(&tmp, min, max); | 412 | resource_clip(&tmp, min, max); |
413 | tmp.start = ALIGN(tmp.start, align); | ||
414 | 413 | ||
415 | alloc.start = alignf(alignf_data, &tmp, size, align); | 414 | /* Check for overflow after ALIGN() */ |
416 | alloc.end = alloc.start + size - 1; | 415 | avail = *new; |
417 | if (resource_contains(&tmp, &alloc)) { | 416 | avail.start = ALIGN(tmp.start, align); |
418 | new->start = alloc.start; | 417 | avail.end = tmp.end; |
419 | new->end = alloc.end; | 418 | if (avail.start >= tmp.start) { |
420 | return 0; | 419 | alloc.start = alignf(alignf_data, &avail, size, align); |
420 | alloc.end = alloc.start + size - 1; | ||
421 | if (resource_contains(&avail, &alloc)) { | ||
422 | new->start = alloc.start; | ||
423 | new->end = alloc.end; | ||
424 | return 0; | ||
425 | } | ||
421 | } | 426 | } |
422 | if (!this) | 427 | if (!this) |
423 | break; | 428 | break; |