github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/syscalls/linux/vfs2/inotify.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/sentry/arch"
    21  	"github.com/SagerNet/gvisor/pkg/sentry/kernel"
    22  	"github.com/SagerNet/gvisor/pkg/sentry/vfs"
    23  )
    24  
    25  const allFlags = linux.IN_NONBLOCK | linux.IN_CLOEXEC
    26  
    27  // InotifyInit1 implements the inotify_init1() syscalls.
    28  func InotifyInit1(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    29  	flags := args[0].Int()
    30  	if flags&^allFlags != 0 {
    31  		return 0, nil, linuxerr.EINVAL
    32  	}
    33  
    34  	ino, err := vfs.NewInotifyFD(t, t.Kernel().VFS(), uint32(flags))
    35  	if err != nil {
    36  		return 0, nil, err
    37  	}
    38  	defer ino.DecRef(t)
    39  
    40  	fd, err := t.NewFDFromVFS2(0, ino, kernel.FDFlags{
    41  		CloseOnExec: flags&linux.IN_CLOEXEC != 0,
    42  	})
    43  
    44  	if err != nil {
    45  		return 0, nil, err
    46  	}
    47  
    48  	return uintptr(fd), nil, nil
    49  }
    50  
    51  // InotifyInit implements the inotify_init() syscalls.
    52  func InotifyInit(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    53  	args[0].Value = 0
    54  	return InotifyInit1(t, args)
    55  }
    56  
    57  // fdToInotify resolves an fd to an inotify object. If successful, the file will
    58  // have an extra ref and the caller is responsible for releasing the ref.
    59  func fdToInotify(t *kernel.Task, fd int32) (*vfs.Inotify, *vfs.FileDescription, error) {
    60  	f := t.GetFileVFS2(fd)
    61  	if f == nil {
    62  		// Invalid fd.
    63  		return nil, nil, linuxerr.EBADF
    64  	}
    65  
    66  	ino, ok := f.Impl().(*vfs.Inotify)
    67  	if !ok {
    68  		// Not an inotify fd.
    69  		f.DecRef(t)
    70  		return nil, nil, linuxerr.EINVAL
    71  	}
    72  
    73  	return ino, f, nil
    74  }
    75  
    76  // InotifyAddWatch implements the inotify_add_watch() syscall.
    77  func InotifyAddWatch(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    78  	fd := args[0].Int()
    79  	addr := args[1].Pointer()
    80  	mask := args[2].Uint()
    81  
    82  	// "EINVAL: The given event mask contains no valid events."
    83  	// -- inotify_add_watch(2)
    84  	if mask&linux.ALL_INOTIFY_BITS == 0 {
    85  		return 0, nil, linuxerr.EINVAL
    86  	}
    87  
    88  	// "IN_DONT_FOLLOW: Don't dereference pathname if it is a symbolic link."
    89  	//  -- inotify(7)
    90  	follow := followFinalSymlink
    91  	if mask&linux.IN_DONT_FOLLOW == 0 {
    92  		follow = nofollowFinalSymlink
    93  	}
    94  
    95  	ino, f, err := fdToInotify(t, fd)
    96  	if err != nil {
    97  		return 0, nil, err
    98  	}
    99  	defer f.DecRef(t)
   100  
   101  	path, err := copyInPath(t, addr)
   102  	if err != nil {
   103  		return 0, nil, err
   104  	}
   105  	if mask&linux.IN_ONLYDIR != 0 {
   106  		path.Dir = true
   107  	}
   108  	tpop, err := getTaskPathOperation(t, linux.AT_FDCWD, path, disallowEmptyPath, follow)
   109  	if err != nil {
   110  		return 0, nil, err
   111  	}
   112  	defer tpop.Release(t)
   113  	d, err := t.Kernel().VFS().GetDentryAt(t, t.Credentials(), &tpop.pop, &vfs.GetDentryOptions{})
   114  	if err != nil {
   115  		return 0, nil, err
   116  	}
   117  	defer d.DecRef(t)
   118  
   119  	fd, err = ino.AddWatch(d.Dentry(), mask)
   120  	if err != nil {
   121  		return 0, nil, err
   122  	}
   123  	return uintptr(fd), nil, nil
   124  }
   125  
   126  // InotifyRmWatch implements the inotify_rm_watch() syscall.
   127  func InotifyRmWatch(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   128  	fd := args[0].Int()
   129  	wd := args[1].Int()
   130  
   131  	ino, f, err := fdToInotify(t, fd)
   132  	if err != nil {
   133  		return 0, nil, err
   134  	}
   135  	defer f.DecRef(t)
   136  	return 0, nil, ino.RmWatch(t, wd)
   137  }