Skip to content
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

libcontainer: workaround for empty key label bug in RHEL7 #2070

Closed
wants to merge 1 commit into from

Conversation

kolyshkin
Copy link
Contributor

On a freshly installed CentOS 7 system (kernel 3.10.0-957.12.2.el7.x86_64)
with SELinux enabled, the kernel does not allow to write an empty label
to the keycreate file. Here's an strace except from containerd:

20396 openat(AT_FDCWD, "/proc/self/attr/keycreate", O_WRONLY|O_CLOEXEC) = 7
...
20396 write(7, "", 0) = -1 EACCES (Permission denied)

NOTE: upgrading or downgrading container-selinux makes this to go
away, so in order to reproduce you need a freshly booted system.

Here is a reproducer in C:

[root@kir-ce7-selinux-01 ~]# cat a.c
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <stdio.h>

int main(void) {
    int fd, r;

    fd = open("/proc/self/attr/keycreate", O_WRONLY);
    if (fd < 0) {
	    perror("open");
    }

    r = write(fd, "", 0);
    if (r < 0) {
	    perror("write");
    }

    return 0;
}

[root@kir-ce7-selinux-01 ~]# uname -a
Linux kir-ce7-selinux-01 3.10.0-957.12.2.el7.x86_64 #1 SMP Tue May 14 21:24:32 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

[root@kir-ce7-selinux-01 ~]# gcc -Wall -O2 -o a a.c

[root@kir-ce7-selinux-01 ~]# ./a
write: Permission denied
[root@kir-ce7-selinux-01 ~]# strace ./a
...
open("/proc/self/attr/keycreate", O_WRONLY) = 3
write(3, "", 0)                         = -1 EACCES (Permission denied)
...

So, this is presumably a kernel bug, but since there is no update
available for this kernel, we have to have this workaround here.

This fixes non-working docker/containerd/runc on CentOS 7 (and,
presumably, RHEL 7, too).

Signed-off-by: Kir Kolyshkin kolyshkin@gmail.com

On a freshly installed CentOS 7 system (kernel 3.10.0-957.12.2.el7.x86_64)
with SELinux enabled, the kernel does not allow to write an empty label
to the keycreate file. Here's an strace except from containerd:

> 20396 openat(AT_FDCWD, "/proc/self/attr/keycreate", O_WRONLY|O_CLOEXEC) = 7
> ...
> 20396 write(7, "", 0)                   = -1 EACCES (Permission denied)

NOTE: upgrading or downgrading container-selinux makes this to go
away, so in order to reproduce you need a freshly booted system.

Here is a reproducer in C:

```
[root@kir-ce7-selinux-01 ~]# cat a.c
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <stdio.h>

int main(void) {
    int fd, r;

    fd = open("/proc/self/attr/keycreate", O_WRONLY);
    if (fd < 0) {
	    perror("open");
    }

    r = write(fd, "", 0);
    if (r < 0) {
	    perror("write");
    }

    return 0;
}

[root@kir-ce7-selinux-01 ~]# uname -a
Linux kir-ce7-selinux-01 3.10.0-957.12.2.el7.x86_64 #1 SMP Tue May 14 21:24:32 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

[root@kir-ce7-selinux-01 ~]# gcc -Wall -O2 -o a a.c

[root@kir-ce7-selinux-01 ~]# ./a
write: Permission denied
[root@kir-ce7-selinux-01 ~]# strace ./a
...
open("/proc/self/attr/keycreate", O_WRONLY) = 3
write(3, "", 0)                         = -1 EACCES (Permission denied)
...
```

So, this is presumably a kernel bug, but since there is no update
available for this kernel, we have to have this workaround here.

This fixes non-working docker/containerd/runc on CentOS 7 (and,
presumably, RHEL 7, too).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
@kolyshkin
Copy link
Contributor Author

This is an alternative to #2033 in case opencontainers/selinux#56 won't be accepted.

@cyphar
Copy link
Member

cyphar commented Jun 10, 2019

/cc @rhatdan

