mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
This pull request enhances the safety of the `linux_wipe.sh` script by ensuring that destructive file operations do not affect network-mounted filesystems. The changes introduce checks to detect network filesystems, prevent accidental deletion of remote data, and improve the reliability of wipe operations by avoiding crossing filesystem boundaries. **Network filesystem safety improvements:** * Added a `NETWORK_FS_TYPES` variable and functions to detect and unmount network filesystems, preventing the script from deleting data on NFS, CIFS, SMB, SSHFS, and similar mounts. (`ee/server/service/embedded_scripts/linux_wipe.sh`) [[1]](diffhunk://#diff-7ac85220cbd45e63481837a405dacf198822a4fbf885b88f89b9bc870c947fccR3-R4) [[2]](diffhunk://#diff-7ac85220cbd45e63481837a405dacf198822a4fbf885b88f89b9bc870c947fccR17-R84) * Introduced an `unmount_network_filesystems` function called before wiping operations to unmount all detected network filesystems. (`ee/server/service/embedded_scripts/linux_wipe.sh`) * Added an `is_network_mount` function to skip wiping any path residing on a network filesystem. (`ee/server/service/embedded_scripts/linux_wipe.sh`) **Safe file deletion enhancements:** * Implemented a `safe_rm` function that ensures file deletions do not cross filesystem boundaries, using `rm --one-file-system` or `find -xdev` as a fallback. All destructive operations now use this wrapper. (`ee/server/service/embedded_scripts/linux_wipe.sh`) * Updated `wipe_non_essential_data` and `wipe_system_files` to use `safe_rm` and to skip paths on network filesystems. (`ee/server/service/embedded_scripts/linux_wipe.sh`) These changes significantly reduce the risk of deleting data on remote or shared filesystems during a wipe operation. <!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves # # Checklist for submitter If some of the following don't apply, delete the relevant line. - [ ] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [ ] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects - [ ] If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes ## Testing - [ ] Added/updated automated tests - [ ] Where appropriate, [automated tests simulate multiple hosts and test for host isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing) (updates to one hosts's records do not affect another) - [ ] QA'd all new/changed functionality manually For unreleased bug fixes in a release candidate, one of: - [ ] Confirmed that the fix is not expected to adversely impact load test results - [ ] Alerted the release DRI if additional load testing is needed ## Database migrations - [ ] Checked schema for all modified table for columns that will auto-update timestamps during migration. - [ ] Confirmed that updating the timestamps is acceptable, and will not cause unwanted side effects. - [ ] Ensured the correct collation is explicitly set for character columns (`COLLATE utf8mb4_unicode_ci`). ## New Fleet configuration settings - [ ] Setting(s) is/are explicitly excluded from GitOps If you didn't check the box above, follow this checklist for GitOps-enabled settings: - [ ] Verified that the setting is exported via `fleetctl generate-gitops` - [ ] Verified the setting is documented in a separate PR to [the GitOps documentation](https://github.com/fleetdm/fleet/blob/main/docs/Configuration/yaml-files.md#L485) - [ ] Verified that the setting is cleared on the server if it is not supplied in a YAML file (or that it is documented as being optional) - [ ] Verified that any relevant UI is disabled when GitOps mode is enabled ## fleetd/orbit/Fleet Desktop - [ ] Verified compatibility with the latest released version of Fleet (see [Must rule](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/workflows/fleetd-development-and-release-strategy.md)) - [ ] If the change applies to only one platform, confirmed that `runtime.GOOS` is used as needed to isolate changes - [ ] Verified that fleetd runs on macOS, Linux and Windows - [ ] Verified auto-update works from the released version of component to the new version (see [tools/tuf/test](../tools/tuf/test/README.md)) --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
166 lines
5.4 KiB
Bash
166 lines
5.4 KiB
Bash
#!/bin/sh
|
|
|
|
NETWORK_FS_TYPES="nfs|nfs4|cifs|smb|smbfs|fuse\.sshfs|afs|ncpfs|9p"
|
|
|
|
# Function to log out all users and lock their passwords except root
|
|
logout_users() {
|
|
for user in $(who | awk '{print $1}' | sort | uniq)
|
|
do
|
|
if [ "$user" != "root" ]; then
|
|
echo "Logging out $user"
|
|
pkill -KILL -u "$user"
|
|
passwd -l "$user"
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Unmount all network filesystems to prevent remote data deletion.
|
|
unmount_network_filesystems() {
|
|
if [ ! -f /proc/mounts ]; then
|
|
echo "Error: /proc/mounts not found; aborting wipe to avoid unsafe network data deletion" >&2
|
|
exit 1
|
|
fi
|
|
|
|
awk '$3 ~ /^('"$NETWORK_FS_TYPES"')$/ {print $2}' /proc/mounts \
|
|
| awk '{print length, $0}' \
|
|
| sort -nr \
|
|
| cut -d" " -f2- \
|
|
| while read -r mnt_esc; do
|
|
# Unescape mountpoint in case it contains octal escapes like \040 for space.
|
|
mnt=$(printf '%b' "$mnt_esc")
|
|
# Never unmount critical mountpoints that may contain required userland.
|
|
case "$mnt" in
|
|
/|/usr|/bin|/sbin|/lib|/lib64|/usr/bin|/usr/sbin|/usr/lib|/usr/lib64)
|
|
echo "Skipping critical network-mounted filesystem: $mnt"
|
|
continue
|
|
;;
|
|
esac
|
|
echo "Unmounting network filesystem: $mnt"
|
|
umount -f -l "$mnt" 2>/dev/null || echo "Warning: failed to unmount $mnt"
|
|
done
|
|
}
|
|
|
|
# Returns 0 (true) if the given path resides on a network filesystem.
|
|
is_network_mount() {
|
|
if [ ! -f /proc/mounts ]; then
|
|
echo "Error: /proc/mounts not found; aborting wipe to avoid unsafe network data deletion" >&2
|
|
exit 1
|
|
fi
|
|
_target="$1"
|
|
# Resolve the target to a canonical path if possible, so that symlinks
|
|
# (e.g. /home -> /mnt/nfs/home) do not hide network mounts.
|
|
if command -v readlink >/dev/null 2>&1; then
|
|
_resolved=$(readlink -f -- "$_target" 2>/dev/null || printf '%s\n' "$_target")
|
|
_target="$_resolved"
|
|
fi
|
|
# Walk up to find the mount point that contains this path.
|
|
_match=$(awk '$3 ~ /^('"$NETWORK_FS_TYPES"')$/ {print $2}' /proc/mounts | while read -r mnt_esc; do
|
|
mnt=$(printf '%b' "$mnt_esc")
|
|
case "$mnt" in
|
|
/)
|
|
case "$_target" in
|
|
/*) echo "$mnt"; break ;;
|
|
esac
|
|
;;
|
|
*)
|
|
# Normalize mountpoint by removing any trailing slash (except for root,
|
|
# which is already handled above) and perform literal prefix checks
|
|
# so that glob metacharacters in $mnt do not affect matching.
|
|
mnt_no_slash=${mnt%/}
|
|
if [ "$_target" = "$mnt_no_slash" ] || [ "${_target#"$mnt_no_slash"/}" != "$_target" ]; then
|
|
echo "$mnt_no_slash"
|
|
break
|
|
fi
|
|
;;
|
|
esac
|
|
done)
|
|
[ -n "$_match" ]
|
|
}
|
|
|
|
# rm -rf wrapper that prevents crossing filesystem boundaries.
|
|
# Uses GNU --one-file-system when available, falls back to find -xdev.
|
|
safe_rm() {
|
|
_path="$1"
|
|
if rm --one-file-system -rf "$_path" 2>/dev/null; then
|
|
return
|
|
fi
|
|
# Fallback for non-GNU rm (e.g. BusyBox): use find -xdev to stay on the
|
|
# same filesystem. Avoid rm -rf so we never recurse into nested mounts
|
|
# whose mountpoint entries live on the local device.
|
|
# If the path is not a directory or is a symlink, just unlink it directly.
|
|
if [ ! -d "$_path" ] || [ -L "$_path" ]; then
|
|
rm -f "$_path" 2>/dev/null
|
|
return
|
|
fi
|
|
(
|
|
cd "$_path" 2>/dev/null || exit 0
|
|
find . -xdev -depth ! -name . ! -type d -exec rm -f {} \; 2>/dev/null
|
|
find . -xdev -depth ! -name . -type d -exec rmdir {} \; 2>/dev/null
|
|
)
|
|
rmdir "$_path" 2>/dev/null
|
|
}
|
|
|
|
# Function to wipe non-essential data
|
|
wipe_non_essential_data() {
|
|
non_essential_paths="/home/* /tmp /var/tmp /var/log /home/*/.cache /var/cache /home/*/.local/share/Trash"
|
|
|
|
for path in $non_essential_paths
|
|
do
|
|
if [ -e "$path" ]; then
|
|
if is_network_mount "$path"; then
|
|
echo "Skipping $path (network filesystem)"
|
|
continue
|
|
fi
|
|
echo "Wiping $path"
|
|
safe_rm "$path"
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Function to wipe system files - Warning: This will render the system inoperable
|
|
wipe_system_files() {
|
|
essential_system_paths="/bin /sbin /usr /lib /opt /etc /var /srv"
|
|
|
|
for path in $essential_system_paths
|
|
do
|
|
if is_network_mount "$path"; then
|
|
echo "Skipping $path (network filesystem)"
|
|
continue
|
|
fi
|
|
echo "Wiping $path"
|
|
safe_rm "$path"
|
|
done
|
|
}
|
|
|
|
prepare_system_reset() {
|
|
cp /usr/bin/sync /sync_bin
|
|
# https://docs.kernel.org/admin-guide/sysrq.html
|
|
echo "1" > /proc/sys/kernel/sysrq
|
|
}
|
|
|
|
system_reset() {
|
|
# Give the system time to sync
|
|
/sync_bin
|
|
# Halt the system immediately
|
|
echo "o" > /proc/sysrq-trigger
|
|
}
|
|
|
|
wipe_all_files() {
|
|
sleep 10 # Give fleetd enough time to register the script as completed
|
|
prepare_system_reset
|
|
unmount_network_filesystems
|
|
wipe_non_essential_data
|
|
wipe_system_files
|
|
system_reset
|
|
}
|
|
|
|
if [ "$1" = "wipe" ]; then
|
|
# We are in the detached child process
|
|
wipe_all_files
|
|
else
|
|
# We are in the parent shell, logout users and begin the detached
|
|
# wipe child process
|
|
logout_users
|
|
echo "Wiping, system will be unreachable"
|
|
(/usr/bin/nohup sh $0 wipe >/dev/null 2>/dev/null </dev/null) &
|
|
fi
|