mirror of
https://github.com/ilyakooo0/nixpkgs.git
synced 2024-10-06 12:39:54 +03:00
Merge pull request #305853 from virchau13s-forks/isolate-module
isolate: add module and module tests
This commit is contained in:
commit
3ed7049cdd
@ -191,6 +191,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
|
|||||||
|
|
||||||
- [prometheus-nats-exporter](https://github.com/nats-io/prometheus-nats-exporter), a Prometheus exporter for NATS. Available as [services.prometheus.exporters.nats](#opt-services.prometheus.exporters.nats.enable).
|
- [prometheus-nats-exporter](https://github.com/nats-io/prometheus-nats-exporter), a Prometheus exporter for NATS. Available as [services.prometheus.exporters.nats](#opt-services.prometheus.exporters.nats.enable).
|
||||||
|
|
||||||
|
- [isolate](https://github.com/ioi/isolate), a sandbox for securely executing untrusted programs. Available as [security.isolate](#opt-security.isolate.enable).
|
||||||
|
|
||||||
## Backward Incompatibilities {#sec-release-24.05-incompatibilities}
|
## Backward Incompatibilities {#sec-release-24.05-incompatibilities}
|
||||||
|
|
||||||
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
|
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
|
||||||
|
@ -325,6 +325,7 @@
|
|||||||
./security/duosec.nix
|
./security/duosec.nix
|
||||||
./security/google_oslogin.nix
|
./security/google_oslogin.nix
|
||||||
./security/ipa.nix
|
./security/ipa.nix
|
||||||
|
./security/isolate.nix
|
||||||
./security/krb5
|
./security/krb5
|
||||||
./security/lock-kernel-modules.nix
|
./security/lock-kernel-modules.nix
|
||||||
./security/misc.nix
|
./security/misc.nix
|
||||||
|
133
nixos/modules/security/isolate.nix
Normal file
133
nixos/modules/security/isolate.nix
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib) mkEnableOption mkPackageOption mkOption types mkIf maintainers;
|
||||||
|
|
||||||
|
cfg = config.security.isolate;
|
||||||
|
configFile = pkgs.writeText "isolate-config.cf" ''
|
||||||
|
box_root=${cfg.boxRoot}
|
||||||
|
lock_root=${cfg.lockRoot}
|
||||||
|
cg_root=${cfg.cgRoot}
|
||||||
|
first_uid=${toString cfg.firstUid}
|
||||||
|
first_gid=${toString cfg.firstGid}
|
||||||
|
num_boxes=${toString cfg.numBoxes}
|
||||||
|
restricted_init=${if cfg.restrictedInit then "1" else "0"}
|
||||||
|
${cfg.extraConfig}
|
||||||
|
'';
|
||||||
|
isolate = pkgs.symlinkJoin {
|
||||||
|
name = "isolate-wrapped-${pkgs.isolate.version}";
|
||||||
|
|
||||||
|
paths = [ pkgs.isolate ];
|
||||||
|
|
||||||
|
nativeBuildInputs = [ pkgs.makeWrapper ];
|
||||||
|
|
||||||
|
postBuild = ''
|
||||||
|
wrapProgram $out/bin/isolate \
|
||||||
|
--set ISOLATE_CONFIG_FILE ${configFile}
|
||||||
|
|
||||||
|
wrapProgram $out/bin/isolate-cg-keeper \
|
||||||
|
--set ISOLATE_CONFIG_FILE ${configFile}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.security.isolate = {
|
||||||
|
enable = mkEnableOption ''
|
||||||
|
Sandbox for securely executing untrusted programs
|
||||||
|
'';
|
||||||
|
|
||||||
|
package = mkPackageOption pkgs "isolate-unwrapped" { };
|
||||||
|
|
||||||
|
boxRoot = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
default = "/var/lib/isolate/boxes";
|
||||||
|
description = ''
|
||||||
|
All sandboxes are created under this directory.
|
||||||
|
To avoid symlink attacks, this directory and all its ancestors
|
||||||
|
must be writeable only by root.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
lockRoot = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
default = "/run/isolate/locks";
|
||||||
|
description = ''
|
||||||
|
Directory where lock files are created.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
cgRoot = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "auto:/run/isolate/cgroup";
|
||||||
|
description = ''
|
||||||
|
Control group which subgroups are placed under.
|
||||||
|
Either an explicit path to a subdirectory in cgroupfs, or "auto:file" to read
|
||||||
|
the path from "file", where it is put by `isolate-cg-helper`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
firstUid = mkOption {
|
||||||
|
type = types.numbers.between 1000 65533;
|
||||||
|
default = 60000;
|
||||||
|
description = ''
|
||||||
|
Start of block of UIDs reserved for sandboxes.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
firstGid = mkOption {
|
||||||
|
type = types.numbers.between 1000 65533;
|
||||||
|
default = 60000;
|
||||||
|
description = ''
|
||||||
|
Start of block of GIDs reserved for sandboxes.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
numBoxes = mkOption {
|
||||||
|
type = types.numbers.between 1000 65533;
|
||||||
|
default = 1000;
|
||||||
|
description = ''
|
||||||
|
Number of UIDs and GIDs to reserve, starting from
|
||||||
|
{option}`firstUid` and {option}`firstGid`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
restrictedInit = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
If true, only root can create sandboxes.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
extraConfig = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "";
|
||||||
|
description = ''
|
||||||
|
Extra configuration to append to the configuration file.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
environment.systemPackages = [
|
||||||
|
isolate
|
||||||
|
];
|
||||||
|
|
||||||
|
systemd.services.isolate = {
|
||||||
|
description = "Isolate control group hierarchy daemon";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "notify";
|
||||||
|
ExecStart = "${isolate}/bin/isolate-cg-keeper";
|
||||||
|
Slice = "isolate.slice";
|
||||||
|
Delegate = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.slices.isolate = {
|
||||||
|
description = "Isolate sandbox slice";
|
||||||
|
};
|
||||||
|
|
||||||
|
meta.maintainers = with maintainers; [ virchau13 ];
|
||||||
|
};
|
||||||
|
}
|
@ -399,6 +399,7 @@ in {
|
|||||||
honk = runTest ./honk.nix;
|
honk = runTest ./honk.nix;
|
||||||
installed-tests = pkgs.recurseIntoAttrs (handleTest ./installed-tests {});
|
installed-tests = pkgs.recurseIntoAttrs (handleTest ./installed-tests {});
|
||||||
invidious = handleTest ./invidious.nix {};
|
invidious = handleTest ./invidious.nix {};
|
||||||
|
isolate = handleTest ./isolate.nix {};
|
||||||
livebook-service = handleTest ./livebook-service.nix {};
|
livebook-service = handleTest ./livebook-service.nix {};
|
||||||
pyload = handleTest ./pyload.nix {};
|
pyload = handleTest ./pyload.nix {};
|
||||||
oci-containers = handleTestOn ["aarch64-linux" "x86_64-linux"] ./oci-containers.nix {};
|
oci-containers = handleTestOn ["aarch64-linux" "x86_64-linux"] ./oci-containers.nix {};
|
||||||
|
38
nixos/tests/isolate.nix
Normal file
38
nixos/tests/isolate.nix
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import ./make-test-python.nix ({ lib, ... }:
|
||||||
|
{
|
||||||
|
name = "isolate";
|
||||||
|
meta.maintainers = with lib.maintainers; [ virchau13 ];
|
||||||
|
|
||||||
|
nodes.machine =
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
security.isolate = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
bash_path = machine.succeed('realpath $(which bash)').strip()
|
||||||
|
sleep_path = machine.succeed('realpath $(which sleep)').strip()
|
||||||
|
def sleep_test(walltime, sleeptime):
|
||||||
|
return f'isolate --no-default-dirs --wall-time {walltime} ' + \
|
||||||
|
f'--dir=/box={box_path} --dir=/nix=/nix --run -- ' + \
|
||||||
|
f"{bash_path} -c 'exec -a sleep {sleep_path} {sleeptime}'"
|
||||||
|
|
||||||
|
def sleep_test_cg(walltime, sleeptime):
|
||||||
|
return f'isolate --cg --no-default-dirs --wall-time {walltime} ' + \
|
||||||
|
f'--dir=/box={box_path} --dir=/nix=/nix --processes=2 --run -- ' + \
|
||||||
|
f"{bash_path} -c '( exec -a sleep {sleep_path} {sleeptime} )'"
|
||||||
|
|
||||||
|
with subtest("without cgroups"):
|
||||||
|
box_path = machine.succeed('isolate --init').strip()
|
||||||
|
machine.succeed(sleep_test(1, 0.5))
|
||||||
|
machine.fail(sleep_test(0.5, 1))
|
||||||
|
machine.succeed('isolate --cleanup')
|
||||||
|
with subtest("with cgroups"):
|
||||||
|
box_path = machine.succeed('isolate --cg --init').strip()
|
||||||
|
machine.succeed(sleep_test_cg(1, 0.5))
|
||||||
|
machine.fail(sleep_test_cg(0.5, 1))
|
||||||
|
machine.succeed('isolate --cg --cleanup')
|
||||||
|
'';
|
||||||
|
})
|
@ -3,7 +3,10 @@
|
|||||||
, fetchFromGitHub
|
, fetchFromGitHub
|
||||||
, asciidoc
|
, asciidoc
|
||||||
, libcap
|
, libcap
|
||||||
|
, pkg-config
|
||||||
|
, systemdLibs
|
||||||
, installShellFiles
|
, installShellFiles
|
||||||
|
, nixosTests
|
||||||
}:
|
}:
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
@ -20,26 +23,33 @@ stdenv.mkDerivation rec {
|
|||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
asciidoc
|
asciidoc
|
||||||
installShellFiles
|
installShellFiles
|
||||||
|
pkg-config
|
||||||
];
|
];
|
||||||
|
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
libcap.dev
|
libcap.dev
|
||||||
|
systemdLibs.dev
|
||||||
];
|
];
|
||||||
|
|
||||||
buildFlags = [
|
patches = [
|
||||||
"isolate"
|
./take-config-file-from-env.patch
|
||||||
"isolate.1"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
runHook preInstall
|
runHook preInstall
|
||||||
|
|
||||||
install -Dm755 ./isolate $out/bin/isolate
|
install -Dm755 ./isolate $out/bin/isolate
|
||||||
|
install -Dm755 ./isolate-cg-keeper $out/bin/isolate-cg-keeper
|
||||||
|
install -Dm755 ./isolate-check-environment $out/bin/isolate-check-environment
|
||||||
installManPage isolate.1
|
installManPage isolate.1
|
||||||
|
|
||||||
runHook postInstall
|
runHook postInstall
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
passthru.tests = {
|
||||||
|
isolate = nixosTests.isolate;
|
||||||
|
};
|
||||||
|
|
||||||
meta = {
|
meta = {
|
||||||
description = "Sandbox for securely executing untrusted programs";
|
description = "Sandbox for securely executing untrusted programs";
|
||||||
mainProgram = "isolate";
|
mainProgram = "isolate";
|
||||||
|
19
pkgs/tools/security/isolate/take-config-file-from-env.patch
Normal file
19
pkgs/tools/security/isolate/take-config-file-from-env.patch
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
diff --git a/config.c b/config.c
|
||||||
|
index 6477259..c462ed3 100644
|
||||||
|
--- a/config.c
|
||||||
|
+++ b/config.c
|
||||||
|
@@ -114,9 +114,12 @@ cf_check(void)
|
||||||
|
void
|
||||||
|
cf_parse(void)
|
||||||
|
{
|
||||||
|
- FILE *f = fopen(CONFIG_FILE, "r");
|
||||||
|
+ char *config_file = getenv("ISOLATE_CONFIG_FILE");
|
||||||
|
+ if(!config_file)
|
||||||
|
+ die("ISOLATE_CONFIG_FILE environment variable not set");
|
||||||
|
+ FILE *f = fopen(config_file, "r");
|
||||||
|
if (!f)
|
||||||
|
- die("Cannot open %s: %m", CONFIG_FILE);
|
||||||
|
+ die("Cannot open %s: %m", config_file);
|
||||||
|
|
||||||
|
char line[MAX_LINE_LEN];
|
||||||
|
while (fgets(line, sizeof(line), f))
|
Loading…
Reference in New Issue
Block a user