em is progressing nicely, to the point that it is now very close to produce a correct stage1 from scratch.
Since one of the additional design constraint for portage-cli is that I want to be able to keep everything as unprivileged as possible, now it is time to tackle that annoying bit.
Build systems and root privileges
Most packages usually do not care at all about having privileges, they build as whichever user you are, as long the build and install directories are writable.
Some need something more because at the install phase they need to create device files using mknod or just they want to have dedicated users.
Nice build systems may let you override the root-only bits or just disable them, that's what linuxbrew tends to leverage. But since the plan is to produce complete Gentoo stage3 and not just user-install packages this isn't an option.
To root or not to root
The traditional way get away with that is either become root using sudo for the install phase and be done with that, relying on some kind of sandboxing to avoid surprises.
Another path is to simulate being root without being it, fakeroot is a good example of this approach.
A third way sort of in between, that I'm using in crossdev-stages already, is to leverage more modern linux features to have both sandboxing AND the illusion of being root. hakoniwa and bubblewrap are the best tools to achieve that.
Faking root
When dealing with simulating being root one of the details to consider is how much overhead this adds.
We are using this while building software and this is already time consuming in itself.
LD_PRELOAD
The venerable approach is to just rely on the dynamic linker to interpose over the libc functions we care about (stat, mknod and so on) patch its argument and keep track of the fake creations so when its time to package the files the correct users and permissions are recorded.
This works as long as:
- The binary is dynamically linked
- The dynamic linker listens to you
- You interpose all the functions used in the binary (e.g. stat64 vs stat)
That on Linux distributions is generally the case, but since statically linking is back fashionable we might not want to bet on it.
It has potentially among the least amount of overhead as long as the permission/ownership accounting does not get in the way.
ptrace
If you have to deal with the corner case an approach is to rely on ptrace and do the patching at the syscall level.
This has an higher overhead compared to alternatives, but if we are on Linux, seccomp lets us be more selective, but still the per-call overhead is much larger. Since on macOS it became impractical to use, it also has portability concerns.
Linux namespaces
Linux namespaces make easy to simulate the user id (by having subid offsets) and it is pretty much 0 overhead.
The only problem is that to avoid leaving a large security hole mknod cannot create new devices in the sandbox produced, so it isn't a full solution if we aim to cover also that specific bit of the image/package creation story.
So far
I released pseudoroot since it is already overall nicer and faster than the alternatives and provides enough coverage.
I'm still contributing to fakeroost trying to make it faster even if it works only in Linux, since you never know when static build systems might appear, even if a sandbox based on Landlock and Seatbelt might complete the picture keeping the overhead hopefully low.
Top comments (0)