Skip to content

Commit

Permalink
Implement qrexec-based connection to updates proxy
Browse files Browse the repository at this point in the history
Configure package manager to use 127.0.0.1:8082 as proxy instead of
"magic" IP intercepted later. The listen on this port and whenever
new connection arrives, spawn qubes.UpdatesProxy service call (to
default target domain - subject to configuration in dom0) and connect
its stdin/out to the local TCP connection. This part use systemd.socket
unit in case of systemd, and ncat --exec otherwise.

On the other end - in target domain - simply pass stdin/out to updates
proxy (tinyproxy) running locally.

It's important to _not_ configure the same VM to both be updates proxy and
use it. In practice such configuration makes little sense - if VM can
access network (which is required to run updates proxy), package manager
can use it directly. Even if this network access is through some
VPN/Tor. If a single VM would be configured as both proxy provider and
proxy user, connection would loop back to itself. Because of this, proxy
connection redirection (to qrexec service) is disabled when the same VM
also run updates proxy.

Fixes QubesOS/qubes-issues#1854
  • Loading branch information
marmarek committed May 26, 2017
1 parent f9d6ff8 commit b49ae50
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 2 deletions.
3 changes: 3 additions & 0 deletions Makefile
Expand Up @@ -119,6 +119,7 @@ install-systemd: install-init
install -d $(DESTDIR)$(SYSLIBDIR)/systemd/system{,-preset} $(DESTDIR)$(LIBDIR)/qubes/init $(DESTDIR)$(SYSLIBDIR)/modules-load.d
install -m 0644 vm-systemd/qubes-*.service $(DESTDIR)$(SYSLIBDIR)/systemd/system/
install -m 0644 vm-systemd/qubes-*.timer $(DESTDIR)$(SYSLIBDIR)/systemd/system/
install -m 0644 vm-systemd/qubes-*.socket $(DESTDIR)$(SYSLIBDIR)/systemd/system/
install -m 0644 vm-systemd/75-qubes-vm.preset $(DESTDIR)$(SYSLIBDIR)/systemd/system-preset/
install -m 0644 vm-systemd/qubes-core.conf $(DESTDIR)$(SYSLIBDIR)/modules-load.d/
install -m 0644 vm-systemd/qubes-misc.conf $(DESTDIR)$(SYSLIBDIR)/modules-load.d/
Expand All @@ -136,6 +137,7 @@ install-sysvinit: install-init
install vm-init.d/qubes-qrexec-agent $(DESTDIR)/etc/init.d/
install vm-init.d/qubes-updates-proxy $(DESTDIR)/etc/init.d/
install vm-init.d/qubes-dvm $(DESTDIR)/etc/init.d/
install vm-init.d/qubes-updates-proxy-forwarder $(DESTDIR)/etc/init.d/
install -D vm-init.d/qubes-core.modules $(DESTDIR)/etc/sysconfig/modules/qubes-core.modules
install -D vm-init.d/qubes-misc.modules $(DESTDIR)/etc/sysconfig/modules/qubes-misc.modules
install network/qubes-iptables $(DESTDIR)/etc/init.d/
Expand Down Expand Up @@ -268,6 +270,7 @@ install-common:
install -m 0755 qubes-rpc/qubes.InstallUpdatesGUI $(DESTDIR)/etc/qubes-rpc
install -m 0755 qubes-rpc/qubes.ResizeDisk $(DESTDIR)/etc/qubes-rpc
install -m 0755 qubes-rpc/qubes.StartApp $(DESTDIR)/etc/qubes-rpc
install -m 0755 qubes-rpc/qubes.UpdatesProxy $(DESTDIR)/etc/qubes-rpc

