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
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions container.fc
Original file line number Diff line number Diff line change
Expand Up @@ -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?

/usr/lib/docker/docker-novolume-plugin -- gen_context(system_u:object_r:container_auth_exec_t,s0)
/usr/lib/docker/[^/]*plugin -- gen_context(system_u:object_r:container_runtime_exec_t,s0)
/usr/local/lib/docker/[^/]*plugin -- gen_context(system_u:object_r:container_runtime_exec_t,s0)
Expand Down
40 changes: 40 additions & 0 deletions container.te
Original file line number Diff line number Diff line change
Expand Up @@ -1631,3 +1631,43 @@ tunable_policy(`deny_ptrace',`',`
# netavark needs to write to /run/sysctl.d and needs the right label for systemd to read it.
# https://issues.redhat.com/browse/RHEL-91380
files_pid_filetrans(container_runtime_t, system_conf_t, dir, "sysctl.d")

# Needed for "bootc status" to work (via sudo) as a confined user.
gen_require(`
attribute_role install_roles;
type sysadm_t;
')

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

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.


# Needed to be able to build an rpm-ostree/bootc image, inside of a container
# ran by a confined user.
allow container_t container_ro_file_t:dir watch;
allow container_t devpts_t:filesystem mount;
allow container_t proc_t:filesystem mount;
allow container_t tmpfs_t:filesystem remount;
Comment on lines +1648 to +1650

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.


# Needed to allow systemd socket activation of containers ran by confined users
allow userdomain container_runtime_t:tcp_socket { bind create getopt listen setopt };
allow userdomain container_runtime_t:udp_socket { bind create getopt listen setopt };
Comment on lines +1653 to +1654

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.


# Allow systemd to kill containers (needed for when stopping a Quadlet service
# times out)
allow userdomain container_runtime_t:process { sigkill signal signull };
allow userdomain container_t:process { sigkill signal signull };

# 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.


# Harmless AVC denial
dontaudit container_runtime_t self:process2 nnp_transition;

# Ignore containers trying to chown stdin/stdout/stderr
dontaudit container_t container_runtime_t:fifo_file setattr;