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:
+5
-3
@@ -2136,9 +2136,11 @@ pub(crate) fn plan_upper_sync(
|
||||
///
|
||||
/// Removals go through the privileged path: the upperdir's entries were
|
||||
/// copy-up'd by whoever wrote them during the build — in a rootless build
|
||||
/// the unprivileged build user (a subuid of the invoking user host-side) —
|
||||
/// so a plain removal by the invoking user fails with EPERM exactly when a
|
||||
/// host-modified file's stale upper copy must go.
|
||||
/// the unprivileged build identity, whose files are the invoking user's
|
||||
/// own host-side under the mapped namespace (a subuid of theirs with the
|
||||
/// setpriv fallback, or of earlier builds) — so a plain removal by the
|
||||
/// invoking user fails with EPERM exactly when a host-modified file's
|
||||
/// stale upper copy must go.
|
||||
pub(crate) fn apply_upper_sync(upper_root: &Path, ops: &[UpperOp]) -> io::Result<usize> {
|
||||
let mut removed_prefixes: Vec<String> = Vec::new();
|
||||
let mut removed = 0;
|
||||
|
||||
Reference in New Issue
Block a user