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