ad9bfe2254
linux-hardened sets kernel.unprivileged_userns_clone=0 by default; see anthraxx/linux-hardened@104f44058f. This allows the Nix sandbox to function while reducing the attack surface posed by user namespaces, which allow unprivileged code to exercise lots of root-only code paths and have lead to privilege escalation vulnerabilities in the past. We can safely leave user namespaces on for privileged users, as root already has root privileges, but if you're not running builds on your machine and really want to minimize the kernel attack surface then you can set security.allowUserNamespaces to false. Note that Chrome's sandbox requires either unprivileged CLONE_NEWUSER or setuid, and Firefox's silently reduces the security level if it isn't allowed (see about:support), so desktop users may want to set: boot.kernel.sysctl."kernel.unprivileged_userns_clone" = true;
126 lines
4.1 KiB
Nix
126 lines
4.1 KiB
Nix
import ./make-test.nix ({ pkgs, ...} : {
|
|
name = "hardened";
|
|
meta = with pkgs.stdenv.lib.maintainers; {
|
|
maintainers = [ joachifm ];
|
|
};
|
|
|
|
machine =
|
|
{ lib, pkgs, config, ... }:
|
|
with lib;
|
|
{ users.users.alice = { isNormalUser = true; extraGroups = [ "proc" ]; };
|
|
users.users.sybil = { isNormalUser = true; group = "wheel"; };
|
|
imports = [ ../modules/profiles/hardened.nix ];
|
|
environment.memoryAllocator.provider = "graphene-hardened";
|
|
nix.useSandbox = false;
|
|
virtualisation.emptyDiskImages = [ 4096 ];
|
|
boot.initrd.postDeviceCommands = ''
|
|
${pkgs.dosfstools}/bin/mkfs.vfat -n EFISYS /dev/vdb
|
|
'';
|
|
fileSystems = lib.mkVMOverride {
|
|
"/efi" = {
|
|
device = "/dev/disk/by-label/EFISYS";
|
|
fsType = "vfat";
|
|
options = [ "noauto" ];
|
|
};
|
|
};
|
|
boot.extraModulePackages = [ config.boot.kernelPackages.wireguard ];
|
|
boot.kernelModules = [ "wireguard" ];
|
|
};
|
|
|
|
testScript =
|
|
let
|
|
hardened-malloc-tests = pkgs.stdenv.mkDerivation {
|
|
name = "hardened-malloc-tests-${pkgs.graphene-hardened-malloc.version}";
|
|
src = pkgs.graphene-hardened-malloc.src;
|
|
buildPhase = ''
|
|
cd test/simple-memory-corruption
|
|
make -j4
|
|
'';
|
|
|
|
installPhase = ''
|
|
find . -type f -executable -exec install -Dt $out/bin '{}' +
|
|
'';
|
|
};
|
|
in
|
|
''
|
|
$machine->waitForUnit("multi-user.target");
|
|
|
|
subtest "apparmor-loaded", sub {
|
|
$machine->succeed("systemctl status apparmor.service");
|
|
};
|
|
|
|
# AppArmor securityfs
|
|
subtest "apparmor-securityfs", sub {
|
|
$machine->succeed("mountpoint -q /sys/kernel/security");
|
|
$machine->succeed("cat /sys/kernel/security/apparmor/profiles");
|
|
};
|
|
|
|
# Test loading out-of-tree modules
|
|
subtest "extra-module-packages", sub {
|
|
$machine->succeed("grep -Fq wireguard /proc/modules");
|
|
};
|
|
|
|
# Test hidepid
|
|
subtest "hidepid", sub {
|
|
$machine->succeed("grep -Fq hidepid=2 /proc/mounts");
|
|
# cannot use pgrep -u here, it segfaults when access to process info is denied
|
|
$machine->succeed("[ `su - sybil -c 'ps --no-headers --user root | wc -l'` = 0 ]");
|
|
$machine->succeed("[ `su - alice -c 'ps --no-headers --user root | wc -l'` != 0 ]");
|
|
};
|
|
|
|
# Test kernel module hardening
|
|
subtest "lock-modules", sub {
|
|
# note: this better a be module we normally wouldn't load ...
|
|
$machine->fail("modprobe dccp");
|
|
};
|
|
|
|
# Test userns
|
|
subtest "userns", sub {
|
|
$machine->succeed("unshare --user true");
|
|
$machine->fail("su -l alice -c 'unshare --user true'");
|
|
};
|
|
|
|
# Test dmesg restriction
|
|
subtest "dmesg", sub {
|
|
$machine->fail("su -l alice -c dmesg");
|
|
};
|
|
|
|
# Test access to kcore
|
|
subtest "kcore", sub {
|
|
$machine->fail("cat /proc/kcore");
|
|
};
|
|
|
|
# Test deferred mount
|
|
subtest "mount", sub {
|
|
$machine->fail("mountpoint -q /efi"); # was deferred
|
|
$machine->execute("mkdir -p /efi");
|
|
$machine->succeed("mount /dev/disk/by-label/EFISYS /efi");
|
|
$machine->succeed("mountpoint -q /efi"); # now mounted
|
|
};
|
|
|
|
# Test Nix dæmon usage
|
|
subtest "nix-daemon", sub {
|
|
$machine->fail("su -l nobody -s /bin/sh -c 'nix ping-store'");
|
|
$machine->succeed("su -l alice -c 'nix ping-store'") =~ "OK";
|
|
};
|
|
|
|
# Test kernel image protection
|
|
subtest "kernelimage", sub {
|
|
$machine->fail("systemctl hibernate");
|
|
$machine->fail("systemctl kexec");
|
|
};
|
|
|
|
# Test hardened memory allocator
|
|
sub runMallocTestProg {
|
|
my ($progName, $errorText) = @_;
|
|
my $text = "fatal allocator error: " . $errorText;
|
|
$machine->fail("${hardened-malloc-tests}/bin/" . $progName) =~ $text;
|
|
};
|
|
|
|
subtest "hardenedmalloc", sub {
|
|
runMallocTestProg("double_free_large", "invalid free");
|
|
runMallocTestProg("unaligned_free_small", "invalid unaligned free");
|
|
runMallocTestProg("write_after_free_small", "detected write after free");
|
|
};
|
|
'';
|
|
})
|