From a39b03ac2e18a83f73e4e320481323fc8ef8a795 Mon Sep 17 00:00:00 2001 From: Ashlen Date: Wed, 15 Jul 2026 10:58:42 -0600 Subject: [PATCH 1/2] fix(virusforget): skip restore when backup is absent An extraneous file (present in the home directory but absent from the committed backup) is deleted and then unconditionally passed to restore_file, which runs `cp` from a backup path that does not exist. Under `set -e` this aborts the entire `--clean` run on the first such file, leaving the system partially cleaned -- the exact malware-persistence scenario the tool exists to handle. Return early from restore_file when no backup exists. Deleting the extraneous file is the correct action and is already done by the caller (which keeps a forensic copy under the dangerous/ folder). The guard is transparent to the missing-file and modified-file callers, which always have a backup present. --- usr/libexec/security-misc/virusforget#security-misc-shared | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/usr/libexec/security-misc/virusforget#security-misc-shared b/usr/libexec/security-misc/virusforget#security-misc-shared index e1a277f9..446dde89 100755 --- a/usr/libexec/security-misc/virusforget#security-misc-shared +++ b/usr/libexec/security-misc/virusforget#security-misc-shared @@ -297,6 +297,13 @@ unexpected_file() { } restore_file() { + ## An extraneous file has no baseline backup to restore from; the caller + ## has already removed it, which is the correct action. Return early so the + ## 'cp' below does not fail on the missing backup and abort the entire + ## '--clean' run (via 'set -e') on the first extraneous file encountered. + if [ ! -e "$full_path_backup" ]; then + return 0 + fi if [ "$test_mode" = "true" ]; then echo "Simulate restoring file... $full_path_original" >&2 echo cp --no-dereference --archive "$full_path_backup" "$full_path_original" From 6dc96859dd7f350673cc917a8c41da8144357e62 Mon Sep 17 00:00:00 2001 From: Ashlen Date: Wed, 15 Jul 2026 10:59:09 -0600 Subject: [PATCH 2/2] fix(virusforget): exit when --user does not exist The nonexistent-user branch printed a warning but, unlike every sibling validation branch, neither exited nor wrote to stderr, so a mistyped --user proceeded to operate on a bogus /home/ path. Send the error to stderr and exit 1. --- usr/libexec/security-misc/virusforget#security-misc-shared | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/usr/libexec/security-misc/virusforget#security-misc-shared b/usr/libexec/security-misc/virusforget#security-misc-shared index 446dde89..dbab06dd 100755 --- a/usr/libexec/security-misc/virusforget#security-misc-shared +++ b/usr/libexec/security-misc/virusforget#security-misc-shared @@ -86,7 +86,8 @@ parse_cmd_options() { exit 1 fi if ! id -u "$user_name" >/dev/null 2>&1; then - echo "ERROR: User '$user_name' does not appear to exist!" + echo "ERROR: User '$user_name' does not appear to exist!" >&2 + exit 1 fi }