github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/syscalls/linux/sys_mount.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package linux
    16  
    17  import (
    18  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    19  	"github.com/SagerNet/gvisor/pkg/errors/linuxerr"
    20  	"github.com/SagerNet/gvisor/pkg/hostarch"
    21  	"github.com/SagerNet/gvisor/pkg/sentry/arch"
    22  	"github.com/SagerNet/gvisor/pkg/sentry/fs"
    23  	"github.com/SagerNet/gvisor/pkg/sentry/kernel"
    24  )
    25  
    26  // Mount implements Linux syscall mount(2).
    27  func Mount(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    28  	sourceAddr := args[0].Pointer()
    29  	targetAddr := args[1].Pointer()
    30  	typeAddr := args[2].Pointer()
    31  	flags := args[3].Uint64()
    32  	dataAddr := args[4].Pointer()
    33  
    34  	fsType, err := t.CopyInString(typeAddr, hostarch.PageSize)
    35  	if err != nil {
    36  		return 0, nil, err
    37  	}
    38  
    39  	sourcePath, _, err := copyInPath(t, sourceAddr, true /* allowEmpty */)
    40  	if err != nil {
    41  		return 0, nil, err
    42  	}
    43  
    44  	targetPath, _, err := copyInPath(t, targetAddr, false /* allowEmpty */)
    45  	if err != nil {
    46  		return 0, nil, err
    47  	}
    48  
    49  	data := ""
    50  	if dataAddr != 0 {
    51  		// In Linux, a full page is always copied in regardless of null
    52  		// character placement, and the address is passed to each file system.
    53  		// Most file systems always treat this data as a string, though, and so
    54  		// do all of the ones we implement.
    55  		data, err = t.CopyInString(dataAddr, hostarch.PageSize)
    56  		if err != nil {
    57  			return 0, nil, err
    58  		}
    59  	}
    60  
    61  	// Ignore magic value that was required before Linux 2.4.
    62  	if flags&linux.MS_MGC_MSK == linux.MS_MGC_VAL {
    63  		flags = flags &^ linux.MS_MGC_MSK
    64  	}
    65  
    66  	// Must have CAP_SYS_ADMIN in the mount namespace's associated user
    67  	// namespace.
    68  	if !t.HasCapabilityIn(linux.CAP_SYS_ADMIN, t.MountNamespace().UserNamespace()) {
    69  		return 0, nil, linuxerr.EPERM
    70  	}
    71  
    72  	const unsupportedOps = linux.MS_REMOUNT | linux.MS_BIND |
    73  		linux.MS_SHARED | linux.MS_PRIVATE | linux.MS_SLAVE |
    74  		linux.MS_UNBINDABLE | linux.MS_MOVE
    75  
    76  	// Silently allow MS_NOSUID, since we don't implement set-id bits
    77  	// anyway.
    78  	const unsupportedFlags = linux.MS_NODEV |
    79  		linux.MS_NODIRATIME | linux.MS_STRICTATIME
    80  
    81  	// Linux just allows passing any flags to mount(2) - it won't fail when
    82  	// unknown or unsupported flags are passed. Since we don't implement
    83  	// everything, we fail explicitly on flags that are unimplemented.
    84  	if flags&(unsupportedOps|unsupportedFlags) != 0 {
    85  		return 0, nil, linuxerr.EINVAL
    86  	}
    87  
    88  	rsys, ok := fs.FindFilesystem(fsType)
    89  	if !ok {
    90  		return 0, nil, linuxerr.ENODEV
    91  	}
    92  	if !rsys.AllowUserMount() {
    93  		return 0, nil, linuxerr.EPERM
    94  	}
    95  
    96  	var superFlags fs.MountSourceFlags
    97  	if flags&linux.MS_NOATIME == linux.MS_NOATIME {
    98  		superFlags.NoAtime = true
    99  	}
   100  	if flags&linux.MS_RDONLY == linux.MS_RDONLY {
   101  		superFlags.ReadOnly = true
   102  	}
   103  	if flags&linux.MS_NOEXEC == linux.MS_NOEXEC {
   104  		superFlags.NoExec = true
   105  	}
   106  
   107  	rootInode, err := rsys.Mount(t, sourcePath, superFlags, data, nil)
   108  	if err != nil {
   109  		return 0, nil, linuxerr.EINVAL
   110  	}
   111  
   112  	if err := fileOpOn(t, linux.AT_FDCWD, targetPath, true /* resolve */, func(root *fs.Dirent, d *fs.Dirent, _ uint) error {
   113  		// Mount will take a reference on rootInode if successful.
   114  		return t.MountNamespace().Mount(t, d, rootInode)
   115  	}); err != nil {
   116  		// Something went wrong. Drop our ref on rootInode before
   117  		// returning the error.
   118  		rootInode.DecRef(t)
   119  		return 0, nil, err
   120  	}
   121  
   122  	return 0, nil, nil
   123  }
   124  
   125  // Umount2 implements Linux syscall umount2(2).
   126  func Umount2(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   127  	addr := args[0].Pointer()
   128  	flags := args[1].Int()
   129  
   130  	const unsupported = linux.MNT_FORCE | linux.MNT_EXPIRE
   131  	if flags&unsupported != 0 {
   132  		return 0, nil, linuxerr.EINVAL
   133  	}
   134  
   135  	path, _, err := copyInPath(t, addr, false /* allowEmpty */)
   136  	if err != nil {
   137  		return 0, nil, err
   138  	}
   139  
   140  	// Must have CAP_SYS_ADMIN in the mount namespace's associated user
   141  	// namespace.
   142  	//
   143  	// Currently, this is always the init task's user namespace.
   144  	if !t.HasCapabilityIn(linux.CAP_SYS_ADMIN, t.MountNamespace().UserNamespace()) {
   145  		return 0, nil, linuxerr.EPERM
   146  	}
   147  
   148  	resolve := flags&linux.UMOUNT_NOFOLLOW != linux.UMOUNT_NOFOLLOW
   149  	detachOnly := flags&linux.MNT_DETACH == linux.MNT_DETACH
   150  
   151  	return 0, nil, fileOpOn(t, linux.AT_FDCWD, path, resolve, func(root *fs.Dirent, d *fs.Dirent, _ uint) error {
   152  		return t.MountNamespace().Unmount(t, d, detachOnly)
   153  	})
   154  }