summaryrefslogtreecommitdiffstats
path: root/debian/patches/0088-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch
blob: 5f06bd43383d2ceedb76b5ccf4564e01930b9544 (plain)
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
120
121
122
123
124
125
126
127
128
129
130
131
From 9561d7ef621e5e68f12bcd916252ef1c11e60366 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Wed, 6 Apr 2022 18:49:09 +0530
Subject: fs/f2fs: Do not read past the end of nat bitmap

A corrupt f2fs filesystem could have a block offset or a bitmap
offset that would cause us to read beyond the bounds of the nat
bitmap.

Introduce the nat_bitmap_size member in grub_f2fs_data which holds
the size of nat bitmap.

Set the size when loading the nat bitmap in nat_bitmap_ptr(), and
catch when an invalid offset would create a pointer past the end of
the allocated space.

Check against the bitmap size in grub_f2fs_test_bit() test bit to avoid
reading past the end of the nat bitmap.

Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
 grub-core/fs/f2fs.c | 33 +++++++++++++++++++++++++++------
 1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c
index 63702214b..8898b235e 100644
--- a/grub-core/fs/f2fs.c
+++ b/grub-core/fs/f2fs.c
@@ -122,6 +122,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
 #define F2FS_INLINE_DOTS          0x10  /* File having implicit dot dentries. */
 
 #define MAX_VOLUME_NAME           512
+#define MAX_NAT_BITMAP_SIZE       3900
 
 enum FILE_TYPE
 {
@@ -183,7 +184,7 @@ struct grub_f2fs_checkpoint
   grub_uint32_t                   checksum_offset;
   grub_uint64_t                   elapsed_time;
   grub_uint8_t                    alloc_type[MAX_ACTIVE_LOGS];
-  grub_uint8_t                    sit_nat_version_bitmap[3900];
+  grub_uint8_t                    sit_nat_version_bitmap[MAX_NAT_BITMAP_SIZE];
   grub_uint32_t                   checksum;
 } GRUB_PACKED;
 
@@ -302,6 +303,7 @@ struct grub_f2fs_data
 
   struct grub_f2fs_nat_journal    nat_j;
   char                            *nat_bitmap;
+  grub_uint32_t                   nat_bitmap_size;
 
   grub_disk_t                     disk;
   struct grub_f2fs_node           *inode;
@@ -377,15 +379,20 @@ sum_blk_addr (struct grub_f2fs_data *data, int base, int type)
 }
 
 static void *
-nat_bitmap_ptr (struct grub_f2fs_data *data)
+nat_bitmap_ptr (struct grub_f2fs_data *data, grub_uint32_t *nat_bitmap_size)
 {
   struct grub_f2fs_checkpoint *ckpt = &data->ckpt;
   grub_uint32_t offset;
+  *nat_bitmap_size = MAX_NAT_BITMAP_SIZE;
 
   if (grub_le_to_cpu32 (data->sblock.cp_payload) > 0)
     return ckpt->sit_nat_version_bitmap;
 
   offset = grub_le_to_cpu32 (ckpt->sit_ver_bitmap_bytesize);
+  if (offset >= MAX_NAT_BITMAP_SIZE)
+     return NULL;
+
+  *nat_bitmap_size = *nat_bitmap_size - offset;
 
   return ckpt->sit_nat_version_bitmap + offset;
 }
@@ -438,11 +445,15 @@ grub_f2fs_crc_valid (grub_uint32_t blk_crc, void *buf, const grub_uint32_t len)
 }
 
 static int
-grub_f2fs_test_bit (grub_uint32_t nr, const char *p)
+grub_f2fs_test_bit (grub_uint32_t nr, const char *p, grub_uint32_t len)
 {
   int mask;
+  grub_uint32_t shifted_nr = (nr >> 3);
+
+  if (shifted_nr >= len)
+    return -1;
 
-  p += (nr >> 3);
+  p += shifted_nr;
   mask = 1 << (7 - (nr & 0x07));
 
   return mask & *p;
@@ -662,6 +673,7 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
   grub_uint32_t seg_off, block_off, entry_off, block_addr;
   grub_uint32_t blkaddr = 0;
   grub_err_t err;
+  int result_bit;
 
   err = get_blkaddr_from_nat_journal (data, nid, &blkaddr);
   if (err != GRUB_ERR_NONE)
@@ -682,8 +694,15 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid)
         ((seg_off * data->blocks_per_seg) << 1) +
         (block_off & (data->blocks_per_seg - 1));
 
-  if (grub_f2fs_test_bit (block_off, data->nat_bitmap))
+  result_bit = grub_f2fs_test_bit (block_off, data->nat_bitmap,
+                                   data->nat_bitmap_size);
+  if (result_bit > 0)
     block_addr += data->blocks_per_seg;
+  else if (result_bit == -1)
+    {
+      grub_free (nat_block);
+      return 0;
+    }
 
   err = grub_f2fs_block_read (data, block_addr, nat_block);
   if (err)
@@ -833,7 +852,9 @@ grub_f2fs_mount (grub_disk_t disk)
   if (err)
     goto fail;
 
-  data->nat_bitmap = nat_bitmap_ptr (data);
+  data->nat_bitmap = nat_bitmap_ptr (data, &data->nat_bitmap_size);
+  if (data->nat_bitmap == NULL)
+    goto fail;
 
   err = get_nat_journal (data);
   if (err)