Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Best effort supplementary groups #8342

Merged

Conversation

Ericson2314
Copy link
Member

Motivation

There is no obvious good solution for this that has occurred to anyone.

Provide a way to hack around trying to drop supplementary groups when root.

Context

Currently,

unshare --map-root-user nix-build ...

will fail when the outside user is not root, because one doesn't actually have the permission to call setgroups. This provides a work-around to skip that step.

Checklist for maintainers

Maintainers: tick if completed or explain if not relevant

  • agreed on idea
  • agreed on implementation strategy
  • tests, as appropriate
    • functional tests - tests/**.sh
    • unit tests - src/*/tests
    • integration tests - tests/nixos/*
  • documentation in the manual
  • documentation in the internal API docs
  • code and comments are self-explanatory
  • commit message explains why the change was made
  • new feature or incompatible change: updated release notes

Priorities

Add 👍 to pull requests you find important.

Ericson2314 and others added 2 commits May 8, 2023 14:41
There is no obvious good solution for this that has occured to anyone.
@github-actions github-actions bot added the with-tests Issues related to testing. PRs with tests have some priority label May 15, 2023
This gets in the way of the tests running in parallel.
R"(
Whether to drop supplementary groups when building with sandboxing.
This is normally a good idea if we are root and have the capability to
do so.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When is it not? I think we should warn about negative groups (if that's the right name for it); groups that when you're a member, you have fewer capabilities rather than more.

It would guess for it to be rare that the daemon would start as root but have a negative group, but I don't think we are free to assume just assume that and be quiet about it here.

Copy link
Member Author

@Ericson2314 Ericson2314 May 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@roberth The problem is I don't think Unix has any clue what groups are "covariant", "contravariant", or "invariant": it depends on how they are used, and none of the LWM stuff on this mention any attempt to annotate the intent of the group on the group itself.

Unix is thus stuck with the pessimistic assumption that all groups are invariant, and only privilaged users can take them on or drop them alike.

It's extremely mediocre :/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would love to yell ask nicely on the LKML about all this:

  • Why no way to annotate that info on the group, backwards compatibly?!
  • Why do all the groups of a user need to be mapped into the user namespace in the first place?!
  • Why does creating a mount namespace require a user namespace in the first place?!

But I think these are yak shaves not yet fitting in anyone's budget :).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could document our opinion, "open letter" style.

contravariant

That corresponds to my "negative". Not sure which is better. Something "anti-..." could fit and be more explicit. Needs more thought or more reading, or anything will do.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think postive/negative is better than co-/contrainvariant :), but then there is "invariant" too, and what does that map to? "Neutral" sounds more innocuous, like "bivariant" to me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going back to the original question, I am actually fine with Nix assuming all groups are "positive", and always trying to drop groups. Non-positive ones are gross to me and I have little interest in trying to support them.

The real question question is if that operation fails, is it a fatal error or not? That is what feels to me like like a question that ultimately needs to be in the user's not Nix's hand.

(To simply unblock myself writing tests, and also for backwards compat since Nix didn't try to do the operation as non-root before, I made the option on whether to attempt the option. I have issue to instead make the setting about what to do if the operation fails with EPERM or whatever. Non-root could attempt the operation anyways, after all, it's possible to have the CAP_SETGID without being root so it might in fact succeed.)

@thufschmitt thufschmitt added the idea approved The given proposal has been discussed and approved by the Nix team. An implementation is welcome. label Jun 23, 2023
@thufschmitt thufschmitt self-assigned this Jun 23, 2023
@fricklerhandwerk
Copy link
Contributor

  • @edolstra: description of the option should note it's a security issue, as the builds will be less sandboxed with the setting turned on
  • @fricklerhandwerk: default value should be documented by a special string

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/2023-06-22-nix-team-meeting-minutes-65/29643/1

@Ericson2314 Ericson2314 marked this pull request as ready for review July 11, 2023 14:25
@Ericson2314 Ericson2314 requested a review from edolstra as a code owner July 11, 2023 14:25
@Ericson2314 Ericson2314 marked this pull request as draft July 11, 2023 14:30
Copy link
Member Author

@Ericson2314 Ericson2314 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@benradf's changes look good to me in this PR. The only issue is now the test is being skipped.

src/libstore/globals.hh Outdated Show resolved Hide resolved
src/libstore/globals.hh Outdated Show resolved Hide resolved
@Ericson2314 Ericson2314 marked this pull request as ready for review July 13, 2023 19:25
Copy link
Member

@benradf benradf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unset NIX_STORE_DIR changes look good. I see that the supplementary-groups test is no longer being skipped on CI.

Copy link
Member

@thufschmitt thufschmitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that's looking great now:+1:

@thufschmitt thufschmitt merged commit a8d5bb5 into NixOS:master Jul 17, 2023
@Ericson2314 Ericson2314 deleted the best-effort-supplementary-groups branch July 17, 2023 20:26
Ericson2314 added a commit to obsidiansystems/nix that referenced this pull request Jul 24, 2023
The motivation for this is basically explained in the contribution
guide, as guidance on how to design features like this going forward.

In short, I think it is confusing for operations acting on the default
profile to *always* do something different based on whether the user is
regular or root.

Instead, this makes there be flags which are (from the vantage point of
today) "do the root default" vs "do the regular user" default. This make
the situation teachable: we can point to the flags, and the conditional
default, as *exactly* what varies between the root and non-root cases.
And by manually specifying enough flags, we can ensure those defaults
are overridden and Nix will indeed do the same thing (or fail trying).

This is similar to the logic behind the supplementary group setting
(NixOS#8342), which I also discuss in this new section of the contribution
guide as a second example.
Ericson2314 added a commit to obsidiansystems/nix that referenced this pull request Jul 24, 2023
The motivation for this is basically explained in the contribution
guide, as guidance on how to design features like this going forward.

In short, I think it is confusing for operations acting on the default
profile to *always* do something different based on whether the user is
regular or root.

Instead, this makes there be flags which are (from the vantage point of
today) "do the root default" vs "do the regular user" default. This make
the situation teachable: we can point to the flags, and the conditional
default, as *exactly* what varies between the root and non-root cases.
And by manually specifying enough flags, we can ensure those defaults
are overridden and Nix will indeed do the same thing (or fail trying).

This is similar to the logic behind the supplementary group setting
(NixOS#8342), which I also discuss in this new section of the contribution
guide as a second example.

Instead of creating the default dirs in `getDefaultProfile` (which is a
bit odd if the symlink points elsewhere), create the profile dir for the
chosen profile in `createGeneration`. That seems more appropriate and
keeps the test added in e997512 (where
the profiles are deleted but the symlink isn't) working.
Ericson2314 added a commit to obsidiansystems/nix that referenced this pull request Aug 2, 2023
The motivation for this is basically explained in the contribution
guide, as guidance on how to design features like this going forward.

In short, I think it is confusing for operations acting on the default
profile to *always* do something different based on whether the user is
regular or root.

Instead, this makes there be flags which are (from the vantage point of
today) "do the root default" vs "do the regular user" default. This make
the situation teachable: we can point to the flags, and the conditional
default, as *exactly* what varies between the root and non-root cases.
And by manually specifying enough flags, we can ensure those defaults
are overridden and Nix will indeed do the same thing (or fail trying).

This is similar to the logic behind the supplementary group setting
(NixOS#8342), which I also discuss in this new section of the contribution
guide as a second example.

Instead of creating the default dirs in `getDefaultProfile` (which is a
bit odd if the symlink points elsewhere), create the profile dir for the
chosen profile in `createGeneration`. That seems more appropriate and
keeps the test added in e997512 (where
the profiles are deleted but the symlink isn't) working.
Ericson2314 added a commit to obsidiansystems/nix that referenced this pull request Aug 11, 2023
The motivation for this is basically explained in the contribution
guide, as guidance on how to design features like this going forward.

In short, I think it is confusing for operations acting on the default
profile to *always* do something different based on whether the user is
regular or root.

Instead, this makes there be flags which are (from the vantage point of
today) "do the root default" vs "do the regular user" default. This make
the situation teachable: we can point to the flags, and the conditional
default, as *exactly* what varies between the root and non-root cases.
And by manually specifying enough flags, we can ensure those defaults
are overridden and Nix will indeed do the same thing (or fail trying).

This is similar to the logic behind the supplementary group setting
(NixOS#8342), which I also discuss in this new section of the contribution
guide as a second example.

Instead of creating the default dirs in `getDefaultProfile` (which is a
bit odd if the symlink points elsewhere), create the profile dir for the
chosen profile in `createGeneration`. That seems more appropriate and
keeps the test added in e997512 (where
the profiles are deleted but the symlink isn't) working.
Ericson2314 added a commit to obsidiansystems/nix that referenced this pull request Aug 21, 2023
The motivation for this is basically explained in the contribution
guide, as guidance on how to design features like this going forward.

In short, I think it is confusing for operations acting on the default
profile to *always* do something different based on whether the user is
regular or root.

Instead, this makes there be flags which are (from the vantage point of
today) "do the root default" vs "do the regular user" default. This make
the situation teachable: we can point to the flags, and the conditional
default, as *exactly* what varies between the root and non-root cases.
And by manually specifying enough flags, we can ensure those defaults
are overridden and Nix will indeed do the same thing (or fail trying).

This is similar to the logic behind the supplementary group setting
(NixOS#8342), which I also discuss in this new section of the contribution
guide as a second example.

Instead of creating the default dirs in `getDefaultProfile` (which is a
bit odd if the symlink points elsewhere), create the profile dir for the
chosen profile in `createGeneration`. That seems more appropriate and
keeps the test added in e997512 (where
the profiles are deleted but the symlink isn't) working.
Ericson2314 added a commit to obsidiansystems/nix that referenced this pull request Aug 25, 2023
The motivation for this is basically explained in the contribution
guide, as guidance on how to design features like this going forward.

In short, I think it is confusing for operations acting on the default
profile to *always* do something different based on whether the user is
regular or root.

Instead, this makes there be flags which are (from the vantage point of
today) "do the root default" vs "do the regular user" default. This make
the situation teachable: we can point to the flags, and the conditional
default, as *exactly* what varies between the root and non-root cases.
And by manually specifying enough flags, we can ensure those defaults
are overridden and Nix will indeed do the same thing (or fail trying).

This is similar to the logic behind the supplementary group setting
(NixOS#8342), which I also discuss in this new section of the contribution
guide as a second example.

Instead of creating the default dirs in `getDefaultProfile` (which is a
bit odd if the symlink points elsewhere), create the profile dir for the
chosen profile in `createGeneration`. That seems more appropriate and
keeps the test added in e997512 (where
the profiles are deleted but the symlink isn't) working.
Ericson2314 added a commit to obsidiansystems/nix that referenced this pull request Aug 25, 2023
The motivation for this is basically explained in the contribution
guide, as guidance on how to design features like this going forward.

In short, I think it is confusing for operations acting on the default
profile to *always* do something different based on whether the user is
regular or root.

Instead, this makes there be flags which are (from the vantage point of
today) "do the root default" vs "do the regular user" default. This make
the situation teachable: we can point to the flags, and the conditional
default, as *exactly* what varies between the root and non-root cases.
And by manually specifying enough flags, we can ensure those defaults
are overridden and Nix will indeed do the same thing (or fail trying).

This is similar to the logic behind the supplementary group setting
(NixOS#8342), which I also discuss in this new section of the contribution
guide as a second example.

Instead of creating the default dirs in `getDefaultProfile` (which is a
bit odd if the symlink points elsewhere), create the profile dir for the
chosen profile in `createGeneration`. That seems more appropriate and
keeps the test added in e997512 (where
the profiles are deleted but the symlink isn't) working.
Ericson2314 added a commit to obsidiansystems/nix that referenced this pull request Dec 20, 2023
The motivation for this is basically explained in the contribution
guide, as guidance on how to design features like this going forward.

In short, I think it is confusing for operations acting on the default
profile to *always* do something different based on whether the user is
regular or root.

Instead, this makes there be flags which are (from the vantage point of
today) "do the root default" vs "do the regular user" default. This make
the situation teachable: we can point to the flags, and the conditional
default, as *exactly* what varies between the root and non-root cases.
And by manually specifying enough flags, we can ensure those defaults
are overridden and Nix will indeed do the same thing (or fail trying).

This is similar to the logic behind the supplementary group setting
(NixOS#8342), which I also discuss in this new section of the contribution
guide as a second example.

Instead of creating the default dirs in `getDefaultProfile` (which is a
bit odd if the symlink points elsewhere), create the profile dir for the
chosen profile in `createGeneration`. That seems more appropriate and
keeps the test added in e997512 (where
the profiles are deleted but the symlink isn't) working.
Ericson2314 added a commit to obsidiansystems/nix that referenced this pull request May 22, 2024
The motivation for this is basically explained in the contribution
guide, as guidance on how to design features like this going forward.

In short, I think it is confusing for operations acting on the default
profile to *always* do something different based on whether the user is
regular or root.

Instead, this makes there be flags which are (from the vantage point of
today) "do the root default" vs "do the regular user" default. This make
the situation teachable: we can point to the flags, and the conditional
default, as *exactly* what varies between the root and non-root cases.
And by manually specifying enough flags, we can ensure those defaults
are overridden and Nix will indeed do the same thing (or fail trying).

This is similar to the logic behind the supplementary group setting
(NixOS#8342), which I also discuss in this new section of the contribution
guide as a second example.

Instead of creating the default dirs in `getDefaultProfile` (which is a
bit odd if the symlink points elsewhere), create the profile dir for the
chosen profile in `createGeneration`. That seems more appropriate and
keeps the test added in e997512 (where
the profiles are deleted but the symlink isn't) working.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
idea approved The given proposal has been discussed and approved by the Nix team. An implementation is welcome. with-tests Issues related to testing. PRs with tests have some priority
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

7 participants