Move network uplink setup to a separate service

Previously, network uplink (eth0) was configured in two places:
 - udev (asynchronously)
 - qubes-misc-post.service - at the very end of the boot process

This caused multiple issues:
1. Depending on udev event processing (non-deterministic), network
   uplink could be enabled too early, for example before setting up
   firewall.
2. Again depending on udev processing, it can be enabled quite late in
   the boot process, after network.target is up and services assume
   network already configured. This for example causes qubes-firewall to
   fail DNS queries.
3. If udev happen try to enable enable networking even earlier, it may
   happend before qubesdb-daemon is started, in which case network setup
   fill fail. For this case, there was network re-setup in
   qubes-misc-post service - much later in the boot.

Fix the above by placing network uplink setup in a dedicated
qubes-network-uplink@${INTERFACE}.service unit ordered after
network-pre.target and pulled in by udev based on vif device existence,
to handle also dynamic network attach/detach.
Then, create qubes-network-uplink.service unit waiting for appropriate
interface-specific unit (if one is expected!) and order it before
network.target.

QubesOS/qubes-issues#5576
This commit is contained in:
Marek Marczykowski-Górecki 2020-11-12 01:37:12 +01:00
parent e344dcc4c9
commit dd8de797e3
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
9 changed files with 64 additions and 12 deletions

View File

@ -11,9 +11,12 @@ etc/xen/scripts/vif-route-qubes
lib/systemd/system/qubes-firewall.service lib/systemd/system/qubes-firewall.service
lib/systemd/system/qubes-iptables.service lib/systemd/system/qubes-iptables.service
lib/systemd/system/qubes-network.service lib/systemd/system/qubes-network.service
lib/systemd/system/qubes-network-uplink.service
lib/systemd/system/qubes-network-uplink@.service
lib/systemd/system/qubes-updates-proxy.service lib/systemd/system/qubes-updates-proxy.service
usr/lib/qubes/init/network-proxy-setup.sh usr/lib/qubes/init/network-proxy-setup.sh
usr/lib/qubes/init/network-proxy-stop.sh usr/lib/qubes/init/network-proxy-stop.sh
usr/lib/qubes/init/network-uplink-wait.sh
usr/lib/qubes/init/qubes-iptables usr/lib/qubes/init/qubes-iptables
usr/lib/qubes/iptables-updates-proxy usr/lib/qubes/iptables-updates-proxy
usr/lib/qubes/qubes-setup-dnat-to-ns usr/lib/qubes/qubes-setup-dnat-to-ns

View File

