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

Seal /proc/self/exe to protect against CVE-2019-5736 #343

Merged
merged 1 commit into from
Sep 30, 2021
Merged

Seal /proc/self/exe to protect against CVE-2019-5736 #343

merged 1 commit into from
Sep 30, 2021

Conversation

oblique
Copy link
Contributor

@oblique oblique commented Sep 28, 2021

youki is vulnerable to CVE-2019-5736, this can be fixed by sealing /proc/self/exe.
pentacle crate implements the same technique that runc implemented to fix this vulnerability.

For more information about the vulnerability check the following links:

Some PoCs:

@yihuaf
Copy link
Collaborator

yihuaf commented Sep 28, 2021

First of all, thank you for bring this to our attention. Can I ask you to demonstrate that Youki has the same issue? I asked because from the reading, runc has this issue becauserunc executes /proc/self/exec to mimic the effect of fork, which we don't do here in Youki. In fact, we do not execute or touch /proc/self/exec at all. So my question is does this CVE still apply here?

@oblique
Copy link
Contributor Author

oblique commented Sep 29, 2021

The vulnerability is that you can modify the entrypoint file, which can be the actual youki executable. From there you can infect youki executable and when the host machine executes it again (for example by creating a new container) it will run the malicious code on the host machine.

Yesterday, I tested the first PoC, but I needed some modification to make it work. I will give you step-by-step demonstration the following days.

@yihuaf
Copy link
Collaborator

yihuaf commented Sep 29, 2021

The vulnerability is that you can modify the entrypoint file, which can be the actual youki executable. From there you can infect youki executable and when the host machine executes it again (for example by creating a new container) it will run the malicious code on the host machine.

Yesterday, I tested the first PoC, but I needed some modification to make it work. I will give you step-by-step demonstration the following days.

Great. I tried the first PoC mentioned and I got:

yihuaf@yihuaf-dev:~/private/youki$ strings ./youki | tail -n 2
.debug_pubtypes
.debug_ranges

Not clear if the exploit was successful or not. The docker container returns:

yihuaf@yihuaf-dev:~/private/cve-2019-5736-poc$ docker run cve
HAX2: argv: /proc/self/fd/3
HAX2: fd: -1
HAX2: res: -1, 9

@oblique
Copy link
Contributor Author

oblique commented Sep 29, 2021

In your case the vulnerability was not triggered. Maybe you forgot the --runtime=youki parameter. Try it with my steps:

These are my changes on cve-2019-5736-poc:

diff --git a/Dockerfile b/Dockerfile
index e703898..c866bac 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,9 +1,11 @@
-FROM ubuntu:18.04
+FROM ubuntu:21.04
+
+ARG DEBIAN_FRONTEND=noninteractive
 
 RUN set -e -x ;\
     sed -i 's,# deb-src,deb-src,' /etc/apt/sources.list ;\
     apt -y update ;\
-    apt-get -y install build-essential ;\
+    apt-get -y install build-essential libdbus-1-3 ;\
     cd /root ;\
     apt-get -y build-dep libseccomp ;\
     apt-get source libseccomp
@@ -11,7 +13,7 @@ RUN set -e -x ;\
 ADD stage1.c /root/stage1.c
 
 RUN set -e -x ;\
