github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/daemon/graphdriver/overlayutils/userxattr.go (about) 1 //go:build linux 2 // +build linux 3 4 // Forked from https://github.com/containerd/containerd/blob/9ade247b38b5a685244e1391c86ff41ab109556e/snapshots/overlay/check.go 5 /* 6 Copyright The containerd Authors. 7 8 Licensed under the Apache License, Version 2.0 (the "License"); 9 you may not use this file except in compliance with the License. 10 You may obtain a copy of the License at 11 12 http://www.apache.org/licenses/LICENSE-2.0 13 14 Unless required by applicable law or agreed to in writing, software 15 distributed under the License is distributed on an "AS IS" BASIS, 16 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 See the License for the specific language governing permissions and 18 limitations under the License. 19 */ 20 21 package overlayutils 22 23 import ( 24 "fmt" 25 "os" 26 "path/filepath" 27 28 "github.com/containerd/containerd/mount" 29 "github.com/containerd/containerd/pkg/userns" 30 "github.com/docker/docker/pkg/parsers/kernel" 31 "github.com/sirupsen/logrus" 32 ) 33 34 // NeedsUserXAttr returns whether overlayfs should be mounted with the "userxattr" mount option. 35 // 36 // The "userxattr" option is needed for mounting overlayfs inside a user namespace with kernel >= 5.11. 37 // 38 // The "userxattr" option is NOT needed for the initial user namespace (aka "the host"). 39 // 40 // Also, Ubuntu (since circa 2015) and Debian (since 10) with kernel < 5.11 can mount 41 // the overlayfs in a user namespace without the "userxattr" option. 42 // 43 // The corresponding kernel commit: https://github.com/torvalds/linux/commit/2d2f2d7322ff43e0fe92bf8cccdc0b09449bf2e1 44 // > ovl: user xattr 45 // > 46 // > Optionally allow using "user.overlay." namespace instead of "trusted.overlay." 47 // > ... 48 // > Disable redirect_dir and metacopy options, because these would allow privilege escalation through direct manipulation of the 49 // > "user.overlay.redirect" or "user.overlay.metacopy" xattrs. 50 // > ... 51 // 52 // The "userxattr" support is not exposed in "/sys/module/overlay/parameters". 53 func NeedsUserXAttr(d string) (bool, error) { 54 if !userns.RunningInUserNS() { 55 // we are the real root (i.e., the root in the initial user NS), 56 // so we do never need "userxattr" opt. 57 return false, nil 58 } 59 60 // Fast path for kernel >= 5.11 . 61 // 62 // Keep in mind that distro vendors might be going to backport the patch to older kernels. 63 // So we can't completely remove the "slow path". 64 if kernel.CheckKernelVersion(5, 11, 0) { 65 return true, nil 66 } 67 68 tdRoot := filepath.Join(d, "userxattr-check") 69 if err := os.RemoveAll(tdRoot); err != nil { 70 logrus.WithError(err).Warnf("Failed to remove check directory %v", tdRoot) 71 } 72 73 if err := os.MkdirAll(tdRoot, 0700); err != nil { 74 return false, err 75 } 76 77 defer func() { 78 if err := os.RemoveAll(tdRoot); err != nil { 79 logrus.WithError(err).Warnf("Failed to remove check directory %v", tdRoot) 80 } 81 }() 82 83 td, err := os.MkdirTemp(tdRoot, "") 84 if err != nil { 85 return false, err 86 } 87 88 for _, dir := range []string{"lower1", "lower2", "upper", "work", "merged"} { 89 if err := os.Mkdir(filepath.Join(td, dir), 0755); err != nil { 90 return false, err 91 } 92 } 93 94 opts := []string{ 95 fmt.Sprintf("lowerdir=%s:%s,upperdir=%s,workdir=%s", filepath.Join(td, "lower2"), filepath.Join(td, "lower1"), filepath.Join(td, "upper"), filepath.Join(td, "work")), 96 "userxattr", 97 } 98 99 m := mount.Mount{ 100 Type: "overlay", 101 Source: "overlay", 102 Options: opts, 103 } 104 105 dest := filepath.Join(td, "merged") 106 if err := m.Mount(dest); err != nil { 107 // Probably the host is running Ubuntu/Debian kernel (< 5.11) with the userns patch but without the userxattr patch. 108 // Return false without error. 109 logrus.WithError(err).Debugf("cannot mount overlay with \"userxattr\", probably the kernel does not support userxattr") 110 return false, nil 111 } 112 if err := mount.UnmountAll(dest, 0); err != nil { 113 logrus.WithError(err).Warnf("Failed to unmount check directory %v", dest) 114 } 115 return true, nil 116 }