summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChen Qi <Qi.Chen@windriver.com>2019-11-06 13:17:48 +0800
committerBruce Ashfield <bruce.ashfield@gmail.com>2019-11-17 22:28:37 -0500
commit79fb488a7071bbfafb8656adf7826a57b2ef6cd4 (patch)
tree2eca6b99f527a406d45d20cba0a45f2be6e28d4c
parent062d9f1f4faf2ca8a1fe78b7c7365e6378c15836 (diff)
downloadmeta-virtualization-79fb488a7071bbfafb8656adf7826a57b2ef6cd4.tar.gz
runc: fix CVE-2019-16884
Signed-off-by: Chen Qi <Qi.Chen@windriver.com> Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com>
-rw-r--r--recipes-containers/runc/files/0001-Only-allow-proc-mount-if-it-is-procfs.patch201
-rw-r--r--recipes-containers/runc/runc-docker_git.bb1
-rw-r--r--recipes-containers/runc/runc-opencontainers_git.bb1
3 files changed, 203 insertions, 0 deletions
diff --git a/recipes-containers/runc/files/0001-Only-allow-proc-mount-if-it-is-procfs.patch b/recipes-containers/runc/files/0001-Only-allow-proc-mount-if-it-is-procfs.patch
new file mode 100644
index 00000000..5aca99e2
--- /dev/null
+++ b/recipes-containers/runc/files/0001-Only-allow-proc-mount-if-it-is-procfs.patch
@@ -0,0 +1,201 @@
1From d75b05441772417a0828465a9483f16287937724 Mon Sep 17 00:00:00 2001
2From: Michael Crosby <crosbymichael@gmail.com>
3Date: Mon, 23 Sep 2019 16:45:45 -0400
4Subject: [PATCH] Only allow proc mount if it is procfs
5
6Fixes #2128
7
8This allows proc to be bind mounted for host and rootless namespace usecases but
9it removes the ability to mount over the top of proc with a directory.
10
11```bash
12> sudo docker run --rm apparmor
13docker: Error response from daemon: OCI runtime create failed:
14container_linux.go:346: starting container process caused "process_linux.go:449:
15container init caused \"rootfs_linux.go:58: mounting
16\\\"/var/lib/docker/volumes/aae28ea068c33d60e64d1a75916cf3ec2dc3634f97571854c9ed30c8401460c1/_data\\\"
17to rootfs
18\\\"/var/lib/docker/overlay2/a6be5ae911bf19f8eecb23a295dec85be9a8ee8da66e9fb55b47c841d1e381b7/merged\\\"
19at \\\"/proc\\\" caused
20\\\"\\\\\\\"/var/lib/docker/overlay2/a6be5ae911bf19f8eecb23a295dec85be9a8ee8da66e9fb55b47c841d1e381b7/merged/proc\\\\\\\"
21cannot be mounted because it is not of type proc\\\"\"": unknown.
22
23> sudo docker run --rm -v /proc:/proc apparmor
24
25docker-default (enforce) root 18989 0.9 0.0 1288 4 ?
26Ss 16:47 0:00 sleep 20
27```
28
29Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
30
31Upstream-Status: Backport [https://github.com/opencontainers/runc/pull/2129/commits/331692baa7afdf6c186f8667cb0e6362ea0802b3]
32
33CVE: CVE-2019-16884
34
35Signed-off-by: Chen Qi <Qi.Chen@windriver.com>
36---
37 libcontainer/container_linux.go | 4 +--
38 libcontainer/rootfs_linux.go | 50 +++++++++++++++++++++++--------
39 libcontainer/rootfs_linux_test.go | 8 ++---
40 3 files changed, 43 insertions(+), 19 deletions(-)
41
42diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
43index 7e58e5e0..d51e35df 100644
44--- a/src/import/libcontainer/container_linux.go
45+++ b/src/import/libcontainer/container_linux.go
46@@ -19,7 +19,7 @@ import (
47 "syscall" // only for SysProcAttr and Signal
48 "time"
49
50- "github.com/cyphar/filepath-securejoin"
51+ securejoin "github.com/cyphar/filepath-securejoin"
52 "github.com/opencontainers/runc/libcontainer/cgroups"
53 "github.com/opencontainers/runc/libcontainer/configs"
54 "github.com/opencontainers/runc/libcontainer/intelrdt"
55@@ -1160,7 +1160,7 @@ func (c *linuxContainer) makeCriuRestoreMountpoints(m *configs.Mount) error {
56 if err != nil {
57 return err
58 }
59- if err := checkMountDestination(c.config.Rootfs, dest); err != nil {
60+ if err := checkProcMount(c.config.Rootfs, dest, ""); err != nil {
61 return err
62 }
63 m.Destination = dest
64diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go
65index f13b226e..5650b0ac 100644
66--- a/src/import/libcontainer/rootfs_linux.go
67+++ b/src/import/libcontainer/rootfs_linux.go
68@@ -13,7 +13,7 @@ import (
69 "strings"
70 "time"
71
72- "github.com/cyphar/filepath-securejoin"
73+ securejoin "github.com/cyphar/filepath-securejoin"
74 "github.com/mrunalp/fileutils"
75 "github.com/opencontainers/runc/libcontainer/cgroups"
76 "github.com/opencontainers/runc/libcontainer/configs"
77@@ -197,7 +197,7 @@ func prepareBindMount(m *configs.Mount, rootfs string) error {
78 if dest, err = securejoin.SecureJoin(rootfs, m.Destination); err != nil {
79 return err
80 }
81- if err := checkMountDestination(rootfs, dest); err != nil {
82+ if err := checkProcMount(rootfs, dest, m.Source); err != nil {
83 return err
84 }
85 // update the mount with the correct dest after symlinks are resolved.
86@@ -388,7 +388,7 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string, enableCgroupns b
87 if dest, err = securejoin.SecureJoin(rootfs, m.Destination); err != nil {
88 return err
89 }
90- if err := checkMountDestination(rootfs, dest); err != nil {
91+ if err := checkProcMount(rootfs, dest, m.Source); err != nil {
92 return err
93 }
94 // update the mount with the correct dest after symlinks are resolved.
95@@ -435,12 +435,12 @@ func getCgroupMounts(m *configs.Mount) ([]*configs.Mount, error) {
96 return binds, nil
97 }
98
99-// checkMountDestination checks to ensure that the mount destination is not over the top of /proc.
100+// checkProcMount checks to ensure that the mount destination is not over the top of /proc.
101 // dest is required to be an abs path and have any symlinks resolved before calling this function.
102-func checkMountDestination(rootfs, dest string) error {
103- invalidDestinations := []string{
104- "/proc",
105- }
106+//
107+// if source is nil, don't stat the filesystem. This is used for restore of a checkpoint.
108+func checkProcMount(rootfs, dest, source string) error {
109+ const procPath = "/proc"
110 // White list, it should be sub directories of invalid destinations
111 validDestinations := []string{
112 // These entries can be bind mounted by files emulated by fuse,
113@@ -463,16 +463,40 @@ func checkMountDestination(rootfs, dest string) error {
114 return nil
115 }
116 }
117- for _, invalid := range invalidDestinations {
118- path, err := filepath.Rel(filepath.Join(rootfs, invalid), dest)
119+ path, err := filepath.Rel(filepath.Join(rootfs, procPath), dest)
120+ if err != nil {
121+ return err
122+ }
123+ // pass if the mount path is located outside of /proc
124+ if strings.HasPrefix(path, "..") {
125+ return nil
126+ }
127+ if path == "." {
128+ // an empty source is pasted on restore
129+ if source == "" {
130+ return nil
131+ }
132+ // only allow a mount on-top of proc if it's source is "proc"
133+ isproc, err := isProc(source)
134 if err != nil {
135 return err
136 }
137- if path != "." && !strings.HasPrefix(path, "..") {
138- return fmt.Errorf("%q cannot be mounted because it is located inside %q", dest, invalid)
139+ // pass if the mount is happening on top of /proc and the source of
140+ // the mount is a proc filesystem
141+ if isproc {
142+ return nil
143 }
144+ return fmt.Errorf("%q cannot be mounted because it is not of type proc", dest)
145 }
146- return nil
147+ return fmt.Errorf("%q cannot be mounted because it is inside /proc", dest)
148+}
149+
150+func isProc(path string) (bool, error) {
151+ var s unix.Statfs_t
152+ if err := unix.Statfs(path, &s); err != nil {
153+ return false, err
154+ }
155+ return s.Type == unix.PROC_SUPER_MAGIC, nil
156 }
157
158 func setupDevSymlinks(rootfs string) error {
159diff --git a/libcontainer/rootfs_linux_test.go b/libcontainer/rootfs_linux_test.go
160index d755984b..1bfe7c66 100644
161--- a/src/import/libcontainer/rootfs_linux_test.go
162+++ b/src/import/libcontainer/rootfs_linux_test.go
163@@ -10,7 +10,7 @@ import (
164
165 func TestCheckMountDestOnProc(t *testing.T) {
166 dest := "/rootfs/proc/sys"
167- err := checkMountDestination("/rootfs", dest)
168+ err := checkProcMount("/rootfs", dest, "")
169 if err == nil {
170 t.Fatal("destination inside proc should return an error")
171 }
172@@ -18,7 +18,7 @@ func TestCheckMountDestOnProc(t *testing.T) {
173
174 func TestCheckMountDestOnProcChroot(t *testing.T) {
175 dest := "/rootfs/proc/"
176- err := checkMountDestination("/rootfs", dest)
177+ err := checkProcMount("/rootfs", dest, "/proc")
178 if err != nil {
179 t.Fatal("destination inside proc when using chroot should not return an error")
180 }
181@@ -26,7 +26,7 @@ func TestCheckMountDestOnProcChroot(t *testing.T) {
182
183 func TestCheckMountDestInSys(t *testing.T) {
184 dest := "/rootfs//sys/fs/cgroup"
185- err := checkMountDestination("/rootfs", dest)
186+ err := checkProcMount("/rootfs", dest, "")
187 if err != nil {
188 t.Fatal("destination inside /sys should not return an error")
189 }
190@@ -34,7 +34,7 @@ func TestCheckMountDestInSys(t *testing.T) {
191
192 func TestCheckMountDestFalsePositive(t *testing.T) {
193 dest := "/rootfs/sysfiles/fs/cgroup"
194- err := checkMountDestination("/rootfs", dest)
195+ err := checkProcMount("/rootfs", dest, "")
196 if err != nil {
197 t.Fatal(err)
198 }
199--
2002.17.1
201
diff --git a/recipes-containers/runc/runc-docker_git.bb b/recipes-containers/runc/runc-docker_git.bb
index c9f460b2..8d810d01 100644
--- a/recipes-containers/runc/runc-docker_git.bb
+++ b/recipes-containers/runc/runc-docker_git.bb
@@ -7,6 +7,7 @@ SRC_URI = "git://github.com/opencontainers/runc;nobranch=1;name=runc-docker \
7 file://0001-runc-Add-console-socket-dev-null.patch \ 7 file://0001-runc-Add-console-socket-dev-null.patch \
8 file://0001-Makefile-respect-GOBUILDFLAGS-for-runc-and-remove-re.patch \ 8 file://0001-Makefile-respect-GOBUILDFLAGS-for-runc-and-remove-re.patch \
9 file://0001-runc-docker-SIGUSR1-daemonize.patch \ 9 file://0001-runc-docker-SIGUSR1-daemonize.patch \
10 file://0001-Only-allow-proc-mount-if-it-is-procfs.patch \
10 " 11 "
11 12
12RUNC_VERSION = "1.0.0-rc8" 13RUNC_VERSION = "1.0.0-rc8"
diff --git a/recipes-containers/runc/runc-opencontainers_git.bb b/recipes-containers/runc/runc-opencontainers_git.bb
index 361bc94b..3a7e7aaf 100644
--- a/recipes-containers/runc/runc-opencontainers_git.bb
+++ b/recipes-containers/runc/runc-opencontainers_git.bb
@@ -4,5 +4,6 @@ SRCREV = "652297c7c7e6c94e8d064ad5916c32891a6fd388"
4SRC_URI = " \ 4SRC_URI = " \
5 git://github.com/opencontainers/runc;branch=master \ 5 git://github.com/opencontainers/runc;branch=master \
6 file://0001-Makefile-respect-GOBUILDFLAGS-for-runc-and-remove-re.patch \ 6 file://0001-Makefile-respect-GOBUILDFLAGS-for-runc-and-remove-re.patch \
7 file://0001-Only-allow-proc-mount-if-it-is-procfs.patch \
7 " 8 "
8RUNC_VERSION = "1.0.0-rc8" 9RUNC_VERSION = "1.0.0-rc8"