github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/syscalls/linux/sys_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 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/sentry/arch"
    21  	"github.com/SagerNet/gvisor/pkg/sentry/fs"
    22  	"github.com/SagerNet/gvisor/pkg/sentry/fs/timerfd"
    23  	"github.com/SagerNet/gvisor/pkg/sentry/kernel"
    24  	ktime "github.com/SagerNet/gvisor/pkg/sentry/kernel/time"
    25  )
    26  
    27  // TimerfdCreate implements Linux syscall timerfd_create(2).
    28  func TimerfdCreate(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    29  	clockID := args[0].Int()
    30  	flags := args[1].Int()
    31  
    32  	if flags&^(linux.TFD_CLOEXEC|linux.TFD_NONBLOCK) != 0 {
    33  		return 0, nil, linuxerr.EINVAL
    34  	}
    35  
    36  	var c ktime.Clock
    37  	switch clockID {
    38  	case linux.CLOCK_REALTIME:
    39  		c = t.Kernel().RealtimeClock()
    40  	case linux.CLOCK_MONOTONIC, linux.CLOCK_BOOTTIME:
    41  		c = t.Kernel().MonotonicClock()
    42  	default:
    43  		return 0, nil, linuxerr.EINVAL
    44  	}
    45  	f := timerfd.NewFile(t, c)
    46  	defer f.DecRef(t)
    47  	f.SetFlags(fs.SettableFileFlags{
    48  		NonBlocking: flags&linux.TFD_NONBLOCK != 0,
    49  	})
    50  
    51  	fd, err := t.NewFDFrom(0, f, kernel.FDFlags{
    52  		CloseOnExec: flags&linux.TFD_CLOEXEC != 0,
    53  	})
    54  	if err != nil {
    55  		return 0, nil, err
    56  	}
    57  
    58  	return uintptr(fd), nil, nil
    59  }
    60  
    61  // TimerfdSettime implements Linux syscall timerfd_settime(2).
    62  func TimerfdSettime(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    63  	fd := args[0].Int()
    64  	flags := args[1].Int()
    65  	newValAddr := args[2].Pointer()
    66  	oldValAddr := args[3].Pointer()
    67  
    68  	if flags&^(linux.TFD_TIMER_ABSTIME) != 0 {
    69  		return 0, nil, linuxerr.EINVAL
    70  	}
    71  
    72  	f := t.GetFile(fd)
    73  	if f == nil {
    74  		return 0, nil, linuxerr.EBADF
    75  	}
    76  	defer f.DecRef(t)
    77  
    78  	tf, ok := f.FileOperations.(*timerfd.TimerOperations)
    79  	if !ok {
    80  		return 0, nil, linuxerr.EINVAL
    81  	}
    82  
    83  	var newVal linux.Itimerspec
    84  	if _, err := newVal.CopyIn(t, newValAddr); err != nil {
    85  		return 0, nil, err
    86  	}
    87  	newS, err := ktime.SettingFromItimerspec(newVal, flags&linux.TFD_TIMER_ABSTIME != 0, tf.Clock())
    88  	if err != nil {
    89  		return 0, nil, err
    90  	}
    91  	tm, oldS := tf.SetTime(newS)
    92  	if oldValAddr != 0 {
    93  		oldVal := ktime.ItimerspecFromSetting(tm, oldS)
    94  		if _, err := oldVal.CopyOut(t, oldValAddr); err != nil {
    95  			return 0, nil, err
    96  		}
    97  	}
    98  	return 0, nil, nil
    99  }
   100  
   101  // TimerfdGettime implements Linux syscall timerfd_gettime(2).
   102  func TimerfdGettime(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   103  	fd := args[0].Int()
   104  	curValAddr := args[1].Pointer()
   105  
   106  	f := t.GetFile(fd)
   107  	if f == nil {
   108  		return 0, nil, linuxerr.EBADF
   109  	}
   110  	defer f.DecRef(t)
   111  
   112  	tf, ok := f.FileOperations.(*timerfd.TimerOperations)
   113  	if !ok {
   114  		return 0, nil, linuxerr.EINVAL
   115  	}
   116  
   117  	tm, s := tf.GetTime()
   118  	curVal := ktime.ItimerspecFromSetting(tm, s)
   119  	_, err := curVal.CopyOut(t, curValAddr)
   120  	return 0, nil, err
   121  }