Skip to content

Commit cad42f6

Browse files
Merge pull request #2130 from cyphar/apparmor-verify-procfs
*: verify operations on /proc/... are on procfs
2 parents 84373aa + d463f64 commit cad42f6

File tree

6 files changed

+100
-20
lines changed

6 files changed

+100
-20
lines changed

libcontainer/apparmor/apparmor.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"fmt"
77
"io/ioutil"
88
"os"
9+
10+
"github.com/opencontainers/runc/libcontainer/utils"
911
)
1012

1113
// IsEnabled returns true if apparmor is enabled for the host.
@@ -19,7 +21,7 @@ func IsEnabled() bool {
1921
return false
2022
}
2123

22-
func setprocattr(attr, value string) error {
24+
func setProcAttr(attr, value string) error {
2325
// Under AppArmor you can only change your own attr, so use /proc/self/
2426
// instead of /proc/<tid>/ like libapparmor does
2527
path := fmt.Sprintf("/proc/self/attr/%s", attr)
@@ -30,14 +32,18 @@ func setprocattr(attr, value string) error {
3032
}
3133
defer f.Close()
3234

35+
if err := utils.EnsureProcHandle(f); err != nil {
36+
return err
37+
}
38+
3339
_, err = fmt.Fprintf(f, "%s", value)
3440
return err
3541
}
3642

3743
// changeOnExec reimplements aa_change_onexec from libapparmor in Go
3844
func changeOnExec(name string) error {
3945
value := "exec " + name
40-
if err := setprocattr("exec", value); err != nil {
46+
if err := setProcAttr("exec", value); err != nil {
4147
return fmt.Errorf("apparmor failed to apply profile: %s", err)
4248
}
4349
return nil

libcontainer/utils/utils_unix.go

+34-10
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,57 @@
33
package utils
44

55
import (
6-
"io/ioutil"
6+
"fmt"
77
"os"
88
"strconv"
99

1010
"golang.org/x/sys/unix"
1111
)
1212

13+
// EnsureProcHandle returns whether or not the given file handle is on procfs.
14+
func EnsureProcHandle(fh *os.File) error {
15+
var buf unix.Statfs_t
16+
if err := unix.Fstatfs(int(fh.Fd()), &buf); err != nil {
17+
return fmt.Errorf("ensure %s is on procfs: %v", fh.Name(), err)
18+
}
19+
if buf.Type != unix.PROC_SUPER_MAGIC {
20+
return fmt.Errorf("%s is not on procfs", fh.Name())
21+
}
22+
return nil
23+
}
24+
25+
// CloseExecFrom applies O_CLOEXEC to all file descriptors currently open for
26+
// the process (except for those below the given fd value).
1327
func CloseExecFrom(minFd int) error {
14-
fdList, err := ioutil.ReadDir("/proc/self/fd")
28+
fdDir, err := os.Open("/proc/self/fd")
29+
if err != nil {
30+
return err
31+
}
32+
defer fdDir.Close()
33+
34+
if err := EnsureProcHandle(fdDir); err != nil {
35+
return err
36+
}
37+
38+
fdList, err := fdDir.Readdirnames(-1)
1539
if err != nil {
1640
return err
1741
}
18-
for _, fi := range fdList {
19-
fd, err := strconv.Atoi(fi.Name())
42+
for _, fdStr := range fdList {
43+
fd, err := strconv.Atoi(fdStr)
44+
// Ignore non-numeric file names.
2045
if err != nil {
21-
// ignore non-numeric file names
2246
continue
2347
}
24-
48+
// Ignore descriptors lower than our specified minimum.
2549
if fd < minFd {
26-
// ignore descriptors lower than our specified minimum
2750
continue
2851
}
29-
30-
// intentionally ignore errors from unix.CloseOnExec
52+
// Intentionally ignore errors from unix.CloseOnExec -- the cases where
53+
// this might fail are basically file descriptors that have already
54+
// been closed (including and especially the one that was created when
55+
// ioutil.ReadDir did the "opendir" syscall).
3156
unix.CloseOnExec(fd)
32-
// the cases where this might fail are basically file descriptors that have already been closed (including and especially the one that was created when ioutil.ReadDir did the "opendir" syscall)
3357
}
3458
return nil
3559
}

vendor.conf

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ github.com/opencontainers/runtime-spec 29686dbc5559d93fb1ef402eeda3e35c38d75af4
66
# Core libcontainer functionality.
77
github.com/checkpoint-restore/go-criu 17b0214f6c48980c45dc47ecb0cfd6d9e02df723 # v3.11
88
github.com/mrunalp/fileutils 7d4729fb36185a7c1719923406c9d40e54fb93c7
9-
github.com/opencontainers/selinux 3a1f366feb7aecbf7a0e71ac4cea88b31597de9e # v1.2.2
9+
github.com/opencontainers/selinux 5215b1806f52b1fcc2070a8826c542c9d33cd3cf # v1.3.0 (+ CVE-2019-16884)
1010
github.com/seccomp/libseccomp-golang 689e3c1541a84461afc49c1c87352a6cedf72e9c # v0.9.1
1111
github.com/sirupsen/logrus 8bdbc7bcc01dcbb8ec23dc8a28e332258d25251f # v1.4.1
1212
github.com/syndtr/gocapability d98352740cb2c55f81556b63d4a1ec64c5a319c2

vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go

+11-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go

+33
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go

+13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)