91
91
#define ROMFS_RECORD_KIND_DATA_POINTER (3)
92
92
#define ROMFS_RECORD_KIND_DIRECTORY (4)
93
93
#define ROMFS_RECORD_KIND_FILE (5)
94
+ #define ROMFS_RECORD_KIND_FILESYSTEM (0x14a6b1)
94
95
95
96
typedef mp_uint_t record_kind_t ;
96
97
@@ -101,34 +102,72 @@ struct _mp_obj_vfs_rom_t {
101
102
const uint8_t * filesystem_end ;
102
103
};
103
104
104
- static record_kind_t extract_record (const uint8_t * * fs , const uint8_t * * fs_next ) {
105
- record_kind_t record_kind = mp_decode_uint (fs );
106
- mp_uint_t record_len = mp_decode_uint (fs );
105
+ // Returns 0 for success, -1 for failure.
106
+ static int mp_decode_uint_checked (const uint8_t * * ptr , const uint8_t * ptr_max , mp_uint_t * value_out ) {
107
+ mp_uint_t unum = 0 ;
108
+ byte val ;
109
+ const uint8_t * p = * ptr ;
110
+ do {
111
+ if (p >= ptr_max ) {
112
+ return -1 ;
113
+ }
114
+ val = * p ++ ;
115
+ unum = (unum << 7 ) | (val & 0x7f );
116
+ } while ((val & 0x80 ) != 0 );
117
+ * ptr = p ;
118
+ * value_out = unum ;
119
+ return 0 ;
120
+ }
121
+
122
+ static record_kind_t extract_record (const uint8_t * * fs , const uint8_t * * fs_next , const uint8_t * fs_max ) {
123
+ mp_uint_t record_kind ;
124
+ if (mp_decode_uint_checked (fs , fs_max , & record_kind ) != 0 ) {
125
+ return ROMFS_RECORD_KIND_UNUSED ;
126
+ }
127
+ mp_uint_t record_len ;
128
+ if (mp_decode_uint_checked (fs , fs_max , & record_len ) != 0 ) {
129
+ return ROMFS_RECORD_KIND_UNUSED ;
130
+ }
107
131
* fs_next = * fs + record_len ;
108
132
return record_kind ;
109
133
}
110
134
111
- static void extract_data (mp_obj_vfs_rom_t * self , const uint8_t * fs , const uint8_t * fs_top , size_t * size_out , const uint8_t * * data_out ) {
112
- * size_out = 0 ;
113
- * data_out = NULL ;
135
+ // Returns 0 for success, a negative integer for failure.
136
+ static int extract_data (mp_obj_vfs_rom_t * self , const uint8_t * fs , const uint8_t * fs_top , size_t * size_out , const uint8_t * * data_out ) {
114
137
while (fs < fs_top ) {
115
138
const uint8_t * fs_next ;
116
- record_kind_t record_kind = extract_record (& fs , & fs_next );
117
- if (record_kind == ROMFS_RECORD_KIND_DATA_VERBATIM ) {
118
- // Verbatim data.
119
- * size_out = fs_next - fs ;
120
- * data_out = fs ;
139
+ record_kind_t record_kind = extract_record (& fs , & fs_next , fs_top );
140
+ if (record_kind == ROMFS_RECORD_KIND_UNUSED ) {
141
+ // Corrupt filesystem.
121
142
break ;
143
+ } else if (record_kind == ROMFS_RECORD_KIND_DATA_VERBATIM ) {
144
+ // Verbatim data.
145
+ if (size_out != NULL ) {
146
+ * size_out = fs_next - fs ;
147
+ * data_out = fs ;
148
+ }
149
+ return 0 ;
122
150
} else if (record_kind == ROMFS_RECORD_KIND_DATA_POINTER ) {
123
151
// Pointer to data.
124
- * size_out = mp_decode_uint (& fs );
125
- * data_out = self -> filesystem + mp_decode_uint (& fs );
126
- break ;
152
+ mp_uint_t size ;
153
+ if (mp_decode_uint_checked (& fs , fs_next , & size ) != 0 ) {
154
+ break ;
155
+ }
156
+ mp_uint_t offset ;
157
+ if (mp_decode_uint_checked (& fs , fs_next , & offset ) != 0 ) {
158
+ break ;
159
+ }
160
+ if (size_out != NULL ) {
161
+ * size_out = size ;
162
+ * data_out = self -> filesystem + offset ;
163
+ }
164
+ return 0 ;
127
165
} else {
128
166
// Skip this record.
129
167
fs = fs_next ;
130
168
}
131
169
}
170
+ return - MP_EIO ;
132
171
}
133
172
134
173
// Searches for `path` in the filesystem.
@@ -144,10 +183,17 @@ mp_import_stat_t mp_vfs_rom_search_filesystem(mp_obj_vfs_rom_t *self, const char
144
183
}
145
184
while (path_len > 0 && fs < fs_top ) {
146
185
const uint8_t * fs_next ;
147
- record_kind_t record_kind = extract_record (& fs , & fs_next );
148
- if (record_kind == ROMFS_RECORD_KIND_DIRECTORY || record_kind == ROMFS_RECORD_KIND_FILE ) {
186
+ record_kind_t record_kind = extract_record (& fs , & fs_next , fs_top );
187
+ if (record_kind == ROMFS_RECORD_KIND_UNUSED ) {
188
+ // Corrupt filesystem.
189
+ return MP_IMPORT_STAT_NO_EXIST ;
190
+ } else if (record_kind == ROMFS_RECORD_KIND_DIRECTORY || record_kind == ROMFS_RECORD_KIND_FILE ) {
149
191
// A directory or file record.
150
- mp_uint_t name_len = mp_decode_uint (& fs );
192
+ mp_uint_t name_len ;
193
+ if (mp_decode_uint_checked (& fs , fs_next , & name_len ) != 0 ) {
194
+ // Corrupt filesystem.
195
+ return MP_IMPORT_STAT_NO_EXIST ;
196
+ }
151
197
if ((name_len == path_len
152
198
|| (name_len < path_len && path [name_len ] == '/' ))
153
199
&& memcmp (path , fs , name_len ) == 0 ) {
@@ -167,8 +213,9 @@ mp_import_stat_t mp_vfs_rom_search_filesystem(mp_obj_vfs_rom_t *self, const char
167
213
if (path_len != 0 ) {
168
214
return MP_IMPORT_STAT_NO_EXIST ;
169
215
}
170
- if (size_out != NULL ) {
171
- extract_data (self , fs , fs_top , size_out , data_out );
216
+ if (extract_data (self , fs , fs_top , size_out , data_out ) != 0 ) {
217
+ // Corrupt filesystem.
218
+ return MP_IMPORT_STAT_NO_EXIST ;
172
219
}
173
220
return MP_IMPORT_STAT_FILE ;
174
221
}
@@ -214,7 +261,15 @@ static mp_obj_t vfs_rom_make_new(const mp_obj_type_t *type, size_t n_args, size_
214
261
}
215
262
216
263
// The ROMFS is a record itself, so enter into it and compute its limit.
217
- extract_record (& self -> filesystem , & self -> filesystem_end );
264
+ record_kind_t record_kind = extract_record (& self -> filesystem , & self -> filesystem_end , self -> filesystem + bufinfo .len );
265
+ if (record_kind != ROMFS_RECORD_KIND_FILESYSTEM ) {
266
+ mp_raise_OSError (MP_ENODEV );
267
+ }
268
+
269
+ // Check the filesystem is within the limits of the input buffer.
270
+ if (self -> filesystem_end > (const uint8_t * )bufinfo .buf + bufinfo .len ) {
271
+ mp_raise_OSError (MP_ENODEV );
272
+ }
218
273
219
274
return MP_OBJ_FROM_PTR (self );
220
275
}
@@ -259,13 +314,21 @@ static mp_obj_t vfs_rom_ilistdir_it_iternext(mp_obj_t self_in) {
259
314
260
315
while (self -> index < self -> index_top ) {
261
316
const uint8_t * index_next ;
262
- record_kind_t record_kind = extract_record (& self -> index , & index_next );
317
+ record_kind_t record_kind = extract_record (& self -> index , & index_next , self -> index_top );
263
318
uint32_t type ;
264
319
mp_uint_t name_len ;
265
320
size_t data_len ;
266
- if (record_kind == ROMFS_RECORD_KIND_DIRECTORY || record_kind == ROMFS_RECORD_KIND_FILE ) {
321
+ if (record_kind == ROMFS_RECORD_KIND_UNUSED ) {
322
+ // Corrupt filesystem.
323
+ self -> index = self -> index_top ;
324
+ break ;
325
+ } else if (record_kind == ROMFS_RECORD_KIND_DIRECTORY || record_kind == ROMFS_RECORD_KIND_FILE ) {
267
326
// A directory or file record.
268
- name_len = mp_decode_uint (& self -> index );
327
+ if (mp_decode_uint_checked (& self -> index , index_next , & name_len ) != 0 ) {
328
+ // Corrupt filesystem.
329
+ self -> index = self -> index_top ;
330
+ break ;
331
+ }
269
332
if (record_kind == ROMFS_RECORD_KIND_DIRECTORY ) {
270
333
// A directory.
271
334
type = MP_S_IFDIR ;
@@ -274,7 +337,10 @@ static mp_obj_t vfs_rom_ilistdir_it_iternext(mp_obj_t self_in) {
274
337
// A file.
275
338
type = MP_S_IFREG ;
276
339
const uint8_t * data_value ;
277
- extract_data (self -> vfs_rom , self -> index + name_len , index_next , & data_len , & data_value );
340
+ if (extract_data (self -> vfs_rom , self -> index + name_len , index_next , & data_len , & data_value ) != 0 ) {
341
+ // Corrupt filesystem.
342
+ break ;
343
+ }
278
344
}
279
345
} else {
280
346
// Skip this record.
0 commit comments