Errors removing setuid from binaries

I am trying to secure my system further. I have a root user and run0 works fine, so I dont need sudo, su or pkexec. I also dont need to do group and user manipulation as a regular user, so this can go too.

Some binaries will have setuid replaced with exact capabilities, I will see what is necessary and what is already included in nixpkgs.

Several issues occured

  1. Setting a value causes an issue as the packges come with a different value by default. I solve this using setuid = "${lib.mkForce false}";
  2. Now I get a different error which is weird

my config looks like this

security.wrappers = {
    chsh = {
        source = "${lib.getExe pkgs.util-linux "chsh"}";
        setuid = "${lib.mkForce false}";
    };
    chfn = {
        source = "${lib.getExe pkgs.util-linux "chfn"}";
        setuid = "${lib.mkForce false}";
    };
};

Note that false is not in quotes. But still I get this odd error

building the system configuration...
error:
       … while calling the 'head' builtin
         at /nix/store/n8gf8yr0571s1ld4nr6dmk143iv3rvmh-source/lib/attrsets.nix:1534:13:
         1533|           if length values == 1 || pred here (elemAt values 1) (head values) then
         1534|             head values
             |             ^
         1535|           else

       … while evaluating the attribute 'value'
         at /nix/store/n8gf8yr0571s1ld4nr6dmk143iv3rvmh-source/lib/modules.nix:1086:7:
         1085|     // {
         1086|       value = addErrorContext "while evaluating the option `${showOption loc}':" value;
             |       ^
         1087|       inherit (res.defsFinal') highestPrio;

       … while evaluating the option `system.build.toplevel':

       … while evaluating definitions from `/nix/store/n8gf8yr0571s1ld4nr6dmk143iv3rvmh-source/nixos/modules/system/activation/top-level.nix':

       … while evaluating the option `security.wrappers.chage.setuid':

       … while evaluating definitions from `/nix/store/2aysbqzpp72iipf93l6gvbjypf4nvyqx-source/configuration/modules/security.nix':

       (stack trace truncated; use '--show-trace' to show the full, detailed trace)

       error: cannot coerce a set to a string: { _type = "override"; content = false; priority = 50; }

error: cannot coerce a set to a string

using NixOS unstable, nixos-rebuild-ng

This is nonsense.

lib.mkForce is just a function for leaving a special datatstructure behind which the nixos module system then reacts specially to when it encounters it. What it leaves behind is an attrset with a particular value for the _type attribute, among other things. You’re trying to antiquote this attrset into a string, and nix is rightfully asking what you’re talking about.

2 Likes

So instead of being snarky what should I use instead, if a boolean value for setuid already exists and I want to overwrite that?

The interpreter actually recommended to use mkForce or mkDefault (not sure how to spell them), so yeah

Why are you using "${}" in the first place? Just put the value directly. You don’t intend to provide strings here.

setuid = lib.mkForce false;
2 Likes

Oh thanks, I am not fully into nix syntax yet, thought this is generally used for functions like that.

Apologies for coming off snarky. Bad day.

And yeah, I certainly should have been clear about what to do instead.

1 Like

So after a lot of troubleshooting I found the syntax to specify exact binaries within packages.

I think this is still not the best solution? But works.

For some reason owner and user needed to be defined everywhere, even though by default the binaries are there and work normally.

security.wrappers = {
    chsh = {
        source = "${pkgs.shadow}/bin/chsh";
        setuid = lib.mkForce false;
        owner = "root";
        group = "root";
    };
    chfn = {
        source = "${pkgs.util-linux}/bin/chfn";
        setuid = lib.mkForce false;
        owner = "root";
        group = "root";
    };
    su = {
        source = "${pkgs.su}/bin/su";
        setuid = lib.mkForce false;
        owner = "root";
        group = "root";
    };
    chage = {
        source = "${pkgs.shadow}/bin/chage";
        setuid = lib.mkForce false;
        owner = "root";
        group = "root";
    };
    useradd = {
        source = "${pkgs.shadow}/bin/useradd";
        setuid = lib.mkForce false;
        owner = "root";
        group = "root";
    };
    usermod = {
        source = "${pkgs.shadow}/bin/usermod";
        setuid = lib.mkForce false;
        owner = "root";
        group = "root";
    };
    userdel = {
        source = "${pkgs.shadow}/bin/userdel";
        setuid = lib.mkForce false;
        owner = "root";
        group = "root";
    };
    gpasswd = {
        source = "${pkgs.shadow}/bin/gpasswd";
        setuid = lib.mkForce false;
        owner = "root";
        group = "root";
    };
    groupadd = {
        source = "${pkgs.shadow}/bin/groupadd";
        setuid = lib.mkForce false;
        owner = "root";
        group = "root";
    };
    groupdel = {
        source = "${pkgs.shadow}/bin/groupdel";
        setuid = lib.mkForce false;
        owner = "root";
        group = "root";
    };
    fusermount = {
        source = "${pkgs.fuse}/bin/fusermount";
        setuid = lib.mkForce false;
        capabilities = "cap_sys_admin=ep";
        owner = "root";
        group = "root";
    };
    ping = {
        source = "${pkgs.iputils}/bin/ping";
        setuid = lib.mkForce false;
        capabilities = "cap_net_raw+ep";
        owner = "root";
        group = "root";
    };
    pkexec = {
        # not needed, run0
        source = "${pkgs.polkit}/bin/pkexec";
        setuid = lib.mkForce false;
        owner = "root";
        group = "root";
    };
    unix_chkpwd = {
        source = "${pkgs.linux-pam}/bin/unix_chkpwd";
        setuid = lib.mkForce false;
        capabilities = "cap_dac_read_search,cap_audit_write=ep";
        owner = "root";
        group = "root";
    };
};

Would probably be simpler to set security.wrappers.<name>.enable = false; for a bunch of these. I mean, you don’t want any special privileges on them, so there’s not much point in having the wrappers.

2 Likes

Oh damn overlooked that this exists, sure then

Btw what exactly is a wrapper? Do the binaries still exist without it?

Also, if I only change groups and users with nixos-rebuild, do I need setuid or the wrappers? I assume nix invokes the binaries to do its thing, but it runs as root?