@ -173,6 +173,14 @@ qubes_ip_change_hook() {
have_qubesdb || exit 0 have_qubesdb || exit 0
ACTION="$1"
INTERFACE="$2"
if [ -z "$INTERFACE" ]; then
echo "Missing INTERFACE argument" >&2
exit 1
fi
if [ -n "$INTERFACE" ]; then if [ -n "$INTERFACE" ]; then
if [ "$ACTION" == "add" ]; then if [ "$ACTION" == "add" ]; then
MAC="$(get_mac_from_iface "$INTERFACE")" MAC="$(get_mac_from_iface "$INTERFACE")"
@ -232,8 +240,16 @@ if [ -n "$INTERFACE" ]; then
fi fi
fi fi
elif [ "$ACTION" == "remove" ]; then elif [ "$ACTION" == "remove" ]; then
# make sure network is disabled, especially on shutdown, to prevent
# leaks when firewall will get stopped too
ip link set "$INTERFACE" down 2>/dev/null || :
# If exists, we delete NetworkManager configuration file to prevent duplicate entries # If exists, we delete NetworkManager configuration file to prevent duplicate entries
nm_config="/etc/NetworkManager/system-connections/qubes-uplink-$INTERFACE" nm_config="/etc/NetworkManager/system-connections/qubes-uplink-$INTERFACE"
rm -rf "$nm_config" rm -rf "$nm_config"
else
echo "Invalid action '$ACTION'" >&2
exit 1
fi fi
fi fi

View File

@ -1,5 +1,5 @@
# old udev has ENV{ID_NET_DRIVER} # old udev has ENV{ID_NET_DRIVER}
SUBSYSTEMS=="xen", KERNEL=="eth*", ACTION=="add", ENV{ID_NET_DRIVER}=="vif", RUN+="/usr/lib/qubes/setup-ip" SUBSYSTEMS=="xen", KERNEL=="eth*", ACTION=="add", ENV{ID_NET_DRIVER}=="vif", ENV{SYSTEMD_WANTS}+="qubes-network-uplink@%k.service"
SUBSYSTEMS=="net", KERNEL=="eth*", ACTION=="remove", ENV{ID_NET_DRIVER}=="vif", RUN+="/usr/lib/qubes/setup-ip" SUBSYSTEMS=="net", KERNEL=="eth*", ACTION=="remove", ENV{ID_NET_DRIVER}=="vif", ENV{SYSTEMD_WANTS}+="qubes-network-uplink@%k.service"
# new udev has DRIVERS # new udev has DRIVERS
SUBSYSTEMS=="xen", KERNEL=="eth*", ACTION=="add", DRIVERS=="vif", RUN+="/usr/lib/qubes/setup-ip" SUBSYSTEMS=="xen", KERNEL=="eth*", ACTION=="add", DRIVERS=="vif", ENV{SYSTEMD_WANTS}+="qubes-network-uplink@%k.service"

View File

@ -797,9 +797,12 @@ rm -f %{name}-%{version}
/lib/systemd/system/qubes-firewall.service /lib/systemd/system/qubes-firewall.service
/lib/systemd/system/qubes-iptables.service /lib/systemd/system/qubes-iptables.service
/lib/systemd/system/qubes-network.service /lib/systemd/system/qubes-network.service
/lib/systemd/system/qubes-network-uplink.service
/lib/systemd/system/qubes-network-uplink@.service
/lib/systemd/system/qubes-updates-proxy.service /lib/systemd/system/qubes-updates-proxy.service
/usr/lib/qubes/init/network-proxy-setup.sh /usr/lib/qubes/init/network-proxy-setup.sh
/usr/lib/qubes/init/network-proxy-stop.sh /usr/lib/qubes/init/network-proxy-stop.sh
/usr/lib/qubes/init/network-uplink-wait.sh
/usr/lib/qubes/init/qubes-iptables /usr/lib/qubes/init/qubes-iptables
/usr/lib/qubes/iptables-updates-proxy /usr/lib/qubes/iptables-updates-proxy
/usr/lib/qubes/qubes-setup-dnat-to-ns /usr/lib/qubes/qubes-setup-dnat-to-ns

View File

@ -91,6 +91,7 @@ enable qubes-update-check.timer
enable qubes-misc-post.service enable qubes-misc-post.service
enable qubes-updates-proxy.service enable qubes-updates-proxy.service
enable qubes-network.service enable qubes-network.service
enable qubes-network-uplink.service
enable qubes-qrexec-agent.service enable qubes-qrexec-agent.service
enable qubes-mount-dirs.service enable qubes-mount-dirs.service
enable qubes-rootfs-resize.service enable qubes-rootfs-resize.service

View File

@ -11,15 +11,6 @@ if [ -n "$(ls -A /usr/local/lib 2>/dev/null)" ] || \
ldconfig ldconfig
fi fi
# Set IP address again (besides action in udev rules); this is needed by
# DispVM (to override DispVM-template IP) and in case when qubes-ip was
# called by udev before loading evtchn kernel module - in which case
# qubesdb-read fails
QUBES_MANAGED_IFACE="$(get_qubes_managed_iface)"
if [ "x$QUBES_MANAGED_IFACE" != "x" ]; then
INTERFACE="$QUBES_MANAGED_IFACE" ACTION="add" /usr/lib/qubes/setup-ip
fi
if [ -x /rw/config/rc.local ] ; then if [ -x /rw/config/rc.local ] ; then
/rw/config/rc.local /rw/config/rc.local
fi fi

View File

@ -0,0 +1,16 @@
#!/bin/sh
# Source Qubes library.
# shellcheck source=init/functions
. /usr/lib/qubes/init/functions
# Setup IP address at specific time of system boot, instead of asynchronously
# by udev
QUBES_MANAGED_IFACE="$(get_qubes_managed_iface)"
if [ "x$QUBES_MANAGED_IFACE" != "x" ]; then
# systemd does not support conditional After= dependencies, nor a tool to
# just wait for the unit to be activated
# if the network interface is expected, use `systemctl start` to wait for
# it to be started - it would be started by udev (SYSTEMD_WANTS) anyway
systemctl start "qubes-network-uplink@$QUBES_MANAGED_IFACE.service"
fi

View File

@ -0,0 +1,11 @@
[Unit]
Description=Qubes network uplink wait
Before=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/lib/qubes/init/network-uplink-wait.sh
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,11 @@
[Unit]
Description=Qubes network uplink (%i) setup
After=network-pre.target qubes-iptables.service
After=sys-subsystem-net-devices-%i.device
BindsTo=sys-subsystem-net-devices-%i.device
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/lib/qubes/setup-ip add "%i"
ExecStop=/usr/lib/qubes/setup-ip remove "%i"