From eab78547e482635e778935e77b86b72be6be209b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Pierret=20=28fepitre=29?= Date: Sat, 19 Jun 2021 17:34:07 +0200 Subject: [PATCH] Implement VNC GuiVM We expose a new 'guivm' flavor. In order to enable this remote GuiVM, one has to enable Qubes services: - lightdm - guivm - guivm-vnc This is similar to `sys-gui-gpu` setup but here, `guivm-vnc` service add ExecStartPre and ExecStartPost to lightdm systemd service in order to configure Xorg server with dummyqbs driver and x11vnc server. --- Makefile | 20 +++- .../etc/X11/Xsession.d/50guivm-windows-prefix | 4 +- .../etc/X11/Xsession.d/60xfce-desktop | 4 +- .../etc/X11/xorg-qubes-x11vnc.conf.template | 34 ++++++ .../lightdm.service.d/qubes-guivm-vnc.conf | 6 + appvm-scripts/usrbin/qubes-run-x11vnc | 26 ++++ appvm-scripts/usrbin/qubes-run-x11vnc-pre | 112 ++++++++++++++++++ appvm-scripts/usrbin/qubes-run-xorg | 3 +- debian/control | 9 ++ debian/qubes-gui-vnc.install | 4 + rpm_spec/gui-agent.spec.in | 14 +++ 11 files changed, 225 insertions(+), 11 deletions(-) create mode 100644 appvm-scripts/etc/X11/xorg-qubes-x11vnc.conf.template create mode 100644 appvm-scripts/etc/systemd/system/lightdm.service.d/qubes-guivm-vnc.conf create mode 100644 appvm-scripts/usrbin/qubes-run-x11vnc create mode 100644 appvm-scripts/usrbin/qubes-run-x11vnc-pre create mode 100644 debian/qubes-gui-vnc.install diff --git a/Makefile b/Makefile index 603c81b0..0fe2e873 100644 --- a/Makefile +++ b/Makefile @@ -77,9 +77,7 @@ clean: install: install-rh-agent install-pulseaudio -install-rh-agent: appvm install-common - install -m 0644 -D appvm-scripts/qubes-gui-agent.service \ - $(DESTDIR)/$(SYSLIBDIR)/systemd/system/qubes-gui-agent.service +install-rh-agent: appvm install-common install-systemd install -m 0644 -D appvm-scripts/etc/sysconfig/desktop \ $(DESTDIR)/etc/sysconfig/desktop install -D appvm-scripts/etc/X11/xinit/xinitrc.d/20qt-x11-no-mitshm.sh \ @@ -91,13 +89,11 @@ install-rh-agent: appvm install-common install -D appvm-scripts/etc/X11/xinit/xinitrc.d/60xfce-desktop.sh \ $(DESTDIR)/etc/X11/xinit/xinitrc.d/60xfce-desktop.sh -install-debian: appvm install-common install-pulseaudio +install-debian: appvm install-common install-pulseaudio install-systemd install -d $(DESTDIR)/etc/X11/Xsession.d install -m 0644 appvm-scripts/etc/X11/Xsession.d/* $(DESTDIR)/etc/X11/Xsession.d/ install -d $(DESTDIR)/etc/xdg install -m 0644 appvm-scripts/etc/xdg-debian/* $(DESTDIR)/etc/xdg - install -m 0644 -D appvm-scripts/qubes-gui-agent.service \ - $(DESTDIR)/$(SYSLIBDIR)/systemd/system/qubes-gui-agent.service install-pulseaudio: install -D pulse/start-pulseaudio-with-vchan \ @@ -116,6 +112,10 @@ endif install -m 0644 -D appvm-scripts/etc/xdgautostart/qubes-pulseaudio.desktop \ $(DESTDIR)/etc/xdg/autostart/qubes-pulseaudio.desktop +install-systemd: + install -m 0644 -D appvm-scripts/qubes-gui-agent.service \ + $(DESTDIR)/$(SYSLIBDIR)/systemd/system/qubes-gui-agent.service + install-common: install -D gui-agent/qubes-gui $(DESTDIR)/usr/bin/qubes-gui install -D gui-common/qubes-gui-runuser $(DESTDIR)/usr/bin/qubes-gui-runuser @@ -130,6 +130,10 @@ install-common: $(DESTDIR)/usr/bin/qubes-run-xephyr install -D appvm-scripts/usrbin/qubes-start-xephyr \ $(DESTDIR)/usr/bin/qubes-start-xephyr + install -D appvm-scripts/usrbin/qubes-run-x11vnc-pre \ + $(DESTDIR)/usr/bin/qubes-run-x11vnc-pre + install -D appvm-scripts/usrbin/qubes-run-x11vnc \ + $(DESTDIR)/usr/bin/qubes-run-x11vnc install -D appvm-scripts/usrbin/qubes-change-keyboard-layout \ $(DESTDIR)/usr/bin/qubes-change-keyboard-layout install -D appvm-scripts/usrbin/qubes-set-monitor-layout \ @@ -142,6 +146,10 @@ install-common: $(DESTDIR)$(LIBDIR)/xorg/modules/drivers/dummyqbs_drv.so install -m 0644 -D appvm-scripts/etc/X11/xorg-qubes.conf.template \ $(DESTDIR)/etc/X11/xorg-qubes.conf.template + install -m 0644 -D appvm-scripts/etc/X11/xorg-qubes-x11vnc.conf.template \ + $(DESTDIR)/etc/X11/xorg-qubes-x11vnc.conf.template + install -m 0644 -D appvm-scripts/etc/systemd/system/lightdm.service.d/qubes-guivm-vnc.conf \ + $(DESTDIR)/etc/systemd/system/lightdm.service.d/qubes-guivm-vnc.conf install -m 0644 -D appvm-scripts/etc/profile.d/qubes-gui.sh \ $(DESTDIR)/etc/profile.d/qubes-gui.sh install -m 0644 -D appvm-scripts/etc/profile.d/qubes-gui.csh \ diff --git a/appvm-scripts/etc/X11/Xsession.d/50guivm-windows-prefix b/appvm-scripts/etc/X11/Xsession.d/50guivm-windows-prefix index 353bc0dd..ff883dfc 100644 --- a/appvm-scripts/etc/X11/Xsession.d/50guivm-windows-prefix +++ b/appvm-scripts/etc/X11/Xsession.d/50guivm-windows-prefix @@ -7,6 +7,6 @@ QUBES_VMNAME="$(qubesdb-read /guivm-windows-prefix)" # Set _QUBES_VMNAME atom for a window manager (e.g. xfwm4) -if qsvc guivm-gui-agent; then +if qsvc guivm; then xprop -root -f _QUBES_VMNAME 8s -set _QUBES_VMNAME "${QUBES_VMNAME:-GuiVM}" -fi \ No newline at end of file +fi diff --git a/appvm-scripts/etc/X11/Xsession.d/60xfce-desktop b/appvm-scripts/etc/X11/Xsession.d/60xfce-desktop index 57000ad1..0937b568 100755 --- a/appvm-scripts/etc/X11/Xsession.d/60xfce-desktop +++ b/appvm-scripts/etc/X11/Xsession.d/60xfce-desktop @@ -3,7 +3,7 @@ # shellcheck disable=SC1091 . /usr/lib/qubes/init/functions -if ! qsvc guivm-gui-agent; then +if ! qsvc guivm; then XDG_MENU_PREFIX="xfce-" export XDG_MENU_PREFIX @@ -27,4 +27,4 @@ fi export QT_QPA_PLATFORMTHEME=qt5ct xfsettingsd --replace& -fi \ No newline at end of file +fi diff --git a/appvm-scripts/etc/X11/xorg-qubes-x11vnc.conf.template b/appvm-scripts/etc/X11/xorg-qubes-x11vnc.conf.template new file mode 100644 index 00000000..c22a0b2d --- /dev/null +++ b/appvm-scripts/etc/X11/xorg-qubes-x11vnc.conf.template @@ -0,0 +1,34 @@ +Section "Module" + Load "fb" +EndSection + +Section "ServerLayout" + Identifier "Default Layout" + Screen 0 "Screen0" 0 0 +EndSection + +Section "Device" + Identifier "Videocard0" + Driver "dummyqbs" + VideoRam %MEM% + Option "GUIDomID" "%GUI_DOMID%" +EndSection + +Section "Monitor" + Identifier "Monitor0" + HorizSync %MIN_MAX_HSYNC% + VertRefresh %MIN_MAX_VSYNC% +%MODELINES% + Option "PreferredMode" "QB1024x768" +EndSection + +Section "Screen" + Identifier "Screen0" + Device "Videocard0" + Monitor "Monitor0" + DefaultDepth %DEPTH% + SubSection "Display" + Viewport 0 0 + Depth %DEPTH% + EndSubSection +EndSection diff --git a/appvm-scripts/etc/systemd/system/lightdm.service.d/qubes-guivm-vnc.conf b/appvm-scripts/etc/systemd/system/lightdm.service.d/qubes-guivm-vnc.conf new file mode 100644 index 00000000..dfdb23e8 --- /dev/null +++ b/appvm-scripts/etc/systemd/system/lightdm.service.d/qubes-guivm-vnc.conf @@ -0,0 +1,6 @@ +[Unit] +ConditionPathExists=/var/run/qubes-service/lightdm + +[Service] +ExecStartPre=/usr/bin/qubes-run-x11vnc-pre +ExecStartPost=/usr/bin/qubes-run-x11vnc diff --git a/appvm-scripts/usrbin/qubes-run-x11vnc b/appvm-scripts/usrbin/qubes-run-x11vnc new file mode 100644 index 00000000..34eaf85c --- /dev/null +++ b/appvm-scripts/usrbin/qubes-run-x11vnc @@ -0,0 +1,26 @@ +#!/bin/sh +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2021 Frédéric Pierret +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# +X11VNC=/usr/bin/x11vnc +# WIP: Ensure to have the good set of x11vnc options. +OPTIONS_VNC="-display :0 -auth /var/run/lightdm/root/\:0 -noxrecord -noxfixes -noxdamage -loop" + +$X11VNC $OPTIONS_VNC & diff --git a/appvm-scripts/usrbin/qubes-run-x11vnc-pre b/appvm-scripts/usrbin/qubes-run-x11vnc-pre new file mode 100644 index 00000000..27829cd2 --- /dev/null +++ b/appvm-scripts/usrbin/qubes-run-x11vnc-pre @@ -0,0 +1,112 @@ +#!/bin/bash +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2021 Frédéric Pierret +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# + +# Source Qubes library. +# shellcheck disable=SC1091 +. /usr/lib/qubes/init/functions + +array_min_max() { + read -r -a array <<< "$@" + max=${array[0]} + min=${array[0]} + + for i in ${array[*]}; do + (( i > max )) && max=$i + (( i < min )) && min=$i + done + echo "$min"-"$max" +} + +if qsvc guivm-vnc; then + GUI_DOMID="$(qubesdb-read /qubes-gui-domain-xid 2>/dev/null)" + MEM_MIN="$(qubesdb-read /qubes-gui-videoram-min 2>/dev/null)" + MEM_OVERHEAD="$(qubesdb-read /qubes-gui-videoram-overhead 2>/dev/null)" + : "${MEM_MIN:=0}" + : "${MEM_OVERHEAD:=$((2560 * 1600 * 4 / 1024))}" + + MEM=$((MEM + MEM_OVERHEAD)) + if [ $MEM -lt $MEM_MIN ]; then + MEM=$MEM_MIN + fi + + DUMMY_MAX_CLOCK=300 + PREFERRED_HSYNC=50 + DEPTH=24 + + HSYNC=() + VSYNC=() + MODELINES=() + RESOLUTIONS="320x240 + 640x480 + 800x600 + 1024x768 + 1152x864 + 1280x1024 + 1400x1050 + 1600x1200 + 2048x1536 + 800x480 + 1366x768 + 1440x900 + 1600x1024 + 1680x1050 + 1920x1200 + 2560x1600 + 1280x720 + 1920x1080" + + for RES in ${RESOLUTIONS[*]}; + do + W=${RES%x*} + H=${RES#*x} + HTOTAL=$((W+3)) + VTOTAL=$((H+3)) + CLOCK=$((PREFERRED_HSYNC*HTOTAL/1000)) + if [ $CLOCK -gt $DUMMY_MAX_CLOCK ]; then CLOCK=$DUMMY_MAX_CLOCK ; fi + MODELINE="$CLOCK $W $((W+1)) $((W+2)) $HTOTAL $H $((H+1)) $((H+2)) $VTOTAL" + + HSYNC_START=$((CLOCK*1000/HTOTAL)) + HSYNC_END=$((HSYNC_START+1)) + + VREFR_START=$((CLOCK*1000000/HTOTAL/VTOTAL)) + VREFR_END=$((VREFR_START+1)) + + HSYNC+=("$HSYNC_START" "$HSYNC_END") + VSYNC+=("$VREFR_START" "$VREFR_END") + MODELINES+=(" Modeline \"QB$RES\" $MODELINE") + done + + ALL_MODELINES="$(printf '%s\\n' "${MODELINES[@]}")" + MIN_MAX_HSYNC="$(array_min_max "${HSYNC[@]}")" + MIN_MAX_VSYNC="$(array_min_max "${VSYNC[@]}")" + + sed -e s/%MEM%/$MEM/ \ + -e s/%GUI_DOMID%/"$GUI_DOMID"/ \ + -e s/%DEPTH%/$DEPTH/ \ + -e s/%MODELINES%/"$ALL_MODELINES"/ \ + -e s/%MIN_MAX_HSYNC%/"$MIN_MAX_HSYNC"/ \ + -e s/%MIN_MAX_VSYNC%/"$MIN_MAX_VSYNC"/ \ + < /etc/X11/xorg-qubes-x11vnc.conf.template > /etc/X11/xorg.conf + + # 2**30 + echo 1073741824 > /sys/module/xen_gntalloc/parameters/limit +fi diff --git a/appvm-scripts/usrbin/qubes-run-xorg b/appvm-scripts/usrbin/qubes-run-xorg index 74b38079..a9ce3999 100755 --- a/appvm-scripts/usrbin/qubes-run-xorg +++ b/appvm-scripts/usrbin/qubes-run-xorg @@ -24,6 +24,8 @@ # shellcheck disable=SC1091 . /usr/lib/qubes/init/functions +## This script is triggered by qubes-gui-agent systemd service. + #expects W, H, MEM and DEPTH env vars to be set by invoker DUMMY_MAX_CLOCK=300 #hardcoded in dummy_drv PREFERRED_HSYNC=50 @@ -107,7 +109,6 @@ fi if qsvc guivm-gui-agent; then DISPLAY_XORG=:1 - DISPLAY_XEPHYR=:0 # Create Xorg. Xephyr will be started using qubes-start-xephyr later. exec runuser -u "$DEFAULT_USER" -- /bin/sh -l -c "exec $XORG $DISPLAY_XORG -nolisten tcp vt07 -wr -config xorg-qubes.conf > ~/.xorg-errors 2>&1" & diff --git a/debian/control b/debian/control index 8077d504..0eb18dd2 100644 --- a/debian/control +++ b/debian/control @@ -111,3 +111,12 @@ Depends: ${misc:Depends} Description: XFCE desktop support for Qubes VM XFCE desktop support for Qubes VM + +Package: qubes-gui-vnc +Architecture: any +Depends: + x11vnc + ${shlibs:Depends}, + ${misc:Depends} +Description: Remote GuiVM support using VNC + Remote GuiVM support using VNC diff --git a/debian/qubes-gui-vnc.install b/debian/qubes-gui-vnc.install new file mode 100644 index 00000000..c6a00d73 --- /dev/null +++ b/debian/qubes-gui-vnc.install @@ -0,0 +1,4 @@ +usr/bin/qubes-run-x11vnc-pre +usr/bin/qubes-run-x11vnc +etc/X11/xorg-qubes-x11vnc.conf.template +etc/systemd/system/lightdm.service.d/qubes-guivm-vnc.conf diff --git a/rpm_spec/gui-agent.spec.in b/rpm_spec/gui-agent.spec.in index ed5bd15d..37ffef77 100644 --- a/rpm_spec/gui-agent.spec.in +++ b/rpm_spec/gui-agent.spec.in @@ -94,6 +94,13 @@ Summary: XFCE desktop support for Qubes VM %description xfce XFCE desktop support for Qubes VM +%package -n qubes-gui-vnc +Summary: Remote GuiVM support using VNC +Requires: x11vnc + +%description -n qubes-gui-vnc +Remote GuiVM support using VNC + %description The Qubes GUI agent that needs to be installed in VM in order to provide the Qubes fancy GUI. @@ -198,5 +205,12 @@ rm -f %{name}-%{version} %files xfce /etc/X11/xinit/xinitrc.d/60xfce-desktop.sh +%files -n qubes-gui-vnc +#/lib/systemd/system/qubes-gui-vncserver.service +%attr(0644,root,root) /etc/X11/xorg-qubes-x11vnc.conf.template +%attr(0644,root,root) /etc/systemd/system/lightdm.service.d/qubes-guivm-vnc.conf +/usr/bin/qubes-run-x11vnc-pre +/usr/bin/qubes-run-x11vnc + %changelog @CHANGELOG@