diff --git a/daemon/apparmor_default.go b/daemon/apparmor_default.go index a7cc3a5ef4..c5cd348f94 100644 --- a/daemon/apparmor_default.go +++ b/daemon/apparmor_default.go @@ -5,8 +5,8 @@ package daemon // import "github.com/docker/docker/daemon" import ( "fmt" + "github.com/containerd/containerd/pkg/apparmor" aaprofile "github.com/docker/docker/profiles/apparmor" - "github.com/opencontainers/runc/libcontainer/apparmor" ) // Define constants for native driver @@ -17,14 +17,14 @@ const ( // DefaultApparmorProfile returns the name of the default apparmor profile func DefaultApparmorProfile() string { - if apparmor.IsEnabled() { + if apparmor.HostSupports() { return defaultAppArmorProfile } return "" } func ensureDefaultAppArmorProfile() error { - if apparmor.IsEnabled() { + if apparmor.HostSupports() { loaded, err := aaprofile.IsLoaded(defaultAppArmorProfile) if err != nil { return fmt.Errorf("Could not check if %s AppArmor profile was loaded: %s", defaultAppArmorProfile, err) diff --git a/daemon/exec_linux.go b/daemon/exec_linux.go index e3aadb3326..b683fef7de 100644 --- a/daemon/exec_linux.go +++ b/daemon/exec_linux.go @@ -3,10 +3,10 @@ package daemon // import "github.com/docker/docker/daemon" import ( "context" + "github.com/containerd/containerd/pkg/apparmor" "github.com/docker/docker/container" "github.com/docker/docker/daemon/exec" "github.com/docker/docker/oci/caps" - "github.com/opencontainers/runc/libcontainer/apparmor" specs "github.com/opencontainers/runtime-spec/specs-go" ) @@ -27,7 +27,7 @@ func (daemon *Daemon) execSetPlatformOpt(c *container.Container, ec *exec.Config p.Capabilities.Inheritable = p.Capabilities.Bounding p.Capabilities.Effective = p.Capabilities.Bounding } - if apparmor.IsEnabled() { + if apparmor.HostSupports() { var appArmorProfile string if c.AppArmorProfile != "" { appArmorProfile = c.AppArmorProfile diff --git a/daemon/exec_linux_test.go b/daemon/exec_linux_test.go index fe37ead115..cdebeb1cd7 100644 --- a/daemon/exec_linux_test.go +++ b/daemon/exec_linux_test.go @@ -5,16 +5,16 @@ package daemon import ( "testing" + "github.com/containerd/containerd/pkg/apparmor" containertypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/container" "github.com/docker/docker/daemon/exec" - "github.com/opencontainers/runc/libcontainer/apparmor" specs "github.com/opencontainers/runtime-spec/specs-go" "gotest.tools/v3/assert" ) func TestExecSetPlatformOpt(t *testing.T) { - if !apparmor.IsEnabled() { + if !apparmor.HostSupports() { t.Skip("requires AppArmor to be enabled") } d := &Daemon{} @@ -34,7 +34,7 @@ func TestExecSetPlatformOpt(t *testing.T) { // This behavior may change in future, but test for the behavior to prevent it // from being changed accidentally. func TestExecSetPlatformOptPrivileged(t *testing.T) { - if !apparmor.IsEnabled() { + if !apparmor.HostSupports() { t.Skip("requires AppArmor to be enabled") } d := &Daemon{} diff --git a/daemon/oci_linux.go b/daemon/oci_linux.go index 948690fe9a..5d9387611e 100644 --- a/daemon/oci_linux.go +++ b/daemon/oci_linux.go @@ -14,6 +14,7 @@ import ( cdcgroups "github.com/containerd/cgroups" "github.com/containerd/containerd/containers" coci "github.com/containerd/containerd/oci" + "github.com/containerd/containerd/pkg/apparmor" "github.com/containerd/containerd/sys" containertypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/container" @@ -26,7 +27,6 @@ import ( volumemounts "github.com/docker/docker/volume/mounts" "github.com/moby/sys/mount" "github.com/moby/sys/mountinfo" - "github.com/opencontainers/runc/libcontainer/apparmor" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/devices" "github.com/opencontainers/runc/libcontainer/user" @@ -128,7 +128,7 @@ func WithSelinux(c *container.Container) coci.SpecOpts { // WithApparmor sets the apparmor profile func WithApparmor(c *container.Container) coci.SpecOpts { return func(ctx context.Context, _ coci.Client, _ *containers.Container, s *coci.Spec) error { - if apparmor.IsEnabled() { + if apparmor.HostSupports() { var appArmorProfile string if c.AppArmorProfile != "" { appArmorProfile = c.AppArmorProfile diff --git a/vendor.conf b/vendor.conf index 1e78d40d5a..5e16f86d37 100644 --- a/vendor.conf +++ b/vendor.conf @@ -129,7 +129,7 @@ github.com/googleapis/gax-go bd5b16380fd03dc758d11cef74ba google.golang.org/genproto 3f1135a288c9a07e340ae8ba4cc6c7065a3160e8 # containerd -github.com/containerd/containerd fbf1a72de7da110187b7d3dace433914b9beca10 # master (v1.5.0-dev) +github.com/containerd/containerd 55eda46b22f985cde99b599e469ff9c13994bf68 # master (v1.5.0-dev) github.com/containerd/fifo 0724c46b320cf96bb172a0550c19a4b1fca4dacb github.com/containerd/continuity efbc4488d8fe1bdc16bde3b2d2990d9b3a899165 github.com/containerd/cgroups 0b889c03f102012f1d93a97ddd3ef71cd6f4f510 diff --git a/vendor/github.com/containerd/containerd/pkg/apparmor/apparmor.go b/vendor/github.com/containerd/containerd/pkg/apparmor/apparmor.go new file mode 100644 index 0000000000..484bccf7ed --- /dev/null +++ b/vendor/github.com/containerd/containerd/pkg/apparmor/apparmor.go @@ -0,0 +1,48 @@ +// +build apparmor,linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package apparmor + +import ( + "io/ioutil" + "os" + "sync" +) + +var ( + appArmorSupported bool + checkAppArmor sync.Once +) + +// HostSupports returns true if apparmor is enabled for the host, if +// apparmor_parser is enabled, and if we are not running docker-in-docker. +// +// It is a modified version of libcontainer/apparmor.IsEnabled(), which does not +// check for apparmor_parser to be present, or if we're running docker-in-docker. +func HostSupports() bool { + checkAppArmor.Do(func() { + // see https://github.com/docker/docker/commit/de191e86321f7d3136ff42ff75826b8107399497 + if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil && os.Getenv("container") == "" { + if _, err = os.Stat("/sbin/apparmor_parser"); err == nil { + buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled") + appArmorSupported = err == nil && len(buf) > 1 && buf[0] == 'Y' + } + } + }) + return appArmorSupported +} diff --git a/vendor/github.com/containerd/containerd/pkg/apparmor/apparmor_unsupported.go b/vendor/github.com/containerd/containerd/pkg/apparmor/apparmor_unsupported.go new file mode 100644 index 0000000000..68e410d22d --- /dev/null +++ b/vendor/github.com/containerd/containerd/pkg/apparmor/apparmor_unsupported.go @@ -0,0 +1,24 @@ +// +build !apparmor !linux + +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package apparmor + +//nolint: deadcode, unused +func HostSupports() bool { + return false +} diff --git a/vendor/github.com/containerd/containerd/reference/reference.go b/vendor/github.com/containerd/containerd/reference/reference.go index 562ab0d491..a4bf6da601 100644 --- a/vendor/github.com/containerd/containerd/reference/reference.go +++ b/vendor/github.com/containerd/containerd/reference/reference.go @@ -85,6 +85,10 @@ var splitRe = regexp.MustCompile(`[:@]`) // Parse parses the string into a structured ref. func Parse(s string) (Spec, error) { + if strings.Contains(s, "://") { + return Spec{}, ErrInvalid + } + u, err := url.Parse("dummy://" + s) if err != nil { return Spec{}, err diff --git a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go b/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go deleted file mode 100644 index debfc1e489..0000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go +++ /dev/null @@ -1,60 +0,0 @@ -// +build apparmor,linux - -package apparmor - -import ( - "fmt" - "io/ioutil" - "os" - - "github.com/opencontainers/runc/libcontainer/utils" -) - -// IsEnabled returns true if apparmor is enabled for the host. -func IsEnabled() bool { - if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil && os.Getenv("container") == "" { - if _, err = os.Stat("/sbin/apparmor_parser"); err == nil { - buf, err := ioutil.ReadFile("/sys/module/apparmor/parameters/enabled") - return err == nil && len(buf) > 1 && buf[0] == 'Y' - } - } - return false -} - -func setProcAttr(attr, value string) error { - // Under AppArmor you can only change your own attr, so use /proc/self/ - // instead of /proc// like libapparmor does - path := fmt.Sprintf("/proc/self/attr/%s", attr) - - f, err := os.OpenFile(path, os.O_WRONLY, 0) - if err != nil { - return err - } - defer f.Close() - - if err := utils.EnsureProcHandle(f); err != nil { - return err - } - - _, err = fmt.Fprintf(f, "%s", value) - return err -} - -// changeOnExec reimplements aa_change_onexec from libapparmor in Go -func changeOnExec(name string) error { - value := "exec " + name - if err := setProcAttr("exec", value); err != nil { - return fmt.Errorf("apparmor failed to apply profile: %s", err) - } - return nil -} - -// ApplyProfile will apply the profile with the specified name to the process after -// the next exec. -func ApplyProfile(name string) error { - if name == "" { - return nil - } - - return changeOnExec(name) -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_disabled.go b/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_disabled.go deleted file mode 100644 index d4110cf0bc..0000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_disabled.go +++ /dev/null @@ -1,20 +0,0 @@ -// +build !apparmor !linux - -package apparmor - -import ( - "errors" -) - -var ErrApparmorNotEnabled = errors.New("apparmor: config provided but apparmor not supported") - -func IsEnabled() bool { - return false -} - -func ApplyProfile(name string) error { - if name != "" { - return ErrApparmorNotEnabled - } - return nil -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go b/vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go deleted file mode 100644 index c8a9364d54..0000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go +++ /dev/null @@ -1,93 +0,0 @@ -// +build linux - -package utils - -/* - * Copyright 2016, 2017 SUSE LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import ( - "fmt" - "os" - - "golang.org/x/sys/unix" -) - -// MaxSendfdLen is the maximum length of the name of a file descriptor being -// sent using SendFd. The name of the file handle returned by RecvFd will never -// be larger than this value. -const MaxNameLen = 4096 - -// oobSpace is the size of the oob slice required to store a single FD. Note -// that unix.UnixRights appears to make the assumption that fd is always int32, -// so sizeof(fd) = 4. -var oobSpace = unix.CmsgSpace(4) - -// RecvFd waits for a file descriptor to be sent over the given AF_UNIX -// socket. The file name of the remote file descriptor will be recreated -// locally (it is sent as non-auxiliary data in the same payload). -func RecvFd(socket *os.File) (*os.File, error) { - // For some reason, unix.Recvmsg uses the length rather than the capacity - // when passing the msg_controllen and other attributes to recvmsg. So we - // have to actually set the length. - name := make([]byte, MaxNameLen) - oob := make([]byte, oobSpace) - - sockfd := socket.Fd() - n, oobn, _, _, err := unix.Recvmsg(int(sockfd), name, oob, 0) - if err != nil { - return nil, err - } - - if n >= MaxNameLen || oobn != oobSpace { - return nil, fmt.Errorf("recvfd: incorrect number of bytes read (n=%d oobn=%d)", n, oobn) - } - - // Truncate. - name = name[:n] - oob = oob[:oobn] - - scms, err := unix.ParseSocketControlMessage(oob) - if err != nil { - return nil, err - } - if len(scms) != 1 { - return nil, fmt.Errorf("recvfd: number of SCMs is not 1: %d", len(scms)) - } - scm := scms[0] - - fds, err := unix.ParseUnixRights(&scm) - if err != nil { - return nil, err - } - if len(fds) != 1 { - return nil, fmt.Errorf("recvfd: number of fds is not 1: %d", len(fds)) - } - fd := uintptr(fds[0]) - - return os.NewFile(fd, string(name)), nil -} - -// SendFd sends a file descriptor over the given AF_UNIX socket. In -// addition, the file.Name() of the given file will also be sent as -// non-auxiliary data in the same payload (allowing to send contextual -// information for a file descriptor). -func SendFd(socket *os.File, name string, fd uintptr) error { - if len(name) >= MaxNameLen { - return fmt.Errorf("sendfd: filename too long: %s", name) - } - oob := unix.UnixRights(int(fd)) - return unix.Sendmsg(int(socket.Fd()), []byte(name), oob, nil, 0) -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go deleted file mode 100644 index 40ccfaa1a0..0000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go +++ /dev/null @@ -1,112 +0,0 @@ -package utils - -import ( - "encoding/json" - "io" - "os" - "path/filepath" - "strings" - "unsafe" - - "golang.org/x/sys/unix" -) - -const ( - exitSignalOffset = 128 -) - -// ResolveRootfs ensures that the current working directory is -// not a symlink and returns the absolute path to the rootfs -func ResolveRootfs(uncleanRootfs string) (string, error) { - rootfs, err := filepath.Abs(uncleanRootfs) - if err != nil { - return "", err - } - return filepath.EvalSymlinks(rootfs) -} - -// ExitStatus returns the correct exit status for a process based on if it -// was signaled or exited cleanly -func ExitStatus(status unix.WaitStatus) int { - if status.Signaled() { - return exitSignalOffset + int(status.Signal()) - } - return status.ExitStatus() -} - -// WriteJSON writes the provided struct v to w using standard json marshaling -func WriteJSON(w io.Writer, v interface{}) error { - data, err := json.Marshal(v) - if err != nil { - return err - } - _, err = w.Write(data) - return err -} - -// CleanPath makes a path safe for use with filepath.Join. This is done by not -// only cleaning the path, but also (if the path is relative) adding a leading -// '/' and cleaning it (then removing the leading '/'). This ensures that a -// path resulting from prepending another path will always resolve to lexically -// be a subdirectory of the prefixed path. This is all done lexically, so paths -// that include symlinks won't be safe as a result of using CleanPath. -func CleanPath(path string) string { - // Deal with empty strings nicely. - if path == "" { - return "" - } - - // Ensure that all paths are cleaned (especially problematic ones like - // "/../../../../../" which can cause lots of issues). - path = filepath.Clean(path) - - // If the path isn't absolute, we need to do more processing to fix paths - // such as "../../../..//some/path". We also shouldn't convert absolute - // paths to relative ones. - if !filepath.IsAbs(path) { - path = filepath.Clean(string(os.PathSeparator) + path) - // This can't fail, as (by definition) all paths are relative to root. - path, _ = filepath.Rel(string(os.PathSeparator), path) - } - - // Clean the path again for good measure. - return filepath.Clean(path) -} - -// SearchLabels searches a list of key-value pairs for the provided key and -// returns the corresponding value. The pairs must be separated with '='. -func SearchLabels(labels []string, query string) string { - for _, l := range labels { - parts := strings.SplitN(l, "=", 2) - if len(parts) < 2 { - continue - } - if parts[0] == query { - return parts[1] - } - } - return "" -} - -// Annotations returns the bundle path and user defined annotations from the -// libcontainer state. We need to remove the bundle because that is a label -// added by libcontainer. -func Annotations(labels []string) (bundle string, userAnnotations map[string]string) { - userAnnotations = make(map[string]string) - for _, l := range labels { - parts := strings.SplitN(l, "=", 2) - if len(parts) < 2 { - continue - } - if parts[0] == "bundle" { - bundle = parts[1] - } else { - userAnnotations[parts[0]] = parts[1] - } - } - return -} - -func GetIntSize() int { - return int(unsafe.Sizeof(1)) -} diff --git a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go deleted file mode 100644 index 1576f2d4ab..0000000000 --- a/vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go +++ /dev/null @@ -1,68 +0,0 @@ -// +build !windows - -package utils - -import ( - "fmt" - "os" - "strconv" - - "golang.org/x/sys/unix" -) - -// EnsureProcHandle returns whether or not the given file handle is on procfs. -func EnsureProcHandle(fh *os.File) error { - var buf unix.Statfs_t - if err := unix.Fstatfs(int(fh.Fd()), &buf); err != nil { - return fmt.Errorf("ensure %s is on procfs: %v", fh.Name(), err) - } - if buf.Type != unix.PROC_SUPER_MAGIC { - return fmt.Errorf("%s is not on procfs", fh.Name()) - } - return nil -} - -// CloseExecFrom applies O_CLOEXEC to all file descriptors currently open for -// the process (except for those below the given fd value). -func CloseExecFrom(minFd int) error { - fdDir, err := os.Open("/proc/self/fd") - if err != nil { - return err - } - defer fdDir.Close() - - if err := EnsureProcHandle(fdDir); err != nil { - return err - } - - fdList, err := fdDir.Readdirnames(-1) - if err != nil { - return err - } - for _, fdStr := range fdList { - fd, err := strconv.Atoi(fdStr) - // Ignore non-numeric file names. - if err != nil { - continue - } - // Ignore descriptors lower than our specified minimum. - if fd < minFd { - continue - } - // Intentionally ignore errors from unix.CloseOnExec -- 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). - unix.CloseOnExec(fd) - } - return nil -} - -// NewSockPair returns a new unix socket pair -func NewSockPair(name string) (parent *os.File, child *os.File, err error) { - fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0) - if err != nil { - return nil, nil, err - } - return os.NewFile(uintptr(fds[1]), name+"-p"), os.NewFile(uintptr(fds[0]), name+"-c"), nil -}