123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- From 195331a7a64c2a4ba754e2527ca8973012db68c9 Mon Sep 17 00:00:00 2001
- From: B Horn <b@horn.uk>
- Date: Sun, 12 May 2024 04:09:24 +0100
- Subject: [PATCH] kern/disk: Limit recursion depth
- The grub_disk_read() may trigger other disk reads, e.g. via loopbacks.
- This may lead to very deep recursion which can corrupt the heap. So, fix
- the issue by limiting reads depth.
- Reported-by: B Horn <b@horn.uk>
- Signed-off-by: B Horn <b@horn.uk>
- Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
- Upstream: 18212f0648b6de7d71d4c8f41eb4d8b78b3a299b
- Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
- ---
- grub-core/kern/disk.c | 27 ++++++++++++++++++++-------
- include/grub/err.h | 3 ++-
- 2 files changed, 22 insertions(+), 8 deletions(-)
- diff --git a/grub-core/kern/disk.c b/grub-core/kern/disk.c
- index 1eda58fe9..82e04fd00 100644
- --- a/grub-core/kern/disk.c
- +++ b/grub-core/kern/disk.c
- @@ -28,6 +28,10 @@
-
- #define GRUB_CACHE_TIMEOUT 2
-
- +/* Disk reads may trigger other disk reads. So, limit recursion depth. */
- +#define MAX_READ_RECURSION_DEPTH 16
- +static unsigned int read_recursion_depth = 0;
- +
- /* The last time the disk was used. */
- static grub_uint64_t grub_last_time = 0;
-
- @@ -417,6 +421,8 @@ grub_err_t
- grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
- grub_off_t offset, grub_size_t size, void *buf)
- {
- + grub_err_t err = GRUB_ERR_NONE;
- +
- /* First of all, check if the region is within the disk. */
- if (grub_disk_adjust_range (disk, §or, &offset, size) != GRUB_ERR_NONE)
- {
- @@ -427,12 +433,17 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
- return grub_errno;
- }
-
- + if (++read_recursion_depth >= MAX_READ_RECURSION_DEPTH)
- + {
- + grub_error (GRUB_ERR_RECURSION_DEPTH, "grub_disk_read(): Maximum recursion depth exceeded");
- + goto error;
- + }
- +
- /* First read until first cache boundary. */
- if (offset || (sector & (GRUB_DISK_CACHE_SIZE - 1)))
- {
- grub_disk_addr_t start_sector;
- grub_size_t pos;
- - grub_err_t err;
- grub_size_t len;
-
- start_sector = sector & ~((grub_disk_addr_t) GRUB_DISK_CACHE_SIZE - 1);
- @@ -444,7 +455,7 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
- err = grub_disk_read_small (disk, start_sector,
- offset + pos, len, buf);
- if (err)
- - return err;
- + goto error;
- buf = (char *) buf + len;
- size -= len;
- offset += len;
- @@ -457,7 +468,6 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
- {
- char *data = NULL;
- grub_disk_addr_t agglomerate;
- - grub_err_t err;
-
- /* agglomerate read until we find a first cached entry. */
- for (agglomerate = 0; agglomerate
- @@ -493,7 +503,7 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
- - disk->log_sector_size),
- buf);
- if (err)
- - return err;
- + goto error;
-
- for (i = 0; i < agglomerate; i ++)
- grub_disk_cache_store (disk->dev->id, disk->id,
- @@ -527,13 +537,16 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
- /* And now read the last part. */
- if (size)
- {
- - grub_err_t err;
- err = grub_disk_read_small (disk, sector, 0, size, buf);
- if (err)
- - return err;
- + goto error;
- }
-
- - return grub_errno;
- + err = grub_errno;
- +
- + error:
- + read_recursion_depth--;
- + return err;
- }
-
- grub_uint64_t
- diff --git a/include/grub/err.h b/include/grub/err.h
- index b0e54e0a0..202fa8a7a 100644
- --- a/include/grub/err.h
- +++ b/include/grub/err.h
- @@ -74,7 +74,8 @@ typedef enum
- GRUB_ERR_EOF,
- GRUB_ERR_BAD_SIGNATURE,
- GRUB_ERR_BAD_FIRMWARE,
- - GRUB_ERR_STILL_REFERENCED
- + GRUB_ERR_STILL_REFERENCED,
- + GRUB_ERR_RECURSION_DEPTH
- }
- grub_err_t;
-
- --
- 2.50.1
|