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

linux: make sure all config options have the same value #90065

Merged
merged 2 commits into from Mar 8, 2021

Conversation

wizeman
Copy link
Member

@wizeman wizeman commented Jun 10, 2020

Motivation for this change

Currently, kernel config options whose value is yes always override
options whose value is no.

This is not always desired.

Generally speaking, if someone defines an option to have the value
no, presumably they are disabling the option for a reason, so it's
not always OK to silently enable it due to another, probably unrelated
reason.

For example, a user may want to reduce the kernel attack surface and
therefore may want to disable features that are being enabled in
common-config.nix.

In fact, common-config.nix was already silently enabling options that
were intended to be disabled in hardened/config.nix for security
reasons, such as INET_DIAG.

By eliminating the custom merge function, these config options will
now use the default module option merge functions which make sure
that all options with the highest priority have the same value.

A user that wishes to override an option defined in common-config.nix
can currently use mkForce or mkOverride to do so, e.g.:

BINFMT_MISC = mkForce (option no);

That said, this is not going to be necessary in the future, because
the plan is for kernel config options defined in nixpkgs to use a
lower priority by default, like it currently happens for other module
options.

I've also added a commit that (along with #90057, which fixes other unrelated problems) fixes the hardened kernel builds due to said conflicting definitions.

Note: this came about due to #88946 (comment) and the following comments.
I know @teto expressed his opinion that the current merge strategy is fine as long as it's documented, but I disagree for the above reasons, and would like to discuss this issue on its own.

Things done
  • Tested using sandboxing (nix.useSandbox on NixOS, or option sandbox in nix.conf on non-NixOS linux)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Determined the impact on package closure size (by running nix path-info -S before and after)
  • Ensured that relevant documentation is up to date
  • Fits CONTRIBUTING.md.

I've tested building the following kernels:

  • linux_4_4
  • linux_4_14
  • linux_4_19
  • linux_5_4
  • linux_5_6
  • linux_5_7
  • linux_hardened
  • linux_latest_hardened

cc @teto @vcunat

@teto
Copy link
Member

teto commented Jun 10, 2020

without a merge feature, it would be too easy to break kernel configs and one of my goal was to make kernel configs more composable. I believe it's of higher priority to ease enabling stuff vs disabling stuff hence the default merge favors enabling feature. I would say it is mostly a matter of documentation as it should be possible to switch the behavior quite easily (change the order to have "n" first in:

          merge = mergeAnswer [ "y" "m" "n" ];

whole common-config.nix should be a mkDefault IMO.

If you are interested, I had a roadmap here #69014

@wizeman
Copy link
Member Author

wizeman commented Jun 10, 2020

Do you have a use case where a feature is explicitly disabled somewhere, enabled somewhere else and yet you want the result to be that the feature gets enabled?

This is exactly what we don't want to happen in the use case I mentioned before (when someone wants to disable a feature for security reasons).

IMO it's better for the build to break if there are conflicting definitions inside nixpkgs so that the issue can be investigated and the appropriate result can be selected on a case-by-case basis using priorities, since in some cases we may want the result to be enabled and in other cases to be disabled.

IMO the current merge strategy of silently choosing one value when there are conflicting definitions is extremely unintuitive, has led to undesired configurations for quite a long time (in hardened kernels and also for user configs, although I understand the latter will be fixed with mkDefault) and will very likely lead to the same problem in the future.

I agree that using mkDefault in nixpkgs is better so that user configurations take priority by default.

@stale
Copy link

stale bot commented Dec 8, 2020

I marked this as stale due to inactivity. → More info

@stale stale bot added the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Dec 8, 2020
@teto
Copy link
Member

teto commented Dec 8, 2020

I would like to keep the merging functions to provide different strategies. I will write some doc about kernel configuration now that it looks easier to do so. I can try to use mkDefault as discussed instead.

@stale stale bot removed the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Dec 8, 2020
@teto teto mentioned this pull request Dec 8, 2020
10 tasks
INET_RAW_DIAG = whenAtLeast "4.14" module;
INET_DIAG_DESTROY = whenAtLeast "4.9" yes;
# Use a lower priority to allow these options to be overridden in hardened/config.nix
INET_DIAG = mkOverride 1100 module;
Copy link
Member

Choose a reason for hiding this comment

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

I'd prefer mkDefault here.

@lheckemann
Copy link
Member

@teto if multiple places with the same priority disagree on what the option should be set to, I do think it should complain and require a human to decide what should be used.

@lheckemann
Copy link
Member

lheckemann commented Dec 12, 2020

Alternatively, common-config could have mkDefault mapped over it, so the result is as if it were written as

