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 }