Jump to content

NixOS Hardening

From Official NixOS Wiki
Revision as of 09:41, 23 March 2026 by Golbinex (talk | contribs) (Initial page)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

linux-hardened

linux-hardened is a Linux kernel with additional hardening patches applied.

boot.kernelPackages = pkgs.linuxKernel.packages.linux_hardened;

Lock kernel modules

This option locks kernel modules after the system is initialized. For example it prevents malicious USB devices from exploiting vulnerable kernel modules.

security.lockKernelModules = true;

All needed modules must be loaded at boot by adding them to boot.kernelModules.

Module blacklist

boot.blacklistedKernelModules = [
  # Obscure network protocols
  "ax25" "netrom" "rose"

  # Old or rare or insufficiently audited filesystems
  "adfs" "affs"
  "bfs" "befs"
  "cramfs"
  "efs" "erofs" "exofs"
  "freevxfs" "f2fs"
  "hfs" "hpfs"
  "jfs"
  "minix"
  "nilfs2" "ntfs"
  "omfs"
  "qnx4" "qnx6"
  "sysv"
  "ufs"
];

Kernel image protection

Prevents replacing the running kernel image.

security.protectKernelImage = true;

Kernel parameters

boot.kernelParams = [
 # Don't merge slabs
 "slab_nomerge"

 # Overwrite free'd pages
 "page_poison=1"

 # Enable page allocator randomization
 "page_alloc.shuffle=1"

 # Disable debugfs
 "debugfs=off"
];

Sysctl parameters

# Hide kptrs even for processes with CAP_SYSLOG
boot.kernel.sysctl."kernel.kptr_restrict" = "2";

# Disable bpf() JIT (to eliminate spray attacks)
boot.kernel.sysctl."net.core.bpf_jit_enable" = false;

# Disable ftrace debugging
boot.kernel.sysctl."kernel.ftrace_enabled" = false;

# Enable strict reverse path filtering (that is, do not attempt to route
# packets that "obviously" do not belong to the iface's network; dropped
# packets are logged as martians).
boot.kernel.sysctl."net.ipv4.conf.all.log_martians" = true;
boot.kernel.sysctl."net.ipv4.conf.all.rp_filter" = "1";
boot.kernel.sysctl."net.ipv4.conf.default.log_martians" = true;
boot.kernel.sysctl."net.ipv4.conf.default.rp_filter" = "1";

# Ignore broadcast ICMP (mitigate SMURF)
boot.kernel.sysctl."net.ipv4.icmp_echo_ignore_broadcasts" = true;

# Ignore incoming ICMP redirects (note: default is needed to ensure that the
# setting is applied to interfaces added after the sysctls are set)
boot.kernel.sysctl."net.ipv4.conf.all.accept_redirects" = false;
boot.kernel.sysctl."net.ipv4.conf.all.secure_redirects" = false;
boot.kernel.sysctl."net.ipv4.conf.default.accept_redirects" = false;
boot.kernel.sysctl."net.ipv4.conf.default.secure_redirects" = false;
boot.kernel.sysctl."net.ipv6.conf.all.accept_redirects" = false;
boot.kernel.sysctl."net.ipv6.conf.default.accept_redirects" = false;

# Ignore outgoing ICMP redirects (this is ipv4 only)
boot.kernel.sysctl."net.ipv4.conf.all.send_redirects" = false;
boot.kernel.sysctl."net.ipv4.conf.default.send_redirects" = false;

Disable Simultaneous Multithreading (SMT)

Might cause significant performance cost.

security.allowSimultaneousMultithreading = false;

Force Page Table Isolation

security.forcePageTableIsolation = true;

Memory allocator

You can use security-focused memory allocator like scudo or GrapheneOS hardened_malloc.

# scudo
environment.memoryAllocator.provider = "scudo";
environment.variables.SCUDO_OPTIONS = "zero_contents=true";
# hardened_malloc
environment.memoryAllocator.provider = "graphene-hardened";

Some programs may not work with these memory allocators. You can force them to use the default libc allocator by blacklisting /etc/ld-nix.so.preload with a firejail wrap.

programs.firejail = {
  enable = true;
  wrappedBinaries = {
    chromium = {
      executable = "${pkgs.chromium}/bin/chromium-browser";
      profile = "${pkgs.firejail}/etc/firejail/chromium-browser.profile";
      extraArgs = [
        "--blacklist=/etc/ld-nix.so.preload"
      ];
    };
  };
};

Nix allowed users

This option allows only users group to connect to the Nix daemon.

nix.settings.allowed-users = [ "@users" ];

Flush L1 data cache

Might cause significant performance cost.

security.virtualisation.flushL1DataCache = "always";

AppArmor

security.apparmor.enable = true;
security.apparmor.killUnconfinedConfinables = true;