github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/sentry/syscalls/linux/sys_timer.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  	"time"
    19  
    20  	"github.com/metacubex/gvisor/pkg/abi/linux"
    21  	"github.com/metacubex/gvisor/pkg/errors/linuxerr"
    22  	"github.com/metacubex/gvisor/pkg/sentry/arch"
    23  	"github.com/metacubex/gvisor/pkg/sentry/kernel"
    24  )
    25  
    26  const nsecPerSec = int64(time.Second)
    27  
    28  // Getitimer implements linux syscall getitimer(2).
    29  func Getitimer(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    30  	if t.Arch().Width() != 8 {
    31  		// Definition of linux.ItimerVal assumes 64-bit architecture.
    32  		return 0, nil, linuxerr.ENOSYS
    33  	}
    34  
    35  	timerID := args[0].Int()
    36  	addr := args[1].Pointer()
    37  
    38  	olditv, err := t.Getitimer(timerID)
    39  	if err != nil {
    40  		return 0, nil, err
    41  	}
    42  	// A NULL address is allowed, in which case no copy out takes place.
    43  	if addr == 0 {
    44  		return 0, nil, nil
    45  	}
    46  	_, err = olditv.CopyOut(t, addr)
    47  	return 0, nil, err
    48  }
    49  
    50  // Setitimer implements linux syscall setitimer(2).
    51  func Setitimer(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    52  	if t.Arch().Width() != 8 {
    53  		// Definition of linux.ItimerVal assumes 64-bit architecture.
    54  		return 0, nil, linuxerr.ENOSYS
    55  	}
    56  
    57  	timerID := args[0].Int()
    58  	newAddr := args[1].Pointer()
    59  	oldAddr := args[2].Pointer()
    60  
    61  	var newitv linux.ItimerVal
    62  	// A NULL address is allowed because because Linux allows
    63  	// setitimer(which, NULL, &old_value) which disables the timer. There is a
    64  	// KERN_WARN message saying this misfeature will be removed. However, that
    65  	// hasn't happened as of 3.19, so we continue to support it.
    66  	if newAddr != 0 {
    67  		if _, err := newitv.CopyIn(t, newAddr); err != nil {
    68  			return 0, nil, err
    69  		}
    70  	}
    71  	olditv, err := t.Setitimer(timerID, newitv)
    72  	if err != nil {
    73  		return 0, nil, err
    74  	}
    75  	// A NULL address is allowed, in which case no copy out takes place.
    76  	if oldAddr == 0 {
    77  		return 0, nil, nil
    78  	}
    79  	_, err = olditv.CopyOut(t, oldAddr)
    80  	return 0, nil, err
    81  }
    82  
    83  // Alarm implements linux syscall alarm(2).
    84  func Alarm(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    85  	duration := time.Duration(args[0].Uint()) * time.Second
    86  
    87  	olditv, err := t.Setitimer(linux.ITIMER_REAL, linux.ItimerVal{
    88  		Value: linux.DurationToTimeval(duration),
    89  	})
    90  	if err != nil {
    91  		return 0, nil, err
    92  	}
    93  	olddur := olditv.Value.ToDuration()
    94  	secs := olddur.Round(time.Second).Nanoseconds() / nsecPerSec
    95  	if secs == 0 && olddur != 0 {
    96  		// We can't return 0 if an alarm was previously scheduled.
    97  		secs = 1
    98  	}
    99  	return uintptr(secs), nil, nil
   100  }
   101  
   102  // TimerCreate implements linux syscall timer_create(2).
   103  func TimerCreate(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   104  	clockID := args[0].Int()
   105  	sevp := args[1].Pointer()
   106  	timerIDp := args[2].Pointer()
   107  
   108  	c, err := getClock(t, clockID)
   109  	if err != nil {
   110  		return 0, nil, err
   111  	}
   112  
   113  	var sev *linux.Sigevent
   114  	if sevp != 0 {
   115  		sev = &linux.Sigevent{}
   116  		if _, err = sev.CopyIn(t, sevp); err != nil {
   117  			return 0, nil, err
   118  		}
   119  	}
   120  
   121  	id, err := t.IntervalTimerCreate(c, sev)
   122  	if err != nil {
   123  		return 0, nil, err
   124  	}
   125  
   126  	if _, err := id.CopyOut(t, timerIDp); err != nil {
   127  		t.IntervalTimerDelete(id)
   128  		return 0, nil, err
   129  	}
   130  
   131  	return 0, nil, nil
   132  }
   133  
   134  // TimerSettime implements linux syscall timer_settime(2).
   135  func TimerSettime(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   136  	timerID := linux.TimerID(args[0].Value)
   137  	flags := args[1].Int()
   138  	newValAddr := args[2].Pointer()
   139  	oldValAddr := args[3].Pointer()
   140  
   141  	var newVal linux.Itimerspec
   142  	if _, err := newVal.CopyIn(t, newValAddr); err != nil {
   143  		return 0, nil, err
   144  	}
   145  	oldVal, err := t.IntervalTimerSettime(timerID, newVal, flags&linux.TIMER_ABSTIME != 0)
   146  	if err != nil {
   147  		return 0, nil, err
   148  	}
   149  	if oldValAddr != 0 {
   150  		_, err = oldVal.CopyOut(t, oldValAddr)
   151  		return 0, nil, err
   152  	}
   153  	return 0, nil, nil
   154  }
   155  
   156  // TimerGettime implements linux syscall timer_gettime(2).
   157  func TimerGettime(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   158  	timerID := linux.TimerID(args[0].Value)
   159  	curValAddr := args[1].Pointer()
   160  
   161  	curVal, err := t.IntervalTimerGettime(timerID)
   162  	if err != nil {
   163  		return 0, nil, err
   164  	}
   165  	_, err = curVal.CopyOut(t, curValAddr)
   166  	return 0, nil, err
   167  }
   168  
   169  // TimerGetoverrun implements linux syscall timer_getoverrun(2).
   170  func TimerGetoverrun(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   171  	timerID := linux.TimerID(args[0].Value)
   172  
   173  	o, err := t.IntervalTimerGetoverrun(timerID)
   174  	if err != nil {
   175  		return 0, nil, err
   176  	}
   177  	return uintptr(o), nil, nil
   178  }
   179  
   180  // TimerDelete implements linux syscall timer_delete(2).
   181  func TimerDelete(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   182  	timerID := linux.TimerID(args[0].Value)
   183  	return 0, nil, t.IntervalTimerDelete(timerID)
   184  }