install -d $(DESTDIR)/etc/qubes/suspend-pre.d
install -m 0644 qubes-rpc/suspend-pre.README $(DESTDIR)/etc/qubes/suspend-pre.d/README
Expand Down
3 changes: 3 additions & 0 deletions debian/qubes-core-agent.install
Expand Up @@ -30,6 +30,7 @@ etc/qubes-rpc/qubes.SuspendPostAll
etc/qubes-rpc/qubes.SuspendPre
etc/qubes-rpc/qubes.SuspendPreAll
etc/qubes-rpc/qubes.SyncNtpClock
etc/qubes-rpc/qubes.UpdatesProxy
etc/qubes-rpc/qubes.VMShell
etc/qubes-rpc/qubes.WaitForSession
etc/qubes-suspend-module-blacklist
Expand Down Expand Up @@ -83,6 +84,8 @@ lib/systemd/system/qubes-sysinit.service
lib/systemd/system/qubes-update-check.service
lib/systemd/system/qubes-update-check.timer
lib/systemd/system/qubes-updates-proxy.service
lib/systemd/system/qubes-updates-proxy-forwarder@.service
lib/systemd/system/qubes-updates-proxy-forwarder.socket
lib/systemd/system/systemd-random-seed.service.d/30_qubes.conf
lib/systemd/system/tinyproxy.service.d/30_not_needed_in_qubes_by_default.conf
lib/systemd/system/tmp.mount.d/30_qubes.conf
Expand Down
2 changes: 1 addition & 1 deletion network/update-proxy-configs
Expand Up @@ -75,7 +75,7 @@ EOF

# Determine whether the proxy should be used
if qsvc yum-proxy-setup || qsvc updates-proxy-setup ; then
PROXY_ADDR="http://10.137.255.254:8082/"
PROXY_ADDR="http://127.0.0.1:8082/"
PROXY_CONF_ENTRY="proxy=$PROXY_ADDR"
else
PROXY_ADDR=""
Expand Down
2 changes: 2 additions & 0 deletions qubes-rpc/qubes.UpdatesProxy
@@ -0,0 +1,2 @@
#!/bin/sh
exec nc localhost 8082
7 changes: 6 additions & 1 deletion rpm_spec/core-vm.spec
Expand Up @@ -20,7 +20,7 @@
#
#

%define qubes_services qubes-core qubes-core-netvm qubes-core-early qubes-firewall qubes-iptables qubes-updates-proxy qubes-qrexec-agent qubes-dvm
%define qubes_services qubes-core qubes-core-netvm qubes-core-early qubes-firewall qubes-iptables qubes-updates-proxy qubes-qrexec-agent qubes-dvm qubes-updates-proxy-forwarder
%define qubes_preset_file 75-qubes-vm.preset