@@ -35,7 +35,10 @@ func (l *linuxSetnsInit) Init() error {

if !l.config.Config.NoNewKeyring {
if err := label.SetKeyLabel(l.config.ProcessLabel); err != nil {
return err
// workaround for RHEL7 kernel which may return EACCES for an empty label
if !(l.config.ProcessLabel == "" && os.IsPermission(err)) {
Copy link
Member

Choose a reason for hiding this comment

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

I think if l.config.ProcessLabel != "" || !os.IsPermission(err) reads nicer.

Copy link
Contributor Author

@kolyshkin kolyshkin Jun 11, 2019

Choose a reason for hiding this comment

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

To me your version is less readable (despite looking better and being equally correct). I read mine as "ignore the error unless label is empty and error is permission".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@cyphar but I can certainly change it, please let me know

Copy link
Member

Choose a reason for hiding this comment

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

I don't really mind either way. I read mine as "this is an error if the label is not empty, or the error is not a permission-related one" but either works.

@kolyshkin
Copy link
Contributor Author

Just checked that this helps to avoid the issue. Still see the AVC but it no longer affects the operation.

[root@kir-centos-selinux-3 ~]# cp /usr/sbin/runc /usr/sbin/runc-orig
[root@kir-centos-selinux-3 ~]# cp /usr/sbin/runc-my /usr/sbin/runc
cp: overwrite ‘/usr/sbin/runc’? y

[root@kir-centos-selinux-3 ~]# docker run hello-world

Hello from Docker!
....

[root@kir-centos-selinux-3 ~]# runc-orig --version
runc version 1.0.0-rc8
commit: 425e105d5a03fabd737a126ad93d62a9eeede87f
spec: 1.0.1-dev

[root@kir-centos-selinux-3 ~]# runc-my --version
runc version 1.0.0-rc8+dev
commit: 1509446a7ff844302641c9fa871ddcc3eac6d38e
spec: 1.0.1-dev

[root@kir-centos-selinux-3 ~]# ausearch -m avc -ts recent
----
time->Tue Jun 11 02:35:25 2019
type=PROCTITLE msg=audit(1560220525.865:173): proctitle=72756E6300696E6974
type=SYSCALL msg=audit(1560220525.865:173): arch=c000003e syscall=1 success=no exit=-13 a0=7 a1=557e9544f158 a2=0 a3=0 items=0 ppid=11486 pid=11495 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="runc:[2:INIT]" exe="/" subj=system_u:system_r:unconfined_service_t:s0 key=(null)
type=AVC msg=audit(1560220525.865:173): avc:  denied  { create } for  pid=11495 comm="runc:[2:INIT]" scontext=system_u:system_r:unconfined_service_t:s0 tcontext=system_u:object_r:unlabeled_t:s0 tclass=key permissive=0
----
time->Tue Jun 11 02:35:52 2019
type=PROCTITLE msg=audit(1560220552.918:177): proctitle=72756E6300696E6974
type=SYSCALL msg=audit(1560220552.918:177): arch=c000003e syscall=1 success=no exit=-13 a0=6 a1=55855645e638 a2=0 a3=0 items=0 ppid=11538 pid=11547 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="runc:[2:INIT]" exe="/" subj=system_u:system_r:unconfined_service_t:s0 key=(null)
type=AVC msg=audit(1560220552.918:177): avc:  denied  { create } for  pid=11547 comm="runc:[2:INIT]" scontext=system_u:system_r:unconfined_service_t:s0 tcontext=system_u:object_r:unlabeled_t:s0 tclass=key permissive=0

@crosbymichael
Copy link
Member

crosbymichael commented Jun 11, 2019

LGTM

Approved with PullApprove

@crosbymichael
Copy link
Member

ping @cyphar can you review this one again. I looked into this and I think its good to handle this at the runc level and let the selinux pkg just pass through errors.

@crosbymichael
Copy link
Member

cc @opencontainers/runc-maintainers

Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

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

LGTM (not a maintainer)

@crosbymichael
Copy link
Member

ping @mrunalp @cyphar

@rhatdan
Copy link
Contributor

rhatdan commented Jun 11, 2019

Again you are ignoring a legitimate denial of permissions, that could become serious in the future. The issue is to fix the SElinux policy not to ignore Permission Denied.
A process is attempting to disable the default labelling. If you update container-selinux then the denial goes away and the process is able to reset the SELinux label to the default settings.

@rhatdan
Copy link
Contributor

rhatdan commented Jun 11, 2019

If you want to allow this for now, you can simply

# grep container_t /var/log/audit/audit.log | audit2allow -M mycontainer
# semodule -i mycontainer.pp

This will allow the domain to set the key label.

Is runc running in an init script or is it started by Docker/Containerd. If the later then Docker/Containerd is labeled incorrectly.

ls -lZ /usr/bin/docker* /usr/bin/containerd* /usr/bin/runc*

@crosbymichael
Copy link
Member

@rhatdan on package install, should restorecon be called in the rpc scripts post install?

@kolyshkin
Copy link
Contributor Author

OK the reason for this was that

  1. our containerd.io did not require container-selinux. Easy to fix.
  2. container-selinux rpm %post script calls restorecon ... /usr/bin/runc while we install it to /usr/sbin and so it is not labeled after container-selinux is installed.

@rhatdan
Copy link
Contributor

rhatdan commented Jun 12, 2019

It is better to do a Recommends then a Requires, since some people might install contained.io inside of a container, and you probably don't want to pull selinux-policy into a container.

@kolyshkin
Copy link
Contributor Author

It is better to do a Recommends then a Requires, since some people might install contained.io inside of a container, and you probably don't want to pull selinux-policy into a container.

Alas, RHEL7 has rpm-4.11 which does not understand Recommends: (which appeared in rpm-4.12 and allegedly not backported to RHEL7).

@rhatdan
Copy link
Contributor

rhatdan commented Jun 12, 2019

Sorry I did not realize this was for RHEL7, you are correct.

@rhatdan
Copy link
Contributor

rhatdan commented Jun 12, 2019

BTW @kolyshkin The SELinux labeling issue with KeyCreate turns out to be a thirteen year old bug in the kernel. Which just got merged into the SELinux kernel, and should be moving it's way into the upstream kernel, and eventually possibly back into RHEL7.

@kolyshkin kolyshkin deleted the empty-key branch April 21, 2020 08:50
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.

None yet

5 participants