-    cd /root/libseccomp-2.3.1 ;\
+    cd /root/libseccomp-2.5.1 ;\
     cat /root/stage1.c >> src/api.c ;\
     DEB_BUILD_OPTIONS=nocheck dpkg-buildpackage -b -uc -us ;\
     dpkg -i /root/*.deb

Then I run dockerd with:

oblique@dystopia ~/git/youki% sudo dockerd --experimental --add-runtime="youki=$(pwd)/target/x86_64-unknown-linux-gnu/debug/youki"

And this is how I trigger it:

oblique@dystopia ~/git/youki% strings target/x86_64-unknown-linux-gnu/debug/youki | tail -n3
.debug_loc
.debug_pubtypes
.debug_ranges

oblique@dystopia ~/git/youki% sudo docker run --rm  --runtime=youki cve
HAX2: argv: /proc/self/fd/3
HAX2: fd: 4
HAX2: res: 13, 0

oblique@dystopia ~/git/youki% strings target/x86_64-unknown-linux-gnu/debug/youki | tail -n3
.debug_pubtypes
.debug_ranges
cve-2019-5736

@utam0k
Copy link
Member

utam0k commented Sep 29, 2021

In runc, this is the part of the process, right?
https://github.com/opencontainers/runc/blob/d1c9b43e94b49d77cede5af42ef802961584b5bc/libcontainer/nsenter/cloned_binary.

runc handles it in nsexec.c, so it is probably a separate problem from the init subcommand of runc. I also misunderstood this issue when I first saw it.

@yihuaf Can I trust you to handle this problem?

@utam0k utam0k requested a review from yihuaf September 29, 2021 12:02
@oblique
Copy link
Contributor Author

oblique commented Sep 29, 2021

@utam0k Sealing is enforced by copying the runc binary in an anonymous file descriptor that exists only in memory and re-executing that fd. So this needs to happen at the entry point of the execution.

In case of runc, they run it from nsexec() which is called before main() (notice __attribute__((constructor))): https://github.com/opencontainers/runc/blob/5fb9b2a006725d468381de8d300bb9baecc726f7/libcontainer/nsenter/nsenter.go

@oblique oblique changed the title Seal /proc/self/exec to protect against CVE-2019-5736 Seal /proc/self/exe to protect against CVE-2019-5736 Sep 29, 2021
@oblique
Copy link
Contributor Author

oblique commented Sep 29, 2021

In case you are trying to figure out how this works:

  1. The malicious container modifies a dynamic library that is also used by youki (the PoC uses libseccomp.so.2) and inserts a malicious code as __attribute__ ((constructor)).
  2. The malicious container then creates a symbolic link of /proc/self/exe to /entrypoint
  3. youki initializes the container and then does an exec to the entrypoint, which actually points to the youki binary in host machine.
  4. The malicious code on the dynamic library runs before the main of youki and opens /proc/self/exe in read-only (let say the fd of this open is 4) and then opens it again from /proc/self/fd/4 as read-write.
  5. The malicious code after that has read-write fd on youki binary in host machine and modifies it.

Note that SELinux can mitigate this attack, so disable it when you are trying the PoC.

@yihuaf
Copy link
Collaborator

yihuaf commented Sep 29, 2021

In case you are trying to figure out how this works:

1. The malicious container modifies a dynamic library that is also used by youki (the PoC uses `libseccomp.so.2`) and inserts a malicious code as `__attribute__ ((constructor))`.

2. The malicious container then creates a symbolic link of `/proc/self/exe` to `/entrypoint`

3. youki initializes the container and then does an [exec](https://github.com/containers/youki/blob/4557c7b6343a503b2114d3ef1ccc9d04778c5079/src/process/init.rs#L393) to the entrypoint, which actually points to the youki binary in host machine.

4. The malicious code on the dynamic library runs before the `main` of youki and opens `/proc/self/exe` in read-only (let say the fd of this open is `4`) and then opens it again from `/proc/self/fd/4` as read-write.

5. The malicious code after that has read-write fd on youki binary in host machine and modifies it.

Note that SELinux can mitigate this attack, so disable it when you are trying the PoC.

Understood. Thank you for the explanation and I verified your steps. Can I ask you to add an error context for error handling, as well as a bit more explanation in the comments for context. Also add the two commits for reference:

Ref: https://github.com/opencontainers/runc/commit/0a8e4117e7f715d5fbeef398405813ce8e88558b
Ref: https://github.com/lxc/lxc/commit/6400238d08cdf1ca20d49bafb85f4e224348bf9d

Many thanks :)

Copy link
Collaborator

@yihuaf yihuaf left a comment

Choose a reason for hiding this comment

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

LGTM. Just add a bit more comments for context and error handling context.

@oblique
Copy link
Contributor Author

oblique commented Sep 30, 2021

I added more comments. I hope they are good.

@yihuaf yihuaf merged commit 6cb89fc into youki-dev:main Sep 30, 2021
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.

3 participants