mirror of
https://github.com/micropython/micropython.git
synced 2026-01-05 11:40:18 +01:00
extmod/vfs_rom: Add bounds checking for all filesystem accesses.
Some checks are pending
JavaScript code lint and formatting with Biome / eslint (push) Waiting to run
Check code formatting / code-formatting (push) Waiting to run
Check spelling with codespell / codespell (push) Waiting to run
Build docs / build (push) Waiting to run
Check examples / embedding (push) Waiting to run
Package mpremote / build (push) Waiting to run
.mpy file format and tools / test (push) Waiting to run
Build ports metadata / build (push) Waiting to run
cc3200 port / build (push) Waiting to run
esp32 port / build_idf (esp32_build_cmod_spiram_s2) (push) Waiting to run
esp32 port / build_idf (esp32_build_s3_c3) (push) Waiting to run
esp8266 port / build (push) Waiting to run
mimxrt port / build (push) Waiting to run
nrf port / build (push) Waiting to run
powerpc port / build (push) Waiting to run
qemu port / build_and_test_arm (push) Waiting to run
qemu port / build_and_test_rv32 (push) Waiting to run
renesas-ra port / build_renesas_ra_board (push) Waiting to run
rp2 port / build (push) Waiting to run
samd port / build (push) Waiting to run
stm32 port / build_stm32 (stm32_misc_build) (push) Waiting to run
stm32 port / build_stm32 (stm32_nucleo_build) (push) Waiting to run
stm32 port / build_stm32 (stm32_pyb_build) (push) Waiting to run
unix port / minimal (push) Waiting to run
unix port / reproducible (push) Waiting to run
unix port / standard (push) Waiting to run
unix port / standard_v2 (push) Waiting to run
unix port / coverage (push) Waiting to run
unix port / coverage_32bit (push) Waiting to run
unix port / nanbox (push) Waiting to run
unix port / float (push) Waiting to run
unix port / stackless_clang (push) Waiting to run
unix port / float_clang (push) Waiting to run
unix port / settrace (push) Waiting to run
unix port / settrace_stackless (push) Waiting to run
unix port / macos (push) Waiting to run
unix port / qemu_mips (push) Waiting to run
unix port / qemu_arm (push) Waiting to run
unix port / qemu_riscv64 (push) Waiting to run
webassembly port / build (push) Waiting to run
windows port / build-vs (Debug, x64, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Debug, x64, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Debug, x86, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Debug, x86, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2019, dev, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2019, standard, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2022, standard, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-latest, standard, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2019, dev, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2019, standard, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2022, standard, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-latest, standard, 2017, [15, 16)) (push) Waiting to run
windows port / build-mingw (i686, mingw32, dev) (push) Waiting to run
windows port / build-mingw (i686, mingw32, standard) (push) Waiting to run
windows port / build-mingw (x86_64, mingw64, dev) (push) Waiting to run
windows port / build-mingw (x86_64, mingw64, standard) (push) Waiting to run
windows port / cross-build-on-linux (push) Waiting to run
zephyr port / build (push) Waiting to run
Python code lint and formatting with ruff / ruff (push) Waiting to run
Some checks are pending
JavaScript code lint and formatting with Biome / eslint (push) Waiting to run
Check code formatting / code-formatting (push) Waiting to run
Check spelling with codespell / codespell (push) Waiting to run
Build docs / build (push) Waiting to run
Check examples / embedding (push) Waiting to run
Package mpremote / build (push) Waiting to run
.mpy file format and tools / test (push) Waiting to run
Build ports metadata / build (push) Waiting to run
cc3200 port / build (push) Waiting to run
esp32 port / build_idf (esp32_build_cmod_spiram_s2) (push) Waiting to run
esp32 port / build_idf (esp32_build_s3_c3) (push) Waiting to run
esp8266 port / build (push) Waiting to run
mimxrt port / build (push) Waiting to run
nrf port / build (push) Waiting to run
powerpc port / build (push) Waiting to run
qemu port / build_and_test_arm (push) Waiting to run
qemu port / build_and_test_rv32 (push) Waiting to run
renesas-ra port / build_renesas_ra_board (push) Waiting to run
rp2 port / build (push) Waiting to run
samd port / build (push) Waiting to run
stm32 port / build_stm32 (stm32_misc_build) (push) Waiting to run
stm32 port / build_stm32 (stm32_nucleo_build) (push) Waiting to run
stm32 port / build_stm32 (stm32_pyb_build) (push) Waiting to run
unix port / minimal (push) Waiting to run
unix port / reproducible (push) Waiting to run
unix port / standard (push) Waiting to run
unix port / standard_v2 (push) Waiting to run
unix port / coverage (push) Waiting to run
unix port / coverage_32bit (push) Waiting to run
unix port / nanbox (push) Waiting to run
unix port / float (push) Waiting to run
unix port / stackless_clang (push) Waiting to run
unix port / float_clang (push) Waiting to run
unix port / settrace (push) Waiting to run
unix port / settrace_stackless (push) Waiting to run
unix port / macos (push) Waiting to run
unix port / qemu_mips (push) Waiting to run
unix port / qemu_arm (push) Waiting to run
unix port / qemu_riscv64 (push) Waiting to run
webassembly port / build (push) Waiting to run
windows port / build-vs (Debug, x64, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Debug, x64, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Debug, x86, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Debug, x86, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2019, dev, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2019, standard, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2022, standard, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-latest, standard, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2019, dev, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2019, standard, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2022, standard, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-latest, standard, 2017, [15, 16)) (push) Waiting to run
windows port / build-mingw (i686, mingw32, dev) (push) Waiting to run
windows port / build-mingw (i686, mingw32, standard) (push) Waiting to run
windows port / build-mingw (x86_64, mingw64, dev) (push) Waiting to run
windows port / build-mingw (x86_64, mingw64, standard) (push) Waiting to run
windows port / cross-build-on-linux (push) Waiting to run
zephyr port / build (push) Waiting to run
Python code lint and formatting with ruff / ruff (push) Waiting to run
Testing with ROMFS shows that it is relatively easy to end up with a corrupt filesystem on the device -- eg due to the ROMFS deploy process stopping half way through -- which could lead to hard crashes. Notably, there can be boot loops trying to mount a corrupt filesystem, crashes when importing modules like `os` that first scan the filesystem for `os.py`, and crashing when deploying a new ROMFS in certain cases because the old one is removed while still mounted. The main problem is that `mp_decode_uint()` has an loop that keeps going as long as it reads 0xff byte values, which can happen in the case of erased and unwritten flash. This commit adds full bounds checking in the new `mp_decode_uint_checked()` function, and that makes all ROMFS filesystem accesses robust. Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
@@ -223,6 +223,79 @@ class TestEdgeCases(unittest.TestCase):
|
||||
self.assertEqual(f.read(), b"contents")
|
||||
|
||||
|
||||
class TestCorrupt(unittest.TestCase):
|
||||
def test_corrupt_filesystem(self):
|
||||
# Make the filesystem length bigger than the buffer.
|
||||
romfs = bytearray(make_romfs(()))
|
||||
romfs[3] = 0x01
|
||||
with self.assertRaises(OSError):
|
||||
vfs.VfsRom(romfs)
|
||||
|
||||
# Corrupt the filesystem length.
|
||||
romfs = bytearray(make_romfs(()))
|
||||
romfs[3] = 0xFF
|
||||
with self.assertRaises(OSError):
|
||||
vfs.VfsRom(romfs)
|
||||
|
||||
# Corrupt the contents of the filesystem.
|
||||
romfs = bytearray(make_romfs(()))
|
||||
romfs[3] = 0x01
|
||||
romfs.extend(b"\xff\xff")
|
||||
fs = vfs.VfsRom(romfs)
|
||||
with self.assertRaises(OSError):
|
||||
fs.stat("a")
|
||||
self.assertEqual(list(fs.ilistdir("")), [])
|
||||
|
||||
def test_corrupt_file_entry(self):
|
||||
romfs = make_romfs((("file", b"data"),))
|
||||
|
||||
# Corrupt the length of filename.
|
||||
romfs_corrupt = bytearray(romfs)
|
||||
romfs_corrupt[7:] = b"\xff" * (len(romfs) - 7)
|
||||
fs = vfs.VfsRom(romfs_corrupt)
|
||||
with self.assertRaises(OSError):
|
||||
fs.stat("file")
|
||||
self.assertEqual(list(fs.ilistdir("")), [])
|
||||
|
||||
# Erase the data record (change it to a padding record).
|
||||
romfs_corrupt = bytearray(romfs)
|
||||
romfs_corrupt[12] = VfsRomWriter.ROMFS_RECORD_KIND_PADDING
|
||||
fs = vfs.VfsRom(romfs_corrupt)
|
||||
with self.assertRaises(OSError):
|
||||
fs.stat("file")
|
||||
self.assertEqual(list(fs.ilistdir("")), [])
|
||||
|
||||
# Corrupt the header of the data record.
|
||||
romfs_corrupt = bytearray(romfs)
|
||||
romfs_corrupt[12:] = b"\xff" * (len(romfs) - 12)
|
||||
fs = vfs.VfsRom(romfs_corrupt)
|
||||
with self.assertRaises(OSError):
|
||||
fs.stat("file")
|
||||
|
||||
# Corrupt the interior of the data record.
|
||||
romfs_corrupt = bytearray(romfs)
|
||||
romfs_corrupt[13:] = b"\xff" * (len(romfs) - 13)
|
||||
fs = vfs.VfsRom(romfs_corrupt)
|
||||
with self.assertRaises(OSError):
|
||||
fs.stat("file")
|
||||
|
||||
# Change the data record to an indirect pointer and corrupt the length.
|
||||
romfs_corrupt = bytearray(romfs)
|
||||
romfs_corrupt[12] = VfsRomWriter.ROMFS_RECORD_KIND_DATA_POINTER
|
||||
romfs_corrupt[14:18] = b"\xff\xff\xff\xff"
|
||||
fs = vfs.VfsRom(romfs_corrupt)
|
||||
with self.assertRaises(OSError):
|
||||
fs.stat("file")
|
||||
|
||||
# Change the data record to an indirect pointer and corrupt the offset.
|
||||
romfs_corrupt = bytearray(romfs)
|
||||
romfs_corrupt[12] = VfsRomWriter.ROMFS_RECORD_KIND_DATA_POINTER
|
||||
romfs_corrupt[14:18] = b"\x00\xff\xff\xff"
|
||||
fs = vfs.VfsRom(romfs_corrupt)
|
||||
with self.assertRaises(OSError):
|
||||
fs.stat("file")
|
||||
|
||||
|
||||
class TestStandalone(TestBase):
|
||||
def test_constructor(self):
|
||||
self.assertIsInstance(vfs.VfsRom(self.romfs), vfs.VfsRom)
|
||||
|
||||
Reference in New Issue
Block a user