containers / udica

This repository contains a tool for generating SELinux security profiles for containers
GNU General Public License v3.0
478 stars 47 forks source link

Su not working in container with udica generated policy #69

Open jpf91 opened 4 years ago

jpf91 commented 4 years ago

Describe the bug When a container is run in a udica generated policy, su command does not work.

To Reproduce Steps to reproduce the behavior:

  1. Install this rule generated by udica:

    (block container-sabnzbd
    (blockinherit container)
    (blockinherit net_container)
    (blockinherit restricted_net_container)
    (allow process process ( capability ( audit_write chown dac_override fowner fsetid kill mknod net_bind_service net_raw setfcap setgid setpcap setuid sys_chroot ))) 
    
    (allow process unreserved_port_t ( tcp_socket (  name_bind ))) 
    (allow process container_file_t ( dir ( add_name create getattr ioctl lock open read remove_name rmdir search setattr write ))) 
    (allow process container_file_t ( file ( append create getattr ioctl lock map open read rename setattr unlink write ))) 
    (allow process container_file_t ( sock_file ( append getattr open read write ))) 
    (allow process container_file_t ( dir ( add_name create getattr ioctl lock open read remove_name rmdir search setattr write ))) 
    (allow process container_file_t ( file ( append create getattr ioctl lock map open read rename setattr unlink write ))) 
    (allow process container_file_t ( sock_file ( append getattr open read write ))) 
    (allow process public_content_rw_t ( dir ( add_name create getattr ioctl lock open read remove_name rmdir search setattr write ))) 
    (allow process public_content_rw_t ( file ( append create getattr ioctl lock map open read rename setattr unlink write ))) 
    (allow process public_content_rw_t ( sock_file ( append getattr open read write ))) 
    )
  2. podman run --security-opt label=type:container-sabnzbd.process -it debian:buster /bin/sh
  3. su => su: System error

Expected behavior Su should work as expected, like when not specifying -security-opt label=type:container-sabnzbd.process.

Solution

Udica seems to need the (allow process process ( netlink_audit_socket ( nlmsg_read nlmsg_relay nlmsg_tty_audit ))) rule of container-selinux. Adding this rule fixes the problem, I'm not sure though whether it's possible to auto-detect when it is required.

wrabcak commented 4 years ago

Hi @jpf91 , Thank you for report.

You're correct that udica cannot detect what commands you execute inside the container, so this use-case cannot be automated. Can you please also share the whole usecase? Running su inside the container, I'm not sure if it make sense to confine container then.

Thanks, Lukas.

jpf91 commented 4 years ago

Hi Lukas, thanks for the response. I'll elaborate a bit on the usecase:

I wanted to test the "run services in containers" approach to run a sabnzbd container. Sabnzbd seemed to be a good test, as there's also no fedora package for it. Sabnzbd is essentially a data download program and in order to get a volume to store downloads into the container, I have to label it as container_file_t. At the same time, I want this data folder to be shared by samba, nginx and similar protocols, so I'd have to label it public_content_rw_t. But as it's not possible to have two labels for one folder, I'll have to either give nginx, samba and more services access to container_rw_t (which seems wrong) or give one specific container access to public_content_rw_t. (So this is a problem which only appears with containerized services and complicates the "services in containers" approach). I guess the best solution would be to define a new label container_download_t or something, then add rules for samba, nginx and the container, but that seemed even more complicated to me.

So too summarize: The use case is moving services into containers(*). But the default container policy is too restrictive, so I need udica to relax the constrains of the container, not to confine them. Unfortunately, the "relax policy" approach does not work, as the base policy in udica is more restrictive than the default podman container policy, in this case breaking su.

(*) The container image on docker hub was originally written for docker, so it uses su to run commands as non-root. With rootless podman, there's no need to do this and I've opened a bug report for that image to support running as root in the container. But still, it would be nice to be able to run any existing images and give it access to non container_file_t directories.

wrabcak commented 4 years ago

Hi @jpf91 ,

I see however I don't think that using su - in container makes any sense in production env. Therefore I don't see reason to allow it for default container. Maybe we can create some udica template for it, but I don't know if we want to support it.

@rhatdan what do you think?

rhatdan commented 4 years ago

What AVCs are you seeing? Is this because udica removes capabiltiies, IE setuid?

guystreeter commented 3 years ago

This is easy to recreate. This works as expected:

$ podman run -it --rm --name try fedora:latest /bin/bash
[root@e89a491c1656 /]# useradd try
[root@e89a491c1656 /]# su try
[try@e89a491c1656 /]$ id
uid=1000(try) gid=1000(try) groups=1000(try)
[try@e89a491c1656 /]$ 

But while that container is running, use udica to create a policy for it and install the policy. Now run again like this:

$ podman run -it --rm --name try --security-opt label=type:try.process fedora:latest /bin/bash
[root@09b36c29717a /]# useradd try
[root@09b36c29717a /]# su try
su: System error
[root@09b36c29717a /]# 

There are no AVC messages generated.

The official docker image for Nextcloud fails with this su system error if a udica policy is used. Based on some internet searching, I tried adding audit_write to the process capabilities, but it made no difference.

In case you can't tell by the shell prompts, I did this rootless.

vmojzis commented 2 years ago

Thank you for reporting the issue. My testing shows 2 AVCs (normally hidden by dontaudit rules): type=AVC msg=audit(1651596238.754:11870): avc: denied { nlmsg_relay } for pid=118556 comm="su" scontext=system_u:systemr:su.process:s0:c298,c653 tcontext=system_u:systemr:su.process:s0:c298,c653 tclass=netlink_audit_socket permissive=1 type=AVC msg=audit(1651596238.754:11871): avc: denied { search } for pid=118556 comm="su" scontext=system_u:systemr:su.process:s0:c298,c653 tcontext=system_u:system_r:container_t:s0:c554,c736 tclass=key permissive=1

Udica policy with the following additional rules worked properly in enforcing: (allow process su_.process ( netlink_audit_socket ( nlmsg_relay ))) (allow process container_t ( key ( search )))

I could add a new template with the rules, but it is easy to work around using udica --append-rules (the AVCs can only be captured after semodule -DB, which disables dontaudit rules) and using su doesn't seem like a common use case.