This post will describe how to use BusKill as a dead man switch to trigger your laptop to self-destruct if it’s physically separated from you. This guide is specific to QubesOS users.
What if someone literally steals your laptop while you’re working with classified information inside a Whonix DispVM? They’d also be able to recover data from previous DispVMs–as Disposable VM’s rootfs virtual files are not securely shredded after your DispVM is destroyed.
This is part one of a two-part series. For part two, see Disarm BusKill in QubesOS (2/2)
- A Laptop Kill Cord for QubesOS (1/2)
- Disarm BusKill in QubesOS (2/2)
Are you a security researcher, journalist, or intelligence operative that works in QubesOS–exploiting Qubes’ brilliant security-through-compartimentalization to keep your data safe? Do you make use of Whonix Disposable VMs for your work? Great! This post is for you.
I’m sure your QubesOS laptop has Full Disk Encryption and you’re using a strong passphrase. But what if someone literally steals your laptop while you’re working with classified information inside a Whonix DispVM? Not only will they get access to all of your AppVM’s private data and the currently-running Whonix DispVM’s data, but there’s a high chance they’d be able to recover data from previous DispVMs–as Disposable VM’s rootfs virtual files (volatile.img) are not securely shredded after your DispVM is destroyed by Qubes!
Let’s say you’re a journalist, activist, whistleblower, or a human rights worker in an oppressive regime. Or an intelligence operative behind enemy lines doing research or preparing a top-secret document behind a locked door. What do you do to protect your data, sources, or assets when the secret police suddenly batter down your door? How quickly can you actually act to shutdown your laptop and shred your RAM and/or FDE encryption keys?
BusKill utilizes a magnetic trip-wire that tethers your body to your laptop. If you suddenly jump to your feet or fall off your chair (in response to the battering ram crashing through your door) or your laptop is ripped off your table by a group of armed thugs, the data bus’ magnetic connection will be severed. This event causes a configurable trigger to execute.
The BusKill trigger
can be anything from:
- locking your screen or
- shutting down the computer or
- initiating a self-destruct sequence
This post will describe how to setup such a system in QubesOS with BusKill
Disclaimer
This guide contains experimental files, commands, and software. The information contained in this article may or may not lead to corruption or total permanent deletion of some or all of your data. We’ve done our best to carefully guide the user so they know the risks of each BusKill trigger, but we cannot be responsible for any data loss that has occurred as a result of following this guide.
The contents of this guide is provided openly and is licensed under the CC-BY-SA license. The software included in this guide is licensed under the GNU GPLv3 license. All content here is consistent with the limitations of liabilities outlined in its respective licenses.
We highly recommend that any experiments with the scripts included in this article are used exclusively on a disposable machine containing no valuable data.
If data loss is a concern for you, then leave now and do not proceed with following this guide. You have been warned.
Release Note
Also be aware that, due to the risks outlined above, BusKill will not be released with this “self-destruct” trigger.
If you purchase a BusKill cable, it will only ship with non-destructive triggers that lock the screen or shutdown the computer. Advanced users can follow guides to add additional destructive triggers, such as the one described in this post, but they should do so at their own risk–taking carefully into consideration all of the warnings outlined above and throughout this article.
Again, if you buy a BusKill cable, the worst that can happen is your computer will abruptly shutdown.
Assumptions
This guide necessarily makes several assumptions outlined below.
sys-usb
In this guide, we assume that your QubesOS install has a USB-Qube named ‘sys-usb
‘ for handling USB events on behalf of dom0
.
If you decided to combine your USB and networking Qubes at install time, then replace all references in this guide for ‘sys-usb
‘ to ‘sys-net
‘.
If you decided to run your ‘sys-usb
‘ VM as a DispoableVM at install time, then replace all references in this guide for ‘sys-usb
‘ its Disposable TemplateVM (eg ‘fedora-36-dvm
‘).
..And if you chose not to isolate your USB devices, then may god help you.
Udev Device Matching
BusKill in Linux uses udev to detect when the USB’s cable is severed. The exact udev rule that you use in the files below will depend on the drive you choose to use in your BusKill cable.
In this guide, we identify our BusKill-specific drive with the ‘ENV{ID_MODEL}=="Micromax_A74"
‘ udev property. You should replace this property with one that matches your BusKill-specific drive.
To determine how to query your USB drive for device-specific identifiers, see Introducing BusKill: A Kill Cord for your Laptop. Note that the `udevadm monitor --environment --udev
` command should be run in the ‘sys-usb
‘ Qube.
ⓘ Note: If you’d prefer to buy a BusKill cable than make your own, you can buy one fully assembled here.
QubesOS Version
This guide was written for QubesOS v4.0.
[user@dom0 ~]$ cat /etc/redhat-release Qubes release 4.0 (R4.0) [user@dom0 ~]$
BusKill Files
This section will describe what files should be created and where.
sys-usb
To protect dom0
from USB peripherals (ie: vulnerable drivers parsing a malicious partition table), our udev rule to detect when the BusKill cable’s connection is severed will live on ‘sys-usb
‘ in the ‘/etc/udev/rules.d/
‘ directory. But to set this up the Qubes way, we’ll put them in ‘/rw/config/
‘ and use ‘rc.local
‘ to put them in-place when ‘sys-usb
‘ boots.
First, we create our udev rule file ‘sys-usb:/rw/config/buskill.rules
‘.
Execute the following on your ‘sys-usb
‘ Qube:
cat << EOF | sudo tee /rw/config/buskill.rules ################################################################################ # File: sys-usb:/etc/udev/rules.d/buskill.rules -> /rw/config/buskill.rules # Purpose: Add buskill rules. For more info, see: https://buskill.in/qubes-os/ # Authors: Michael Altfield <michael@buskill.in> # Created: 2020-01-02 # License: GNU GPLv3 ################################################################################ ACTION=="remove", SUBSYSTEM=="usb", ENV{ID_MODEL}=="Micromax_A74", RUN+="/usr/bin/qrexec-client-vm dom0 buskill.lock" #ACTION=="remove", SUBSYSTEM=="usb", ENV{ID_MODEL}=="Micromax_A74", RUN+="/usr/bin/qrexec-client-vm dom0 buskill.softShutdown" #ACTION=="remove", SUBSYSTEM=="usb", ENV{ID_MODEL}=="Micromax_A74", RUN+="/usr/bin/qrexec-client-vm dom0 buskill.hardReboot" #ACTION=="remove", SUBSYSTEM=="usb", ENV{ID_MODEL}=="Micromax_A74", RUN+="/usr/bin/qrexec-client-vm dom0 buskill.selfDestruct+--yes" EOF sudo ln -s /rw/config/buskill.rules /etc/udev/rules.d/ sudo udevadm control --reload
The above file defines a number of udev rules that execute distinct triggers when the BusKill device is remove
d from the system. All are commented-out except the top one, which tells ‘sys-usb
‘ to execute the command `/usr/bin/qrexec-client-vm dom0 buskill.lock
`.
The `qrexec-client-vm
` command allows one VM to execute a command on another VM (assuming dom0 permits it–which we’ll setup below). In this case, we’re executing the command on ‘dom0
‘ herself. And the command we’re executing is ‘buskill.lock
‘
Now let’s add the following lines to ‘sys-usb:/rw/config/rc.local
‘.
Execute the following on your ‘sys-usb
‘ Qube:
grep 'buskill' /rw/config/rc.local || cat << EOF | sudo tee --append /rw/config/rc.local # Add buskill rules. For more info, see: https://buskill.in/qubes-os/ sudo ln -s /rw/config/buskill.rules /etc/udev/rules.d/ sudo udevadm control --reload EOF sync
dom0
All of our triggers (lock screen, shutdown, self-destruct, etc) can actually only be executed from dom0
. However, because QubesOS makes it intentionally difficult to put new files in dom0, we’ll be putting them in ‘/tmp/buskill/qubes-rpc
‘ in your AppVM, creating a tarball, copying the tarball to dom0, and then extracting it to ‘/etc/qubes-rpc
‘ inside dom0.
First, let’s create a staging dir where we’ll be adding files that will be later copied to dom0.
Execute the following in a reasonably trustworthy AppVM with internet access (eg ‘personal’):
mkdir -p /tmp/buskill/qubes-rpc/policy
Now let’s define our screen lock trigger. This one is the lowest paranoia level. If you accidentally trip BusKill when going to get a cup of coffee, the worst-case with this trigger is that you’ll have to unlock your screen again.
Execute the following in a reasonably trustworthy AppVM with internet access (eg ‘personal’):
cat << EOF | sudo tee /tmp/buskill/qubes-rpc/buskill.lock ################################################################################ # File: dom0:/etc/qubes-rpc/buskill.lock # Purpose: Locks the screen. For more info, see: https://buskill.in/qubes-os/ # Authors: Michael Altfield <michael@buskill.in> # Created: 2020-01-02 # License: GNU GPLv3 ################################################################################ DISPLAY=:0 xscreensaver-command -lock EOF sudo chmod 0755 /tmp/buskill/qubes-rpc/buskill.lock
Now let’s define a soft shutdown trigger. This one’s a bit more paranoid. You’ll probably loose any unsaved work and anything in a DispVM, but hopefully you won’t actually get data corruption.
Execute the following in a reasonably trustworthy AppVM with internet access (eg ‘personal’):
cat << EOF | sudo tee /tmp/buskill/qubes-rpc/buskill.softShutdown ################################################################################ # File: dom0:/etc/qubes-rpc/buskill.softShutdown # Purpose: Locks the screen. For more info, see: https://buskill.in/qubes-os/ # Authors: Michael Altfield <michael@buskill.in> # Created: 2020-01-02 # License: GNU GPLv3 ################################################################################ sudo shutdown -h now EOF sudo chmod 0755 /tmp/buskill/qubes-rpc/buskill.softShutdown
And now let’s define a hard reboot trigger. This effectively yanks the power immediately to reboot as fast as possible. Here you’re definitely risking data corruption.
Execute the following in a reasonably trustworthy AppVM with internet access (eg ‘personal’):
cat << EOF | sudo tee /tmp/buskill/qubes-rpc/buskill.hardReboot ################################################################################ # File: dom0:/etc/qubes-rpc/buskill.hardReboot # Purpose: Immediate reboot. For more info, see: https://buskill.in/qubes-os/ # Authors: Michael Altfield <michael@buskill.in> # Created: 2020-01-02 # License: GNU GPLv3 ################################################################################ sudo bash -c "echo b > /proc/sysrq-trigger" EOF sudo chmod 0755 /tmp/buskill/qubes-rpc/buskill.hardReboot
Finally, the most paranoid and most destructive if you accidentally trigger it is the ‘selfDestruct
‘ trigger that will overwrite your LUKS header with random data (including all your key slots containing your FDE master key and all LUKS metadata). In a matter of seconds, this will render all of the data on your machine permanently useless–even against rubber hose cryptanalysis.
If you only need BusKill for locking your screen or triggering a shutdown and don’t want to risk a false-positive wiping all your data, feel free to skip creating this script.
Execute the following in a reasonably trustworthy AppVM with internet access (eg ‘personal’):
cat > /tmp/buskill/qubes-rpc/buskill.selfDestruct <<'EOWF' #!/bin/bash #set -x ################################################################################ # File: buskill.selfDestruct # Purpose: Self-destruct trigger script for BusKill Kill Cord # For more info, see: https://buskill.in/ # WARNING: THIS IS EXPERIMENTAL SOFTWARE THAT IS DESIGNED TO CAUSE PERMANENT, # COMPLETE AND IRREVERSIBLE DATA LOSS! # Note : This script will *not* execute unless it's passed the '--yes' # argument. Be sure to test this trigger before depending on it! # Authors: Michael Altfield <michael@buskill.in> # Created: 2020-03-11 # Updated: 2020-03-11 # Version: 0.1 ################################################################################ ############ # SETTINGS # ############ BUSKILL_LOCK='/etc/qubes-rpc/buskill.lock' [ -f ${BUSKILL_LOCK} ] || echo "ERROR: Unable to find buskill.lock" WHICH="/usr/bin/which" CRYPTSETUP=`${WHICH} --skip-alias cryptsetup` || echo "ERROR: Unable to find cryptsetup" LS=`${WHICH} --skip-alias ls` || echo "ERROR: Unable to find ls" CP=`${WHICH} --skip-alias cp` || echo "ERROR: Unable to find cp" MV=`${WHICH} --skip-alias mv` || echo "ERROR: Unable to find mv" LN=`${WHICH} --skip-alias ln` || echo "ERROR: Unable to find ln" MKDIR=`${WHICH} --skip-alias mkdir` || echo "ERROR: Unable to find mkdir" MOUNT=`${WHICH} --skip-alias mount` || echo "ERROR: Unable to find mount" CAT=`${WHICH} --skip-alias cat` || echo "ERROR: Unable to find cat" GREP=`${WHICH} --skip-alias grep` || echo "ERROR: Unable to find grep" ECHO=`${WHICH} --skip-alias echo` || echo "ERROR: Unable to find echo" AWK=`${WHICH} --skip-alias awk` || echo "ERROR: Unable to find awk" HEAD=`${WHICH} --skip-alias head` || echo "ERROR: Unable to find head" LSBLK=`${WHICH} --skip-alias lsblk` || echo "ERROR: Unable to find lsblk" OD=`${WHICH} --skip-alias od` || echo "ERROR: Unable to find od" SUDO=`${WHICH} --skip-alias sudo` || echo "ERROR: Unable to find sudo" CHMOD=`${WHICH} --skip-alias chmod` || echo "ERROR: Unable to find chmod" BASH=`${WHICH} --skip-alias bash` || echo "ERROR: Unable to find bash" NOHUP=`${WHICH} --skip-alias nohup` || echo "ERROR: Unable to find nohup" SLEEP=`${WHICH} --skip-alias sleep` || echo "ERROR: Unable to find sleep" QVM_KILL=`${WHICH} --skip-alias qvm-kill` || echo "ERROR: Unable to find qvm-kill" POWEROFF=`${WHICH} --skip-alias poweroff` || echo "ERROR: Unable to find poweroff" CHROOT=`${WHICH} --skip-alias chroot` || echo "ERROR: Unable to find chroot" SYNC=`${WHICH} --skip-alias sync` || echo "ERROR: Unable to find sync" LDD=`${WHICH} --skip-alias ldd` || echo "ERROR: Unable to find ldd" XARGS=`${WHICH} --skip-alias xargs` || echo "ERROR: Unable to find xargs" CHROOT_PATH='/dev/shm/buskill/chroot' DIE_SCRIPT='/usr/bin/die.sh' ############## # ROOT CHECK # ############## # re-run as root if [[ $EUID -ne 0 ]]; then exec ${SUDO} ${BASH} "$0" "$@" fi ########### # CONFIRM # ########### # for safety, exit if this script is executed without a '--yes' argument ${ECHO} "${@}" | ${GREP} '\--yes' &> /dev/null if [ $? -ne 0 ]; then ${ECHO} "WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING" ${ECHO} "================================================================================" ${ECHO} "WARNING: THIS IS EXPERIMENTAL SOFTWARE THAT IS DESIGNED TO CAUSE PERMANENT, COMPLETE AND IRREVERSIBLE DATA LOSS!" ${ECHO} "================================================================================" ${ECHO} "WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING" ${ECHO} ${ECHO} "cowardly refusing to execute without the '--yes' argument for your protection. If really you want to proceed with damaging your system, retry with the '--yes' argument" exit 1 fi ########################### # (DELAYED) HARD SHUTDOWN # ########################### # The most secure encrypted computer is an encrypted computer that is *off* # This is our highest priority; initiate a hard-shutdown to occur in 1 # minute regardless of what happens later in this script ${NOHUP} ${SLEEP} 60 && ${ECHO} o > /proc/sysrq-trigger & ${NOHUP} ${SLEEP} 61 && ${POWEROFF} --poweroff --no-sync --no-wall --force & ${NOHUP} ${SLEEP} 62 && shutdown -h now & ############### # LOCK SCREEN # ############### # first action: lock the screen! ${SUDO} -u "${SUDO_USER}" ${BASH} -c "${BUSKILL_LOCK}" & ################ # KILL ALL VMs # ################ # doing this sooner will decrease the time needed to hard shutdown later # See https://github.com/QubesOS/qubes-issues/issues/5887 ${QVM_KILL} --all & ##################### # WIPE LUKS VOLUMES # ##################### # overwrite luks headers ${ECHO} "INFO: shredding LUKS header (plaintext metadata and keyslots with encrypted master decryption key)" writes='' oldIFS="${IFS}" IFS=$'\n' for line in $( ${LSBLK} --list --output 'UUID,FSTYPE' | ${GREP} 'crypt' ); do device="/dev/disk/by-uuid/`${ECHO} \"${line}\" | ${AWK} '{print \$1}'`" ${ECHO} -e "\t${device}" ########################### # OVERWRITE LUKS KEYSLOTS # ########################### # erases all keyslots, making the LUKS container "permanently inaccessible" ${CRYPTSETUP} luksErase --batch-mode "${device}" || ${HEAD} --bytes 20M /dev/urandom > ${device} & # store the pid of the above write tasks so we can try to wait for it to # flush to disk later -- before triggering a brutal hard-shutdown writes="${writes} $!" ##################################### # OVERWRITE LUKS PLAINTEXT METADATA # ##################################### luksVersion=`${OD} --skip-bytes 6 --read-bytes 2 --format d2 --endian=big --address-radix "n" "${device}"` # get the end byte to overwrite. For more info, see: # https://security.stackexchange.com/questions/227359/how-to-determine-start-and-end-bytes-of-luks-header if [[ $luksVersion -eq 1 ]]; then # LUKS1: https://gitlab.com/cryptsetup/cryptsetup/-/wikis/LUKS-standard/on-disk-format.pdf # in LUKS1, the whole header ends at 512 * the `payload-offset` # this is actually more than we need (includes keyslots), but # it's the fastest/easiest to bound to fetch in LUKS1 payloadOffset=`${OD} --skip-bytes 104 --read-bytes 4 --format d4 --endian=big --address-radix "n" "${device}"` luksEndByte=$(( 512 * ${payloadOffset} )) elif [[ $luksVersion -eq 2 ]]; then # LUKS2: https://gitlab.com/cryptsetup/LUKS2-docs/blob/master/luks2_doc_wip.pdf # in LUKS2, the end of the plaintext metadata area is twice the # size of the `hdr_size` field hdr_size=`${OD} --skip-bytes 8 --read-bytes 8 --format d8 --endian=big --address-radix "n" "${device}"` luksEndByte=$(( 2 * ${hdr_size} )) else # version unclear; just overwrite 20 MiB luksEndByte=20971520 fi # finally, shred that plaintext metadata; we do this in a new file descriptor # to prevent bash from truncating if ${device} is a file exec 5<> "${device}" ${HEAD} --bytes "${luksEndByte}" /dev/urandom >&5 & writes="${writes} $!" exec 5>&- done IFS="${oldIFS}" ####################### # WAIT ON DISK WRITES # ####################### # xargs is our leading/trailing whitespace trim() function writes=`${ECHO} "${writes}" | ${XARGS}` # wait until all the write tasks above have completed # note: do *not* put quotes around this arg or the whitespace will break wait # note: without the conditional, wait will wait indefinitely when $writes is empty if [[ ${writes} ]]; then wait ${writes}; fi # clear write buffer to ensure headers overwrites are actually synced to disks sync; echo 3 > /proc/sys/vm/drop_caches ################# # CREATE CHROOT # ################# # we have to create a ramfs chroot with cryptsetup, poweroff, and a few other # basic depends for after we luksSuspend our rootfs from under our feet ${MKDIR} -p "${CHROOT_PATH}/proc" ${MKDIR} -p "${CHROOT_PATH}/sys" ${MKDIR} -p "${CHROOT_PATH}/dev" ${MKDIR} -p "${CHROOT_PATH}/pts" ${MKDIR} -p "${CHROOT_PATH}/bin" ${MKDIR} -p "${CHROOT_PATH}/lib64" ${MKDIR} -p "${CHROOT_PATH}/lib/systemd" ${MKDIR} -p "${CHROOT_PATH}/usr/sbin" ${MKDIR} -p "${CHROOT_PATH}/usr/bin" ${MOUNT} -t proc none "${CHROOT_PATH}/proc" ${MOUNT} -t sysfs none "${CHROOT_PATH}/sys" ${MOUNT} -o bind /dev "${CHROOT_PATH}/dev" ${MOUNT} -o bind /dev/pts "${CHROOT_PATH}/dev/pts" # copy-in our binaries and their depends binaries="${BASH} ${CRYPTSETUP} ${ECHO} ${LS} ${NOHUP} ${SLEEP} ${XARGS} ${SYNC} ${POWEROFF}" for binary in ${binaries}; do ${CP} -vf "${binary}" "${CHROOT_PATH}/${binary}" libs="$( ${LDD} "${binary}" | ${GREP} -Eo '/lib.*\.so(\.[0-9]*)*' )" for lib in ${libs}; do ${CP} -vf "${lib}" "${CHROOT_PATH}/${lib}" done done # fix around some libs and symlink issues ${MV} "${CHROOT_PATH}/lib" "${CHROOT_PATH}/usr/lib" ${LN} -s "usr/lib" "${CHROOT_PATH}/lib" ${CAT} << EOF > "${CHROOT_PATH}/${DIE_SCRIPT}" #!${BASH} # let's give ourselves 10 more seconds to wipe luks keys from RAM ${NOHUP} ${SLEEP} 10 && ${ECHO} o > /proc/sysrq-trigger & ${NOHUP} ${SLEEP} 11 && ${POWEROFF} --poweroff --no-sync --no-wall --force & ################################# # WIPE DECRYPTION KEYS FROM RAM # ################################# # suspend each currently-decrypted LUKS volume ${ECHO} "INFO: removing decryption keys from memory" waits='' for device in \$( ${LS} -1 "/dev/mapper" ); do ${ECHO} -e "\t\${device}"; ${CRYPTSETUP} luksSuspend "\${device}" & waits="\${waits} $!" done ${ECHO} "INFO: finished luksSuspend calls" # xargs is our leading/trailing whitespace trim() function waits=`${ECHO} "\${waits}" | ${XARGS}` if [[ \${waits} ]]; then wait \${waits}; fi ${ECHO} "INFO: finished waiting" # clear page caches in memory (again) sync; echo 3 > /proc/sys/vm/drop_caches ${ECHO} "INFO: finished syncing" ############################# # (IMMEDIATE) HARD SHUTDOWN # ############################# ${ECHO} "INFO: Powering Down" # do whatever works; this is important. ${ECHO} o > /proc/sysrq-trigger & ${SLEEP} 1 ${POWEROFF} --poweroff --no-sync --no-wall --force & EOF ${CHMOD} +x "${CHROOT_PATH}/${DIE_SCRIPT}" # finally, enter the chroot and call the above die.sh script inside it ${CHROOT} "${CHROOT_PATH}" "${DIE_SCRIPT}" EOWF sudo chmod 0755 /tmp/buskill/qubes-rpc/buskill.selfDestruct sudo chown root:root /tmp/buskill/qubes-rpc/buskill.selfDestruct
Finally, we define policy files in dom0
that permit our ‘sys-usb
‘ VM to be able to execute the above triggers. Note that ‘sys-usb
‘ is necessarily a high-risk and untrusted VM that could easily be compromised. Therefore, it’s critically important that any buskill triggers defined on dom0
are self-contained and don’t accept any input telling them them what to execute on dom0
.
Execute the following in a reasonably trustworthy AppVM with internet access (eg ‘personal’):
cat << EOF | sudo tee /tmp/buskill/qubes-rpc/policy/buskill.lock ################################################################################ # File: dom0:/etc/qubes-rpc/policy/buskill.lock # Purpose: Permits sys-usb VM to execute the lock screen BusKill trigger. # For more info, see: https://buskill.in/qubes-os/ # Authors: Michael Altfield <michael@buskill.in> # Created: 2020-01-02 # License: GNU GPLv3 ################################################################################ sys-usb dom0 allow EOF sudo chmod 0644 /tmp/buskill/qubes-rpc/policy/buskill.lock cat << EOF | sudo tee /tmp/buskill/qubes-rpc/policy/buskill.softShutdown ################################################################################ # File: dom0:/etc/qubes-rpc/policy/buskill.softShutdown # Purpose: Permits sys-usb VM to execute the soft shutdown BusKill trigger. # For more info, see: https://buskill.in/qubes-os/ # Authors: Michael Altfield <michael@buskill.in> # Created: 2020-01-02 # License: GNU GPLv3 ################################################################################ sys-usb dom0 allow EOF sudo chmod 0644 /tmp/buskill/qubes-rpc/policy/buskill.softShutdown cat << EOF | sudo tee /tmp/buskill/qubes-rpc/policy/buskill.hardReboot ################################################################################ # File: dom0:/etc/qubes-rpc/policy/buskill.hardReboot # Purpose: Permits sys-usb VM to execute the hard reboot BusKill trigger. # For more info, see: https://buskill.in/qubes-os/ # Authors: Michael Altfield <michael@buskill.in> # Created: 2020-01-02 # License: GNU GPLv3 ################################################################################ sys-usb dom0 allow EOF sudo chmod 0644 /tmp/buskill/qubes-rpc/policy/buskill.hardReboot cat << EOF | sudo tee /tmp/buskill/qubes-rpc/policy/buskill.selfDestruct ################################################################################ # File: dom0:/etc/qubes-rpc/policy/buskill.selfDestruct # Purpose: Permits sys-usb VM to execute the wipe data BusKill trigger. # For more info, see: https://buskill.in/qubes-os/ # Authors: Michael Altfield <michael@buskill.in> # Created: 2020-01-02 # License: GNU GPLv3 ################################################################################ sys-usb dom0 allow EOF sudo chmod 0644 /tmp/buskill/qubes-rpc/policy/buskill.selfDestruct
Now that all our files destined for dom0 are prepared in our AppVM, let’s create a tarball of them.
Execute the following in a reasonably trustworthy AppVM with internet access (eg ‘personal’):
pushd /tmp/buskill tar -czvf buskill.qubes-rpc.tar.gz qubes-rpc/* sync
Finally, we copy the tarball to dom0 and extract it. Note that you’ll have to type this manually as copy-paste to dom0 isn’t allowed–this is why we did the tarball/copy approach. Don’t worry, it’s only 4 lines ;P. Be sure to replace ‘personal
‘ with whatever AppVM you ran the above commmands on (where the tarball created above lives).
Execute the following in Dom0:
sudo su - cd /etc qvm-run --pass-io personal 'cat /tmp/buskill/buskill.qubes-rpc.tar.gz' > buskill.qubes-rpc.tar.gz tar -xzvf buskill.qubes-rpc.tar.gz sync
That’s it! BusKill is now installed.
Customization
If you want to customize what is triggered when your BusKill USB device is removed from your system, you want to edit your ‘/etc/udev/rules.d/buskill.rules
‘ file on your ‘sys-usb
‘ Qube.
The defaults described above enable the screen lock trigger. For example, if you want BusKill to trigger a hard shutdown instead of locking the screen, comment-out the ‘buskill.lock
‘ line and uncomment the ‘hardReboot
‘ line.
... #ACTION=="remove", SUBSYSTEM=="usb", ENV{ID_MODEL}=="Micromax_A74", RUN+="/usr/bin/qrexec-client-vm dom0 buskill.lock" #ACTION=="remove", SUBSYSTEM=="usb", ENV{ID_MODEL}=="Micromax_A74", RUN+="/usr/bin/qrexec-client-vm dom0 buskill.softShutdown" ACTION=="remove", SUBSYSTEM=="usb", ENV{ID_MODEL}=="Micromax_A74", RUN+="/usr/bin/qrexec-client-vm dom0 buskill.hardReboot" #ACTION=="remove", SUBSYSTEM=="usb", ENV{ID_MODEL}=="Micromax_A74", RUN+="/usr/bin/qrexec-client-vm dom0 buskill.selfDestruct+--yes" EOF sudo udevadm control --reload
Note: Changes to the
buskill.rules
file require a restart or udev rule reload via `sudo udevadm control --reload
`
Troubleshooting
Is unplugging your USB device doing nothing? Try removing the udev property from your ‘/etc/udev/rules.d/buskill.rules
‘ file on your ‘sys-usb
‘ Qube.
... ACTION=="remove", SUBSYSTEM=="usb", RUN+="/usr/bin/qrexec-client-vm dom0 buskill.lock" #ACTION=="remove", SUBSYSTEM=="usb", RUN+="/usr/bin/qrexec-client-vm dom0 buskill.softShutdown" #ACTION=="remove", SUBSYSTEM=="usb", RUN+="/usr/bin/qrexec-client-vm dom0 buskill.hardReboot" #ACTION=="remove", SUBSYSTEM=="usb", RUN+="/usr/bin/qrexec-client-vm dom0 buskill.selfDestruct+--yes" EOF sudo udevadm control --reload
The above example should trigger the screen to lock when any USB device is removed from your system. If you want to be more specific, learn how to query your USB drive for device-specific identifiers in our original article Introducing BusKill: A Kill Cord for your Laptop. Note that the `udevadm monitor --environment --udev
` command should be run in the ‘sys-usb
‘ Qube.
Note: Changes to the
buskill.rules
file require a restart or udev rule reload via `sudo udevadm control --reload
`
Limitations/Improvements
Security is porous. All software has bugs. Nothing is 100% secure.
This section will explain limitations to the information outlined in this article, as well as suggest potential improvements.
Not a suitable replacement for TAILS
If you are an investigative journalist, activist, or political dissident operating in an oppressive regime where an adversary having access to your Internet activity could cause pain, suffering, or loss-of-life, then you should consider using TAILS.
Don’t trust sys-usb
This implementation of BusKill in QubesOS necessarily grants the ‘sys-usb
‘ Qube permission to execute scripts in dom0
with immense destructive power, such as the ability to make all of the data on your computer permanently inaccessible.
The ‘sys-usb
‘ Qube is also a particularly exposed Qube that should not be trusted, as it could become infected by a malicious USB peripheral. Please take this into consideration when designing your BusKill triggers and granting permission to the ‘sys-usb
‘ Qube to execute them on dom0
via your dom0:/etc/qubes-rpc/policy/
files.
IANA QubesOS Dev
Disclaimer: I am a QubesOS user; I am not a QubesOS developer. The way BusKill was implemented in QubesOS here was done to the best of my ability to make it functional and secure, but I did not consult the Qubes dev team for a review prior to publication. If you are a QubesOS developer and have noticed a flaw or have a recommendation on how this was implemented, please let me know in the comments or by email
No Hard-Shutdown
You may have noticed the absence of a `buskill.hardShutdown
` trigger. Indeed, a “hard shutdown” is preferred to a “hard reboot” as it stops power from flowing to your RAM (which holds your FDE master key) ASAP.
Unfortunatley, there’s a bug in QubesOS that causes would-be 1-second shutdowns via the SysRq Power Off signal take over a minute 🙁
Self-Destruct Implementation Details
For more details on the self-destruct trigger–including post-destruct forensic details, see LUKS Header Shredder.
QubesOS Trigger Integration
In July 2020, I created a feature request and PR for the QubesOS team to integrate a lockscreen qrexec service directly into their release, which would simplifiy these installation instructions.
If you would like to make BusKill more accessible on QubesOS, please consider commenting on the QubesOS #5893 requesting the QubesOS team to incorporate lockscreen and shutdown qrexec services into the next QubesOS release.
Bathroom Breaks
The installation guide described in this article does not have any way to easy way to “pause” BusKill before stepping away from your computer (eg to go to the bathroom).
We’ve published an updated article describing how to setup a simple keyboard shortcut that disarms BusKill so you can step away from your computer without it shutting-down or self-destructing.
If you’d like to purchase a BusKill cable, click here.
Good afternoon
I’m asking for your help.
I would like to set up Bushkill in Qubes according to your instructions
https://www.buskill.in/qubes-os/
But I can’t figure out how to execute these commands?
Follow these steps in your Qube “sys-usb”:
sys-usb:/rw/config/buskill.rules
Do I need to run them sequentially line by line? Please help me
The first `cat` command is a multi-line command that should be pasted-into your BASH terminal all at once. Everything between the two `EOF` characters is used to create the file ‘/rw/config/buskill.rules’. For more info, see https://stackoverflow.com/questions/2500436/how-does-cat-eof-work-in-bash
What isn’t working for you? Are you getting an error?
I followed the guide and it also didn’t work. My first guess would be that the Qubes-Team is currently (starting with 4.2) implementing a new policy system and the locations provided in the tutorial all point to the old implementation. The new one is located at /etc/qubes/policy.d
I’m at no means an expert, but that’s what i noticed.
Thanks for letting us know 🙂
Were you able to get it working by simply substituting
/etc/qubes/policy.d/
instead of/etc/qubes-rpc/
?Edit: on my Qubes system, I have both
/etc/qubes/policy.d/
and/etc/qubes-rpc/
dirs, so I’m not sure if this is the issue. Though I do only have Qubes 4.1.It looks like the changes you mentioned are described here https://www.qubes-os.org/news/2020/06/22/new-qrexec-policy-system/#policy-files
But the above guide also states that it’s backwards compatible (so afaict the old dir & formats should be supported until Qubes 5.0):
* https://www.qubes-os.org/news/2020/06/22/new-qrexec-policy-system/#backward-compatibility