]>
Commit | Line | Data |
---|---|---|
6671639d JAK |
1 | From 9561d7ef621e5e68f12bcd916252ef1c11e60366 Mon Sep 17 00:00:00 2001 |
2 | From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com> | |
3 | Date: Wed, 6 Apr 2022 18:49:09 +0530 | |
4 | Subject: fs/f2fs: Do not read past the end of nat bitmap | |
5 | ||
6 | A corrupt f2fs filesystem could have a block offset or a bitmap | |
7 | offset that would cause us to read beyond the bounds of the nat | |
8 | bitmap. | |
9 | ||
10 | Introduce the nat_bitmap_size member in grub_f2fs_data which holds | |
11 | the size of nat bitmap. | |
12 | ||
13 | Set the size when loading the nat bitmap in nat_bitmap_ptr(), and | |
14 | catch when an invalid offset would create a pointer past the end of | |
15 | the allocated space. | |
16 | ||
17 | Check against the bitmap size in grub_f2fs_test_bit() test bit to avoid | |
18 | reading past the end of the nat bitmap. | |
19 | ||
20 | Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com> | |
21 | Signed-off-by: Daniel Axtens <dja@axtens.net> | |
22 | Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> | |
23 | --- | |
24 | grub-core/fs/f2fs.c | 33 +++++++++++++++++++++++++++------ | |
25 | 1 file changed, 27 insertions(+), 6 deletions(-) | |
26 | ||
27 | diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c | |
28 | index 63702214b..8898b235e 100644 | |
29 | --- a/grub-core/fs/f2fs.c | |
30 | +++ b/grub-core/fs/f2fs.c | |
31 | @@ -122,6 +122,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); | |
32 | #define F2FS_INLINE_DOTS 0x10 /* File having implicit dot dentries. */ | |
33 | ||
34 | #define MAX_VOLUME_NAME 512 | |
35 | +#define MAX_NAT_BITMAP_SIZE 3900 | |
36 | ||
37 | enum FILE_TYPE | |
38 | { | |
39 | @@ -183,7 +184,7 @@ struct grub_f2fs_checkpoint | |
40 | grub_uint32_t checksum_offset; | |
41 | grub_uint64_t elapsed_time; | |
42 | grub_uint8_t alloc_type[MAX_ACTIVE_LOGS]; | |
43 | - grub_uint8_t sit_nat_version_bitmap[3900]; | |
44 | + grub_uint8_t sit_nat_version_bitmap[MAX_NAT_BITMAP_SIZE]; | |
45 | grub_uint32_t checksum; | |
46 | } GRUB_PACKED; | |
47 | ||
48 | @@ -302,6 +303,7 @@ struct grub_f2fs_data | |
49 | ||
50 | struct grub_f2fs_nat_journal nat_j; | |
51 | char *nat_bitmap; | |
52 | + grub_uint32_t nat_bitmap_size; | |
53 | ||
54 | grub_disk_t disk; | |
55 | struct grub_f2fs_node *inode; | |
56 | @@ -377,15 +379,20 @@ sum_blk_addr (struct grub_f2fs_data *data, int base, int type) | |
57 | } | |
58 | ||
59 | static void * | |
60 | -nat_bitmap_ptr (struct grub_f2fs_data *data) | |
61 | +nat_bitmap_ptr (struct grub_f2fs_data *data, grub_uint32_t *nat_bitmap_size) | |
62 | { | |
63 | struct grub_f2fs_checkpoint *ckpt = &data->ckpt; | |
64 | grub_uint32_t offset; | |
65 | + *nat_bitmap_size = MAX_NAT_BITMAP_SIZE; | |
66 | ||
67 | if (grub_le_to_cpu32 (data->sblock.cp_payload) > 0) | |
68 | return ckpt->sit_nat_version_bitmap; | |
69 | ||
70 | offset = grub_le_to_cpu32 (ckpt->sit_ver_bitmap_bytesize); | |
71 | + if (offset >= MAX_NAT_BITMAP_SIZE) | |
72 | + return NULL; | |
73 | + | |
74 | + *nat_bitmap_size = *nat_bitmap_size - offset; | |
75 | ||
76 | return ckpt->sit_nat_version_bitmap + offset; | |
77 | } | |
78 | @@ -438,11 +445,15 @@ grub_f2fs_crc_valid (grub_uint32_t blk_crc, void *buf, const grub_uint32_t len) | |
79 | } | |
80 | ||
81 | static int | |
82 | -grub_f2fs_test_bit (grub_uint32_t nr, const char *p) | |
83 | +grub_f2fs_test_bit (grub_uint32_t nr, const char *p, grub_uint32_t len) | |
84 | { | |
85 | int mask; | |
86 | + grub_uint32_t shifted_nr = (nr >> 3); | |
87 | + | |
88 | + if (shifted_nr >= len) | |
89 | + return -1; | |
90 | ||
91 | - p += (nr >> 3); | |
92 | + p += shifted_nr; | |
93 | mask = 1 << (7 - (nr & 0x07)); | |
94 | ||
95 | return mask & *p; | |
96 | @@ -662,6 +673,7 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) | |
97 | grub_uint32_t seg_off, block_off, entry_off, block_addr; | |
98 | grub_uint32_t blkaddr = 0; | |
99 | grub_err_t err; | |
100 | + int result_bit; | |
101 | ||
102 | err = get_blkaddr_from_nat_journal (data, nid, &blkaddr); | |
103 | if (err != GRUB_ERR_NONE) | |
104 | @@ -682,8 +694,15 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) | |
105 | ((seg_off * data->blocks_per_seg) << 1) + | |
106 | (block_off & (data->blocks_per_seg - 1)); | |
107 | ||
108 | - if (grub_f2fs_test_bit (block_off, data->nat_bitmap)) | |
109 | + result_bit = grub_f2fs_test_bit (block_off, data->nat_bitmap, | |
110 | + data->nat_bitmap_size); | |
111 | + if (result_bit > 0) | |
112 | block_addr += data->blocks_per_seg; | |
113 | + else if (result_bit == -1) | |
114 | + { | |
115 | + grub_free (nat_block); | |
116 | + return 0; | |
117 | + } | |
118 | ||
119 | err = grub_f2fs_block_read (data, block_addr, nat_block); | |
120 | if (err) | |
121 | @@ -833,7 +852,9 @@ grub_f2fs_mount (grub_disk_t disk) | |
122 | if (err) | |
123 | goto fail; | |
124 | ||
125 | - data->nat_bitmap = nat_bitmap_ptr (data); | |
126 | + data->nat_bitmap = nat_bitmap_ptr (data, &data->nat_bitmap_size); | |
127 | + if (data->nat_bitmap == NULL) | |
128 | + goto fail; | |
129 | ||
130 | err = get_nat_journal (data); | |
131 | if (err) |