Unmounting inside a container

We do RPM things. Some of those RPM things need the /proc file system. Not forever, but for a short while. So we mount /proc, do something, and unmount. Which works fine.

Until we tried to do it in a container.

When we ran our umount code in the container, we got the following error:

umount: /meta/meta-rpm/build/tmp/work/qemux86_64-redhat-linux/rpmbased-minimal-image/1.0-r0/rootfs/.proc: block devices are not permitted on filesystem.

SELinux. Running in permissive mode worked fine. In /var/log/messages We have the following message:

May 5 15:22:41 zygarde setroubleshoot[1733179]: SELinux is preventing /meta/meta-rpm/build/tmp/work/qemux86_64-redhat-linux/rpmbased-minimal-image/1.0-r0/recipe-sysroot-native/usr/bin/umount from unmount access on the filesystem .#012#012 Plugin catchall (100. confidence) suggests *******#012#012If you believe that umount should be allowed unmount access on the filesystem by default.#012Then you should report this as a bug.#012You can generate a local policy module to allow this access.#012Do#012allow this access for now by executing:#012# ausearch -c ‘umount’ –raw | audit2allow -M my-umount#012# semodule -X 300 -i my-umount.pp

It seems somewhat unbalanced that a container can mount a filesystem, but not unmount one.

As the messages said, we can get by it by building and running a custom policy:

ausearch -c 'umount' --raw | audit2allow -M my-umount
semodule -X 300 -i my-umount.pp

Its overkill, but you can never have too much overkill.

Actually, yes you can. When your goal is to not violate security constraints, opening up a hole is counterproductive.

When we run a container, by default, it gets the labeled as container_runtime_t:

unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 ayoung 1736123 1609658  0 18:04 pts/1 00:00:00 grep --color=auto metarpm

To change the label, run with a different security context. For instancing running podman with –security-opt label=type:metarpm.process like this:

 podman run   -it   --security-opt label=type:metarpm.process  -v /dev/fuse:/dev/fuse         -v metadata:/meta localhost/metarpm  /usr/bin/bash

Gives ends up with a process labeled system_u:system_r:metarpm_policy.process like this:

system_u:system_r:metarpm_policy.process:s0:c738,c1010 100999 1736385 1736373  0 18:08 pts/0 00:00:00 /usr/bin/bash

So long as this matches policy, we can do new things. But if we don’t ,we can’t do anything. But writing SELinux policy is a non-trivial amount of learning curve. How can we simplify?

Udica. Pronounced you-DI-tza. Or something like that.

Now…I’m going to cut out some of my trial and error with Udica. Following the instructions alone did not solve my problem, mainly because Udica does not yet understand how to deal with the umount or ioctl erros caused by the container. Here is what worked

  • set SELinux in permissive mode, so the operations succeeds, but the errors get caught in the audit log
  • as a non-root user,
    • start the container and run the bitbake function to generate the errors
    • run the podman ps command to get the container id
    • redirect the output a file
    • stop the container
  • as root
    • re-enable SELinux
    • cat the output of the file generated above into udica, add the flag to read the audit file
    • load the generated policy

Here is what that looks like on the terminal. As root

setenforce permissive

As ayoung

$ podman run   -it      --security-opt seccomp=unconfined -v /dev/fuse:/dev/fuse         -v metadata:/meta localhost/metarpm  /usr/bin/bash
$ cd /meta/meta-rpm/
$ . ./oe-init-build-env
$ bitbake rpmbased-minimal-image

Leave that running, and go to another terminal as ayoung

$ podman ps
CONTAINER ID  IMAGE              COMMAND        CREATED             STATUS                 PORTS   NAMES
c153bee4a84d  localhost/metarpm  /usr/bin/bash  About a minute ago  Up About a minute ago          naughty_heyrovsky
$ podman inspect c153bee4a84d > container.json
<!-- /wp:html -->
<!-- wp:paragraph -->
<p>Now as <strong>root</strong></p>
<!-- /wp:paragraph -->
<!-- wp:html -->
<pre lang="bash">
$ cat container.json | udica metarpm  --append-rules /var/log/audit/audit.log
$ setenforce enforcing
$ semodule -i metarpm.cil /usr/share/udica/templates/base_container.cil
$ semodule -l | grep meta

As the ayoung user, rerun the container with the additional flag

$ podman run   -it    --security-opt label=type:metarpm.process   --security-opt seccomp=unconfined -v /dev/fuse:/dev/fuse         -v metadata:/meta localhost/metarpm  /usr/bin/bash

If you look in the process list, you can see the container running:

$ ps -efZ | grep meta
unconfined_u:system_r:container_runtime_t:s0-s0:c0.c1023 ayoung 1977102 1609151  0 13:25 pts/0 00:00:00 podman run -it --security-opt label=type:meth
unconfined_u:system_r:container_runtime_t:s0-s0:c0.c1023 ayoung 1977115 1977102  0 13:25 pts/0 00:00:00 podman run -it --security-opt label=type:meth
system_u:system_r:metarpm.process:s0:c492,c842 100999 1977157 1977145  0 13:25 pts/0 00:00:00 /usr/bin/bash
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 ayoung 1977217 1939598  0 13:26 pts/1 00:00:00 grep --color=auto meta

If I rerun the bitbake command now (after cleaning the output of the successful permissive run) it will succeed.

Here is the difference between the default output of udica and adding in the flag that pulls in the audit file:

# diff metarpm.cil.orig metarpm.cil
>     (allow process proc_t ( file ( ioctl ))) 
>     (allow process proc_t ( filesystem ( unmount )))

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.