1*4882a593SmuzhiyunFrom a1845e90fc19fb5e904091bad8a378f458798e4a Mon Sep 17 00:00:00 2001
2*4882a593SmuzhiyunFrom: Peter Jones <pjones@redhat.com>
3*4882a593SmuzhiyunDate: Sun, 19 Jul 2020 15:48:20 -0400
4*4882a593SmuzhiyunSubject: [PATCH] lvm: Fix two more potential data-dependent alloc
5*4882a593Smuzhiyun overflows
6*4882a593SmuzhiyunMIME-Version: 1.0
7*4882a593SmuzhiyunContent-Type: text/plain; charset=UTF-8
8*4882a593SmuzhiyunContent-Transfer-Encoding: 8bit
9*4882a593Smuzhiyun
10*4882a593SmuzhiyunIt appears to be possible to make a (possibly invalid) lvm PV with
11*4882a593Smuzhiyuna metadata size field that overflows our type when adding it to the
12*4882a593Smuzhiyunaddress we've allocated. Even if it doesn't, it may be possible to do so
13*4882a593Smuzhiyunwith the math using the outcome of that as an operand. Check them both.
14*4882a593Smuzhiyun
15*4882a593SmuzhiyunSigned-off-by: Peter Jones <pjones@redhat.com>
16*4882a593SmuzhiyunSigned-off-by: Darren Kenny <darren.kenny@oracle.com>
17*4882a593SmuzhiyunReviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
18*4882a593SmuzhiyunSigned-off-by: Stefan Sørensen <stefan.sorensen@spectralink.com>
19*4882a593Smuzhiyun---
20*4882a593Smuzhiyun grub-core/disk/lvm.c | 48 ++++++++++++++++++++++++++++++++++++--------
21*4882a593Smuzhiyun 1 file changed, 40 insertions(+), 8 deletions(-)
22*4882a593Smuzhiyun
23*4882a593Smuzhiyundiff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c
24*4882a593Smuzhiyunindex d1df640b3..139fafd47 100644
25*4882a593Smuzhiyun--- a/grub-core/disk/lvm.c
26*4882a593Smuzhiyun+++ b/grub-core/disk/lvm.c
27*4882a593Smuzhiyun@@ -25,6 +25,7 @@
28*4882a593Smuzhiyun #include <grub/lvm.h>
29*4882a593Smuzhiyun #include <grub/partition.h>
30*4882a593Smuzhiyun #include <grub/i18n.h>
31*4882a593Smuzhiyun+#include <grub/safemath.h>
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #ifdef GRUB_UTIL
34*4882a593Smuzhiyun #include <grub/emu/misc.h>
35*4882a593Smuzhiyun@@ -102,10 +103,11 @@ grub_lvm_detect (grub_disk_t disk,
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun   grub_err_t err;
38*4882a593Smuzhiyun   grub_uint64_t mda_offset, mda_size;
39*4882a593Smuzhiyun+  grub_size_t ptr;
40*4882a593Smuzhiyun   char buf[GRUB_LVM_LABEL_SIZE];
41*4882a593Smuzhiyun   char vg_id[GRUB_LVM_ID_STRLEN+1];
42*4882a593Smuzhiyun   char pv_id[GRUB_LVM_ID_STRLEN+1];
43*4882a593Smuzhiyun-  char *metadatabuf, *p, *q, *vgname;
44*4882a593Smuzhiyun+  char *metadatabuf, *p, *q, *mda_end, *vgname;
45*4882a593Smuzhiyun   struct grub_lvm_label_header *lh = (struct grub_lvm_label_header *) buf;
46*4882a593Smuzhiyun   struct grub_lvm_pv_header *pvh;
47*4882a593Smuzhiyun   struct grub_lvm_disk_locn *dlocn;
48*4882a593Smuzhiyun@@ -205,19 +207,31 @@ grub_lvm_detect (grub_disk_t disk,
49*4882a593Smuzhiyun 		   grub_le_to_cpu64 (rlocn->size) -
50*4882a593Smuzhiyun 		   grub_le_to_cpu64 (mdah->size));
51*4882a593Smuzhiyun     }
52*4882a593Smuzhiyun-  p = q = metadatabuf + grub_le_to_cpu64 (rlocn->offset);
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun-  while (*q != ' ' && q < metadatabuf + mda_size)
55*4882a593Smuzhiyun-    q++;
56*4882a593Smuzhiyun-
57*4882a593Smuzhiyun-  if (q == metadatabuf + mda_size)
58*4882a593Smuzhiyun+  if (grub_add ((grub_size_t)metadatabuf,
59*4882a593Smuzhiyun+		(grub_size_t)grub_le_to_cpu64 (rlocn->offset),
60*4882a593Smuzhiyun+		&ptr))
61*4882a593Smuzhiyun     {
62*4882a593Smuzhiyun+ error_parsing_metadata:
63*4882a593Smuzhiyun #ifdef GRUB_UTIL
64*4882a593Smuzhiyun       grub_util_info ("error parsing metadata");
65*4882a593Smuzhiyun #endif
66*4882a593Smuzhiyun       goto fail2;
67*4882a593Smuzhiyun     }
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun+  p = q = (char *)ptr;
70*4882a593Smuzhiyun+
71*4882a593Smuzhiyun+  if (grub_add ((grub_size_t)metadatabuf, (grub_size_t)mda_size, &ptr))
72*4882a593Smuzhiyun+    goto error_parsing_metadata;
73*4882a593Smuzhiyun+
74*4882a593Smuzhiyun+  mda_end = (char *)ptr;
75*4882a593Smuzhiyun+
76*4882a593Smuzhiyun+  while (*q != ' ' && q < mda_end)
77*4882a593Smuzhiyun+    q++;
78*4882a593Smuzhiyun+
79*4882a593Smuzhiyun+  if (q == mda_end)
80*4882a593Smuzhiyun+    goto error_parsing_metadata;
81*4882a593Smuzhiyun+
82*4882a593Smuzhiyun   vgname_len = q - p;
83*4882a593Smuzhiyun   vgname = grub_malloc (vgname_len + 1);
84*4882a593Smuzhiyun   if (!vgname)
85*4882a593Smuzhiyun@@ -367,8 +381,26 @@ grub_lvm_detect (grub_disk_t disk,
86*4882a593Smuzhiyun 	      {
87*4882a593Smuzhiyun 		const char *iptr;
88*4882a593Smuzhiyun 		char *optr;
89*4882a593Smuzhiyun-		lv->fullname = grub_malloc (sizeof ("lvm/") - 1 + 2 * vgname_len
90*4882a593Smuzhiyun-					    + 1 + 2 * s + 1);
91*4882a593Smuzhiyun+
92*4882a593Smuzhiyun+		/*
93*4882a593Smuzhiyun+		 * This is kind of hard to read with our safe (but rather
94*4882a593Smuzhiyun+		 * baroque) math primatives, but it boils down to:
95*4882a593Smuzhiyun+		 *
96*4882a593Smuzhiyun+		 *   sz0 = vgname_len * 2 + 1 +
97*4882a593Smuzhiyun+		 *         s * 2 + 1 +
98*4882a593Smuzhiyun+		 *         sizeof ("lvm/") - 1;
99*4882a593Smuzhiyun+		 */
100*4882a593Smuzhiyun+		grub_size_t sz0 = vgname_len, sz1 = s;
101*4882a593Smuzhiyun+
102*4882a593Smuzhiyun+		if (grub_mul (sz0, 2, &sz0) ||
103*4882a593Smuzhiyun+		    grub_add (sz0, 1, &sz0) ||
104*4882a593Smuzhiyun+		    grub_mul (sz1, 2, &sz1) ||
105*4882a593Smuzhiyun+		    grub_add (sz1, 1, &sz1) ||
106*4882a593Smuzhiyun+		    grub_add (sz0, sz1, &sz0) ||
107*4882a593Smuzhiyun+		    grub_add (sz0, sizeof ("lvm/") - 1, &sz0))
108*4882a593Smuzhiyun+		  goto lvs_fail;
109*4882a593Smuzhiyun+
110*4882a593Smuzhiyun+		lv->fullname = grub_malloc (sz0);
111*4882a593Smuzhiyun 		if (!lv->fullname)
112*4882a593Smuzhiyun 		  goto lvs_fail;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun--
115*4882a593Smuzhiyun2.26.2
116*4882a593Smuzhiyun
117