{
  IKCONFIG = mkDefault yes;
  IKCONFIG_PROC = mkDefault yes;
  …
}

rather than mkDefault over the whole set as in mkDefault { IKCONFIG = yes; IKCONFIG_PROC = yes; } — that way only the individual settings will be overridden, rather than having a single setting completely disable common-config. I still prefer only using mkDefault for ones that we know need to be overridden elsewhere in nixpkgs though: using a different value than what nixpkgs usually would should be a conscious decision on the user's behalf.

@@ -78,6 +78,13 @@ assert (versionAtLeast version "4.9");
PROC_KCORE = no; # Exposes kernel text image layout
INET_DIAG = no; # Has been used for heap based attacks in the past

# INET_DIAG=n causes the following options to not exist anymore, but since they are defined in common-config.nix,
# make them optional
INET_DIAG_DESTROY = option no;
Copy link
Member

Choose a reason for hiding this comment

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

Would INET_DIAG_DESTROY = null unset this option?

Copy link
Member

@lheckemann lheckemann Mar 7, 2021

Choose a reason for hiding this comment

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

error: The option value `settings.INET_DIAG_DESTROY' in `structuredExtraConfig' is not of type `submodule'.

Maybe this could be made to work by adjusting the type a bit, but I don't think there's much point investing any effort into that when we can leave it as option no.

@NeQuissimus
Copy link
Member

I would suggest adding mkDefault all over common-config.nix to be honest. The hardened config should also have MODULES = n and that is going to cause all kinds of messes anyways :)

@NeQuissimus
Copy link
Member

Additionally, I would add a subtest to the test latestKernel.hardened. Even if it is a simple check again /proc/config.gz and maybe make sure the ss command fails (which should rely on INET_DIAG)

@lheckemann
Copy link
Member

I'd prefer using mkDefault only where something like the hardened config requires a different setting: that way, setting options to non-stock-NixOS values will make it extra clear to the user (unlike for completely unrelated options like hardware support flags which NixOS is simply missing) that they're contradicting the "preferred" nixpkgs way.

@NeQuissimus
Copy link
Member

I can agree with that reasoning. Sounds good to me.
What else do we need for this?

@lheckemann
Copy link
Member

  • Addressing review comments
  • Fixing merge conflicts
  • Merging :)

@wizeman are you willing to do this? If not I'll pick it up sometime soon probably.

@NeQuissimus
Copy link
Member

Sounds good, ping me when you want another review :)

@wizeman
Copy link
Member Author

wizeman commented Mar 5, 2021

@lheckemann Please, feel free to pick up. I don't think I will be able to finish this anytime soon.

Currently, kernel config options whose value is "yes" always override
options whose value is "no".

This is not always desired.

Generally speaking, if someone defines an option to have the value
"no", presumably they are disabling the option for a reason, so it's
not always OK to silently enable it due to another, probably unrelated
reason.

For example, a user may want to reduce the kernel attack surface and
therefore may want to disable features that are being enabled in
common-config.nix.

In fact, common-config.nix was already silently enabling options that
were intended to be disabled in hardened/config.nix for security
reasons, such as INET_DIAG.

By eliminating the custom merge function, these config options will
now use the default module option merge functions which make sure
that all options with the highest priority have the same value.

A user that wishes to override an option defined in common-config.nix
can currently use mkForce or mkOverride to do so, e.g.:

BINFMT_MISC = mkForce (option no);

That said, this is not going to be necessary in the future, because
the plan is for kernel config options defined in nixpkgs to use a
lower priority by default, like it currently happens for other module
options.
The parent commit forbids conflicting kernel config options.

Fix the hardened kernels by allowing options in common-config.nix to
be overridden by conflicting ones in hardened/config.nix.

I'm explicitly avoiding using a higher priority (e.g. using mkForce)
in hardened/config.nix so that the user can easily override the
options in that file.
@lheckemann
Copy link
Member

Done, @NeQuissimus what do you think?

@NeQuissimus
Copy link
Member

@ofborg test kernel-latest kernel-lts latestKernel.login kernel-latest-ath-user-regd latestKernel.hardened

@lheckemann lheckemann merged commit c762b1e into NixOS:master Mar 8, 2021
Artturin added a commit to Artturin/nixpkgs that referenced this pull request Jan 17, 2023
error: The option `settings.NIXOS_TEST_BOOLEAN.tristate' has conflicting definition values:
- In `structuredExtraConfig': "n"
- In `structuredExtraConfig': "y"

since NixOS#90065
yes does not silently win over no
@Artturin Artturin mentioned this pull request Jan 17, 2023
13 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants