File: kern-disk-Limit-recursion-depth.patch

package info (click to toggle)
grub2 2.12-9
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie, trixie-proposed-updates, trixie-updates
  • size: 70,780 kB
  • sloc: ansic: 424,740; asm: 16,228; sh: 9,525; cpp: 2,095; makefile: 1,590; python: 1,468; sed: 431; lex: 393; yacc: 268; awk: 85; lisp: 54; perl: 31
file content (119 lines) | stat: -rw-r--r-- 3,521 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
From: B Horn <b@horn.uk>
Date: Sun, 12 May 2024 04:09:24 +0100
Subject: 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>
---
 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 1eda58f..82e04fd 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, &sector, &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 b0e54e0..202fa8a 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;