* [RFC 00/12] add support to build isar unprivileged
@ 2026-02-18 11:58 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 01/12] refactor bootstrap: store rootfs tar with user permissions 'Felix Moessbauer' via isar-users
` (12 more replies)
0 siblings, 13 replies; 19+ messages in thread
From: 'Felix Moessbauer' via isar-users @ 2026-02-18 11:58 UTC (permalink / raw)
To: isar-users; +Cc: quirin.gylstorff, Felix Moessbauer
Dear isar-users,
currently isar requires password-less sudo and an environment
where mounting file systems is possible. This has proven problematic
for security reasons, both when running in a privileged container or
locally.
To solve this, we implement fully rootless builds that rely on the
unshare syscall which allows us to avoid sudo and instead operate in
temporary kernel namespaces as a user that is just privileged within
that namespace. This comes with some challenges regarding the handling
of mounts (they are cleared when leaving the namespace), as well as
cross namespace deployments (the outer user might not be able to access
the inner data). For that, we rework the handling of mounts and artifact
passing to make it compatible with both chroot modes (schroot and
unshare).
The patches 1-10 align the file permissions of deployments and artifacts
to avoid the use of chown (which will not work anymore across uid
boundaries). In addition, helpers are introduced to perform privileged
operations, which simplifies the migration of existing layers.
The patches 11 and 12 introduce the unshare mode, which can be executed
as a normal user and does not require root. To enable this mode, set
ISAR_ROOTLESS = "1".
While the series is by far not complete yet, it already passes the DevTest
CI. Know issues are currently:
- no support for VM and container images
- unprivileged cleanup of the build/tmp dir is non trivial
- sporadic issues on partial rebuilds on rootfs_install_sstate_finalize
- interfaces between kas and isar need to be defined
Note, that this series can be tested on a custom kas-container build
provided in [1]. Hints how to migrate downstream layers are provided
in the API changelog.
[1] https://groups.google.com/g/kas-devel/c/NWQFCU2aUHg
Best regards,
Felix Moessbauer
Siemens AG
Felix Moessbauer (12):
refactor bootstrap: store rootfs tar with user permissions
deb-dl-dir: export without root privileges
download debs without locking
introduce wrappers for privileged execution
bootstrap: move cleanup trap to function
rootfs: rework sstate caching of rootfs artifact
rootfs_generate_initramfs: rework deployment to avoid chowning
wic: rework image deploy logic to deploy under correct user
use bitbake function to generate mounting scripts
apt-fetcher: prepare for chroot specific fetching
add support for fully rootless builds
apt-fetcher: implement support for unshare backend
Kconfig | 2 +-
RECIPE-API-CHANGELOG.md | 57 +++++
doc/user_manual.md | 2 +
meta/classes-global/base.bbclass | 93 ++++++++
meta/classes-recipe/deb-dl-dir.bbclass | 20 +-
meta/classes-recipe/dpkg-base.bbclass | 20 +-
meta/classes-recipe/dpkg-source.bbclass | 2 +-
meta/classes-recipe/dpkg.bbclass | 16 +-
.../image-account-extension.bbclass | 4 +-
.../image-locales-extension.bbclass | 13 +-
.../image-postproc-extension.bbclass | 30 +--
.../image-tools-extension.bbclass | 96 +++++++-
meta/classes-recipe/image.bbclass | 24 +-
meta/classes-recipe/imagetypes.bbclass | 47 ++--
.../imagetypes_container.bbclass | 26 +--
meta/classes-recipe/imagetypes_wic.bbclass | 12 +-
meta/classes-recipe/rootfs.bbclass | 221 ++++++++++--------
meta/classes-recipe/sbuild.bbclass | 37 ++-
meta/classes-recipe/sdk.bbclass | 23 +-
meta/classes-recipe/squashfs.bbclass | 2 +-
meta/classes/sbom.bbclass | 2 +-
meta/conf/bitbake.conf | 7 +-
meta/lib/aptsrc_fetcher.py | 90 ++++++-
.../isar-mmdebstrap/isar-mmdebstrap.inc | 47 ++--
.../sbuild-chroot/sbuild-chroot.inc | 24 +-
.../unittests/test_image_account_extension.py | 9 +-
26 files changed, 691 insertions(+), 235 deletions(-)
--
2.51.0
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260218115827.3947145-1-felix.moessbauer%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC 01/12] refactor bootstrap: store rootfs tar with user permissions
2026-02-18 11:58 [RFC 00/12] add support to build isar unprivileged 'Felix Moessbauer' via isar-users
@ 2026-02-18 11:58 ` 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 02/12] deb-dl-dir: export without root privileges 'Felix Moessbauer' via isar-users
` (11 subsequent siblings)
12 siblings, 0 replies; 19+ messages in thread
From: 'Felix Moessbauer' via isar-users @ 2026-02-18 11:58 UTC (permalink / raw)
To: isar-users; +Cc: quirin.gylstorff, Felix Moessbauer
As the mmdebstrap itself is executed as root, the generated rootfs will
also be owned by root when stored as file. To avoid this, we let
mmdebstrap emit the rootfs on stdout and write it to a file outside of
the sudo call.
Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com>
---
.../isar-mmdebstrap/isar-mmdebstrap.inc | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc b/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc
index 73fe9434..d5bbae70 100644
--- a/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc
+++ b/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc
@@ -240,11 +240,11 @@ do_bootstrap() {
${@get_apt_opts(d, '--aptopt')} \
${@get_distro_components_argument(d)} \
"${@get_distro_suite(d)}" \
- "${WORKDIR}/rootfs.tar.zst" \
- "$bootstrap_list"
+ - \
+ "$bootstrap_list" > ${WORKDIR}/rootfs.tar.zst
# Finalize bootstrap by setting the link in deploy
- sudo ln -Tfsr "${WORKDIR}/rootfs.tar.zst" "${DEPLOY_ISAR_BOOTSTRAP}.tar.zst"
+ ln -Tfsr "${WORKDIR}/rootfs.tar.zst" "${DEPLOY_ISAR_BOOTSTRAP}.tar.zst"
if [ "${ISAR_USE_CACHED_BASE_REPO}" != "1" ]; then
deb_dl_dir_export "${WORKDIR}/dl_dir" "${BOOTSTRAP_BASE_DISTRO}-${BASE_DISTRO_CODENAME}"
@@ -259,8 +259,7 @@ SSTATEPOSTINSTFUNCS += "bootstrap_sstate_finalize"
bootstrap_sstate_prepare() {
# this runs in SSTATE_BUILDDIR, which will be deleted automatically
- sudo cp -a "${WORKDIR}/rootfs.tar.zst" ./bootstrap.tar.zst
- sudo chown $(id -u):$(id -g) bootstrap.tar.zst
+ cp -a "${WORKDIR}/rootfs.tar.zst" ./bootstrap.tar.zst
}
bootstrap_sstate_finalize() {
@@ -268,8 +267,8 @@ bootstrap_sstate_finalize() {
# we should restore symlinks after using tar
if [ -f bootstrap.tar.zst ]; then
mv bootstrap.tar.zst "${WORKDIR}/rootfs.tar.zst"
- sudo ln -Tfsr "${WORKDIR}/rootfs.tar.zst" \
- "${DEPLOY_ISAR_BOOTSTRAP}.tar.zst"
+ ln -Tfsr "${WORKDIR}/rootfs.tar.zst" \
+ "${DEPLOY_ISAR_BOOTSTRAP}.tar.zst"
fi
}
--
2.51.0
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260218115827.3947145-2-felix.moessbauer%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC 02/12] deb-dl-dir: export without root privileges
2026-02-18 11:58 [RFC 00/12] add support to build isar unprivileged 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 01/12] refactor bootstrap: store rootfs tar with user permissions 'Felix Moessbauer' via isar-users
@ 2026-02-18 11:58 ` 'Felix Moessbauer' via isar-users
2026-02-18 14:01 ` 'Jan Kiszka' via isar-users
2026-02-18 11:58 ` [RFC 03/12] download debs without locking 'Felix Moessbauer' via isar-users
` (10 subsequent siblings)
12 siblings, 1 reply; 19+ messages in thread
From: 'Felix Moessbauer' via isar-users @ 2026-02-18 11:58 UTC (permalink / raw)
To: isar-users; +Cc: quirin.gylstorff, Felix Moessbauer
The archive is world readable, so we can access it without root
privileges. By that, the files in the download dir are also owned by the
calling user, making the additional chown obsolete.
Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com>
---
meta/classes-recipe/deb-dl-dir.bbclass | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/meta/classes-recipe/deb-dl-dir.bbclass b/meta/classes-recipe/deb-dl-dir.bbclass
index 7ebc3526..76c2435f 100644
--- a/meta/classes-recipe/deb-dl-dir.bbclass
+++ b/meta/classes-recipe/deb-dl-dir.bbclass
@@ -153,7 +153,7 @@ deb_dl_dir_export() {
isar_debs="$(${SCRIPTSDIR}/lockrun.py -r -f '${REPO_ISAR_DIR}/isar.lock' -c \
"find '${REPO_ISAR_DIR}/${DISTRO}' -name '*.deb' -print")"
- flock "${pc}".lock sudo -Es << 'EOSUDO'
+ flock "${pc}".lock /bin/bash -s << 'EOF'
set -e
printenv | grep -q BB_VERBOSE_LOGS && set -x
@@ -170,6 +170,5 @@ deb_dl_dir_export() {
ln -Pf "${p}" "${pc}" 2>/dev/null ||
cp -n "${p}" "${pc}"
done
- chown -R ${owner} "${pc}"
-EOSUDO
+EOF
}
--
2.51.0
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260218115827.3947145-3-felix.moessbauer%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC 03/12] download debs without locking
2026-02-18 11:58 [RFC 00/12] add support to build isar unprivileged 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 01/12] refactor bootstrap: store rootfs tar with user permissions 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 02/12] deb-dl-dir: export without root privileges 'Felix Moessbauer' via isar-users
@ 2026-02-18 11:58 ` 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 04/12] introduce wrappers for privileged execution 'Felix Moessbauer' via isar-users
` (9 subsequent siblings)
12 siblings, 0 replies; 19+ messages in thread
From: 'Felix Moessbauer' via isar-users @ 2026-02-18 11:58 UTC (permalink / raw)
To: isar-users; +Cc: quirin.gylstorff, Felix Moessbauer
As we are only downloading and we are the only one acting on the rootfs,
it is safe to not lock the apt cache. By that, we can avoid complex file
ownerships in the tree.
Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com>
---
meta/classes-recipe/deb-dl-dir.bbclass | 2 +-
meta/classes-recipe/dpkg-source.bbclass | 2 +-
meta/classes-recipe/image-locales-extension.bbclass | 2 +-
meta/classes-recipe/image-tools-extension.bbclass | 3 ++-
meta/classes-recipe/rootfs.bbclass | 10 +---------
meta/lib/aptsrc_fetcher.py | 2 +-
6 files changed, 7 insertions(+), 14 deletions(-)
diff --git a/meta/classes-recipe/deb-dl-dir.bbclass b/meta/classes-recipe/deb-dl-dir.bbclass
index 76c2435f..6675d48d 100644
--- a/meta/classes-recipe/deb-dl-dir.bbclass
+++ b/meta/classes-recipe/deb-dl-dir.bbclass
@@ -80,6 +80,7 @@ debsrc_download() {
--chdir "/deb-src/${rootfs_distro}/${src}" \
-- \
apt-get -o APT::Architecture=${DISTRO_ARCH} \
+ -oDebug::NoLocking=1 \
-o Dir="${rootfs}" -y --download-only \
--only-source source "${src}=${version}" \
|| echo "${src} ${version}" >> ${missing}
@@ -121,7 +122,6 @@ deb_dl_dir_import() {
# let our unprivileged user place downloaded packages in /var/cache/apt/archives/
sudo -Es << ' EOSUDO'
mkdir -p "${rootfs}"/var/cache/apt/archives/partial/
- touch "${rootfs}"/var/cache/apt/archives/lock
chown -R ${uid}:${gid} "${rootfs}"/var/cache/apt/archives/
EOSUDO
diff --git a/meta/classes-recipe/dpkg-source.bbclass b/meta/classes-recipe/dpkg-source.bbclass
index 1227da36..d0809477 100644
--- a/meta/classes-recipe/dpkg-source.bbclass
+++ b/meta/classes-recipe/dpkg-source.bbclass
@@ -77,7 +77,7 @@ do_fetch_common_source() {
schroot -r -c ${session_id} -d / -- \
sh -c '
cd /work
- apt-get -y --download-only --only-source -o Acquire::Source-Symlinks="false" source ${DEBIAN_SOURCE}'
+ apt-get -y --download-only --only-source -o Debug::NoLocking=1 -o Acquire::Source-Symlinks="false" source ${DEBIAN_SOURCE}'
schroot -e -c ${session_id}
remove_mounts
diff --git a/meta/classes-recipe/image-locales-extension.bbclass b/meta/classes-recipe/image-locales-extension.bbclass
index b6b07dba..9bff36ff 100644
--- a/meta/classes-recipe/image-locales-extension.bbclass
+++ b/meta/classes-recipe/image-locales-extension.bbclass
@@ -30,7 +30,7 @@ image_install_localepurge_download[weight] = "40"
image_install_localepurge_download[network] = "${TASK_USE_NETWORK_AND_SUDO}"
image_install_localepurge_download() {
sudo -E chroot '${ROOTFSDIR}' \
- /usr/bin/apt-get ${ROOTFS_APT_ARGS} --download-only localepurge
+ /usr/bin/apt-get ${ROOTFS_APT_ARGS} -oDebug::NoLocking=1 --download-only localepurge
}
ROOTFS_INSTALL_COMMAND += "image_install_localepurge_install"
diff --git a/meta/classes-recipe/image-tools-extension.bbclass b/meta/classes-recipe/image-tools-extension.bbclass
index b0f25a69..e88557f6 100644
--- a/meta/classes-recipe/image-tools-extension.bbclass
+++ b/meta/classes-recipe/image-tools-extension.bbclass
@@ -54,7 +54,8 @@ imager_run() {
apt-get update \
-o Dir::Etc::SourceList='sources.list.d/isar-apt.list' \
-o Dir::Etc::SourceParts='-' \
- -o APT::Get::List-Cleanup='0'
+ -o APT::Get::List-Cleanup='0' \
+ -o Debug::NoLocking=1
apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends -y \
--allow-unauthenticated --allow-downgrades --download-only install \
${local_install}"
diff --git a/meta/classes-recipe/rootfs.bbclass b/meta/classes-recipe/rootfs.bbclass
index 8485b32f..629dc666 100644
--- a/meta/classes-recipe/rootfs.bbclass
+++ b/meta/classes-recipe/rootfs.bbclass
@@ -340,18 +340,10 @@ rootfs_install_pkgs_download[progress] = "custom:rootfs_progress.PkgsDownloadPro
rootfs_install_pkgs_download[isar-apt-lock] = "release-after"
rootfs_install_pkgs_download[network] = "${TASK_USE_NETWORK}"
rootfs_install_pkgs_download() {
- mkdir -p "${WORKDIR}/dpkg"
-
- # Use our own dpkg lock files rather than those in the rootfs since we are not root
- # (this is safe as there are no concurrent apt/dpkg operations for that rootfs)
- touch "${WORKDIR}/dpkg/lock" "${WORKDIR}/dpkg/lock-frontend"
-
# download packages using apt in a non-privileged namespace
rootfs_cmd --bind "${ROOTFSDIR}/var/cache/apt/archives" /var/cache/apt/archives \
- --bind "${WORKDIR}/dpkg/lock" /var/lib/dpkg/lock \
- --bind "${WORKDIR}/dpkg/lock-frontend" /var/lib/dpkg/lock-frontend \
${ROOTFSDIR} \
- -- /usr/bin/apt-get ${ROOTFS_APT_ARGS} --download-only ${ROOTFS_PACKAGES}
+ -- /usr/bin/apt-get ${ROOTFS_APT_ARGS} -oDebug::NoLocking=1 --download-only ${ROOTFS_PACKAGES}
}
ROOTFS_INSTALL_COMMAND_BEFORE_EXPORT ??= ""
diff --git a/meta/lib/aptsrc_fetcher.py b/meta/lib/aptsrc_fetcher.py
index 041f5445..dfa784a9 100644
--- a/meta/lib/aptsrc_fetcher.py
+++ b/meta/lib/aptsrc_fetcher.py
@@ -41,7 +41,7 @@ class AptSrc(FetchMethod):
set -e
mkdir -p /downloads/{ud.localfile}
cd /downloads/{ud.localfile}
- apt-get -y --download-only --only-source source {ud.src_package}
+ apt-get -y -oDebug::NoLocking=1 --download-only --only-source source {ud.src_package}
'
''', d)
except (OSError, FetchError):
--
2.51.0
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260218115827.3947145-4-felix.moessbauer%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC 04/12] introduce wrappers for privileged execution
2026-02-18 11:58 [RFC 00/12] add support to build isar unprivileged 'Felix Moessbauer' via isar-users
` (2 preceding siblings ...)
2026-02-18 11:58 ` [RFC 03/12] download debs without locking 'Felix Moessbauer' via isar-users
@ 2026-02-18 11:58 ` 'Felix Moessbauer' via isar-users
2026-02-18 14:11 ` 'Jan Kiszka' via isar-users
2026-02-18 11:58 ` [RFC 05/12] bootstrap: move cleanup trap to function 'Felix Moessbauer' via isar-users
` (8 subsequent siblings)
12 siblings, 1 reply; 19+ messages in thread
From: 'Felix Moessbauer' via isar-users @ 2026-02-18 11:58 UTC (permalink / raw)
To: isar-users; +Cc: quirin.gylstorff, Felix Moessbauer
As a preparation to enable rootless builds, we introduce wrappers for
common cases of privileged command execution. The wrappers are defined
in the base class where later on the executor dispatching will be
implemented as well.
The wrappers are introduced throughout the whole codebase and downstream
layers are also encouraged to use them to increase compatibility with
upcoming API changes.
Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com>
---
RECIPE-API-CHANGELOG.md | 16 ++++
meta/classes-global/base.bbclass | 30 +++++++
meta/classes-recipe/deb-dl-dir.bbclass | 4 +-
meta/classes-recipe/dpkg-base.bbclass | 2 +-
meta/classes-recipe/dpkg.bbclass | 2 +-
.../image-account-extension.bbclass | 4 +-
.../image-locales-extension.bbclass | 4 +-
.../image-postproc-extension.bbclass | 30 +++----
meta/classes-recipe/image.bbclass | 14 +--
.../imagetypes_container.bbclass | 26 +++---
meta/classes-recipe/imagetypes_wic.bbclass | 4 +-
meta/classes-recipe/rootfs.bbclass | 88 +++++++++----------
meta/classes-recipe/sbuild.bbclass | 10 +--
meta/classes-recipe/sdk.bbclass | 14 +--
meta/classes/sbom.bbclass | 2 +-
.../isar-mmdebstrap/isar-mmdebstrap.inc | 12 +--
.../unittests/test_image_account_extension.py | 9 +-
17 files changed, 157 insertions(+), 114 deletions(-)
diff --git a/RECIPE-API-CHANGELOG.md b/RECIPE-API-CHANGELOG.md
index 0bad8a44..bc40a403 100644
--- a/RECIPE-API-CHANGELOG.md
+++ b/RECIPE-API-CHANGELOG.md
@@ -962,3 +962,19 @@ INSTALLER_UNATTENDED_ABORT_ENABLE = "1"
# Optional: set countdown timeout in seconds (default 5)
INSTALLER_UNATTENDED_ABORT_TIMEOUT = "5"
```
+
+### Execution of privileged commands
+
+When operations require higher privileges than those available to the build user,
+the following helper functions shall be used:
+
+**run_privileged**: Run a command as root while preserving the environment.
+
+**run_privileged_here**: Execute commands provided via stdin in a root shell.
+
+**run_in_chroot**: Run a command within a chroot environment. The first argument
+specifies the rootfs path.
+
+Using these helpers instead of direct `sudo` invocations centralizes platform-specific
+privileged execution logic in `base.bbclass`. Direct use of `sudo` is discouraged
+in downstream layers.
diff --git a/meta/classes-global/base.bbclass b/meta/classes-global/base.bbclass
index 6c788adb..16939f64 100644
--- a/meta/classes-global/base.bbclass
+++ b/meta/classes-global/base.bbclass
@@ -384,3 +384,33 @@ python deprecation_checking() {
deprecation_checking[vardepsexclude] += "MACHINE"
do_unpack[prefuncs] += "deprecation_checking"
+
+# Helpers for privileged execution. Only the non-underscore functions
+# shall be used outside of this class.
+
+def run_privileged_cmd(d):
+ cmd = 'sudo -E'
+ bb.debug(1, "privileged cmd: %s" % cmd)
+ return cmd
+
+RUN_PRIVILEGED_CMD := "${@run_privileged_cmd(d)}"
+
+run_privileged() {
+ ${RUN_PRIVILEGED_CMD} "$@"
+}
+
+run_privileged_here() {
+ ${RUN_PRIVILEGED_CMD} /bin/bash -s "$@"
+}
+
+# create a directory that is suitable to be the
+# parent of a rootfs
+create_chroot_parent_dir() {
+ mkdir -p "$@"
+}
+
+run_in_chroot() {
+ rootfs="$1"
+ shift
+ ${RUN_PRIVILEGED_CMD} chroot "$rootfs" "$@"
+}
diff --git a/meta/classes-recipe/deb-dl-dir.bbclass b/meta/classes-recipe/deb-dl-dir.bbclass
index 6675d48d..fc0cd915 100644
--- a/meta/classes-recipe/deb-dl-dir.bbclass
+++ b/meta/classes-recipe/deb-dl-dir.bbclass
@@ -110,7 +110,7 @@ dbg_pkgs_download() {
| grep "${DISTRO_ARCH}" \
| awk '!/Binary:/ {print $1}' \
| sort -u
- done | xargs -r sudo -E chroot ${rootfs} sh -c '/usr/bin/apt-get -y --download-only install "$@"' --
+ done | xargs -r run_in_chroot ${rootfs} sh -c '/usr/bin/apt-get -y --download-only install "$@"' --
}
deb_dl_dir_import() {
@@ -120,7 +120,7 @@ deb_dl_dir_import() {
export gid=$(id -g)
# let our unprivileged user place downloaded packages in /var/cache/apt/archives/
- sudo -Es << ' EOSUDO'
+ run_privileged_here << ' EOSUDO'
mkdir -p "${rootfs}"/var/cache/apt/archives/partial/
chown -R ${uid}:${gid} "${rootfs}"/var/cache/apt/archives/
EOSUDO
diff --git a/meta/classes-recipe/dpkg-base.bbclass b/meta/classes-recipe/dpkg-base.bbclass
index d8287e8d..df3dd1fd 100644
--- a/meta/classes-recipe/dpkg-base.bbclass
+++ b/meta/classes-recipe/dpkg-base.bbclass
@@ -161,7 +161,7 @@ def isar_export_build_settings(d):
dpkg_schroot_create_configs() {
schroot_create_configs
- sudo -s <<'EOSUDO'
+ run_privileged_here <<'EOSUDO'
sbuild_fstab="${SBUILD_CONF_DIR}/fstab"
fstab_isarapt="${WORKDIR}/isar-apt/${DISTRO}-${DISTRO_ARCH}/apt/${DISTRO} /isar-apt none rw,bind 0 0"
grep -qxF "${fstab_isarapt}" ${sbuild_fstab} || echo "${fstab_isarapt}" >> ${sbuild_fstab}
diff --git a/meta/classes-recipe/dpkg.bbclass b/meta/classes-recipe/dpkg.bbclass
index 8bb5adeb..8d7ff092 100644
--- a/meta/classes-recipe/dpkg.bbclass
+++ b/meta/classes-recipe/dpkg.bbclass
@@ -129,5 +129,5 @@ dpkg_runbuild() {
deb_dl_dir_export "${WORKDIR}/rootfs" "${distro}"
# Cleanup apt artifacts
- sudo rm -rf ${WORKDIR}/rootfs
+ run_privileged rm -rf ${WORKDIR}/rootfs
}
diff --git a/meta/classes-recipe/image-account-extension.bbclass b/meta/classes-recipe/image-account-extension.bbclass
index a8a3c7ff..bd721130 100644
--- a/meta/classes-recipe/image-account-extension.bbclass
+++ b/meta/classes-recipe/image-account-extension.bbclass
@@ -34,7 +34,7 @@ def image_create_groups(d: "DataSmart") -> None:
"""
entries = (d.getVar("GROUPS") or "").split()
rootfsdir = d.getVar("ROOTFSDIR")
- chroot = ["sudo", "-E", "chroot", rootfsdir]
+ chroot = run_privileged_cmd(d).split() + ["chroot", rootfsdir]
for entry in entries:
args = []
@@ -72,7 +72,7 @@ def image_create_users(d: "DataSmart") -> None:
entries = (d.getVar("USERS") or "").split()
rootfsdir = d.getVar("ROOTFSDIR")
- chroot = ["sudo", "-E", "chroot", rootfsdir]
+ chroot = run_privileged_cmd(d).split() + ["chroot", rootfsdir]
for entry in entries:
args = []
diff --git a/meta/classes-recipe/image-locales-extension.bbclass b/meta/classes-recipe/image-locales-extension.bbclass
index 9bff36ff..f4eb3718 100644
--- a/meta/classes-recipe/image-locales-extension.bbclass
+++ b/meta/classes-recipe/image-locales-extension.bbclass
@@ -29,7 +29,7 @@ ROOTFS_INSTALL_COMMAND_BEFORE_EXPORT += "image_install_localepurge_download"
image_install_localepurge_download[weight] = "40"
image_install_localepurge_download[network] = "${TASK_USE_NETWORK_AND_SUDO}"
image_install_localepurge_download() {
- sudo -E chroot '${ROOTFSDIR}' \
+ run_in_chroot '${ROOTFSDIR}' \
/usr/bin/apt-get ${ROOTFS_APT_ARGS} -oDebug::NoLocking=1 --download-only localepurge
}
@@ -60,7 +60,7 @@ ${@get_nopurge(d)}
__EOF__
# Install configuration into image:
- sudo -E -s <<'EOSUDO'
+ run_privileged_here <<'EOSUDO'
set -e
localepurge_state='i'
if chroot '${ROOTFSDIR}' dpkg -s localepurge 2>/dev/null >&2
diff --git a/meta/classes-recipe/image-postproc-extension.bbclass b/meta/classes-recipe/image-postproc-extension.bbclass
index 1aba2ec5..86db0f7b 100644
--- a/meta/classes-recipe/image-postproc-extension.bbclass
+++ b/meta/classes-recipe/image-postproc-extension.bbclass
@@ -17,19 +17,19 @@ update_etc_os_release() {
done
if [ -n "${OS_RELEASE_BUILD_ID}" ]; then
- sudo sed -i '/^BUILD_ID=.*/d' '${IMAGE_ROOTFS}/etc/os-release'
+ run_privileged sed -i '/^BUILD_ID=.*/d' '${IMAGE_ROOTFS}/etc/os-release'
echo "BUILD_ID=\"${OS_RELEASE_BUILD_ID}\"" | \
- sudo tee -a '${IMAGE_ROOTFS}/etc/os-release'
+ run_privileged tee -a '${IMAGE_ROOTFS}/etc/os-release'
fi
if [ -n "${OS_RELEASE_VARIANT}" ]; then
- sudo sed -i '/^VARIANT=.*/d' '${IMAGE_ROOTFS}/etc/os-release'
+ run_privileged sed -i '/^VARIANT=.*/d' '${IMAGE_ROOTFS}/etc/os-release'
echo "VARIANT=\"${OS_RELEASE_VARIANT}\"" | \
- sudo tee -a '${IMAGE_ROOTFS}/etc/os-release'
+ run_privileged tee -a '${IMAGE_ROOTFS}/etc/os-release'
fi
if [ -n "${OS_RELEASE_VARIANT_VERSION}" ]; then
- sudo sed -i '/^VARIANT_VERSION=.*/d' '${IMAGE_ROOTFS}/etc/os-release'
+ run_privileged sed -i '/^VARIANT_VERSION=.*/d' '${IMAGE_ROOTFS}/etc/os-release'
echo "VARIANT_VERSION=\"${OS_RELEASE_VARIANT_VERSION}\"" | \
- sudo tee -a '${IMAGE_ROOTFS}/etc/os-release'
+ run_privileged tee -a '${IMAGE_ROOTFS}/etc/os-release'
fi
}
@@ -37,11 +37,11 @@ ROOTFS_POSTPROCESS_COMMAND =+ "image_postprocess_configure"
image_postprocess_configure() {
# Configure root filesystem
if [ -n "${DISTRO_CONFIG_SCRIPT}" ]; then
- sudo install -m 755 "${WORKDIR}/${DISTRO_CONFIG_SCRIPT}" "${IMAGE_ROOTFS}"
+ run_privileged install -m 755 "${WORKDIR}/${DISTRO_CONFIG_SCRIPT}" "${IMAGE_ROOTFS}"
TARGET_DISTRO_CONFIG_SCRIPT="$(basename ${DISTRO_CONFIG_SCRIPT})"
- sudo chroot ${IMAGE_ROOTFS} "/$TARGET_DISTRO_CONFIG_SCRIPT" \
+ run_in_chroot ${IMAGE_ROOTFS} "/$TARGET_DISTRO_CONFIG_SCRIPT" \
"${MACHINE_SERIAL}" "${BAUDRATE_TTY}"
- sudo rm "${IMAGE_ROOTFS}/$TARGET_DISTRO_CONFIG_SCRIPT"
+ run_privileged rm "${IMAGE_ROOTFS}/$TARGET_DISTRO_CONFIG_SCRIPT"
fi
}
@@ -58,13 +58,13 @@ image_postprocess_machine_id() {
# systemd(1) takes care of recreating the machine-id on first boot
# for systemd < v247, set to empty string, else set to uninitialized
# (required if initramfs with ro root is used)
- SYSTEMD_VERSION=$( sudo chroot ${IMAGE_ROOTFS} dpkg-query --showformat='${source:Upstream-Version}' --show systemd || echo "0" )
+ SYSTEMD_VERSION=$( run_in_chroot ${IMAGE_ROOTFS} dpkg-query --showformat='${source:Upstream-Version}' --show systemd || echo "0" )
MACHINE_ID="uninitialized"
if dpkg --compare-versions "$SYSTEMD_VERSION" "lt" "247"; then
MACHINE_ID=""
fi
- echo "$MACHINE_ID" | sudo chroot ${IMAGE_ROOTFS} tee /etc/machine-id
- sudo rm -f '${IMAGE_ROOTFS}/var/lib/dbus/machine-id'
+ echo "$MACHINE_ID" | run_in_chroot ${IMAGE_ROOTFS} tee /etc/machine-id
+ run_privileged rm -f '${IMAGE_ROOTFS}/var/lib/dbus/machine-id'
}
ROOTFS_POSTPROCESS_COMMAND =+ "image_postprocess_sshd_key_regen"
@@ -82,13 +82,13 @@ image_postprocess_sshd_key_regen() {
ROOTFS_POSTPROCESS_COMMAND =+ "image_postprocess_disable_systemd_firstboot"
image_postprocess_disable_systemd_firstboot() {
- SYSTEMD_VERSION=$(sudo chroot '${ROOTFSDIR}' dpkg-query \
+ SYSTEMD_VERSION=$(run_in_chroot '${ROOTFSDIR}' dpkg-query \
--showformat='${source:Upstream-Version}' \
--show systemd || echo "0" )
if dpkg --compare-versions "$SYSTEMD_VERSION" "ge" "251"; then
- sudo chroot '${ROOTFSDIR}' systemctl mask systemd-firstboot
- if ! cmd_output=$(sudo chroot '${ROOTFSDIR}' systemd-firstboot \
+ run_in_chroot '${ROOTFSDIR}' systemctl mask systemd-firstboot
+ if ! cmd_output=$(run_in_chroot '${ROOTFSDIR}' systemd-firstboot \
--prompt --welcome=false </dev/null 2>/dev/null); then
bbwarn "Your image is not configured completely according to systemd-firstboot."
bbwarn "It prompted: \"${cmd_output}\""
diff --git a/meta/classes-recipe/image.bbclass b/meta/classes-recipe/image.bbclass
index afe6906e..ca449ec5 100644
--- a/meta/classes-recipe/image.bbclass
+++ b/meta/classes-recipe/image.bbclass
@@ -363,7 +363,7 @@ get_build_id() {
ROOTFS_CONFIGURE_COMMAND += "image_configure_fstab"
image_configure_fstab[weight] = "2"
image_configure_fstab() {
- sudo tee '${IMAGE_ROOTFS}/etc/fstab' << EOF
+ run_privileged tee '${IMAGE_ROOTFS}/etc/fstab' << EOF
# Begin /etc/fstab
proc /proc proc nosuid,noexec,nodev 0 0
sysfs /sys sysfs nosuid,noexec,nodev 0 0
@@ -391,7 +391,7 @@ do_copy_boot_files() {
kernel="$(realpath -q '${IMAGE_ROOTFS}'/boot/vmlinu[xz])"
fi
if [ -f "$kernel" ]; then
- sudo cat "$kernel" > "${DEPLOYDIR}/${KERNEL_IMAGE}"
+ run_privileged cat "$kernel" > "${DEPLOYDIR}/${KERNEL_IMAGE}"
fi
for file in ${DTB_FILES}; do
@@ -447,7 +447,7 @@ def apt_list_files(d):
IMAGE_LISTS = "${@ ' '.join(apt_list_files(d)) }"
do_rootfs_finalize() {
- sudo -s <<'EOSUDO'
+ run_privileged_here <<'EOSUDO'
set -e
if [ -e "${ROOTFSDIR}/chroot-setup.sh" ]; then
@@ -473,14 +473,14 @@ EOSUDO
# Sometimes qemu-user-static generates coredumps in chroot, move them
# to work temporary directory and inform user about it.
- for f in $(sudo find ${ROOTFSDIR} -type f -name *.core -exec file --mime-type {} \; | grep 'application/x-coredump' | cut -d: -f1); do
- sudo mv "${f}" "${WORKDIR}/temp/"
+ for f in $(run_privileged find ${ROOTFSDIR} -type f -name *.core -exec file --mime-type {} \; | grep 'application/x-coredump' | cut -d: -f1); do
+ run_privileged mv "${f}" "${WORKDIR}/temp/"
bbwarn "found core dump in rootfs, check it in ${WORKDIR}/temp/${f##*/}"
done
# Set same time-stamps to the newly generated file/folders in the
# rootfs image for the purpose of reproducible builds.
- sudo find ${ROOTFSDIR} -newermt "$(date -d@${SOURCE_DATE_EPOCH} '+%Y-%m-%d %H:%M:%S')" \
+ run_privileged find ${ROOTFSDIR} -newermt "$(date -d@${SOURCE_DATE_EPOCH} '+%Y-%m-%d %H:%M:%S')" \
-exec touch '{}' -h -d@${SOURCE_DATE_EPOCH} ';'
}
do_rootfs_finalize[network] = "${TASK_USE_SUDO}"
@@ -517,7 +517,7 @@ do_rootfs_quality_check() {
;;
esac
done
- found=$( sudo find ${ROOTFSDIR} -type f -newer $rootfs_install_stamp $args )
+ found=$( run_privileged find ${ROOTFSDIR} -type f -newer $rootfs_install_stamp $args )
if [ -n "$found" ]; then
bbwarn "Files changed after package install. The following files seem"
bbwarn "to have changed where they probably should not have."
diff --git a/meta/classes-recipe/imagetypes_container.bbclass b/meta/classes-recipe/imagetypes_container.bbclass
index ea15decf..b6cc4a14 100644
--- a/meta/classes-recipe/imagetypes_container.bbclass
+++ b/meta/classes-recipe/imagetypes_container.bbclass
@@ -37,38 +37,38 @@ do_containerize() {
# prepare OCI container image skeleton
bbdebug 1 "prepare OCI container image skeleton"
- sudo rm -rf "${oci_img_dir}" "${oci_img_dir}_unpacked"
- sudo umoci init --layout "${oci_img_dir}"
- sudo umoci new --image "${oci_img_dir}:${empty_tag}"
+ run_privileged rm -rf "${oci_img_dir}" "${oci_img_dir}_unpacked"
+ run_privileged umoci init --layout "${oci_img_dir}"
+ run_privileged umoci new --image "${oci_img_dir}:${empty_tag}"
if [ -n "${cmd}" ]; then
- sudo umoci config --image "${oci_img_dir}:${empty_tag}" \
+ run_privileged umoci config --image "${oci_img_dir}:${empty_tag}" \
--config.cmd="${cmd}"
fi
if [ -n "${entrypoint}" ]; then
- sudo umoci config --image "${oci_img_dir}:${empty_tag}" \
+ run_privileged umoci config --image "${oci_img_dir}:${empty_tag}" \
--config.entrypoint="${entrypoint}"
fi
if [ -n "${path}" ]; then
- sudo umoci config --image "${oci_img_dir}:${empty_tag}" \
+ run_privileged umoci config --image "${oci_img_dir}:${empty_tag}" \
--config.env="PATH=${path}"
fi
- sudo umoci unpack --image "${oci_img_dir}:${empty_tag}" \
+ run_privileged umoci unpack --image "${oci_img_dir}:${empty_tag}" \
"${oci_img_dir}_unpacked"
# add root filesystem as the flesh of the skeleton
- sudo cp --reflink=auto -a "${rootfs}"/* "${oci_img_dir}_unpacked/rootfs/"
+ run_privileged cp --reflink=auto -a "${rootfs}"/* "${oci_img_dir}_unpacked/rootfs/"
# clean-up temporary files
- sudo find "${oci_img_dir}_unpacked/rootfs/tmp" -mindepth 1 -delete
+ run_privileged find "${oci_img_dir}_unpacked/rootfs/tmp" -mindepth 1 -delete
# pack container image
bbdebug 1 "pack container image"
- sudo umoci repack --image "${oci_img_dir}:${tag}" \
+ run_privileged umoci repack --image "${oci_img_dir}:${tag}" \
"${oci_img_dir}_unpacked"
- sudo umoci remove --image "${oci_img_dir}:${empty_tag}"
- sudo rm -rf "${oci_img_dir}_unpacked"
+ run_privileged umoci remove --image "${oci_img_dir}:${empty_tag}"
+ run_privileged rm -rf "${oci_img_dir}_unpacked"
# no root needed anymore
- sudo chown --recursive $(id -u):$(id -g) "${oci_img_dir}"
+ run_privileged chown --recursive $(id -u):$(id -g) "${oci_img_dir}"
}
convert_container() {
diff --git a/meta/classes-recipe/imagetypes_wic.bbclass b/meta/classes-recipe/imagetypes_wic.bbclass
index 6b82add3..63974a3e 100644
--- a/meta/classes-recipe/imagetypes_wic.bbclass
+++ b/meta/classes-recipe/imagetypes_wic.bbclass
@@ -193,8 +193,8 @@ generate_wic_image() {
fi
EOIMAGER
- sudo chown -R $(stat -c "%U" ${LAYERDIR_core}) ${LAYERDIR_core} ${LAYERDIR_isar} ${SCRIPTSDIR} || true
- sudo chown -R $(id -u):$(id -g) "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.wic"*
+ run_privileged chown -R $(stat -c "%U" ${LAYERDIR_core}) ${LAYERDIR_core} ${LAYERDIR_isar} ${SCRIPTSDIR} || true
+ run_privileged chown -R $(id -u):$(id -g) "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.wic"*
rm -rf ${IMAGE_ROOTFS}/../pseudo
cat ${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.manifest \
diff --git a/meta/classes-recipe/rootfs.bbclass b/meta/classes-recipe/rootfs.bbclass
index 629dc666..b64a5bde 100644
--- a/meta/classes-recipe/rootfs.bbclass
+++ b/meta/classes-recipe/rootfs.bbclass
@@ -136,7 +136,7 @@ rootfs_cmd() {
rootfs_do_mounts[weight] = "3"
rootfs_do_mounts() {
- sudo -s <<'EOSUDO'
+ run_privileged_here <<'EOSUDO'
set -e
mountpoint -q '${ROOTFSDIR}/dev' || \
( mount -o bind,private /dev '${ROOTFSDIR}/dev' &&
@@ -182,7 +182,7 @@ EOSUDO
}
rootfs_do_umounts() {
- sudo -s <<'EOSUDO'
+ run_privileged_here <<'EOSUDO'
set -e
if mountpoint -q '${ROOTFSDIR}/isar-apt'; then
umount '${ROOTFSDIR}/isar-apt'
@@ -225,7 +225,7 @@ rootfs_do_qemu() {
if [ '${@repr(d.getVar('ROOTFS_ARCH') == d.getVar('HOST_ARCH'))}' = 'False' ]
then
test -e '${ROOTFSDIR}/usr/bin/qemu-${QEMU_ARCH}-static' || \
- sudo cp '/usr/bin/qemu-${QEMU_ARCH}-static' '${ROOTFSDIR}/usr/bin/qemu-${QEMU_ARCH}-static'
+ run_privileged cp '/usr/bin/qemu-${QEMU_ARCH}-static' '${ROOTFSDIR}/usr/bin/qemu-${QEMU_ARCH}-static'
fi
}
@@ -240,16 +240,16 @@ ROOTFS_EXTRA_IMPORTED := "${@rootfs_extra_import(d)}"
rootfs_prepare[weight] = "25"
rootfs_prepare(){
- sudo tar -xf "${BOOTSTRAP_SRC}" -C "${ROOTFSDIR}" --exclude="./dev/console"
+ run_privileged tar -xf "${BOOTSTRAP_SRC}" -C "${ROOTFSDIR}" --exclude="./dev/console"
# setup chroot
- sudo "${ROOTFSDIR}/chroot-setup.sh" "setup" "${ROOTFSDIR}"
+ run_privileged "${ROOTFSDIR}/chroot-setup.sh" "setup" "${ROOTFSDIR}"
}
ROOTFS_CONFIGURE_COMMAND += "rootfs_configure_isar_apt"
rootfs_configure_isar_apt[weight] = "2"
rootfs_configure_isar_apt() {
- sudo -s <<'EOSUDO'
+ run_privileged_here <<'EOSUDO'
set -e
mkdir -p '${ROOTFSDIR}/etc/apt/sources.list.d'
@@ -270,7 +270,7 @@ EOSUDO
ROOTFS_CONFIGURE_COMMAND += "rootfs_configure_apt"
rootfs_configure_apt[weight] = "2"
rootfs_configure_apt() {
- sudo -s <<'EOSUDO'
+ run_privileged_here <<'EOSUDO'
set -e
mkdir -p '${ROOTFSDIR}/etc/apt/apt.conf.d'
@@ -293,7 +293,7 @@ ROOTFS_CONFIGURE_COMMAND += "rootfs_disable_initrd_generation"
rootfs_disable_initrd_generation[weight] = "1"
rootfs_disable_initrd_generation() {
# fully disable initrd generation
- sudo -s <<'EOSUDO'
+ run_privileged_here <<'EOSUDO'
set -e
mkdir -p "${ROOTFSDIR}${ROOTFS_STUBS_DIR}"
@@ -310,7 +310,7 @@ rootfs_install_pkgs_update[weight] = "5"
rootfs_install_pkgs_update[isar-apt-lock] = "acquire-before"
rootfs_install_pkgs_update[network] = "${TASK_USE_NETWORK_AND_SUDO}"
rootfs_install_pkgs_update() {
- sudo -E chroot '${ROOTFSDIR}' /usr/bin/apt-get update \
+ run_in_chroot '${ROOTFSDIR}' /usr/bin/apt-get update \
-o Dir::Etc::SourceList="sources.list.d/isar-apt.list" \
-o Dir::Etc::SourceParts="-" \
-o APT::Get::List-Cleanup="0"
@@ -322,9 +322,9 @@ rootfs_install_resolvconf() {
if [ "${@repr(bb.utils.to_boolean(d.getVar('BB_NO_NETWORK')))}" != "True" ]
then
if [ -L "${ROOTFSDIR}/etc/resolv.conf" ]; then
- sudo unlink "${ROOTFSDIR}/etc/resolv.conf"
+ run_privileged unlink "${ROOTFSDIR}/etc/resolv.conf"
fi
- sudo cp -rL /etc/resolv.conf '${ROOTFSDIR}/etc'
+ run_privileged cp -rL /etc/resolv.conf '${ROOTFSDIR}/etc'
fi
}
@@ -358,7 +358,7 @@ rootfs_export_package_cache() {
ROOTFS_INSTALL_COMMAND += "${@ 'rootfs_install_clean_files' if (d.getVar('ROOTFS_CLEAN_FILES') or '').strip() else ''}"
rootfs_install_clean_files[weight] = "2"
rootfs_install_clean_files() {
- sudo -s <<'EOSUDO'
+ run_privileged_here <<'EOSUDO'
for clean_file in ${ROOTFS_CLEAN_FILES}; do
rm -f "${ROOTFSDIR}/$clean_file"
done
@@ -370,14 +370,14 @@ rootfs_install_pkgs_install[weight] = "8000"
rootfs_install_pkgs_install[progress] = "custom:rootfs_progress.PkgsInstallProgressHandler"
rootfs_install_pkgs_install[network] = "${TASK_USE_SUDO}"
rootfs_install_pkgs_install() {
- sudo -E chroot "${ROOTFSDIR}" \
+ run_in_chroot "${ROOTFSDIR}" \
/usr/bin/apt-get ${ROOTFS_APT_ARGS} ${ROOTFS_PACKAGES}
}
ROOTFS_INSTALL_COMMAND += "rootfs_restore_initrd_tooling"
rootfs_restore_initrd_tooling[weight] = "1"
rootfs_restore_initrd_tooling() {
- sudo -s <<'EOSUDO'
+ run_privileged_here <<'EOSUDO'
set -e
rm -f "${ROOTFSDIR}/etc/apt/apt.conf.d/50isar-stubs"
rm -rf "${ROOTFSDIR}${ROOTFS_STUBS_DIR}"
@@ -386,8 +386,8 @@ EOSUDO
ROOTFS_INSTALL_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'generate-initrd', '', 'rootfs_clear_initrd_symlinks', d)}"
rootfs_clear_initrd_symlinks() {
- sudo rm -f ${ROOTFSDIR}/initrd.img
- sudo rm -f ${ROOTFSDIR}/initrd.img.old
+ run_privileged rm -f ${ROOTFSDIR}/initrd.img
+ run_privileged rm -f ${ROOTFSDIR}/initrd.img.old
}
do_rootfs_install[root_cleandirs] = "${ROOTFSDIR}"
@@ -437,21 +437,21 @@ do_cache_deb_src[network] = "${TASK_USE_SUDO}"
do_cache_deb_src() {
if [ -e "${ROOTFSDIR}"/etc/resolv.conf ] ||
[ -h "${ROOTFSDIR}"/etc/resolv.conf ]; then
- sudo mv "${ROOTFSDIR}"/etc/resolv.conf "${ROOTFSDIR}"/etc/resolv.conf.isar
+ run_privileged mv "${ROOTFSDIR}"/etc/resolv.conf "${ROOTFSDIR}"/etc/resolv.conf.isar
fi
rootfs_install_resolvconf
# Note: ISAR updates the apt state information(apt-get update) only once during bootstrap and
# relies on that through out the build. Copy that state information instead of apt-get update
# which generates a new state from upstream.
- sudo tar -xf "${BOOTSTRAP_SRC}" ./var/lib/apt/lists --one-top-level="${ROOTFSDIR}"
+ run_privileged tar -xf "${BOOTSTRAP_SRC}" ./var/lib/apt/lists --one-top-level="${ROOTFSDIR}"
deb_dl_dir_import ${ROOTFSDIR} ${ROOTFS_BASE_DISTRO}-${BASE_DISTRO_CODENAME}
debsrc_download ${ROOTFSDIR} ${ROOTFS_BASE_DISTRO}-${BASE_DISTRO_CODENAME}
- sudo rm -f "${ROOTFSDIR}"/etc/resolv.conf
+ run_privileged rm -f "${ROOTFSDIR}"/etc/resolv.conf
if [ -e "${ROOTFSDIR}"/etc/resolv.conf.isar ] ||
[ -h "${ROOTFSDIR}"/etc/resolv.conf.isar ]; then
- sudo mv "${ROOTFSDIR}"/etc/resolv.conf.isar "${ROOTFSDIR}"/etc/resolv.conf
+ run_privileged mv "${ROOTFSDIR}"/etc/resolv.conf.isar "${ROOTFSDIR}"/etc/resolv.conf
fi
}
@@ -459,21 +459,21 @@ ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('BASE_REPO_FEATURES', 'cache
cache_dbg_pkgs() {
if [ -e "${ROOTFSDIR}"/etc/resolv.conf ] ||
[ -h "${ROOTFSDIR}"/etc/resolv.conf ]; then
- sudo mv "${ROOTFSDIR}"/etc/resolv.conf "${ROOTFSDIR}"/etc/resolv.conf.isar
+ run_privileged mv "${ROOTFSDIR}"/etc/resolv.conf "${ROOTFSDIR}"/etc/resolv.conf.isar
fi
rootfs_install_resolvconf
# Note: ISAR updates the apt state information(apt-get update) only once during bootstrap and
# relies on that through out the build. Copy that state information instead of apt-get update
# which generates a new state from upstream.
- sudo tar -xf "${BOOTSTRAP_SRC}" ./var/lib/apt/lists --one-top-level="${ROOTFSDIR}"
+ run_privileged tar -xf "${BOOTSTRAP_SRC}" ./var/lib/apt/lists --one-top-level="${ROOTFSDIR}"
deb_dl_dir_import ${ROOTFSDIR} ${ROOTFS_BASE_DISTRO}-${BASE_DISTRO_CODENAME}
dbg_pkgs_download ${ROOTFSDIR}
- sudo rm -f "${ROOTFSDIR}"/etc/resolv.conf
+ run_privileged rm -f "${ROOTFSDIR}"/etc/resolv.conf
if [ -e "${ROOTFSDIR}"/etc/resolv.conf.isar ] ||
[ -h "${ROOTFSDIR}"/etc/resolv.conf.isar ]; then
- sudo mv "${ROOTFSDIR}"/etc/resolv.conf.isar "${ROOTFSDIR}"/etc/resolv.conf
+ run_privileged mv "${ROOTFSDIR}"/etc/resolv.conf.isar "${ROOTFSDIR}"/etc/resolv.conf
fi
}
@@ -482,17 +482,17 @@ ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'generate
ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'clean-package-cache', 'rootfs_postprocess_clean_package_cache', '', d)}"
rootfs_postprocess_clean_package_cache() {
- sudo -E chroot '${ROOTFSDIR}' \
+ run_in_chroot '${ROOTFSDIR}' \
/usr/bin/apt-get clean
- sudo rm -rf "${ROOTFSDIR}/var/lib/apt/lists/"*
+ run_privileged rm -rf "${ROOTFSDIR}/var/lib/apt/lists/"*
# remove apt-cache folder itself (required in case rootfs is provided by sstate cache)
- sudo rm -rf "${ROOTFSDIR}/var/cache/apt/archives"
+ run_privileged rm -rf "${ROOTFSDIR}/var/cache/apt/archives"
}
ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'clean-log-files', 'rootfs_postprocess_clean_log_files', '', d)}"
rootfs_postprocess_clean_log_files() {
# Delete log files that are not owned by packages
- sudo -E chroot '${ROOTFSDIR}' \
+ run_in_chroot '${ROOTFSDIR}' \
/usr/bin/find /var/log/ -type f \
-exec sh -c '! dpkg -S {} > /dev/null 2>&1' ';' \
-exec rm -f {} ';'
@@ -501,32 +501,32 @@ rootfs_postprocess_clean_log_files() {
ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'clean-debconf-cache', 'rootfs_postprocess_clean_debconf_cache', '', d)}"
rootfs_postprocess_clean_debconf_cache() {
# Delete debconf cache files
- sudo rm -rf "${ROOTFSDIR}/var/cache/debconf/"*
+ run_privileged rm -rf "${ROOTFSDIR}/var/cache/debconf/"*
}
ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'clean-pycache', 'rootfs_postprocess_clean_pycache', '', d)}"
rootfs_postprocess_clean_pycache() {
- sudo find ${ROOTFSDIR}/usr -type f -name '*.pyc' -delete -print
- sudo find ${ROOTFSDIR}/usr -type d -name '__pycache__' -delete -print
+ run_privileged find ${ROOTFSDIR}/usr -type f -name '*.pyc' -delete -print
+ run_privileged find ${ROOTFSDIR}/usr -type d -name '__pycache__' -delete -print
}
ROOTFS_POSTPROCESS_COMMAND += "rootfs_postprocess_clean_ldconfig_cache"
rootfs_postprocess_clean_ldconfig_cache() {
# the ldconfig aux-cache is not portable and breaks reproducability
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=845034#49
- sudo rm -f ${ROOTFSDIR}/var/cache/ldconfig/aux-cache
+ run_privileged rm -f ${ROOTFSDIR}/var/cache/ldconfig/aux-cache
}
ROOTFS_POSTPROCESS_COMMAND += "rootfs_postprocess_clean_tmp"
rootfs_postprocess_clean_tmp() {
# /tmp is by definition non persistent across boots
- sudo rm -rf "${ROOTFSDIR}/tmp/"*
+ run_privileged rm -rf "${ROOTFSDIR}/tmp/"*
}
ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'generate-manifest', 'rootfs_generate_manifest', '', d)}"
rootfs_generate_manifest () {
mkdir -p ${ROOTFS_MANIFEST_DEPLOY_DIR}
- sudo -E chroot --userspec=$(id -u):$(id -g) '${ROOTFSDIR}' \
+ run_in_chroot '${ROOTFSDIR}' \
dpkg-query -W -f \
'${source:Package}|${source:Version}|${Package}:${Architecture}|${Version}\n' > \
'${ROOTFS_MANIFEST_DEPLOY_DIR}'/'${ROOTFS_PACKAGE_SUFFIX}'.manifest
@@ -542,7 +542,7 @@ rootfs_export_dpkg_status() {
ROOTFS_POSTPROCESS_COMMAND += "rootfs_cleanup_isar_apt"
rootfs_cleanup_isar_apt[weight] = "2"
rootfs_cleanup_isar_apt() {
- sudo -s <<'EOSUDO'
+ run_privileged_here <<'EOSUDO'
set -e
rm -f "${ROOTFSDIR}/etc/apt/sources.list.d/isar-apt.list"
rm -f "${ROOTFSDIR}/etc/apt/preferences.d/isar-apt"
@@ -553,7 +553,7 @@ EOSUDO
ROOTFS_POSTPROCESS_COMMAND += "${@'rootfs_cleanup_base_apt' if bb.utils.to_boolean(d.getVar('ISAR_USE_CACHED_BASE_REPO')) else ''}"
rootfs_cleanup_base_apt[weight] = "2"
rootfs_cleanup_base_apt() {
- sudo -s <<'EOSUDO'
+ run_privileged_here <<'EOSUDO'
set -e
rm -f "${ROOTFSDIR}/etc/apt/sources.list.d/"*base-apt.list
EOSUDO
@@ -561,12 +561,12 @@ EOSUDO
ROOTFS_POSTPROCESS_COMMAND += "${@bb.utils.contains('ROOTFS_FEATURES', 'populate-systemd-preset', 'image_postprocess_populate_systemd_preset', '', d)}"
image_postprocess_populate_systemd_preset() {
- SYSTEMD_INSTALLED=$(sudo chroot '${ROOTFSDIR}' dpkg-query \
+ SYSTEMD_INSTALLED=$(run_in_chroot '${ROOTFSDIR}' dpkg-query \
--showformat='${db:Status-Status}' \
--show systemd || echo "" )
if (test "$SYSTEMD_INSTALLED" = "installed"); then
- sudo chroot '${ROOTFSDIR}' systemctl preset-all --preset-mode="enable-only"
+ run_in_chroot '${ROOTFSDIR}' systemctl preset-all --preset-mode="enable-only"
fi
}
@@ -626,7 +626,7 @@ rootfs_generate_initramfs() {
mods_total="$(find ${ROOTFSDIR}/usr/lib/modules/$kernel_version -type f -name '*.ko*' | wc -l)"
echo "Total number of modules: $mods_total"
echo "Generating initrd for kernel version: $kernel_version"
- sudo -E chroot "${ROOTFSDIR}" sh -ec ' \
+ run_in_chroot "${ROOTFSDIR}" sh -ec ' \
${ROOTFS_INITRAMFS_GENERATOR_CMDLINE}; \
find /boot -name "initrd.img-$kernel_version*" -exec install --mode 0644 {} /isar-work/initrd.img \; \
'
@@ -663,11 +663,11 @@ rootfs_install_sstate_prepare() {
# tar --one-file-system will cross bind-mounts to the same filesystem,
# so we use some mount magic to prevent that
mkdir -p ${WORKDIR}/mnt/rootfs
- sudo mount -o bind,private '${WORKDIR}/rootfs' '${WORKDIR}/mnt/rootfs' -o ro
+ run_privileged mount -o bind,private '${WORKDIR}/rootfs' '${WORKDIR}/mnt/rootfs' -o ro
lopts="--one-file-system --exclude=var/cache/apt/archives"
- sudo tar -C ${WORKDIR}/mnt -cpSf rootfs.tar $lopts ${SSTATE_TAR_ATTR_FLAGS} rootfs
- sudo umount ${WORKDIR}/mnt/rootfs
- sudo chown $(id -u):$(id -g) rootfs.tar
+ run_privileged tar -C ${WORKDIR}/mnt -cpSf rootfs.tar $lopts ${SSTATE_TAR_ATTR_FLAGS} rootfs
+ run_privileged umount ${WORKDIR}/mnt/rootfs
+ run_privileged chown $(id -u):$(id -g) rootfs.tar
}
do_rootfs_install_sstate_prepare[lockfiles] = "${REPO_ISAR_DIR}/isar.lock"
@@ -676,7 +676,7 @@ rootfs_install_sstate_finalize() {
# - after building the rootfs, the tar won't be there, but we also don't need to unpack
# - after restoring from cache, there will be a tar which we unpack and then delete
if [ -f rootfs.tar ]; then
- sudo tar -C ${WORKDIR} -xpf rootfs.tar ${SSTATE_TAR_ATTR_FLAGS}
+ run_privileged tar -C ${WORKDIR} -xpf rootfs.tar ${SSTATE_TAR_ATTR_FLAGS}
rm rootfs.tar
fi
}
diff --git a/meta/classes-recipe/sbuild.bbclass b/meta/classes-recipe/sbuild.bbclass
index 1ab72aad..f0757891 100644
--- a/meta/classes-recipe/sbuild.bbclass
+++ b/meta/classes-recipe/sbuild.bbclass
@@ -20,7 +20,7 @@ SCHROOT_LOCKFILE = "/tmp/schroot.lock"
schroot_create_configs() {
mkdir -p "${TMPDIR}/schroot-overlay"
echo "Creating ${SCHROOT_CONF_FILE}"
- sudo -s <<'EOSUDO'
+ run_privileged_here <<'EOSUDO'
set -e
cat << EOF > "${SCHROOT_CONF_FILE}"
@@ -59,7 +59,7 @@ EOSUDO
schroot_delete_configs() {
(flock -x 9
set -e
- sudo -s <<'EOSUDO'
+ run_privileged_here <<'EOSUDO'
set -e
if [ -d "${SBUILD_CONF_DIR}" ]; then
echo "Removing ${SBUILD_CONF_DIR}"
@@ -101,7 +101,7 @@ sbuild_export() {
}
insert_mounts() {
- sudo -s <<'EOSUDO'
+ run_privileged_here <<'EOSUDO'
set -e
for mp in ${SCHROOT_MOUNTS}; do
FSTAB_LINE="${mp%%:*} ${mp#*:} none rw,bind,private 0 0"
@@ -112,7 +112,7 @@ EOSUDO
}
remove_mounts() {
- sudo -s <<'EOSUDO'
+ run_privileged_here <<'EOSUDO'
set -e
for mp in ${SCHROOT_MOUNTS}; do
FSTAB_LINE="${mp%%:*} ${mp#*:} none rw,bind,private 0 0"
@@ -123,7 +123,7 @@ EOSUDO
schroot_configure_ccache() {
mkdir -p "${CCACHE_DIR}"
- sudo -s <<'EOSUDO'
+ run_privileged_here <<'EOSUDO'
set -e
sbuild_fstab="${SBUILD_CONF_DIR}/fstab"
diff --git a/meta/classes-recipe/sdk.bbclass b/meta/classes-recipe/sdk.bbclass
index 17b56bcf..074f5ef8 100644
--- a/meta/classes-recipe/sdk.bbclass
+++ b/meta/classes-recipe/sdk.bbclass
@@ -69,12 +69,12 @@ ROOTFS_POSTPROCESS_COMMAND:remove = "${@'rootfs_cleanup_isar_apt' if bb.utils.to
ROOTFS_CONFIGURE_COMMAND:append:class-sdk = " ${@'rootfs_configure_isar_apt_dir' if bb.utils.to_boolean(d.getVar('SDK_INCLUDE_ISAR_APT')) else ''}"
rootfs_configure_isar_apt_dir() {
# Copy isar-apt instead of mounting:
- sudo cp -Trpfx --reflink=auto ${REPO_ISAR_DIR}/${DISTRO} ${ROOTFSDIR}/isar-apt
+ run_privileged cp -Trpfx --reflink=auto ${REPO_ISAR_DIR}/${DISTRO} ${ROOTFSDIR}/isar-apt
}
ROOTFS_POSTPROCESS_COMMAND:prepend:class-sdk = "sdkchroot_configscript "
sdkchroot_configscript () {
- sudo chroot ${ROOTFSDIR} /configscript.sh ${DISTRO_ARCH}
+ run_in_chroot ${ROOTFSDIR} /configscript.sh ${DISTRO_ARCH}
}
ROOTFS_POSTPROCESS_COMMAND:append:class-sdk = " sdkchroot_finalize"
@@ -83,7 +83,7 @@ sdkchroot_finalize() {
rootfs_do_umounts
# Remove setup scripts
- sudo rm -f ${ROOTFSDIR}/chroot-setup.sh ${ROOTFSDIR}/configscript.sh
+ run_privileged rm -f ${ROOTFSDIR}/chroot-setup.sh ${ROOTFSDIR}/configscript.sh
# Make all links relative
for link in $(find ${ROOTFSDIR}/ -type l); do
@@ -95,16 +95,16 @@ sdkchroot_finalize() {
new_target=$(realpath --no-symlinks -m --relative-to=$basedir ${ROOTFSDIR}${target})
# remove first to allow rewriting directory links
- sudo rm $link
- sudo ln -s $new_target $link
+ run_privileged rm $link
+ run_privileged ln -s $new_target $link
fi
done
# Set up sysroot wrapper
for tool_pattern in "gcc-[0-9]*" "g++-[0-9]*" "cpp-[0-9]*" "ld.bfd" "ld.gold"; do
for tool in $(find ${ROOTFSDIR}/usr/bin -type f -name "*-linux-gnu*-${tool_pattern}"); do
- sudo mv "${tool}" "${tool}.bin"
- sudo ln -sf gcc-sysroot-wrapper.sh ${tool}
+ run_privileged mv "${tool}" "${tool}.bin"
+ run_privileged ln -sf gcc-sysroot-wrapper.sh ${tool}
done
done
}
diff --git a/meta/classes/sbom.bbclass b/meta/classes/sbom.bbclass
index a16f6ea0..e3d0e702 100644
--- a/meta/classes/sbom.bbclass
+++ b/meta/classes/sbom.bbclass
@@ -41,7 +41,7 @@ def sbom_doc_uuid(d):
d.setVar("SBOM_DOCUMENT_UUID", generate_document_uuid(d))
generate_sbom() {
- sudo mkdir -p ${SBOM_CHROOT}/mnt/rootfs ${SBOM_CHROOT}/mnt/deploy-dir
+ run_privileged mkdir -p ${SBOM_CHROOT}/mnt/rootfs ${SBOM_CHROOT}/mnt/deploy-dir
TIMESTAMP=$(date --iso-8601=s -d @${SOURCE_DATE_EPOCH})
bwrap \
diff --git a/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc b/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc
index d5bbae70..f420c3c1 100644
--- a/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc
+++ b/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc
@@ -204,19 +204,19 @@ do_bootstrap() {
trap '[ -r "${WORKDIR}/mmtmpdir" ] && tmpdir=$(cat "${WORKDIR}/mmtmpdir") \
&& rm "${WORKDIR}/mmtmpdir"; \
[ -d "$tmpdir" ] && mountpoint -q $tmpdir/$base_apt_tmp \
- && sudo umount $tmpdir/$base_apt_tmp; \
+ && run_privileged umount $tmpdir/$base_apt_tmp; \
[ -d "$tmpdir" ] && mountpoint -q $tmpdir/base-apt \
- && sudo umount $tmpdir/base-apt; \
- [ -d "$tmpdir" ] && sudo rm -rf --one-file-system $tmpdir; \
+ && run_privileged umount $tmpdir/base-apt; \
+ [ -d "$tmpdir" ] && run_privileged rm -rf --one-file-system $tmpdir; \
[ -n "$base_apt_tmp" ] && mountpoint -q $base_apt_tmp \
- && sudo umount $base_apt_tmp \
+ && run_privileged umount $base_apt_tmp \
&& rm -rf --one-file-system $base_apt_tmp' EXIT
# Create lock file so that it is owned by the user running the build (not root)
mkdir -p ${DEBDIR}
touch ${DEB_DL_LOCK}
- sudo TMPDIR="${BOOTSTRAP_TMPDIR}" mmdebstrap $bootstrap_args \
+ run_privileged TMPDIR="${BOOTSTRAP_TMPDIR}" mmdebstrap $bootstrap_args \
$arch_param \
--mode=unshare \
${MMHOOKS} \
@@ -248,7 +248,7 @@ do_bootstrap() {
if [ "${ISAR_USE_CACHED_BASE_REPO}" != "1" ]; then
deb_dl_dir_export "${WORKDIR}/dl_dir" "${BOOTSTRAP_BASE_DISTRO}-${BASE_DISTRO_CODENAME}"
- sudo rm -rf --one-file-system "${WORKDIR}/dl_dir"
+ run_privileged rm -rf --one-file-system "${WORKDIR}/dl_dir"
fi
}
addtask bootstrap before do_build after do_generate_keyrings
diff --git a/testsuite/unittests/test_image_account_extension.py b/testsuite/unittests/test_image_account_extension.py
index 97d221fd..e2ff4a5a 100644
--- a/testsuite/unittests/test_image_account_extension.py
+++ b/testsuite/unittests/test_image_account_extension.py
@@ -54,9 +54,8 @@ class TestImageAccountExtensionImageCreateUsers(
image_create_users(d)
run_mock.assert_called_once_with(
+ run_privileged_cmd(d).split() +
[
- 'sudo',
- '-E',
'chroot',
rootfs.path(),
'/usr/sbin/useradd',
@@ -136,9 +135,8 @@ class TestImageAccountExtensionImageCreateGroups(
image_create_groups(d)
run_mock.assert_called_once_with(
+ run_privileged_cmd(d).split() +
[
- 'sudo',
- '-E',
'chroot',
rootfs.path(),
'/usr/sbin/groupadd',
@@ -164,9 +162,8 @@ class TestImageAccountExtensionImageCreateGroups(
image_create_groups(d)
run_mock.assert_called_once_with(
+ run_privileged_cmd(d).split() +
[
- 'sudo',
- '-E',
'chroot',
rootfs.path(),
'/usr/sbin/groupmod',
--
2.51.0
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260218115827.3947145-5-felix.moessbauer%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC 05/12] bootstrap: move cleanup trap to function
2026-02-18 11:58 [RFC 00/12] add support to build isar unprivileged 'Felix Moessbauer' via isar-users
` (3 preceding siblings ...)
2026-02-18 11:58 ` [RFC 04/12] introduce wrappers for privileged execution 'Felix Moessbauer' via isar-users
@ 2026-02-18 11:58 ` 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 06/12] rootfs: rework sstate caching of rootfs artifact 'Felix Moessbauer' via isar-users
` (7 subsequent siblings)
12 siblings, 0 replies; 19+ messages in thread
From: 'Felix Moessbauer' via isar-users @ 2026-02-18 11:58 UTC (permalink / raw)
To: isar-users; +Cc: quirin.gylstorff, Felix Moessbauer
By that, we can make the trap more easily conditional.
Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com>
---
.../isar-mmdebstrap/isar-mmdebstrap.inc | 24 +++++++++++--------
1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc b/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc
index f420c3c1..8ca295b7 100644
--- a/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc
+++ b/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc
@@ -105,6 +105,19 @@ def get_apt_auth_opts(d):
f"--setup-hook='upload \"{workdir}/apt-auth\" /etc/apt/auth.conf.d/isar.conf'"
return ''
+bootstrap_cleanup() {
+ [ -r "${WORKDIR}/mmtmpdir" ] && tmpdir=$(cat "${WORKDIR}/mmtmpdir") \
+ && rm "${WORKDIR}/mmtmpdir"
+ [ -d "$tmpdir" ] && mountpoint -q $tmpdir/$base_apt_tmp \
+ && run_privileged umount $tmpdir/$base_apt_tmp
+ [ -d "$tmpdir" ] && mountpoint -q $tmpdir/base-apt \
+ && run_privileged umount $tmpdir/base-apt
+ [ -d "$tmpdir" ] && run_privileged rm -rf --one-file-system $tmpdir
+ [ -n "$base_apt_tmp" ] && mountpoint -q $base_apt_tmp \
+ && run_privileged umount $base_apt_tmp \
+ && rm -rf --one-file-system $base_apt_tmp
+}
+
do_bootstrap[vardeps] += " \
DISTRO_APT_PREMIRRORS \
ISAR_ENABLE_COMPAT_ARCH \
@@ -201,16 +214,7 @@ do_bootstrap() {
# Cleanup mounts if fails
trap 'exit 1' INT HUP QUIT TERM ALRM USR1
- trap '[ -r "${WORKDIR}/mmtmpdir" ] && tmpdir=$(cat "${WORKDIR}/mmtmpdir") \
- && rm "${WORKDIR}/mmtmpdir"; \
- [ -d "$tmpdir" ] && mountpoint -q $tmpdir/$base_apt_tmp \
- && run_privileged umount $tmpdir/$base_apt_tmp; \
- [ -d "$tmpdir" ] && mountpoint -q $tmpdir/base-apt \
- && run_privileged umount $tmpdir/base-apt; \
- [ -d "$tmpdir" ] && run_privileged rm -rf --one-file-system $tmpdir; \
- [ -n "$base_apt_tmp" ] && mountpoint -q $base_apt_tmp \
- && run_privileged umount $base_apt_tmp \
- && rm -rf --one-file-system $base_apt_tmp' EXIT
+ trap 'bootstrap_cleanup' EXIT
# Create lock file so that it is owned by the user running the build (not root)
mkdir -p ${DEBDIR}
--
2.51.0
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260218115827.3947145-6-felix.moessbauer%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC 06/12] rootfs: rework sstate caching of rootfs artifact
2026-02-18 11:58 [RFC 00/12] add support to build isar unprivileged 'Felix Moessbauer' via isar-users
` (4 preceding siblings ...)
2026-02-18 11:58 ` [RFC 05/12] bootstrap: move cleanup trap to function 'Felix Moessbauer' via isar-users
@ 2026-02-18 11:58 ` 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 07/12] rootfs_generate_initramfs: rework deployment to avoid chowning 'Felix Moessbauer' via isar-users
` (6 subsequent siblings)
12 siblings, 0 replies; 19+ messages in thread
From: 'Felix Moessbauer' via isar-users @ 2026-02-18 11:58 UTC (permalink / raw)
To: isar-users; +Cc: quirin.gylstorff, Felix Moessbauer
We ensure that the sstate artifact is always generated for the correct
rootfs directory by using the ROOTFSDIR variable instead of the
assumption that it is in "rootfs". Further, we avoid file permission
cleanup by using stdout to pass the artifact from the privileged space
to the caller.
Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com>
---
meta/classes-recipe/rootfs.bbclass | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/meta/classes-recipe/rootfs.bbclass b/meta/classes-recipe/rootfs.bbclass
index b64a5bde..c9b0a6d1 100644
--- a/meta/classes-recipe/rootfs.bbclass
+++ b/meta/classes-recipe/rootfs.bbclass
@@ -663,11 +663,12 @@ rootfs_install_sstate_prepare() {
# tar --one-file-system will cross bind-mounts to the same filesystem,
# so we use some mount magic to prevent that
mkdir -p ${WORKDIR}/mnt/rootfs
- run_privileged mount -o bind,private '${WORKDIR}/rootfs' '${WORKDIR}/mnt/rootfs' -o ro
- lopts="--one-file-system --exclude=var/cache/apt/archives"
- run_privileged tar -C ${WORKDIR}/mnt -cpSf rootfs.tar $lopts ${SSTATE_TAR_ATTR_FLAGS} rootfs
- run_privileged umount ${WORKDIR}/mnt/rootfs
- run_privileged chown $(id -u):$(id -g) rootfs.tar
+ run_privileged_here <<'EOF' 3> rootfs.tar
+ mount -o bind,private '${ROOTFSDIR}' '${WORKDIR}/mnt/rootfs' -o ro
+ lopts="--one-file-system --exclude=var/cache/apt/archives"
+ tar -C ${WORKDIR}/mnt/rootfs -cpS $lopts ${SSTATE_TAR_ATTR_FLAGS} . >&3
+ umount -q ${WORKDIR}/mnt/rootfs
+EOF
}
do_rootfs_install_sstate_prepare[lockfiles] = "${REPO_ISAR_DIR}/isar.lock"
@@ -676,7 +677,8 @@ rootfs_install_sstate_finalize() {
# - after building the rootfs, the tar won't be there, but we also don't need to unpack
# - after restoring from cache, there will be a tar which we unpack and then delete
if [ -f rootfs.tar ]; then
- run_privileged tar -C ${WORKDIR} -xpf rootfs.tar ${SSTATE_TAR_ATTR_FLAGS}
+ mkdir -p ${ROOTFSDIR}
+ run_privileged tar -C ${ROOTFSDIR} -xp ${SSTATE_TAR_ATTR_FLAGS} < rootfs.tar
rm rootfs.tar
fi
}
--
2.51.0
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260218115827.3947145-7-felix.moessbauer%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC 07/12] rootfs_generate_initramfs: rework deployment to avoid chowning
2026-02-18 11:58 [RFC 00/12] add support to build isar unprivileged 'Felix Moessbauer' via isar-users
` (5 preceding siblings ...)
2026-02-18 11:58 ` [RFC 06/12] rootfs: rework sstate caching of rootfs artifact 'Felix Moessbauer' via isar-users
@ 2026-02-18 11:58 ` 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 08/12] wic: rework image deploy logic to deploy under correct user 'Felix Moessbauer' via isar-users
` (5 subsequent siblings)
12 siblings, 0 replies; 19+ messages in thread
From: 'Felix Moessbauer' via isar-users @ 2026-02-18 11:58 UTC (permalink / raw)
To: isar-users; +Cc: quirin.gylstorff, Felix Moessbauer
Previously the initrd was deployed as root and later chowned in the
deploy dir. This involves privileged operations which will no longer be
possible when running rootless. To prepare for that, we deploy via a
stdout and create the target file by the correct user.
While doing this, we also remove a useless sudo invocation when listing
the ROOTFS/boot dir, as this can be listed by all users.
Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com>
---
meta/classes-recipe/rootfs.bbclass | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/meta/classes-recipe/rootfs.bbclass b/meta/classes-recipe/rootfs.bbclass
index c9b0a6d1..3bf4190f 100644
--- a/meta/classes-recipe/rootfs.bbclass
+++ b/meta/classes-recipe/rootfs.bbclass
@@ -620,18 +620,16 @@ python do_generate_initramfs_setscene () {
rootfs_generate_initramfs[progress] = "custom:rootfs_progress.InitrdProgressHandler"
rootfs_generate_initramfs() {
- if [ -n "$(sudo find '${ROOTFSDIR}/boot' -type f -name 'vmlinu[xz]*')" ]; then
+ if [ -n "$(find '${ROOTFSDIR}/boot' -type f -name 'vmlinu[xz]*')" ]; then
for kernel in ${ROOTFSDIR}/boot/vmlinu[xz]-*; do
export kernel_version=$(basename $kernel | cut -d'-' -f2-)
mods_total="$(find ${ROOTFSDIR}/usr/lib/modules/$kernel_version -type f -name '*.ko*' | wc -l)"
echo "Total number of modules: $mods_total"
echo "Generating initrd for kernel version: $kernel_version"
- run_in_chroot "${ROOTFSDIR}" sh -ec ' \
- ${ROOTFS_INITRAMFS_GENERATOR_CMDLINE}; \
- find /boot -name "initrd.img-$kernel_version*" -exec install --mode 0644 {} /isar-work/initrd.img \; \
- '
+ run_in_chroot "${ROOTFSDIR}" sh -ec '${ROOTFS_INITRAMFS_GENERATOR_CMDLINE}'
+ find ${ROOTFSDIR}/boot -name "initrd.img-$kernel_version*" -exec cat {} \; \
+ > ${DEPLOYDIR}/${INITRD_DEPLOY_FILE}
done
- install --owner $(id -u) --group $(id -g) ${WORKDIR}/initrd.img ${DEPLOYDIR}/${INITRD_DEPLOY_FILE}
else
echo "no kernel in this rootfs, do not generate initrd"
fi
--
2.51.0
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260218115827.3947145-8-felix.moessbauer%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC 08/12] wic: rework image deploy logic to deploy under correct user
2026-02-18 11:58 [RFC 00/12] add support to build isar unprivileged 'Felix Moessbauer' via isar-users
` (6 preceding siblings ...)
2026-02-18 11:58 ` [RFC 07/12] rootfs_generate_initramfs: rework deployment to avoid chowning 'Felix Moessbauer' via isar-users
@ 2026-02-18 11:58 ` 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 09/12] use bitbake function to generate mounting scripts 'Felix Moessbauer' via isar-users
` (4 subsequent siblings)
12 siblings, 0 replies; 19+ messages in thread
From: 'Felix Moessbauer' via isar-users @ 2026-02-18 11:58 UTC (permalink / raw)
To: isar-users; +Cc: quirin.gylstorff, Felix Moessbauer
We previously deployed the image file as root and then chowned the
deployed files to the calling user. Hereby the chown command itself
requires to be run under root, which is not possible on rootless.
As a preparation for rootless, we rework the deploy logic to deploy the
files under the calling user. For that, we deploy to a temporary
directory within workdir that is writeable from inside the chroot and
then copy out under the calling user.
Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com>
---
RECIPE-API-CHANGELOG.md | 12 +++++
.../image-tools-extension.bbclass | 11 +++++
meta/classes-recipe/image.bbclass | 10 +++-
meta/classes-recipe/imagetypes.bbclass | 47 +++++++++++--------
meta/classes-recipe/imagetypes_wic.bbclass | 10 ++--
meta/classes-recipe/squashfs.bbclass | 2 +-
6 files changed, 66 insertions(+), 26 deletions(-)
diff --git a/RECIPE-API-CHANGELOG.md b/RECIPE-API-CHANGELOG.md
index bc40a403..f80630a0 100644
--- a/RECIPE-API-CHANGELOG.md
+++ b/RECIPE-API-CHANGELOG.md
@@ -978,3 +978,15 @@ specifies the rootfs path.
Using these helpers instead of direct `sudo` invocations centralizes platform-specific
privileged execution logic in `base.bbclass`. Direct use of `sudo` is discouraged
in downstream layers.
+
+### Changes to image types
+
+The way different image types are handled has changed to be be compatible with
+rootless builds. For that, the deployment of images happens in two steps:
+
+1. generate the image in the `${IMAGE_STAGE_CHROOT}`
+2. the `imager_run` or `${SUDO_CHROOT}` command takes care of deploying the image
+ into the `${DEPLOY_DIR_IMAGE}`
+
+Conversion commands need to follow this strategy as well, but can read the image
+(prior to conversion) from `${IMAGE_FILE_CHROOT}`.
diff --git a/meta/classes-recipe/image-tools-extension.bbclass b/meta/classes-recipe/image-tools-extension.bbclass
index e88557f6..2eac3619 100644
--- a/meta/classes-recipe/image-tools-extension.bbclass
+++ b/meta/classes-recipe/image-tools-extension.bbclass
@@ -17,6 +17,17 @@ SCHROOT_MOUNTS = "${WORKDIR}:${PP_WORK} ${IMAGE_ROOTFS}:${PP_ROOTFS} ${DEPLOY_DI
SCHROOT_MOUNTS += "${REPO_ISAR_DIR}/${DISTRO}:/isar-apt"
imager_run() {
+ IMAGE_STAGE_DIR=$(dirname $IMAGE_STAGE_HOST)
+ create_chroot_parent_dir $IMAGE_STAGE_DIR
+ imager_run_${ISAR_CHROOT_MODE} "$@"
+
+ # copy locally deployed files with correct permissions to deploy dir
+ find $IMAGE_STAGE_DIR -type f -exec cp {} ${DEPLOY_DIR_IMAGE} \;
+ # on error keep the files for investigation
+ run_privileged rm -rf $IMAGE_STAGE_DIR
+}
+
+imager_run_schroot() {
local_install="${@(d.getVar("INSTALL_%s" % d.getVar("BB_CURRENTTASK")) or '').strip()}"
local_bom="${@(d.getVar("BOM_%s" % d.getVar("BB_CURRENTTASK")) or '').strip()}"
diff --git a/meta/classes-recipe/image.bbclass b/meta/classes-recipe/image.bbclass
index ca449ec5..e0e19adf 100644
--- a/meta/classes-recipe/image.bbclass
+++ b/meta/classes-recipe/image.bbclass
@@ -180,8 +180,14 @@ IMGCLASSES += "${IMAGE_CLASSES}"
inherit ${IMGCLASSES}
# convenience variables to be used by CMDs
+# Note, that the variables are only valid within the type specific task itself
+# but not in transitively called shell functions
IMAGE_FILE_HOST = "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.${type}"
+# view (only for reading) the image in the deploy dir (useful for conversion commands)
IMAGE_FILE_CHROOT = "${PP_DEPLOY}/${IMAGE_FULLNAME}.${type}"
+# staging location for copy-out (should only be written to from chroot)
+IMAGE_STAGE_HOST = "${WORKDIR}/deploy-image-${type}/${IMAGE_FULLNAME}.${type}"
+IMAGE_STAGE_CHROOT = "${PP_WORK}/deploy-image-${type}/${IMAGE_FULLNAME}.${type}"
SUDO_CHROOT = "imager_run -d ${PP_ROOTFS} -u root --"
# hook up IMAGE_CMD_*
@@ -262,8 +268,8 @@ python() {
image_cmd = localdata.getVar('IMAGE_CMD:' + bt_clean)
if image_cmd:
localdata.setVar('type', bt)
+ cmds.append(localdata.expand('\tIMAGE_STAGE_HOST="${IMAGE_STAGE_HOST}"'))
cmds.append(localdata.expand(image_cmd))
- cmds.append(localdata.expand('\tsudo chown $(id -u):$(id -g) ${IMAGE_FILE_HOST}'))
else:
bb.fatal("No IMAGE_CMD for %s" % bt)
vardeps.add('IMAGE_CMD:' + bt_clean)
@@ -292,8 +298,8 @@ python() {
localdata.setVar('type', t)
cmd = '\t' + localdata.getVar('CONVERSION_CMD:' + c)
if cmd not in cmds:
+ cmds.append(localdata.expand('\tIMAGE_STAGE_HOST="${IMAGE_STAGE_HOST}"'))
cmds.append(cmd)
- cmds.append(localdata.expand('\tsudo chown $(id -u):$(id -g) ${IMAGE_FILE_HOST}.%s' % c))
vardeps.add('CONVERSION_CMD:' + c)
for dep in (localdata.getVar('CONVERSION_DEPS:' + c) or '').split():
conversion_install.add(dep)
diff --git a/meta/classes-recipe/imagetypes.bbclass b/meta/classes-recipe/imagetypes.bbclass
index f802c11c..78b89393 100644
--- a/meta/classes-recipe/imagetypes.bbclass
+++ b/meta/classes-recipe/imagetypes.bbclass
@@ -9,7 +9,7 @@ TAR_TRANSFORM = "--transform='s|rootfs|.|'"
TAR_OPTIONS:append = " ${TAR_TRANSFORM}"
IMAGE_CMD:tar() {
${SUDO_CHROOT} tar ${TAR_OPTIONS} -cvSf \
- ${IMAGE_FILE_CHROOT} --one-file-system -C ${PP} rootfs
+ ${IMAGE_STAGE_CHROOT} --one-file-system -C ${PP} rootfs
}
# image type: ext4
@@ -38,10 +38,11 @@ do_image_ext4[prefuncs] = "set_mke2fs_args"
IMAGE_CMD:ext4() {
export E2FSPROGS_FAKE_TIME="${SOURCE_DATE_EPOCH}"
- truncate -s ${ROOTFS_SIZE}K '${IMAGE_FILE_HOST}'
-
- ${SUDO_CHROOT} /sbin/mke2fs ${MKE2FS_ARGS} \
- -F -d '${PP_ROOTFS}' '${IMAGE_FILE_CHROOT}'
+ ${SUDO_CHROOT} /bin/bash -s <<'EOF'
+ set -e
+ truncate -s ${ROOTFS_SIZE}K '${IMAGE_STAGE_CHROOT}'
+ /sbin/mke2fs ${MKE2FS_ARGS} -F -d '${PP_ROOTFS}' '${IMAGE_STAGE_CHROOT}'
+EOF
}
# image type: cpio
@@ -49,10 +50,12 @@ IMAGER_INSTALL:cpio += "cpio"
CPIO_IMAGE_FORMAT ?= "newc"
IMAGE_CMD:cpio() {
- ${SUDO_CHROOT} \
- sh -c "cd ${PP_ROOTFS}; /usr/bin/find . | \
- /usr/bin/cpio -H ${CPIO_IMAGE_FORMAT} -o > \
- ${IMAGE_FILE_CHROOT}"
+ imager_run -p -d ${PP_WORK} -u root <<'EOIMAGER'
+ set -e
+ cd '${PP_ROOTFS}'; /usr/bin/find . | \
+ /usr/bin/cpio -H ${CPIO_IMAGE_FORMAT} -o > \
+ '${IMAGE_STAGE_CHROOT}'
+EOIMAGER
}
# image type: fit
@@ -72,8 +75,9 @@ IMAGE_CMD:fit() {
die "FIT_IMAGE_SOURCE does not contain fitimage source file"
fi
- ${SUDO_CHROOT} /usr/bin/mkimage ${MKIMAGE_ARGS} \
- -f '${PP_WORK}/${FIT_IMAGE_SOURCE}' '${IMAGE_FILE_CHROOT}'
+ ${SUDO_CHROOT} /usr/bin/mkimage \
+ ${MKIMAGE_ARGS} -f '${PP_WORK}/${FIT_IMAGE_SOURCE}' \
+ '${IMAGE_STAGE_CHROOT}'
}
IMAGE_CMD:fit[depends] = "${PN}:do_transform_template"
@@ -90,8 +94,9 @@ THIS_ISAR_CROSS_COMPILE := "${ISAR_CROSS_COMPILE}"
ISAR_CROSS_COMPILE:armhf = "${@bb.utils.contains('IMAGE_BASETYPES', 'ubifs', '1', '${THIS_ISAR_CROSS_COMPILE}', d)}"
IMAGE_CMD:ubifs() {
- ${SUDO_CHROOT} /usr/sbin/mkfs.ubifs ${MKUBIFS_ARGS} \
- -r '${PP_ROOTFS}' '${IMAGE_FILE_CHROOT}'
+ ${SUDO_CHROOT} /usr/sbin/mkfs.ubifs \
+ ${MKUBIFS_ARGS} -r '${PP_ROOTFS}' \
+ '${IMAGE_FILE_CHROOT}'
}
# image type: ubi
@@ -108,22 +113,26 @@ IMAGE_CMD:ubi() {
die "UBINIZE_CFG does not contain ubinize config file."
fi
- ${SUDO_CHROOT} /usr/sbin/ubinize ${UBINIZE_ARGS} \
- -o '${IMAGE_FILE_CHROOT}' '${PP_WORK}/${UBINIZE_CFG}'
+ ${SUDO_CHROOT} /usr/sbin/ubinize \
+ ${UBINIZE_ARGS} -o '${IMAGE_STAGE_CHROOT}' \
+ '${PP_WORK}/${UBINIZE_CFG}'
}
IMAGE_CMD:ubi[depends] = "${PN}:do_transform_template"
# image conversions
IMAGE_CONVERSIONS = "gz xz zst zck"
-CONVERSION_CMD:gz = "${SUDO_CHROOT} sh -c 'gzip -f -9 -n -c --rsyncable ${IMAGE_FILE_CHROOT} > ${IMAGE_FILE_CHROOT}.gz'"
+# image conversions
+IMAGE_CONVERSIONS = "gz xz zst zck"
+
+CONVERSION_CMD:gz = "${SUDO_CHROOT} sh -c 'gzip -f -9 -n -c --rsyncable ${IMAGE_FILE_CHROOT} > ${IMAGE_STAGE_CHROOT}.gz'"
CONVERSION_DEPS:gz = "gzip"
-CONVERSION_CMD:xz = "${SUDO_CHROOT} sh -c 'xz -c ${XZ_DEFAULTS} ${IMAGE_FILE_CHROOT} > ${IMAGE_FILE_CHROOT}.xz'"
+CONVERSION_CMD:xz = "${SUDO_CHROOT} sh -c 'xz -c ${XZ_DEFAULTS} ${IMAGE_FILE_CHROOT} > ${IMAGE_STAGE_CHROOT}.xz'"
CONVERSION_DEPS:xz = "xz-utils"
-CONVERSION_CMD:zst = "${SUDO_CHROOT} sh -c 'zstd -c --sparse ${ZSTD_DEFAULTS} ${IMAGE_FILE_CHROOT} > ${IMAGE_FILE_CHROOT}.zst'"
+CONVERSION_CMD:zst = "${SUDO_CHROOT} sh -c 'zstd -c --sparse ${ZSTD_DEFAULTS} ${IMAGE_FILE_CHROOT} > ${IMAGE_STAGE_CHROOT}.zst'"
CONVERSION_DEPS:zst = "zstd"
-CONVERSION_CMD:zck = "${SUDO_CHROOT} sh -c 'cd $(dirname ${IMAGE_FILE_CHROOT}); zck ${ZCK_DEFAULTS} ${IMAGE_FILE_CHROOT}'"
+CONVERSION_CMD:zck = "${SUDO_CHROOT} sh -c 'cd $(dirname ${IMAGE_FILE_CHROOT}); zck ${ZCK_DEFAULTS} ${IMAGE_STAGE_CHROOT}'"
CONVERSION_DEPS:zck = "zchunk"
diff --git a/meta/classes-recipe/imagetypes_wic.bbclass b/meta/classes-recipe/imagetypes_wic.bbclass
index 63974a3e..ebf3ce8e 100644
--- a/meta/classes-recipe/imagetypes_wic.bbclass
+++ b/meta/classes-recipe/imagetypes_wic.bbclass
@@ -145,6 +145,9 @@ check_for_wic_warnings() {
do_image_wic[file-checksums] += "${WKS_FILE_CHECKSUM}"
IMAGE_CMD:wic() {
+ # variable is type specific, hence capture here and
+ # forward to functions via export
+ export IMAGE_STAGE_CHROOT="${IMAGE_STAGE_CHROOT}"
generate_wic_image
check_for_wic_warnings
}
@@ -181,20 +184,19 @@ generate_wic_image() {
-e "${IMAGE_BASENAME}" ${WIC_CREATE_EXTRA_ARGS}
WIC_DIRECT=$(ls -t -1 /tmp/${IMAGE_FULLNAME}.wic/*.direct | head -1)
- mv -f ${WIC_DIRECT} ${PP_DEPLOY}/${IMAGE_FULLNAME}.wic
- mv -f ${WIC_DIRECT}.bmap ${PP_DEPLOY}/${IMAGE_FULLNAME}.wic.bmap
+ mv -f ${WIC_DIRECT} $IMAGE_STAGE_CHROOT
+ mv -f ${WIC_DIRECT}.bmap $IMAGE_STAGE_CHROOT.bmap
# deploy partition files if requested (ending with .p<x>)
if [ "${WIC_DEPLOY_PARTITIONS}" -eq "1" ]; then
# locate *.direct.p<x> partition files
find "/tmp/${IMAGE_FULLNAME}.wic/" -type f -regextype sed -regex ".*\.direct.*\.p[0-9]\{1,\}" | while read f; do
suffix=$(basename $f | sed 's/.*\.direct\(.*\)/\1/')
- mv -f ${f} ${PP_DEPLOY}/${IMAGE_FULLNAME}.wic${suffix}
+ mv -f ${f} $IMAGE_STAGE_CHROOT${suffix}
done
fi
EOIMAGER
run_privileged chown -R $(stat -c "%U" ${LAYERDIR_core}) ${LAYERDIR_core} ${LAYERDIR_isar} ${SCRIPTSDIR} || true
- run_privileged chown -R $(id -u):$(id -g) "${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.wic"*
rm -rf ${IMAGE_ROOTFS}/../pseudo
cat ${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.manifest \
diff --git a/meta/classes-recipe/squashfs.bbclass b/meta/classes-recipe/squashfs.bbclass
index 9cd7ed3d..8330ffb5 100644
--- a/meta/classes-recipe/squashfs.bbclass
+++ b/meta/classes-recipe/squashfs.bbclass
@@ -42,6 +42,6 @@ IMAGE_CMD:squashfs[depends] = "${PN}:do_transform_template"
IMAGE_CMD:squashfs[vardepsexclude] += "SQUASHFS_CREATION_LIMITS"
IMAGE_CMD:squashfs() {
${SUDO_CHROOT} /bin/mksquashfs \
- '${SQUASHFS_CONTENT}' '${IMAGE_FILE_CHROOT}' \
+ '${SQUASHFS_CONTENT}' '${IMAGE_STAGE_CHROOT}' \
-noappend ${SQUASHFS_CREATION_LIMITS} ${SQUASHFS_CREATION_ARGS}
}
--
2.51.0
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260218115827.3947145-9-felix.moessbauer%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC 09/12] use bitbake function to generate mounting scripts
2026-02-18 11:58 [RFC 00/12] add support to build isar unprivileged 'Felix Moessbauer' via isar-users
` (7 preceding siblings ...)
2026-02-18 11:58 ` [RFC 08/12] wic: rework image deploy logic to deploy under correct user 'Felix Moessbauer' via isar-users
@ 2026-02-18 11:58 ` 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 10/12] apt-fetcher: prepare for chroot specific fetching 'Felix Moessbauer' via isar-users
` (3 subsequent siblings)
12 siblings, 0 replies; 19+ messages in thread
From: 'Felix Moessbauer' via isar-users @ 2026-02-18 11:58 UTC (permalink / raw)
To: isar-users; +Cc: quirin.gylstorff, Felix Moessbauer
By introducing a bitbake python function (a code generator) to
generate the mount shell code, we make it reusable within here
documents where external shell functions cannot be called.
Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com>
---
meta/classes-recipe/rootfs.bbclass | 68 ++++++++++++++----------------
1 file changed, 31 insertions(+), 37 deletions(-)
diff --git a/meta/classes-recipe/rootfs.bbclass b/meta/classes-recipe/rootfs.bbclass
index 3bf4190f..5a7c2a93 100644
--- a/meta/classes-recipe/rootfs.bbclass
+++ b/meta/classes-recipe/rootfs.bbclass
@@ -49,6 +49,16 @@ ROOTFS_PACKAGE_SUFFIX ?= "${PN}-${DISTRO}-${DISTRO_ARCH}"
# path to deploy stubbed versions of initrd update scripts during do_rootfs_install
ROOTFS_STUBS_DIR = "/usr/local/isar-sbin"
+# list of <outer>:<inner> or <outer> mount entries
+ROOTFS_MOUNTS ??= "${REPO_ISAR_DIR}/${DISTRO}:/isar-apt ${WORKDIR}:/isar-work"
+
+python () {
+ mounts = d.getVar('ROOTFS_MOUNTS', False)
+ if d.getVar('ISAR_USE_CACHED_BASE_REPO') and not '/base-apt' in mounts:
+ base_apt = '{}/base-apt:/base-apt'.format(d.getVar('REPO_BASE_DIR'))
+ mounts.append(' {}'.format(base_apt))
+}
+
# helper to compute the rootfs distro also under cross building
def get_rootfs_distro(d):
host_arch = d.getVar('HOST_ARCH')
@@ -58,6 +68,25 @@ def get_rootfs_distro(d):
else:
return d.getVar('HOST_DISTRO')
+def insert_isar_mounts(d, rootfs, mounts):
+ lines = []
+ for m in mounts.split():
+ host, inner = m.split(':') if ':' in m else (m, m)
+ inner_full = os.path.join(rootfs, inner[1:])
+ lines.append('mkdir -p {}'.format(inner_full))
+ lines.append('mount -o bind,private {} {}'.format(host, inner_full))
+ return '\n'.join(lines)
+
+def insert_isar_umounts(d, rootfs, mounts):
+ lines = []
+ for m in mounts.split():
+ host, inner = m.split(':') if ':' in m else (m, m)
+ lines.append('if mountpoint -q {}/{}; then'.format(rootfs, inner))
+ lines.append(' umount {}/{}'.format(rootfs, inner))
+ lines.append(' rmdir --ignore-fail-on-non-empty {}/{}'.format(rootfs, inner))
+ lines.append('fi')
+ return '\n'.join(lines)
+
# Useful environment variables:
export E = "${@ isar_export_proxies(d)}"
export DEBIAN_FRONTEND = "noninteractive"
@@ -154,50 +183,15 @@ rootfs_do_mounts() {
mount -t tmpfs -o size=1m,nosuid,nodev none '${ROOTFSDIR}/sys/firmware'
fi
- # Mount isar-apt if the directory does not exist or if it is empty
- # This prevents overwriting something that was copied there
- if [ ! -e '${ROOTFSDIR}/isar-apt' ] || \
- [ "$(find '${ROOTFSDIR}/isar-apt' -maxdepth 1 -mindepth 1 | wc -l)" = "0" ]
- then
- mkdir -p '${ROOTFSDIR}/isar-apt'
- mountpoint -q '${ROOTFSDIR}/isar-apt' || \
- mount -o bind,private '${REPO_ISAR_DIR}/${DISTRO}' '${ROOTFSDIR}/isar-apt'
- fi
-
- if [ ! -e '$ROOTFSDIR'/isar-work ]; then
- mkdir -p '${ROOTFSDIR}/isar-work'
- mountpoint -q '${ROOTFSDIR}/isar-work' || \
- mount -o bind,private '${WORKDIR}' '${ROOTFSDIR}/isar-work'
- fi
-
- # Mount base-apt if 'ISAR_USE_CACHED_BASE_REPO' is set
- if [ "${@repr(bb.utils.to_boolean(d.getVar('ISAR_USE_CACHED_BASE_REPO')))}" = 'True' ]
- then
- mkdir -p '${ROOTFSDIR}/base-apt'
- mountpoint -q '${ROOTFSDIR}/base-apt' || \
- mount -o bind,private '${REPO_BASE_DIR}' '${ROOTFSDIR}/base-apt'
- fi
-
+ ${@insert_isar_mounts(d, d.getVar('ROOTFSDIR'), d.getVar('ROOTFS_MOUNTS'))}
EOSUDO
}
rootfs_do_umounts() {
run_privileged_here <<'EOSUDO'
set -e
- if mountpoint -q '${ROOTFSDIR}/isar-apt'; then
- umount '${ROOTFSDIR}/isar-apt'
- rmdir --ignore-fail-on-non-empty ${ROOTFSDIR}/isar-apt
- fi
- if mountpoint -q '${ROOTFSDIR}/base-apt'; then
- umount '${ROOTFSDIR}/base-apt'
- rmdir --ignore-fail-on-non-empty ${ROOTFSDIR}/base-apt
- fi
-
- if mountpoint -q '${ROOTFSDIR}/isar-work'; then
- umount '${ROOTFSDIR}/isar-work'
- rmdir --ignore-fail-on-non-empty ${ROOTFSDIR}/isar-work
- fi
+ ${@insert_isar_umounts(d, d.getVar('ROOTFSDIR'), d.getVar('ROOTFS_MOUNTS'))}
if mountpoint -q '${ROOTFSDIR}/dev/pts'; then
umount '${ROOTFSDIR}/dev/pts'
--
2.51.0
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260218115827.3947145-10-felix.moessbauer%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC 10/12] apt-fetcher: prepare for chroot specific fetching
2026-02-18 11:58 [RFC 00/12] add support to build isar unprivileged 'Felix Moessbauer' via isar-users
` (8 preceding siblings ...)
2026-02-18 11:58 ` [RFC 09/12] use bitbake function to generate mounting scripts 'Felix Moessbauer' via isar-users
@ 2026-02-18 11:58 ` 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 11/12] add support for fully rootless builds 'Felix Moessbauer' via isar-users
` (2 subsequent siblings)
12 siblings, 0 replies; 19+ messages in thread
From: 'Felix Moessbauer' via isar-users @ 2026-02-18 11:58 UTC (permalink / raw)
To: isar-users; +Cc: quirin.gylstorff, Felix Moessbauer
The implementation of the fetching depends on the chroot mode (e.g.
schroot or unshare). As a preparation for the unshare mode, we hide the
concrete fetcher implementation behind a factory, so that we will be
able to dispatch based on the mode.
Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com>
---
meta/classes-recipe/dpkg-base.bbclass | 2 +-
meta/lib/aptsrc_fetcher.py | 12 +++++++++---
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/meta/classes-recipe/dpkg-base.bbclass b/meta/classes-recipe/dpkg-base.bbclass
index df3dd1fd..5841d6ee 100644
--- a/meta/classes-recipe/dpkg-base.bbclass
+++ b/meta/classes-recipe/dpkg-base.bbclass
@@ -84,7 +84,7 @@ python() {
# apt-src fetcher
import aptsrc_fetcher
- methods.append(aptsrc_fetcher.AptSrc())
+ methods.append(aptsrc_fetcher.AptSrc.create(d))
src_uri = (d.getVar('SRC_URI', False) or "").split()
for u in src_uri:
diff --git a/meta/lib/aptsrc_fetcher.py b/meta/lib/aptsrc_fetcher.py
index dfa784a9..37c84fa7 100644
--- a/meta/lib/aptsrc_fetcher.py
+++ b/meta/lib/aptsrc_fetcher.py
@@ -9,6 +9,10 @@ from bb.fetch2 import logger
from bb.fetch2 import runfetchcmd
class AptSrc(FetchMethod):
+ @classmethod
+ def create(cls, d):
+ return AptSrcSchroot()
+
def supports(self, ud, d):
return ud.type in ['apt']
@@ -20,6 +24,11 @@ class AptSrc(FetchMethod):
codename = d.getVar('BASE_DISTRO_CODENAME')
ud.localfile='deb-src/' + base_distro + '-' + codename + '/' + ud.host
+ def clean(self, ud, d):
+ bb.utils.remove(ud.localpath, recurse=True)
+
+
+class AptSrcSchroot(AptSrc):
def download(self, ud, d):
bb.utils.exec_flat_python_func('isar_export_proxies', d)
bb.build.exec_func('schroot_create_configs', d)
@@ -83,6 +92,3 @@ class AptSrc(FetchMethod):
finally:
runfetchcmd(f'schroot -q -f -e -c {session_id}', d)
bb.build.exec_func('schroot_delete_configs', d)
-
- def clean(self, ud, d):
- bb.utils.remove(ud.localpath, recurse=True)
--
2.51.0
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260218115827.3947145-11-felix.moessbauer%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC 11/12] add support for fully rootless builds
2026-02-18 11:58 [RFC 00/12] add support to build isar unprivileged 'Felix Moessbauer' via isar-users
` (9 preceding siblings ...)
2026-02-18 11:58 ` [RFC 10/12] apt-fetcher: prepare for chroot specific fetching 'Felix Moessbauer' via isar-users
@ 2026-02-18 11:58 ` 'Felix Moessbauer' via isar-users
2026-02-18 16:09 ` 'Jan Kiszka' via isar-users
2026-02-18 16:50 ` 'Jan Kiszka' via isar-users
2026-02-18 11:58 ` [RFC 12/12] apt-fetcher: implement support for unshare backend 'Felix Moessbauer' via isar-users
2026-02-18 18:20 ` [RFC 00/12] add support to build isar unprivileged 'Jan Kiszka' via isar-users
12 siblings, 2 replies; 19+ messages in thread
From: 'Felix Moessbauer' via isar-users @ 2026-02-18 11:58 UTC (permalink / raw)
To: isar-users; +Cc: quirin.gylstorff, Felix Moessbauer
Currently isar requires passwordless sudo and an environment
where mounting file systems is possible. This has proven problematic
for security reasons, both when running in a privileged container or
locally.
To solve this, we implement fully rootless builds that rely on the
unshare syscall which allows us to avoid sudo and instead operate in
temporary kernel namespaces as a user that is just privileged within
that namespace. This comes with some challenges regarding the handling
of mounts (they are cleared when leaving the namespace), as well as
cross namespace deployments (the outer user might not be able to access
the inner data). For that, we rework the handling of mounts and artifact
passing to make it compatible with both chroot modes (schroot and
unshare).
Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com>
---
Kconfig | 2 +-
RECIPE-API-CHANGELOG.md | 29 +++++++
doc/user_manual.md | 2 +
meta/classes-global/base.bbclass | 67 ++++++++++++++-
meta/classes-recipe/deb-dl-dir.bbclass | 9 +-
meta/classes-recipe/dpkg-base.bbclass | 16 +++-
meta/classes-recipe/dpkg.bbclass | 14 +++-
.../image-locales-extension.bbclass | 9 +-
.../image-tools-extension.bbclass | 82 +++++++++++++++++++
meta/classes-recipe/rootfs.bbclass | 53 +++++++++---
meta/classes-recipe/sbuild.bbclass | 27 +++++-
meta/classes-recipe/sdk.bbclass | 11 ++-
meta/conf/bitbake.conf | 7 +-
.../isar-mmdebstrap/isar-mmdebstrap.inc | 12 ++-
.../sbuild-chroot/sbuild-chroot.inc | 24 +++++-
15 files changed, 332 insertions(+), 32 deletions(-)
diff --git a/Kconfig b/Kconfig
index 683c0da5..5ef2bfcb 100644
--- a/Kconfig
+++ b/Kconfig
@@ -14,7 +14,7 @@ config KAS_INCLUDE_MAIN
config KAS_BUILD_SYSTEM
string
- default "isar"
+ default "isar-rootless"
source "kas/machine/Kconfig"
source "kas/distro/Kconfig"
diff --git a/RECIPE-API-CHANGELOG.md b/RECIPE-API-CHANGELOG.md
index f80630a0..29bf7590 100644
--- a/RECIPE-API-CHANGELOG.md
+++ b/RECIPE-API-CHANGELOG.md
@@ -990,3 +990,32 @@ rootless builds. For that, the deployment of images happens in two steps:
Conversion commands need to follow this strategy as well, but can read the image
(prior to conversion) from `${IMAGE_FILE_CHROOT}`.
+
+### Rootless isar execution
+
+Isar is able to run without the need for `sudo` in an environment that
+allows unprivileged users to unshare the kernels `user namespace`. Further,
+a sufficiently large set of sub ids needs to be configured in `/etc/subuid` / `etc/subgid`.
+This range should be `> 65536`, but smaller ranges might work as well, depending on the
+ids used in the rootfs.
+
+A simple check if rootless is supported can be done by running:
+
+```bash
+mmdebstrap --unshare-helper /bin/echo "rootless supported" || echo "rootless not supported"
+```
+
+On many systems, setting the following settings is sufficent, but no general guidance
+can be provided.
+
+```bash
+echo 0 | sudo tee -a /proc/sys/kernel/apparmor_restrict_unprivileged_userns
+echo 1 | sudo tee -a /proc/sys/kernel/unprivileged_userns_clone
+```
+
+To enable rootless builds, set the bitbake variable `ISAR_ROOTLESS = "1"`.
+This internally switches the chroot mode from `schroot` to `unshare`.
+
+When using kas, the `build_system` needs to be set to `isar-rootless`, but the final
+interfaces still need to be clarified. Further, kas patches are needed (for details,
+check the kas mailing list).
diff --git a/doc/user_manual.md b/doc/user_manual.md
index 7520854b..77a37e9b 100644
--- a/doc/user_manual.md
+++ b/doc/user_manual.md
@@ -74,6 +74,7 @@ Building `debian-trixie` requires host system >= bookworm.
Install the following packages:
```
apt install \
+ acl \
binfmt-support \
bubblewrap \
bzip2 \
@@ -88,6 +89,7 @@ apt install \
qemu-user-static \
reprepro \
sudo \
+ uidmap \
unzip \
xz-utils \
git-buildpackage \
diff --git a/meta/classes-global/base.bbclass b/meta/classes-global/base.bbclass
index 16939f64..26d1ee22 100644
--- a/meta/classes-global/base.bbclass
+++ b/meta/classes-global/base.bbclass
@@ -388,11 +388,54 @@ do_unpack[prefuncs] += "deprecation_checking"
# Helpers for privileged execution. Only the non-underscore functions
# shall be used outside of this class.
+def get_subid_range(idmap, d):
+ with open(idmap, 'r') as f:
+ entries = f.readlines()
+ for e in entries:
+ user, base, cnt = e.split(':')
+ if user == os.getuid() or user == os.getlogin():
+ return base, cnt
+ bb.error("No sub-id range specified in %s" % idmap)
+
def run_privileged_cmd(d):
- cmd = 'sudo -E'
+ """
+ In unshare mode we need to map the rootfs uid/gid range into the
+ subuid/subgid range of the parent namespace. As we usually only
+ get 65534 ids, we cannot map the whole range, as two ids are already
+ used by the calling environment (root and builder user). Hence, map
+ as much as we can but also map the highest id (nobody / nogroup) as
+ these are used within the rootfs. It would be easier to use
+ mmdebstrap --unshare-helper as command (which is also internally used
+ by sbuild), but this only maps linear ranges, hence it cannot map the
+ nobody / nogroup on the default subid range. By that, we have to avoid
+ the nobody / nogroup when building packages in this case.
+ """
+ if d.getVar('ISAR_CHROOT_MODE') == 'unshare':
+ noone_id = 65534
+ uid_base = int(d.getVar('UNSHARE_SUBUID_BASE'))
+ uid_cnt = int(d.getVar('UNSHARE_SUBUID_COUNT')) - 2
+ nobody_subid = uid_base + uid_cnt
+ gid_base = int(d.getVar('UNSHARE_SUBGID_BASE'))
+ gid_cnt = int(d.getVar('UNSHARE_SUBGID_COUNT')) - 2
+ nogroup_subid = gid_base + gid_cnt
+ cmd = 'unshare --mount --user --pid' \
+ ' --setuid 0 --setgid 0 --fork' \
+ f' --map-users 0:{uid_base}:{uid_cnt}' \
+ f' --map-groups 0:{gid_base}:{gid_cnt}'
+ if uid_cnt < noone_id:
+ cmd += f' --map-users {noone_id}:{nobody_subid}:1'
+ if gid_cnt < noone_id:
+ cmd += f' --map-groups {noone_id}:{nogroup_subid}:1'
+ else:
+ cmd = 'sudo -E'
bb.debug(1, "privileged cmd: %s" % cmd)
return cmd
+UNSHARE_SUBUID_BASE := "${@get_subid_range('/etc/subuid', d)[0]}"
+UNSHARE_SUBUID_COUNT := "${@get_subid_range('/etc/subuid', d)[1]}"
+UNSHARE_SUBGID_BASE := "${@get_subid_range('/etc/subgid', d)[0]}"
+UNSHARE_SUBGID_COUNT := "${@get_subid_range('/etc/subgid', d)[1]}"
+# store in variable to only compute once and make available to fetcher
RUN_PRIVILEGED_CMD := "${@run_privileged_cmd(d)}"
run_privileged() {
@@ -404,9 +447,29 @@ run_privileged_here() {
}
# create a directory that is suitable to be the
-# parent of a rootfs
+# parent of a rootfs. In unshare mode, we further need to
+# give the inner user the right to create a directory there.
+# This is needed, as the inner user needs to extract the
+# rootfs tarball and owns the '.' dir.
+create_chroot_parent_dir() {
+ mkdir -p "$@"
+ if [ "${ISAR_CHROOT_MODE}" = "unshare" ]; then
+ setfacl -m u:${UNSHARE_SUBUID_BASE}:rwX "$@"
+ fi
+}
+
+# get the base of the calling users subuid range
+get_base_subuid() {
+ grep $(whoami) /etc/subuid | cut -d ':' -f 2
+}
+
+# create the directory and prepare permissions to untar
+# a rootfs into an inner directory
create_chroot_parent_dir() {
mkdir -p "$@"
+ if [ "${ISAR_CHROOT_MODE}" = "unshare" ]; then
+ setfacl -m u:$(get_base_subuid):rwX "$@"
+ fi
}
run_in_chroot() {
diff --git a/meta/classes-recipe/deb-dl-dir.bbclass b/meta/classes-recipe/deb-dl-dir.bbclass
index fc0cd915..2020cdd0 100644
--- a/meta/classes-recipe/deb-dl-dir.bbclass
+++ b/meta/classes-recipe/deb-dl-dir.bbclass
@@ -121,8 +121,13 @@ deb_dl_dir_import() {
# let our unprivileged user place downloaded packages in /var/cache/apt/archives/
run_privileged_here << ' EOSUDO'
- mkdir -p "${rootfs}"/var/cache/apt/archives/partial/
- chown -R ${uid}:${gid} "${rootfs}"/var/cache/apt/archives/
+ if [ "${ISAR_CHROOT_MODE}" = "unshare" ]; then
+ mkdir -p "${rootfs}"/var/cache/apt/archives
+ chmod 777 "${rootfs}"/var/cache/apt/archives
+ else
+ mkdir -p "${rootfs}"/var/cache/apt/archives/partial/
+ chown -R ${uid}:${gid} "${rootfs}"/var/cache/apt/archives/
+ fi
EOSUDO
# nothing to copy if download directory does not exist just yet
diff --git a/meta/classes-recipe/dpkg-base.bbclass b/meta/classes-recipe/dpkg-base.bbclass
index 5841d6ee..e4e72f80 100644
--- a/meta/classes-recipe/dpkg-base.bbclass
+++ b/meta/classes-recipe/dpkg-base.bbclass
@@ -168,12 +168,24 @@ dpkg_schroot_create_configs() {
EOSUDO
}
+dpkg_chroot_prepare() {
+ if [ "${ISAR_CHROOT_MODE}" = "schroot" ]; then
+ dpkg_schroot_create_configs
+ fi
+}
+
+dpkg_chroot_finalize() {
+ if [ "${ISAR_CHROOT_MODE}" = "schroot" ]; then
+ schroot_delete_configs
+ fi
+}
+
python do_dpkg_build() {
- bb.build.exec_func('dpkg_schroot_create_configs', d)
+ bb.build.exec_func('dpkg_chroot_prepare', d)
try:
bb.build.exec_func("dpkg_runbuild", d)
finally:
- bb.build.exec_func('schroot_delete_configs', d)
+ bb.build.exec_func('dpkg_chroot_finalize', d)
}
do_dpkg_build[network] = "${TASK_USE_NETWORK_AND_SUDO}"
diff --git a/meta/classes-recipe/dpkg.bbclass b/meta/classes-recipe/dpkg.bbclass
index 8d7ff092..9fda58af 100644
--- a/meta/classes-recipe/dpkg.bbclass
+++ b/meta/classes-recipe/dpkg.bbclass
@@ -78,6 +78,7 @@ dpkg_runbuild() {
distro="${HOST_BASE_DISTRO}-${BASE_DISTRO_CODENAME}"
fi
+ create_chroot_parent_dir ${WORKDIR}
deb_dl_dir_import "${WORKDIR}/rootfs" "${distro}"
deb_dir="/var/cache/apt/archives"
@@ -85,7 +86,10 @@ dpkg_runbuild() {
ext_deb_dir="${ext_root}${deb_dir}"
if [ ${USE_CCACHE} -eq 1 ]; then
- schroot_configure_ccache
+ ${ISAR_CHROOT_MODE}_configure_ccache
+ fi
+ if [ "${ISAR_CHROOT_MODE}" = "unshare" ]; then
+ sbuild_add_unshare_mounts
fi
profiles="${@ isar_deb_build_profiles(d)}"
@@ -110,12 +114,13 @@ dpkg_runbuild() {
DSC_FILE=$(find ${WORKDIR} -maxdepth 1 -name "${DEBIAN_SOURCE}_*.dsc" -print)
sbuild -A -n -c ${SBUILD_CHROOT} \
+ --chroot-mode=${ISAR_CHROOT_MODE} \
--host=${PACKAGE_ARCH} --build=${BUILD_ARCH} ${profiles} \
--no-run-lintian --no-run-piuparts --no-run-autopkgtest --resolve-alternatives \
--bd-uninstallable-explainer=apt \
--no-apt-update --apt-distupgrade \
--chroot-setup-commands="echo \"Package: *\nPin: release n=${DEBDISTRONAME}\nPin-Priority: 1000\" > /etc/apt/preferences.d/isar-apt" \
- --chroot-setup-commands="echo \"APT::Get::allow-downgrades 1;\" > /etc/apt/apt.conf.d/50isar-apt" \
+ --chroot-setup-commands="echo \"APT::Get::allow-downgrades 1;${@'\nAPT::Sandbox::User root;' if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else ''}\" > /etc/apt/apt.conf.d/50isar-apt" \
--chroot-setup-commands="rm -f /var/log/dpkg.log" \
--chroot-setup-commands="mkdir -p ${deb_dir}" \
--chroot-setup-commands="find ${ext_deb_dir} -maxdepth 1 -name '*.deb' -exec ln -t ${deb_dir}/ -sf {} +" \
@@ -125,7 +130,10 @@ dpkg_runbuild() {
--finished-build-commands="cp /var/log/dpkg.log ${ext_root}/dpkg_partial.log" \
--build-path="" --build-dir=${WORKDIR} --dist="${DEBDISTRONAME}" ${DSC_FILE}
- sbuild_dpkg_log_export "${WORKDIR}/rootfs/dpkg_partial.log"
+ # TODO: unclear if needed under unshare
+ if [ "${ISAR_CHROOT_MODE}" = "schroot" ]; then
+ sbuild_dpkg_log_export "${WORKDIR}/rootfs/dpkg_partial.log"
+ fi
deb_dl_dir_export "${WORKDIR}/rootfs" "${distro}"
# Cleanup apt artifacts
diff --git a/meta/classes-recipe/image-locales-extension.bbclass b/meta/classes-recipe/image-locales-extension.bbclass
index f4eb3718..f0683996 100644
--- a/meta/classes-recipe/image-locales-extension.bbclass
+++ b/meta/classes-recipe/image-locales-extension.bbclass
@@ -29,8 +29,15 @@ ROOTFS_INSTALL_COMMAND_BEFORE_EXPORT += "image_install_localepurge_download"
image_install_localepurge_download[weight] = "40"
image_install_localepurge_download[network] = "${TASK_USE_NETWORK_AND_SUDO}"
image_install_localepurge_download() {
- run_in_chroot '${ROOTFSDIR}' \
+ run_privileged_here <<'EOF'
+ set -e
+ if [ "${ISAR_CHROOT_MODE}" = "unshare" ]; then
+ mount -o bind,private '${REPO_ISAR_DIR}/${DISTRO}' '${ROOTFSDIR}/isar-apt'
+ fi
+
+ chroot ${ROOTFSDIR} \
/usr/bin/apt-get ${ROOTFS_APT_ARGS} -oDebug::NoLocking=1 --download-only localepurge
+EOF
}
ROOTFS_INSTALL_COMMAND += "image_install_localepurge_install"
diff --git a/meta/classes-recipe/image-tools-extension.bbclass b/meta/classes-recipe/image-tools-extension.bbclass
index 2eac3619..addc514a 100644
--- a/meta/classes-recipe/image-tools-extension.bbclass
+++ b/meta/classes-recipe/image-tools-extension.bbclass
@@ -16,6 +16,9 @@ do_image_tools[depends] += " \
SCHROOT_MOUNTS = "${WORKDIR}:${PP_WORK} ${IMAGE_ROOTFS}:${PP_ROOTFS} ${DEPLOY_DIR_IMAGE}:${PP_DEPLOY}"
SCHROOT_MOUNTS += "${REPO_ISAR_DIR}/${DISTRO}:/isar-apt"
+# only used on unshare
+ROOTFS_IMAGETOOLS ?= "${WORKDIR}/rootfs-imgtools-${BB_CURRENTTASK}"
+
imager_run() {
IMAGE_STAGE_DIR=$(dirname $IMAGE_STAGE_HOST)
create_chroot_parent_dir $IMAGE_STAGE_DIR
@@ -114,3 +117,82 @@ generate_imager_sbom() {
--timestamp $TIMESTAMP ${SBOM_DEBSBOM_EXTRA_ARGS} \
< ${WORKDIR}/imager.manifest
}
+
+imager_run_unshare() {
+ exec 3<&0
+
+ # ignore everything before '--'. If the remaining list is empty,
+ # assume a here document is passed via stdin
+ while [ "$#" -gt 0 ]; do
+ case "$1" in
+ --) shift 1; break ;;
+ *) shift 1 ;;
+ esac
+ done
+
+ if [ "$#" -eq 0 ]; then
+ set -- "$@" '/bin/bash' '-s'
+ fi
+
+ local_install="${@(d.getVar("INSTALL_%s" % d.getVar("BB_CURRENTTASK")) or '').strip()}"
+
+ create_chroot_parent_dir $(realpath -m "${ROOTFS_IMAGETOOLS}/..")
+
+ run_privileged_here <<'EOF'
+ set -e
+ mkdir -p ${ROOTFS_IMAGETOOLS}
+ tar -xf "${SBUILD_CHROOT}" -C "${ROOTFS_IMAGETOOLS}"
+ mkdir -p ${ROOTFS_IMAGETOOLS}/isar-apt
+ cp -rL /etc/resolv.conf "${ROOTFS_IMAGETOOLS}/etc"
+EOF
+
+ # setting up error handler
+ imager_cleanup() {
+ run_privileged rm -rf ${ROOTFS_IMAGETOOLS}
+ }
+ trap 'exit 1' INT HUP QUIT TERM ALRM USR1
+ trap 'imager_cleanup' EXIT
+
+ if [ -n "${local_install}" ]; then
+ echo "Installing imager deps: ${local_install}"
+
+ distro="${BASE_DISTRO}-${BASE_DISTRO_CODENAME}"
+ if [ ${ISAR_CROSS_COMPILE} -eq 1 ]; then
+ distro="${HOST_BASE_DISTRO}-${BASE_DISTRO_CODENAME}"
+ fi
+
+ E="${@ isar_export_proxies(d)}"
+ deb_dl_dir_import ${ROOTFS_IMAGETOOLS} ${distro}
+ ${SCRIPTSDIR}/lockrun.py -r -f "${REPO_ISAR_DIR}/isar.lock" -s <<'EOAPT'
+ local_install=$local_install ${@run_privileged_cmd(d)} /bin/bash -s <<'EOF'
+ set -e
+ mount -o bind,private ${REPO_ISAR_DIR}/${DISTRO} ${ROOTFS_IMAGETOOLS}/isar-apt
+ chroot ${ROOTFS_IMAGETOOLS} apt-get update \
+ -o Dir::Etc::SourceList='sources.list.d/isar-apt.list' \
+ -o Dir::Etc::SourceParts='-' \
+ -o APT::Get::List-Cleanup='0'
+ chroot ${ROOTFS_IMAGETOOLS} apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends -y \
+ --allow-unauthenticated --allow-downgrades --download-only install \
+ $local_install
+EOF
+EOAPT
+
+ deb_dl_dir_export ${ROOTFS_IMAGETOOLS} ${distro}
+ local_install=$local_install run_privileged_here <<'EOF'
+ set -e
+ mount -o bind,private ${REPO_ISAR_DIR}/${DISTRO} ${ROOTFS_IMAGETOOLS}/isar-apt
+ chroot ${ROOTFS_IMAGETOOLS} apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends -y \
+ --allow-unauthenticated --allow-downgrades install \
+ $local_install
+EOF
+ fi
+
+ run_privileged_here <<'EOF' "$@"
+ set -e
+ mkdir -p ${ROOTFS_IMAGETOOLS}/${SCRIPTSDIR}
+ ${@insert_isar_mounts(d, d.getVar('ROOTFS_IMAGETOOLS'), d.getVar('SCHROOT_MOUNTS'))}
+ chroot ${ROOTFS_IMAGETOOLS} "$@" <&3
+EOF
+
+ run_privileged rm -rf ${ROOTFS_IMAGETOOLS}
+}
diff --git a/meta/classes-recipe/rootfs.bbclass b/meta/classes-recipe/rootfs.bbclass
index 5a7c2a93..4d1f542f 100644
--- a/meta/classes-recipe/rootfs.bbclass
+++ b/meta/classes-recipe/rootfs.bbclass
@@ -164,7 +164,12 @@ rootfs_cmd() {
}
rootfs_do_mounts[weight] = "3"
-rootfs_do_mounts() {
+python rootfs_do_mounts() {
+ if d.getVar('ISAR_CHROOT_MODE') == 'schroot':
+ bb.build.exec_func('rootfs_do_mounts_priv', d)
+}
+
+rootfs_do_mounts_priv() {
run_privileged_here <<'EOSUDO'
set -e
mountpoint -q '${ROOTFSDIR}/dev' || \
@@ -187,7 +192,12 @@ rootfs_do_mounts() {
EOSUDO
}
-rootfs_do_umounts() {
+python rootfs_do_umounts() {
+ if d.getVar('ISAR_CHROOT_MODE') == 'schroot':
+ bb.build.exec_func('rootfs_do_umounts_priv', d)
+}
+
+rootfs_do_umounts_priv() {
run_privileged_here <<'EOSUDO'
set -e
@@ -234,7 +244,12 @@ ROOTFS_EXTRA_IMPORTED := "${@rootfs_extra_import(d)}"
rootfs_prepare[weight] = "25"
rootfs_prepare(){
- run_privileged tar -xf "${BOOTSTRAP_SRC}" -C "${ROOTFSDIR}" --exclude="./dev/console"
+ create_chroot_parent_dir $(realpath "${ROOTFSDIR}/..")
+ rm -rf ${ROOTFSDIR}
+ run_privileged_here << 'EOF'
+ mkdir -p ${ROOTFSDIR}
+ tar -xf "${BOOTSTRAP_SRC}" -C "${ROOTFSDIR}" --exclude="./dev/console"
+EOF
# setup chroot
run_privileged "${ROOTFSDIR}/chroot-setup.sh" "setup" "${ROOTFSDIR}"
@@ -304,10 +319,14 @@ rootfs_install_pkgs_update[weight] = "5"
rootfs_install_pkgs_update[isar-apt-lock] = "acquire-before"
rootfs_install_pkgs_update[network] = "${TASK_USE_NETWORK_AND_SUDO}"
rootfs_install_pkgs_update() {
- run_in_chroot '${ROOTFSDIR}' /usr/bin/apt-get update \
- -o Dir::Etc::SourceList="sources.list.d/isar-apt.list" \
- -o Dir::Etc::SourceParts="-" \
- -o APT::Get::List-Cleanup="0"
+ run_privileged_here <<'EOF'
+ set -e
+ ${@insert_isar_mounts(d, d.getVar('ROOTFSDIR'), d.getVar('ROOTFS_MOUNTS')) if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else ''}
+ chroot '${ROOTFSDIR}' /usr/bin/apt-get update \
+ -o Dir::Etc::SourceList="sources.list.d/isar-apt.list" \
+ -o Dir::Etc::SourceParts="-" \
+ -o APT::Get::List-Cleanup="0"
+EOF
}
ROOTFS_INSTALL_COMMAND += "rootfs_install_resolvconf"
@@ -335,9 +354,12 @@ rootfs_install_pkgs_download[isar-apt-lock] = "release-after"
rootfs_install_pkgs_download[network] = "${TASK_USE_NETWORK}"
rootfs_install_pkgs_download() {
# download packages using apt in a non-privileged namespace
- rootfs_cmd --bind "${ROOTFSDIR}/var/cache/apt/archives" /var/cache/apt/archives \
- ${ROOTFSDIR} \
- -- /usr/bin/apt-get ${ROOTFS_APT_ARGS} -oDebug::NoLocking=1 --download-only ${ROOTFS_PACKAGES}
+ run_privileged_here <<'EOF'
+ set -e
+ ${@insert_isar_mounts(d, d.getVar('ROOTFSDIR'), d.getVar('ROOTFS_MOUNTS')) if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else ''}
+ chroot ${ROOTFSDIR} \
+ /usr/bin/apt-get ${ROOTFS_APT_ARGS} -oDebug::NoLocking=1 --download-only ${ROOTFS_PACKAGES}
+EOF
}
ROOTFS_INSTALL_COMMAND_BEFORE_EXPORT ??= ""
@@ -364,8 +386,12 @@ rootfs_install_pkgs_install[weight] = "8000"
rootfs_install_pkgs_install[progress] = "custom:rootfs_progress.PkgsInstallProgressHandler"
rootfs_install_pkgs_install[network] = "${TASK_USE_SUDO}"
rootfs_install_pkgs_install() {
- run_in_chroot "${ROOTFSDIR}" \
+ run_privileged_here <<'EOF'
+ set -e
+ ${@insert_isar_mounts(d, d.getVar('ROOTFSDIR'), d.getVar('ROOTFS_MOUNTS')) if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else ''}
+ chroot "${ROOTFSDIR}" \
/usr/bin/apt-get ${ROOTFS_APT_ARGS} ${ROOTFS_PACKAGES}
+EOF
}
ROOTFS_INSTALL_COMMAND += "rootfs_restore_initrd_tooling"
@@ -669,8 +695,11 @@ rootfs_install_sstate_finalize() {
# - after building the rootfs, the tar won't be there, but we also don't need to unpack
# - after restoring from cache, there will be a tar which we unpack and then delete
if [ -f rootfs.tar ]; then
+ create_chroot_parent_dir $(realpath -m "${ROOTFSDIR}/..")
+ run_privileged_here <<'EOF'
mkdir -p ${ROOTFSDIR}
- run_privileged tar -C ${ROOTFSDIR} -xp ${SSTATE_TAR_ATTR_FLAGS} < rootfs.tar
+ tar -C ${ROOTFSDIR} -xp ${SSTATE_TAR_ATTR_FLAGS} -f rootfs.tar
+EOF
rm rootfs.tar
fi
}
diff --git a/meta/classes-recipe/sbuild.bbclass b/meta/classes-recipe/sbuild.bbclass
index f0757891..d2d333ed 100644
--- a/meta/classes-recipe/sbuild.bbclass
+++ b/meta/classes-recipe/sbuild.bbclass
@@ -7,7 +7,8 @@ SCHROOT_MOUNTS ?= ""
inherit crossvars
-SBUILD_CHROOT ?= "${DEBDISTRONAME}-${SCHROOT_USER}-${ISAR_BUILD_UUID}-${@os.getpid()}"
+SBUILD_CHROOT:unshare ?= "${SCHROOT_DIR}.tar.zst"
+SBUILD_CHROOT:schroot ?= "${DEBDISTRONAME}-${SCHROOT_USER}-${ISAR_BUILD_UUID}-${@os.getpid()}"
SBUILD_CONF_DIR ?= "${SCHROOT_CONF}/${SBUILD_CHROOT}"
SCHROOT_CONF_FILE ?= "${SCHROOT_CONF}/chroot.d/${SBUILD_CHROOT}"
@@ -144,6 +145,14 @@ END
EOSUDO
}
+unshare_configure_ccache() {
+ # ccache must be below /build for file permissions to work properly
+ cat <<'EOF' >> ${SBUILD_CONFIG}
+$build_environment = { "CCACHE_DIR" => "/ccache" };
+$path = "/usr/lib/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games";
+EOF
+}
+
sbuild_dpkg_log_export() {
export dpkg_partial_log="${1}"
@@ -152,3 +161,19 @@ sbuild_dpkg_log_export() {
cat ${dpkg_partial_log} >> ${SCHROOT_DIR}/tmp/dpkg_common.log
) 9>"${SCHROOT_DIR}/tmp/dpkg_common.log.lock"
}
+
+# additional mounts managed by sbuild
+sbuild_add_unshare_mounts() {
+ mkdir -p "${CCACHE_DIR}"
+ # sbuild id from https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1110942
+ setfacl -m u:${UNSHARE_SUBUID_BASE}:rwX -m u:${@int(d.getVar('UNSHARE_SUBUID_BASE')) + 999}:rwx "${CCACHE_DIR}"
+
+ cat <<'EOF' >> ${SBUILD_CONFIG}
+$unshare_bind_mounts = [
+ { directory => '${WORKDIR}/rootfs', mountpoint => '${PP}/rootfs' },
+ { directory => '${WORKDIR}/isar-apt/${DISTRO}-${DISTRO_ARCH}/apt/${DISTRO}', mountpoint => '/isar-apt' },
+ { directory => '${REPO_BASE_DIR}', mountpoint => '/base-apt' },
+ { directory => "${CCACHE_DIR}", mountpoint => "/ccache" }
+];
+EOF
+}
diff --git a/meta/classes-recipe/sdk.bbclass b/meta/classes-recipe/sdk.bbclass
index 074f5ef8..64a501d2 100644
--- a/meta/classes-recipe/sdk.bbclass
+++ b/meta/classes-recipe/sdk.bbclass
@@ -74,13 +74,20 @@ rootfs_configure_isar_apt_dir() {
ROOTFS_POSTPROCESS_COMMAND:prepend:class-sdk = "sdkchroot_configscript "
sdkchroot_configscript () {
- run_in_chroot ${ROOTFSDIR} /configscript.sh ${DISTRO_ARCH}
+ run_privileged_here <<'EOF'
+ set -e
+ ${@insert_isar_mounts(d, d.getVar('ROOTFSDIR'), d.getVar('ROOTFS_MOUNTS')) if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else ''}
+ cp -rL /etc/resolv.conf '${ROOTFSDIR}/etc'
+ chroot ${ROOTFSDIR} /configscript.sh ${DISTRO_ARCH}
+EOF
}
ROOTFS_POSTPROCESS_COMMAND:append:class-sdk = " sdkchroot_finalize"
sdkchroot_finalize() {
- rootfs_do_umounts
+ if [ "${ISAR_CHROOT_MODE}" = "schroot" ]; then
+ rootfs_do_umounts_priv
+ fi
# Remove setup scripts
run_privileged rm -f ${ROOTFSDIR}/chroot-setup.sh ${ROOTFSDIR}/configscript.sh
diff --git a/meta/conf/bitbake.conf b/meta/conf/bitbake.conf
index 0f84e715..1c3a6f4a 100644
--- a/meta/conf/bitbake.conf
+++ b/meta/conf/bitbake.conf
@@ -72,7 +72,7 @@ KERNEL_FILE:arm64 ?= "vmlinux"
MACHINEOVERRIDES ?= "${MACHINE}"
DISTROOVERRIDES ?= "${DISTRO}"
-OVERRIDES = "${PACKAGE_ARCH}:${MACHINEOVERRIDES}:${DISTROOVERRIDES}:${BASE_DISTRO_CODENAME}:forcevariable"
+OVERRIDES = "${PACKAGE_ARCH}:${MACHINEOVERRIDES}:${DISTROOVERRIDES}:${BASE_DISTRO_CODENAME}:${ISAR_CHROOT_MODE}:forcevariable"
FILESOVERRIDES = "${PACKAGE_ARCH}:${MACHINE}"
# Setting default QEMU_ARCH variables for different DISTRO_ARCH:
@@ -151,6 +151,10 @@ ISAR_APT_RETRIES ??= "${@'10' if bb.utils.to_boolean(d.getVar('ISAR_USE_APT_SNAP
ISAR_APT_DELAY_MAX ??= "${@'600' if bb.utils.to_boolean(d.getVar('ISAR_USE_APT_SNAPSHOT')) else ''}"
ISAR_APT_SNAPSHOT_TIMESTAMP ??= "${SOURCE_DATE_EPOCH}"
+# Rootless build execution
+ISAR_ROOTLESS ??= "0"
+ISAR_CHROOT_MODE ??= "${@'unshare' if bb.utils.to_boolean(d.getVar('ISAR_ROOTLESS')) else 'schroot'}"
+
# Default parallelism and resource usage for xz
XZ_MEMLIMIT ?= "50%"
XZ_THREADS ?= "${@oe.utils.cpu_count(at_least=2)}"
@@ -206,6 +210,7 @@ CCACHE_DEBUG ?= "0"
# Variables for tasks marking
# Long term TODO: get rid of sudo marked tasks
TASK_USE_NETWORK = "1"
+# nested namespacing requires this as well
TASK_USE_SUDO = "1"
TASK_USE_NETWORK_AND_SUDO = "1"
diff --git a/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc b/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc
index 8ca295b7..c90bc59c 100644
--- a/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc
+++ b/meta/recipes-core/isar-mmdebstrap/isar-mmdebstrap.inc
@@ -178,6 +178,8 @@ do_bootstrap() {
umount \$1/$base_apt_tmp && rm ${WORKDIR}/mmtmpdir && \
umount $base_apt_tmp && rm -rf --one-file-system $base_apt_tmp"
else
+ # prepare dl_dir for access from both sides (local and rootfs)
+ create_chroot_parent_dir ${WORKDIR}/dl_dir
deb_dl_dir_import "${WORKDIR}/dl_dir" "${BOOTSTRAP_BASE_DISTRO}-${BASE_DISTRO_CODENAME}"
bootstrap_list="${WORKDIR}/sources.list.d/bootstrap.list"
@@ -197,6 +199,7 @@ do_bootstrap() {
-o Dir::State="$1/var/lib/apt" \
-o Dir::Etc="$1/etc/apt" \
-o Dir::Cache="$1/var/cache/apt" \
+ ${@'-o APT::Sandbox::User=root' if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else ''} \
-o Apt::Architecture="${BOOTSTRAP_DISTRO_ARCH}" \
${@get_apt_opts(d, '-o')}'
extra_essential="$extra_essential && $syncout"
@@ -214,13 +217,14 @@ do_bootstrap() {
# Cleanup mounts if fails
trap 'exit 1' INT HUP QUIT TERM ALRM USR1
- trap 'bootstrap_cleanup' EXIT
+ trap ${@'true' if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else 'bootstrap_cleanup'} EXIT
# Create lock file so that it is owned by the user running the build (not root)
mkdir -p ${DEBDIR}
touch ${DEB_DL_LOCK}
- run_privileged TMPDIR="${BOOTSTRAP_TMPDIR}" mmdebstrap $bootstrap_args \
+ ${@'' if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else 'run_privileged'} \
+ TMPDIR="${BOOTSTRAP_TMPDIR}" mmdebstrap $bootstrap_args \
$arch_param \
--mode=unshare \
${MMHOOKS} \
@@ -239,6 +243,7 @@ do_bootstrap() {
--customize-hook='sed -i "/en_US.UTF-8 UTF-8/s/^#//g" "$1/etc/locale.gen"' \
--customize-hook='chroot "$1" /usr/sbin/locale-gen' \
--customize-hook='chroot "$1" /usr/bin/apt-get -y clean' \
+ ${@'--skip=output/dev' if d.getVar('ISAR_CHROOT_MODE') == 'unshare' else ''} \
--skip=cleanup/apt \
--skip=download/empty \
${@get_apt_opts(d, '--aptopt')} \
@@ -252,7 +257,8 @@ do_bootstrap() {
if [ "${ISAR_USE_CACHED_BASE_REPO}" != "1" ]; then
deb_dl_dir_export "${WORKDIR}/dl_dir" "${BOOTSTRAP_BASE_DISTRO}-${BASE_DISTRO_CODENAME}"
- run_privileged rm -rf --one-file-system "${WORKDIR}/dl_dir"
+ run_privileged find ${WORKDIR}/dl_dir -maxdepth 1 -mindepth 1 -exec rm -rf --one-file-system "{}" \;
+ rmdir ${WORKDIR}/dl_dir
fi
}
addtask bootstrap before do_build after do_generate_keyrings
diff --git a/meta/recipes-devtools/sbuild-chroot/sbuild-chroot.inc b/meta/recipes-devtools/sbuild-chroot/sbuild-chroot.inc
index 61d37760..7a778d8c 100644
--- a/meta/recipes-devtools/sbuild-chroot/sbuild-chroot.inc
+++ b/meta/recipes-devtools/sbuild-chroot/sbuild-chroot.inc
@@ -66,8 +66,28 @@ ROOTFS_POSTPROCESS_COMMAND:remove = "rootfs_cleanup_base_apt"
DEPLOY_SCHROOT = "${@d.getVar('SCHROOT_' + d.getVar('SBUILD_VARIANT').upper() + '_DIR')}${SBUILD_SCHROOT_SUFFIX}"
-do_sbuildchroot_deploy[dirs] = "${DEPLOY_DIR}/schroot-${SBUILD_VARIANT}"
-do_sbuildchroot_deploy() {
+sbuildchroot_deploy_tree() {
ln -Tfsr "${ROOTFSDIR}" "${DEPLOY_SCHROOT}"
}
+sbuildchroot_deploy_tar() {
+ lopts="--one-file-system --exclude=var/cache/apt/archives --exclude=isar-apt"
+ # we cannot use pzstd, as this results in a different magic
+ # (zstd skippable frame) which is not detected by sbuild
+ # https://salsa.debian.org/debian/sbuild/-/blob/d975d388a98627a0d7d112791e441c27a6d529df/lib/Sbuild/ChrootUnshare.pm#L608
+ ZSTD="zstd -${SSTATE_ZSTD_CLEVEL} -T${ZSTD_THREADS}"
+ run_privileged \
+ tar -C ${ROOTFSDIR} -cpS $lopts ${ROOTFS_TAR_ATTR_FLAGS} . \
+ | $ZSTD > ${DEPLOY_SCHROOT}.tar.zst
+ # cleanup extracted rootfs
+ run_privileged rm -rf ${ROOTFSDIR}
+}
+
+do_sbuildchroot_deploy[network] = "${TASK_USE_SUDO}"
+do_sbuildchroot_deploy[dirs] += "${DEPLOY_DIR}/schroot-${SBUILD_VARIANT}"
+python do_sbuildchroot_deploy() {
+ if d.getVar('ISAR_CHROOT_MODE') == 'unshare':
+ bb.build.exec_func('sbuildchroot_deploy_tar', d)
+ else:
+ bb.build.exec_func('sbuildchroot_deploy_tree', d)
+}
addtask sbuildchroot_deploy before do_build after do_rootfs
--
2.51.0
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260218115827.3947145-12-felix.moessbauer%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC 12/12] apt-fetcher: implement support for unshare backend
2026-02-18 11:58 [RFC 00/12] add support to build isar unprivileged 'Felix Moessbauer' via isar-users
` (10 preceding siblings ...)
2026-02-18 11:58 ` [RFC 11/12] add support for fully rootless builds 'Felix Moessbauer' via isar-users
@ 2026-02-18 11:58 ` 'Felix Moessbauer' via isar-users
2026-02-18 18:20 ` [RFC 00/12] add support to build isar unprivileged 'Jan Kiszka' via isar-users
12 siblings, 0 replies; 19+ messages in thread
From: 'Felix Moessbauer' via isar-users @ 2026-02-18 11:58 UTC (permalink / raw)
To: isar-users; +Cc: quirin.gylstorff, Felix Moessbauer
Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com>
---
meta/lib/aptsrc_fetcher.py | 78 ++++++++++++++++++++++++++++++++++++++
1 file changed, 78 insertions(+)
diff --git a/meta/lib/aptsrc_fetcher.py b/meta/lib/aptsrc_fetcher.py
index 37c84fa7..5cacbec2 100644
--- a/meta/lib/aptsrc_fetcher.py
+++ b/meta/lib/aptsrc_fetcher.py
@@ -7,10 +7,13 @@ from bb.fetch2 import FetchError
from bb.fetch2 import FetchMethod
from bb.fetch2 import logger
from bb.fetch2 import runfetchcmd
+import os
class AptSrc(FetchMethod):
@classmethod
def create(cls, d):
+ if d.getVar('ISAR_CHROOT_MODE') == 'unshare':
+ return AptSrcUnshare()
return AptSrcSchroot()
def supports(self, ud, d):
@@ -92,3 +95,78 @@ class AptSrcSchroot(AptSrc):
finally:
runfetchcmd(f'schroot -q -f -e -c {session_id}', d)
bb.build.exec_func('schroot_delete_configs', d)
+
+
+class AptSrcUnshare(AptSrc):
+ def _setup_chroot(self, rootfsdir, d):
+ sbuild_chroot = d.getVar('SBUILD_CHROOT')
+ workdir = d.getVar('WORKDIR')
+ uid_base = d.getVar('UNSHARE_SUBUID_BASE')
+ unshare_cmd = d.getVar('RUN_PRIVILEGED_CMD')
+
+ runfetchcmd(
+ f'''
+setfacl -m u:{uid_base}:rwX {workdir}
+{unshare_cmd} /bin/bash -s <<EOF
+ mkdir -p {rootfsdir}
+ tar -xf {sbuild_chroot} -C {rootfsdir}
+ cp /etc/resolv.conf {os.path.join(rootfsdir, 'etc/resolv.conf')}
+EOF
+ ''', d)
+ logger.info(f'rootfs extracted to: {rootfsdir}')
+
+ def _teardown_chroot(self, rootfsdir, d):
+ unshare_cmd = d.getVar('RUN_PRIVILEGED_CMD')
+ runfetchcmd(f'{unshare_cmd} rm -rf {rootfsdir}', d)
+
+ def download(self, ud, d):
+ bb.utils.exec_flat_python_func('isar_export_proxies', d)
+
+ workdir = d.getVar('WORKDIR')
+ rootfsdir = os.path.join(workdir, 'rootfs-fetcher')
+ unshare_cmd = d.getVar('RUN_PRIVILEGED_CMD')
+
+ if not os.path.exists(os.path.join(rootfsdir, 'etc')):
+ self._setup_chroot(rootfsdir, d)
+
+ repo_isar_dir = d.getVar('REPO_ISAR_DIR')
+ lockfile = bb.utils.lockfile(f'{repo_isar_dir}/isar.lock')
+ os.makedirs(self.localpath(ud, d))
+
+ try:
+ runfetchcmd(f'''
+set -e
+{unshare_cmd} /bin/bash -s <<'EOF' | tar -C {self.localpath(ud, d)} -x
+ chroot {rootfsdir} /bin/bash -c '
+ set -e
+ TMPDIR=$(mktemp -d)
+ mkdir -p $TMPDIR/{ud.localfile}
+ cd $TMPDIR/{ud.localfile}
+ apt-get -y -oDebug::NoLocking=1 --download-only --only-source source {ud.src_package} >/dev/null;
+ tar -c --owner=0 --group=0 --numeric-owner .
+ '
+EOF
+ ''', d)
+ except (OSError, FetchError):
+ raise
+ finally:
+ bb.utils.unlockfile(lockfile)
+ self._teardown_chroot(rootfsdir, d)
+
+ def unpack(self, ud, rootdir, d):
+ workdir = d.getVar('WORKDIR')
+ rootfsdir = os.path.join(workdir, 'rootfs-fetcher')
+ extractto = f'{d.getVar("S")}.dpkg'
+ bb.utils.remove(extractto, recurse=True)
+
+ try:
+ runfetchcmd(f'''
+ set -e
+ find {self.localpath(ud, d)} -print -type f -name '*.dsc' -exec dpkg-source -su -x {{}} {extractto} \\;
+ find {extractto} -mindepth 1 -maxdepth 1 -exec mv {{}} {d.getVar('S')}/ \\;
+ ''', d)
+ except (OSError, FetchError):
+ raise
+ finally:
+ bb.utils.remove(extractto, recurse=True)
+ self._teardown_chroot(rootfsdir, d)
--
2.51.0
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260218115827.3947145-13-felix.moessbauer%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC 02/12] deb-dl-dir: export without root privileges
2026-02-18 11:58 ` [RFC 02/12] deb-dl-dir: export without root privileges 'Felix Moessbauer' via isar-users
@ 2026-02-18 14:01 ` 'Jan Kiszka' via isar-users
0 siblings, 0 replies; 19+ messages in thread
From: 'Jan Kiszka' via isar-users @ 2026-02-18 14:01 UTC (permalink / raw)
To: Felix Moessbauer, isar-users; +Cc: quirin.gylstorff
On 18.02.26 12:58, 'Felix Moessbauer' via isar-users wrote:
> The archive is world readable, so we can access it without root
> privileges. By that, the files in the download dir are also owned by the
> calling user, making the additional chown obsolete.
>
> Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com>
> ---
> meta/classes-recipe/deb-dl-dir.bbclass | 5 ++---
> 1 file changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/meta/classes-recipe/deb-dl-dir.bbclass b/meta/classes-recipe/deb-dl-dir.bbclass
> index 7ebc3526..76c2435f 100644
> --- a/meta/classes-recipe/deb-dl-dir.bbclass
> +++ b/meta/classes-recipe/deb-dl-dir.bbclass
> @@ -153,7 +153,7 @@ deb_dl_dir_export() {
> isar_debs="$(${SCRIPTSDIR}/lockrun.py -r -f '${REPO_ISAR_DIR}/isar.lock' -c \
> "find '${REPO_ISAR_DIR}/${DISTRO}' -name '*.deb' -print")"
>
> - flock "${pc}".lock sudo -Es << 'EOSUDO'
> + flock "${pc}".lock /bin/bash -s << 'EOF'
Do we need bash here or would /bin/sh suffice?
Jan
> set -e
> printenv | grep -q BB_VERBOSE_LOGS && set -x
>
> @@ -170,6 +170,5 @@ deb_dl_dir_export() {
> ln -Pf "${p}" "${pc}" 2>/dev/null ||
> cp -n "${p}" "${pc}"
> done
> - chown -R ${owner} "${pc}"
> -EOSUDO
> +EOF
> }
--
Siemens AG, Foundational Technologies
Linux Expert Center
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/5775f816-da05-4d81-8e24-540cf5c29a4e%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC 04/12] introduce wrappers for privileged execution
2026-02-18 11:58 ` [RFC 04/12] introduce wrappers for privileged execution 'Felix Moessbauer' via isar-users
@ 2026-02-18 14:11 ` 'Jan Kiszka' via isar-users
0 siblings, 0 replies; 19+ messages in thread
From: 'Jan Kiszka' via isar-users @ 2026-02-18 14:11 UTC (permalink / raw)
To: Felix Moessbauer, isar-users; +Cc: quirin.gylstorff
On 18.02.26 12:58, 'Felix Moessbauer' via isar-users wrote:
> As a preparation to enable rootless builds, we introduce wrappers for
> common cases of privileged command execution. The wrappers are defined
> in the base class where later on the executor dispatching will be
> implemented as well.
>
> The wrappers are introduced throughout the whole codebase and downstream
> layers are also encouraged to use them to increase compatibility with
> upcoming API changes.
>
> Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com>
> ---
> RECIPE-API-CHANGELOG.md | 16 ++++
> meta/classes-global/base.bbclass | 30 +++++++
> meta/classes-recipe/deb-dl-dir.bbclass | 4 +-
> meta/classes-recipe/dpkg-base.bbclass | 2 +-
> meta/classes-recipe/dpkg.bbclass | 2 +-
> .../image-account-extension.bbclass | 4 +-
> .../image-locales-extension.bbclass | 4 +-
> .../image-postproc-extension.bbclass | 30 +++----
> meta/classes-recipe/image.bbclass | 14 +--
> .../imagetypes_container.bbclass | 26 +++---
> meta/classes-recipe/imagetypes_wic.bbclass | 4 +-
> meta/classes-recipe/rootfs.bbclass | 88 +++++++++----------
> meta/classes-recipe/sbuild.bbclass | 10 +--
> meta/classes-recipe/sdk.bbclass | 14 +--
> meta/classes/sbom.bbclass | 2 +-
> .../isar-mmdebstrap/isar-mmdebstrap.inc | 12 +--
> .../unittests/test_image_account_extension.py | 9 +-
> 17 files changed, 157 insertions(+), 114 deletions(-)
>
> diff --git a/RECIPE-API-CHANGELOG.md b/RECIPE-API-CHANGELOG.md
> index 0bad8a44..bc40a403 100644
> --- a/RECIPE-API-CHANGELOG.md
> +++ b/RECIPE-API-CHANGELOG.md
> @@ -962,3 +962,19 @@ INSTALLER_UNATTENDED_ABORT_ENABLE = "1"
> # Optional: set countdown timeout in seconds (default 5)
> INSTALLER_UNATTENDED_ABORT_TIMEOUT = "5"
> ```
> +
> +### Execution of privileged commands
> +
> +When operations require higher privileges than those available to the build user,
> +the following helper functions shall be used:
> +
> +**run_privileged**: Run a command as root while preserving the environment.
> +
> +**run_privileged_here**: Execute commands provided via stdin in a root shell.
From their names, these two commands sound to me like they differ in
where they are running the commands, not how. But from the description
it is the latter. "run_privileged_from_stdin"?
> +
> +**run_in_chroot**: Run a command within a chroot environment. The first argument
> +specifies the rootfs path.
> +
> +Using these helpers instead of direct `sudo` invocations centralizes platform-specific
> +privileged execution logic in `base.bbclass`. Direct use of `sudo` is discouraged
> +in downstream layers.
Are there sudos left in Isar after this conversion? If not, should we
start to catch sudo as invalid afterwards?
Jan
--
Siemens AG, Foundational Technologies
Linux Expert Center
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/3b3f160d-f71b-4c2f-bcf6-ef5a2ef48baa%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC 11/12] add support for fully rootless builds
2026-02-18 11:58 ` [RFC 11/12] add support for fully rootless builds 'Felix Moessbauer' via isar-users
@ 2026-02-18 16:09 ` 'Jan Kiszka' via isar-users
2026-02-18 16:50 ` 'Jan Kiszka' via isar-users
1 sibling, 0 replies; 19+ messages in thread
From: 'Jan Kiszka' via isar-users @ 2026-02-18 16:09 UTC (permalink / raw)
To: Felix Moessbauer, isar-users; +Cc: quirin.gylstorff
On 18.02.26 12:58, 'Felix Moessbauer' via isar-users wrote:
> Currently isar requires passwordless sudo and an environment
> where mounting file systems is possible. This has proven problematic
> for security reasons, both when running in a privileged container or
> locally.
>
> To solve this, we implement fully rootless builds that rely on the
> unshare syscall which allows us to avoid sudo and instead operate in
> temporary kernel namespaces as a user that is just privileged within
> that namespace. This comes with some challenges regarding the handling
> of mounts (they are cleared when leaving the namespace), as well as
> cross namespace deployments (the outer user might not be able to access
> the inner data). For that, we rework the handling of mounts and artifact
> passing to make it compatible with both chroot modes (schroot and
> unshare).
>
> Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com>
> ---
> Kconfig | 2 +-
> RECIPE-API-CHANGELOG.md | 29 +++++++
> doc/user_manual.md | 2 +
> meta/classes-global/base.bbclass | 67 ++++++++++++++-
> meta/classes-recipe/deb-dl-dir.bbclass | 9 +-
> meta/classes-recipe/dpkg-base.bbclass | 16 +++-
> meta/classes-recipe/dpkg.bbclass | 14 +++-
> .../image-locales-extension.bbclass | 9 +-
> .../image-tools-extension.bbclass | 82 +++++++++++++++++++
> meta/classes-recipe/rootfs.bbclass | 53 +++++++++---
> meta/classes-recipe/sbuild.bbclass | 27 +++++-
> meta/classes-recipe/sdk.bbclass | 11 ++-
> meta/conf/bitbake.conf | 7 +-
> .../isar-mmdebstrap/isar-mmdebstrap.inc | 12 ++-
> .../sbuild-chroot/sbuild-chroot.inc | 24 +++++-
> 15 files changed, 332 insertions(+), 32 deletions(-)
>
> diff --git a/Kconfig b/Kconfig
> index 683c0da5..5ef2bfcb 100644
> --- a/Kconfig
> +++ b/Kconfig
> @@ -14,7 +14,7 @@ config KAS_INCLUDE_MAIN
>
> config KAS_BUILD_SYSTEM
> string
> - default "isar"
> + default "isar-rootless"
>
> source "kas/machine/Kconfig"
> source "kas/distro/Kconfig"
> diff --git a/RECIPE-API-CHANGELOG.md b/RECIPE-API-CHANGELOG.md
> index f80630a0..29bf7590 100644
> --- a/RECIPE-API-CHANGELOG.md
> +++ b/RECIPE-API-CHANGELOG.md
> @@ -990,3 +990,32 @@ rootless builds. For that, the deployment of images happens in two steps:
>
> Conversion commands need to follow this strategy as well, but can read the image
> (prior to conversion) from `${IMAGE_FILE_CHROOT}`.
> +
> +### Rootless isar execution
> +
> +Isar is able to run without the need for `sudo` in an environment that
> +allows unprivileged users to unshare the kernels `user namespace`. Further,
> +a sufficiently large set of sub ids needs to be configured in `/etc/subuid` / `etc/subgid`.
> +This range should be `> 65536`, but smaller ranges might work as well, depending on the
> +ids used in the rootfs.
> +
> +A simple check if rootless is supported can be done by running:
> +
> +```bash
> +mmdebstrap --unshare-helper /bin/echo "rootless supported" || echo "rootless not supported"
> +```
> +
> +On many systems, setting the following settings is sufficent, but no general guidance
> +can be provided.
> +
> +```bash
> +echo 0 | sudo tee -a /proc/sys/kernel/apparmor_restrict_unprivileged_userns
This might be an Ubuntu patch, right? Should be clarified.
> +echo 1 | sudo tee -a /proc/sys/kernel/unprivileged_userns_clone
This is Debian-only (see e.g.
https://salsa.debian.org/kernel-team/linux/-/blob/debian/latest/debian/patches/debian/add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by-default.patch?ref_type=heads).
But it's on by default now.
Jan
--
Siemens AG, Foundational Technologies
Linux Expert Center
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/da499bc0-a3f6-48de-884a-8e9a3e435b85%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC 11/12] add support for fully rootless builds
2026-02-18 11:58 ` [RFC 11/12] add support for fully rootless builds 'Felix Moessbauer' via isar-users
2026-02-18 16:09 ` 'Jan Kiszka' via isar-users
@ 2026-02-18 16:50 ` 'Jan Kiszka' via isar-users
1 sibling, 0 replies; 19+ messages in thread
From: 'Jan Kiszka' via isar-users @ 2026-02-18 16:50 UTC (permalink / raw)
To: Felix Moessbauer, isar-users; +Cc: quirin.gylstorff
On 18.02.26 12:58, 'Felix Moessbauer' via isar-users wrote:
> Currently isar requires passwordless sudo and an environment
> where mounting file systems is possible. This has proven problematic
> for security reasons, both when running in a privileged container or
> locally.
>
> To solve this, we implement fully rootless builds that rely on the
> unshare syscall which allows us to avoid sudo and instead operate in
> temporary kernel namespaces as a user that is just privileged within
> that namespace. This comes with some challenges regarding the handling
> of mounts (they are cleared when leaving the namespace), as well as
> cross namespace deployments (the outer user might not be able to access
> the inner data). For that, we rework the handling of mounts and artifact
> passing to make it compatible with both chroot modes (schroot and
> unshare).
>
> Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com>
> ---
> Kconfig | 2 +-
> RECIPE-API-CHANGELOG.md | 29 +++++++
> doc/user_manual.md | 2 +
> meta/classes-global/base.bbclass | 67 ++++++++++++++-
> meta/classes-recipe/deb-dl-dir.bbclass | 9 +-
> meta/classes-recipe/dpkg-base.bbclass | 16 +++-
> meta/classes-recipe/dpkg.bbclass | 14 +++-
> .../image-locales-extension.bbclass | 9 +-
> .../image-tools-extension.bbclass | 82 +++++++++++++++++++
> meta/classes-recipe/rootfs.bbclass | 53 +++++++++---
> meta/classes-recipe/sbuild.bbclass | 27 +++++-
> meta/classes-recipe/sdk.bbclass | 11 ++-
> meta/conf/bitbake.conf | 7 +-
> .../isar-mmdebstrap/isar-mmdebstrap.inc | 12 ++-
> .../sbuild-chroot/sbuild-chroot.inc | 24 +++++-
> 15 files changed, 332 insertions(+), 32 deletions(-)
>
> diff --git a/Kconfig b/Kconfig
> index 683c0da5..5ef2bfcb 100644
> --- a/Kconfig
> +++ b/Kconfig
> @@ -14,7 +14,7 @@ config KAS_INCLUDE_MAIN
>
> config KAS_BUILD_SYSTEM
> string
> - default "isar"
> + default "isar-rootless"
You didn't patch kas/isar.yaml as well - might be a trap for people not
using the menu.
Jan
--
Siemens AG, Foundational Technologies
Linux Expert Center
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/fe587e5b-9d7d-432b-aee5-df18d10a5743%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC 00/12] add support to build isar unprivileged
2026-02-18 11:58 [RFC 00/12] add support to build isar unprivileged 'Felix Moessbauer' via isar-users
` (11 preceding siblings ...)
2026-02-18 11:58 ` [RFC 12/12] apt-fetcher: implement support for unshare backend 'Felix Moessbauer' via isar-users
@ 2026-02-18 18:20 ` 'Jan Kiszka' via isar-users
2026-02-18 18:31 ` 'Jan Kiszka' via isar-users
12 siblings, 1 reply; 19+ messages in thread
From: 'Jan Kiszka' via isar-users @ 2026-02-18 18:20 UTC (permalink / raw)
To: Felix Moessbauer, isar-users; +Cc: quirin.gylstorff
On 18.02.26 12:58, 'Felix Moessbauer' via isar-users wrote:
> Dear isar-users,
>
> currently isar requires password-less sudo and an environment
> where mounting file systems is possible. This has proven problematic
> for security reasons, both when running in a privileged container or
> locally.
>
> To solve this, we implement fully rootless builds that rely on the
> unshare syscall which allows us to avoid sudo and instead operate in
> temporary kernel namespaces as a user that is just privileged within
> that namespace. This comes with some challenges regarding the handling
> of mounts (they are cleared when leaving the namespace), as well as
> cross namespace deployments (the outer user might not be able to access
> the inner data). For that, we rework the handling of mounts and artifact
> passing to make it compatible with both chroot modes (schroot and
> unshare).
>
> The patches 1-10 align the file permissions of deployments and artifacts
> to avoid the use of chown (which will not work anymore across uid
> boundaries). In addition, helpers are introduced to perform privileged
> operations, which simplifies the migration of existing layers.
>
> The patches 11 and 12 introduce the unshare mode, which can be executed
> as a normal user and does not require root. To enable this mode, set
> ISAR_ROOTLESS = "1".
>
> While the series is by far not complete yet, it already passes the DevTest
> CI. Know issues are currently:
>
> - no support for VM and container images
> - unprivileged cleanup of the build/tmp dir is non trivial
> - sporadic issues on partial rebuilds on rootfs_install_sstate_finalize
> - interfaces between kas and isar need to be defined
>
> Note, that this series can be tested on a custom kas-container build
> provided in [1]. Hints how to migrate downstream layers are provided
> in the API changelog.
>
> [1] https://groups.google.com/g/kas-devel/c/NWQFCU2aUHg
>
> Best regards,
> Felix Moessbauer
> Siemens AG
>
> Felix Moessbauer (12):
> refactor bootstrap: store rootfs tar with user permissions
> deb-dl-dir: export without root privileges
> download debs without locking
> introduce wrappers for privileged execution
> bootstrap: move cleanup trap to function
> rootfs: rework sstate caching of rootfs artifact
> rootfs_generate_initramfs: rework deployment to avoid chowning
> wic: rework image deploy logic to deploy under correct user
> use bitbake function to generate mounting scripts
> apt-fetcher: prepare for chroot specific fetching
> add support for fully rootless builds
> apt-fetcher: implement support for unshare backend
>
> Kconfig | 2 +-
> RECIPE-API-CHANGELOG.md | 57 +++++
> doc/user_manual.md | 2 +
> meta/classes-global/base.bbclass | 93 ++++++++
> meta/classes-recipe/deb-dl-dir.bbclass | 20 +-
> meta/classes-recipe/dpkg-base.bbclass | 20 +-
> meta/classes-recipe/dpkg-source.bbclass | 2 +-
> meta/classes-recipe/dpkg.bbclass | 16 +-
> .../image-account-extension.bbclass | 4 +-
> .../image-locales-extension.bbclass | 13 +-
> .../image-postproc-extension.bbclass | 30 +--
> .../image-tools-extension.bbclass | 96 +++++++-
> meta/classes-recipe/image.bbclass | 24 +-
> meta/classes-recipe/imagetypes.bbclass | 47 ++--
> .../imagetypes_container.bbclass | 26 +--
> meta/classes-recipe/imagetypes_wic.bbclass | 12 +-
> meta/classes-recipe/rootfs.bbclass | 221 ++++++++++--------
> meta/classes-recipe/sbuild.bbclass | 37 ++-
> meta/classes-recipe/sdk.bbclass | 23 +-
> meta/classes-recipe/squashfs.bbclass | 2 +-
> meta/classes/sbom.bbclass | 2 +-
> meta/conf/bitbake.conf | 7 +-
> meta/lib/aptsrc_fetcher.py | 90 ++++++-
> .../isar-mmdebstrap/isar-mmdebstrap.inc | 47 ++--
> .../sbuild-chroot/sbuild-chroot.inc | 24 +-
> .../unittests/test_image_account_extension.py | 9 +-
> 26 files changed, 691 insertions(+), 235 deletions(-)
>
Hmm, just testing xenomai-images with this and minimal changes for
itself (buildsystem update). It seems to build the kernel - put only on
a single core. This part looks still fine:
# $PARALLEL_MAKE
# set? /work/build/../isar/meta/conf/bitbake.conf:135
# "-j ${@bb.utils.cpu_count()}"
PARALLEL_MAKE="-j 16"
But the "-j 16" does not end up in the actually make call of the kernel
build. How could we possibly lose this?
I wanted to test if rootfull mode with your patches applied may answer
this, but:
...
ERROR: Unable to parse Var <UNSHARE_SUBUID_BASE[:=]>
Traceback (most recent call last):
File "Var <UNSHARE_SUBUID_BASE[:=]>", line 1, in <module>
File "/work/build/../isar/meta/classes-global/base.bbclass", line 396, in get_subid_range(idmap='/etc/subuid', d=<bb.data_smart.DataSmart object at 0x7f73357b7110>):
user, base, cnt = e.split(':')
> if user == os.getuid() or user == os.getlogin():
return base, cnt
bb.data_smart.ExpansionError: Failure expanding variable UNSHARE_SUBUID_BASE[:=], expression was ${@get_subid_range('/etc/subuid', d)[0]} which triggered exception OSError: [Errno -25] Unknown error -25
The variable dependency chain for the failure is: UNSHARE_SUBUID_BASE[:=]
2026-02-18 19:18:28 - ERROR - Command "/work/isar/bitbake/bin/bitbake -c build linux-xenomai-3" failed with error 1
I bet you can reproduce with plane Isar and a linux-mailine build as
well.
Jan
--
Siemens AG, Foundational Technologies
Linux Expert Center
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/cda4b0c2-3296-43df-ba0d-8e51c17495ea%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC 00/12] add support to build isar unprivileged
2026-02-18 18:20 ` [RFC 00/12] add support to build isar unprivileged 'Jan Kiszka' via isar-users
@ 2026-02-18 18:31 ` 'Jan Kiszka' via isar-users
0 siblings, 0 replies; 19+ messages in thread
From: 'Jan Kiszka' via isar-users @ 2026-02-18 18:31 UTC (permalink / raw)
To: Felix Moessbauer, isar-users; +Cc: quirin.gylstorff
On 18.02.26 19:20, Jan Kiszka wrote:
> On 18.02.26 12:58, 'Felix Moessbauer' via isar-users wrote:
>> Dear isar-users,
>>
>> currently isar requires password-less sudo and an environment
>> where mounting file systems is possible. This has proven problematic
>> for security reasons, both when running in a privileged container or
>> locally.
>>
>> To solve this, we implement fully rootless builds that rely on the
>> unshare syscall which allows us to avoid sudo and instead operate in
>> temporary kernel namespaces as a user that is just privileged within
>> that namespace. This comes with some challenges regarding the handling
>> of mounts (they are cleared when leaving the namespace), as well as
>> cross namespace deployments (the outer user might not be able to access
>> the inner data). For that, we rework the handling of mounts and artifact
>> passing to make it compatible with both chroot modes (schroot and
>> unshare).
>>
>> The patches 1-10 align the file permissions of deployments and artifacts
>> to avoid the use of chown (which will not work anymore across uid
>> boundaries). In addition, helpers are introduced to perform privileged
>> operations, which simplifies the migration of existing layers.
>>
>> The patches 11 and 12 introduce the unshare mode, which can be executed
>> as a normal user and does not require root. To enable this mode, set
>> ISAR_ROOTLESS = "1".
>>
>> While the series is by far not complete yet, it already passes the DevTest
>> CI. Know issues are currently:
>>
>> - no support for VM and container images
>> - unprivileged cleanup of the build/tmp dir is non trivial
>> - sporadic issues on partial rebuilds on rootfs_install_sstate_finalize
>> - interfaces between kas and isar need to be defined
>>
>> Note, that this series can be tested on a custom kas-container build
>> provided in [1]. Hints how to migrate downstream layers are provided
>> in the API changelog.
>>
>> [1] https://groups.google.com/g/kas-devel/c/NWQFCU2aUHg
>>
>> Best regards,
>> Felix Moessbauer
>> Siemens AG
>>
>> Felix Moessbauer (12):
>> refactor bootstrap: store rootfs tar with user permissions
>> deb-dl-dir: export without root privileges
>> download debs without locking
>> introduce wrappers for privileged execution
>> bootstrap: move cleanup trap to function
>> rootfs: rework sstate caching of rootfs artifact
>> rootfs_generate_initramfs: rework deployment to avoid chowning
>> wic: rework image deploy logic to deploy under correct user
>> use bitbake function to generate mounting scripts
>> apt-fetcher: prepare for chroot specific fetching
>> add support for fully rootless builds
>> apt-fetcher: implement support for unshare backend
>>
>> Kconfig | 2 +-
>> RECIPE-API-CHANGELOG.md | 57 +++++
>> doc/user_manual.md | 2 +
>> meta/classes-global/base.bbclass | 93 ++++++++
>> meta/classes-recipe/deb-dl-dir.bbclass | 20 +-
>> meta/classes-recipe/dpkg-base.bbclass | 20 +-
>> meta/classes-recipe/dpkg-source.bbclass | 2 +-
>> meta/classes-recipe/dpkg.bbclass | 16 +-
>> .../image-account-extension.bbclass | 4 +-
>> .../image-locales-extension.bbclass | 13 +-
>> .../image-postproc-extension.bbclass | 30 +--
>> .../image-tools-extension.bbclass | 96 +++++++-
>> meta/classes-recipe/image.bbclass | 24 +-
>> meta/classes-recipe/imagetypes.bbclass | 47 ++--
>> .../imagetypes_container.bbclass | 26 +--
>> meta/classes-recipe/imagetypes_wic.bbclass | 12 +-
>> meta/classes-recipe/rootfs.bbclass | 221 ++++++++++--------
>> meta/classes-recipe/sbuild.bbclass | 37 ++-
>> meta/classes-recipe/sdk.bbclass | 23 +-
>> meta/classes-recipe/squashfs.bbclass | 2 +-
>> meta/classes/sbom.bbclass | 2 +-
>> meta/conf/bitbake.conf | 7 +-
>> meta/lib/aptsrc_fetcher.py | 90 ++++++-
>> .../isar-mmdebstrap/isar-mmdebstrap.inc | 47 ++--
>> .../sbuild-chroot/sbuild-chroot.inc | 24 +-
>> .../unittests/test_image_account_extension.py | 9 +-
>> 26 files changed, 691 insertions(+), 235 deletions(-)
>>
>
> Hmm, just testing xenomai-images with this and minimal changes for
> itself (buildsystem update). It seems to build the kernel - put only on
> a single core. This part looks still fine:
>
> # $PARALLEL_MAKE
> # set? /work/build/../isar/meta/conf/bitbake.conf:135
> # "-j ${@bb.utils.cpu_count()}"
> PARALLEL_MAKE="-j 16"
>
> But the "-j 16" does not end up in the actually make call of the kernel
> build. How could we possibly lose this?
>
FWIW, I'm no longer seeing that PARALLEL_MAKE is even defined inside
sbuild (this is normally logged). Maybe the different sbuild mode needs
a different way of passing env vars in?
Jan
>
> I wanted to test if rootfull mode with your patches applied may answer
> this, but:
>
> ...
> ERROR: Unable to parse Var <UNSHARE_SUBUID_BASE[:=]>
> Traceback (most recent call last):
> File "Var <UNSHARE_SUBUID_BASE[:=]>", line 1, in <module>
> File "/work/build/../isar/meta/classes-global/base.bbclass", line 396, in get_subid_range(idmap='/etc/subuid', d=<bb.data_smart.DataSmart object at 0x7f73357b7110>):
> user, base, cnt = e.split(':')
> > if user == os.getuid() or user == os.getlogin():
> return base, cnt
> bb.data_smart.ExpansionError: Failure expanding variable UNSHARE_SUBUID_BASE[:=], expression was ${@get_subid_range('/etc/subuid', d)[0]} which triggered exception OSError: [Errno -25] Unknown error -25
> The variable dependency chain for the failure is: UNSHARE_SUBUID_BASE[:=]
>
> 2026-02-18 19:18:28 - ERROR - Command "/work/isar/bitbake/bin/bitbake -c build linux-xenomai-3" failed with error 1
>
> I bet you can reproduce with plane Isar and a linux-mailine build as
> well.
>
> Jan
>
--
Siemens AG, Foundational Technologies
Linux Expert Center
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/f95d77f4-423d-4161-ba99-11ffd65ca6db%40siemens.com.
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2026-02-18 18:32 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-02-18 11:58 [RFC 00/12] add support to build isar unprivileged 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 01/12] refactor bootstrap: store rootfs tar with user permissions 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 02/12] deb-dl-dir: export without root privileges 'Felix Moessbauer' via isar-users
2026-02-18 14:01 ` 'Jan Kiszka' via isar-users
2026-02-18 11:58 ` [RFC 03/12] download debs without locking 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 04/12] introduce wrappers for privileged execution 'Felix Moessbauer' via isar-users
2026-02-18 14:11 ` 'Jan Kiszka' via isar-users
2026-02-18 11:58 ` [RFC 05/12] bootstrap: move cleanup trap to function 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 06/12] rootfs: rework sstate caching of rootfs artifact 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 07/12] rootfs_generate_initramfs: rework deployment to avoid chowning 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 08/12] wic: rework image deploy logic to deploy under correct user 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 09/12] use bitbake function to generate mounting scripts 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 10/12] apt-fetcher: prepare for chroot specific fetching 'Felix Moessbauer' via isar-users
2026-02-18 11:58 ` [RFC 11/12] add support for fully rootless builds 'Felix Moessbauer' via isar-users
2026-02-18 16:09 ` 'Jan Kiszka' via isar-users
2026-02-18 16:50 ` 'Jan Kiszka' via isar-users
2026-02-18 11:58 ` [RFC 12/12] apt-fetcher: implement support for unshare backend 'Felix Moessbauer' via isar-users
2026-02-18 18:20 ` [RFC 00/12] add support to build isar unprivileged 'Jan Kiszka' via isar-users
2026-02-18 18:31 ` 'Jan Kiszka' via isar-users
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox