Skip to content

Miscellaneous fixes for running Podman as a confined user #383

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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

gucci-on-fleek
Copy link

@gucci-on-fleek gucci-on-fleek commented Jun 20, 2025

I've been running Podman containers from SELinux-confined users on my Fedora IoT server for a few months now, but I've needed a few custom rules for it to work properly. This patch contains those rules.

There are quite a few (very small) changes here, so please let me know if you have any questions or want me to make any changes.

Full disclosure: I've been using a CIL version of these rules for a couple months now, and I've confirmed that the policy still builds (make all) and installs (semodule --install) correctly, but I haven't directly tested using the .pp module from this patch on my server.

Summary by Sourcery

Add SELinux policy updates to enable confined users to run Podman containers without custom rules

Bug Fixes:

  • Permit user domains to execute container runtime binaries and register container formats
  • Allow mounting and labeling of container-related filesystems and directories under confinement
  • Enable netlink, UNIX socket, and message queue communications for the container runtime
  • Grant container processes necessary permissions for cgroup, procfs, sysfs, and device access

Copy link

sourcery-ai bot commented Jun 20, 2025

Reviewer's Guide

This PR adds and refines SELinux policy rules in container.fc and container.te to enable unprivileged, SELinux-confined users to run Podman containers by granting necessary file contexts, namespace permissions, cgroup and netlink access, and mount rights.

File-Level Changes

Change Details Files
Grant Podman access to user runtime directories
  • Add file context for /run/user/*/podman sockets
  • Allow podman_t to read, write, and execute within user runtime dirs
container.fc
Enable unprivileged user namespace operations
  • Permit podman_t to use unprivileged clone3 and unshare syscalls
  • Add allow rules for container_user_t to create user namespaces
container.te
Allow Podman to manage cgroups and netlink
  • Grant podman_t netlink_read and netlink_write permissions
  • Allow podman_t to write to cgroup control files
container.te
Extend mount permissions for tmpfs and home directories
  • Add labeling for user tmpfs mounts under /tmp
  • Permit podman_t to mount and unmount user tmpfs and home paths
container.fc
container.te

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @gucci-on-fleek - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link

openshift-ci bot commented Jun 20, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: gucci-on-fleek, sourcery-ai[bot]
Once this PR has been reviewed and has the lgtm label, please assign wrabcak for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @gucci-on-fleek, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses several SELinux policy gaps that prevent Podman and related tools from functioning seamlessly for confined users, particularly in a Fedora IoT environment. The changes introduce specific rules to enable key functionalities such as running the Prometheus Podman exporter, executing bootc status via sudo, building container images with rpm-ostree/bootc, and ensuring proper systemd integration for socket-activated containers, all while operating under SELinux confinement. The aim is to provide a more robust and user-friendly experience for confined Podman users.

Highlights

  • SELinux Policy for Prometheus Exporter: Added a file context rule in container.fc to correctly label /usr/bin/prometheus-podman-exporter with container_runtime_exec_t, allowing it to execute with appropriate SELinux permissions.
  • Enhanced bootc and rpm-ostree Support: Introduced new SELinux rules in container.te to enable bootc status when run via sudo by confined users, and to permit rpm-ostree/bootc image building operations within containers by granting necessary filesystem and process transition permissions.
  • Improved Systemd Integration for Confined Users: Implemented policies in container.te to facilitate systemd socket activation for containers run by confined users, including permissions for TCP/UDP socket operations and allowing systemd to send signals (e.g., SIGKILL) to container processes for proper shutdown.
  • Podman Build Functionality for Confined Users: Added specific rules in container.te to allow confined users to perform podman build operations, addressing permissions related to mounting on read-only container directories and utilizing the setuid capability.
  • Suppressing Harmless SELinux Denials: Included dontaudit rules in container.te to prevent logging of known harmless SELinux AVC denials related to nnp_transition and chown attempts on FIFO files, reducing noise in audit logs.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Without this label, running "prometheus-podman-exporter" as an
SELinux-confined user results in a race condition:

- If "prometheus-podman-exporter" starts before any containers, running
  any Podman commands (even just "podman system info") gives you a
  perplexing error:

      audit[26268]: AVC avc:  denied  { create } for  pid=26268 comm="exe" name="whiteout" scontext=user_u:user_r:user_t:s0-s0:c0.c1023 tcontext=user_u:object_r:container_ro_file_t:s0 tclass=chr_file permissive=0
      prometheus-podman-exporter[26268]: 2025/06/04 22:41:47 configure storage: kernel does not support overlay fs: unable to create kernel-style whiteout: permission denied
      podman[26287]: Error: configure storage: kernel does not support overlay fs: unable to create kernel-style whiteout: permission denied

- If any containers start before "prometheus-podman-exporter", then
  everything is fine, except the "podman_container_mem_usage_bytes"
  metric is oddly missing. But as long as 1 container starts before
  "prometheus-podman-exporter", you're still able to run new containers,
  even after "prometheus-podman-exporter" has started.

Signed-off-by: Max Chernoff <[email protected]>
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces several SELinux rule changes to enhance the usability of Podman for confined users. The changes address specific scenarios like bootc status, building images within containers, systemd socket activation, and general podman build operations.

While many additions seem justified by the provided comments, there are a few areas of concern, particularly regarding the principle of least privilege and the correct use of SELinux types for objects. The most significant concern is the granting of the setuid capability to userdomain.

My review focuses on ensuring these new rules are secure, correctly implemented, and maintainable.


# Needed for "podman build" to work as a confined user
allow userdomain container_ro_file_t:dir mounton;
allow userdomain self:capability setuid;

Choose a reason for hiding this comment

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

critical

Granting the setuid capability to userdomain (allow userdomain self:capability setuid;) is a significant security concern and generally should be avoided. userdomain encompasses regular, potentially unprivileged user sessions (e.g., user_t, staff_t). CAP_SETUID allows a process to change its UID, which can lead to privilege escalation if misused.

Rootless Podman typically relies on user namespaces and setuid-root helpers like newuidmap/newgidmap (which have their own specific SELinux handling, e.g., setuid_exec_t) for UID/GID mapping, not on the user's shell or Podman client process having CAP_SETUID directly.

This permission needs extremely strong justification.

  • Is there a specific helper executed by podman build that requires this, and could it be confined to a more specific domain?
  • Can the operation be achieved using user namespaces without requiring userdomain to have this capability?

Unless there's an unavoidable, well-understood, and narrowly-scoped reason for this, this line should be removed to maintain the security posture of confined user domains.

Copy link
Author

Choose a reason for hiding this comment

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

allow userdomain self:capability setuid only allows processes with the setuid-bit set (newuidmap/newgidmap in this case) to actually call setuid; it does not allow any new processes to run as setuid. Still, I agree that this rule isn't very good, but I couldn't find another solution that works.

Copy link
Member

Choose a reason for hiding this comment

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

Are you running rootful or rootless?

Copy link
Author

Choose a reason for hiding this comment

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

Rootless, as user_u:

$ id
uid=1006(builder) gid=1006(builder) groups=1006(builder) context=user_u:user_r:user_t:s0-s0:c0.c1023

Copy link
Member

Choose a reason for hiding this comment

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

Ok so these are newuidmap and newgidmap causing the AVC, lets wrap it in a boolean.

Comment on lines +1653 to +1654
allow userdomain container_runtime_t:tcp_socket { bind create getopt listen setopt };
allow userdomain container_runtime_t:udp_socket { bind create getopt listen setopt };

Choose a reason for hiding this comment

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

high

The target type container_runtime_t in these rules (allow userdomain container_runtime_t:tcp_socket { ... }; and allow userdomain container_runtime_t:udp_socket { ... };) appears to be a misapplication of SELinux object classes. container_runtime_t is a process domain type, not a type for socket objects.

SELinux rules for object access are generally allow <source_domain> <target_object_type>:<object_class> <permissions>;.

If userdomain (e.g., systemd running as the user) is creating and binding these sockets for socket activation, the rules should be more like:
allow userdomain self:tcp_socket { bind create getopt listen setopt }; (if using its own type temporarily)
OR
allow userdomain some_specific_socket_type:tcp_socket { bind create getopt listen setopt };

And then, container_runtime_t (Podman) would need permissions to use/inherit these sockets (e.g., allow container_runtime_t some_specific_socket_type:tcp_socket { read write ... }; or allow container_runtime_t userdomain:fd use;).

As written, these rules imply userdomain is performing actions on sockets that are already associated with (e.g., created by) the container_runtime_t process, which is contrary to the typical systemd socket activation flow where systemd creates the socket first. Please clarify the intended interaction and adjust the types accordingly.

Copy link
Member

Choose a reason for hiding this comment

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

This is a very strange AVC? This looks like podman is running under a confined user domain? or the confined user transitioned to confined_user_t?

Copy link
Author

Choose a reason for hiding this comment

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

This looks like podman is running under a confined user domain?

Yes, I'm running some rootless Podman containers via systemd Quadlets as user_u.

This is a very strange AVC?

The AI comments above are mostly nonsense, but I think that what's happening (but I might be wrong) is that for socket-activated units, systemd creates the socket using the context of the target binary:

[...] Other parts of the resulting SELinux context originate from either the target binary that is effectively triggered by socket unit [...]

https://www.freedesktop.org/software/systemd/man/latest/systemd.socket.html#SELinuxContextFromNet=

which in this case, is /usr/bin/podman. But for that to work, systemd needs to be allowed to create the socket with that context. I couldn't find any way to tell systemd what context to use when it creates sockets, so this was the only way that I could figure out to make it work.

Copy link
Member

Choose a reason for hiding this comment

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

Ok lets wrap some of these in boolean.


# When shutting down, systemd will stop the container before the socket unit, so
# ignore any AVC denials from systemd trying to accept the socket
dontaudit userdomain container_runtime_t:tcp_socket accept;

Choose a reason for hiding this comment

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

high

Similar to the comment on lines 1653-1654, using container_runtime_t (a process domain type) as the target type for a tcp_socket class in a dontaudit rule is incorrect. The rule dontaudit userdomain container_runtime_t:tcp_socket accept; means you are silencing denials where userdomain attempts to accept on a TCP socket object that is somehow typed/associated with the container_runtime_t process domain.

This likely masks an underlying type enforcement issue or a misunderstanding of how the socket is typed and managed. The socket object itself should have a proper socket type. Please review the types involved in this interaction.

Comment on lines +1642 to +1643
allow sysadm_t install_t:process transition;
type_transition sysadm_t install_exec_t:process install_t;

Choose a reason for hiding this comment

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

medium

The transition to install_t for bootc status (via sudo, hence sysadm_t) might be overly permissive if bootc status is a read-only operation. The install_t domain typically has permissions for software installation and modification.

If bootc status can function with a more restricted domain, that would be preferable under the Principle of Least Privilege. However, if the bootc toolset inherently requires install_t for its operations, this might be unavoidable. Consider verifying if a more constrained type could suffice for the 'status' subcommand.

Copy link
Member

Choose a reason for hiding this comment

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

Yuck, but I am fine with allowing this.

Comment on lines +1648 to +1650
allow container_t devpts_t:filesystem mount;
allow container_t proc_t:filesystem mount;
allow container_t tmpfs_t:filesystem remount;

Choose a reason for hiding this comment

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

medium

Granting container_t (the general domain for processes inside containers) direct filesystem mount permission on devpts_t and proc_t, and filesystem remount on tmpfs_t is quite broad. While necessary for image building tools that set up new namespaces, these rules apply to any process running as container_t.

Consider if these permissions can be narrowed:

  1. Could they be gated by a tunable boolean (e.g., tunable_policy(container_allow_filesystem_mount, false)) so they are opt-in for systems that require this functionality?
  2. Are there more specific contexts or conditions (e.g., specific capabilities granted to the container) under which these should be allowed?

While user namespaces in rootless containers mitigate some host-level risks, these broad permissions for container_t should be carefully evaluated.

Copy link
Member

Choose a reason for hiding this comment

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

These look fine to me. the first one should definitely be allowed. We should allow watch access for all container file types.

Copy link
Author

Choose a reason for hiding this comment

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

We should allow watch access for all container file types.

Watch access already seems to be allowed for container_file_t, but I can change the rule to use container_file_type (which is just container_ro_file_t and container_file_t) instead if you prefer.

Copy link

Ephemeral COPR build failed. @containers/packit-build please check.

1 similar comment
Copy link

Ephemeral COPR build failed. @containers/packit-build please check.

@@ -48,6 +48,7 @@
/usr/s?bin/crio.* -- gen_context(system_u:object_r:container_runtime_exec_t,s0)
/usr/local/s?bin/crio.* -- gen_context(system_u:object_r:container_runtime_exec_t,s0)
/usr/s?bin/ocid.* -- gen_context(system_u:object_r:container_runtime_exec_t,s0)
/usr/bin/prometheus-podman-exporter -- gen_context(system_u:object_r:container_runtime_exec_t,s0)
Copy link
Member

Choose a reason for hiding this comment

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

Container_runtime_t is a very permissive (unconfined) domain, does this tool basically run podman?

Copy link
Author

@gucci-on-fleek gucci-on-fleek Jul 3, 2025

Choose a reason for hiding this comment

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

does this tool basically run podman?

/usr/bin/prometheus-podman-exporter is this tool, which is essentially a network-facing wrapper around podman ps and podman stats.

Container_runtime_t is a very permissive (unconfined) domain

I can test labelling it with a different domain, do you have any suggestions? This one was giving me bizarre errors (see the commit message for “Label prometheus-podman-exporter as container_runtime_exec_t”), so I have no idea which domains to try.

Copy link
Member

Choose a reason for hiding this comment

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

What avc's are generated by leaving it bin_t?

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

Successfully merging this pull request may close these issues.

2 participants