A modern, delicious implementation of the Nix package manager, focused on correctness, usability, and growth — and committed to doing right by its community
Find a file
Maximilian Bosch 045ee37438 libstore/local-derivation-goal: prohibit creating setuid/setgid binaries
With Linux kernel >=6.6 & glibc 2.39 a `fchmodat2(2)` is available that
isn't filtered away by the libseccomp sandbox.

Being able to use this to bypass that restriction has surprising results
for some builds such as lxc[1]:

> With kernel ≥6.6 and glibc 2.39, lxc's install phase uses fchmodat2,
> which slips through 9b88e52846/src/libstore/build/local-derivation-goal.cc (L1650-L1663).
> The fixupPhase then uses fchmodat, which fails.
> With older kernel or glibc, setting the suid bit fails in the
> install phase, which is not treated as fatal, and then the
> fixup phase does not try to set it again.

Please note that there are still ways to bypass this sandbox[2] and this is
mostly a fix for the breaking builds.

This change works by creating a syscall filter for the `fchmodat2`
syscall (number 452 on most systems). The problem is that glibc 2.39
is needed to have the correct syscall number available via
`__NR_fchmodat2` / `__SNR_fchmodat2`, but this flake is still on
nixpkgs 23.11. To have this change everywhere and not dependent on the
glibc this package is built against, I added a header
"fchmodat2-compat.hh" that sets the syscall number based on the
architecture. On most platforms its 452 according to glibc with a few
exceptions:

    $ rg --pcre2 'define __NR_fchmodat2 (?!452)'
    sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
    58:#define __NR_fchmodat2 1073742276

    sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h
    67:#define __NR_fchmodat2 6452

    sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h
    62:#define __NR_fchmodat2 5452

    sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
    70:#define __NR_fchmodat2 4452

    sysdeps/unix/sysv/linux/alpha/arch-syscall.h
    59:#define __NR_fchmodat2 562

I added a small regression-test to the setuid integration-test that
attempts to set the suid bit on a file using the fchmodat2 syscall.
I confirmed that the test fails without the change in
local-derivation-goal.

Additionally, we require libseccomp 2.5.5 or greater now: as it turns
out, libseccomp maintains an internal syscall table and
validates each rule against it. This means that when using libseccomp
2.5.4 or older, one may pass `452` as syscall number against it, but
since it doesn't exist in the internal structure, `libseccomp` will refuse
to create a filter for that. This happens with nixpkgs-23.11, i.e. on
stable NixOS and when building Lix against the project's flake.

To work around that

* a backport of libseccomp 2.5.5 on upstream nixpkgs has been
  scheduled[3].

* the package now uses libseccomp 2.5.5 on its own already. This is to
  provide a quick fix since the correct fix for 23.11 is still a staging cycle
  away.

We still need the compat header though since `SCMP_SYS(fchmodat2)`
internally transforms this into `__SNR_fchmodat2` which points to
`__NR_fchmodat2` from glibc 2.39, so it wouldn't build on glibc 2.38.
The updated syscall table from libseccomp 2.5.5 is NOT used for that
step, but used later, so we need both, our compat header and their
syscall table 🤷

Relevant PRs in CppNix:

* https://github.com/NixOS/nix/pull/10591
* https://github.com/NixOS/nix/pull/10501

[1] https://github.com/NixOS/nixpkgs/issues/300635#issuecomment-2031073804
[2] https://github.com/NixOS/nixpkgs/issues/300635#issuecomment-2030844251
[3] https://github.com/NixOS/nixpkgs/pull/306070

