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 | |
| 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')
| -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; |
