Hi, I wrote a script that solves the problem (no changes to the code, no need to compile binaries, etc.). My script start custom service in the system root, and your clipboard will work (user mode also):
I’m posting this because I want others who have encountered the same problem to get a quick, effective solution without having to run third-party code on the host machine.
I ask everyone, including @arraybolt3 @Patrick to take note of my solution (from an OS security perspective)
!!!
-
Update your VirtualBox
-
login to system like sysmaint
-
run script
-
set bidirectional
-
reboot system
(I understand how this looks from the outside, so I suggest and ask everyone to familiarize themselves with this script (don’t trust people on the internet, especially on a forum about an anonymous OS; there’s nothing criminal here, just automation so you don’t have to type things manually)
After you run it, don’t forget to set it to Bidirectional, and the buffer will work the same way as a root/user
Let me know if you run into any issues ![]()
download file:
https[:]//filebin[.]net/562pahe0lulimhj7/setup.sh
or copy it:
#!/bin/bash
set -o nounset
set -o pipefail
UNIT_NAME='vbox-wayland-clipboard.service'
UNIT_PATH='/usr/lib/systemd/user/vbox-wayland-clipboard.service'
LAUNCH_PATH='/usr/libexec/vm-config-dist/vbox-wayland-clipboard-autostart'
DESK_PATH='/etc/xdg/autostart/vbox-wayland-clipboard.desktop'
red() { printf '\033[31m%s\033[0m\n' "$*"; }
grn() { printf '\033[32m%s\033[0m\n' "$*"; }
ylw() { printf '\033[33m%s\033[0m\n' "$*"; }
if [ "$(id -u)" -ne 0 ]; then
red "ERROR: run as root in the 'sysmaint' boot mode: sudo bash $0"
exit 1
fi
search_dirs=(/etc/systemd/user /run/systemd/user /usr/lib/systemd/user \
/usr/local/lib/systemd/user /root/.config/systemd/user)
for h in /home/*; do
[ -d "$h/.config/systemd/user" ] && search_dirs+=("$h/.config/systemd/user")
done
echo "=== INSTALL ==="
echo "[1/6] clearing masks (/dev/null symlinks) and empty unit files ..."
for d in "${search_dirs[@]}"; do
f="$d/$UNIT_NAME"
if [ -L "$f" ] || { [ -e "$f" ] && [ ! -s "$f" ]; }; then
echo " removing $f"
rm -f "$f"
fi
done
systemctl --global unmask "$UNIT_NAME" 2>/dev/null || true
echo "[2/6] writing $UNIT_PATH ..."
install -d /usr/lib/systemd/user
cat > "$UNIT_PATH" <<'UNIT'
[Unit]
Description=VirtualBox shared clipboard for Wayland (opt-in, default-off)
ConditionVirtualization=oracle
ConditionEnvironment=WAYLAND_DISPLAY
StartLimitIntervalSec=10
StartLimitBurst=3
[Service]
Type=simple
ExecStart=/usr/bin/VBoxClient --foreground --wayland
Restart=on-failure
RestartSec=2s
[Install]
WantedBy=default.target
UNIT
echo "[3/6] writing $LAUNCH_PATH ..."
install -d /usr/libexec/vm-config-dist
cat > "$LAUNCH_PATH" <<'LAUNCH'
#!/bin/bash
set -o nounset
set -o pipefail
PATH=/usr/bin:/bin
unit='vbox-wayland-clipboard.service'
state="$(systemctl --user is-enabled "$unit" 2>/dev/null || true)"
case "$state" in
enabled|enabled-runtime) ;;
*) exit 0 ;;
esac
counter=0
while [ "$counter" -lt 50 ]; do
systemctl --user show-environment 2>/dev/null | grep -q '^WAYLAND_DISPLAY=' && break
counter="$(( counter + 1 ))"
sleep 0.2
done
systemctl --user reset-failed "$unit" 2>/dev/null || true
exec systemctl --user start "$unit"
LAUNCH
chmod 755 "$LAUNCH_PATH"
echo "[4/6] writing $DESK_PATH ..."
cat > "$DESK_PATH" <<'DESK'
[Desktop Entry]
Type=Application
Name=VirtualBox shared clipboard for Wayland (opt-in)
Exec=/usr/libexec/vm-config-dist/vbox-wayland-clipboard-autostart
StartupNotify=false
NoDisplay=true
NotShowIn=QUBES;
DESK
echo "[5/6] Guest Additions device (/dev/vboxuser) on every boot ..."
systemctl enable --now virtualbox-guest-utils.service 2>/dev/null \
|| ylw " virtualbox-guest-utils.service not found; loading module only."
echo vboxguest > /etc/modules-load.d/vboxguest.conf
modprobe vboxguest 2>/dev/null || true
echo "[6/6] enabling for ALL users ..."
systemctl daemon-reload
systemctl --global enable "$UNIT_NAME"
echo
echo "=== CHECKUP ==="
fail=0; warn=0
chk_file() {
local p="$1" min="$2" sz
if [ -L "$p" ]; then red " FAIL $p is a symlink (masked?)"; fail=$((fail+1)); return; fi
if [ ! -f "$p" ]; then red " FAIL $p missing"; fail=$((fail+1)); return; fi
sz="$(wc -c < "$p")"
if [ "$sz" -lt "$min" ]; then red " FAIL $p is $sz bytes (empty/too small)"; fail=$((fail+1)); return; fi
grn " OK $p ($sz bytes)"
}
chk_file "$UNIT_PATH" 100
chk_file "$LAUNCH_PATH" 100
chk_file "$DESK_PATH" 50
leftover=0
for d in "${search_dirs[@]}"; do
f="$d/$UNIT_NAME"
[ "$f" = "$UNIT_PATH" ] && continue
if [ -L "$f" ] || { [ -e "$f" ] && [ ! -s "$f" ]; }; then
red " FAIL leftover mask/empty: $f"; leftover=$((leftover+1)); fail=$((fail+1))
fi
done
[ "$leftover" -eq 0 ] && grn " OK no leftover masks / empty unit files"
if [ -x "$LAUNCH_PATH" ]; then grn " OK launcher is executable"; else red " FAIL launcher not executable"; fail=$((fail+1)); fi
if [ -L "/etc/systemd/user/default.target.wants/$UNIT_NAME" ]; then
grn " OK enabled for all users (default.target.wants symlink present)"
else
ylw " WARN global enable symlink missing"; warn=$((warn+1))
fi
if command -v VBoxClient >/dev/null 2>&1; then
grn " OK VBoxClient present ($(VBoxClient --version 2>/dev/null | head -n1))"
else
red " FAIL /usr/bin/VBoxClient not found (Guest Additions missing)"; fail=$((fail+1))
fi
if lsmod 2>/dev/null | grep -q '^vboxguest'; then grn " OK vboxguest module loaded"; else ylw " WARN vboxguest module not loaded"; warn=$((warn+1)); fi
if [ -e /dev/vboxuser ]; then grn " OK /dev/vboxuser present"; else red " FAIL /dev/vboxuser missing (VBoxClient will fail VbglR3InitUser)"; fail=$((fail+1)); fi
echo
if [ "$fail" -eq 0 ]; then grn "RESULT: install OK ($warn warning(s))."; else red "RESULT: $fail problem(s), $warn warning(s) — fix the FAIL lines above."; fi
echo
echo "NEXT:"
echo " 1) On the HOST (normal user, VM powered off):"
echo " VBoxManage modifyvm \"<vm-name-or-uuid>\" --clipboard-mode bidirectional"
echo " and launch the VM as your NORMAL user, not root."
echo " 2) Reboot Whonix into the normal 'user' mode."
echo " 3) As 'user' (no sudo) verify:"
echo " systemctl --user is-enabled $UNIT_NAME # => enabled (NOT masked)"
echo " systemctl --user status $UNIT_NAME # => active (running)"
[ "$fail" -eq 0 ] && exit 0 || exit 1