Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

busybox-sandbox-shell: replace pkgsStatic with useMusl #314845

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

szlend
Copy link
Member

@szlend szlend commented May 26, 2024

Description of changes

Nix requires a static build of busybox for /bin/sh. However we can't actually use the main busybox derivation for this, because it links against glibc, and glibc is famously difficult to statically link against. For this reason Nix uses busybox-sandbox-shell which is configured to build with musl via pkgsStatic.

However this is not ideal:

  • Using pkgsStatic slows down eval time by instantiating another instance of nixpkgs.
  • pkgsStatic uses a different stdenv, so we need to bootstrap another compiler just to build busybox. This wastes a ton of time, especially when cross-compiling nix.

The busybox derivation actually supports linking against musl with a useMusl argument, so we don't actually need to use pkgsStatic just to use musl.

Things done

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandboxing enabled in nix.conf? (See Nix manual)
    • sandbox = relaxed
    • sandbox = true
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 24.11 Release Notes (or backporting 23.11 and 24.05 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

Add a 👍 reaction to pull requests you find important.

@szlend
Copy link
Member Author

szlend commented May 26, 2024

Sucessfully built the following platforms:

❯ nix build -L -f . pkgsCross.aarch64-multiplatform.busybox-sandbox-shell; nix-store --query --requisites result
/nix/store/kspcl6xn0vgmrz4xjdla33vzk2ihjs79-busybox-aarch64-unknown-linux-gnu-1.36.1

❯ nix build -L -f . pkgsCross.gnu64.busybox-sandbox-shell; nix-store --query --requisites result
/nix/store/8f374gs3k9glc4rwycgivc1wj1a6n7qz-busybox-x86_64-unknown-linux-gnu-1.36.1

❯ nix build -L -f . pkgsCross.riscv64.busybox-sandbox-shell; nix-store --query --requisites result
/nix/store/7rgj3dy5dd9bkk97m23c8nyi2hi48s51-busybox-riscv64-unknown-linux-gnu-1.36.1

❯ nix build -L -f . pkgsCross.ppc64.busybox-sandbox-shell; nix-store --query --requisites result
/nix/store/z7npv0g76kliin7igcjs23amsd503idk-busybox-powerpc64-unknown-linux-gnuabielfv2-1.36.1

❯ nix build -L -f . pkgsCross.powernv.busybox-sandbox-shell; nix-store --query --requisites result
/nix/store/3w6j46nkg2i85h6mx07vslmx4jxjxm9d-busybox-powerpc64le-unknown-linux-gnu-1.36.1

On loongarch64 we don't have musl available, so it tries to statically link with glibc with expected (bad) results:

❯ nix build -L -f . pkgsCross.loongarch64-linux.busybox-sandbox-shell; nix-store --query --requisites result
/nix/store/z5i8sca0z4wywky6aj78g06rpshd131r-libgcc-loongarch64-unknown-linux-gnu-13.2.0
/nix/store/ak68mapbyn9zpkvmh3a6dqb1k7w6vgnc-glibc-loongarch64-unknown-linux-gnu-2.39-52
/nix/store/r81i6qzi6r6ibgnkv699k90qg93hb3kk-busybox-loongarch64-unknown-linux-gnu-1.36.1

@szlend
Copy link
Member Author

szlend commented May 26, 2024

I'm not familiar with bionic, and aarch64-android failed at building compiler-rt-libc-aarch64-unknown-linux-android, so I'm unable to test that platform.

@wolfgangwalther
Copy link
Contributor

Great timing. I had a strange eval failure (for ./outpaths.nix) in #303849, which did involve recursing into busybox-sandbox-shell and then pkgsStatic. Cherry-picking your commit from here, I can finally eval my branch - at least locally, let's see what ofborg does with it.

@wolfgangwalther
Copy link
Contributor

I'm not familiar with bionic, and aarch64-android failed at building compiler-rt-libc-aarch64-unknown-linux-android, so I'm unable to test that platform.

Since pkgsCross.aarch64-android.stdenv.hostPlatform.isGnu is false, you have the same condition for taking musl as it was before. So should be good?

@alyssais
Copy link
Member

I'm not even sure it was intentional that this used pkgsStatic in the first place — at least 39769df doesn't include any explanation. @domenkozar I'm guessing you don't remember why you did this five years ago, but wanted to give you a heads up.

Comment on lines 8 to 12
useMusl =
# GNU hosts use glibc which is difficult to statically link against.
# Prefer musl if the host platform supports it.
stdenv.hostPlatform.isGnu && lib.meta.availableOn stdenv.hostPlatform musl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I'm not sure I understand, yet, is this:

I tried the following:

Suggested change
useMusl =
# GNU hosts use glibc which is difficult to statically link against.
# Prefer musl if the host platform supports it.
stdenv.hostPlatform.isGnu && lib.meta.availableOn stdenv.hostPlatform musl;
useMusl = false;

Then tried to build busybox-sandbox-shell on linux. Works fine. The binary is much bigger, because it's linked against glibc.static. But the build succeeds.

There is also #196329 which indicates that nowadays glibc.static is just fine.

Is all of this still required in the first place?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the question is, which choice is better for users? It sounds like the musl version in, if the glibc one is still much bigger, and there's no other difference between them.

Copy link
Member Author

@szlend szlend May 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not. Though personally I don't mind using musl that much because /bin/sh is rarely used and it brings the final closure size down as a side benefit.

Imo we don't need to make that decision in this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. In that case the comment should be adjusted to say that musl is used with the intention of making it minimal, not avoiding glibc. Furthermore, The condition could probably be changed to lib.meta.availableOn stdenv.hostPlatform musl only.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree about the comment, but think I would probably still keep isGnu here as this is much less of an issue with other libcs.

If we switch to musl across the board, then we'd probably want to exclude it at least for bionic.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to switch to musl across the board if there is consensus though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bionic is android, right?

Do we even have the sandbox on the other platforms?

Copy link
Member Author

@szlend szlend May 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Android yeah. busybox-sandbox-shell is only really used on Linux, so we're just talking about variations of Linux, compilers and different cpu architectures here.

Copy link
Member Author

@szlend szlend May 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, linking against glibc.static is not even that bad, the binary is only around 1MB in size. The only issue is it references glibc and libgcc from the /nix/store because of string references to zoneinfo, locale, gconv, ld.so.cache and libgcc-*/lib/.

@szlend szlend force-pushed the busybox-sandbox-shell-musl branch from 8f0d0af to 49eb8bd Compare May 26, 2024 15:10
@szlend szlend added the backport release-24.05 Backport PR automatically label May 26, 2024
@Ericson2314
Copy link
Member

I don't like making a one-off useMusl static hack for just one package (I think we we should delete it, not use it). I also don't like using pkgsStatic and pkgsCross within Nixpkgs. I wonder what option I would like :)

