Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ add_executable(moria
src/extract/compressed.cpp
src/extract/android_sparse.cpp
src/extract/ext.cpp
src/extract/reiserfs.cpp
src/extract/jffs2.cpp
src/extract/ubifs.cpp
src/extract/tar.cpp
Expand Down Expand Up @@ -254,6 +255,7 @@ if(Python3_Interpreter_FOUND)
test_esp32_part
test_esp32_nvs
test_legacy_fs
test_reiserfs_extract
test_luks
test_lzma
test_jzlzma
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ moria --help

Unpacked in-process, no external tools and no sudo:

- **Filesystems:** SquashFS, ext2/3/4, F2FS, FAT12/16/32, exFAT, NTFS, HFS+/HFSX, XFS, btrfs, JFFS2, UBI/UBIFS, romfs, YAFFS2, cramfs, EROFS
- **Filesystems:** SquashFS, ext2/3/4, F2FS, FAT12/16/32, exFAT, NTFS, HFS+/HFSX, XFS, btrfs, JFFS2, UBI/UBIFS, romfs, YAFFS2, cramfs, EROFS, ReiserFS
- **Archives and images:** ZIP, tar, cpio, MS-CAB (stored/MSZIP/LZX), CFBF compound files / Windows Installer `.msi`, ISO 9660, Android sparse, Android boot
- **Kernels and wrappers:** U-Boot uImage, U-Boot FIT, Windows CE XIP ROM (nk.bin / .cos), standalone gzip / xz / zstd / lz4 streams, Ingenic jzlzma (hardware LZ77)
- **Firmware packages:** RAE Systems / Honeywell RFP (section table; LZARI-decompresses each section); Artosyn OTRA (AR8030 / VT4 / VR04; SHA-256-verified, LZO1X-decompresses each partition, or exposes the raw flash body on flat images)
Expand Down
2 changes: 1 addition & 1 deletion fuzz/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mapfile -t SRCS < <(find src -name '*.cpp' ! -name 'main.cpp' | sort)
# Xcode clang lacks the libFuzzer runtime; override with a clang that has it
# (e.g. CXX=/opt/homebrew/opt/llvm/bin/clang++ on macOS).
CXX="${CXX:-clang++}"
for target in fuzz_scan fuzz_esp32_part fuzz_esp32_nvs fuzz_lzx; do
for target in fuzz_scan fuzz_esp32_part fuzz_esp32_nvs fuzz_lzx fuzz_reiserfs; do
"$CXX" -std=c++20 -O1 -g -fsanitize=fuzzer,address -I src -I third_party \
-DFT_FUZZ_SIGDIR="\"$PWD/signatures\"" \
"${SRCS[@]}" "fuzz/${target}.cpp" -o "$target"
Expand Down
65 changes: 65 additions & 0 deletions fuzz/fuzz_reiserfs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// fuzz_reiserfs.cpp — libFuzzer entry point for the ReiserFS extractor.
// Drives the parse-only tree/leaf-item walk directly: the fuzzer bytes are the
// tree region, spliced after a fixed valid superblock so the walk is always
// reached, with the superblock tried at both the 3.6 (64 KiB) and 3.5 (8 KiB)
// placements. Also feeds the raw bytes to the full scan pipeline so the
// identify/validator path sees adversarial input (issue #63).
//
// Build via fuzz/build.sh. Run: ./fuzz_reiserfs -max_total_time=60
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <span>
#include <vector>

#include "extract/reiserfs.hpp"
#include "reader.hpp"
#include "scan.hpp"
#include "sigload.hpp"

#ifndef FT_FUZZ_SIGDIR
#define FT_FUZZ_SIGDIR "signatures"
#endif

namespace {
constexpr uint64_t BS = 4096;
constexpr uint64_t SB_BLK = 16; // 64 KiB / 4096

// A minimal valid superblock so locate_base/root_block_ok accept block SB_BLK+1
// as the tree root; the fuzzer owns everything from the root block onward.
void write_sb(std::vector<uint8_t>& img, uint32_t nblocks, uint32_t root_block,
const char* magic) {
const size_t o = SB_BLK * BS;
auto put32 = [&](size_t off, uint32_t v) { std::memcpy(img.data() + o + off, &v, 4); };
auto put16 = [&](size_t off, uint16_t v) { std::memcpy(img.data() + o + off, &v, 2); };
put32(0, nblocks); // s_block_count
put32(8, root_block); // s_root_block
put16(44, BS); // s_blocksize
std::memcpy(img.data() + o + 52, magic, std::strlen(magic)); // s_magic
put16(68, 3); // s_tree_height
}
} // namespace

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
static const ft::LoadResult sigs = ft::load_signatures(FT_FUZZ_SIGDIR);

// Build an image: [zeros .. SB block .. fuzzer bytes as the tree region].
// Cap so a pathological size field can't make us allocate unboundedly here.
const size_t tree_bytes = size > (8u << 20) ? (8u << 20) : size;
const uint32_t nblocks = static_cast<uint32_t>((SB_BLK + 1) + (tree_bytes + BS - 1) / BS + 1);
std::vector<uint8_t> img(static_cast<size_t>(nblocks) * BS, 0);
const uint32_t root_block = SB_BLK + 1;
std::memcpy(img.data() + static_cast<size_t>(root_block) * BS, data, tree_bytes);

for (const char* magic : {"ReIsEr2Fs", "ReIsErFs"}) {
write_sb(img, nblocks, root_block, magic);
ft::Reader reader(std::span<const uint8_t>(img.data(), img.size()));
ft::reiserfs_probe(reader, SB_BLK * BS);
}

// Via the pipeline: magic-driven identification on the raw bytes.
ft::Reader raw(std::span<const uint8_t>(data, size));
auto findings = ft::scan(raw, sigs.signatures);
(void)findings;
return 0;
}
4 changes: 2 additions & 2 deletions moria.1
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ embedded formats (filesystems, containers, bootloaders, executables,
compression, media) with byte offsets and confidence tiers. It is
identification-first; with
.B \-\-extract
it also unpacks SquashFS, ext2/3/4, F2FS, JFFS2, UBIFS, romfs, YAFFS2, cramfs, FAT, exFAT, NTFS, HFS+, XFS, btrfs, EROFS, and ISO9660 filesystems, ZIP/tar/cpio/MS-CAB archives, CFBF compound files (Windows Installer .msi), U-Boot uImage/FIT containers, Windows CE XIP ROM images and registry hives, RAE Systems/Honeywell RFP firmware packages (LZARI-decompressing their sections), and Ingenic jzlzma-compressed kernel/rootfs images (hardware LZ77)
it also unpacks SquashFS, ext2/3/4, F2FS, JFFS2, UBIFS, romfs, YAFFS2, cramfs, FAT, exFAT, NTFS, HFS+, XFS, btrfs, EROFS, ReiserFS, and ISO9660 filesystems, ZIP/tar/cpio/MS-CAB archives, CFBF compound files (Windows Installer .msi), U-Boot uImage/FIT containers, Windows CE XIP ROM images and registry hives, RAE Systems/Honeywell RFP firmware packages (LZARI-decompressing their sections), and Ingenic jzlzma-compressed kernel/rootfs images (hardware LZ77)
internally (no sudo). Every other format is still identified and located by offset, ready for another tool such as binwalk.
.PP
Output is human-readable by default. A single file shows a findings tree
Expand Down Expand Up @@ -55,7 +55,7 @@ List tar/cpio/zip/MS-CAB member names and sizes, or a Windows CE ROM's modules a
.SS Extract
.TP
.BR \-e ", " \-\-extract
Unpack identified SquashFS, ext2/3/4, F2FS, JFFS2, UBIFS (incl. UBI), romfs, YAFFS2, cramfs, FAT, exFAT, NTFS, EROFS, and ISO9660 filesystems, ZIP/tar/cpio/MS-CAB archives, CFBF compound files such as Windows Installer .msi packages, U-Boot uImage/FIT containers, Android boot/sparse images, Windows CE XIP ROM images, Windows CE registry hives, and RAE Systems/Honeywell RFP firmware packages into
Unpack identified SquashFS, ext2/3/4, F2FS, JFFS2, UBIFS (incl. UBI), romfs, YAFFS2, cramfs, FAT, exFAT, NTFS, EROFS, ReiserFS, and ISO9660 filesystems, ZIP/tar/cpio/MS-CAB archives, CFBF compound files such as Windows Installer .msi packages, U-Boot uImage/FIT containers, Android boot/sparse images, Windows CE XIP ROM images, Windows CE registry hives, and RAE Systems/Honeywell RFP firmware packages into
.IR file .extracted/
(one subdir per region, named
.IR 0x<offset>\-<type> ).
Expand Down
2 changes: 2 additions & 0 deletions src/extract/manifest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "extract/ext.hpp"
#include "extract/exfat.hpp"
#include "extract/hfsplus.hpp"
#include "extract/reiserfs.hpp"
#include "extract/xfs.hpp"
#include "extract/btrfs.hpp"

Expand Down Expand Up @@ -56,6 +57,7 @@ Extractor find_extractor(const std::string& type) {
if (type == "tar") return extract_tar;
if (type == "romfs") return extract_romfs;
if (type == "cramfs") return extract_cramfs;
if (type == "reiserfs") return extract_reiserfs;
if (type == "erofs") return extract_erofs;
if (type == "f2fs") return extract_f2fs;
if (type == "android_sparse") return extract_android_sparse;
Expand Down
Loading
Loading