9191#define ROMFS_RECORD_KIND_DATA_POINTER (3)
9292#define ROMFS_RECORD_KIND_DIRECTORY (4)
9393#define ROMFS_RECORD_KIND_FILE (5)
94+ #define ROMFS_RECORD_KIND_FILESYSTEM (0x14a6b1)
9495
9596typedef mp_uint_t record_kind_t ;
9697
@@ -101,34 +102,72 @@ struct _mp_obj_vfs_rom_t {
101102 const uint8_t * filesystem_end ;
102103};
103104
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+ }
107131 * fs_next = * fs + record_len ;
108132 return record_kind ;
109133}
110134
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 ) {
114137 while (fs < fs_top ) {
115138 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.
121142 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 ;
122150 } else if (record_kind == ROMFS_RECORD_KIND_DATA_POINTER ) {
123151 // 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 ;
127165 } else {
128166 // Skip this record.
129167 fs = fs_next ;
130168 }
131169 }
170+ return - MP_EIO ;
132171}
133172
134173// 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
144183 }
145184 while (path_len > 0 && fs < fs_top ) {
146185 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 ) {
149191 // 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+ }
151197 if ((name_len == path_len
152198 || (name_len < path_len && path [name_len ] == '/' ))
153199 && 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
167213 if (path_len != 0 ) {
168214 return MP_IMPORT_STAT_NO_EXIST ;
169215 }
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 ;
172219 }
173220 return MP_IMPORT_STAT_FILE ;
174221 }
@@ -214,7 +261,15 @@ static mp_obj_t vfs_rom_make_new(const mp_obj_type_t *type, size_t n_args, size_
214261 }
215262
216263 // 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+ }
218273
219274 return MP_OBJ_FROM_PTR (self );
220275}
@@ -259,13 +314,21 @@ static mp_obj_t vfs_rom_ilistdir_it_iternext(mp_obj_t self_in) {
259314
260315 while (self -> index < self -> index_top ) {
261316 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 );
263318 uint32_t type ;
264319 mp_uint_t name_len ;
265320 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 ) {
267326 // 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+ }
269332 if (record_kind == ROMFS_RECORD_KIND_DIRECTORY ) {
270333 // A directory.
271334 type = MP_S_IFDIR ;
@@ -274,7 +337,10 @@ static mp_obj_t vfs_rom_ilistdir_it_iternext(mp_obj_t self_in) {
274337 // A file.
275338 type = MP_S_IFREG ;
276339 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+ }
278344 }
279345 } else {
280346 // Skip this record.
0 commit comments