context,deb: run the rules as a nested-namespace build identity
Rootless builds handed the staged tree to the build user with a recursive chown; through the overlay staging every lower-layer file the chown touched copy-ups — the full data movement of the tree, 19% of a kernel build's wall clock. The rules steps are now flagged and the unshare driver enters the chroot by pivot_root instead of chroot(2), then creates a nested user namespace mapping the context's root onto a fixed build id: the chroot's files are the invoking user's host-side and the context maps that user to uid 0, so the staged tree is owned by the build identity by construction — no chown, no data movement. The kernel refuses user namespace creation to chrooted processes, hence the pivot, and the bind is recursive and taken inside the namespace: a plain bind of the chroot's host-made submounts fails EINVAL on locked children, while the rbind carries them across the pivot, and a fresh /proc is mounted before the old root is shed (umount resolves through /proc/mounts). fakeroot's chown wrappers attempt the real chown and swallow only EPERM; as the mapped identity, root targets are unmapped and fail EINVAL, so mapped builds export FAKEROOTDONTTRYCHOWN — fakeroot's own knob — and the fake ownership is still recorded. Files the build writes come out as the invoking user host-side, which also fixes the silently missing .buildinfo/.changes of rootless builds: the host-side rewrite of debian/files hit a subuid-owned file with EACCES. The wrapper is probed per build; when nested namespaces are unavailable (old util-linux, userns disabled), the previous setpriv plus selective parallel chown handover runs unchanged. A setpriv-era staged tree is handed to the invoking user once, host-side and metadata-only, before the overlay mounts it — afterwards overlayfs serves stale owners from its attribute cache.
This commit is contained in:
+14
-2
@@ -46,8 +46,10 @@ pub enum Phase {
|
||||
/// Drop the resumed tree's input-untracked stamp caches (quirk:
|
||||
/// `resume_clear`)
|
||||
ClearingResumeCaches,
|
||||
/// Create the unprivileged build user and hand the staged tree to
|
||||
/// it (rootless builds)
|
||||
/// Establish the unprivileged build identity for the rules steps
|
||||
/// (rootless builds): a nested user namespace mapping the chroot's
|
||||
/// root ownership onto the identity — the tree needs no chown — or,
|
||||
/// when unavailable, a build user with a chown tree handover
|
||||
PreparingBuildUser,
|
||||
/// debian/rules build
|
||||
Building,
|
||||
@@ -642,6 +644,16 @@ async fn build_binary_package_impl(
|
||||
log::info!(
|
||||
"Reusing the build artifacts of the previous attempt (incremental build)"
|
||||
);
|
||||
// Before the overlay mounts (see the function's doc): a
|
||||
// setpriv-era tree handed over here lets the mapped
|
||||
// build identity run the rules; a failed handover makes
|
||||
// the identity setup fall back to the chown handover.
|
||||
if let Err(e) = local::migrate_upper_ownership(s) {
|
||||
log::warn!(
|
||||
"cannot hand the staged tree to the invoking user \
|
||||
({e}); falling back to the chown handover"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
let staged_path = if let Some(s) = &session {
|
||||
|
||||
Reference in New Issue
Block a user