aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang-tidy/meson.build13
-rw-r--r--doc/internal-api/doxygen.cfg.in2
-rw-r--r--doc/manual/redirects.js2
-rw-r--r--doc/manual/rl-next/clang-tidy-sorta.md10
-rw-r--r--doc/manual/rl-next/clicolor-clarity.md26
-rw-r--r--doc/manual/rl-next/flake-metadata-time.md28
-rw-r--r--doc/manual/src/contributing/testing.md1
-rw-r--r--doc/manual/src/language/advanced-attributes.md7
-rw-r--r--flake.nix24
-rw-r--r--justfile10
-rwxr-xr-xmaintainers/check-syscalls.sh2
-rw-r--r--meson.build2
-rw-r--r--meson.options8
-rwxr-xr-xmeson/clang-tidy/build_required_targets.py21
-rwxr-xr-xmeson/clang-tidy/clean_compdb.py53
-rw-r--r--meson/clang-tidy/fake.cc0
-rw-r--r--meson/clang-tidy/meson.build98
-rw-r--r--package.nix18
-rw-r--r--src/libexpr/eval.cc14
-rw-r--r--src/libexpr/eval.hh13
-rw-r--r--src/libexpr/flake/config.cc2
-rw-r--r--src/libexpr/parser/parser.cc13
-rw-r--r--src/libexpr/parser/state.hh1
-rw-r--r--src/libexpr/primops.cc14
-rw-r--r--src/libstore/build/local-derivation-goal.cc619
-rw-r--r--src/libstore/build/local-derivation-goal.hh6
-rw-r--r--src/libstore/filetransfer.cc13
-rw-r--r--src/libstore/machines.cc2
-rw-r--r--src/libstore/platform/linux.cc633
-rw-r--r--src/libstore/platform/linux.hh5
-rw-r--r--src/libutil/archive.cc2
-rw-r--r--src/libutil/file-descriptor.cc2
-rw-r--r--src/libutil/hash.cc2
-rw-r--r--src/libutil/logging.cc2
-rw-r--r--src/libutil/shlex.cc2
-rw-r--r--src/libutil/terminal.cc23
-rw-r--r--src/libutil/terminal.hh12
-rw-r--r--src/libutil/url.cc2
-rw-r--r--src/nix/flake.cc24
-rw-r--r--src/nix/meson.build17
-rw-r--r--subprojects/lix-clang-tidy/.clang-format (renamed from clang-tidy/.clang-format)0
-rw-r--r--subprojects/lix-clang-tidy/.editorconfig (renamed from clang-tidy/.editorconfig)0
-rw-r--r--subprojects/lix-clang-tidy/FixIncludes.cc (renamed from clang-tidy/FixIncludes.cc)0
-rw-r--r--subprojects/lix-clang-tidy/FixIncludes.hh (renamed from clang-tidy/FixIncludes.hh)0
-rw-r--r--subprojects/lix-clang-tidy/HasPrefixSuffix.cc (renamed from clang-tidy/HasPrefixSuffix.cc)0
-rw-r--r--subprojects/lix-clang-tidy/HasPrefixSuffix.hh (renamed from clang-tidy/HasPrefixSuffix.hh)0
-rw-r--r--subprojects/lix-clang-tidy/LixClangTidyChecks.cc (renamed from clang-tidy/LixClangTidyChecks.cc)0
-rw-r--r--subprojects/lix-clang-tidy/README.md (renamed from clang-tidy/README.md)0
-rw-r--r--subprojects/lix-clang-tidy/default.nix44
-rw-r--r--subprojects/lix-clang-tidy/meson.build18
-rw-r--r--subprojects/lix-clang-tidy/meson.options3
-rw-r--r--tests/functional/flakes/flake-metadata.sh36
-rw-r--r--tests/functional/flakes/flake-metadata/flake.lock245
-rw-r--r--tests/functional/flakes/flake-metadata/metadata.out.expected36
-rw-r--r--tests/functional/lang/eval-okay-derivation-legacy.err.exp6
-rw-r--r--tests/functional/lang/eval-okay-derivation-legacy.exp1
-rw-r--r--tests/functional/lang/eval-okay-derivation-legacy.nix12
-rw-r--r--tests/functional/meson.build3
-rw-r--r--tests/functional/search.sh2
-rw-r--r--tests/unit/libexpr-support/tests/libexpr.hh4
-rw-r--r--tests/unit/libexpr/trivial.cc17
-rw-r--r--tests/unit/libutil-support/tests/cli-literate-parser.cc9
62 files changed, 1501 insertions, 683 deletions
diff --git a/clang-tidy/meson.build b/clang-tidy/meson.build
deleted file mode 100644
index c59164a72..000000000
--- a/clang-tidy/meson.build
+++ /dev/null
@@ -1,13 +0,0 @@
-project('lix-clang-tidy', ['cpp', 'c'],
- version : '0.1',
- default_options : ['warning_level=3', 'cpp_std=c++20'])
-
-llvm = dependency('Clang', version: '>= 14', modules: ['libclang'])
-sources = files(
- 'HasPrefixSuffix.cc',
- 'LixClangTidyChecks.cc',
- 'FixIncludes.cc',
-)
-
-shared_module('lix-clang-tidy', sources,
- dependencies: llvm)
diff --git a/doc/internal-api/doxygen.cfg.in b/doc/internal-api/doxygen.cfg.in
index 55bccebd7..73fba6948 100644
--- a/doc/internal-api/doxygen.cfg.in
+++ b/doc/internal-api/doxygen.cfg.in
@@ -20,7 +20,7 @@ OUTPUT_DIRECTORY = @docdir@
# for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short.
-PROJECT_BRIEF = "Nix, the purely functional package manager; unstable internal interfaces"
+PROJECT_BRIEF = "Lix: A modern, delicious implementation of the Nix package manager; unstable internal interfaces"
# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
# The default value is: YES.
diff --git a/doc/manual/redirects.js b/doc/manual/redirects.js
index f270d31a4..7a61de643 100644
--- a/doc/manual/redirects.js
+++ b/doc/manual/redirects.js
@@ -345,7 +345,7 @@ const redirects = {
"linux": "uninstall.html#linux",
"macos": "uninstall.html#macos",
"uninstalling": "uninstall.html",
- }
+ },
"contributing/hacking.html": {
"nix-with-flakes": "#building-nix-with-flakes",
"classic-nix": "#building-nix",
diff --git a/doc/manual/rl-next/clang-tidy-sorta.md b/doc/manual/rl-next/clang-tidy-sorta.md
new file mode 100644
index 000000000..5f3f84348
--- /dev/null
+++ b/doc/manual/rl-next/clang-tidy-sorta.md
@@ -0,0 +1,10 @@
+---
+synopsis: "clang-tidy support"
+cls: 1697
+issues: fj#147
+credits: jade
+category: Development
+---
+
+`clang-tidy` can be used to lint Lix with a limited set of lints using `ninja -C build clang-tidy` and `ninja -C build clang-tidy-fix`.
+In practice, this fixes the built-in meson rule that was used the same as above being broken ever since precompiled headers were introduced.
diff --git a/doc/manual/rl-next/clicolor-clarity.md b/doc/manual/rl-next/clicolor-clarity.md
new file mode 100644
index 000000000..8a289e362
--- /dev/null
+++ b/doc/manual/rl-next/clicolor-clarity.md
@@ -0,0 +1,26 @@
+---
+synopsis: "Better usage of colour control environment variables"
+cls: [1699, 1702]
+credits: [jade]
+category: Improvements
+---
+
+Lix now heeds `NO_COLOR`/`NOCOLOR` for more output types, such as that used in `nix search`, `nix flake metadata` and similar.
+
+It also now supports `CLICOLOR_FORCE`/`FORCE_COLOR` to force colours regardless of whether there is a terminal on the other side.
+
+It now follows rules compatible with those described on <https://bixense.com/clicolors/> with `CLICOLOR` defaulted to enabled.
+
+That is to say, the following procedure is followed in order:
+- NO_COLOR or NOCOLOR set
+
+ Always disable colour
+- CLICOLOR_FORCE or FORCE_COLOR set
+
+ Enable colour
+- The output is a tty; TERM != "dumb"
+
+ Enable colour
+- Otherwise
+
+ Disable colour
diff --git a/doc/manual/rl-next/flake-metadata-time.md b/doc/manual/rl-next/flake-metadata-time.md
new file mode 100644
index 000000000..8664b5a75
--- /dev/null
+++ b/doc/manual/rl-next/flake-metadata-time.md
@@ -0,0 +1,28 @@
+---
+synopsis: "`nix flake metadata` prints modified date"
+cls: 1700
+credits: jade
+category: Improvements
+---
+
+Ever wonder "gee, when *did* I update nixpkgs"?
+Wonder no more, because `nix flake metadata` now simply tells you the times every locked flake input was updated:
+
+```
+<...>
+Description: The purely functional package manager
+Path: /nix/store/c91yi8sxakc2ry7y4ac1smzwka4l5p78-source
+Revision: c52cff582043838bbe29768e7da232483d52b61d-dirty
+Last modified: 2024-07-31 22:15:54
+Inputs:
+├───flake-compat: github:edolstra/flake-compat/0f9255e01c2351cc7d116c072cb317785dd33b33
+│ Last modified: 2023-10-04 06:37:54
+├───nix2container: github:nlewo/nix2container/3853e5caf9ad24103b13aa6e0e8bcebb47649fe4
+│ Last modified: 2024-07-10 13:15:56
+├───nixpkgs: github:NixOS/nixpkgs/e21630230c77140bc6478a21cd71e8bb73706fce
+│ Last modified: 2024-07-25 11:26:27
+├───nixpkgs-regression: github:NixOS/nixpkgs/215d4d0fd80ca5163643b03a33fde804a29cc1e2
+│ Last modified: 2022-01-24 11:20:45
+└───pre-commit-hooks: github:cachix/git-hooks.nix/f451c19376071a90d8c58ab1a953c6e9840527fd
+ Last modified: 2024-07-15 04:21:09
+```
diff --git a/doc/manual/src/contributing/testing.md b/doc/manual/src/contributing/testing.md
index cea6ee3bf..33197b0ba 100644
--- a/doc/manual/src/contributing/testing.md
+++ b/doc/manual/src/contributing/testing.md
@@ -427,6 +427,7 @@ I grepped `src/` for `get[eE]nv\("` to find the mentions in Lix code.
- `NIX_SHOW_STATS_PATH` - Writes those statistics into a file at the given path instead of stdout. Undocumented.
- `NIX_SHOW_SYMBOLS` - Dumps the symbol table into the show-stats json output.
- `TERM` - If `dumb` or unset, disables ANSI colour output.
+- `FORCE_COLOR`, `CLICOLOR_FORCE` - Enables ANSI colour output if `NO_COLOR`/`NOCOLOR` not set.
- `NO_COLOR`, `NOCOLOR` - Disables ANSI colour output.
- `_NIX_DEVELOPER_SHOW_UNKNOWN_LOCATIONS` - Highlights unknown locations in errors.
- `NIX_PROFILE` - Selects which profile `nix-env` will operate on. Documented elsewhere.
diff --git a/doc/manual/src/language/advanced-attributes.md b/doc/manual/src/language/advanced-attributes.md
index ec21b9990..ee93f5672 100644
--- a/doc/manual/src/language/advanced-attributes.md
+++ b/doc/manual/src/language/advanced-attributes.md
@@ -292,6 +292,12 @@ Derivations can declare some infrequently used optional attributes.
(associative) arrays. For example, the attribute `hardening.format = true`
ends up as the Bash associative array element `${hardening[format]}`.
+ > **Warning**
+ >
+ > If set to `true`, other advanced attributes such as [`allowedReferences`](#adv-attr-allowedReferences), [`allowedReferences`](#adv-attr-allowedReferences), [`allowedRequisites`](#adv-attr-allowedRequisites),
+ [`disallowedReferences`](#adv-attr-disallowedReferences) and [`disallowedRequisites`](#adv-attr-disallowedRequisites), maxSize, and maxClosureSize.
+ will have no effect.
+
- [`outputChecks`]{#adv-attr-outputChecks}\
When using [structured attributes](#adv-attr-structuredAttrs), the `outputChecks`
attribute allows defining checks per-output.
@@ -326,7 +332,6 @@ Derivations can declare some infrequently used optional attributes.
```
- [`unsafeDiscardReferences`]{#adv-attr-unsafeDiscardReferences}\
-
When using [structured attributes](#adv-attr-structuredAttrs), the
attribute `unsafeDiscardReferences` is an attribute set with a boolean value for each output name.
If set to `true`, it disables scanning the output for runtime dependencies.
diff --git a/flake.nix b/flake.nix
index a1fc947b7..c160daed9 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,5 +1,5 @@
{
- description = "The purely functional package manager";
+ description = "Lix: A modern, delicious implementation of the Nix package manager";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05-small";
@@ -197,6 +197,8 @@
busybox-sandbox-shell = final.busybox-sandbox-shell or final.default-busybox-sandbox-shell;
};
+ lix-clang-tidy = final.callPackage ./subprojects/lix-clang-tidy { };
+
# Export the patched version of boehmgc that Lix uses into the overlay
# for consumers of this flake.
boehmgc-nix = final.nix.passthru.boehmgc-nix;
@@ -290,6 +292,24 @@
werror = true;
};
+ # Although this might be nicer to do with pre-commit, that would
+ # require adding 12MB of nodejs to the dev shell, whereas building it
+ # in CI with Nix avoids that at a cost of slower feedback on rarely
+ # touched files.
+ jsSyntaxCheck =
+ let
+ nixpkgs = nixpkgsFor.x86_64-linux.native;
+ inherit (nixpkgs) pkgs;
+ docSources = lib.fileset.toSource {
+ root = ./doc;
+ fileset = lib.fileset.fileFilter (f: f.hasExt "js") ./doc;
+ };
+ in
+ pkgs.runCommand "js-syntax-check" { } ''
+ find ${docSources} -type f -print -exec ${pkgs.nodejs-slim}/bin/node --check '{}' ';'
+ touch $out
+ '';
+
# Make sure that nix-env still produces the exact same result
# on a particular version of Nixpkgs.
evalNixpkgs =
@@ -384,6 +404,8 @@
rec {
inherit (nixpkgsFor.${system}.native) nix;
default = nix;
+
+ inherit (nixpkgsFor.${system}.native) lix-clang-tidy;
}
// (
lib.optionalAttrs (builtins.elem system linux64BitSystems) {
diff --git a/justfile b/justfile
index 6a93fa63f..1576c759d 100644
--- a/justfile
+++ b/justfile
@@ -25,3 +25,13 @@ install *OPTIONS: (build OPTIONS)
# Run tests
test *OPTIONS:
meson test -C build --print-errorlogs {{ OPTIONS }}
+
+alias clang-tidy := lint
+
+lint:
+ ninja -C build clang-tidy
+
+alias clang-tidy-fix := lint-fix
+
+lint-fix:
+ ninja -C build clang-tidy-fix
diff --git a/maintainers/check-syscalls.sh b/maintainers/check-syscalls.sh
index cd72ac23b..72b629438 100755
--- a/maintainers/check-syscalls.sh
+++ b/maintainers/check-syscalls.sh
@@ -2,6 +2,6 @@
set -e
-diff -u <(awk < src/libstore/build/local-derivation-goal.cc '/BEGIN extract-syscalls/ { extracting = 1; next }
+diff -u <(awk < src/libstore/platform/linux.cc '/BEGIN extract-syscalls/ { extracting = 1; next }
match($0, /allowSyscall\(ctx, SCMP_SYS\(([^)]*)\)\);|\/\/ skip ([^ ]*)/, result) { print result[1] result[2] }
/END extract-syscalls/ { extracting = 0; next }') <(tail -n+2 "$1" | cut -d, -f 1)
diff --git a/meson.build b/meson.build
index ed50dff78..8577657d9 100644
--- a/meson.build
+++ b/meson.build
@@ -548,3 +548,5 @@ if enable_tests
subdir('tests/unit')
subdir('tests/functional')
endif
+
+subdir('meson/clang-tidy')
diff --git a/meson.options b/meson.options
index fc2050809..679d88347 100644
--- a/meson.options
+++ b/meson.options
@@ -1,7 +1,7 @@
# vim: filetype=meson
option('enable-build', type : 'boolean', value : true,
- description : 'Set to false to not actually build. Only really makes sense with -Dinternal-api-docs=true',
+ description : 'set to false to not actually build. Only really makes sense with -Dinternal-api-docs=true',
)
option('gc', type : 'feature',
@@ -37,7 +37,7 @@ option('tests-brief', type : 'boolean', value : false,
)
option('profile-build', type : 'feature', value: 'disabled',
- description : 'whether to enable -ftime-trace in clang builds, allowing for speeding up the build.'
+ description : 'whether to enable -ftime-trace in clang builds, allowing for diagnosing the cause of build time.'
)
option('store-dir', type : 'string', value : '/nix/store',
@@ -68,3 +68,7 @@ option('profile-dir', type : 'string', value : 'etc/profile.d',
option('enable-pch-std', type : 'boolean', value : true,
description : 'whether to use precompiled headers for C++\'s standard library (breaks clangd if you\'re using GCC)',
)
+
+option('lix-clang-tidy-checks-path', type : 'string', value : '',
+ description: 'path to lix-clang-tidy-checks library file, if providing it externally. Uses an internal one if this is not set',
+)
diff --git a/meson/clang-tidy/build_required_targets.py b/meson/clang-tidy/build_required_targets.py
new file mode 100755
index 000000000..5c0e9641e
--- /dev/null
+++ b/meson/clang-tidy/build_required_targets.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python3
+import subprocess
+
+def get_targets_of_rule(build_root: str, rule_name: str) -> list[str]:
+ return subprocess.check_output(['ninja', '-C', build_root, '-t', 'targets', 'rule', rule_name]).decode().strip().splitlines()
+
+def ninja_build(build_root: str, targets: list[str]):
+ subprocess.check_call(['ninja', '-C', build_root, '--', *targets])
+
+def main():
+ import argparse
+ ap = argparse.ArgumentParser(description='Builds required targets for clang-tidy')
+ ap.add_argument('build_root', help='Ninja build root', type=str)
+
+ args = ap.parse_args()
+
+ targets = [t for t in get_targets_of_rule(args.build_root, 'CUSTOM_COMMAND') if t.endswith('gen.hh')]
+ ninja_build(args.build_root, targets)
+
+if __name__ == '__main__':
+ main()
diff --git a/meson/clang-tidy/clean_compdb.py b/meson/clang-tidy/clean_compdb.py
new file mode 100755
index 000000000..6736fe63a
--- /dev/null
+++ b/meson/clang-tidy/clean_compdb.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+# Deletes the PCH arguments from a compilation database, to workaround nixpkgs
+# stdenv having a cc-wrapper that is impossible to use for anything except cc
+# itself, for example, clang-tidy.
+
+import json
+import shlex
+
+
+def process_compdb(compdb: list[dict]) -> list[dict]:
+
+ def munch_command(args: list[str]) -> list[str]:
+ out = []
+ eat_next = False
+ for i, arg in enumerate(args):
+ if arg == '-fpch-preprocess':
+ # as used with gcc
+ continue
+ elif arg == '-include-pch' or (arg == '-include' and args[i + 1] == 'precompiled-headers.hh'):
+ # -include-pch some-pch (clang), or -include some-pch (gcc)
+ eat_next = True
+ continue
+ if not eat_next:
+ out.append(arg)
+ eat_next = False
+ return out
+
+ def chomp(item: dict) -> dict:
+ item = item.copy()
+ item['command'] = shlex.join(munch_command(shlex.split(item['command'])))
+ return item
+
+ return [chomp(x) for x in compdb if not x['file'].endswith('precompiled-headers.hh')]
+
+
+def main():
+ import argparse
+ ap = argparse.ArgumentParser(
+ description='Delete pch arguments from compilation database')
+ ap.add_argument('input',
+ type=argparse.FileType('r'),
+ help='Input json file')
+ ap.add_argument('output',
+ type=argparse.FileType('w'),
+ help='Output json file')
+ args = ap.parse_args()
+
+ input_json = json.load(args.input)
+ json.dump(process_compdb(input_json), args.output, indent=2)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/meson/clang-tidy/fake.cc b/meson/clang-tidy/fake.cc
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/meson/clang-tidy/fake.cc
diff --git a/meson/clang-tidy/meson.build b/meson/clang-tidy/meson.build
new file mode 100644
index 000000000..9aba5fbdc
--- /dev/null
+++ b/meson/clang-tidy/meson.build
@@ -0,0 +1,98 @@
+# The clang-tidy target for Lix
+
+run_clang_tidy = find_program('run-clang-tidy', required : false)
+# Although this looks like it wants to be pkg-config, pkg-config does not
+# really work for *plugins*, which are executable-like .so files that also
+# cannot be found via find_program. Fun!
+if get_option('lix-clang-tidy-checks-path') != ''
+ lix_clang_tidy_so = get_option('lix-clang-tidy-checks-path')
+ lix_clang_tidy_so_found = true
+else
+ lix_clang_tidy_subproj = subproject(
+ 'lix-clang-tidy',
+ required : false,
+ default_options : {'build-by-default': false}
+ )
+ if lix_clang_tidy_subproj.found()
+ lix_clang_tidy_so = lix_clang_tidy_subproj.get_variable('lix_clang_tidy')
+ lix_clang_tidy_so_found = true
+ else
+ lix_clang_tidy_so_found = false
+ endif
+endif
+
+# Due to numerous problems, such as:
+# - Meson does not expose pch targets, but *fine*, I can just ask Ninja for
+# them with `ninja -t targets rule cpp_PCH` and build them manually:
+# https://github.com/mesonbuild/meson/issues/13499
+# - Nixpkgs stdenv buries the cc-wrapper under a giant pile of assumptions
+# about the cc-wrapper actually being used on the cc of a stdenv, rather than
+# independently for clang-tidy, and we need to use cc-wrapper to get the
+# correct hardening flags so that clang-tidy can actually parse the PCH file
+#
+# I give up. I am going to delete the damn PCH args and then it will work.
+meson.add_postconf_script(
+ python,
+ meson.current_source_dir() / 'clean_compdb.py',
+ meson.global_build_root() / 'compile_commands.json',
+ meson.current_build_dir() / 'compile_commands.json',
+)
+
+# Horrible hack to get around not being able to depend on another target's
+# generated headers in any way in the meson DSL
+# https://github.com/mesonbuild/meson/issues/12817 which was incorrectly
+# closed, if you *actually* need to generate the files once.
+# Also related: https://github.com/mesonbuild/meson/issues/3667
+#
+# Or we could ban meson generators because their design is broken.
+build_all_generated_headers = custom_target(
+ command : [
+ python,
+ meson.current_source_dir() / 'build_required_targets.py',
+ meson.global_build_root(),
+ ],
+ output : 'generated_headers.stamp',
+ build_by_default : false,
+ build_always_stale : true,
+)
+
+if lix_clang_tidy_so_found
+ run_clang_tidy_args = [
+ '-load',
+ lix_clang_tidy_so,
+ '-p',
+ # We have to workaround a run-clang-tidy bug too, so we must give the
+ # directory name rather than the actual compdb file.
+ # https://github.com/llvm/llvm-project/issues/101440
+ meson.current_build_dir(),
+ '-quiet',
+ ]
+ run_target(
+ 'clang-tidy',
+ command : [
+ # XXX: This explicitly invokes it with python because of a nixpkgs bug
+ # where clang-unwrapped does not patch interpreters in run-clang-tidy.
+ # However, making clang-unwrapped depend on python is also silly, so idk.
+ python,
+ run_clang_tidy,
+ run_clang_tidy_args,
+ '-warnings-as-errors',
+ '*',
+ ],
+ depends : [
+ build_all_generated_headers,
+ ],
+ )
+ run_target(
+ 'clang-tidy-fix',
+ command : [
+ python,
+ run_clang_tidy,
+ run_clang_tidy_args,
+ '-fix',
+ ],
+ depends : [
+ build_all_generated_headers,
+ ],
+ )
+endif
diff --git a/package.nix b/package.nix
index 7ebe2721b..be2f0010d 100644
--- a/package.nix
+++ b/package.nix
@@ -58,8 +58,11 @@
buildUnreleasedNotes ? true,
internalApiDocs ? false,
+ # Support garbage collection in the evaluator.
+ enableGC ? sanitize == null || !builtins.elem "address" sanitize,
# List of Meson sanitize options. Accepts values of b_sanitize, e.g.
# "address", "undefined", "thread".
+ # Enabling the "address" sanitizer will disable garbage collection in the evaluator.
sanitize ? null,
# Turn compiler warnings into errors.
werror ? false,
@@ -118,10 +121,7 @@ let
# The internal API docs need these for the build, but if we're not building
# Nix itself, then these don't need to be propagated.
- maybePropagatedInputs = [
- boehmgc-nix
- nlohmann_json
- ];
+ maybePropagatedInputs = lib.optional enableGC boehmgc-nix ++ [ nlohmann_json ];
# .gitignore has already been processed, so any changes in it are irrelevant
# at this point. It is not represented verbatim for test purposes because
@@ -179,10 +179,9 @@ stdenv.mkDerivation (finalAttrs: {
mesonFlags =
let
- sanitizeOpts = lib.optionals (sanitize != null) (
- [ "-Db_sanitize=${builtins.concatStringsSep "," sanitize}" ]
- ++ lib.optional (builtins.elem "address" sanitize) "-Dgc=disabled"
- );
+ sanitizeOpts = lib.optional (
+ sanitize != null
+ ) "-Db_sanitize=${builtins.concatStringsSep "," sanitize}";
in
lib.optionals hostPlatform.isLinux [
# You'd think meson could just find this in PATH, but busybox is in buildInputs,
@@ -196,6 +195,7 @@ stdenv.mkDerivation (finalAttrs: {
# mesonConfigurePhase automatically passes -Dauto_features=enabled,
# so we must explicitly enable or disable features that we are not passing
# dependencies for.
+ (lib.mesonEnable "gc" enableGC)
(lib.mesonEnable "internal-api-docs" internalApiDocs)
(lib.mesonBool "enable-tests" finalAttrs.finalPackage.doCheck)
(lib.mesonBool "enable-docs" canRunInstalled)
@@ -502,7 +502,7 @@ stdenv.mkDerivation (finalAttrs: {
PATH=$prefix/bin''${PATH:+:''${PATH}}
unset PYTHONPATH
- export MANPATH=$out/share/man''${MANPATH:+:''${MANPATH}}
+ export MANPATH=$out/share/man:''${MANPATH:-}
# Make bash completion work.
XDG_DATA_DIRS+=:$out/share
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index a925ce2d8..741a24e3c 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -249,6 +249,12 @@ EvalState::EvalState(
, sRight(symbols.create("right"))
, sWrong(symbols.create("wrong"))
, sStructuredAttrs(symbols.create("__structuredAttrs"))
+ , sAllowedReferences(symbols.create("allowedReferences"))
+ , sAllowedRequisites(symbols.create("allowedRequisites"))
+ , sDisallowedReferences(symbols.create("disallowedReferences"))
+ , sDisallowedRequisites(symbols.create("disallowedRequisites"))
+ , sMaxSize(symbols.create("maxSize"))
+ , sMaxClosureSize(symbols.create("maxClosureSize"))
, sBuilder(symbols.create("builder"))
, sArgs(symbols.create("args"))
, sContentAddressed(symbols.create("__contentAddressed"))
@@ -2802,20 +2808,20 @@ Expr & EvalState::parseExprFromFile(const SourcePath & path, std::shared_ptr<Sta
}
-Expr & EvalState::parseExprFromString(std::string s_, const SourcePath & basePath, std::shared_ptr<StaticEnv> & staticEnv)
+Expr & EvalState::parseExprFromString(std::string s_, const SourcePath & basePath, std::shared_ptr<StaticEnv> & staticEnv, const ExperimentalFeatureSettings & xpSettings)
{
// NOTE this method (and parseStdin) must take care to *fully copy* their input
// into their respective Pos::Origin until the parser stops overwriting its input
// data.
auto s = make_ref<std::string>(s_);
s_.append("\0\0", 2);
- return *parse(s_.data(), s_.size(), Pos::String{.source = s}, basePath, staticEnv);
+ return *parse(s_.data(), s_.size(), Pos::String{.source = s}, basePath, staticEnv, xpSettings);
}
-Expr & EvalState::parseExprFromString(std::string s, const SourcePath & basePath)
+Expr & EvalState::parseExprFromString(std::string s, const SourcePath & basePath, const ExperimentalFeatureSettings & xpSettings)
{
- return parseExprFromString(std::move(s), basePath, staticBaseEnv);
+ return parseExprFromString(std::move(s), basePath, staticBaseEnv, xpSettings);
}
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index e54eede40..ff45efc08 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -13,7 +13,6 @@
#include "search-path.hh"
#include "repl-exit-status.hh"
-#include <gc/gc_allocator.h>
#include <map>
#include <optional>
#include <unordered_map>
@@ -162,7 +161,10 @@ public:
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue,
sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls,
sFile, sLine, sColumn, sFunctor, sToString,
- sRight, sWrong, sStructuredAttrs, sBuilder, sArgs,
+ sRight, sWrong, sStructuredAttrs,
+ sAllowedReferences, sAllowedRequisites, sDisallowedReferences, sDisallowedRequisites,
+ sMaxSize, sMaxClosureSize,
+ sBuilder, sArgs,
sContentAddressed, sImpure,
sOutputHash, sOutputHashAlgo, sOutputHashMode,
sRecurseForDerivations,
@@ -342,8 +344,8 @@ public:
/**
* Parse a Nix expression from the specified string.
*/
- Expr & parseExprFromString(std::string s, const SourcePath & basePath, std::shared_ptr<StaticEnv> & staticEnv);
- Expr & parseExprFromString(std::string s, const SourcePath & basePath);
+ Expr & parseExprFromString(std::string s, const SourcePath & basePath, std::shared_ptr<StaticEnv> & staticEnv, const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
+ Expr & parseExprFromString(std::string s, const SourcePath & basePath, const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
Expr & parseStdin();
@@ -566,7 +568,8 @@ private:
size_t length,
Pos::Origin origin,
const SourcePath & basePath,
- std::shared_ptr<StaticEnv> & staticEnv);
+ std::shared_ptr<StaticEnv> & staticEnv,
+ const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
/**
* Current Nix call stack depth, used with `max-call-depth` setting to throw stack overflow hopefully before we run out of system stack.
diff --git a/src/libexpr/flake/config.cc b/src/libexpr/flake/config.cc
index adcf7fd10..558b3e9b9 100644
--- a/src/libexpr/flake/config.cc
+++ b/src/libexpr/flake/config.cc
@@ -53,7 +53,7 @@ void ConfigFile::apply()
bool trusted = whitelist.count(baseName);
if (!trusted) {
- switch (nix::fetchSettings.acceptFlakeConfig) {
+ switch (nix::fetchSettings.acceptFlakeConfig.get()) {
case AcceptFlakeConfig::True: {
trusted = true;
break;
diff --git a/src/libexpr/parser/parser.cc b/src/libexpr/parser/parser.cc
index a00586c36..68aa3ddc5 100644
--- a/src/libexpr/parser/parser.cc
+++ b/src/libexpr/parser/parser.cc
@@ -12,7 +12,6 @@
#include "state.hh"
#include <charconv>
-#include <clocale>
#include <memory>
// flip this define when doing parser development to enable some g checks.
@@ -254,7 +253,8 @@ struct AttrState : SubexprState {
std::vector<AttrName> attrs;
- void pushAttr(auto && attr, PosIdx) { attrs.emplace_back(std::move(attr)); }
+ template <typename T>
+ void pushAttr(T && attr, PosIdx) { attrs.emplace_back(std::forward<T>(attr)); }
};
template<> struct BuildAST<grammar::attr::simple> {
@@ -290,7 +290,8 @@ struct InheritState : SubexprState {
std::unique_ptr<Expr> from;
PosIdx fromPos;
- void pushAttr(auto && attr, PosIdx pos) { attrs.emplace_back(std::move(attr), pos); }
+ template <typename T>
+ void pushAttr(T && attr, PosIdx pos) { attrs.emplace_back(std::forward<T>(attr), pos); }
};
template<> struct BuildAST<grammar::inherit::from> {
@@ -630,7 +631,7 @@ template<> struct BuildAST<grammar::expr::path> : p::maybe_nothing {};
template<> struct BuildAST<grammar::expr::uri> {
static void apply(const auto & in, ExprState & s, State & ps) {
- static bool noURLLiterals = experimentalFeatureSettings.isEnabled(Xp::NoUrlLiterals);
+ bool noURLLiterals = ps.xpSettings.isEnabled(Xp::NoUrlLiterals);
if (noURLLiterals)
throw ParseError({
.msg = HintFmt("URL literals are disabled"),
@@ -831,7 +832,8 @@ Expr * EvalState::parse(
size_t length,
Pos::Origin origin,
const SourcePath & basePath,
- std::shared_ptr<StaticEnv> & staticEnv)
+ std::shared_ptr<StaticEnv> & staticEnv,
+ const ExperimentalFeatureSettings & xpSettings)
{
parser::State s = {
symbols,
@@ -839,6 +841,7 @@ Expr * EvalState::parse(
basePath,
positions.addOrigin(origin, length),
exprSymbols,
+ xpSettings
};
parser::ExprState x;
diff --git a/src/libexpr/parser/state.hh b/src/libexpr/parser/state.hh
index 29889152e..30803a37e 100644
--- a/src/libexpr/parser/state.hh
+++ b/src/libexpr/parser/state.hh
@@ -19,6 +19,7 @@ struct State
SourcePath basePath;
PosTable::Origin origin;
const Expr::AstSymbols & s;
+ const ExperimentalFeatureSettings & xpSettings;
void dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos);
void dupAttr(Symbol attr, const PosIdx pos, const PosIdx prevPos);
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 0951a54de..561492f86 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -1213,6 +1213,20 @@ drvName, Bindings * attrs, Value & v)
handleOutputs(ss);
}
+ if (i->name == state.sAllowedReferences)
+ warn("In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'allowedReferences'; use 'outputChecks.<output>.allowedReferences' instead", drvName);
+ if (i->name == state.sAllowedRequisites)
+ warn("In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'allowedRequisites'; use 'outputChecks.<output>.allowedRequisites' instead", drvName);
+ if (i->name == state.sDisallowedReferences)
+ warn("In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'disallowedReferences'; use 'outputChecks.<output>.disallowedReferences' instead", drvName);
+ if (i->name == state.sDisallowedRequisites)
+ warn("In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'disallowedRequisites'; use 'outputChecks.<output>.disallowedRequisites' instead", drvName);
+ if (i->name == state.sMaxSize)
+ warn("In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'maxSize'; use 'outputChecks.<output>.maxSize' instead", drvName);
+ if (i->name == state.sMaxClosureSize)
+ warn("In a derivation named '%s', 'structuredAttrs' disables the effect of the derivation attribute 'maxClosureSize'; use 'outputChecks.<output>.maxClosureSize' instead", drvName);
+
+
} else {
auto s = state.coerceToString(pos, *i->value, context, context_below, true).toOwned();
drv.env.emplace(key, s);
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index fb5ccc6f1..db380e07c 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -42,11 +42,7 @@
#include <sched.h>
#include <sys/param.h>
#include <sys/mount.h>
-#include <sys/prctl.h>
#include <sys/syscall.h>
-#if HAVE_SECCOMP
-#include <seccomp.h>
-#endif
#define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root, put_old))
#endif
@@ -61,14 +57,6 @@ extern "C" int sandbox_init_with_parameters(const char *profile, uint64_t flags,
namespace nix {
-namespace {
-/**
- * The system for which Nix is compiled.
- */
-[[gnu::unused]]
-constexpr const std::string_view nativeSystem = SYSTEM;
-}
-
void handleDiffHook(
uid_t uid, uid_t gid,
const Path & tryA, const Path & tryB,
@@ -1361,593 +1349,6 @@ void LocalDerivationGoal::chownToBuilder(const Path & path)
throw SysError("cannot change ownership of '%1%'", path);
}
-#if HAVE_SECCOMP
-
-static void allowSyscall(scmp_filter_ctx ctx, int syscall) {
- if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscall, 0) != 0)
- throw SysError("unable to add seccomp rule");
-}
-
-#define ALLOW_CHMOD_IF_SAFE(ctx, syscall, modePos) \
- if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscall, 1, SCMP_A##modePos(SCMP_CMP_MASKED_EQ, S_ISUID | S_ISGID, 0)) != 0 || \
- seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), syscall, 1, SCMP_A##modePos(SCMP_CMP_MASKED_EQ, S_ISUID, S_ISUID)) != 0 || \
- seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), syscall, 1, SCMP_A##modePos(SCMP_CMP_MASKED_EQ, S_ISGID, S_ISGID)) != 0) \
- throw SysError("unable to add seccomp rule");
-
-#endif
-
-void setupSeccomp()
-{
-#if __linux__
-#if HAVE_SECCOMP
- scmp_filter_ctx ctx;
-
- // Pretend that syscalls we don't yet know about don't exist.
- // This is the best option for compatibility: after all, they did in fact not exist not too long ago.
- if (!(ctx = seccomp_init(SCMP_ACT_ERRNO(ENOSYS))))
- throw SysError("unable to initialize seccomp mode 2");
-
- Finally cleanup([&]() {
- seccomp_release(ctx);
- });
-
- if (nativeSystem == "x86_64-linux" &&
- seccomp_arch_add(ctx, SCMP_ARCH_X86) != 0)
- throw SysError("unable to add 32-bit seccomp architecture");
-
- if (nativeSystem == "x86_64-linux" &&
- seccomp_arch_add(ctx, SCMP_ARCH_X32) != 0)
- throw SysError("unable to add X32 seccomp architecture");
-
- if (nativeSystem == "aarch64-linux" &&
- seccomp_arch_add(ctx, SCMP_ARCH_ARM) != 0)
- printError("unable to add ARM seccomp architecture; this may result in spurious build failures if running 32-bit ARM processes");
-
- if (nativeSystem == "mips64-linux" &&
- seccomp_arch_add(ctx, SCMP_ARCH_MIPS) != 0)
- printError("unable to add mips seccomp architecture");
-
- if (nativeSystem == "mips64-linux" &&
- seccomp_arch_add(ctx, SCMP_ARCH_MIPS64N32) != 0)
- printError("unable to add mips64-*abin32 seccomp architecture");
-
- if (nativeSystem == "mips64el-linux" &&
- seccomp_arch_add(ctx, SCMP_ARCH_MIPSEL) != 0)
- printError("unable to add mipsel seccomp architecture");
-
- if (nativeSystem == "mips64el-linux" &&
- seccomp_arch_add(ctx, SCMP_ARCH_MIPSEL64N32) != 0)
- printError("unable to add mips64el-*abin32 seccomp architecture");
-
- // This list is intended for machine consumption.
- // Please keep its format, order and BEGIN/END markers.
- //
- // Currently, it is up to date with libseccomp 2.5.5 and glibc 2.39.
- // Run check-syscalls to determine which new syscalls should be added.
- // New syscalls must be audited and handled in a way that blocks the following dangerous operations:
- // * Creation of non-empty setuid/setgid files
- // * Creation of extended attributes (including ACLs)
- //
- // BEGIN extract-syscalls
- allowSyscall(ctx, SCMP_SYS(accept));
- allowSyscall(ctx, SCMP_SYS(accept4));
- allowSyscall(ctx, SCMP_SYS(access));
- allowSyscall(ctx, SCMP_SYS(acct));
- allowSyscall(ctx, SCMP_SYS(add_key));
- allowSyscall(ctx, SCMP_SYS(adjtimex));
- allowSyscall(ctx, SCMP_SYS(afs_syscall));
- allowSyscall(ctx, SCMP_SYS(alarm));
- allowSyscall(ctx, SCMP_SYS(arch_prctl));
- allowSyscall(ctx, SCMP_SYS(arm_fadvise64_64));
- allowSyscall(ctx, SCMP_SYS(arm_sync_file_range));
- allowSyscall(ctx, SCMP_SYS(bdflush));
- allowSyscall(ctx, SCMP_SYS(bind));
- allowSyscall(ctx, SCMP_SYS(bpf));
- allowSyscall(ctx, SCMP_SYS(break));
- allowSyscall(ctx, SCMP_SYS(breakpoint));
- allowSyscall(ctx, SCMP_SYS(brk));
- allowSyscall(ctx, SCMP_SYS(cachectl));
- allowSyscall(ctx, SCMP_SYS(cacheflush));
- allowSyscall(ctx, SCMP_SYS(cachestat));
- allowSyscall(ctx, SCMP_SYS(capget));
- allowSyscall(ctx, SCMP_SYS(capset));
- allowSyscall(ctx, SCMP_SYS(chdir));
- // skip chmod (dangerous)
- allowSyscall(ctx, SCMP_SYS(chown));
- allowSyscall(ctx, SCMP_SYS(chown32));
- allowSyscall(ctx, SCMP_SYS(chroot));
- allowSyscall(ctx, SCMP_SYS(clock_adjtime));
- allowSyscall(ctx, SCMP_SYS(clock_adjtime64));
- allowSyscall(ctx, SCMP_SYS(clock_getres));
- allowSyscall(ctx, SCMP_SYS(clock_getres_time64));
- allowSyscall(ctx, SCMP_SYS(clock_gettime));
- allowSyscall(ctx, SCMP_SYS(clock_gettime64));
- allowSyscall(ctx, SCMP_SYS(clock_nanosleep));
- allowSyscall(ctx, SCMP_SYS(clock_nanosleep_time64));
- allowSyscall(ctx, SCMP_SYS(clock_settime));
- allowSyscall(ctx, SCMP_SYS(clock_settime64));
- allowSyscall(ctx, SCMP_SYS(clone));
- allowSyscall(ctx, SCMP_SYS(clone3));
- allowSyscall(ctx, SCMP_SYS(close));
- allowSyscall(ctx, SCMP_SYS(close_range));
- allowSyscall(ctx, SCMP_SYS(connect));
- allowSyscall(ctx, SCMP_SYS(copy_file_range));
- allowSyscall(ctx, SCMP_SYS(creat));
- allowSyscall(ctx, SCMP_SYS(create_module));
- allowSyscall(ctx, SCMP_SYS(delete_module));
- allowSyscall(ctx, SCMP_SYS(dup));
- allowSyscall(ctx, SCMP_SYS(dup2));
- allowSyscall(ctx, SCMP_SYS(dup3));
- allowSyscall(ctx, SCMP_SYS(epoll_create));
- allowSyscall(ctx, SCMP_SYS(epoll_create1));
- allowSyscall(ctx, SCMP_SYS(epoll_ctl));
- allowSyscall(ctx, SCMP_SYS(epoll_ctl_old));
- allowSyscall(ctx, SCMP_SYS(epoll_pwait));
- allowSyscall(ctx, SCMP_SYS(epoll_pwait2));
- allowSyscall(ctx, SCMP_SYS(epoll_wait));
- allowSyscall(ctx, SCMP_SYS(epoll_wait_old));
- allowSyscall(ctx, SCMP_SYS(eventfd));
- allowSyscall(ctx, SCMP_SYS(eventfd2));
- allowSyscall(ctx, SCMP_SYS(execve));
- allowSyscall(ctx, SCMP_SYS(execveat));
- allowSyscall(ctx, SCMP_SYS(exit));
- allowSyscall(ctx, SCMP_SYS(exit_group));
- allowSyscall(ctx, SCMP_SYS(faccessat));
- allowSyscall(ctx, SCMP_SYS(faccessat2));
- allowSyscall(ctx, SCMP_SYS(fadvise64));
- allowSyscall(ctx, SCMP_SYS(fadvise64_64));
- allowSyscall(ctx, SCMP_SYS(fallocate));
- allowSyscall(ctx, SCMP_SYS(fanotify_init));
- allowSyscall(ctx, SCMP_SYS(fanotify_mark));
- allowSyscall(ctx, SCMP_SYS(fchdir));
- // skip fchmod (dangerous)
- // skip fchmodat (dangerous)
- // skip fchmodat2 (dangerous)
- allowSyscall(ctx, SCMP_SYS(fchown));
- allowSyscall(ctx, SCMP_SYS(fchown32));
- allowSyscall(ctx, SCMP_SYS(fchownat));
- allowSyscall(ctx, SCMP_SYS(fcntl));
- allowSyscall(ctx, SCMP_SYS(fcntl64));
- allowSyscall(ctx, SCMP_SYS(fdatasync));
- allowSyscall(ctx, SCMP_SYS(fgetxattr));
- allowSyscall(ctx, SCMP_SYS(finit_module));
- allowSyscall(ctx, SCMP_SYS(flistxattr));
- allowSyscall(ctx, SCMP_SYS(flock));
- allowSyscall(ctx, SCMP_SYS(fork));
- allowSyscall(ctx, SCMP_SYS(fremovexattr));
- allowSyscall(ctx, SCMP_SYS(fsconfig));
- // skip fsetxattr (dangerous)
- allowSyscall(ctx, SCMP_SYS(fsmount));
- allowSyscall(ctx, SCMP_SYS(fsopen));
- allowSyscall(ctx, SCMP_SYS(fspick));
- allowSyscall(ctx, SCMP_SYS(fstat));
- allowSyscall(ctx, SCMP_SYS(fstat64));
- allowSyscall(ctx, SCMP_SYS(fstatat64));
- allowSyscall(ctx, SCMP_SYS(fstatfs));
- allowSyscall(ctx, SCMP_SYS(fstatfs64));
- allowSyscall(ctx, SCMP_SYS(fsync));
- allowSyscall(ctx, SCMP_SYS(ftime));
- allowSyscall(ctx, SCMP_SYS(ftruncate));
- allowSyscall(ctx, SCMP_SYS(ftruncate64));
- allowSyscall(ctx, SCMP_SYS(futex));
- allowSyscall(ctx, SCMP_SYS(futex_requeue));
- allowSyscall(ctx, SCMP_SYS(futex_time64));
- allowSyscall(ctx, SCMP_SYS(futex_wait));
- allowSyscall(ctx, SCMP_SYS(futex_waitv));
- allowSyscall(ctx, SCMP_SYS(futex_wake));
- allowSyscall(ctx, SCMP_SYS(futimesat));
- allowSyscall(ctx, SCMP_SYS(getcpu));
- allowSyscall(ctx, SCMP_SYS(getcwd));
- allowSyscall(ctx, SCMP_SYS(getdents));
- allowSyscall(ctx, SCMP_SYS(getdents64));
- allowSyscall(ctx, SCMP_SYS(getegid));
- allowSyscall(ctx, SCMP_SYS(getegid32));
- allowSyscall(ctx, SCMP_SYS(geteuid));
- allowSyscall(ctx, SCMP_SYS(geteuid32));
- allowSyscall(ctx, SCMP_SYS(getgid));
- allowSyscall(ctx, SCMP_SYS(getgid32));
- allowSyscall(ctx, SCMP_SYS(getgroups));
- allowSyscall(ctx, SCMP_SYS(getgroups32));
- allowSyscall(ctx, SCMP_SYS(getitimer));
- allowSyscall(ctx, SCMP_SYS(get_kernel_syms));
- allowSyscall(ctx, SCMP_SYS(get_mempolicy));
- allowSyscall(ctx, SCMP_SYS(getpeername));
- allowSyscall(ctx, SCMP_SYS(getpgid));
- allowSyscall(ctx, SCMP_SYS(getpgrp));
- allowSyscall(ctx, SCMP_SYS(getpid));
- allowSyscall(ctx, SCMP_SYS(getpmsg));
- allowSyscall(ctx, SCMP_SYS(getppid));
- allowSyscall(ctx, SCMP_SYS(getpriority));
- allowSyscall(ctx, SCMP_SYS(getrandom));
- allowSyscall(ctx, SCMP_SYS(getresgid));
- allowSyscall(ctx, SCMP_SYS(getresgid32));
- allowSyscall(ctx, SCMP_SYS(getresuid));
- allowSyscall(ctx, SCMP_SYS(getresuid32));
- allowSyscall(ctx, SCMP_SYS(getrlimit));
- allowSyscall(ctx, SCMP_SYS(get_robust_list));
- allowSyscall(ctx, SCMP_SYS(getrusage));
- allowSyscall(ctx, SCMP_SYS(getsid));
- allowSyscall(ctx, SCMP_SYS(getsockname));
- allowSyscall(ctx, SCMP_SYS(getsockopt));
- allowSyscall(ctx, SCMP_SYS(get_thread_area));
- allowSyscall(ctx, SCMP_SYS(gettid));
- allowSyscall(ctx, SCMP_SYS(gettimeofday));
- allowSyscall(ctx, SCMP_SYS(get_tls));
- allowSyscall(ctx, SCMP_SYS(getuid));
- allowSyscall(ctx, SCMP_SYS(getuid32));
- allowSyscall(ctx, SCMP_SYS(getxattr));
- allowSyscall(ctx, SCMP_SYS(gtty));
- allowSyscall(ctx, SCMP_SYS(idle));
- allowSyscall(ctx, SCMP_SYS(init_module));
- allowSyscall(ctx, SCMP_SYS(inotify_add_watch));
- allowSyscall(ctx, SCMP_SYS(inotify_init));
- allowSyscall(ctx, SCMP_SYS(inotify_init1));
- allowSyscall(ctx, SCMP_SYS(inotify_rm_watch));
- allowSyscall(ctx, SCMP_SYS(io_cancel));
- allowSyscall(ctx, SCMP_SYS(ioctl));
- allowSyscall(ctx, SCMP_SYS(io_destroy));
- allowSyscall(ctx, SCMP_SYS(io_getevents));
- allowSyscall(ctx, SCMP_SYS(ioperm));
- allowSyscall(ctx, SCMP_SYS(io_pgetevents));
- allowSyscall(ctx, SCMP_SYS(io_pgetevents_time64));
- allowSyscall(ctx, SCMP_SYS(iopl));
- allowSyscall(ctx, SCMP_SYS(ioprio_get));
- allowSyscall(ctx, SCMP_SYS(ioprio_set));
- allowSyscall(ctx, SCMP_SYS(io_setup));
- allowSyscall(ctx, SCMP_SYS(io_submit));
- // skip io_uring_enter (may become dangerous)
- // skip io_uring_register (may become dangerous)
- // skip io_uring_setup (may become dangerous)
- allowSyscall(ctx, SCMP_SYS(ipc));
- allowSyscall(ctx, SCMP_SYS(kcmp));
- allowSyscall(ctx, SCMP_SYS(kexec_file_load));
- allowSyscall(ctx, SCMP_SYS(kexec_load));
- allowSyscall(ctx, SCMP_SYS(keyctl));
- allowSyscall(ctx, SCMP_SYS(kill));
- allowSyscall(ctx, SCMP_SYS(landlock_add_rule));
- allowSyscall(ctx, SCMP_SYS(landlock_create_ruleset));
- allowSyscall(ctx, SCMP_SYS(landlock_restrict_self));
- allowSyscall(ctx, SCMP_SYS(lchown));
- allowSyscall(ctx, SCMP_SYS(lchown32));
- allowSyscall(ctx, SCMP_SYS(lgetxattr));
- allowSyscall(ctx, SCMP_SYS(link));
- allowSyscall(ctx, SCMP_SYS(linkat));
- allowSyscall(ctx, SCMP_SYS(listen));
- allowSyscall(ctx, SCMP_SYS(listxattr));
- allowSyscall(ctx, SCMP_SYS(llistxattr));
- allowSyscall(ctx, SCMP_SYS(_llseek));
- allowSyscall(ctx, SCMP_SYS(lock));
- allowSyscall(ctx, SCMP_SYS(lookup_dcookie));
- allowSyscall(ctx, SCMP_SYS(lremovexattr));
- allowSyscall(ctx, SCMP_SYS(lseek));
- // skip lsetxattr (dangerous)
- allowSyscall(ctx, SCMP_SYS(lstat));
- allowSyscall(ctx, SCMP_SYS(lstat64));
- allowSyscall(ctx, SCMP_SYS(madvise));
- allowSyscall(ctx, SCMP_SYS(map_shadow_stack));
- allowSyscall(ctx, SCMP_SYS(mbind));
- allowSyscall(ctx, SCMP_SYS(membarrier));
- allowSyscall(ctx, SCMP_SYS(memfd_create));
- allowSyscall(ctx, SCMP_SYS(memfd_secret));
- allowSyscall(ctx, SCMP_SYS(migrate_pages));
- allowSyscall(ctx, SCMP_SYS(mincore));
- allowSyscall(ctx, SCMP_SYS(mkdir));
- allowSyscall(ctx, SCMP_SYS(mkdirat));
- allowSyscall(ctx, SCMP_SYS(mknod));
- allowSyscall(ctx, SCMP_SYS(mknodat));
- allowSyscall(ctx, SCMP_SYS(mlock));
- allowSyscall(ctx, SCMP_SYS(mlock2));
- allowSyscall(ctx, SCMP_SYS(mlockall));
- allowSyscall(ctx, SCMP_SYS(mmap));
- allowSyscall(ctx, SCMP_SYS(mmap2));
- allowSyscall(ctx, SCMP_SYS(modify_ldt));
- allowSyscall(ctx, SCMP_SYS(mount));
- allowSyscall(ctx, SCMP_SYS(mount_setattr));
- allowSyscall(ctx, SCMP_SYS(move_mount));
- allowSyscall(ctx, SCMP_SYS(move_pages));
- allowSyscall(ctx, SCMP_SYS(mprotect));
- allowSyscall(ctx, SCMP_SYS(mpx));
- allowSyscall(ctx, SCMP_SYS(mq_getsetattr));
- allowSyscall(ctx, SCMP_SYS(mq_notify));
- allowSyscall(ctx, SCMP_SYS(mq_open));
- allowSyscall(ctx, SCMP_SYS(mq_timedreceive));
- allowSyscall(ctx, SCMP_SYS(mq_timedreceive_time64));
- allowSyscall(ctx, SCMP_SYS(mq_timedsend));
- allowSyscall(ctx, SCMP_SYS(mq_timedsend_time64));
- allowSyscall(ctx, SCMP_SYS(mq_unlink));
- allowSyscall(ctx, SCMP_SYS(mremap));
- allowSyscall(ctx, SCMP_SYS(msgctl));
- allowSyscall(ctx, SCMP_SYS(msgget));
- allowSyscall(ctx, SCMP_SYS(msgrcv));
- allowSyscall(ctx, SCMP_SYS(msgsnd));
- allowSyscall(ctx, SCMP_SYS(msync));
- allowSyscall(ctx, SCMP_SYS(multiplexer));
- allowSyscall(ctx, SCMP_SYS(munlock));
- allowSyscall(ctx, SCMP_SYS(munlockall));
- allowSyscall(ctx, SCMP_SYS(munmap));
- allowSyscall(ctx, SCMP_SYS(name_to_handle_at));
- allowSyscall(ctx, SCMP_SYS(nanosleep));
- allowSyscall(ctx, SCMP_SYS(newfstatat));
- allowSyscall(ctx, SCMP_SYS(_newselect));
- allowSyscall(ctx, SCMP_SYS(nfsservctl));
- allowSyscall(ctx, SCMP_SYS(nice));
- allowSyscall(ctx, SCMP_SYS(oldfstat));
- allowSyscall(ctx, SCMP_SYS(oldlstat));
- allowSyscall(ctx, SCMP_SYS(oldolduname));
- allowSyscall(ctx, SCMP_SYS(oldstat));
- allowSyscall(ctx, SCMP_SYS(olduname));
- allowSyscall(ctx, SCMP_SYS(open));
- allowSyscall(ctx, SCMP_SYS(openat));
- allowSyscall(ctx, SCMP_SYS(openat2));
- allowSyscall(ctx, SCMP_SYS(open_by_handle_at));
- allowSyscall(ctx, SCMP_SYS(open_tree));
- allowSyscall(ctx, SCMP_SYS(pause));
- allowSyscall(ctx, SCMP_SYS(pciconfig_iobase));
- allowSyscall(ctx, SCMP_SYS(pciconfig_read));
- allowSyscall(ctx, SCMP_SYS(pciconfig_write));
- allowSyscall(ctx, SCMP_SYS(perf_event_open));
- allowSyscall(ctx, SCMP_SYS(personality));
- allowSyscall(ctx, SCMP_SYS(pidfd_getfd));
- allowSyscall(ctx, SCMP_SYS(pidfd_open));
- allowSyscall(ctx, SCMP_SYS(pidfd_send_signal));
- allowSyscall(ctx, SCMP_SYS(pipe));
- allowSyscall(ctx, SCMP_SYS(pipe2));
- allowSyscall(ctx, SCMP_SYS(pivot_root));
- allowSyscall(ctx, SCMP_SYS(pkey_alloc));
- allowSyscall(ctx, SCMP_SYS(pkey_free));
- allowSyscall(ctx, SCMP_SYS(pkey_mprotect));
- allowSyscall(ctx, SCMP_SYS(poll));
- allowSyscall(ctx, SCMP_SYS(ppoll));
- allowSyscall(ctx, SCMP_SYS(ppoll_time64));
- allowSyscall(ctx, SCMP_SYS(prctl));
- allowSyscall(ctx, SCMP_SYS(pread64));
- allowSyscall(ctx, SCMP_SYS(preadv));
- allowSyscall(ctx, SCMP_SYS(preadv2));
- allowSyscall(ctx, SCMP_SYS(prlimit64));
- allowSyscall(ctx, SCMP_SYS(process_madvise));
- allowSyscall(ctx, SCMP_SYS(process_mrelease));
- allowSyscall(ctx, SCMP_SYS(process_vm_readv));
- allowSyscall(ctx, SCMP_SYS(process_vm_writev));
- allowSyscall(ctx, SCMP_SYS(prof));
- allowSyscall(ctx, SCMP_SYS(profil));
- allowSyscall(ctx, SCMP_SYS(pselect6));
- allowSyscall(ctx, SCMP_SYS(pselect6_time64));
- allowSyscall(ctx, SCMP_SYS(ptrace));
- allowSyscall(ctx, SCMP_SYS(putpmsg));
- allowSyscall(ctx, SCMP_SYS(pwrite64));
- allowSyscall(ctx, SCMP_SYS(pwritev));
- allowSyscall(ctx, SCMP_SYS(pwritev2));
- allowSyscall(ctx, SCMP_SYS(query_module));
- allowSyscall(ctx, SCMP_SYS(quotactl));
- allowSyscall(ctx, SCMP_SYS(quotactl_fd));
- allowSyscall(ctx, SCMP_SYS(read));
- allowSyscall(ctx, SCMP_SYS(readahead));
- allowSyscall(ctx, SCMP_SYS(readdir));
- allowSyscall(ctx, SCMP_SYS(readlink));
- allowSyscall(ctx, SCMP_SYS(readlinkat));
- allowSyscall(ctx, SCMP_SYS(readv));
- allowSyscall(ctx, SCMP_SYS(reboot));
- allowSyscall(ctx, SCMP_SYS(recv));
- allowSyscall(ctx, SCMP_SYS(recvfrom));
- allowSyscall(ctx, SCMP_SYS(recvmmsg));
- allowSyscall(ctx, SCMP_SYS(recvmmsg_time64));
- allowSyscall(ctx, SCMP_SYS(recvmsg));
- allowSyscall(ctx, SCMP_SYS(remap_file_pages));
- allowSyscall(ctx, SCMP_SYS(removexattr));
- allowSyscall(ctx, SCMP_SYS(rename));
- allowSyscall(ctx, SCMP_SYS(renameat));
- allowSyscall(ctx, SCMP_SYS(renameat2));
- allowSyscall(ctx, SCMP_SYS(request_key));
- allowSyscall(ctx, SCMP_SYS(restart_syscall));
- allowSyscall(ctx, SCMP_SYS(riscv_flush_icache));
- allowSyscall(ctx, SCMP_SYS(rmdir));
- allowSyscall(ctx, SCMP_SYS(rseq));
- allowSyscall(ctx, SCMP_SYS(rtas));
- allowSyscall(ctx, SCMP_SYS(rt_sigaction));
- allowSyscall(ctx, SCMP_SYS(rt_sigpending));
- allowSyscall(ctx, SCMP_SYS(rt_sigprocmask));
- allowSyscall(ctx, SCMP_SYS(rt_sigqueueinfo));
- allowSyscall(ctx, SCMP_SYS(rt_sigreturn));
- allowSyscall(ctx, SCMP_SYS(rt_sigsuspend));
- allowSyscall(ctx, SCMP_SYS(rt_sigtimedwait));
- allowSyscall(ctx, SCMP_SYS(rt_sigtimedwait_time64));
- allowSyscall(ctx, SCMP_SYS(rt_tgsigqueueinfo));
- allowSyscall(ctx, SCMP_SYS(s390_guarded_storage));
- allowSyscall(ctx, SCMP_SYS(s390_pci_mmio_read));
- allowSyscall(ctx, SCMP_SYS(s390_pci_mmio_write));
- allowSyscall(ctx, SCMP_SYS(s390_runtime_instr));
- allowSyscall(ctx, SCMP_SYS(s390_sthyi));
- allowSyscall(ctx, SCMP_SYS(sched_getaffinity));
- allowSyscall(ctx, SCMP_SYS(sched_getattr));
- allowSyscall(ctx, SCMP_SYS(sched_getparam));
- allowSyscall(ctx, SCMP_SYS(sched_get_priority_max));
- allowSyscall(ctx, SCMP_SYS(sched_get_priority_min));
- allowSyscall(ctx, SCMP_SYS(sched_getscheduler));
- allowSyscall(ctx, SCMP_SYS(sched_rr_get_interval));
- allowSyscall(ctx, SCMP_SYS(sched_rr_get_interval_time64));
- allowSyscall(ctx, SCMP_SYS(sched_setaffinity));
- allowSyscall(ctx, SCMP_SYS(sched_setattr));
- allowSyscall(ctx, SCMP_SYS(sched_setparam));
- allowSyscall(ctx, SCMP_SYS(sched_setscheduler));
- allowSyscall(ctx, SCMP_SYS(sched_yield));
- allowSyscall(ctx, SCMP_SYS(seccomp));
- allowSyscall(ctx, SCMP_SYS(security));
- allowSyscall(ctx, SCMP_SYS(select));
- allowSyscall(ctx, SCMP_SYS(semctl));
- allowSyscall(ctx, SCMP_SYS(semget));
- allowSyscall(ctx, SCMP_SYS(semop));
- allowSyscall(ctx, SCMP_SYS(semtimedop));
- allowSyscall(ctx, SCMP_SYS(semtimedop_time64));
- allowSyscall(ctx, SCMP_SYS(send));
- allowSyscall(ctx, SCMP_SYS(sendfile));
- allowSyscall(ctx, SCMP_SYS(sendfile64));
- allowSyscall(ctx, SCMP_SYS(sendmmsg));
- allowSyscall(ctx, SCMP_SYS(sendmsg));
- allowSyscall(ctx, SCMP_SYS(sendto));
- allowSyscall(ctx, SCMP_SYS(setdomainname));
- allowSyscall(ctx, SCMP_SYS(setfsgid));
- allowSyscall(ctx, SCMP_SYS(setfsgid32));
- allowSyscall(ctx, SCMP_SYS(setfsuid));
- allowSyscall(ctx, SCMP_SYS(setfsuid32));
- allowSyscall(ctx, SCMP_SYS(setgid));
- allowSyscall(ctx, SCMP_SYS(setgid32));
- allowSyscall(ctx, SCMP_SYS(setgroups));
- allowSyscall(ctx, SCMP_SYS(setgroups32));
- allowSyscall(ctx, SCMP_SYS(sethostname));
- allowSyscall(ctx, SCMP_SYS(setitimer));
- allowSyscall(ctx, SCMP_SYS(set_mempolicy));
- allowSyscall(ctx, SCMP_SYS(set_mempolicy_home_node));
- allowSyscall(ctx, SCMP_SYS(setns));
- allowSyscall(ctx, SCMP_SYS(setpgid));
- allowSyscall(ctx, SCMP_SYS(setpriority));
- allowSyscall(ctx, SCMP_SYS(setregid));
- allowSyscall(ctx, SCMP_SYS(setregid32));
- allowSyscall(ctx, SCMP_SYS(setresgid));
- allowSyscall(ctx, SCMP_SYS(setresgid32));
- allowSyscall(ctx, SCMP_SYS(setresuid));
- allowSyscall(ctx, SCMP_SYS(setresuid32));
- allowSyscall(ctx, SCMP_SYS(setreuid));
- allowSyscall(ctx, SCMP_SYS(setreuid32));
- allowSyscall(ctx, SCMP_SYS(setrlimit));
- allowSyscall(ctx, SCMP_SYS(set_robust_list));
- allowSyscall(ctx, SCMP_SYS(setsid));
- allowSyscall(ctx, SCMP_SYS(setsockopt));
- allowSyscall(ctx, SCMP_SYS(set_thread_area));
- allowSyscall(ctx, SCMP_SYS(set_tid_address));
- allowSyscall(ctx, SCMP_SYS(settimeofday));
- allowSyscall(ctx, SCMP_SYS(set_tls));
- allowSyscall(ctx, SCMP_SYS(setuid));
- allowSyscall(ctx, SCMP_SYS(setuid32));
- // skip setxattr (dangerous)
- allowSyscall(ctx, SCMP_SYS(sgetmask));
- allowSyscall(ctx, SCMP_SYS(shmat));
- allowSyscall(ctx, SCMP_SYS(shmctl));
- allowSyscall(ctx, SCMP_SYS(shmdt));
- allowSyscall(ctx, SCMP_SYS(shmget));
- allowSyscall(ctx, SCMP_SYS(shutdown));
- allowSyscall(ctx, SCMP_SYS(sigaction));
- allowSyscall(ctx, SCMP_SYS(sigaltstack));
- allowSyscall(ctx, SCMP_SYS(signal));
- allowSyscall(ctx, SCMP_SYS(signalfd));
- allowSyscall(ctx, SCMP_SYS(signalfd4));
- allowSyscall(ctx, SCMP_SYS(sigpending));
- allowSyscall(ctx, SCMP_SYS(sigprocmask));
- allowSyscall(ctx, SCMP_SYS(sigreturn));
- allowSyscall(ctx, SCMP_SYS(sigsuspend));
- allowSyscall(ctx, SCMP_SYS(socket));
- allowSyscall(ctx, SCMP_SYS(socketcall));
- allowSyscall(ctx, SCMP_SYS(socketpair));
- allowSyscall(ctx, SCMP_SYS(splice));
- allowSyscall(ctx, SCMP_SYS(spu_create));
- allowSyscall(ctx, SCMP_SYS(spu_run));
- allowSyscall(ctx, SCMP_SYS(ssetmask));
- allowSyscall(ctx, SCMP_SYS(stat));
- allowSyscall(ctx, SCMP_SYS(stat64));
- allowSyscall(ctx, SCMP_SYS(statfs));
- allowSyscall(ctx, SCMP_SYS(statfs64));
- allowSyscall(ctx, SCMP_SYS(statx));
- allowSyscall(ctx, SCMP_SYS(stime));
- allowSyscall(ctx, SCMP_SYS(stty));
- allowSyscall(ctx, SCMP_SYS(subpage_prot));
- allowSyscall(ctx, SCMP_SYS(swapcontext));
- allowSyscall(ctx, SCMP_SYS(swapoff));
- allowSyscall(ctx, SCMP_SYS(swapon));
- allowSyscall(ctx, SCMP_SYS(switch_endian));
- allowSyscall(ctx, SCMP_SYS(symlink));
- allowSyscall(ctx, SCMP_SYS(symlinkat));
- allowSyscall(ctx, SCMP_SYS(sync));
- allowSyscall(ctx, SCMP_SYS(sync_file_range));
- allowSyscall(ctx, SCMP_SYS(sync_file_range2));
- allowSyscall(ctx, SCMP_SYS(syncfs));
- allowSyscall(ctx, SCMP_SYS(syscall));
- allowSyscall(ctx, SCMP_SYS(_sysctl));
- allowSyscall(ctx, SCMP_SYS(sys_debug_setcontext));
- allowSyscall(ctx, SCMP_SYS(sysfs));
- allowSyscall(ctx, SCMP_SYS(sysinfo));
- allowSyscall(ctx, SCMP_SYS(syslog));
- allowSyscall(ctx, SCMP_SYS(sysmips));
- allowSyscall(ctx, SCMP_SYS(tee));
- allowSyscall(ctx, SCMP_SYS(tgkill));
- allowSyscall(ctx, SCMP_SYS(time));
- allowSyscall(ctx, SCMP_SYS(timer_create));
- allowSyscall(ctx, SCMP_SYS(timer_delete));
- allowSyscall(ctx, SCMP_SYS(timerfd));
- allowSyscall(ctx, SCMP_SYS(timerfd_create));
- allowSyscall(ctx, SCMP_SYS(timerfd_gettime));
- allowSyscall(ctx, SCMP_SYS(timerfd_gettime64));
- allowSyscall(ctx, SCMP_SYS(timerfd_settime));
- allowSyscall(ctx, SCMP_SYS(timerfd_settime64));
- allowSyscall(ctx, SCMP_SYS(timer_getoverrun));
- allowSyscall(ctx, SCMP_SYS(timer_gettime));
- allowSyscall(ctx, SCMP_SYS(timer_gettime64));
- allowSyscall(ctx, SCMP_SYS(timer_settime));
- allowSyscall(ctx, SCMP_SYS(timer_settime64));
- allowSyscall(ctx, SCMP_SYS(times));
- allowSyscall(ctx, SCMP_SYS(tkill));
- allowSyscall(ctx, SCMP_SYS(truncate));
- allowSyscall(ctx, SCMP_SYS(truncate64));
- allowSyscall(ctx, SCMP_SYS(tuxcall));
- allowSyscall(ctx, SCMP_SYS(ugetrlimit));
- allowSyscall(ctx, SCMP_SYS(ulimit));
- allowSyscall(ctx, SCMP_SYS(umask));
- allowSyscall(ctx, SCMP_SYS(umount));
- allowSyscall(ctx, SCMP_SYS(umount2));
- allowSyscall(ctx, SCMP_SYS(uname));
- allowSyscall(ctx, SCMP_SYS(unlink));
- allowSyscall(ctx, SCMP_SYS(unlinkat));
- allowSyscall(ctx, SCMP_SYS(unshare));
- allowSyscall(ctx, SCMP_SYS(uselib));
- allowSyscall(ctx, SCMP_SYS(userfaultfd));
- allowSyscall(ctx, SCMP_SYS(usr26));
- allowSyscall(ctx, SCMP_SYS(usr32));
- allowSyscall(ctx, SCMP_SYS(ustat));
- allowSyscall(ctx, SCMP_SYS(utime));
- allowSyscall(ctx, SCMP_SYS(utimensat));
- allowSyscall(ctx, SCMP_SYS(utimensat_time64));
- allowSyscall(ctx, SCMP_SYS(utimes));
- allowSyscall(ctx, SCMP_SYS(vfork));
- allowSyscall(ctx, SCMP_SYS(vhangup));
- allowSyscall(ctx, SCMP_SYS(vm86));
- allowSyscall(ctx, SCMP_SYS(vm86old));
- allowSyscall(ctx, SCMP_SYS(vmsplice));
- allowSyscall(ctx, SCMP_SYS(vserver));
- allowSyscall(ctx, SCMP_SYS(wait4));
- allowSyscall(ctx, SCMP_SYS(waitid));
- allowSyscall(ctx, SCMP_SYS(waitpid));
- allowSyscall(ctx, SCMP_SYS(write));
- allowSyscall(ctx, SCMP_SYS(writev));
- // END extract-syscalls
-
- // chmod family: prevent adding setuid/setgid bits to existing files.
- // The Nix store does not support setuid/setgid, and even their temporary creation can weaken the security of the sandbox.
- ALLOW_CHMOD_IF_SAFE(ctx, SCMP_SYS(chmod), 1);
- ALLOW_CHMOD_IF_SAFE(ctx, SCMP_SYS(fchmod), 1);
- ALLOW_CHMOD_IF_SAFE(ctx, SCMP_SYS(fchmodat), 2);
- ALLOW_CHMOD_IF_SAFE(ctx, SCMP_SYS(fchmodat2), 2);
-
- // setxattr family: prevent creation of extended attributes or ACLs.
- // Not all filesystems support them, and they're incompatible with the NAR format.
- if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(setxattr), 0) != 0 ||
- seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(lsetxattr), 0) != 0 ||
- seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(fsetxattr), 0) != 0)
- throw SysError("unable to add seccomp rule");
-
- // Set the NO_NEW_PRIVS prctl flag.
- // This both makes loading seccomp filters work for unprivileged users,
- // and is an additional security measure in its own right.
- if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 1) != 0)
- throw SysError("unable to set 'no new privileges' seccomp attribute");
-
- if (seccomp_load(ctx) != 0)
- throw SysError("unable to load seccomp BPF program");
-#else
- // Still set the no-new-privileges flag if libseccomp is not available.
- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
- throw SysError("PR_SET_NO_NEW_PRIVS failed");
-#endif
-#endif
-}
-
void LocalDerivationGoal::runChild()
{
@@ -1960,7 +1361,7 @@ void LocalDerivationGoal::runChild()
commonChildInit();
- setupSeccomp();
+ setupSyscallFilter();
bool setUser = true;
@@ -3116,6 +2517,24 @@ void LocalDerivationGoal::checkOutputs(const std::map<std::string, ValidPathInfo
};
if (auto structuredAttrs = parsedDrv->getStructuredAttrs()) {
+ if (get(*structuredAttrs, "allowedReferences")){
+ warn("'structuredAttrs' disables the effect of the top-level attribute 'allowedReferences'; use 'outputChecks' instead");
+ }
+ if (get(*structuredAttrs, "allowedRequisites")){
+ warn("'structuredAttrs' disables the effect of the top-level attribute 'allowedRequisites'; use 'outputChecks' instead");
+ }
+ if (get(*structuredAttrs, "disallowedRequisites")){
+ warn("'structuredAttrs' disables the effect of the top-level attribute 'disallowedRequisites'; use 'outputChecks' instead");
+ }
+ if (get(*structuredAttrs, "disallowedReferences")){
+ warn("'structuredAttrs' disables the effect of the top-level attribute 'disallowedReferences'; use 'outputChecks' instead");
+ }
+ if (get(*structuredAttrs, "maxSize")){
+ warn("'structuredAttrs' disables the effect of the top-level attribute 'maxSize'; use 'outputChecks' instead");
+ }
+ if (get(*structuredAttrs, "maxClosureSize")){
+ warn("'structuredAttrs' disables the effect of the top-level attribute 'maxClosureSize'; use 'outputChecks' instead");
+ }
if (auto outputChecks = get(*structuredAttrs, "outputChecks")) {
if (auto output = get(*outputChecks, outputName)) {
Checks checks;
diff --git a/src/libstore/build/local-derivation-goal.hh b/src/libstore/build/local-derivation-goal.hh
index 237417b42..e87f2c696 100644
--- a/src/libstore/build/local-derivation-goal.hh
+++ b/src/libstore/build/local-derivation-goal.hh
@@ -340,6 +340,12 @@ protected:
virtual Pid startChild(std::function<void()> openSlave);
/**
+ * Set up the system call filtering required for the sandbox.
+ * This currently only has an effect on Linux.
+ */
+ virtual void setupSyscallFilter() {}
+
+ /**
* Execute the builder, replacing the current process.
* Generally this means an `execve` call.
*/
diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc
index fcb947f96..9cb805444 100644
--- a/src/libstore/filetransfer.cc
+++ b/src/libstore/filetransfer.cc
@@ -477,8 +477,17 @@ struct curlFileTransfer : public FileTransfer
~curlFileTransfer()
{
- stopWorkerThread();
-
+ try {
+ stopWorkerThread();
+ } catch (nix::Error & e) {
+ // This can only fail if a socket to our own process cannot be
+ // written to, so it is always a bug in the program if it fails.
+ //
+ // Joining the thread would probably only cause a deadlock if this
+ // happened, so just die on purpose.
+ printError("failed to join curl file transfer worker thread: %1%", e.what());
+ std::terminate();
+ }
workerThread.join();
if (curlm) curl_multi_cleanup(curlm);
diff --git a/src/libstore/machines.cc b/src/libstore/machines.cc
index 833482815..d0897b81f 100644
--- a/src/libstore/machines.cc
+++ b/src/libstore/machines.cc
@@ -33,7 +33,7 @@ Machine::Machine(decltype(storeUri) storeUri,
systemTypes(systemTypes),
sshKey(sshKey),
maxJobs(maxJobs),
- speedFactor(speedFactor == 0.0f ? 1.0f : std::move(speedFactor)),
+ speedFactor(speedFactor == 0.0f ? 1.0f : speedFactor),
supportedFeatures(supportedFeatures),
mandatoryFeatures(mandatoryFeatures),
sshPublicHostKey(sshPublicHostKey)
diff --git a/src/libstore/platform/linux.cc b/src/libstore/platform/linux.cc
index 204f62b71..03b8bc0be 100644
--- a/src/libstore/platform/linux.cc
+++ b/src/libstore/platform/linux.cc
@@ -8,8 +8,23 @@
#include <grp.h>
#include <regex>
+#include <sys/prctl.h>
+
+#if HAVE_SECCOMP
+#include <linux/filter.h>
+#include <seccomp.h>
+#endif
namespace nix {
+
+namespace {
+/**
+ * The system for which Nix is compiled.
+ */
+[[gnu::unused]]
+constexpr const std::string_view nativeSystem = SYSTEM;
+}
+
static RegisterStoreImplementation<LinuxLocalStore, LocalStoreConfig> regLocalStore;
static void readProcLink(const std::string & file, UncheckedRoots & roots)
@@ -119,6 +134,617 @@ void LinuxLocalStore::findPlatformRoots(UncheckedRoots & unchecked)
readFileRoots("/proc/sys/kernel/poweroff_cmd", unchecked);
}
+#if HAVE_SECCOMP
+
+static void allowSyscall(scmp_filter_ctx ctx, int syscall) {
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscall, 0) != 0)
+ throw SysError("unable to add seccomp rule");
+}
+
+#define ALLOW_CHMOD_IF_SAFE(ctx, syscall, modePos) \
+ if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscall, 1, SCMP_A##modePos(SCMP_CMP_MASKED_EQ, S_ISUID | S_ISGID, 0)) != 0 || \
+ seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), syscall, 1, SCMP_A##modePos(SCMP_CMP_MASKED_EQ, S_ISUID, S_ISUID)) != 0 || \
+ seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), syscall, 1, SCMP_A##modePos(SCMP_CMP_MASKED_EQ, S_ISGID, S_ISGID)) != 0) \
+ throw SysError("unable to add seccomp rule");
+
+static std::vector<struct sock_filter> compileSyscallFilter()
+{
+ scmp_filter_ctx ctx;
+
+ // Pretend that syscalls we don't yet know about don't exist.
+ // This is the best option for compatibility: after all, they did in fact not exist not too long ago.
+ if (!(ctx = seccomp_init(SCMP_ACT_ERRNO(ENOSYS))))
+ throw SysError("unable to initialize seccomp mode 2");
+
+ Finally cleanup([&]() {
+ seccomp_release(ctx);
+ });
+
+ if (nativeSystem == "x86_64-linux" &&
+ seccomp_arch_add(ctx, SCMP_ARCH_X86) != 0)
+ throw SysError("unable to add 32-bit seccomp architecture");
+
+ if (nativeSystem == "x86_64-linux" &&
+ seccomp_arch_add(ctx, SCMP_ARCH_X32) != 0)
+ throw SysError("unable to add X32 seccomp architecture");
+
+ if (nativeSystem == "aarch64-linux" &&
+ seccomp_arch_add(ctx, SCMP_ARCH_ARM) != 0)
+ printError("unable to add ARM seccomp architecture; this may result in spurious build failures if running 32-bit ARM processes");
+
+ if (nativeSystem == "mips64-linux" &&
+ seccomp_arch_add(ctx, SCMP_ARCH_MIPS) != 0)
+ printError("unable to add mips seccomp architecture");
+
+ if (nativeSystem == "mips64-linux" &&
+ seccomp_arch_add(ctx, SCMP_ARCH_MIPS64N32) != 0)
+ printError("unable to add mips64-*abin32 seccomp architecture");
+
+ if (nativeSystem == "mips64el-linux" &&
+ seccomp_arch_add(ctx, SCMP_ARCH_MIPSEL) != 0)
+ printError("unable to add mipsel seccomp architecture");
+
+ if (nativeSystem == "mips64el-linux" &&
+ seccomp_arch_add(ctx, SCMP_ARCH_MIPSEL64N32) != 0)
+ printError("unable to add mips64el-*abin32 seccomp architecture");
+
+ // This list is intended for machine consumption.
+ // Please keep its format, order and BEGIN/END markers.
+ //
+ // Currently, it is up to date with libseccomp 2.5.5 and glibc 2.39.
+ // Run check-syscalls to determine which new syscalls should be added.
+ // New syscalls must be audited and handled in a way that blocks the following dangerous operations:
+ // * Creation of non-empty setuid/setgid files
+ // * Creation of extended attributes (including ACLs)
+ //
+ // BEGIN extract-syscalls
+ allowSyscall(ctx, SCMP_SYS(accept));
+ allowSyscall(ctx, SCMP_SYS(accept4));
+ allowSyscall(ctx, SCMP_SYS(access));
+ allowSyscall(ctx, SCMP_SYS(acct));
+ allowSyscall(ctx, SCMP_SYS(add_key));
+ allowSyscall(ctx, SCMP_SYS(adjtimex));
+ allowSyscall(ctx, SCMP_SYS(afs_syscall));
+ allowSyscall(ctx, SCMP_SYS(alarm));
+ allowSyscall(ctx, SCMP_SYS(arch_prctl));
+ allowSyscall(ctx, SCMP_SYS(arm_fadvise64_64));
+ allowSyscall(ctx, SCMP_SYS(arm_sync_file_range));
+ allowSyscall(ctx, SCMP_SYS(bdflush));
+ allowSyscall(ctx, SCMP_SYS(bind));
+ allowSyscall(ctx, SCMP_SYS(bpf));
+ allowSyscall(ctx, SCMP_SYS(break));
+ allowSyscall(ctx, SCMP_SYS(breakpoint));
+ allowSyscall(ctx, SCMP_SYS(brk));
+ allowSyscall(ctx, SCMP_SYS(cachectl));
+ allowSyscall(ctx, SCMP_SYS(cacheflush));
+ allowSyscall(ctx, SCMP_SYS(cachestat));
+ allowSyscall(ctx, SCMP_SYS(capget));
+ allowSyscall(ctx, SCMP_SYS(capset));
+ allowSyscall(ctx, SCMP_SYS(chdir));
+ // skip chmod (dangerous)
+ allowSyscall(ctx, SCMP_SYS(chown));
+ allowSyscall(ctx, SCMP_SYS(chown32));
+ allowSyscall(ctx, SCMP_SYS(chroot));
+ allowSyscall(ctx, SCMP_SYS(clock_adjtime));
+ allowSyscall(ctx, SCMP_SYS(clock_adjtime64));
+ allowSyscall(ctx, SCMP_SYS(clock_getres));
+ allowSyscall(ctx, SCMP_SYS(clock_getres_time64));
+ allowSyscall(ctx, SCMP_SYS(clock_gettime));
+ allowSyscall(ctx, SCMP_SYS(clock_gettime64));
+ allowSyscall(ctx, SCMP_SYS(clock_nanosleep));
+ allowSyscall(ctx, SCMP_SYS(clock_nanosleep_time64));
+ allowSyscall(ctx, SCMP_SYS(clock_settime));
+ allowSyscall(ctx, SCMP_SYS(clock_settime64));
+ allowSyscall(ctx, SCMP_SYS(clone));
+ allowSyscall(ctx, SCMP_SYS(clone3));
+ allowSyscall(ctx, SCMP_SYS(close));
+ allowSyscall(ctx, SCMP_SYS(close_range));
+ allowSyscall(ctx, SCMP_SYS(connect));
+ allowSyscall(ctx, SCMP_SYS(copy_file_range));
+ allowSyscall(ctx, SCMP_SYS(creat));
+ allowSyscall(ctx, SCMP_SYS(create_module));
+ allowSyscall(ctx, SCMP_SYS(delete_module));
+ allowSyscall(ctx, SCMP_SYS(dup));
+ allowSyscall(ctx, SCMP_SYS(dup2));
+ allowSyscall(ctx, SCMP_SYS(dup3));
+ allowSyscall(ctx, SCMP_SYS(epoll_create));
+ allowSyscall(ctx, SCMP_SYS(epoll_create1));
+ allowSyscall(ctx, SCMP_SYS(epoll_ctl));
+ allowSyscall(ctx, SCMP_SYS(epoll_ctl_old));
+ allowSyscall(ctx, SCMP_SYS(epoll_pwait));
+ allowSyscall(ctx, SCMP_SYS(epoll_pwait2));
+ allowSyscall(ctx, SCMP_SYS(epoll_wait));
+ allowSyscall(ctx, SCMP_SYS(epoll_wait_old));
+ allowSyscall(ctx, SCMP_SYS(eventfd));
+ allowSyscall(ctx, SCMP_SYS(eventfd2));
+ allowSyscall(ctx, SCMP_SYS(execve));
+ allowSyscall(ctx, SCMP_SYS(execveat));
+ allowSyscall(ctx, SCMP_SYS(exit));
+ allowSyscall(ctx, SCMP_SYS(exit_group));
+ allowSyscall(ctx, SCMP_SYS(faccessat));
+ allowSyscall(ctx, SCMP_SYS(faccessat2));
+ allowSyscall(ctx, SCMP_SYS(fadvise64));
+ allowSyscall(ctx, SCMP_SYS(fadvise64_64));
+ allowSyscall(ctx, SCMP_SYS(fallocate));
+ allowSyscall(ctx, SCMP_SYS(fanotify_init));
+ allowSyscall(ctx, SCMP_SYS(fanotify_mark));
+ allowSyscall(ctx, SCMP_SYS(fchdir));
+ // skip fchmod (dangerous)
+ // skip fchmodat (dangerous)
+ // skip fchmodat2 (dangerous)
+ allowSyscall(ctx, SCMP_SYS(fchown));
+ allowSyscall(ctx, SCMP_SYS(fchown32));
+ allowSyscall(ctx, SCMP_SYS(fchownat));
+ allowSyscall(ctx, SCMP_SYS(fcntl));
+ allowSyscall(ctx, SCMP_SYS(fcntl64));
+ allowSyscall(ctx, SCMP_SYS(fdatasync));
+ allowSyscall(ctx, SCMP_SYS(fgetxattr));
+ allowSyscall(ctx, SCMP_SYS(finit_module));
+ allowSyscall(ctx, SCMP_SYS(flistxattr));
+ allowSyscall(ctx, SCMP_SYS(flock));
+ allowSyscall(ctx, SCMP_SYS(fork));
+ allowSyscall(ctx, SCMP_SYS(fremovexattr));
+ allowSyscall(ctx, SCMP_SYS(fsconfig));
+ // skip fsetxattr (dangerous)
+ allowSyscall(ctx, SCMP_SYS(fsmount));
+ allowSyscall(ctx, SCMP_SYS(fsopen));
+ allowSyscall(ctx, SCMP_SYS(fspick));
+ allowSyscall(ctx, SCMP_SYS(fstat));
+ allowSyscall(ctx, SCMP_SYS(fstat64));
+ allowSyscall(ctx, SCMP_SYS(fstatat64));
+ allowSyscall(ctx, SCMP_SYS(fstatfs));
+ allowSyscall(ctx, SCMP_SYS(fstatfs64));
+ allowSyscall(ctx, SCMP_SYS(fsync));
+ allowSyscall(ctx, SCMP_SYS(ftime));
+ allowSyscall(ctx, SCMP_SYS(ftruncate));
+ allowSyscall(ctx, SCMP_SYS(ftruncate64));
+ allowSyscall(ctx, SCMP_SYS(futex));
+ allowSyscall(ctx, SCMP_SYS(futex_requeue));
+ allowSyscall(ctx, SCMP_SYS(futex_time64));
+ allowSyscall(ctx, SCMP_SYS(futex_wait));
+ allowSyscall(ctx, SCMP_SYS(futex_waitv));
+ allowSyscall(ctx, SCMP_SYS(futex_wake));
+ allowSyscall(ctx, SCMP_SYS(futimesat));
+ allowSyscall(ctx, SCMP_SYS(getcpu));
+ allowSyscall(ctx, SCMP_SYS(getcwd));
+ allowSyscall(ctx, SCMP_SYS(getdents));
+ allowSyscall(ctx, SCMP_SYS(getdents64));
+ allowSyscall(ctx, SCMP_SYS(getegid));
+ allowSyscall(ctx, SCMP_SYS(getegid32));
+ allowSyscall(ctx, SCMP_SYS(geteuid));
+ allowSyscall(ctx, SCMP_SYS(geteuid32));
+ allowSyscall(ctx, SCMP_SYS(getgid));
+ allowSyscall(ctx, SCMP_SYS(getgid32));
+ allowSyscall(ctx, SCMP_SYS(getgroups));
+ allowSyscall(ctx, SCMP_SYS(getgroups32));
+ allowSyscall(ctx, SCMP_SYS(getitimer));
+ allowSyscall(ctx, SCMP_SYS(get_kernel_syms));
+ allowSyscall(ctx, SCMP_SYS(get_mempolicy));
+ allowSyscall(ctx, SCMP_SYS(getpeername));
+ allowSyscall(ctx, SCMP_SYS(getpgid));
+ allowSyscall(ctx, SCMP_SYS(getpgrp));
+ allowSyscall(ctx, SCMP_SYS(getpid));
+ allowSyscall(ctx, SCMP_SYS(getpmsg));
+ allowSyscall(ctx, SCMP_SYS(getppid));
+ allowSyscall(ctx, SCMP_SYS(getpriority));
+ allowSyscall(ctx, SCMP_SYS(getrandom));
+ allowSyscall(ctx, SCMP_SYS(getresgid));
+ allowSyscall(ctx, SCMP_SYS(getresgid32));
+ allowSyscall(ctx, SCMP_SYS(getresuid));
+ allowSyscall(ctx, SCMP_SYS(getresuid32));
+ allowSyscall(ctx, SCMP_SYS(getrlimit));
+ allowSyscall(ctx, SCMP_SYS(get_robust_list));
+ allowSyscall(ctx, SCMP_SYS(getrusage));
+ allowSyscall(ctx, SCMP_SYS(getsid));
+ allowSyscall(ctx, SCMP_SYS(getsockname));
+ allowSyscall(ctx, SCMP_SYS(getsockopt));
+ allowSyscall(ctx, SCMP_SYS(get_thread_area));
+ allowSyscall(ctx, SCMP_SYS(gettid));
+ allowSyscall(ctx, SCMP_SYS(gettimeofday));
+ allowSyscall(ctx, SCMP_SYS(get_tls));
+ allowSyscall(ctx, SCMP_SYS(getuid));
+ allowSyscall(ctx, SCMP_SYS(getuid32));
+ allowSyscall(ctx, SCMP_SYS(getxattr));
+ allowSyscall(ctx, SCMP_SYS(gtty));
+ allowSyscall(ctx, SCMP_SYS(idle));
+ allowSyscall(ctx, SCMP_SYS(init_module));
+ allowSyscall(ctx, SCMP_SYS(inotify_add_watch));
+ allowSyscall(ctx, SCMP_SYS(inotify_init));
+ allowSyscall(ctx, SCMP_SYS(inotify_init1));
+ allowSyscall(ctx, SCMP_SYS(inotify_rm_watch));
+ allowSyscall(ctx, SCMP_SYS(io_cancel));
+ allowSyscall(ctx, SCMP_SYS(ioctl));
+ allowSyscall(ctx, SCMP_SYS(io_destroy));
+ allowSyscall(ctx, SCMP_SYS(io_getevents));
+ allowSyscall(ctx, SCMP_SYS(ioperm));
+ allowSyscall(ctx, SCMP_SYS(io_pgetevents));
+ allowSyscall(ctx, SCMP_SYS(io_pgetevents_time64));
+ allowSyscall(ctx, SCMP_SYS(iopl));
+ allowSyscall(ctx, SCMP_SYS(ioprio_get));
+ allowSyscall(ctx, SCMP_SYS(ioprio_set));
+ allowSyscall(ctx, SCMP_SYS(io_setup));
+ allowSyscall(ctx, SCMP_SYS(io_submit));
+ // skip io_uring_enter (may become dangerous)
+ // skip io_uring_register (may become dangerous)
+ // skip io_uring_setup (may become dangerous)
+ allowSyscall(ctx, SCMP_SYS(ipc));
+ allowSyscall(ctx, SCMP_SYS(kcmp));
+ allowSyscall(ctx, SCMP_SYS(kexec_file_load));
+ allowSyscall(ctx, SCMP_SYS(kexec_load));
+ allowSyscall(ctx, SCMP_SYS(keyctl));
+ allowSyscall(ctx, SCMP_SYS(kill));
+ allowSyscall(ctx, SCMP_SYS(landlock_add_rule));
+ allowSyscall(ctx, SCMP_SYS(landlock_create_ruleset));
+ allowSyscall(ctx, SCMP_SYS(landlock_restrict_self));
+ allowSyscall(ctx, SCMP_SYS(lchown));
+ allowSyscall(ctx, SCMP_SYS(lchown32));
+ allowSyscall(ctx, SCMP_SYS(lgetxattr));
+ allowSyscall(ctx, SCMP_SYS(link));
+ allowSyscall(ctx, SCMP_SYS(linkat));
+ allowSyscall(ctx, SCMP_SYS(listen));
+ allowSyscall(ctx, SCMP_SYS(listxattr));
+ allowSyscall(ctx, SCMP_SYS(llistxattr));
+ allowSyscall(ctx, SCMP_SYS(_llseek));
+ allowSyscall(ctx, SCMP_SYS(lock));
+ allowSyscall(ctx, SCMP_SYS(lookup_dcookie));
+ allowSyscall(ctx, SCMP_SYS(lremovexattr));
+ allowSyscall(ctx, SCMP_SYS(lseek));
+ // skip lsetxattr (dangerous)
+ allowSyscall(ctx, SCMP_SYS(lstat));
+ allowSyscall(ctx, SCMP_SYS(lstat64));
+ allowSyscall(ctx, SCMP_SYS(madvise));
+ allowSyscall(ctx, SCMP_SYS(map_shadow_stack));
+ allowSyscall(ctx, SCMP_SYS(mbind));
+ allowSyscall(ctx, SCMP_SYS(membarrier));
+ allowSyscall(ctx, SCMP_SYS(memfd_create));
+ allowSyscall(ctx, SCMP_SYS(memfd_secret));
+ allowSyscall(ctx, SCMP_SYS(migrate_pages));
+ allowSyscall(ctx, SCMP_SYS(mincore));
+ allowSyscall(ctx, SCMP_SYS(mkdir));
+ allowSyscall(ctx, SCMP_SYS(mkdirat));
+ allowSyscall(ctx, SCMP_SYS(mknod));
+ allowSyscall(ctx, SCMP_SYS(mknodat));
+ allowSyscall(ctx, SCMP_SYS(mlock));
+ allowSyscall(ctx, SCMP_SYS(mlock2));
+ allowSyscall(ctx, SCMP_SYS(mlockall));
+ allowSyscall(ctx, SCMP_SYS(mmap));
+ allowSyscall(ctx, SCMP_SYS(mmap2));
+ allowSyscall(ctx, SCMP_SYS(modify_ldt));
+ allowSyscall(ctx, SCMP_SYS(mount));
+ allowSyscall(ctx, SCMP_SYS(mount_setattr));
+ allowSyscall(ctx, SCMP_SYS(move_mount));
+ allowSyscall(ctx, SCMP_SYS(move_pages));
+ allowSyscall(ctx, SCMP_SYS(mprotect));
+ allowSyscall(ctx, SCMP_SYS(mpx));
+ allowSyscall(ctx, SCMP_SYS(mq_getsetattr));
+ allowSyscall(ctx, SCMP_SYS(mq_notify));
+ allowSyscall(ctx, SCMP_SYS(mq_open));
+ allowSyscall(ctx, SCMP_SYS(mq_timedreceive));
+ allowSyscall(ctx, SCMP_SYS(mq_timedreceive_time64));
+ allowSyscall(ctx, SCMP_SYS(mq_timedsend));
+ allowSyscall(ctx, SCMP_SYS(mq_timedsend_time64));
+ allowSyscall(ctx, SCMP_SYS(mq_unlink));
+ allowSyscall(ctx, SCMP_SYS(mremap));
+ allowSyscall(ctx, SCMP_SYS(msgctl));
+ allowSyscall(ctx, SCMP_SYS(msgget));
+ allowSyscall(ctx, SCMP_SYS(msgrcv));
+ allowSyscall(ctx, SCMP_SYS(msgsnd));
+ allowSyscall(ctx, SCMP_SYS(msync));
+ allowSyscall(ctx, SCMP_SYS(multiplexer));
+ allowSyscall(ctx, SCMP_SYS(munlock));
+ allowSyscall(ctx, SCMP_SYS(munlockall));
+ allowSyscall(ctx, SCMP_SYS(munmap));
+ allowSyscall(ctx, SCMP_SYS(name_to_handle_at));
+ allowSyscall(ctx, SCMP_SYS(nanosleep));
+ allowSyscall(ctx, SCMP_SYS(newfstatat));
+ allowSyscall(ctx, SCMP_SYS(_newselect));
+ allowSyscall(ctx, SCMP_SYS(nfsservctl));
+ allowSyscall(ctx, SCMP_SYS(nice));
+ allowSyscall(ctx, SCMP_SYS(oldfstat));
+ allowSyscall(ctx, SCMP_SYS(oldlstat));
+ allowSyscall(ctx, SCMP_SYS(oldolduname));
+ allowSyscall(ctx, SCMP_SYS(oldstat));
+ allowSyscall(ctx, SCMP_SYS(olduname));
+ allowSyscall(ctx, SCMP_SYS(open));
+ allowSyscall(ctx, SCMP_SYS(openat));
+ allowSyscall(ctx, SCMP_SYS(openat2));
+ allowSyscall(ctx, SCMP_SYS(open_by_handle_at));
+ allowSyscall(ctx, SCMP_SYS(open_tree));
+ allowSyscall(ctx, SCMP_SYS(pause));
+ allowSyscall(ctx, SCMP_SYS(pciconfig_iobase));
+ allowSyscall(ctx, SCMP_SYS(pciconfig_read));
+ allowSyscall(ctx, SCMP_SYS(pciconfig_write));
+ allowSyscall(ctx, SCMP_SYS(perf_event_open));
+ allowSyscall(ctx, SCMP_SYS(personality));
+ allowSyscall(ctx, SCMP_SYS(pidfd_getfd));
+ allowSyscall(ctx, SCMP_SYS(pidfd_open));
+ allowSyscall(ctx, SCMP_SYS(pidfd_send_signal));
+ allowSyscall(ctx, SCMP_SYS(pipe));
+ allowSyscall(ctx, SCMP_SYS(pipe2));
+ allowSyscall(ctx, SCMP_SYS(pivot_root));
+ allowSyscall(ctx, SCMP_SYS(pkey_alloc));
+ allowSyscall(ctx, SCMP_SYS(pkey_free));
+ allowSyscall(ctx, SCMP_SYS(pkey_mprotect));
+ allowSyscall(ctx, SCMP_SYS(poll));
+ allowSyscall(ctx, SCMP_SYS(ppoll));
+ allowSyscall(ctx, SCMP_SYS(ppoll_time64));
+ allowSyscall(ctx, SCMP_SYS(prctl));
+ allowSyscall(ctx, SCMP_SYS(pread64));
+ allowSyscall(ctx, SCMP_SYS(preadv));
+ allowSyscall(ctx, SCMP_SYS(preadv2));
+ allowSyscall(ctx, SCMP_SYS(prlimit64));
+ allowSyscall(ctx, SCMP_SYS(process_madvise));
+ allowSyscall(ctx, SCMP_SYS(process_mrelease));
+ allowSyscall(ctx, SCMP_SYS(process_vm_readv));
+ allowSyscall(ctx, SCMP_SYS(process_vm_writev));
+ allowSyscall(ctx, SCMP_SYS(prof));
+ allowSyscall(ctx, SCMP_SYS(profil));
+ allowSyscall(ctx, SCMP_SYS(pselect6));
+ allowSyscall(ctx, SCMP_SYS(pselect6_time64));
+ allowSyscall(ctx, SCMP_SYS(ptrace));
+ allowSyscall(ctx, SCMP_SYS(putpmsg));
+ allowSyscall(ctx, SCMP_SYS(pwrite64));
+ allowSyscall(ctx, SCMP_SYS(pwritev));
+ allowSyscall(ctx, SCMP_SYS(pwritev2));
+ allowSyscall(ctx, SCMP_SYS(query_module));
+ allowSyscall(ctx, SCMP_SYS(quotactl));
+ allowSyscall(ctx, SCMP_SYS(quotactl_fd));
+ allowSyscall(ctx, SCMP_SYS(read));
+ allowSyscall(ctx, SCMP_SYS(readahead));
+ allowSyscall(ctx, SCMP_SYS(readdir));
+ allowSyscall(ctx, SCMP_SYS(readlink));
+ allowSyscall(ctx, SCMP_SYS(readlinkat));
+ allowSyscall(ctx, SCMP_SYS(readv));
+ allowSyscall(ctx, SCMP_SYS(reboot));
+ allowSyscall(ctx, SCMP_SYS(recv));
+ allowSyscall(ctx, SCMP_SYS(recvfrom));
+ allowSyscall(ctx, SCMP_SYS(recvmmsg));
+ allowSyscall(ctx, SCMP_SYS(recvmmsg_time64));
+ allowSyscall(ctx, SCMP_SYS(recvmsg));
+ allowSyscall(ctx, SCMP_SYS(remap_file_pages));
+ allowSyscall(ctx, SCMP_SYS(removexattr));
+ allowSyscall(ctx, SCMP_SYS(rename));
+ allowSyscall(ctx, SCMP_SYS(renameat));
+ allowSyscall(ctx, SCMP_SYS(renameat2));
+ allowSyscall(ctx, SCMP_SYS(request_key));
+ allowSyscall(ctx, SCMP_SYS(restart_syscall));
+ allowSyscall(ctx, SCMP_SYS(riscv_flush_icache));
+ allowSyscall(ctx, SCMP_SYS(rmdir));
+ allowSyscall(ctx, SCMP_SYS(rseq));
+ allowSyscall(ctx, SCMP_SYS(rtas));
+ allowSyscall(ctx, SCMP_SYS(rt_sigaction));
+ allowSyscall(ctx, SCMP_SYS(rt_sigpending));
+ allowSyscall(ctx, SCMP_SYS(rt_sigprocmask));
+ allowSyscall(ctx, SCMP_SYS(rt_sigqueueinfo));
+ allowSyscall(ctx, SCMP_SYS(rt_sigreturn));
+ allowSyscall(ctx, SCMP_SYS(rt_sigsuspend));
+ allowSyscall(ctx, SCMP_SYS(rt_sigtimedwait));
+ allowSyscall(ctx, SCMP_SYS(rt_sigtimedwait_time64));
+ allowSyscall(ctx, SCMP_SYS(rt_tgsigqueueinfo));
+ allowSyscall(ctx, SCMP_SYS(s390_guarded_storage));
+ allowSyscall(ctx, SCMP_SYS(s390_pci_mmio_read));
+ allowSyscall(ctx, SCMP_SYS(s390_pci_mmio_write));
+ allowSyscall(ctx, SCMP_SYS(s390_runtime_instr));
+ allowSyscall(ctx, SCMP_SYS(s390_sthyi));
+ allowSyscall(ctx, SCMP_SYS(sched_getaffinity));
+ allowSyscall(ctx, SCMP_SYS(sched_getattr));
+ allowSyscall(ctx, SCMP_SYS(sched_getparam));
+ allowSyscall(ctx, SCMP_SYS(sched_get_priority_max));
+ allowSyscall(ctx, SCMP_SYS(sched_get_priority_min));
+ allowSyscall(ctx, SCMP_SYS(sched_getscheduler));
+ allowSyscall(ctx, SCMP_SYS(sched_rr_get_interval));
+ allowSyscall(ctx, SCMP_SYS(sched_rr_get_interval_time64));
+ allowSyscall(ctx, SCMP_SYS(sched_setaffinity));
+ allowSyscall(ctx, SCMP_SYS(sched_setattr));
+ allowSyscall(ctx, SCMP_SYS(sched_setparam));
+ allowSyscall(ctx, SCMP_SYS(sched_setscheduler));
+ allowSyscall(ctx, SCMP_SYS(sched_yield));
+ allowSyscall(ctx, SCMP_SYS(seccomp));
+ allowSyscall(ctx, SCMP_SYS(security));
+ allowSyscall(ctx, SCMP_SYS(select));
+ allowSyscall(ctx, SCMP_SYS(semctl));
+ allowSyscall(ctx, SCMP_SYS(semget));
+ allowSyscall(ctx, SCMP_SYS(semop));
+ allowSyscall(ctx, SCMP_SYS(semtimedop));
+ allowSyscall(ctx, SCMP_SYS(semtimedop_time64));
+ allowSyscall(ctx, SCMP_SYS(send));
+ allowSyscall(ctx, SCMP_SYS(sendfile));
+ allowSyscall(ctx, SCMP_SYS(sendfile64));
+ allowSyscall(ctx, SCMP_SYS(sendmmsg));
+ allowSyscall(ctx, SCMP_SYS(sendmsg));
+ allowSyscall(ctx, SCMP_SYS(sendto));
+ allowSyscall(ctx, SCMP_SYS(setdomainname));
+ allowSyscall(ctx, SCMP_SYS(setfsgid));
+ allowSyscall(ctx, SCMP_SYS(setfsgid32));
+ allowSyscall(ctx, SCMP_SYS(setfsuid));
+ allowSyscall(ctx, SCMP_SYS(setfsuid32));
+ allowSyscall(ctx, SCMP_SYS(setgid));
+ allowSyscall(ctx, SCMP_SYS(setgid32));
+ allowSyscall(ctx, SCMP_SYS(setgroups));
+ allowSyscall(ctx, SCMP_SYS(setgroups32));
+ allowSyscall(ctx, SCMP_SYS(sethostname));
+ allowSyscall(ctx, SCMP_SYS(setitimer));
+ allowSyscall(ctx, SCMP_SYS(set_mempolicy));
+ allowSyscall(ctx, SCMP_SYS(set_mempolicy_home_node));
+ allowSyscall(ctx, SCMP_SYS(setns));
+ allowSyscall(ctx, SCMP_SYS(setpgid));
+ allowSyscall(ctx, SCMP_SYS(setpriority));
+ allowSyscall(ctx, SCMP_SYS(setregid));
+ allowSyscall(ctx, SCMP_SYS(setregid32));
+ allowSyscall(ctx, SCMP_SYS(setresgid));
+ allowSyscall(ctx, SCMP_SYS(setresgid32));
+ allowSyscall(ctx, SCMP_SYS(setresuid));
+ allowSyscall(ctx, SCMP_SYS(setresuid32));
+ allowSyscall(ctx, SCMP_SYS(setreuid));
+ allowSyscall(ctx, SCMP_SYS(setreuid32));
+ allowSyscall(ctx, SCMP_SYS(setrlimit));
+ allowSyscall(ctx, SCMP_SYS(set_robust_list));
+ allowSyscall(ctx, SCMP_SYS(setsid));
+ allowSyscall(ctx, SCMP_SYS(setsockopt));
+ allowSyscall(ctx, SCMP_SYS(set_thread_area));
+ allowSyscall(ctx, SCMP_SYS(set_tid_address));
+ allowSyscall(ctx, SCMP_SYS(settimeofday));
+ allowSyscall(ctx, SCMP_SYS(set_tls));
+ allowSyscall(ctx, SCMP_SYS(setuid));
+ allowSyscall(ctx, SCMP_SYS(setuid32));
+ // skip setxattr (dangerous)
+ allowSyscall(ctx, SCMP_SYS(sgetmask));
+ allowSyscall(ctx, SCMP_SYS(shmat));
+ allowSyscall(ctx, SCMP_SYS(shmctl));
+ allowSyscall(ctx, SCMP_SYS(shmdt));
+ allowSyscall(ctx, SCMP_SYS(shmget));
+ allowSyscall(ctx, SCMP_SYS(shutdown));
+ allowSyscall(ctx, SCMP_SYS(sigaction));
+ allowSyscall(ctx, SCMP_SYS(sigaltstack));
+ allowSyscall(ctx, SCMP_SYS(signal));
+ allowSyscall(ctx, SCMP_SYS(signalfd));
+ allowSyscall(ctx, SCMP_SYS(signalfd4));
+ allowSyscall(ctx, SCMP_SYS(sigpending));
+ allowSyscall(ctx, SCMP_SYS(sigprocmask));
+ allowSyscall(ctx, SCMP_SYS(sigreturn));
+ allowSyscall(ctx, SCMP_SYS(sigsuspend));
+ allowSyscall(ctx, SCMP_SYS(socket));
+ allowSyscall(ctx, SCMP_SYS(socketcall));
+ allowSyscall(ctx, SCMP_SYS(socketpair));
+ allowSyscall(ctx, SCMP_SYS(splice));
+ allowSyscall(ctx, SCMP_SYS(spu_create));
+ allowSyscall(ctx, SCMP_SYS(spu_run));
+ allowSyscall(ctx, SCMP_SYS(ssetmask));
+ allowSyscall(ctx, SCMP_SYS(stat));
+ allowSyscall(ctx, SCMP_SYS(stat64));
+ allowSyscall(ctx, SCMP_SYS(statfs));
+ allowSyscall(ctx, SCMP_SYS(statfs64));
+ allowSyscall(ctx, SCMP_SYS(statx));
+ allowSyscall(ctx, SCMP_SYS(stime));
+ allowSyscall(ctx, SCMP_SYS(stty));
+ allowSyscall(ctx, SCMP_SYS(subpage_prot));
+ allowSyscall(ctx, SCMP_SYS(swapcontext));
+ allowSyscall(ctx, SCMP_SYS(swapoff));
+ allowSyscall(ctx, SCMP_SYS(swapon));
+ allowSyscall(ctx, SCMP_SYS(switch_endian));
+ allowSyscall(ctx, SCMP_SYS(symlink));
+ allowSyscall(ctx, SCMP_SYS(symlinkat));
+ allowSyscall(ctx, SCMP_SYS(sync));
+ allowSyscall(ctx, SCMP_SYS(sync_file_range));
+ allowSyscall(ctx, SCMP_SYS(sync_file_range2));
+ allowSyscall(ctx, SCMP_SYS(syncfs));
+ allowSyscall(ctx, SCMP_SYS(syscall));
+ allowSyscall(ctx, SCMP_SYS(_sysctl));
+ allowSyscall(ctx, SCMP_SYS(sys_debug_setcontext));
+ allowSyscall(ctx, SCMP_SYS(sysfs));
+ allowSyscall(ctx, SCMP_SYS(sysinfo));
+ allowSyscall(ctx, SCMP_SYS(syslog));
+ allowSyscall(ctx, SCMP_SYS(sysmips));
+ allowSyscall(ctx, SCMP_SYS(tee));
+ allowSyscall(ctx, SCMP_SYS(tgkill));
+ allowSyscall(ctx, SCMP_SYS(time));
+ allowSyscall(ctx, SCMP_SYS(timer_create));
+ allowSyscall(ctx, SCMP_SYS(timer_delete));
+ allowSyscall(ctx, SCMP_SYS(timerfd));
+ allowSyscall(ctx, SCMP_SYS(timerfd_create));
+ allowSyscall(ctx, SCMP_SYS(timerfd_gettime));
+ allowSyscall(ctx, SCMP_SYS(timerfd_gettime64));
+ allowSyscall(ctx, SCMP_SYS(timerfd_settime));
+ allowSyscall(ctx, SCMP_SYS(timerfd_settime64));
+ allowSyscall(ctx, SCMP_SYS(timer_getoverrun));
+ allowSyscall(ctx, SCMP_SYS(timer_gettime));
+ allowSyscall(ctx, SCMP_SYS(timer_gettime64));
+ allowSyscall(ctx, SCMP_SYS(timer_settime));
+ allowSyscall(ctx, SCMP_SYS(timer_settime64));
+ allowSyscall(ctx, SCMP_SYS(times));
+ allowSyscall(ctx, SCMP_SYS(tkill));
+ allowSyscall(ctx, SCMP_SYS(truncate));
+ allowSyscall(ctx, SCMP_SYS(truncate64));
+ allowSyscall(ctx, SCMP_SYS(tuxcall));
+ allowSyscall(ctx, SCMP_SYS(ugetrlimit));
+ allowSyscall(ctx, SCMP_SYS(ulimit));
+ allowSyscall(ctx, SCMP_SYS(umask));
+ allowSyscall(ctx, SCMP_SYS(umount));
+ allowSyscall(ctx, SCMP_SYS(umount2));
+ allowSyscall(ctx, SCMP_SYS(uname));
+ allowSyscall(ctx, SCMP_SYS(unlink));
+ allowSyscall(ctx, SCMP_SYS(unlinkat));
+ allowSyscall(ctx, SCMP_SYS(unshare));
+ allowSyscall(ctx, SCMP_SYS(uselib));
+ allowSyscall(ctx, SCMP_SYS(userfaultfd));
+ allowSyscall(ctx, SCMP_SYS(usr26));
+ allowSyscall(ctx, SCMP_SYS(usr32));
+ allowSyscall(ctx, SCMP_SYS(ustat));
+ allowSyscall(ctx, SCMP_SYS(utime));
+ allowSyscall(ctx, SCMP_SYS(utimensat));
+ allowSyscall(ctx, SCMP_SYS(utimensat_time64));
+ allowSyscall(ctx, SCMP_SYS(utimes));
+ allowSyscall(ctx, SCMP_SYS(vfork));
+ allowSyscall(ctx, SCMP_SYS(vhangup));
+ allowSyscall(ctx, SCMP_SYS(vm86));
+ allowSyscall(ctx, SCMP_SYS(vm86old));
+ allowSyscall(ctx, SCMP_SYS(vmsplice));
+ allowSyscall(ctx, SCMP_SYS(vserver));
+ allowSyscall(ctx, SCMP_SYS(wait4));
+ allowSyscall(ctx, SCMP_SYS(waitid));
+ allowSyscall(ctx, SCMP_SYS(waitpid));
+ allowSyscall(ctx, SCMP_SYS(write));
+ allowSyscall(ctx, SCMP_SYS(writev));
+ // END extract-syscalls
+
+ // chmod family: prevent adding setuid/setgid bits to existing files.
+ // The Nix store does not support setuid/setgid, and even their temporary creation can weaken the security of the sandbox.
+ ALLOW_CHMOD_IF_SAFE(ctx, SCMP_SYS(chmod), 1);
+ ALLOW_CHMOD_IF_SAFE(ctx, SCMP_SYS(fchmod), 1);
+ ALLOW_CHMOD_IF_SAFE(ctx, SCMP_SYS(fchmodat), 2);
+ ALLOW_CHMOD_IF_SAFE(ctx, SCMP_SYS(fchmodat2), 2);
+
+ // setxattr family: prevent creation of extended attributes or ACLs.
+ // Not all filesystems support them, and they're incompatible with the NAR format.
+ if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(setxattr), 0) != 0 ||
+ seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(lsetxattr), 0) != 0 ||
+ seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(fsetxattr), 0) != 0)
+ throw SysError("unable to add seccomp rule");
+
+ Pipe filterPipe;
+ filterPipe.create();
+ auto filterBytes_ = std::async([&]() {
+ return drainFD(filterPipe.readSide.get());
+ });
+ if (seccomp_export_bpf(ctx, filterPipe.writeSide.get()) != 0)
+ throw SysError("unable to compile seccomp BPF program");
+ filterPipe.writeSide.close();
+ auto filterBytes = filterBytes_.get();
+
+ assert(filterBytes.size() % sizeof(struct sock_filter) == 0);
+ std::vector<struct sock_filter> filter(filterBytes.size() / sizeof(struct sock_filter));
+ std::memcpy(filter.data(), filterBytes.data(), filterBytes.size());
+ return filter;
+}
+
+static const std::vector<struct sock_filter> &getSyscallFilter()
+{
+ static auto filter = compileSyscallFilter();
+ return filter;
+}
+
+#endif
+
+void LinuxLocalDerivationGoal::setupSyscallFilter()
+{
+ // Set the NO_NEW_PRIVS prctl flag.
+ // This both makes loading seccomp filters work for unprivileged users,
+ // and is an additional security measure in its own right.
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
+ throw SysError("PR_SET_NO_NEW_PRIVS failed");
+#if HAVE_SECCOMP
+ const auto &seccompBPF = getSyscallFilter();
+ assert(seccompBPF.size() <= std::numeric_limits<unsigned short>::max());
+ struct sock_fprog fprog = {
+ .len = static_cast<unsigned short>(seccompBPF.size()),
+ // the kernel does not actually write to the filter
+ .filter = const_cast<struct sock_filter *>(seccompBPF.data()),
+ };
+ if (syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, 0, &fprog) != 0)
+ throw SysError("unable to load seccomp BPF program");
+#endif
+}
+
void LinuxLocalDerivationGoal::prepareSandbox()
{
/* Create a temporary directory in which we set up the chroot
@@ -208,6 +834,13 @@ void LinuxLocalDerivationGoal::prepareSandbox()
Pid LinuxLocalDerivationGoal::startChild(std::function<void()> openSlave)
{
+#if HAVE_SECCOMP
+ // Our seccomp filter program is surprisingly expensive to compile (~10ms).
+ // For this reason, we precompile it once and then cache it.
+ // This has to be done in the parent so that all builds get to use the same cache.
+ getSyscallFilter();
+#endif
+
// If we're not sandboxing no need to faff about, use the fallback
if (!useChroot) {
return LocalDerivationGoal::startChild(openSlave);
diff --git a/src/libstore/platform/linux.hh b/src/libstore/platform/linux.hh
index 2173205bc..c8842e09c 100644
--- a/src/libstore/platform/linux.hh
+++ b/src/libstore/platform/linux.hh
@@ -59,6 +59,11 @@ private:
*/
void killSandbox(bool getStatus) override;
+ /**
+ * Set up system call filtering using seccomp, unless disabled at build time.
+ * This also sets the NO_NEW_PRIVS flag.
+ */
+ void setupSyscallFilter() override;
bool supportsUidRange() override
{
diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc
index 5fb33ef56..d4da18f14 100644
--- a/src/libutil/archive.cc
+++ b/src/libutil/archive.cc
@@ -192,7 +192,7 @@ static Generator<Entry> parseObject(Source & source, const Path & path)
#define EXPECT(raw, kind) \
do { \
const auto s = readString(source); \
- if (s != raw) { \
+ if (s != (raw)) { \
throw badArchive("expected " kind " tag"); \
} \
co_yield MetadataString{s}; \
diff --git a/src/libutil/file-descriptor.cc b/src/libutil/file-descriptor.cc
index ab69b5754..037cd5297 100644
--- a/src/libutil/file-descriptor.cc
+++ b/src/libutil/file-descriptor.cc
@@ -131,7 +131,7 @@ AutoCloseFD::AutoCloseFD(AutoCloseFD && that) : fd{that.fd}
}
-AutoCloseFD & AutoCloseFD::operator =(AutoCloseFD && that)
+AutoCloseFD & AutoCloseFD::operator =(AutoCloseFD && that) noexcept(false)
{
close();
fd = that.fd;
diff --git a/src/libutil/hash.cc b/src/libutil/hash.cc
index a762dc940..0ce82f273 100644
--- a/src/libutil/hash.cc
+++ b/src/libutil/hash.cc
@@ -229,7 +229,7 @@ Hash::Hash(std::string_view rest, HashType type, bool isSRI)
for (unsigned int n = 0; n < rest.size(); ++n) {
char c = rest[rest.size() - n - 1];
- unsigned char digit;
+ size_t digit;
for (digit = 0; digit < base32Chars.size(); ++digit) /* !!! slow */
if (base32Chars[digit] == c) break;
if (digit >= 32)
diff --git a/src/libutil/logging.cc b/src/libutil/logging.cc
index 53460f729..cbeb7aa36 100644
--- a/src/libutil/logging.cc
+++ b/src/libutil/logging.cc
@@ -37,7 +37,7 @@ void Logger::warn(const std::string & msg)
void Logger::writeToStdout(std::string_view s)
{
- writeFull(STDOUT_FILENO, s);
+ writeFull(STDOUT_FILENO, filterANSIEscapes(s, !shouldANSI(), std::numeric_limits<unsigned int>::max(), false));
writeFull(STDOUT_FILENO, "\n");
}
diff --git a/src/libutil/shlex.cc b/src/libutil/shlex.cc
index 21fa0502a..b923fef65 100644
--- a/src/libutil/shlex.cc
+++ b/src/libutil/shlex.cc
@@ -62,6 +62,8 @@ std::vector<std::string> shell_split(const std::string & input)
begin = ++iterator;
}
break;
+ // no other relevant cases; silence exhaustiveness compiler warning
+ default: break;
}
}
diff --git a/src/libutil/terminal.cc b/src/libutil/terminal.cc
index b58331d04..2ba1cb81b 100644
--- a/src/libutil/terminal.cc
+++ b/src/libutil/terminal.cc
@@ -9,12 +9,25 @@ namespace nix {
bool shouldANSI()
{
- return isatty(STDERR_FILENO)
- && getEnv("TERM").value_or("dumb") != "dumb"
- && !(getEnv("NO_COLOR").has_value() || getEnv("NOCOLOR").has_value());
+ // Implements the behaviour described by https://bixense.com/clicolors/
+ // As well as https://force-color.org/ for compatibility, since it fits in the same shape.
+ // NO_COLOR CLICOLOR CLICOLOR_FORCE Colours?
+ // set x x No
+ // unset x set Yes
+ // unset x unset If attached to a terminal
+ // [we choose the "modern" approach of colour-by-default]
+ auto compute = []() -> bool {
+ bool mustNotColour = getEnv("NO_COLOR").has_value() || getEnv("NOCOLOR").has_value();
+ bool shouldForce = getEnv("CLICOLOR_FORCE").has_value() || getEnv("FORCE_COLOR").has_value();
+ bool isTerminal = isatty(STDERR_FILENO) && getEnv("TERM").value_or("dumb") != "dumb";
+ return !mustNotColour && (shouldForce || isTerminal);
+ };
+ static bool cached = compute();
+ return cached;
}
-std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int width)
+// FIXME(jade): replace with TerminalCodeEater. wowie this is evil code.
+std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int width, bool eatTabs)
{
std::string t, e;
size_t w = 0;
@@ -43,7 +56,7 @@ std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int w
t += e;
}
- else if (*i == '\t') {
+ else if (*i == '\t' && eatTabs) {
i++; t += ' '; w++;
while (w < (size_t) width && w % 8) {
t += ' '; w++;
diff --git a/src/libutil/terminal.hh b/src/libutil/terminal.hh
index 43df5bd70..2c422ecff 100644
--- a/src/libutil/terminal.hh
+++ b/src/libutil/terminal.hh
@@ -9,6 +9,15 @@ namespace nix {
/**
* Determine whether ANSI escape sequences are appropriate for the
* present output.
+ *
+ * This follows the rules described on https://bixense.com/clicolors/
+ * with CLICOLOR defaulted to enabled (and thus ignored).
+ *
+ * That is to say, the following procedure is followed in order:
+ * - NO_COLOR or NOCOLOR set -> always disable colour
+ * - CLICOLOR_FORCE or FORCE_COLOR set -> enable colour
+ * - The output is a tty; TERM != "dumb" -> enable colour
+ * - Otherwise -> disable colour
*/
bool shouldANSI();
@@ -21,7 +30,8 @@ bool shouldANSI();
*/
std::string filterANSIEscapes(std::string_view s,
bool filterAll = false,
- unsigned int width = std::numeric_limits<unsigned int>::max());
+ unsigned int width = std::numeric_limits<unsigned int>::max(),
+ bool eatTabs = true);
/**
* Recalculate the window size, updating a global variable. Used in the
diff --git a/src/libutil/url.cc b/src/libutil/url.cc
index 87146ca56..2de50dd4d 100644
--- a/src/libutil/url.cc
+++ b/src/libutil/url.cc
@@ -63,7 +63,7 @@ std::string percentDecode(std::string_view in)
if (i + 2 >= in.size())
throw BadURL("invalid URI parameter '%s'", in);
try {
- decoded += std::stoul(std::string(in, i + 1, 2), 0, 16);
+ decoded += char8_t(std::stoul(std::string(in, i + 1, 2), 0, 16));
i += 3;
} catch (...) {
throw BadURL("invalid URI parameter '%s'", in);
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index 9d18b81b8..672930342 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -209,6 +209,11 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
{
auto lockedFlake = lockFlake();
auto & flake = lockedFlake.flake;
+ auto formatTime = [](time_t time) -> std::string {
+ std::ostringstream os{};
+ os << std::put_time(std::localtime(&time), "%F %T");
+ return os.str();
+ };
if (json) {
nlohmann::json j;
@@ -260,7 +265,7 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
if (auto lastModified = flake.lockedRef.input.getLastModified())
logger->cout(
ANSI_BOLD "Last modified:" ANSI_NORMAL " %s",
- std::put_time(std::localtime(&*lastModified), "%F %T"));
+ formatTime(*lastModified));
if (!lockedFlake.lockFile.root->inputs.empty())
logger->cout(ANSI_BOLD "Inputs:" ANSI_NORMAL);
@@ -275,16 +280,25 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON
bool last = i + 1 == node.inputs.size();
if (auto lockedNode = std::get_if<0>(&input.second)) {
- logger->cout("%s" ANSI_BOLD "%s" ANSI_NORMAL ": %s",
- prefix + (last ? treeLast : treeConn), input.first,
+ // ├───agenix: github:ryantm/agenix/8d37c5bdeade12b6479c85acd133063ab53187a0
+ logger->cout("%s%s" ANSI_BOLD "%s" ANSI_NORMAL ": %s",
+ prefix, last ? treeLast : treeConn, input.first,
(*lockedNode)->lockedRef);
+ // ├───lix: https://git.lix.systems/api/v1/repos/lix-project <....>
+ // │ Last modified: 2024-07-31 21:01:34
+ if (auto lastModified = (*lockedNode)->lockedRef.input.getLastModified()) {
+ logger->cout("%s%s" ANSI_BOLD "%s" ANSI_NORMAL ": %s",
+ prefix, last ? treeNull : treeLine, "Last modified", formatTime(*lastModified));
+ }
+
bool firstVisit = visited.insert(*lockedNode).second;
if (firstVisit) recurse(**lockedNode, prefix + (last ? treeNull : treeLine));
} else if (auto follows = std::get_if<1>(&input.second)) {
- logger->cout("%s" ANSI_BOLD "%s" ANSI_NORMAL " follows input '%s'",
- prefix + (last ? treeLast : treeConn), input.first,
+ // │ ├───darwin follows input 'flake-utils'
+ logger->cout("%s%s" ANSI_BOLD "%s" ANSI_NORMAL " follows input '%s'",
+ prefix, last ? treeLast : treeConn, input.first,
printInputPath(*follows));
}
}
diff --git a/src/nix/meson.build b/src/nix/meson.build
index 97387e402..80223a390 100644
--- a/src/nix/meson.build
+++ b/src/nix/meson.build
@@ -1,8 +1,8 @@
-generate_manpage_gen = gen_header.process(meson.project_source_root() / 'doc/manual/generate-manpage.nix')
-
-utils_gen = gen_header.process(meson.project_source_root() / 'doc/manual/utils.nix')
-
-get_env_gen = gen_header.process('get-env.sh')
+nix_generated_headers = [
+ gen_header.process(meson.project_source_root() / 'doc/manual/generate-manpage.nix'),
+ gen_header.process(meson.project_source_root() / 'doc/manual/utils.nix'),
+ gen_header.process('get-env.sh'),
+]
# src/nix/profile.cc includes src/nix/profile.md, which includes "doc/files/profiles.md.gen.hh".
# Unfortunately, https://github.com/mesonbuild/meson/issues/2320.
@@ -18,7 +18,7 @@ run_command(
meson.current_build_dir() / 'doc/files/profiles.md',
check : true,
)
-profiles_md_gen = gen_header.process(
+nix_generated_headers += gen_header.process(
meson.current_build_dir() / 'doc/files/profiles.md',
preserve_path_from : meson.current_build_dir(),
)
@@ -74,10 +74,7 @@ nix_sources = files(
nix = executable(
'nix',
nix_sources,
- generate_manpage_gen,
- utils_gen,
- get_env_gen,
- profiles_md_gen,
+ nix_generated_headers,
nix2_commands_sources,
dependencies : [
libasanoptions,
diff --git a/clang-tidy/.clang-format b/subprojects/lix-clang-tidy/.clang-format
index cd8995543..cd8995543 100644
--- a/clang-tidy/.clang-format
+++ b/subprojects/lix-clang-tidy/.clang-format
diff --git a/clang-tidy/.editorconfig b/subprojects/lix-clang-tidy/.editorconfig
index 19ee09eec..19ee09eec 100644
--- a/clang-tidy/.editorconfig
+++ b/subprojects/lix-clang-tidy/.editorconfig
diff --git a/clang-tidy/FixIncludes.cc b/subprojects/lix-clang-tidy/FixIncludes.cc
index 602d3d355..602d3d355 100644
--- a/clang-tidy/FixIncludes.cc
+++ b/subprojects/lix-clang-tidy/FixIncludes.cc
diff --git a/clang-tidy/FixIncludes.hh b/subprojects/lix-clang-tidy/FixIncludes.hh
index ea890cd39..ea890cd39 100644
--- a/clang-tidy/FixIncludes.hh
+++ b/subprojects/lix-clang-tidy/FixIncludes.hh
diff --git a/clang-tidy/HasPrefixSuffix.cc b/subprojects/lix-clang-tidy/HasPrefixSuffix.cc
index e29b67e7c..e29b67e7c 100644
--- a/clang-tidy/HasPrefixSuffix.cc
+++ b/subprojects/lix-clang-tidy/HasPrefixSuffix.cc
diff --git a/clang-tidy/HasPrefixSuffix.hh b/subprojects/lix-clang-tidy/HasPrefixSuffix.hh
index 8693b6767..8693b6767 100644
--- a/clang-tidy/HasPrefixSuffix.hh
+++ b/subprojects/lix-clang-tidy/HasPrefixSuffix.hh
diff --git a/clang-tidy/LixClangTidyChecks.cc b/subprojects/lix-clang-tidy/LixClangTidyChecks.cc
index b3503dd3a..b3503dd3a 100644
--- a/clang-tidy/LixClangTidyChecks.cc
+++ b/subprojects/lix-clang-tidy/LixClangTidyChecks.cc
diff --git a/clang-tidy/README.md b/subprojects/lix-clang-tidy/README.md
index c2d1cb258..c2d1cb258 100644
--- a/clang-tidy/README.md
+++ b/subprojects/lix-clang-tidy/README.md
diff --git a/subprojects/lix-clang-tidy/default.nix b/subprojects/lix-clang-tidy/default.nix
new file mode 100644
index 000000000..1bfc2d9a4
--- /dev/null
+++ b/subprojects/lix-clang-tidy/default.nix
@@ -0,0 +1,44 @@
+{
+ lib,
+ stdenv,
+ cmake,
+ meson,
+ ninja,
+ llvmPackages,
+}:
+let
+ inherit (lib) fileset;
+in
+stdenv.mkDerivation {
+ pname = "lix-clang-tidy-checks";
+ # Setting the version to the Lix version is just going to cause pointless
+ # rebuilds due to versionSuffix and similar, and I cannot conceive of a usage
+ # where we actually care about its version since this is internal-only.
+ version = "0.1";
+
+ src = fileset.toSource {
+ root = ./.;
+ fileset = fileset.unions [
+ ./meson.build
+ ./meson.options
+ (fileset.fileFilter (
+ { hasExt, ... }:
+ builtins.any hasExt [
+ "cc"
+ "hh"
+ ]
+ ) ./.)
+ ];
+ };
+
+ nativeBuildInputs = [
+ meson
+ cmake
+ ninja
+ ];
+
+ buildInputs = [
+ llvmPackages.llvm
+ llvmPackages.clang-unwrapped.dev
+ ];
+}
diff --git a/subprojects/lix-clang-tidy/meson.build b/subprojects/lix-clang-tidy/meson.build
new file mode 100644
index 000000000..ef0226420
--- /dev/null
+++ b/subprojects/lix-clang-tidy/meson.build
@@ -0,0 +1,18 @@
+project('lix-clang-tidy', ['cpp', 'c'],
+ version : '0.1',
+ default_options : ['warning_level=3', 'cpp_std=c++20']
+)
+
+llvm = dependency('Clang', version: '>= 17', modules: ['libclang'])
+sources = files(
+ 'HasPrefixSuffix.cc',
+ 'LixClangTidyChecks.cc',
+ 'FixIncludes.cc',
+)
+
+lix_clang_tidy = shared_module('lix-clang-tidy', sources,
+ dependencies: llvm,
+ # overrides build_by_default, see https://github.com/mesonbuild/meson/issues/13498
+ install : get_option('build-by-default'),
+ build_by_default : get_option('build-by-default')
+)
diff --git a/subprojects/lix-clang-tidy/meson.options b/subprojects/lix-clang-tidy/meson.options
new file mode 100644
index 000000000..57f0f713b
--- /dev/null
+++ b/subprojects/lix-clang-tidy/meson.options
@@ -0,0 +1,3 @@
+option('build-by-default', type : 'boolean', value : true,
+ description : 'set to false to not actually build targets by default. This is a hack to deal with meson lacking a build_by_default default option and building subprojects by default'
+)
diff --git a/tests/functional/flakes/flake-metadata.sh b/tests/functional/flakes/flake-metadata.sh
new file mode 100644
index 000000000..ab5a69b3a
--- /dev/null
+++ b/tests/functional/flakes/flake-metadata.sh
@@ -0,0 +1,36 @@
+source ./common.sh
+
+flakeDir=$TEST_ROOT/flake
+mkdir -p "$flakeDir"
+
+cat > "$flakeDir/flake.nix" <<-'EOF'
+{
+ inputs = {
+ nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable-small";
+ flake-utils.url = "github:numtide/flake-utils";
+ flake-compat = {
+ url = "github:edolstra/flake-compat";
+ flake = false;
+ };
+ lanzaboote = {
+ url = "github:nix-community/lanzaboote";
+ inputs.nixpkgs.follows = "nixpkgs";
+ inputs.flake-utils.follows = "flake-utils";
+ inputs.flake-compat.follows = "flake-compat";
+ };
+ };
+
+ outputs = { ... }: {};
+}
+EOF
+
+cp flake-metadata/flake.lock "$flakeDir"
+touch -d @1000 "$flakeDir/flake.nix" "$flakeDir/flake.lock" "$flakeDir"
+
+# For some reason we use NIX_STORE_DIR which causes unstable paths. This is
+# goofy. We can just use --store, which sets rootDir and does not have this
+# problem.
+actualStore=$NIX_STORE_DIR
+unset NIX_STORE_DIR
+NOCOLOR=1 TZ=UTC LC_ALL=C.UTF-8 nix flake metadata --store "$actualStore" "$flakeDir" | grep -v -e 'Locked URL:' -e 'Resolved URL:' > "$TEST_ROOT/metadata.out.actual"
+diff -u flake-metadata/metadata.out.expected "$TEST_ROOT/metadata.out.actual"
diff --git a/tests/functional/flakes/flake-metadata/flake.lock b/tests/functional/flakes/flake-metadata/flake.lock
new file mode 100644
index 000000000..62b7dc3e8
--- /dev/null
+++ b/tests/functional/flakes/flake-metadata/flake.lock
@@ -0,0 +1,245 @@
+{
+ "nodes": {
+ "crane": {
+ "inputs": {
+ "nixpkgs": [
+ "lanzaboote",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1711299236,
+ "narHash": "sha256-6/JsyozOMKN8LUGqWMopKTSiK8N79T8Q+hcxu2KkTXg=",
+ "owner": "ipetkov",
+ "repo": "crane",
+ "rev": "880573f80d09e18a11713f402b9e6172a085449f",
+ "type": "github"
+ },
+ "original": {
+ "owner": "ipetkov",
+ "repo": "crane",
+ "type": "github"
+ }
+ },
+ "flake-compat": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1696426674,
+ "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
+ "owner": "edolstra",
+ "repo": "flake-compat",
+ "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
+ "type": "github"
+ },
+ "original": {
+ "owner": "edolstra",
+ "repo": "flake-compat",
+ "type": "github"
+ }
+ },
+ "flake-parts": {
+ "inputs": {
+ "nixpkgs-lib": [
+ "lanzaboote",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1709336216,
+ "narHash": "sha256-Dt/wOWeW6Sqm11Yh+2+t0dfEWxoMxGBvv3JpIocFl9E=",
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "rev": "f7b3c975cf067e56e7cda6cb098ebe3fb4d74ca2",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "type": "github"
+ }
+ },
+ "flake-utils": {
+ "inputs": {
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1710146030,
+ "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "gitignore": {
+ "inputs": {
+ "nixpkgs": [
+ "lanzaboote",
+ "pre-commit-hooks-nix",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1709087332,
+ "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "type": "github"
+ }
+ },
+ "lanzaboote": {
+ "inputs": {
+ "crane": "crane",
+ "flake-compat": [
+ "flake-compat"
+ ],
+ "flake-parts": "flake-parts",
+ "flake-utils": [
+ "flake-utils"
+ ],
+ "nixpkgs": [
+ "nixpkgs"
+ ],
+ "pre-commit-hooks-nix": "pre-commit-hooks-nix",
+ "rust-overlay": "rust-overlay"
+ },
+ "locked": {
+ "lastModified": 1713369831,
+ "narHash": "sha256-G4OGxvlIIjphpkxcRAkf1QInYsAeqbfNh6Yl1JLy2uM=",
+ "owner": "nix-community",
+ "repo": "lanzaboote",
+ "rev": "850f27322239f8cfa56b122cc9a278ab99a49015",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "repo": "lanzaboote",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1719824438,
+ "narHash": "sha256-pY0wosAgcr9W4vmGML0T3BVhQiGuKoozCbs2t+Je1zc=",
+ "owner": "nixos",
+ "repo": "nixpkgs",
+ "rev": "7f993cdf26ccef564eabf31fdb40d140821e12bc",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nixos",
+ "ref": "nixos-unstable-small",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "nixpkgs-stable": {
+ "locked": {
+ "lastModified": 1710695816,
+ "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "614b4613980a522ba49f0d194531beddbb7220d3",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixos-23.11",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "pre-commit-hooks-nix": {
+ "inputs": {
+ "flake-compat": [
+ "lanzaboote",
+ "flake-compat"
+ ],
+ "flake-utils": [
+ "lanzaboote",
+ "flake-utils"
+ ],
+ "gitignore": "gitignore",
+ "nixpkgs": [
+ "lanzaboote",
+ "nixpkgs"
+ ],
+ "nixpkgs-stable": "nixpkgs-stable"
+ },
+ "locked": {
+ "lastModified": 1710923068,
+ "narHash": "sha256-6hOpUiuxuwpXXc/xfJsBUJeqqgGI+JMJuLo45aG3cKc=",
+ "owner": "cachix",
+ "repo": "pre-commit-hooks.nix",
+ "rev": "e611897ddfdde3ed3eaac4758635d7177ff78673",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "repo": "pre-commit-hooks.nix",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-compat": "flake-compat",
+ "flake-utils": "flake-utils",
+ "lanzaboote": "lanzaboote",
+ "nixpkgs": "nixpkgs"
+ }
+ },
+ "rust-overlay": {
+ "inputs": {
+ "flake-utils": [
+ "lanzaboote",
+ "flake-utils"
+ ],
+ "nixpkgs": [
+ "lanzaboote",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1711246447,
+ "narHash": "sha256-g9TOluObcOEKewFo2fR4cn51Y/jSKhRRo4QZckHLop0=",
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "rev": "dcc802a6ec4e9cc6a1c8c393327f0c42666f22e4",
+ "type": "github"
+ },
+ "original": {
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "type": "github"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/tests/functional/flakes/flake-metadata/metadata.out.expected b/tests/functional/flakes/flake-metadata/metadata.out.expected
new file mode 100644
index 000000000..72e57eca7
--- /dev/null
+++ b/tests/functional/flakes/flake-metadata/metadata.out.expected
@@ -0,0 +1,36 @@
+Path: /nix/store/gaxb42z68bcr8lch467shvmnhjjzgd8b-source
+Last modified: 1970-01-01 00:16:40
+Inputs:
+├───flake-compat: github:edolstra/flake-compat/0f9255e01c2351cc7d116c072cb317785dd33b33
+│ Last modified: 2023-10-04 13:37:54
+├───flake-utils: github:numtide/flake-utils/b1d9ab70662946ef0850d488da1c9019f3a9752a
+│ Last modified: 2024-03-11 08:33:50
+│ └───systems: github:nix-systems/default/da67096a3b9bf56a91d16901293e51ba5b49a27e
+│ Last modified: 2023-04-09 08:27:08
+├───lanzaboote: github:nix-community/lanzaboote/850f27322239f8cfa56b122cc9a278ab99a49015
+│ Last modified: 2024-04-17 16:03:51
+│ ├───crane: github:ipetkov/crane/880573f80d09e18a11713f402b9e6172a085449f
+│ │ Last modified: 2024-03-24 16:53:56
+│ │ └───nixpkgs follows input 'lanzaboote/nixpkgs'
+│ ├───flake-compat follows input 'flake-compat'
+│ ├───flake-parts: github:hercules-ci/flake-parts/f7b3c975cf067e56e7cda6cb098ebe3fb4d74ca2
+│ │ Last modified: 2024-03-01 23:36:56
+│ │ └───nixpkgs-lib follows input 'lanzaboote/nixpkgs'
+│ ├───flake-utils follows input 'flake-utils'
+│ ├───nixpkgs follows input 'nixpkgs'
+│ ├───pre-commit-hooks-nix: github:cachix/pre-commit-hooks.nix/e611897ddfdde3ed3eaac4758635d7177ff78673
+│ │ Last modified: 2024-03-20 08:24:28
+│ │ ├───flake-compat follows input 'lanzaboote/flake-compat'
+│ │ ├───flake-utils follows input 'lanzaboote/flake-utils'
+│ │ ├───gitignore: github:hercules-ci/gitignore.nix/637db329424fd7e46cf4185293b9cc8c88c95394
+│ │ │ Last modified: 2024-02-28 02:28:52
+│ │ │ └───nixpkgs follows input 'lanzaboote/pre-commit-hooks-nix/nixpkgs'
+│ │ ├───nixpkgs follows input 'lanzaboote/nixpkgs'
+│ │ └───nixpkgs-stable: github:NixOS/nixpkgs/614b4613980a522ba49f0d194531beddbb7220d3
+│ │ Last modified: 2024-03-17 17:16:56
+│ └───rust-overlay: github:oxalica/rust-overlay/dcc802a6ec4e9cc6a1c8c393327f0c42666f22e4
+│ Last modified: 2024-03-24 02:14:07
+│ ├───flake-utils follows input 'lanzaboote/flake-utils'
+│ └───nixpkgs follows input 'lanzaboote/nixpkgs'
+└───nixpkgs: github:nixos/nixpkgs/7f993cdf26ccef564eabf31fdb40d140821e12bc
+ Last modified: 2024-07-01 09:00:38
diff --git a/tests/functional/lang/eval-okay-derivation-legacy.err.exp b/tests/functional/lang/eval-okay-derivation-legacy.err.exp
new file mode 100644
index 000000000..94f0854dd
--- /dev/null
+++ b/tests/functional/lang/eval-okay-derivation-legacy.err.exp
@@ -0,0 +1,6 @@
+warning: In a derivation named 'eval-okay-derivation-legacy', 'structuredAttrs' disables the effect of the derivation attribute 'allowedReferences'; use 'outputChecks.<output>.allowedReferences' instead
+warning: In a derivation named 'eval-okay-derivation-legacy', 'structuredAttrs' disables the effect of the derivation attribute 'allowedRequisites'; use 'outputChecks.<output>.allowedRequisites' instead
+warning: In a derivation named 'eval-okay-derivation-legacy', 'structuredAttrs' disables the effect of the derivation attribute 'disallowedReferences'; use 'outputChecks.<output>.disallowedReferences' instead
+warning: In a derivation named 'eval-okay-derivation-legacy', 'structuredAttrs' disables the effect of the derivation attribute 'disallowedRequisites'; use 'outputChecks.<output>.disallowedRequisites' instead
+warning: In a derivation named 'eval-okay-derivation-legacy', 'structuredAttrs' disables the effect of the derivation attribute 'maxClosureSize'; use 'outputChecks.<output>.maxClosureSize' instead
+warning: In a derivation named 'eval-okay-derivation-legacy', 'structuredAttrs' disables the effect of the derivation attribute 'maxSize'; use 'outputChecks.<output>.maxSize' instead
diff --git a/tests/functional/lang/eval-okay-derivation-legacy.exp b/tests/functional/lang/eval-okay-derivation-legacy.exp
new file mode 100644
index 000000000..4f374a1aa
--- /dev/null
+++ b/tests/functional/lang/eval-okay-derivation-legacy.exp
@@ -0,0 +1 @@
+"/nix/store/mzgwvrjjir216ra58mwwizi8wj6y9ddr-eval-okay-derivation-legacy"
diff --git a/tests/functional/lang/eval-okay-derivation-legacy.nix b/tests/functional/lang/eval-okay-derivation-legacy.nix
new file mode 100644
index 000000000..b529cdf90
--- /dev/null
+++ b/tests/functional/lang/eval-okay-derivation-legacy.nix
@@ -0,0 +1,12 @@
+(builtins.derivationStrict {
+ name = "eval-okay-derivation-legacy";
+ system = "x86_64-linux";
+ builder = "/dontcare";
+ __structuredAttrs = true;
+ allowedReferences = [ ];
+ disallowedReferences = [ ];
+ allowedRequisites = [ ];
+ disallowedRequisites = [ ];
+ maxSize = 1234;
+ maxClosureSize = 12345;
+}).out
diff --git a/tests/functional/meson.build b/tests/functional/meson.build
index 7a9c7182f..2b5dfe422 100644
--- a/tests/functional/meson.build
+++ b/tests/functional/meson.build
@@ -69,8 +69,9 @@ functional_tests_scripts = [
'flakes/unlocked-override.sh',
'flakes/absolute-paths.sh',
'flakes/build-paths.sh',
- 'flakes/flake-registry.sh',
'flakes/flake-in-submodule.sh',
+ 'flakes/flake-metadata.sh',
+ 'flakes/flake-registry.sh',
'flakes/subdir-flake.sh',
'gc.sh',
'nix-collect-garbage-d.sh',
diff --git a/tests/functional/search.sh b/tests/functional/search.sh
index d9c7a75da..1a2a20089 100644
--- a/tests/functional/search.sh
+++ b/tests/functional/search.sh
@@ -29,6 +29,8 @@ nix search -f search.nix '' ^ | grepQuiet hello
## Tests for multiple regex/match highlighting
+# FIXME: possibly not test this with colour in the future
+export CLICOLOR_FORCE=1
e=$'\x1b' # grep doesn't support \e, \033 or even \x1b
# Multiple overlapping regexes
(( $(nix search -f search.nix '' 'oo' 'foo' 'oo' | grep -c "$e\[32;1mfoo$e\\[0;1m") == 1 ))
diff --git a/tests/unit/libexpr-support/tests/libexpr.hh b/tests/unit/libexpr-support/tests/libexpr.hh
index 01dcbb34c..745aa168d 100644
--- a/tests/unit/libexpr-support/tests/libexpr.hh
+++ b/tests/unit/libexpr-support/tests/libexpr.hh
@@ -26,9 +26,9 @@ namespace nix {
, state({}, store)
{
}
- Value eval(std::string input, bool forceValue = true) {
+ Value eval(std::string input, bool forceValue = true, const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings) {
Value v;
- Expr & e = state.parseExprFromString(input, state.rootPath(CanonPath::root));
+ Expr & e = state.parseExprFromString(input, state.rootPath(CanonPath::root), xpSettings);
state.eval(e, v);
if (forceValue)
state.forceValue(v, noPos);
diff --git a/tests/unit/libexpr/trivial.cc b/tests/unit/libexpr/trivial.cc
index 171727ac7..19b62aff8 100644
--- a/tests/unit/libexpr/trivial.cc
+++ b/tests/unit/libexpr/trivial.cc
@@ -59,6 +59,11 @@ namespace nix {
ASSERT_THAT(v, IsFloatEq(1.234));
}
+ TEST_F(TrivialExpressionTest, pointfloat) {
+ auto v = eval(".234");
+ ASSERT_THAT(v, IsFloatEq(0.234));
+ }
+
TEST_F(TrivialExpressionTest, updateAttrs) {
auto v = eval("{ a = 1; } // { b = 2; a = 3; }");
ASSERT_THAT(v, IsAttrsOfSize(2));
@@ -81,6 +86,18 @@ namespace nix {
ASSERT_THAT(v, IsTrue());
}
+ TEST_F(TrivialExpressionTest, urlLiteral) {
+ auto v = eval("https://nixos.org");
+ ASSERT_THAT(v, IsStringEq("https://nixos.org"));
+ }
+
+ TEST_F(TrivialExpressionTest, noUrlLiteral) {
+ ExperimentalFeatureSettings mockXpSettings;
+ mockXpSettings.set("experimental-features", "no-url-literals");
+
+ ASSERT_THROW(eval("https://nixos.org", true, mockXpSettings), Error);
+ }
+
TEST_F(TrivialExpressionTest, withFound) {
auto v = eval("with { a = 23; }; a");
ASSERT_THAT(v, IsIntEq(23));
diff --git a/tests/unit/libutil-support/tests/cli-literate-parser.cc b/tests/unit/libutil-support/tests/cli-literate-parser.cc
index f74fe85eb..3aa55859c 100644
--- a/tests/unit/libutil-support/tests/cli-literate-parser.cc
+++ b/tests/unit/libutil-support/tests/cli-literate-parser.cc
@@ -1,20 +1,16 @@
#include "cli-literate-parser.hh"
#include "escape-string.hh"
-#include "escape-char.hh"
-#include "libexpr/print.hh"
#include "types.hh"
#include <ranges>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <iostream>
-#include <memory>
#include <sstream>
#include <variant>
#include "cli-literate-parser.hh"
#include "escape-string.hh"
#include "fmt.hh"
-#include "libexpr/print.hh"
#include "shlex.hh"
#include "types.hh"
#include "strings.hh"
@@ -361,9 +357,8 @@ const char * ParseError::what() const noexcept
return what_->c_str();
} else {
auto escaped = escapeString(rest, {.maxLength = 256, .escapeNonPrinting = true});
- auto hint =
- new HintFmt("Parse error: Expected %1%, got:\n%2%", expected, Uncolored(escaped));
- what_ = hint->str();
+ auto hint = HintFmt("Parse error: Expected %1%, got:\n%2%", expected, Uncolored(escaped));
+ what_ = hint.str();
return what_->c_str();
}
}