@Ericson2314
Copy link
Member

This wastes a ton of time, especially when cross-compiling nix.

This is a GCC problem that is entirely solvable, however. Especially if we make C++ libs optional.

@szlend
Copy link
Member Author

szlend commented May 28, 2024

I don't like making a one-off useMusl static hack for just one package (I think we we should delete it, not use it). I also don't like using pkgsStatic and pkgsCross within Nixpkgs. I wonder what option I would like :)

Personally I find pkgsStatic much worse. It's easier to just override one thing (libc) than re-instantiate the entire nixpkgs and hope it evaluates to an equivalent compiler toolchain (and not drift over time). The only real alternative I see is to use glibc.static. But imo useMusl is already a decent improvement.

@szlend
Copy link
Member Author

szlend commented May 28, 2024

Alternatively, if you'd like to generalize this, we could add a stdenv adapter to link against musl to pkgs/stdenv/adapters.nix, instead of the useMusl flag. Not sure how that would look like, just throwing it out there as it seems like it's unclear how we want to solve this right now.

@Ericson2314
Copy link
Member

Ericson2314 commented May 29, 2024

Yes, overriding the stdenv passed in (override the C compile to override the libc) would make me feel better.

@szlend
Copy link
Member Author

szlend commented May 31, 2024

After playing with this for a bit, I'm not really sure that this is a great idea. While the stdenv adapter does seem to work, I'm not really confident in adding this to the the official list of adapters because I'm not convinced it's going to be applicable to most derivations and just add to the growing list of tech debt. There's also the question of how to override stdenv.hostPlatform.libc properly and whether stdenv.parsed should be adjusted, etc.

useMuslLibc = stdenv: let
  bintools = stdenv.cc.bintools.override { libc = pkgs.musl; };
  cc = stdenv.cc.override { inherit bintools; libc = pkgs.musl; };
  in stdenv.override (old: {
    inherit cc;
    allowedRequisites = null;
    mkDerivationFromStdenv = extendMkDerivationArgs old (args: {
      NIX_CFLAGS_COMPILE = toString (args.NIX_CFLAGS_COMPILE or "") + " -isystem ${pkgs.musl.dev}/include -B${pkgs.musl}/lib -L${pkgs.musl}/lib";
    });
  });

I still think useMusl is preferable to pkgsStatic. It's a really simple zero-dependency package to build and the flag has already been there for years. Though I'm happy to just use the override downstream and close this if there is disagreement.

@wolfgangwalther
Copy link
Contributor

I still think useMusl is preferable to pkgsStatic. It's a really simple zero-dependency package to build and the flag has already been there for years. Though I'm happy to just use the override downstream and close this if there is disagreement.

Fully agree. While useMusl might not be the best solution, it's much better than what we have right now. It also fixes real problems, for example #303849. There doesn't seem to be a good reason to hold this back.

@alyssais
Copy link
Member

alyssais commented Sep 14, 2024

In #341780 I propose getting rid of uses of pkgsStatic.busybox in the package set across the board. The references shouldn't be a problem, because the requirement is for the binaries to not be dynamically linked, not to be free of references, and the size difference, as pointed out by @szlend, is not big enough to warrant a whole separate toolchain.

@szlend
Copy link
Member Author

szlend commented Sep 14, 2024

The references shouldn't be a problem, because the requirement is for the binaries to not be dynamically linked, not to be free of references

My understanding was that at least for the nix sandbox, the references are a problem.

@wolfgangwalther
Copy link
Contributor

I still think we should go ahead with this PR and merge it. The only objections to it was about useMusl, but this argument already exists and it's merely used here. Whether to change that to a more generic approach or not, can be a question for a different PR. Replacing pkgsStatic and the whole related toolchain here is a good thing regardless.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants