Skip to content

v1.16.11: selinux is an unconditional dependency, breaking source builds on distros that don't package libselinux #2431

Closed

Description

@Danathar

Note: Used a bit of AI to help with the issue. Glad to respond if you need more info.

Building bootc from source with make bin install-all regressed in v1.16.11 on distributions that do not ship libselinux development headers. v1.16.10 builds fine.

Cause

v1.16.11 added selinux to the workspace and consumes it unconditionally:

  • Cargo.toml:76 ([workspace.dependencies]) — selinux = "=0.5.0". Not present in v1.16.10.
  • crates/lib/Cargo.toml:54 — selinux = { workspace = true }, with no optional = true and no feature gate.

So every build of crates/lib now requires libselinux at link time, whether or not the target system has SELinux.

Failure

error: failed to run custom build command for `selinux-sys v0.6.15`

  selinux-sys: Failed to find 'selinux/selinux.h'. Please make sure the C header
  files of libselinux are installed and accessible: Kind(NotFound)

make: *** [Makefile:44: manpages] Error 1

It surfaces in the manpages target because that is the first thing to build the lib, but make bin fails the same way.

Why this is hard to work around downstream

Arch Linux packages neither libselinux nor libsepol in its official repositories, so there is no package to install:

$ curl -s 'https://archlinux.org/packages/search/json/?name=libselinux' | jq .count
0
$ curl -s 'https://archlinux.org/packages/search/json/?name=libsepol' | jq .count
0

That leaves adding a third-party repository, or building both libraries from source, purely to satisfy a link-time dependency on a system where SELinux is never enabled.

Worth noting this arrived in a patch release, so it reached anyone auto-updating within the 1.16 range.

Suggested fix

Gate it behind a cargo feature. crates/lib already uses this pattern for install-to-disk, rhsm and docgen:

# crates/lib/Cargo.toml
selinux = { workspace = true, optional = true }

[features]
default = ["install-to-disk", "selinux"]
selinux = ["dep:selinux"]

That keeps current behaviour for everyone by default and lets non-SELinux distros opt out. If the SELinux call sites are not easily made conditional, even a documented statement that libselinux is now a hard build requirement would help downstreams decide what to do.

Environment

bootc v1.16.11, built from source in an archlinux:latest container, rust from the Arch repositories. Context is an Arch-based bootc image; happy to test a patch.

