From cef2814a4f0530f6e020badc56dd808a96422a66 Mon Sep 17 00:00:00 2001 From: Joachim Fasting Date: Sat, 9 Apr 2016 20:22:16 +0200 Subject: [PATCH] nixos: add optional process information hiding This module adds an option `security.hideProcessInformation` that, when enabled, restricts access to process information such as command-line arguments to the process owner. The module adds a static group "proc" whose members are exempt from process information hiding. Ideally, this feature would be implemented by simply adding the appropriate mount options to `fileSystems."/proc".fsOptions`, but this was found to not work in vmtests. To ensure that process information hiding is enforced, we use a systemd service unit that remounts `/proc` after `systemd-remount-fs.service` has completed. To verify the correctness of the feature, simple tests were added to nixos/tests/misc: the test ensures that unprivileged users cannot see process information owned by another user, while members of "proc" CAN. Thanks to @abbradar for feedback and suggestions. --- nixos/modules/misc/ids.nix | 2 ++ nixos/modules/module-list.nix | 1 + nixos/modules/security/hidepid.nix | 42 ++++++++++++++++++++++++++++++ nixos/tests/misc.nix | 9 +++++++ 4 files changed, 54 insertions(+) create mode 100644 nixos/modules/security/hidepid.nix diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 1e14fe655fc0..3f2c735b2216 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -47,6 +47,7 @@ #floppy = 18; # unused #uucp = 19; # unused #lp = 20; # unused + #proc = 21; # unused pulseaudio = 22; # must match `pulseaudio' GID gpsd = 23; #cdrom = 24; # unused @@ -288,6 +289,7 @@ floppy = 18; uucp = 19; lp = 20; + proc = 21; pulseaudio = 22; # must match `pulseaudio' UID gpsd = 23; cdrom = 24; diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 7bcc5b849417..19c8db1039b6 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -90,6 +90,7 @@ ./security/ca.nix ./security/duosec.nix ./security/grsecurity.nix + ./security/hidepid.nix ./security/oath.nix ./security/pam.nix ./security/pam_usb.nix diff --git a/nixos/modules/security/hidepid.nix b/nixos/modules/security/hidepid.nix new file mode 100644 index 000000000000..8271578c55d6 --- /dev/null +++ b/nixos/modules/security/hidepid.nix @@ -0,0 +1,42 @@ +{ config, pkgs, lib, ... }: +with lib; + +{ + options = { + security.hideProcessInformation = mkEnableOption "" // { description = '' + Restrict access to process information to the owning user. Enabling + this option implies, among other things, that command-line arguments + remain private. This option is recommended for most systems, unless + there's a legitimate reason for allowing unprivileged users to inspect + the process information of other users. + + Members of the group "proc" are exempt from process information hiding. + To allow a service to run without process information hiding, add "proc" + to its supplementary groups via + . + ''; }; + }; + + config = mkIf config.security.hideProcessInformation { + users.groups.proc.gid = config.ids.gids.proc; + + systemd.services.hidepid = { + wantedBy = [ "local-fs.target" ]; + after = [ "systemd-remount-fs.service" ]; + before = [ "local-fs-pre.target" "local-fs.target" "shutdown.target" ]; + wants = [ "local-fs-pre.target" ]; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = ''${pkgs.utillinux}/bin/mount -o remount,hidepid=2,gid=${toString config.ids.gids.proc} /proc''; + ExecStop = ''${pkgs.utillinux}/bin/mount -o remount,hidepid=0,gid=0 /proc''; + }; + + unitConfig = { + DefaultDependencies = false; + Conflicts = "shutdown.target"; + }; + }; + }; +} diff --git a/nixos/tests/misc.nix b/nixos/tests/misc.nix index b926a62194b4..cd4086cb8f62 100644 --- a/nixos/tests/misc.nix +++ b/nixos/tests/misc.nix @@ -25,6 +25,8 @@ import ./make-test.nix ({ pkgs, ...} : { }; users.users.sybil = { isNormalUser = true; group = "wheel"; }; security.sudo = { enable = true; wheelNeedsPassword = false; }; + security.hideProcessInformation = true; + users.users.alice = { isNormalUser = true; extraGroups = [ "proc" ]; }; }; testScript = @@ -117,5 +119,12 @@ import ./make-test.nix ({ pkgs, ...} : { subtest "sudo", sub { $machine->succeed("su - sybil -c 'sudo true'"); }; + + # Test hidepid + subtest "hidepid", sub { + $machine->succeed("grep -Fq hidepid=2 /etc/mtab"); + $machine->succeed("[ `su - sybil -c 'pgrep -c -u root'` = 0 ]"); + $machine->succeed("[ `su - alice -c 'pgrep -c -u root'` != 0 ]"); + }; ''; })