I’m not expert in this topic, though it has stood out in my mind given Ubuntu requires root password to effect certain changes to the OS, but Qubes does not. It’s a bit counterintutive, but then, as the 4+ year long thread shows, there are is a lot of complexity involved.
The explanation offered from past-Joanna, that sudo is unnecessary because…
In Qubes VMs there is no point in isolating the root account from the user account. This is because all the user data is already accessible from the user account, so there is no direct benefit for the attacker if she could escalate to root (there is even no benefit in trying to install some persistent rootkits, as the VM’s root filesystem modifications are lost upon each start of a VM).
https://www.qubes-os.org/doc/vm-sudo/
…only seems relevant for app qubes. What about standalone qubes? In that case, the system files are persistent across reboots, and it would seem sudo should be required. I’m not sure what 2024-Joanna would have to say about this.
I’m also confused about what the status of Whonix is in relation to this. Apparently Whonix shouldn’t have passwordless root in VMs, but as a matter of fact it does (in Qubes) because [flatpak, …, etc. ] breaks if Whonix removes qubes-core-agent-passowrdless-root
. So I guess this problem has not been resolved. I am still using passwordless sudo in Whonix.
Solution in Bash
Given the task was specifically to create a desktop icon, and that this should open a root terminal in a specific qube (https://www.kicksecure.com/wiki/Root#Qubes_Root_Console), the following bash script would suffice:
#!/bin/bash
# root-terminal
# open root terminal in any qube running
pause() {
echo -n "<Press Any Key>"
local Pause
read Pause
}
Id=$(xdotool getwindowfocus)
Qube=$(xprop _QUBES_VMNAME -id $Id|cut -f2 -d \" )
if [[ "$Qube" == "_QUBES_VMNAME: not found." ]]
then
echo "Open root terminal selector:"
RunningQubes=($(qvm-ls --fields=name --running | grep -vE "dom0|NAME" | sort ))
Count=0
for RunningQube in "${RunningQubes[@]}"; do
echo " [$Count]: $RunningQube"
Count=$((Count+1))
done
echo "Select qube, or press <ENTER> to cancel"
read Selection
if [[ $Selection =~ [0-9]+ ]]
then
Qube="${RunningQubes[$Selection]}"
else
Qube=""
echo "Cancelled"
pause
fi
fi
# If $Qube is not empty, try to open the root terminal
[[ -n $Qube ]] && qvm-run -u root $Qube qubes-run-terminal -e bash
Save it as open-root-terminal
in your your script folder in dom0.
Create this shortcut (‘launcher’) in ~/Desktop
in dom0:
[Desktop Entry]
Version=1.0
Type=Application
Name=Root-Terminal
Comment=Open a root terminal in your present qube
Exec=/home/<your-username>/<your-script-folder>/root-terminal
Icon=utilities-terminal
Path=
Terminal=false
StartupNotify=false
Save it as “Root-Terminal.desktop” and make it executable with chmod +x Root-Terminal.desktop
. The creation of this shortcut could be automated by including it in the bashscript.
The script works with both the desktop and keyboard shortcuts.
Solution in GUI
It would be preferable to use the GUI qubes selector widget like the one that opens up when copying files between qubes with qvm-copy-to-vm
. Unfortunately there is no command to select qubes in the GUI.
This thread gets us half-way there: https://forum.qubes-os.org/t/how-does-one-create-a-gui-app-on-dom0/30143/7
Tinkering with Python a bit, I managed to turn this partial solution into a working version:
#!/usr/bin/python3
# root-terminal
# open root terminal in any qube running
import gi, subprocess, os
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Get running qubes
output = subprocess.check_output("qvm-ls --fields=name --running | grep -vE \"dom0|NAME\" | sort -r", shell=True, universal_newlines=True)
# Make a list
_qubes_list = output.split('\n')
# Remove empty list entries
qubes_list = list(filter(bool, _qubes_list))
def create_window():
window = Gtk.Window(title="Open Root Terminal")
window.connect("delete-event", Gtk.main_quit)
window.set_border_width(10)
# Set width manually, so title is visible
# window.set_size_request(width=300, height=50)
# create the drop down menu
menu = Gtk.ComboBoxText()
menu.set_entry_text_column(0)
menu.set_id_column(0)
for qube in qubes_list:
menu.insert(0, f"{qube}", f"{qube}")
menu.insert(0, "Open Root Terminal: Select qube", "Select qube")
menu.set_active(0)
menu.connect("changed", selection_changed)
# add the drop down menu to the window
window.add(menu)
window.show_all()
def selection_changed(menu):
selection = menu.get_active_text()
qube_name = selection
# qvm-run qubes-run-terminal as root in {qube_name} and then disown (close own window)
cmd = f"qvm-run 2>/dev/null -u root {qube_name} qubes-run-terminal & disown"
# run the command
os.system(cmd)
Gtk.main_quit()
def main():
create_window()
Gtk.main()
if __name__ == "__main__":
main()
This works both with both desktop and keyboard shortcuts. It could be improved by having the script open a root terminal in qube that calls it without prompting. I pulled that code out because it was giving me a headache.