2024-05-15 15:35:15 +00:00
|
|
|
{ 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 = {
|
2024-10-04 16:56:33 +00:00
|
|
|
description = "Isolate Sandbox Slice";
|
2024-05-15 15:35:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
meta.maintainers = with maintainers; [ virchau13 ];
|
|
|
|
};
|
|
|
|
}
|