Skip to content

ext4 image extraction loses permissions: all dirs/files become 0700 (breaks uhttpd, dropbear, …) #52

@lacraig2

Description

@lacraig2

Summary

When extracting an ext4 disk image (handled by the unblob backend), fw2tar loses the source filesystem's permission bits — every directory and file in the produced .rootfs.tar.gz comes out as 0700 (owner-only), except the top-level ./ which is forced to 0755. The real modes in the source ext4 inodes (e.g. 0755 for /bin, /usr, /etc, /www) are not preserved.

This silently breaks rehosting: any service that enforces permission checks fails. Concretely, it made an OpenWrt x86-64 rehosting's uhttpd return 403 Forbidden to every request because its /www docroot was 0700 instead of 0755 (uhttpd refuses to serve a docroot that isn't world-traversable, even as root). It would equally affect dropbear host-key perm checks, anything that drops privileges, etc.

Reproduce

wget https://downloads.openwrt.org/releases/23.05.5/targets/x86/64/openwrt-23.05.5-x86-64-generic-ext4-combined.img.gz
gunzip openwrt-23.05.5-x86-64-generic-ext4-combined.img.gz
fakeroot fw2tar openwrt-23.05.5-x86-64-generic-ext4-combined.img   # -> unblob backend

(binwalk finds no filesystem in this image; fw2tar selects the unblob extractor.)

Evidence

Source ext4 rootfs (read directly from the image's rootfs partition with debugfs, no mount):

/      Mode: 0755
/bin   Mode: 0755
/usr   Mode: 0755
/etc   Mode: 0755
/sbin  Mode: 0755
/www   Mode: 0755

fw2tar output (*.rootfs.tar.gz): everything collapsed to 0700.

$ find . -type d -printf '%m\n' | sort | uniq -c
    111 700
      1 755        # only ./ (the forced top-level)

$ stat -c '%a %n' bin usr etc sbin www www/index.html bin/busybox sbin/init
700 bin
700 usr
700 etc
700 sbin
700 www
700 www/index.html
700 bin/busybox
700 sbin/init

So the source is 0755 but the extracted tar is 0700 for all 111 non-root directories (and files).

Likely cause

src/archive.rs:104-110 copies each entry's mode verbatim from the on-disk extracted tree and only special-cases the root:

header.set_metadata_in_mode(&metadata, tar::HeaderMode::Deterministic);
header.set_mode(metadata.permissions().mode());

if entry_path == "./" {
    header.set_mode(0o755);
}

The ./-only 0o755 override is exactly what produces the observed "root is 0755, everything else is 0700" pattern — the extracted tree already has 0700 everywhere, and fw2tar reflects it. The mode loss happens upstream in the extraction step (the unblob ext4 extractor isn't preserving the source inode modes; they end up 0700 on disk before archiving).

Suggested directions

  • Preserve real modes through the unblob ext4 extraction (so archive.rs reflects correct perms), or
  • Have fw2tar re-derive modes from the source filesystem rather than trusting the extracted tree's on-disk perms when the extractor is known to drop them.

A blanket "everything 0700" is never a faithful rootfs (a real Linux rootfs needs 0755 on /bin, /usr, etc. or nothing works for non-root), so this is safe to treat as an extraction-fidelity bug.

Environment

  • fw2tar image rehosting/fw2tar:latest digest sha256:7f1bb5d5f798597b98d936146716c2aec5adee098503a2b6c8854b0d05a40302 (built 2026-05-15, repo HEAD 2723ef0).
  • Also relevant to the pinned f44361d4c64e9e6f54d940cb2637bf9283961a29 used by the rehostings corpus.
  • Extractor selected: unblob (binwalk found no filesystem in this ext4 image).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions