From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from atuin.qyliss.net (localhost [IPv6:::1]) by atuin.qyliss.net (Postfix) with ESMTP id EFC6B18CD2; Fri, 28 Nov 2025 20:41:59 +0000 (UTC) Received: by atuin.qyliss.net (Postfix, from userid 993) id 100C818936; Fri, 28 Nov 2025 20:41:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on atuin.qyliss.net X-Spam-Level: X-Spam-Status: No, score=-0.8 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,DMARC_MISSING,RCVD_IN_DNSWL_LOW,SPF_HELO_PASS autolearn=unavailable autolearn_force=no version=4.0.1 Received: from fhigh-b2-smtp.messagingengine.com (fhigh-b2-smtp.messagingengine.com [202.12.124.153]) by atuin.qyliss.net (Postfix) with ESMTPS id 76FCC1892F for ; Fri, 28 Nov 2025 20:41:56 +0000 (UTC) Received: from phl-compute-04.internal (phl-compute-04.internal [10.202.2.44]) by mailfhigh.stl.internal (Postfix) with ESMTP id ACC127A03EF; Fri, 28 Nov 2025 15:41:52 -0500 (EST) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-04.internal (MEProxy); Fri, 28 Nov 2025 15:41:52 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=alyssa.is; h=cc :cc:content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm3; t=1764362512; x=1764448912; bh=J2AiA1dAq5 wY/MARC0YXjRZJjASD7qwtX9BCkdBNLZk=; b=m4adPHFbBE4IwIL/4LwR/5CLu+ X3N1yLdPwWyLqs0rmNtD1xe0J3ZxOuNXQdu7I7FpISY3dAIVL5grw8tkaLZY6Abd ZL0pjdxlyItM3wdNU/M6wBSxsapuonRgiIG+zgDE3xhaI8RGW1KSKd+e+OfHyarc beAh0mPB0zS80mr0EhP4AM8r3s1hNlD/4byatkcY4ZLgJ13rGg4aEdc4M33qiQVn LGMPgZZhcWobH0E29ahBMM7qM+sj/+A0RY6V3caT/g2qAIG8iDBrsGVT2p7Rp88m G48MtvxpJpTiKNDdx0ztvNjyESCN5IVWximBwXNi8ghMf8UZ6qVxbQcZ7lyQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t= 1764362512; x=1764448912; bh=J2AiA1dAq5wY/MARC0YXjRZJjASD7qwtX9B CkdBNLZk=; b=QCoJeGaXB8so2HPKCt6avLKRSmILnT0KTxB76gypNGky+8uY1iF mq30LLwKOk6wjOwPIk11WzWBXcZoRrKWSFnAUN4r8EHWITlzDgDjK9o7Ybs9brIm k/KY8YJhdAtZH3JL/sQc7W1YRojIpAhAJpg5db4QNfKOMzQeGmH7p8yUlWb5RrBI yVpJtOx/HGS/+7fASeJXkr2gjcA4sWrF1g+PBCiApgLg/qsbNrZqnFSeTAAp/DZS cn1EbmQUZYf4+k2vQvTAVUInSh9Lo4D3xO5WoJoor/F4joJZzs9NG11uCKkHmfCe oDoQMafMbzFlNYevOAlg12j1AE4l86exRfw== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdeggddvhedtkedvucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhephffvvefujghffffkgggtsehgtderredttddtnecuhfhrohhmpeetlhihshhsrgcu tfhoshhsuceohhhisegrlhihshhsrgdrihhsqeenucggtffrrghtthgvrhhnpeeiudffue eilefgtefgtddttdekkeehkefgheekudefveetgeefiefftedvteeuveenucevlhhushht vghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehhihesrghlhihsshgrrd hishdpnhgspghrtghpthhtohepvddpmhhouggvpehsmhhtphhouhhtpdhrtghpthhtohep uggvmhhiohgsvghnohhurhesghhmrghilhdrtghomhdprhgtphhtthhopeguvghvvghlse hsphgvtghtrhhumhdqohhsrdhorhhg X-ME-Proxy: Feedback-ID: i12284293:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Fri, 28 Nov 2025 15:41:51 -0500 (EST) Received: by fw12.qyliss.net (Postfix, from userid 1000) id 2F1B92DB2AF5; Fri, 28 Nov 2025 21:41:41 +0100 (CET) From: Alyssa Ross To: Demi Marie Obenour Subject: Re: [PATCH v5 11/13] Support updates via systemd-sysupdate In-Reply-To: References: <20251126-updates-v5-0-fd746748febd@gmail.com> <20251126-updates-v5-11-fd746748febd@gmail.com> <87zf86nuay.fsf@alyssa.is> Date: Fri, 28 Nov 2025 21:41:40 +0100 Message-ID: <87v7itopob.fsf@alyssa.is> MIME-Version: 1.0 Content-Type: multipart/signed; boundary="=-=-="; micalg=pgp-sha512; protocol="application/pgp-signature" Message-ID-Hash: WRAOB5NEXVHBW3NKIVF5J7XOOOM3DATS X-Message-ID-Hash: WRAOB5NEXVHBW3NKIVF5J7XOOOM3DATS X-MailFrom: hi@alyssa.is X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-devel.spectrum-os.org-0; header-match-devel.spectrum-os.org-1; header-match-devel.spectrum-os.org-2; header-match-devel.spectrum-os.org-3; header-match-devel.spectrum-os.org-4; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Spectrum OS Development X-Mailman-Version: 3.3.9 Precedence: list List-Id: Patches and low-level development discussion Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: --=-=-= Content-Type: text/plain Content-Transfer-Encoding: quoted-printable Demi Marie Obenour writes: > On 11/28/25 08:47, Alyssa Ross wrote: >> Demi Marie Obenour writes: >>=20 >>> diff --git a/host/rootfs/image/usr/bin/spectrum-update b/host/rootfs/im= age/usr/bin/spectrum-update >>> new file mode 100755 >>> index 0000000000000000000000000000000000000000..613b43570d0538fce20296c= cb1de2a6364e0df55 >>> --- /dev/null >>> +++ b/host/rootfs/image/usr/bin/spectrum-update >>> @@ -0,0 +1,92 @@ >>> +#!/bin/execlineb -WS1 >>> +# SPDX-License-Identifier: EUPL-1.2+ >>> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour >>> + >>> +if { mkdir -p -m 0700 /run/updater } >>> + >>> +# Take a global lock to avoid races. >>> +s6-setlock /run/update-lock >>> + >>> +foreground { redirfd -w 2 /dev/null rmdir -- $1 } >>> +if { umask 0077 mkdir -p -- $1 } >>> +cd $1 >>> +foreground { >>> + # If this exists already that is okay. >>> + foreground { redirfd -w 2 /dev/null btrfs subvolume create -- shared= } >>> + >>> + # Delete any stale temporary files. Delete any existing signature >>> + # files. If the VM is still running (it should not be), the VM might >>> + # have write access to the directory. However, updates-dir-check is >>> + # safe against that. >>> + if { updates-dir-check cleanup shared } >>> + >>> + if { >>> + foreground { >>> + # TODO: suppress only "subvolume does not exist" errors. >>> + redirfd -w 2 /dev/null >>> + btrfs subvolume delete snapshot >>> + } >>> + rm -f snapshot >>> + } >>> + >>> + backtick -E update_vm_id { >>> + backtick -E id_path { readlink /run/vm/by-name/sys.appvm-systemd-s= ysupdate } >>> + basename -- $id_path >>> + } >>> + >>> + # $fsdir is read-only to the guest, but read-write to the host. >>> + # Directories bind-mounted into it are read-write to the guest. >>> + # See etc/s6-linux-init/run-image/service/vhost-user-fs/template/run >>> + # for details. >>> + >>=20 >> This still refers to a non-existent variable. >>=20 >>> + # Set up /etc with what the VM needs. The VM will overlay this >>> + # on its own /etc. >>> + # >>> + # In the future, this should use a bind mount instead of copying >>> + # into a tmpfs. However, this would significantly complicate the >>> + # cleanup code. Deleting fs/etc would require undoing the bind >>> + # mounts instead of rm -rf. Once this code is in a separate mount >>> + # namespace, the copies should be replaced by bind mounts. >>> + if { >>> + if { rm -rf -- /run/vm/by-id/${update_vm_id}/fs/etc } >>> + umask 022 >>> + if { mkdir -p -- /run/vm/by-id/${update_vm_id}/fs/updates /run/vm/= by-id/${update_vm_id}/fs/etc/systemd } >>> + if { cp -R -- /etc/vm-sysupdate.d /etc/update-url /run/vm/by-id/${= update_vm_id}/fs/etc } >>> + cp -- /etc/systemd/import-pubring.gpg /run/vm/by-id/${update_vm_id= }/fs/etc/systemd >>> + } >>> + >>> + # If the directory is already mounted, unmount it. This prevents a >>> + # confusing error from mount. >>> + foreground { redirfd -w 2 /dev/null umount -- /run/vm/by-id/${update= _vm_id}/fs/updates } >>> + >>> + # Share the update directory with the VM. >>> + if { mount --bind -- shared /run/vm/by-id/${update_vm_id}/fs/updates= } >>> + >>> + # Start the update VM. >>> + if { vm-start $update_vm_id } >>> + >>> + # Wait for the VM to exit. >>> + # TODO: This is racy. If the update finishes before this code runs, >>> + # the s6-svwait call will fail. >>> + if { s6-svwait -D /run/service/vmm/instance/${update_vm_id} } >>> + >>> + # Remove the bind mount. >>> + if { umount -- /run/vm/by-id/${update_vm_id}/fs/updates } >>> + >>> + # Ensure that the VM cannot change the directory >>> + # while systemd-sysupdate is using it. >>> + if { btrfs subvolume snapshot -- shared snapshot } >>> + >>> + # Validate the update directory. Delete any stale temporary files. >>> + # Check that a signature file was downloaded. >>> + if { updates-dir-check check snapshot } >>> + >>> + unshare --mount >>> + if { mount --bind -o ro -- snapshot /run/updater } >>> + >>> + /usr/lib/systemd/systemd-sysupdate update >>=20 >> Why not just make a readonly snapshot? >> (btrfs subvolume snapshot -r) > > The checker will delete any temporary files it comes across, so it > needs write access. A snapshot is much heavier than a bind mount > and isn't automatically cleaned up. Okay, but why do we need to block systemd-sysupdate from writing to this directory, but not to anywhere else on the system? >>> diff --git a/vm/app/systemd-sysupdate/default.nix b/vm/app/systemd-sysu= pdate/default.nix >>> new file mode 100644 >>> index 0000000000000000000000000000000000000000..69be0bab500ea2ea6cb3b6d= 71edbf1a3e7bddbba >>> --- /dev/null >>> +++ b/vm/app/systemd-sysupdate/default.nix >>> @@ -0,0 +1,26 @@ >>> +# SPDX-License-Identifier: MIT >>> +# SPDX-FileCopyrightText: 2023 Alyssa Ross >>> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour >>> + >>> +import ../../../lib/call-package.nix ( >>> +{ callSpectrumPackage, curl, lib, src >>> +, runCommand, systemd, writeScript >>> +}: >>> + >>> +let >>> + downloadUpdate =3D builtins.path { >>> + name =3D "download-update"; >>> + path =3D ./download-update; >>> + }; >>=20 >> builtins.path is overkill here surely, as opposed to just writing >> ${./download-update} below? > > ${./download-update} includes the working directory in the Nix store > hash, which means that renaming your source tree forces an unnecessary > rebuild. builtins.path is the standard way to avoid this. Oh, I didn't realise it included the whole directory rather than just the file name. Very justified then. --=-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iHUEARYKAB0WIQQGoGac7QfI+H5ZtFCZddwkt31pFQUCaSoJBAAKCRCZddwkt31p FUyRAP9h6EV1sxxoqVlyOO9lg2dh9FAbarKt5COCv/49r6WtxgD+P0OlS3LvSFaf yEprOTOa8KrlAzZ+60bLBR866LMZ8gA= =ITN0 -----END PGP SIGNATURE----- --=-=-=--