Skip to content
This repository has been archived by the owner on Oct 16, 2020. It is now read-only.

Nodes created/touched by Ignition lack the proper selinux labels #2417

Closed
cgonyeo opened this issue Apr 30, 2018 · 11 comments
Closed

Nodes created/touched by Ignition lack the proper selinux labels #2417

cgonyeo opened this issue Apr 30, 2018 · 11 comments

Comments

@cgonyeo
Copy link

cgonyeo commented Apr 30, 2018

Issue Report

Bug

Environment

All distros with selinux enabled

Expected Behavior

Filesystem nodes created by Ignition receive the correct default selinux labels for their location

Actual Behavior

Nodes created by Ignition lack a selinux label (ls -Z shows system_u:object_r:unlabeled_t:s0)

Other Information

When a node (i.e. files, dirs, and links) is created on a distro with selinux a default label is applied to the node based on the selinux policies. These selinux policies are stored on disk, and on a typical distro with selinux enabled (Fedora 27 is what I'm testing on) these policies are loaded in after the switch-root occurs. This means that any node created by Ignition lacks the proper default selinux label. One side effect of this is that when Ignition creates a user /etc/{passwd,shadow,group} become unlabeled, sssd.service fails to start as a result, and then the machine doesn't fully boot.

I asked Dan Walsh the following:

Would it make sense for Ignition to fetch the SELinux policy off of the root filesystem and load it into the initramfs systemd?

His answer was:

that involves a lot of intelligence and would have to be coordinated with the systemd team

So loading in the selinux policies in the initramfs would be a fairly involved solution to this.

Luckily Ignition knows which nodes it creates, so a far easier solution would be to call restorecon on the touched nodes once the policies have been loaded. Having Ignition create a unit like this resulted in a Fedora machine successfully booting in my testing.

This leaves the question of what creates this unit. I see two options:

  • Ignition generates this unit in the files stage. The path for restorecon could be set in the internal/distro package, and if the file exists in the root fs then Ignition will add/enable this generated unit. This approach somewhat breaks the Ignition model by being dependent on work post switch-root, but this work would happen as early as possible after that point. It should be safe to always generate this unit when restorecon exists, since having things labeled properly on systems with selinux disabled won't affect things.
  • Some tool that generates Ignition configs for Fedora/RHEL (the ct equivalent that doesn't exist yet) is responsible for generating this unit and including it in the config. This approach makes hand writing Ignition configs that don't break machines much trickier, since the config author would need to manually generate this unit.

Which option should I take?

And as a side note, I'm going to add the ability to manually set extended attributes on nodes eventually. Any node that has security.selinux set for it in the config wouldn't be included in the list of nodes to be relabeled.

@cgwalters
Copy link
Member

I find the term "node" to mean "file" to be rather confusing 😄

Policy should have already been loaded by the time ignition runs - systemd does it very early in the initramfs. I think this is probably just a matter of telling libselinux to look in /sysroot using selinux_set_policy_root().

I may be missing something.

@dustymabe
Copy link
Member

dustymabe commented Apr 30, 2018

I definitely vote for Ignition generates this unit in the files stage, but do think the possible race condition there is not ideal. Is there any possibility of an intermediate "query what the policy would be for this given file given this policy" without fully loading the selinux policy into the initramfs systemd?

@cgonyeo
Copy link
Author

cgonyeo commented Apr 30, 2018

@cgwalters it's the phrasing the code base uses to refer to a generic file/directory/link, if you're got better terminology I'd be happy to use it.

So Ignition could call selinux_set_policy_root on /sysroot? Would that work for binaries that Ignition invokes?

I hadn't seen that function before.

@ajeddeloh
Copy link

@cgwalters Ignition internally uses "node" for file-like things (e.g. dirs, regular files, links, etc) and "file" for regular files. In practice we're pretty bad at using precise langauge when discussing things.

Another issue with the systemd unit is the contents of that unit are tied to the OS and it's units. I don't particularly want an entire unit sitting in internal/distro. They're also subject to the distro changing. We don't want a unit rename breaking everything.

@cgonyeo
Copy link
Author

cgonyeo commented Apr 30, 2018

@ajeddeloh I intend for just the restorecon path sitting in internal/distro. The unit itself would be distro-independent (pending restorecon existing).

@ajeddeloh
Copy link

A unit can't really be distro independent. What if sssd.service changes name or a different distro renamed it for who-knows-why? Ignition shouldn't really care what units you have, other than that you're using systemd and have units in general. Nothing in Ignition currrently makes such assumptions of the distro it's running on and I'd prefer to keep it that way.

@cgonyeo
Copy link
Author

cgonyeo commented Apr 30, 2018

@ajeddeloh ah yeah, that's fair. I'm leaning towards the second option here anyway. If selinux_set_policy_root works for exec'd binaries though that'd probably be the cleanest solution.

@cgonyeo
Copy link
Author

cgonyeo commented May 1, 2018

I just made a patch that has Ignition call selinux_set_policy_root at the start of the files stage:
cgonyeo/ignition@0bf83f9

The function returns successfully but files created by Ignition are still unlabeled, so unless I'm missing something there I don't believe that will work for this use case.

@dustymabe
Copy link
Member

I just made a patch that has Ignition call selinux_set_policy_root at the start of the files stage:
cgonyeo/ignition@0bf83f9

The function returns successfully but files created by Ignition are still unlabeled, so unless I'm missing something there I don't believe that will work for this use case.

yeah. this is probably because we exec to run other binaries in their own process. It's possible if we stay in our own process using a go selinux library and then call the equivalent of restorecon it might work.

@jlebon
Copy link
Member

jlebon commented Jun 26, 2018

So, to summarize my findings here (though note my perspective is from getting this working on an OSTree-based system, not CL):

  • The SELinux policy is not loaded at the time ignition runs. Initramfs systemd does try to load it at the very start if we'd include /etc/selinux in the initramfs. However, including the SELinux policy in the initramfs is AFAICT not standard in e.g. RHEL and Fedora. It would also mean that'd we'd have to worry about syncing the policy in the initramfs with the (possibly modified, though see SELinux policy modifications override new policies during upgrades rpm-ostree#27) one from the real root. Yuck.
  • There is a 98selinux dracut module that adds a pre-pivot hook to directly load the policy from /sysroot. But those hooks run before ostree-prepare-root which finds the correct /sysroot. Also AFAICT, that module isn't used much; it might predate when systemd learned to do this itself post-pivot?

So the obvious thing to do is to teach ignition to load the policy. This is what this PR does:
coreos/ignition#569

It feels a bit awkward to do this in Ignition, given that this affects the whole initramfs environment. At the same time, this is right before we pivot, and systemd prompty reloads it again right after, so we're talking about a pretty thin time window. Though I'm open to doing this somewhere else (a new flag to ostree-prepare-root perhaps since that's when the correct /sysroot is finally mounted?).

With the PR above, I was able to boot RHCOS in enforcing mode without issues.

@coreosbot
Copy link

Moved to coreos/ignition#591.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants