github.com/wozhu6104/docker@v20.10.10+incompatible/daemon/graphdriver/overlayutils/userxattr.go (about)

     1  // +build linux
     2  
     3  // Forked from https://github.com/containerd/containerd/blob/9ade247b38b5a685244e1391c86ff41ab109556e/snapshots/overlay/check.go
     4  /*
     5     Copyright The containerd Authors.
     6  
     7     Licensed under the Apache License, Version 2.0 (the "License");
     8     you may not use this file except in compliance with the License.
     9     You may obtain a copy of the License at
    10  
    11         http://www.apache.org/licenses/LICENSE-2.0
    12  
    13     Unless required by applicable law or agreed to in writing, software
    14     distributed under the License is distributed on an "AS IS" BASIS,
    15     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16     See the License for the specific language governing permissions and
    17     limitations under the License.
    18  */
    19  
    20  package overlayutils
    21  
    22  import (
    23  	"fmt"
    24  	"io/ioutil"
    25  	"os"
    26  	"path/filepath"
    27  
    28  	"github.com/containerd/containerd/mount"
    29  	"github.com/containerd/containerd/sys"
    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 !sys.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 := ioutil.TempDir(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  }