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

     1  // Copyright 2020 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 vfs2
    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/kernel"
    23  	"github.com/SagerNet/gvisor/pkg/sentry/vfs"
    24  	"github.com/SagerNet/gvisor/pkg/syserror"
    25  )
    26  
    27  // Link implements Linux syscall link(2).
    28  func Link(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    29  	oldpathAddr := args[0].Pointer()
    30  	newpathAddr := args[1].Pointer()
    31  	return 0, nil, linkat(t, linux.AT_FDCWD, oldpathAddr, linux.AT_FDCWD, newpathAddr, 0 /* flags */)
    32  }
    33  
    34  // Linkat implements Linux syscall linkat(2).
    35  func Linkat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    36  	olddirfd := args[0].Int()
    37  	oldpathAddr := args[1].Pointer()
    38  	newdirfd := args[2].Int()
    39  	newpathAddr := args[3].Pointer()
    40  	flags := args[4].Int()
    41  	return 0, nil, linkat(t, olddirfd, oldpathAddr, newdirfd, newpathAddr, flags)
    42  }
    43  
    44  func linkat(t *kernel.Task, olddirfd int32, oldpathAddr hostarch.Addr, newdirfd int32, newpathAddr hostarch.Addr, flags int32) error {
    45  	if flags&^(linux.AT_EMPTY_PATH|linux.AT_SYMLINK_FOLLOW) != 0 {
    46  		return linuxerr.EINVAL
    47  	}
    48  	if flags&linux.AT_EMPTY_PATH != 0 && !t.HasCapability(linux.CAP_DAC_READ_SEARCH) {
    49  		return syserror.ENOENT
    50  	}
    51  
    52  	oldpath, err := copyInPath(t, oldpathAddr)
    53  	if err != nil {
    54  		return err
    55  	}
    56  	oldtpop, err := getTaskPathOperation(t, olddirfd, oldpath, shouldAllowEmptyPath(flags&linux.AT_EMPTY_PATH != 0), shouldFollowFinalSymlink(flags&linux.AT_SYMLINK_FOLLOW != 0))
    57  	if err != nil {
    58  		return err
    59  	}
    60  	defer oldtpop.Release(t)
    61  
    62  	newpath, err := copyInPath(t, newpathAddr)
    63  	if err != nil {
    64  		return err
    65  	}
    66  	newtpop, err := getTaskPathOperation(t, newdirfd, newpath, disallowEmptyPath, nofollowFinalSymlink)
    67  	if err != nil {
    68  		return err
    69  	}
    70  	defer newtpop.Release(t)
    71  
    72  	return t.Kernel().VFS().LinkAt(t, t.Credentials(), &oldtpop.pop, &newtpop.pop)
    73  }
    74  
    75  // Mkdir implements Linux syscall mkdir(2).
    76  func Mkdir(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    77  	addr := args[0].Pointer()
    78  	mode := args[1].ModeT()
    79  	return 0, nil, mkdirat(t, linux.AT_FDCWD, addr, mode)
    80  }
    81  
    82  // Mkdirat implements Linux syscall mkdirat(2).
    83  func Mkdirat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    84  	dirfd := args[0].Int()
    85  	addr := args[1].Pointer()
    86  	mode := args[2].ModeT()
    87  	return 0, nil, mkdirat(t, dirfd, addr, mode)
    88  }
    89  
    90  func mkdirat(t *kernel.Task, dirfd int32, addr hostarch.Addr, mode uint) error {
    91  	path, err := copyInPath(t, addr)
    92  	if err != nil {
    93  		return err
    94  	}
    95  	tpop, err := getTaskPathOperation(t, dirfd, path, disallowEmptyPath, nofollowFinalSymlink)
    96  	if err != nil {
    97  		return err
    98  	}
    99  	defer tpop.Release(t)
   100  	return t.Kernel().VFS().MkdirAt(t, t.Credentials(), &tpop.pop, &vfs.MkdirOptions{
   101  		Mode: linux.FileMode(mode & (0777 | linux.S_ISVTX) &^ t.FSContext().Umask()),
   102  	})
   103  }
   104  
   105  // Mknod implements Linux syscall mknod(2).
   106  func Mknod(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   107  	addr := args[0].Pointer()
   108  	mode := args[1].ModeT()
   109  	dev := args[2].Uint()
   110  	return 0, nil, mknodat(t, linux.AT_FDCWD, addr, linux.FileMode(mode), dev)
   111  }
   112  
   113  // Mknodat implements Linux syscall mknodat(2).
   114  func Mknodat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   115  	dirfd := args[0].Int()
   116  	addr := args[1].Pointer()
   117  	mode := args[2].ModeT()
   118  	dev := args[3].Uint()
   119  	return 0, nil, mknodat(t, dirfd, addr, linux.FileMode(mode), dev)
   120  }
   121  
   122  func mknodat(t *kernel.Task, dirfd int32, addr hostarch.Addr, mode linux.FileMode, dev uint32) error {
   123  	path, err := copyInPath(t, addr)
   124  	if err != nil {
   125  		return err
   126  	}
   127  	tpop, err := getTaskPathOperation(t, dirfd, path, disallowEmptyPath, nofollowFinalSymlink)
   128  	if err != nil {
   129  		return err
   130  	}
   131  	defer tpop.Release(t)
   132  
   133  	// "Zero file type is equivalent to type S_IFREG." - mknod(2)
   134  	if mode.FileType() == 0 {
   135  		mode |= linux.ModeRegular
   136  	}
   137  	major, minor := linux.DecodeDeviceID(dev)
   138  	return t.Kernel().VFS().MknodAt(t, t.Credentials(), &tpop.pop, &vfs.MknodOptions{
   139  		Mode:     mode &^ linux.FileMode(t.FSContext().Umask()),
   140  		DevMajor: uint32(major),
   141  		DevMinor: minor,
   142  	})
   143  }
   144  
   145  // Open implements Linux syscall open(2).
   146  func Open(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   147  	addr := args[0].Pointer()
   148  	flags := args[1].Uint()
   149  	mode := args[2].ModeT()
   150  	return openat(t, linux.AT_FDCWD, addr, flags, mode)
   151  }
   152  
   153  // Openat implements Linux syscall openat(2).
   154  func Openat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   155  	dirfd := args[0].Int()
   156  	addr := args[1].Pointer()
   157  	flags := args[2].Uint()
   158  	mode := args[3].ModeT()
   159  	return openat(t, dirfd, addr, flags, mode)
   160  }
   161  
   162  // Creat implements Linux syscall creat(2).
   163  func Creat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   164  	addr := args[0].Pointer()
   165  	mode := args[1].ModeT()
   166  	return openat(t, linux.AT_FDCWD, addr, linux.O_WRONLY|linux.O_CREAT|linux.O_TRUNC, mode)
   167  }
   168  
   169  func openat(t *kernel.Task, dirfd int32, pathAddr hostarch.Addr, flags uint32, mode uint) (uintptr, *kernel.SyscallControl, error) {
   170  	path, err := copyInPath(t, pathAddr)
   171  	if err != nil {
   172  		return 0, nil, err
   173  	}
   174  	tpop, err := getTaskPathOperation(t, dirfd, path, disallowEmptyPath, shouldFollowFinalSymlink(flags&linux.O_NOFOLLOW == 0))
   175  	if err != nil {
   176  		return 0, nil, err
   177  	}
   178  	defer tpop.Release(t)
   179  
   180  	file, err := t.Kernel().VFS().OpenAt(t, t.Credentials(), &tpop.pop, &vfs.OpenOptions{
   181  		Flags: flags | linux.O_LARGEFILE,
   182  		Mode:  linux.FileMode(mode & (0777 | linux.S_ISUID | linux.S_ISGID | linux.S_ISVTX) &^ t.FSContext().Umask()),
   183  	})
   184  	if err != nil {
   185  		return 0, nil, err
   186  	}
   187  	defer file.DecRef(t)
   188  
   189  	fd, err := t.NewFDFromVFS2(0, file, kernel.FDFlags{
   190  		CloseOnExec: flags&linux.O_CLOEXEC != 0,
   191  	})
   192  	return uintptr(fd), nil, err
   193  }
   194  
   195  // Rename implements Linux syscall rename(2).
   196  func Rename(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   197  	oldpathAddr := args[0].Pointer()
   198  	newpathAddr := args[1].Pointer()
   199  	return 0, nil, renameat(t, linux.AT_FDCWD, oldpathAddr, linux.AT_FDCWD, newpathAddr, 0 /* flags */)
   200  }
   201  
   202  // Renameat implements Linux syscall renameat(2).
   203  func Renameat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   204  	olddirfd := args[0].Int()
   205  	oldpathAddr := args[1].Pointer()
   206  	newdirfd := args[2].Int()
   207  	newpathAddr := args[3].Pointer()
   208  	return 0, nil, renameat(t, olddirfd, oldpathAddr, newdirfd, newpathAddr, 0 /* flags */)
   209  }
   210  
   211  // Renameat2 implements Linux syscall renameat2(2).
   212  func Renameat2(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   213  	olddirfd := args[0].Int()
   214  	oldpathAddr := args[1].Pointer()
   215  	newdirfd := args[2].Int()
   216  	newpathAddr := args[3].Pointer()
   217  	flags := args[4].Uint()
   218  	return 0, nil, renameat(t, olddirfd, oldpathAddr, newdirfd, newpathAddr, flags)
   219  }
   220  
   221  func renameat(t *kernel.Task, olddirfd int32, oldpathAddr hostarch.Addr, newdirfd int32, newpathAddr hostarch.Addr, flags uint32) error {
   222  	oldpath, err := copyInPath(t, oldpathAddr)
   223  	if err != nil {
   224  		return err
   225  	}
   226  	// "If oldpath refers to a symbolic link, the link is renamed" - rename(2)
   227  	oldtpop, err := getTaskPathOperation(t, olddirfd, oldpath, disallowEmptyPath, nofollowFinalSymlink)
   228  	if err != nil {
   229  		return err
   230  	}
   231  	defer oldtpop.Release(t)
   232  
   233  	newpath, err := copyInPath(t, newpathAddr)
   234  	if err != nil {
   235  		return err
   236  	}
   237  	newtpop, err := getTaskPathOperation(t, newdirfd, newpath, disallowEmptyPath, nofollowFinalSymlink)
   238  	if err != nil {
   239  		return err
   240  	}
   241  	defer newtpop.Release(t)
   242  
   243  	return t.Kernel().VFS().RenameAt(t, t.Credentials(), &oldtpop.pop, &newtpop.pop, &vfs.RenameOptions{
   244  		Flags: flags,
   245  	})
   246  }
   247  
   248  // Rmdir implements Linux syscall rmdir(2).
   249  func Rmdir(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   250  	pathAddr := args[0].Pointer()
   251  	return 0, nil, rmdirat(t, linux.AT_FDCWD, pathAddr)
   252  }
   253  
   254  func rmdirat(t *kernel.Task, dirfd int32, pathAddr hostarch.Addr) error {
   255  	path, err := copyInPath(t, pathAddr)
   256  	if err != nil {
   257  		return err
   258  	}
   259  	tpop, err := getTaskPathOperation(t, dirfd, path, disallowEmptyPath, nofollowFinalSymlink)
   260  	if err != nil {
   261  		return err
   262  	}
   263  	defer tpop.Release(t)
   264  	return t.Kernel().VFS().RmdirAt(t, t.Credentials(), &tpop.pop)
   265  }
   266  
   267  // Unlink implements Linux syscall unlink(2).
   268  func Unlink(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   269  	pathAddr := args[0].Pointer()
   270  	return 0, nil, unlinkat(t, linux.AT_FDCWD, pathAddr)
   271  }
   272  
   273  func unlinkat(t *kernel.Task, dirfd int32, pathAddr hostarch.Addr) error {
   274  	path, err := copyInPath(t, pathAddr)
   275  	if err != nil {
   276  		return err
   277  	}
   278  	tpop, err := getTaskPathOperation(t, dirfd, path, disallowEmptyPath, nofollowFinalSymlink)
   279  	if err != nil {
   280  		return err
   281  	}
   282  	defer tpop.Release(t)
   283  	return t.Kernel().VFS().UnlinkAt(t, t.Credentials(), &tpop.pop)
   284  }
   285  
   286  // Unlinkat implements Linux syscall unlinkat(2).
   287  func Unlinkat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   288  	dirfd := args[0].Int()
   289  	pathAddr := args[1].Pointer()
   290  	flags := args[2].Int()
   291  
   292  	if flags&^linux.AT_REMOVEDIR != 0 {
   293  		return 0, nil, linuxerr.EINVAL
   294  	}
   295  
   296  	if flags&linux.AT_REMOVEDIR != 0 {
   297  		return 0, nil, rmdirat(t, dirfd, pathAddr)
   298  	}
   299  	return 0, nil, unlinkat(t, dirfd, pathAddr)
   300  }
   301  
   302  // Symlink implements Linux syscall symlink(2).
   303  func Symlink(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   304  	targetAddr := args[0].Pointer()
   305  	linkpathAddr := args[1].Pointer()
   306  	return 0, nil, symlinkat(t, targetAddr, linux.AT_FDCWD, linkpathAddr)
   307  }
   308  
   309  // Symlinkat implements Linux syscall symlinkat(2).
   310  func Symlinkat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   311  	targetAddr := args[0].Pointer()
   312  	newdirfd := args[1].Int()
   313  	linkpathAddr := args[2].Pointer()
   314  	return 0, nil, symlinkat(t, targetAddr, newdirfd, linkpathAddr)
   315  }
   316  
   317  func symlinkat(t *kernel.Task, targetAddr hostarch.Addr, newdirfd int32, linkpathAddr hostarch.Addr) error {
   318  	target, err := t.CopyInString(targetAddr, linux.PATH_MAX)
   319  	if err != nil {
   320  		return err
   321  	}
   322  	if len(target) == 0 {
   323  		return syserror.ENOENT
   324  	}
   325  	linkpath, err := copyInPath(t, linkpathAddr)
   326  	if err != nil {
   327  		return err
   328  	}
   329  	tpop, err := getTaskPathOperation(t, newdirfd, linkpath, disallowEmptyPath, nofollowFinalSymlink)
   330  	if err != nil {
   331  		return err
   332  	}
   333  	defer tpop.Release(t)
   334  	return t.Kernel().VFS().SymlinkAt(t, t.Credentials(), &tpop.pop, target)
   335  }