From 8efcaebcabfd37661f928fad379a7a2b3e96c52a Mon Sep 17 00:00:00 2001 From: DevStorm Date: Mon, 18 May 2026 18:37:18 +0800 Subject: [PATCH] fix(pi): refuse to auto-format USB drives with existing data The Pi external storage mount script silently ran wipefs and mkfs.ext4 when a single USB disk was not recognised as an Umbrel data drive. Require explicit opt-in before formatting and block foreign filesystems. Fixes getumbrel/umbrel#1956 Co-authored-by: Cursor --- .../umbrel-external-storage | 69 ++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/packages/os/overlay-pi/opt/umbrel-external-storage/umbrel-external-storage b/packages/os/overlay-pi/opt/umbrel-external-storage/umbrel-external-storage index 4fc49740e3..8db85d9335 100755 --- a/packages/os/overlay-pi/opt/umbrel-external-storage/umbrel-external-storage +++ b/packages/os/overlay-pi/opt/umbrel-external-storage/umbrel-external-storage @@ -108,6 +108,71 @@ is_partition_ext4 () { blkid -o value -s TYPE "${partition_path}" | grep --quiet '^ext4$' } +get_partition_fstype () { + partition_path="${1}" + sync + blkid -o value -s TYPE "${partition_path}" 2>/dev/null || true +} + +# Explicit opt-in is required before we wipe a user's USB drive. +# See https://github.com/getumbrel/umbrel/issues/1956 +UMBREL_ALLOW_FORMAT_PATHS=( + "/boot/firmware/umbrel-allow-external-format" + "/boot/umbrel-allow-external-format" +) + +is_external_format_explicitly_allowed () { + if [[ "${UMBREL_ALLOW_EXTERNAL_FORMAT:-}" == "1" ]]; then + return 0 + fi + for path in "${UMBREL_ALLOW_FORMAT_PATHS[@]}"; do + if [[ -f "${path}" ]]; then + return 0 + fi + done + return 1 +} + +device_has_filesystem_signatures () { + device_path="${1}" + signatures=$(wipefs --noheadings "${device_path}" 2>/dev/null || true) + [[ -n "${signatures}" ]] +} + +refuse_automatic_format () { + reason="${1}" + echo "ERROR: Refusing to automatically format external storage: ${reason}" + echo "Umbrel will continue running from the SD card." + echo "To intentionally use this drive as Umbrel data storage (this erases all data), create:" + echo " /boot/firmware/umbrel-allow-external-format" + echo "on the SD card boot partition, then reboot." + exit 1 +} + +assert_safe_to_format () { + block_device="${1}" + partition_path="${2}" + device_path="/dev/${block_device}" + + if is_external_format_explicitly_allowed; then + echo "Explicit consent to format external storage detected, continuing..." + return 0 + fi + + if device_has_filesystem_signatures "${device_path}"; then + refuse_automatic_format "existing filesystem signatures detected on ${device_path}" + fi + + fstype=$(get_partition_fstype "${partition_path}") + if [[ -n "${fstype}" && "${fstype}" != "ext4" ]]; then + refuse_automatic_format "partition ${partition_path} uses filesystem type '${fstype}'" + fi + + if [[ "${fstype}" == "ext4" ]]; then + refuse_automatic_format "ext4 partition exists but is not a recognised Umbrel data drive" + fi +} + # Wipes a block device and reformats it with a single EXT4 partition format_block_device () { device="${1}" @@ -139,6 +204,8 @@ setup_new_device () { block_device="${1}" partition_path="${2}" + assert_safe_to_format "${block_device}" "${partition_path}" + echo "Formatting device..." format_block_device $block_device @@ -164,7 +231,7 @@ copy_docker_to_external_storage () { main () { echo "Running external storage mount script..." check_root - check_dependencies sed wipefs parted mount sync umount + check_dependencies sed wipefs parted mount sync umount blkid if [[ "$(running_off_sdcard)" == "false" ]] then