first commit
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
*.sh text eol=lf
|
||||||
|
*.hook.chroot text eol=lf
|
||||||
|
Dockerfile text eol=lf
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
FROM debian:trixie
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
|
live-build ca-certificates debootstrap xorriso squashfs-tools dosfstools \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /work
|
||||||
|
ENTRYPOINT ["/bin/sh", "-c", "tr -d '\\r' < /work/build.sh | EP_ERASER_ROOT=/work /bin/sh"]
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# EP Eraser
|
||||||
|
|
||||||
|
EP Eraser is a small Debian Live image for securely retiring SATA/NVMe SSDs and rotational HDDs. It boots into a text console inspired by DBAN, but uses device-specific erase methods instead of overwriting every disk indiscriminately.
|
||||||
|
|
||||||
|
## Safety model
|
||||||
|
|
||||||
|
- The tool requires an exact device name and a typed `ERASE` confirmation.
|
||||||
|
- It refuses mounted devices, the live boot device, read-only devices, and devices with mounted descendants.
|
||||||
|
- SSDs use `blkdiscard --secure` where supported, with NVMe sanitize as an option.
|
||||||
|
- HDDs use a three-pass `shred` overwrite followed by a device-state/status check.
|
||||||
|
- Every operation is logged to `/var/log/ep-eraser.log` and a summary is written to the target's parent device metadata only when supported.
|
||||||
|
|
||||||
|
No software can guarantee recovery resistance for every controller, reserved area, remapped sector, or damaged drive. For high-assurance disposal, combine this image with the drive vendor's sanitize command or physical destruction according to your organization's policy.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Build from Debian/Ubuntu, WSL, or Docker. The builder must run as root because `live-build` creates a chroot.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo ./build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The output is `build/ep-eraser-amd64.hybrid.iso`. Write it to a USB drive with a tool such as Rufus or `dd`. Verify the output checksum before deployment.
|
||||||
|
|
||||||
|
To build without installing packages on the host, use Docker from Linux or WSL:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker build -t ep-eraser-builder .
|
||||||
|
docker run --rm -v "$PWD:/work" ep-eraser-builder
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use
|
||||||
|
|
||||||
|
Boot the target machine from the image, inspect the disk list, and choose the exact device path. The program detects rotational media and presents the appropriate operation. Reboot after completion; do not remove the USB device until the result is shown.
|
||||||
|
|
||||||
|
This project intentionally does not include an automatic wipe-all mode.
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
|
echo "Run this builder as root (or use the Dockerfile)." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ROOT=${EP_ERASER_ROOT:-$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)}
|
||||||
|
cd "$ROOT"
|
||||||
|
rm -rf build
|
||||||
|
mkdir -p build
|
||||||
|
|
||||||
|
lb config \
|
||||||
|
--distribution trixie \
|
||||||
|
--architectures amd64 \
|
||||||
|
--binary-images iso-hybrid \
|
||||||
|
--debian-installer false \
|
||||||
|
--archive-areas "main contrib non-free-firmware" \
|
||||||
|
--apt-recommends false \
|
||||||
|
--bootappend-live "boot=live components username=eraser hostname=ep-eraser" \
|
||||||
|
--iso-application "EP Eraser" \
|
||||||
|
--iso-publisher "EP Eraser Project" \
|
||||||
|
--iso-volume "EP_ERASER" \
|
||||||
|
--image-name "ep-eraser" \
|
||||||
|
--source false
|
||||||
|
|
||||||
|
lb build
|
||||||
|
mv ./*.hybrid.iso build/ep-eraser-amd64.hybrid.iso
|
||||||
|
sha256sum build/ep-eraser-amd64.hybrid.iso > build/ep-eraser-amd64.hybrid.iso.sha256
|
||||||
|
echo "Built build/ep-eraser-amd64.hybrid.iso"
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
chmod 0755 /usr/local/sbin/ep-eraser
|
||||||
|
systemctl enable ep-eraser.service
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=EP Eraser console
|
||||||
|
After=local-fs.target systemd-udev-settle.service
|
||||||
|
Wants=systemd-udev-settle.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/local/sbin/ep-eraser
|
||||||
|
StandardInput=tty
|
||||||
|
StandardOutput=tty
|
||||||
|
StandardError=tty
|
||||||
|
TTYPath=/dev/tty1
|
||||||
|
TTYReset=yes
|
||||||
|
TTYVHangup=yes
|
||||||
|
TTYVTDisallocate=yes
|
||||||
|
Restart=no
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
LOG=/var/log/ep-eraser.log
|
||||||
|
exec > >(tee -a "$LOG") 2>&1
|
||||||
|
|
||||||
|
die() { printf '\nERROR: %s\n' "$*" >&2; read -r -p 'Press Enter to return to the menu...' _; }
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
findmnt -rn -S "$1" >/dev/null 2>&1 && return 0
|
||||||
|
lsblk -nrpo NAME,MOUNTPOINTS "$1" | awk 'NF > 1 && $2 != "" { found=1 } END { exit !found }'
|
||||||
|
}
|
||||||
|
|
||||||
|
is_live_device() {
|
||||||
|
local live parent
|
||||||
|
live=$(findmnt -rn -o SOURCE /run/live/medium 2>/dev/null || true)
|
||||||
|
[ -n "$live" ] || return 1
|
||||||
|
parent=$(lsblk -dnro PKNAME "$live" 2>/dev/null || true)
|
||||||
|
[ -n "$parent" ] && [ "$1" = "/dev/$parent" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
disk_info() {
|
||||||
|
lsblk -dnpo NAME,TYPE,SIZE,MODEL,SERIAL,TRAN | awk '$2 == "disk" { print }'
|
||||||
|
}
|
||||||
|
|
||||||
|
choose_disk() {
|
||||||
|
mapfile -t disks < <(lsblk -dnpo NAME,TYPE | awk '$2 == "disk" { print $1 }')
|
||||||
|
[ "${#disks[@]}" -gt 0 ] || { die 'No whole disks were detected.'; return 1; }
|
||||||
|
printf '\nDetected disks:\n\n'
|
||||||
|
printf '%-4s %-18s %-10s %-24s %-16s %s\n' '#' DEVICE SIZE MODEL SERIAL TRAN
|
||||||
|
disk_info | nl -w2 -s' '
|
||||||
|
printf '\nEnter the number shown above, or q to quit: '
|
||||||
|
read -r choice
|
||||||
|
[ "$choice" = q ] && exit 0
|
||||||
|
[[ "$choice" =~ ^[0-9]+$ ]] || { die 'Invalid selection.'; return 1; }
|
||||||
|
target=${disks[$((choice - 1))]:-}
|
||||||
|
[ -n "$target" ] || { die 'Invalid selection.'; return 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_target() {
|
||||||
|
[ -b "$target" ] || { die 'Selected path is not a block device.'; return 1; }
|
||||||
|
[ "$(lsblk -dnro TYPE "$target")" = disk ] || { die 'Only whole disks may be erased.'; return 1; }
|
||||||
|
[ "$(lsblk -dnro RO "$target")" = 0 ] || { die 'The disk is read-only.'; return 1; }
|
||||||
|
mounted "$target" && { die 'The disk or one of its partitions is mounted.'; return 1; }
|
||||||
|
is_live_device "$target" && { die 'The live boot device cannot be erased.'; return 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
confirm() {
|
||||||
|
local info
|
||||||
|
info=$(lsblk -dnpo NAME,SIZE,MODEL,SERIAL "$target")
|
||||||
|
printf '\nTARGET: %s\n%s\n\nThis permanently destroys all data. Type ERASE to continue: ' "$target" "$info"
|
||||||
|
read -r answer
|
||||||
|
[ "$answer" = ERASE ] || { printf 'Cancelled.\n'; return 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
erase_ssd() {
|
||||||
|
printf '\nSSD/NVMe erase options:\n1) Secure discard (blkdiscard --secure)\n2) NVMe sanitize (NVMe only)\n3) Cancel\nChoose: '
|
||||||
|
read -r method
|
||||||
|
case "$method" in
|
||||||
|
1)
|
||||||
|
blkdiscard --secure --force "$target" || { die 'Secure discard failed; no data was overwritten.'; return 1; }
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
[[ "$target" == /dev/nvme*n* ]] || { die 'NVMe sanitize requires an NVMe namespace.'; return 1; }
|
||||||
|
nvme sanitize "$target" -a 2 || { die 'NVMe sanitize failed.'; return 1; }
|
||||||
|
nvme sanitize-log "$target" -H || true
|
||||||
|
;;
|
||||||
|
*) printf 'Cancelled.\n'; return 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
erase_hdd() {
|
||||||
|
printf '\nHDD erase uses three random overwrite passes plus a zero pass. Continue? [yes/no]: '
|
||||||
|
read -r answer
|
||||||
|
[ "$answer" = yes ] || { printf 'Cancelled.\n'; return 1; }
|
||||||
|
shred --verbose --iterations=3 --zero --force "$target"
|
||||||
|
}
|
||||||
|
|
||||||
|
verify() {
|
||||||
|
printf '\nFinal device state:\n'
|
||||||
|
lsblk -dnpo NAME,TYPE,SIZE,MODEL,SERIAL "$target"
|
||||||
|
printf 'Erase command completed. Verification is limited to command/device status.\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
[ "$(id -u)" -eq 0 ] || { echo 'This tool must run as root.' >&2; exit 1; }
|
||||||
|
printf '\nEP ERASER - destructive disk sanitization\n==========================================\n'
|
||||||
|
while true; do
|
||||||
|
choose_disk || continue
|
||||||
|
validate_target || continue
|
||||||
|
rotational=$(lsblk -dnro ROTA "$target")
|
||||||
|
if [ "$rotational" = 1 ]; then
|
||||||
|
operation=HDD
|
||||||
|
else
|
||||||
|
operation=SSD/NVMe
|
||||||
|
fi
|
||||||
|
printf '\nDetected media type: %s\n' "$operation"
|
||||||
|
confirm || continue
|
||||||
|
if [ "$operation" = HDD ]; then erase_hdd; else erase_ssd; fi
|
||||||
|
verify
|
||||||
|
printf '\nPress Enter to return to the disk menu, or type q to quit: '
|
||||||
|
read -r answer
|
||||||
|
[ "$answer" = q ] && exit 0
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
bash
|
||||||
|
coreutils
|
||||||
|
hdparm
|
||||||
|
nvme-cli
|
||||||
|
parted
|
||||||
|
smartmontools
|
||||||
|
util-linux
|
||||||
|
whiptail
|
||||||
Reference in New Issue
Block a user