%{!?version: %define version %(cat version)}
Expand Down Expand Up @@ -124,6 +124,7 @@ Conflicts: firewalld
Requires: xdg-utils
Requires: ethtool
Requires: tinyproxy
Requires: nmap-ncat
Requires: ntpdate
Requires: net-tools
Requires: qubes-utils >= 3.1.3
Expand Down Expand Up @@ -440,6 +441,7 @@ rm -f %{name}-%{version}
%config(noreplace) /etc/qubes-rpc/qubes.InstallUpdatesGUI
%config(noreplace) /etc/qubes-rpc/qubes.ResizeDisk
%config(noreplace) /etc/qubes-rpc/qubes.StartApp
%config(noreplace) /etc/qubes-rpc/qubes.UpdatesProxy
%dir /etc/qubes/autostart
/etc/qubes/autostart/README.txt
%config /etc/qubes/autostart/*.desktop.d/30_qubes.conf
Expand Down Expand Up @@ -576,6 +578,7 @@ The Qubes core startup configuration for SysV init (or upstart).
/etc/init.d/qubes-iptables
/etc/init.d/qubes-updates-proxy
/etc/init.d/qubes-qrexec-agent
/etc/init.d/qubes-updates-proxy-forwarder
/etc/sysconfig/modules/qubes-core.modules
/etc/sysconfig/modules/qubes-misc.modules

Expand Down Expand Up @@ -650,6 +653,8 @@ The Qubes core startup configuration for SystemD init.
/lib/systemd/system/qubes-update-check.timer
/lib/systemd/system/qubes-updates-proxy.service
/lib/systemd/system/qubes-qrexec-agent.service
/lib/systemd/system/qubes-updates-proxy-forwarder@.service
/lib/systemd/system/qubes-updates-proxy-forwarder.socket
/lib/systemd/system-preset/%qubes_preset_file
/lib/modules-load.d/qubes-core.conf
/lib/modules-load.d/qubes-misc.conf
Expand Down
115 changes: 115 additions & 0 deletions vm-init.d/qubes-updates-proxy-forwarder
@@ -0,0 +1,115 @@
#!/bin/bash
#
# Updates proxy forwarder Startup script for the updates proxy forwarder
#
# chkconfig: 345 85 15
# description: forwards connection to updates proxy over Qubes RPC
#
# processname: ncat
# pidfile: /var/run/qubes-updates-proxy-forwarder.pid
#

# Source function library.
. /etc/rc.d/init.d/functions

# Source Qubes library.
. /usr/lib/qubes/init/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0

exec="/usr/bin/ncat"
prog=$(basename $exec)
pidfile="/var/run/qubes-updates-proxy-forwarder.pid"

[ -e /etc/sysconfig/qubes-updates-proxy-forwarder ] && . /etc/sysconfig/qubes-updates-proxy-forwarder

lockfile=/var/lock/subsys/qubes-updates-proxy-forwarder

start() {
have_qubesdb || return

if ! qsvc updates-proxy-setup ; then
# updates proxy configuration disabled
exit 0
fi

if qsvc qubes-updates-proxy ; then
# updates proxy running here too, avoid looping traffic back to itself
exit 0
fi

[ -x $exec ] || exit 5

echo -n $"Starting $prog (as Qubes updates proxy forwarder): "
start-stop-daemon \
--exec $exec \
--pidfile "$pidfile" \
--make-pidfile \
--background \
--start \
-- \
-k -l -e 'qrexec-client-vm $default qubes.UpdatesProxy'
retval=$?
echo
[ $retval -eq 0 ] && touch $lockfile
return $retval
}

stop() {
echo -n $"Stopping $prog: "
killproc -p $pidfile $prog
retval=$?
echo
[ $retval -eq 0 ] && rm -f $lockfile
return $retval
}

restart() {
stop
start
}

force_reload() {
restart
}

rh_status() {
status $prog
}

rh_status_q() {
rh_status >/dev/null 2>&1
}

case "$1" in
start)
rh_status_q && exit 0
$1
;;
stop)
rh_status_q || exit 0
$1
;;
restart)
$1
;;
force-reload)
force_reload
;;
status)
rh_status
;;
condrestart|try-restart)
rh_status_q || exit 0
restart
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|force-reload}"
exit 2
esac
exit $?

1 change: 1 addition & 0 deletions vm-systemd/75-qubes-vm.preset
Expand Up @@ -90,6 +90,7 @@ enable qubes-mount-dirs.service
enable qubes-firewall.service
enable qubes-meminfo-writer.service
enable qubes-iptables.service
enable qubes-updates-proxy-forwarder.socket
enable haveged.service
enable chronyd.service
enable xendriverdomain.service
14 changes: 14 additions & 0 deletions vm-systemd/qubes-updates-proxy-forwarder.socket
@@ -0,0 +1,14 @@
[Unit]
Description=Forward connection to updates proxy over Qubes RPC
ConditionPathExists=/var/run/qubes-service/updates-proxy-setup
# don't start the forwarder when updates proxy itself is also enabled here,
# otherwise it would most likely loop back to itself
ConditionPathExists=!/var/run/qubes-service/qubes-updates-proxy

[Socket]
ListenStream=127.0.0.1:8082
BindToDevice=lo
Accept=true

[Install]
WantedBy=multi-user.target
7 changes: 7 additions & 0 deletions vm-systemd/qubes-updates-proxy-forwarder@.service
@@ -0,0 +1,7 @@
[Unit]
Description=Forward connection to updates proxy over Qubes RPC

[Service]
ExecStart=/usr/bin/qrexec-client-vm '' qubes.UpdatesProxy
StandardInput=socket
StandardOutput=inherit

2 comments on commit b49ae50

@jpouellet
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The impact of "don't use updates proxy to avoid self-redirection" is on e.g. whonix-gw template?

@marmarek
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depends on configuration. But in standard scenario it will end in infinite loop of qrexec connections to the VM itself. Oh, currently qrexec (vchan to be precise) does not support loopback connections, so it will fail instead.

Please sign in to comment.