forked from lix-project/lix
Compare commits
12 commits
8c06b7b431
...
6a945e1d2b
Author | SHA1 | Date | |
---|---|---|---|
Artemis Tosini | 6a945e1d2b | ||
jade | dd53bce476 | ||
alois31 | ddfe379a6b | ||
jade | 2a7a824d83 | ||
Qyriad | 5b4b216fac | ||
Qyriad | 1c0f3c540e | ||
Qyriad | f3f68fcfac | ||
Qyriad | 076c19e0d1 | ||
alois31 | f047e4357b | ||
Qyriad | d0390b5cf2 | ||
jade | 19ea351642 | ||
jade | 745b5d3d4f |
|
@ -44,32 +44,41 @@ void FixIncludesCallbacks::LexedFileChanged(FileID, LexedFileChangeReason,
|
||||||
}
|
}
|
||||||
|
|
||||||
void FixIncludesCallbacks::InclusionDirective(
|
void FixIncludesCallbacks::InclusionDirective(
|
||||||
SourceLocation, const Token &, StringRef, bool,
|
SourceLocation, const Token &, StringRef FileName, bool IsAngled,
|
||||||
CharSourceRange FilenameRange, OptionalFileEntryRef File, StringRef,
|
CharSourceRange FilenameRange, OptionalFileEntryRef File, StringRef,
|
||||||
StringRef, const Module *, SrcMgr::CharacteristicKind) {
|
StringRef, const Module *, SrcMgr::CharacteristicKind) {
|
||||||
if (Ignore)
|
if (Ignore)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// FIXME: this is kinda evil, but this is a one-time fixup
|
// FIXME: this is kinda evil, but this is a one-time fixup
|
||||||
const std::string SourceDir = "src/";
|
const std::vector<std::string> SourceDirs = {"src/", "include/lix/"};
|
||||||
|
|
||||||
if (File && File->getNameAsRequested().contains(SourceDir)) {
|
const auto Bracketize = [IsAngled](StringRef s) {
|
||||||
|
return IsAngled ? ("<" + s + ">").str() : ("\"" + s + "\"").str();
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto &SourceDir : SourceDirs) {
|
||||||
|
const bool IsAlreadyFixed = FileName.starts_with("lix/lib");
|
||||||
|
if (File && File->getNameAsRequested().contains(SourceDir) &&
|
||||||
|
!IsAlreadyFixed) {
|
||||||
StringRef Name = File->getNameAsRequested();
|
StringRef Name = File->getNameAsRequested();
|
||||||
auto Idx = Name.find(SourceDir);
|
auto Idx = Name.find(SourceDir);
|
||||||
assert(Idx != std::string::npos);
|
assert(Idx != std::string::npos);
|
||||||
StringRef Suffix = Name.drop_front(Idx + SourceDir.length());
|
std::string Suffix = Name.drop_front(Idx + SourceDir.length()).str();
|
||||||
|
|
||||||
if (!Suffix.starts_with("lib")) {
|
if (!Suffix.starts_with("lib")) {
|
||||||
llvm::dbgs() << "ignored: " << Suffix << "\n";
|
llvm::dbgs() << "ignored: " << Suffix << "\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Suffix = "lix/" + Suffix;
|
||||||
|
|
||||||
auto Diag = Check.diag(FilenameRange.getBegin(),
|
auto Diag = Check.diag(FilenameRange.getBegin(),
|
||||||
"include needs to specify the source subdir");
|
"include needs to specify the source subdir");
|
||||||
|
|
||||||
Diag << FilenameRange
|
Diag << FilenameRange
|
||||||
<< FixItHint::CreateReplacement(FilenameRange,
|
<< FixItHint::CreateReplacement(FilenameRange, Bracketize(Suffix));
|
||||||
("\"" + Suffix + "\"").str());
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Clang tidy lints for Nix
|
# Clang tidy lints for Lix
|
||||||
|
|
||||||
This is a skeleton of a clang-tidy lints library for Nix.
|
This is a skeleton of a clang-tidy lints library for Lix.
|
||||||
|
|
||||||
Currently there is one check (which is already obsolete as it has served its
|
Currently there is one check (which is already obsolete as it has served its
|
||||||
goal and is there as an example), `HasPrefixSuffixCheck`.
|
goal and is there as an example), `HasPrefixSuffixCheck`.
|
||||||
|
@ -10,13 +10,13 @@ goal and is there as an example), `HasPrefixSuffixCheck`.
|
||||||
One file:
|
One file:
|
||||||
|
|
||||||
```
|
```
|
||||||
ninja -C build && clang-tidy --checks='-*,nix-*' --load=build/libnix-clang-tidy.so -p ../compile_commands.json --fix ../src/libcmd/installables.cc
|
ninja -C build && clang-tidy --checks='-*,lix-*' --load=build/liblix-clang-tidy.so -p ../compile_commands.json -header-filter '\.\./src/.*\.h' --fix ../src/libcmd/installables.cc
|
||||||
```
|
```
|
||||||
|
|
||||||
Several files, in parallel:
|
Several files, in parallel:
|
||||||
|
|
||||||
```
|
```
|
||||||
ninja -C build && run-clang-tidy -checks='-*,nix-*' -load=build/libnix-clang-tidy.so -p .. -fix ../src | tee -a clang-tidy-result
|
ninja -C build && run-clang-tidy -checks='-*,lix-*' -load=build/liblix-clang-tidy.so -p .. -header-filter '\.\./src/.*\.h' -fix ../src | tee -a clang-tidy-result
|
||||||
```
|
```
|
||||||
|
|
||||||
## Resources
|
## Resources
|
||||||
|
|
|
@ -24,7 +24,6 @@ const redirects = {
|
||||||
"chap-writing-nix-expressions": "language/index.html",
|
"chap-writing-nix-expressions": "language/index.html",
|
||||||
"part-command-ref": "command-ref/command-ref.html",
|
"part-command-ref": "command-ref/command-ref.html",
|
||||||
"conf-allow-import-from-derivation": "command-ref/conf-file.html#conf-allow-import-from-derivation",
|
"conf-allow-import-from-derivation": "command-ref/conf-file.html#conf-allow-import-from-derivation",
|
||||||
"conf-allow-new-privileges": "command-ref/conf-file.html#conf-allow-new-privileges",
|
|
||||||
"conf-allowed-uris": "command-ref/conf-file.html#conf-allowed-uris",
|
"conf-allowed-uris": "command-ref/conf-file.html#conf-allowed-uris",
|
||||||
"conf-allowed-users": "command-ref/conf-file.html#conf-allowed-users",
|
"conf-allowed-users": "command-ref/conf-file.html#conf-allowed-users",
|
||||||
"conf-auto-optimise-store": "command-ref/conf-file.html#conf-auto-optimise-store",
|
"conf-auto-optimise-store": "command-ref/conf-file.html#conf-auto-optimise-store",
|
||||||
|
|
12
doc/manual/rl-next/linux-sandbox-consistency.md
Normal file
12
doc/manual/rl-next/linux-sandbox-consistency.md
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
---
|
||||||
|
synopsis: Enforce syscall filtering and no-new-privileges on Linux
|
||||||
|
cls: 1063
|
||||||
|
category: Breaking Changes
|
||||||
|
credits: alois31
|
||||||
|
---
|
||||||
|
|
||||||
|
In order to improve consistency of the build environment, system call filtering and no-new-privileges are now unconditionally enabled on Linux.
|
||||||
|
The `filter-syscalls` and `allow-new-privileges` options which could be used to disable these features under some circumstances have been removed.
|
||||||
|
|
||||||
|
In order to support building on architectures without libseccomp support, the option to disable syscall filtering at build time remains.
|
||||||
|
However, other uses of this option are heavily discouraged, since it would reduce the security of the sandbox substantially.
|
|
@ -22,10 +22,10 @@ Migration path:
|
||||||
To apply this migration automatically, remove all `<nix/>` from includes, so `#include <nix/expr.hh>` -> `#include <expr.hh>`.
|
To apply this migration automatically, remove all `<nix/>` from includes, so `#include <nix/expr.hh>` -> `#include <expr.hh>`.
|
||||||
Then, the correct paths will be resolved from the tangled mess, and the clang-tidy automated fix will work.
|
Then, the correct paths will be resolved from the tangled mess, and the clang-tidy automated fix will work.
|
||||||
|
|
||||||
Then run the following for out of tree projects:
|
Then run the following for out of tree projects (header filter is set to only fix instances in headers in `../src` relative to the compiler's working directory, as would be the case in nix-eval-jobs or other things built with meson, e.g.):
|
||||||
|
|
||||||
```console
|
```console
|
||||||
lix_root=$HOME/lix
|
lix_root=$HOME/lix
|
||||||
(cd $lix_root/clang-tidy && nix develop -c 'meson setup build && ninja -C build')
|
(cd $lix_root/clang-tidy && nix develop -c 'meson setup build && ninja -C build')
|
||||||
run-clang-tidy -checks='-*,lix-fixincludes' -load=$lix_root/clang-tidy/build/liblix-clang-tidy.so -p build/ -fix src
|
run-clang-tidy -checks='-*,lix-fixincludes' -load=$lix_root/clang-tidy/build/liblix-clang-tidy.so -p build/ -header-filter '\.\./src/.*\.h' -fix src
|
||||||
```
|
```
|
||||||
|
|
|
@ -68,10 +68,7 @@ The most current alternative to this section is to read `package.nix` and see wh
|
||||||
may also work, but ancient versions like the ubiquitous 2.5.4a
|
may also work, but ancient versions like the ubiquitous 2.5.4a
|
||||||
won't.
|
won't.
|
||||||
|
|
||||||
- The `libseccomp` is used to provide syscall filtering on Linux. This
|
- The `libseccomp` is used to provide syscall filtering on Linux. To get
|
||||||
is an optional dependency and can be disabled passing a
|
|
||||||
`--disable-seccomp-sandboxing` option to the `configure` script (Not
|
|
||||||
recommended unless your system doesn't support `libseccomp`). To get
|
|
||||||
the library, visit <https://github.com/seccomp/libseccomp>.
|
the library, visit <https://github.com/seccomp/libseccomp>.
|
||||||
|
|
||||||
- On 64-bit x86 machines only, `libcpuid` library
|
- On 64-bit x86 machines only, `libcpuid` library
|
||||||
|
|
10
meson.build
10
meson.build
|
@ -138,6 +138,7 @@ message('canonical Nix system name:', host_system)
|
||||||
|
|
||||||
is_linux = host_machine.system() == 'linux'
|
is_linux = host_machine.system() == 'linux'
|
||||||
is_darwin = host_machine.system() == 'darwin'
|
is_darwin = host_machine.system() == 'darwin'
|
||||||
|
is_freebsd = host_machine.system() == 'freebsd'
|
||||||
is_x64 = host_machine.cpu_family() == 'x86_64'
|
is_x64 = host_machine.cpu_family() == 'x86_64'
|
||||||
|
|
||||||
# Per-platform arguments that you should probably pass to shared_module() invocations.
|
# Per-platform arguments that you should probably pass to shared_module() invocations.
|
||||||
|
@ -182,6 +183,9 @@ deps += cpuid
|
||||||
# seccomp only makes sense on Linux
|
# seccomp only makes sense on Linux
|
||||||
seccomp_required = is_linux ? get_option('seccomp-sandboxing') : false
|
seccomp_required = is_linux ? get_option('seccomp-sandboxing') : false
|
||||||
seccomp = dependency('libseccomp', 'seccomp', required : seccomp_required, version : '>=2.5.5')
|
seccomp = dependency('libseccomp', 'seccomp', required : seccomp_required, version : '>=2.5.5')
|
||||||
|
if is_linux and not seccomp.found()
|
||||||
|
warning('Sandbox security is reduced because libseccomp has not been found! Please provide libseccomp if it supports your CPU architecture.')
|
||||||
|
endif
|
||||||
configdata += {
|
configdata += {
|
||||||
'HAVE_SECCOMP': seccomp.found().to_int(),
|
'HAVE_SECCOMP': seccomp.found().to_int(),
|
||||||
}
|
}
|
||||||
|
@ -451,6 +455,12 @@ if cxx.get_linker_id() in ['ld.bfd', 'ld.gold']
|
||||||
add_project_link_arguments('-Wl,--no-copy-dt-needed-entries', language : 'cpp')
|
add_project_link_arguments('-Wl,--no-copy-dt-needed-entries', language : 'cpp')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if is_freebsd
|
||||||
|
# FreeBSD's `environ` is defined in `crt1.o`, not `libc.so`.
|
||||||
|
#
|
||||||
|
add_project_link_arguments('-Wl,-z,undefs', language: 'cpp')
|
||||||
|
endif
|
||||||
|
|
||||||
# Generate Chromium tracing files for each compiled file, which enables
|
# Generate Chromium tracing files for each compiled file, which enables
|
||||||
# maintainers/buildtime_report.sh BUILD-DIR to simply work in clang builds.
|
# maintainers/buildtime_report.sh BUILD-DIR to simply work in clang builds.
|
||||||
#
|
#
|
||||||
|
|
|
@ -27,7 +27,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||||
platforms = lib.platforms.unix;
|
platforms = lib.platforms.unix;
|
||||||
# `long long int` != `size_t`
|
# `long long int` != `size_t`
|
||||||
# There's no convenient lib.platforms.32bit or anything, but it's easy enough to do ourselves.
|
# There's no convenient lib.platforms.32bit or anything, but it's easy enough to do ourselves.
|
||||||
badPlatforms = lib.filter (plat: (lib.systems.elaborate plat).is32bit) lib.platforms.all;
|
badPlatforms = (lib.filter (plat: (lib.systems.elaborate plat).is32bit) lib.platforms.all) ++ lib.platforms.freebsd;
|
||||||
mainProgram = "ClangBuildAnalyzer";
|
mainProgram = "ClangBuildAnalyzer";
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
|
@ -1115,7 +1115,7 @@ void EvalState::evalFile(const SourcePath & path_, Value & v, bool mustBeTrivial
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printTalkative("evaluating file '%1%'", resolvedPath);
|
debug("evaluating file '%1%'", resolvedPath);
|
||||||
Expr * e = nullptr;
|
Expr * e = nullptr;
|
||||||
|
|
||||||
auto j = fileParseCache.find(resolvedPath);
|
auto j = fileParseCache.find(resolvedPath);
|
||||||
|
|
|
@ -242,7 +242,7 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v
|
||||||
// No need to call staticEnv.sort(), because
|
// No need to call staticEnv.sort(), because
|
||||||
// args[0]->attrs is already sorted.
|
// args[0]->attrs is already sorted.
|
||||||
|
|
||||||
printTalkative("evaluating file '%1%'", path);
|
debug("evaluating file '%1%'", path);
|
||||||
Expr * e = state.parseExprFromFile(resolveExprPath(path), staticEnv);
|
Expr * e = state.parseExprFromFile(resolveExprPath(path), staticEnv);
|
||||||
|
|
||||||
e->eval(state, *env, v);
|
e->eval(state, *env, v);
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
/* Includes required for chroot support. */
|
/* Includes required for chroot support. */
|
||||||
#if __linux__
|
#if __linux__
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include "linux/fchmodat2-compat.hh"
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <netinet/ip.h>
|
#include <netinet/ip.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
@ -44,6 +43,7 @@
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#if HAVE_SECCOMP
|
#if HAVE_SECCOMP
|
||||||
|
#include "linux/fchmodat2-compat.hh"
|
||||||
#include <seccomp.h>
|
#include <seccomp.h>
|
||||||
#endif
|
#endif
|
||||||
#define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root, put_old))
|
#define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root, put_old))
|
||||||
|
@ -1612,7 +1612,6 @@ void LocalDerivationGoal::chownToBuilder(const Path & path)
|
||||||
void setupSeccomp()
|
void setupSeccomp()
|
||||||
{
|
{
|
||||||
#if __linux__
|
#if __linux__
|
||||||
if (!settings.filterSyscalls) return;
|
|
||||||
#if HAVE_SECCOMP
|
#if HAVE_SECCOMP
|
||||||
scmp_filter_ctx ctx;
|
scmp_filter_ctx ctx;
|
||||||
|
|
||||||
|
@ -1678,15 +1677,18 @@ void setupSeccomp()
|
||||||
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(fsetxattr), 0) != 0)
|
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(fsetxattr), 0) != 0)
|
||||||
throw SysError("unable to add seccomp rule");
|
throw SysError("unable to add seccomp rule");
|
||||||
|
|
||||||
if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, settings.allowNewPrivileges ? 0 : 1) != 0)
|
// 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");
|
throw SysError("unable to set 'no new privileges' seccomp attribute");
|
||||||
|
|
||||||
if (seccomp_load(ctx) != 0)
|
if (seccomp_load(ctx) != 0)
|
||||||
throw SysError("unable to load seccomp BPF program");
|
throw SysError("unable to load seccomp BPF program");
|
||||||
#else
|
#else
|
||||||
throw Error(
|
// Still set the no-new-privileges flag if libseccomp is not available.
|
||||||
"seccomp is not supported on this platform; "
|
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
|
||||||
"you can bypass this error by setting the option 'filter-syscalls' to false, but note that untrusted builds can then create setuid binaries!");
|
throw SysError("PR_SET_NO_NEW_PRIVS failed");
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -1954,10 +1956,6 @@ void LocalDerivationGoal::runChild()
|
||||||
throw SysError("setuid failed");
|
throw SysError("setuid failed");
|
||||||
|
|
||||||
setUser = false;
|
setUser = false;
|
||||||
|
|
||||||
// Make sure we can't possibly gain new privileges in the sandbox
|
|
||||||
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
|
|
||||||
throw SysError("PR_SET_NO_NEW_PRIVS failed");
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -527,7 +527,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
auto drvs = WorkerProto::Serialise<DerivedPaths>::read(*store, rconn);
|
auto drvs = WorkerProto::Serialise<DerivedPaths>::read(*store, rconn);
|
||||||
BuildMode mode = bmNormal;
|
BuildMode mode = bmNormal;
|
||||||
if (GET_PROTOCOL_MINOR(clientVersion) >= 15) {
|
if (GET_PROTOCOL_MINOR(clientVersion) >= 15) {
|
||||||
mode = (BuildMode) readInt(from);
|
mode = buildModeFromInteger(readInt(from));
|
||||||
|
|
||||||
/* Repairing is not atomic, so disallowed for "untrusted"
|
/* Repairing is not atomic, so disallowed for "untrusted"
|
||||||
clients.
|
clients.
|
||||||
|
@ -551,7 +551,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
case WorkerProto::Op::BuildPathsWithResults: {
|
case WorkerProto::Op::BuildPathsWithResults: {
|
||||||
auto drvs = WorkerProto::Serialise<DerivedPaths>::read(*store, rconn);
|
auto drvs = WorkerProto::Serialise<DerivedPaths>::read(*store, rconn);
|
||||||
BuildMode mode = bmNormal;
|
BuildMode mode = bmNormal;
|
||||||
mode = (BuildMode) readInt(from);
|
mode = buildModeFromInteger(readInt(from));
|
||||||
|
|
||||||
/* Repairing is not atomic, so disallowed for "untrusted"
|
/* Repairing is not atomic, so disallowed for "untrusted"
|
||||||
clients.
|
clients.
|
||||||
|
@ -582,7 +582,7 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
|
||||||
* correctly.
|
* correctly.
|
||||||
*/
|
*/
|
||||||
readDerivation(from, *store, drv, Derivation::nameFromPath(drvPath));
|
readDerivation(from, *store, drv, Derivation::nameFromPath(drvPath));
|
||||||
BuildMode buildMode = (BuildMode) readInt(from);
|
BuildMode buildMode = buildModeFromInteger(readInt(from));
|
||||||
logger->startWork();
|
logger->startWork();
|
||||||
|
|
||||||
auto drvType = drv.type();
|
auto drvType = drv.type();
|
||||||
|
|
|
@ -912,29 +912,6 @@ public:
|
||||||
)"};
|
)"};
|
||||||
|
|
||||||
#if __linux__
|
#if __linux__
|
||||||
Setting<bool> filterSyscalls{
|
|
||||||
this, true, "filter-syscalls",
|
|
||||||
R"(
|
|
||||||
Whether to prevent certain dangerous system calls, such as
|
|
||||||
creation of setuid/setgid files or adding ACLs or extended
|
|
||||||
attributes. Only disable this if you're aware of the
|
|
||||||
security implications.
|
|
||||||
)"};
|
|
||||||
|
|
||||||
Setting<bool> allowNewPrivileges{
|
|
||||||
this, false, "allow-new-privileges",
|
|
||||||
R"(
|
|
||||||
(Linux-specific.) By default, builders on Linux cannot acquire new
|
|
||||||
privileges by calling setuid/setgid programs or programs that have
|
|
||||||
file capabilities. For example, programs such as `sudo` or `ping`
|
|
||||||
will fail. (Note that in sandbox builds, no such programs are
|
|
||||||
available unless you bind-mount them into the sandbox via the
|
|
||||||
`sandbox-paths` option.) You can allow the use of such programs by
|
|
||||||
enabling this option. This is impure and usually undesirable, but
|
|
||||||
may be useful in certain scenarios (e.g. to spin up containers or
|
|
||||||
set up userspace network interfaces in tests).
|
|
||||||
)"};
|
|
||||||
|
|
||||||
Setting<StringSet> ignoredAcls{
|
Setting<StringSet> ignoredAcls{
|
||||||
this, {"security.selinux", "system.nfs4_acl", "security.csm"}, "ignored-acls",
|
this, {"security.selinux", "system.nfs4_acl", "security.csm"}, "ignored-acls",
|
||||||
R"(
|
R"(
|
||||||
|
|
|
@ -20,18 +20,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#if HAVE_SECCOMP
|
#if defined(__alpha__)
|
||||||
# if defined(__alpha__)
|
|
||||||
# define NIX_SYSCALL_FCHMODAT2 562
|
# define NIX_SYSCALL_FCHMODAT2 562
|
||||||
# elif defined(__x86_64__) && SIZE_MAX == 0xFFFFFFFF // x32
|
#elif defined(__x86_64__) && SIZE_MAX == 0xFFFFFFFF // x32
|
||||||
# define NIX_SYSCALL_FCHMODAT2 1073742276
|
# define NIX_SYSCALL_FCHMODAT2 1073742276
|
||||||
# elif defined(__mips__) && defined(__mips64) && defined(_ABIN64) // mips64/n64
|
#elif defined(__mips__) && defined(__mips64) && defined(_ABIN64) // mips64/n64
|
||||||
# define NIX_SYSCALL_FCHMODAT2 5452
|
# define NIX_SYSCALL_FCHMODAT2 5452
|
||||||
# elif defined(__mips__) && defined(__mips64) && defined(_ABIN32) // mips64/n32
|
#elif defined(__mips__) && defined(__mips64) && defined(_ABIN32) // mips64/n32
|
||||||
# define NIX_SYSCALL_FCHMODAT2 6452
|
# define NIX_SYSCALL_FCHMODAT2 6452
|
||||||
# elif defined(__mips__) && defined(_ABIO32) // mips32
|
#elif defined(__mips__) && defined(_ABIO32) // mips32
|
||||||
# define NIX_SYSCALL_FCHMODAT2 4452
|
# define NIX_SYSCALL_FCHMODAT2 4452
|
||||||
# else
|
#else
|
||||||
# define NIX_SYSCALL_FCHMODAT2 452
|
# define NIX_SYSCALL_FCHMODAT2 452
|
||||||
# endif
|
#endif
|
||||||
#endif // HAVE_SECCOMP
|
|
||||||
|
|
|
@ -210,7 +210,6 @@ libstore = library(
|
||||||
seccomp,
|
seccomp,
|
||||||
sqlite,
|
sqlite,
|
||||||
sodium,
|
sodium,
|
||||||
seccomp,
|
|
||||||
curl,
|
curl,
|
||||||
openssl,
|
openssl,
|
||||||
aws_sdk,
|
aws_sdk,
|
||||||
|
|
|
@ -22,6 +22,14 @@ using json = nlohmann::json;
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
BuildMode buildModeFromInteger(int raw) {
|
||||||
|
switch (raw) {
|
||||||
|
case bmNormal: return bmNormal;
|
||||||
|
case bmRepair: return bmRepair;
|
||||||
|
case bmCheck: return bmCheck;
|
||||||
|
default: throw Error("Invalid BuildMode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Store::isInStore(PathView path) const
|
bool Store::isInStore(PathView path) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -90,6 +90,9 @@ const uint32_t exportMagic = 0x4558494e;
|
||||||
|
|
||||||
|
|
||||||
enum BuildMode { bmNormal, bmRepair, bmCheck };
|
enum BuildMode { bmNormal, bmRepair, bmCheck };
|
||||||
|
/** Checks that a build mode is a valid one, then returns it */
|
||||||
|
BuildMode buildModeFromInteger(int);
|
||||||
|
|
||||||
enum TrustedFlag : bool { NotTrusted = false, Trusted = true };
|
enum TrustedFlag : bool { NotTrusted = false, Trusted = true };
|
||||||
|
|
||||||
struct BuildResult;
|
struct BuildResult;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
// Darwin stdenv does not define _GNU_SOURCE but does have _Unwind_Backtrace.
|
// Darwin stdenv does not define _GNU_SOURCE but does have _Unwind_Backtrace.
|
||||||
#ifdef __APPLE__
|
#if __APPLE__ || __FreeBSD__
|
||||||
#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED
|
#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED
|
||||||
#endif
|
#endif
|
||||||
#include <boost/stacktrace.hpp>
|
#include <boost/stacktrace.hpp>
|
||||||
|
|
|
@ -363,11 +363,6 @@ void mainWrapped(int argc, char * * argv)
|
||||||
|
|
||||||
setLogFormat("bar");
|
setLogFormat("bar");
|
||||||
settings.verboseBuild = false;
|
settings.verboseBuild = false;
|
||||||
if (isatty(STDERR_FILENO)) {
|
|
||||||
verbosity = lvlNotice;
|
|
||||||
} else {
|
|
||||||
verbosity = lvlInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
NixArgs args;
|
NixArgs args;
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,23 @@ struct CmdUpgradeNix : MixDryRun, EvalCommand
|
||||||
|
|
||||||
if (pathExists(canonProfileDir + "/manifest.nix")) {
|
if (pathExists(canonProfileDir + "/manifest.nix")) {
|
||||||
|
|
||||||
std::string nixEnvCmd = settings.nixBinDir + "/nix-env";
|
// {settings.nixBinDir}/nix-env is a symlink to a {settings.nixBinDir}/nix, which *then*
|
||||||
|
// is a symlink to /nix/store/meow-nix/bin/nix. We want /nix/store/meow-nix/bin/nix-env.
|
||||||
|
Path const nixInStore = canonPath(settings.nixBinDir + "/nix-env", true);
|
||||||
|
Path const nixEnvCmd = dirOf(nixInStore) + "/nix-env";
|
||||||
|
|
||||||
|
// First remove the existing Nix, then use that Nix by absolute path to
|
||||||
|
// install the new one, in case the new and old versions aren't considered
|
||||||
|
// to be "the same package" by nix-env's logic (e.g., if their pnames differ).
|
||||||
|
Strings removeArgs = {
|
||||||
|
"--uninstall",
|
||||||
|
nixEnvCmd,
|
||||||
|
"--profile",
|
||||||
|
this->profileDir,
|
||||||
|
};
|
||||||
|
printTalkative("running %s %s", nixEnvCmd, concatStringsSep(" ", removeArgs));
|
||||||
|
runProgram(nixEnvCmd, false, removeArgs);
|
||||||
|
|
||||||
Strings upgradeArgs = {
|
Strings upgradeArgs = {
|
||||||
"--profile",
|
"--profile",
|
||||||
this->profileDir,
|
this->profileDir,
|
||||||
|
|
|
@ -184,7 +184,9 @@ in
|
||||||
|
|
||||||
symlinkResolvconf = runNixOSTestFor "x86_64-linux" ./symlink-resolvconf.nix;
|
symlinkResolvconf = runNixOSTestFor "x86_64-linux" ./symlink-resolvconf.nix;
|
||||||
|
|
||||||
rootInSandbox = runNixOSTestFor "x86_64-linux" ./root-in-sandbox;
|
noNewPrivilegesInSandbox = runNixOSTestFor "x86_64-linux" ./no-new-privileges/sandbox.nix;
|
||||||
|
|
||||||
|
noNewPrivilegesOutsideSandbox = runNixOSTestFor "x86_64-linux" ./no-new-privileges/no-sandbox.nix;
|
||||||
|
|
||||||
broken-userns = runNixOSTestFor "x86_64-linux" ./broken-userns.nix;
|
broken-userns = runNixOSTestFor "x86_64-linux" ./broken-userns.nix;
|
||||||
|
|
||||||
|
|
21
tests/nixos/no-new-privileges/no-sandbox.nix
Normal file
21
tests/nixos/no-new-privileges/no-sandbox.nix
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
let
|
||||||
|
inherit (import ../util.nix) mkNixBuildTest;
|
||||||
|
in
|
||||||
|
mkNixBuildTest {
|
||||||
|
name = "no-new-privileges-outside-sandbox";
|
||||||
|
extraMachineConfig =
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
security.wrappers.ohno = {
|
||||||
|
owner = "root";
|
||||||
|
group = "root";
|
||||||
|
capabilities = "cap_sys_nice=eip";
|
||||||
|
source = "${pkgs.libcap}/bin/getpcaps";
|
||||||
|
};
|
||||||
|
nix.settings = {
|
||||||
|
extra-sandbox-paths = [ "/run/wrappers/bin/ohno" ];
|
||||||
|
sandbox = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
expressionFile = ./package.nix;
|
||||||
|
}
|
8
tests/nixos/no-new-privileges/package.nix
Normal file
8
tests/nixos/no-new-privileges/package.nix
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{ runCommand, libcap }:
|
||||||
|
runCommand "cant-get-capabilities" { nativeBuildInputs = [ libcap.out ]; } ''
|
||||||
|
if [ "$(/run/wrappers/bin/ohno 2>&1)" != "failed to inherit capabilities: Operation not permitted" ]; then
|
||||||
|
echo "Oh no! We gained capabilities!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
touch $out
|
||||||
|
''
|
18
tests/nixos/no-new-privileges/sandbox.nix
Normal file
18
tests/nixos/no-new-privileges/sandbox.nix
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
let
|
||||||
|
inherit (import ../util.nix) mkNixBuildTest;
|
||||||
|
in
|
||||||
|
mkNixBuildTest {
|
||||||
|
name = "no-new-privileges-in-sandbox";
|
||||||
|
extraMachineConfig =
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
security.wrappers.ohno = {
|
||||||
|
owner = "root";
|
||||||
|
group = "root";
|
||||||
|
capabilities = "cap_sys_nice=eip";
|
||||||
|
source = "${pkgs.libcap}/bin/getpcaps";
|
||||||
|
};
|
||||||
|
nix.settings.extra-sandbox-paths = [ "/run/wrappers/bin/ohno" ];
|
||||||
|
};
|
||||||
|
expressionFile = ./package.nix;
|
||||||
|
}
|
|
@ -1,15 +0,0 @@
|
||||||
let
|
|
||||||
inherit (import ../util.nix) mkNixBuildTest;
|
|
||||||
in mkNixBuildTest {
|
|
||||||
name = "root-in-sandbox";
|
|
||||||
extraMachineConfig = { pkgs, ... }: {
|
|
||||||
security.wrappers.ohno = {
|
|
||||||
owner = "root";
|
|
||||||
group = "root";
|
|
||||||
setuid = true;
|
|
||||||
source = "${pkgs.coreutils}/bin/whoami";
|
|
||||||
};
|
|
||||||
nix.settings.extra-sandbox-paths = ["/run/wrappers/bin"];
|
|
||||||
};
|
|
||||||
expressionFile = ./package.nix;
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
{ runCommand }:
|
|
||||||
runCommand "cant-get-root-in-sandbox" {} ''
|
|
||||||
if /run/wrappers/bin/ohno; then
|
|
||||||
echo "Oh no! We're root in the sandbox!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
touch $out
|
|
||||||
''
|
|
Loading…
Reference in a new issue