From 5624aa9f812aeccc6b70de9812a28df28996545a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=BCtz?= Date: Wed, 5 May 2021 13:09:45 +0200 Subject: [PATCH] nixos/sudo: add option execWheelOnly By setting the executable's group to wheel and permissions to 4510, we make sure that only members of the wheel group can execute sudo. --- nixos/modules/security/sudo.nix | 28 +++++++++++++++++++++++++--- nixos/tests/sudo.nix | 21 ++++++++++++++++++++- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/nixos/modules/security/sudo.nix b/nixos/modules/security/sudo.nix index cc3ff3d11b9..2e73f8f4f31 100644 --- a/nixos/modules/security/sudo.nix +++ b/nixos/modules/security/sudo.nix @@ -61,6 +61,17 @@ in ''; }; + security.sudo.execWheelOnly = mkOption { + type = types.bool; + default = false; + description = '' + Only allow members of the wheel group to execute sudo by + setting the executable's permissions accordingly. + This prevents users that are not members of wheel from + exploiting vulnerabilities in sudo such as CVE-2021-3156. + ''; + }; + security.sudo.configFile = mkOption { type = types.lines; # Note: if syntax errors are detected in this file, the NixOS @@ -216,9 +227,20 @@ in ${cfg.extraConfig} ''; - security.wrappers = { - sudo.source = "${cfg.package.out}/bin/sudo"; - sudoedit.source = "${cfg.package.out}/bin/sudoedit"; + security.wrappers = let + owner = "root"; + group = if cfg.execWheelOnly then "wheel" else "root"; + setuid = true; + permissions = if cfg.execWheelOnly then "u+rx,g+x" else "u+rx,g+x,o+x"; + in { + sudo = { + source = "${cfg.package.out}/bin/sudo"; + inherit owner group setuid permissions; + }; + sudoedit = { + source = "${cfg.package.out}/bin/sudoedit"; + inherit owner group setuid permissions; + }; }; environment.systemPackages = [ sudo ]; diff --git a/nixos/tests/sudo.nix b/nixos/tests/sudo.nix index 2a85c490665..4885d6e17b8 100644 --- a/nixos/tests/sudo.nix +++ b/nixos/tests/sudo.nix @@ -10,7 +10,7 @@ in maintainers = [ lschuermann ]; }; - machine = + nodes.machine = { lib, ... }: with lib; { @@ -48,6 +48,19 @@ in }; }; + nodes.strict = { ... }: { + users.users = { + admin = { isNormalUser = true; extraGroups = [ "wheel" ]; }; + noadmin = { isNormalUser = true; }; + }; + + security.sudo = { + enable = true; + wheelNeedsPassword = false; + execWheelOnly = true; + }; + }; + testScript = '' with subtest("users in wheel group should have passwordless sudo"): @@ -79,5 +92,11 @@ in with subtest("users in group 'barfoo' should not be able to keep their environment"): machine.fail("sudo -u test3 sudo -n -E -u root true") + + with subtest("users in wheel should be able to run sudo despite execWheelOnly"): + strict.succeed('su - admin -c "sudo -u root true"') + + with subtest("non-wheel users should be unable to run sudo thanks to execWheelOnly"): + strict.fail('su - noadmin -c "sudo --help"') ''; })