(cherry picked from commit ba6804518772e6afb403dd55478365d4b863c854)
Change-Id: I6921ab5a363188c6bff617750d00bb517276b7fe
2024-05-03 16:29:06 +02:00
.github Add pre-commit checks 2024-03-29 22:57:40 -07:00
bench Add benchmarking scripts 2024-04-08 19:50:24 -07:00
clang-tidy Create clang-tidy check to rename all our includes 2024-04-06 04:40:19 +00:00
contrib function-trace: always show the trace 2019-09-18 23:23:21 +02:00
doc libstore/local-derivation-goal: prohibit creating setuid/setgid binaries 2024-05-03 16:29:06 +02:00
lix-doc Format Nix code with nixfmt 2024-04-08 13:00:00 -07:00
m4 Merge pull request #6258 from obsidiansystems/gcc-bug-ergonomics 2024-03-04 05:24:33 +01:00
maintainers docs: don't compute rl-next.md during build 2024-04-09 02:09:36 +00:00
meson Add pre-commit checks 2024-03-29 22:57:40 -07:00
misc Format Nix code with nixfmt 2024-04-08 13:00:00 -07:00
mk Build with traps on signed overflow 2024-03-27 23:54:04 -07:00
nix-support binary tarball: include cacert in root paths 2024-04-12 07:04:37 -06:00
perl Format Nix code with nixfmt 2024-04-08 13:00:00 -07:00
scripts meson: correctly differentiate $profiledir and $sysconfdir/profile.d 2024-04-09 02:25:58 -06:00
src libstore/local-derivation-goal: prohibit creating setuid/setgid binaries 2024-05-03 16:29:06 +02:00
tests libstore/local-derivation-goal: prohibit creating setuid/setgid binaries 2024-05-03 16:29:06 +02:00
.clang-format Add pre-commit checks 2024-03-29 22:57:40 -07:00
.clang-tidy Add basic clang-tidy config 2024-03-29 20:26:38 -07:00
.dir-locals.el .dir-locals.el: Set c-block-comment-prefix 2020-07-10 11:21:06 +02:00
.editorconfig Add .editorconfig 2017-06-05 22:57:28 +01:00
.envrc Set MAKEFLAGS=-j and GTEST_BRIEF in .envrc 2024-03-28 18:17:28 -07:00
.gitignore docs: redo content generation for mdbook and manual 2024-04-11 13:32:06 +00:00
.version Update version to 2.90.0 2024-03-07 19:57:39 -07:00
boehmgc-coroutine-sp-fallback.diff Add pre-commit checks 2024-03-29 22:57:40 -07:00
boehmgc-traceable_allocator-public.diff Add pre-commit checks 2024-03-29 22:57:40 -07:00
configure.ac Stop vendoring toml11 2024-03-27 21:04:00 -04:00
CONTRIBUTING.md Put functional tests in tests/functional 2023-12-01 12:06:43 -05:00
COPYING Add pre-commit checks 2024-03-29 22:57:40 -07:00
default.nix Format Nix code with nixfmt 2024-04-08 13:00:00 -07:00
docker.nix Format Nix code with nixfmt 2024-04-08 13:00:00 -07:00
flake.lock pre-commit: stop using the flake 2024-04-08 15:29:23 -07:00
flake.nix libstore/local-derivation-goal: prohibit creating setuid/setgid binaries 2024-05-03 16:29:06 +02:00
justfile justfile: allow passing args to meson compile 2024-04-25 14:26:38 +02:00
local.mk build: enable libstdc++ assertions 2024-04-08 15:40:12 -07:00
Makefile un-ups your start 2024-03-18 18:28:08 -07:00
Makefile.config.in nix-doc -> lix-doc, make self-contained in package.nix 2024-04-08 04:05:13 +00:00
meson.build libstore/local-derivation-goal: prohibit creating setuid/setgid binaries 2024-05-03 16:29:06 +02:00
meson.options meson: correctly embed sandbox shell when asked 2024-04-18 16:15:58 -06:00
package.nix libstore/local-derivation-goal: prohibit creating setuid/setgid binaries 2024-05-03 16:29:06 +02:00
precompiled-headers.h Config: Use nlohmann/json 2020-08-20 11:02:16 +02:00
README.md Improve hacking.md 2023-02-13 12:00:00 +04:00
shell.nix Remove url literals 2022-01-24 13:28:21 +01:00
treefmt.toml Format Nix code with nixfmt 2024-04-08 13:00:00 -07:00

Nix

Open Collective supporters Test

Nix is a powerful package manager for Linux and other Unix systems that makes package management reliable and reproducible. Please refer to the Nix manual for more details.

Installation

On Linux and macOS the easiest way to install Nix is to run the following shell command (as a user other than root):

$ curl -L https://nixos.org/nix/install | sh

Information on additional installation methods is available on the Nix download page.

Building And Developing

See our Hacking guide in our manual for instruction on how to to set up a development environment and build Nix from source.

Additional Resources

License

Nix is released under the LGPL v2.1.