github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/syscalls/linux/vfs2/timerfd.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 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/fsimpl/timerfd"
    22  	"github.com/SagerNet/gvisor/pkg/sentry/kernel"
    23  	ktime "github.com/SagerNet/gvisor/pkg/sentry/kernel/time"
    24  )
    25  
    26  // TimerfdCreate implements Linux syscall timerfd_create(2).
    27  func TimerfdCreate(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    28  	clockID := args[0].Int()
    29  	flags := args[1].Int()
    30  
    31  	if flags&^(linux.TFD_CLOEXEC|linux.TFD_NONBLOCK) != 0 {
    32  		return 0, nil, linuxerr.EINVAL
    33  	}
    34  
    35  	// Timerfds aren't writable per se (their implementation of Write just
    36  	// returns EINVAL), but they are "opened for writing", which is necessary
    37  	// to actually reach said implementation of Write.
    38  	fileFlags := uint32(linux.O_RDWR)
    39  	if flags&linux.TFD_NONBLOCK != 0 {
    40  		fileFlags |= linux.O_NONBLOCK
    41  	}
    42  
    43  	var clock ktime.Clock
    44  	switch clockID {
    45  	case linux.CLOCK_REALTIME:
    46  		clock = t.Kernel().RealtimeClock()
    47  	case linux.CLOCK_MONOTONIC, linux.CLOCK_BOOTTIME:
    48  		clock = t.Kernel().MonotonicClock()
    49  	default:
    50  		return 0, nil, linuxerr.EINVAL
    51  	}
    52  	vfsObj := t.Kernel().VFS()
    53  	file, err := timerfd.New(t, vfsObj, clock, fileFlags)
    54  	if err != nil {
    55  		return 0, nil, err
    56  	}
    57  	defer file.DecRef(t)
    58  	fd, err := t.NewFDFromVFS2(0, file, kernel.FDFlags{
    59  		CloseOnExec: flags&linux.TFD_CLOEXEC != 0,
    60  	})
    61  	if err != nil {
    62  		return 0, nil, err
    63  	}
    64  	return uintptr(fd), nil, nil
    65  }
    66  
    67  // TimerfdSettime implements Linux syscall timerfd_settime(2).
    68  func TimerfdSettime(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    69  	fd := args[0].Int()
    70  	flags := args[1].Int()
    71  	newValAddr := args[2].Pointer()
    72  	oldValAddr := args[3].Pointer()
    73  
    74  	if flags&^(linux.TFD_TIMER_ABSTIME) != 0 {
    75  		return 0, nil, linuxerr.EINVAL
    76  	}
    77  
    78  	file := t.GetFileVFS2(fd)
    79  	if file == nil {
    80  		return 0, nil, linuxerr.EBADF
    81  	}
    82  	defer file.DecRef(t)
    83  
    84  	tfd, ok := file.Impl().(*timerfd.TimerFileDescription)
    85  	if !ok {
    86  		return 0, nil, linuxerr.EINVAL
    87  	}
    88  
    89  	var newVal linux.Itimerspec
    90  	if _, err := newVal.CopyIn(t, newValAddr); err != nil {
    91  		return 0, nil, err
    92  	}
    93  	newS, err := ktime.SettingFromItimerspec(newVal, flags&linux.TFD_TIMER_ABSTIME != 0, tfd.Clock())
    94  	if err != nil {
    95  		return 0, nil, err
    96  	}
    97  	tm, oldS := tfd.SetTime(newS)
    98  	if oldValAddr != 0 {
    99  		oldVal := ktime.ItimerspecFromSetting(tm, oldS)
   100  		if _, err := oldVal.CopyOut(t, oldValAddr); err != nil {
   101  			return 0, nil, err
   102  		}
   103  	}
   104  	return 0, nil, nil
   105  }
   106  
   107  // TimerfdGettime implements Linux syscall timerfd_gettime(2).
   108  func TimerfdGettime(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   109  	fd := args[0].Int()
   110  	curValAddr := args[1].Pointer()
   111  
   112  	file := t.GetFileVFS2(fd)
   113  	if file == nil {
   114  		return 0, nil, linuxerr.EBADF
   115  	}
   116  	defer file.DecRef(t)
   117  
   118  	tfd, ok := file.Impl().(*timerfd.TimerFileDescription)
   119  	if !ok {
   120  		return 0, nil, linuxerr.EINVAL
   121  	}
   122  
   123  	tm, s := tfd.GetTime()
   124  	curVal := ktime.ItimerspecFromSetting(tm, s)
   125  	_, err := curVal.CopyOut(t, curValAddr)
   126  	return 0, nil, err
   127  }