Activity

  1. cgwalters commented on Sep 3, 2026

    @cgwalters
    Collaborator

    Yes sorry, we can make selinux a build-time option.

  2. Danathar commented on Sep 4, 2026

    @Danathar
    Author

    Yes sorry, we can make selinux a build-time option.

    No prob. I'm probably one of a grand total of 10 people using bootc on arch LOL (just as an experiment really, but it works!)

    Thank you!

  3. smiggiddy commented on Sep 4, 2026

    @smiggiddy

    Yes sorry, we can make selinux a build-time option.

    No prob. I'm probably one of a grand total of 10 people using bootc on arch LOL (just as an experiment really, but it works!)

    Thank you!

    ironically, yesterday I decided to try arch and bootc

    I had DeepSeek write a patch for now

    diff --git i/crates/lib/Cargo.toml w/crates/lib/Cargo.toml
    index 87ed118..6b1a317 100644
    --- i/crates/lib/Cargo.toml
    +++ w/crates/lib/Cargo.toml
    @@ -51,7 +51,7 @@ regex = { workspace = true }
     rustix = { workspace = true }
     serde = { workspace = true, features = ["derive"] }
     serde_json = { workspace = true }
    -selinux = { workspace = true }
    +selinux = { workspace = true, optional = true }
     tempfile = { workspace = true }
     thiserror = { workspace = true }
     tokio = { workspace = true, features = ["io-std", "time", "process", "rt", "net"] }
    @@ -90,6 +90,8 @@ install-to-disk = []
     # This featuares enables `bootc internals publish-rhsm-facts` to integrate with
     # Red Hat Subscription Manager
     rhsm = []
    +# Make SELinux support optional; disable on distros without libselinux (e.g. Arch).
    +selinux = ["dep:selinux"]
     # Implementation detail of man page generation.
     docgen = ["clap_mangen"]
    
    diff --git i/crates/lib/src/lsm.rs w/crates/lib/src/lsm.rs
    index 4d629b2..6670d79 100644
    --- i/crates/lib/src/lsm.rs
    +++ w/crates/lib/src/lsm.rs
    @@ -25,9 +25,11 @@ const SELINUXFS: &str = "/sys/fs/selinux";
     /// The SELinux xattr
     const SELINUX_XATTR: &[u8] = b"security.selinux\0";
     /// The kernel initial SID used for objects without a label.
    +#[cfg(feature = "selinux")]
     const SELINUX_INITIAL_SID_UNLABELED: &str = "unlabeled";
     const SELF_CURRENT: &str = "/proc/self/attr/current";
    
    +#[cfg(feature = "selinux")]
     fn unlabeled_type() -> Result<CString> {
         let context =
             selinux::SecurityContext::of_initial_kernel_context(SELINUX_INITIAL_SID_UNLABELED, true)
    @@ -35,6 +37,11 @@ fn unlabeled_type() -> Result<CString> {
         context_type(context.as_bytes())
     }
    
    +#[cfg(not(feature = "selinux"))]
    +fn unlabeled_type() -> Result<CString> {
    +    anyhow::bail!("SELinux support is not compiled in")
    +}
    +
     #[context("Querying selinux availability")]
     pub(crate) fn selinux_enabled() -> Result<bool> {
         Path::new("/proc/1/root/sys/fs/selinux/enforce")
    @@ -267,6 +274,7 @@ pub(crate) enum SELinuxLabelState {
         Labeled,
     }
    
    +#[cfg(feature = "selinux")]
     fn context_type(context: &[u8]) -> Result<CString> {
         // security.selinux xattrs may include a trailing NUL terminator.
         let context = context.strip_suffix(b"\0").unwrap_or(context);
    @@ -280,6 +288,11 @@ fn context_type(context: &[u8]) -> Result<CString> {
             .context("Reading SELinux context type")
     }
    
    +#[cfg(not(feature = "selinux"))]
    +fn context_type(_context: &[u8]) -> Result<CString> {
    +    anyhow::bail!("SELinux support is not compiled in")
    +}
    +
     /// Query the SELinux labeling for a particular path
     pub(crate) fn has_security_selinux(root: &Dir, path: &Utf8Path) -> Result<SELinuxLabelState> {
         let unlabeled_type = unlabeled_type()?;
    @@ -619,6 +632,7 @@ mod tests {
             assert!(xattrs_have_selinux(&Variant::from(found)));
         }
    
    +    #[cfg(feature = "selinux")]
         #[test]
         fn test_context_type() {
             let cases: &[(&[u8], Option<&str>)] = &[
    
  4. cgwalters commented on Sep 4, 2026

    @cgwalters
    Collaborator

    This intersects with pending PR #2290 - if we make the feature off by default, it will need changes for the OSes that do use selinux.

    For this reason for now I would like to conservatively default it to on, i.e. disabling it would require --no-default-features.

  5. Danathar commented on Sep 4, 2026

    @Danathar
    Author

    This intersects with pending PR #2290 - if we make the feature off by default, it will need changes for the OSes that do use selinux.

    For this reason for now I would like to conservatively default it to on, i.e. disabling it would require --no-default-features.

    Sounds reasonable. Wouldn't want to break my other fedora atomic systems I run.

  6. moved this from Todo to In Progress in Workstreamon Sep 23, 2026
  7. moved this from In Progress to In Review in Workstreamon Sep 23, 2026
  8. 2 remaining items

  9. added 2 commits that reference this issue on Sep 24, 2026
    af0f50d
    5c1a1ce
  10. added a commit that references this issue on Sep 24, 2026
    a3a92ab
  11. added 2 commits that reference this issue on Sep 25, 2026
    e8b5618
    199da5b
  12. added 5 commits that reference this issue on Sep 25, 2026
    32979aa
    6f513e2
    4f37dfe
    753907b
    a659f93
  13. moved this to In Review in Workstreamon Sep 30, 2026
  14. added a commit that references this issue on Sep 30, 2026
    43042ec
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    triagedThis issue appears to be valid

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions