2019-04-29 21:25:05 +00:00
|
|
|
// Copyright 2018 The gVisor Authors.
|
2018-04-27 17:37:02 +00:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package linux
|
|
|
|
|
|
|
|
import (
|
2019-09-30 17:02:14 +00:00
|
|
|
"fmt"
|
2018-04-27 17:37:02 +00:00
|
|
|
"time"
|
|
|
|
|
2019-06-13 23:49:09 +00:00
|
|
|
"gvisor.dev/gvisor/pkg/abi/linux"
|
|
|
|
"gvisor.dev/gvisor/pkg/sentry/arch"
|
|
|
|
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
|
|
|
ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time"
|
|
|
|
"gvisor.dev/gvisor/pkg/sentry/usermem"
|
|
|
|
"gvisor.dev/gvisor/pkg/syserror"
|
2018-04-27 17:37:02 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// The most significant 29 bits hold either a pid or a file descriptor.
|
|
|
|
func pidOfClockID(c int32) kernel.ThreadID {
|
|
|
|
return kernel.ThreadID(^(c >> 3))
|
|
|
|
}
|
|
|
|
|
|
|
|
// whichCPUClock returns one of CPUCLOCK_PERF, CPUCLOCK_VIRT, CPUCLOCK_SCHED or
|
|
|
|
// CLOCK_FD.
|
|
|
|
func whichCPUClock(c int32) int32 {
|
|
|
|
return c & linux.CPUCLOCK_CLOCK_MASK
|
|
|
|
}
|
|
|
|
|
|
|
|
// isCPUClockPerThread returns true if the CPUCLOCK_PERTHREAD bit is set in the
|
|
|
|
// clock id.
|
|
|
|
func isCPUClockPerThread(c int32) bool {
|
|
|
|
return c&linux.CPUCLOCK_PERTHREAD_MASK != 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// isValidCPUClock returns checks that the cpu clock id is valid.
|
|
|
|
func isValidCPUClock(c int32) bool {
|
|
|
|
// Bits 0, 1, and 2 cannot all be set.
|
|
|
|
if c&7 == 7 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if whichCPUClock(c) >= linux.CPUCLOCK_MAX {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// targetTask returns the kernel.Task for the given clock id.
|
|
|
|
func targetTask(t *kernel.Task, c int32) *kernel.Task {
|
|
|
|
pid := pidOfClockID(c)
|
|
|
|
if pid == 0 {
|
|
|
|
return t
|
|
|
|
}
|
|
|
|
return t.PIDNamespace().TaskWithID(pid)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ClockGetres implements linux syscall clock_getres(2).
|
|
|
|
func ClockGetres(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
|
|
|
clockID := int32(args[0].Int())
|
|
|
|
addr := args[1].Pointer()
|
|
|
|
r := linux.Timespec{
|
|
|
|
Sec: 0,
|
|
|
|
Nsec: 1,
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := getClock(t, clockID); err != nil {
|
|
|
|
return 0, nil, syserror.EINVAL
|
|
|
|
}
|
|
|
|
|
|
|
|
if addr == 0 {
|
|
|
|
// Don't need to copy out.
|
|
|
|
return 0, nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0, nil, copyTimespecOut(t, addr, &r)
|
|
|
|
}
|
|
|
|
|
|
|
|
type cpuClocker interface {
|
|
|
|
UserCPUClock() ktime.Clock
|
|
|
|
CPUClock() ktime.Clock
|
|
|
|
}
|
|
|
|
|
|
|
|
func getClock(t *kernel.Task, clockID int32) (ktime.Clock, error) {
|
|
|
|
if clockID < 0 {
|
|
|
|
if !isValidCPUClock(clockID) {
|
|
|
|
return nil, syserror.EINVAL
|
|
|
|
}
|
|
|
|
|
|
|
|
targetTask := targetTask(t, clockID)
|
|
|
|
if targetTask == nil {
|
|
|
|
return nil, syserror.EINVAL
|
|
|
|
}
|
|
|
|
|
|
|
|
var target cpuClocker
|
|
|
|
if isCPUClockPerThread(clockID) {
|
|
|
|
target = targetTask
|
|
|
|
} else {
|
|
|
|
target = targetTask.ThreadGroup()
|
|
|
|
}
|
|
|
|
|
|
|
|
switch whichCPUClock(clockID) {
|
|
|
|
case linux.CPUCLOCK_VIRT:
|
|
|
|
return target.UserCPUClock(), nil
|
|
|
|
case linux.CPUCLOCK_PROF, linux.CPUCLOCK_SCHED:
|
|
|
|
// CPUCLOCK_SCHED is approximated by CPUCLOCK_PROF.
|
|
|
|
return target.CPUClock(), nil
|
|
|
|
default:
|
|
|
|
return nil, syserror.EINVAL
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch clockID {
|
|
|
|
case linux.CLOCK_REALTIME, linux.CLOCK_REALTIME_COARSE:
|
|
|
|
return t.Kernel().RealtimeClock(), nil
|
2019-06-22 05:40:16 +00:00
|
|
|
case linux.CLOCK_MONOTONIC, linux.CLOCK_MONOTONIC_COARSE,
|
|
|
|
linux.CLOCK_MONOTONIC_RAW, linux.CLOCK_BOOTTIME:
|
2018-04-27 17:37:02 +00:00
|
|
|
// CLOCK_MONOTONIC approximates CLOCK_MONOTONIC_RAW.
|
2019-06-22 05:40:16 +00:00
|
|
|
// CLOCK_BOOTTIME is internally mapped to CLOCK_MONOTONIC, as:
|
2019-07-18 03:25:18 +00:00
|
|
|
// - CLOCK_BOOTTIME should behave as CLOCK_MONOTONIC while also
|
|
|
|
// including suspend time.
|
2019-06-22 05:40:16 +00:00
|
|
|
// - gVisor has no concept of suspend/resume.
|
2019-07-18 03:25:18 +00:00
|
|
|
// - CLOCK_MONOTONIC already includes save/restore time, which is
|
|
|
|
// the closest to suspend time.
|
2018-04-27 17:37:02 +00:00
|
|
|
return t.Kernel().MonotonicClock(), nil
|
|
|
|
case linux.CLOCK_PROCESS_CPUTIME_ID:
|
|
|
|
return t.ThreadGroup().CPUClock(), nil
|
|
|
|
case linux.CLOCK_THREAD_CPUTIME_ID:
|
|
|
|
return t.CPUClock(), nil
|
|
|
|
default:
|
|
|
|
return nil, syserror.EINVAL
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ClockGettime implements linux syscall clock_gettime(2).
|
|
|
|
func ClockGettime(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
|
|
|
clockID := int32(args[0].Int())
|
|
|
|
addr := args[1].Pointer()
|
|
|
|
|
|
|
|
c, err := getClock(t, clockID)
|
|
|
|
if err != nil {
|
|
|
|
return 0, nil, err
|
|
|
|
}
|
|
|
|
ts := c.Now().Timespec()
|
|
|
|
return 0, nil, copyTimespecOut(t, addr, &ts)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ClockSettime implements linux syscall clock_settime(2).
|
|
|
|
func ClockSettime(*kernel.Task, arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
|
|
|
return 0, nil, syserror.EPERM
|
|
|
|
}
|
|
|
|
|
|
|
|
// Time implements linux syscall time(2).
|
|
|
|
func Time(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
|
|
|
addr := args[0].Pointer()
|
|
|
|
|
|
|
|
r := t.Kernel().RealtimeClock().Now().TimeT()
|
|
|
|
if addr == usermem.Addr(0) {
|
|
|
|
return uintptr(r), nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := t.CopyOut(addr, r); err != nil {
|
|
|
|
return 0, nil, err
|
|
|
|
}
|
|
|
|
return uintptr(r), nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// clockNanosleepRestartBlock encapsulates the state required to restart
|
|
|
|
// clock_nanosleep(2) via restart_syscall(2).
|
2018-08-02 17:41:44 +00:00
|
|
|
//
|
|
|
|
// +stateify savable
|
2018-04-27 17:37:02 +00:00
|
|
|
type clockNanosleepRestartBlock struct {
|
|
|
|
c ktime.Clock
|
|
|
|
duration time.Duration
|
|
|
|
rem usermem.Addr
|
|
|
|
}
|
|
|
|
|
|
|
|
// Restart implements kernel.SyscallRestartBlock.Restart.
|
|
|
|
func (n *clockNanosleepRestartBlock) Restart(t *kernel.Task) (uintptr, error) {
|
|
|
|
return 0, clockNanosleepFor(t, n.c, n.duration, n.rem)
|
|
|
|
}
|
|
|
|
|
|
|
|
// clockNanosleepUntil blocks until a specified time.
|
|
|
|
//
|
|
|
|
// If blocking is interrupted, the syscall is restarted with the original
|
|
|
|
// arguments.
|
|
|
|
func clockNanosleepUntil(t *kernel.Task, c ktime.Clock, ts linux.Timespec) error {
|
|
|
|
notifier, tchan := ktime.NewChannelNotifier()
|
|
|
|
timer := ktime.NewTimer(c, notifier)
|
|
|
|
|
|
|
|
// Turn on the timer.
|
|
|
|
timer.Swap(ktime.Setting{
|
|
|
|
Period: 0,
|
|
|
|
Enabled: true,
|
|
|
|
Next: ktime.FromTimespec(ts),
|
|
|
|
})
|
|
|
|
|
|
|
|
err := t.BlockWithTimer(nil, tchan)
|
|
|
|
|
|
|
|
timer.Destroy()
|
|
|
|
|
|
|
|
// Did we just block until the timeout happened?
|
|
|
|
if err == syserror.ETIMEDOUT {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return syserror.ConvertIntr(err, kernel.ERESTARTNOHAND)
|
|
|
|
}
|
|
|
|
|
|
|
|
// clockNanosleepFor blocks for a specified duration.
|
|
|
|
//
|
|
|
|
// If blocking is interrupted, the syscall is restarted with the remaining
|
|
|
|
// duration timeout.
|
|
|
|
func clockNanosleepFor(t *kernel.Task, c ktime.Clock, dur time.Duration, rem usermem.Addr) error {
|
|
|
|
timer, start, tchan := ktime.After(c, dur)
|
|
|
|
|
|
|
|
err := t.BlockWithTimer(nil, tchan)
|
|
|
|
|
|
|
|
after := c.Now()
|
|
|
|
|
|
|
|
timer.Destroy()
|
|
|
|
|
2019-09-30 17:02:14 +00:00
|
|
|
switch err {
|
|
|
|
case syserror.ETIMEDOUT:
|
|
|
|
// Slept for entire timeout.
|
|
|
|
return nil
|
|
|
|
case syserror.ErrInterrupted:
|
|
|
|
// Interrupted.
|
|
|
|
remaining := dur - after.Sub(start)
|
2018-04-27 17:37:02 +00:00
|
|
|
if remaining < 0 {
|
|
|
|
remaining = time.Duration(0)
|
|
|
|
}
|
|
|
|
|
2019-09-30 17:02:14 +00:00
|
|
|
// Copy out remaining time.
|
|
|
|
if rem != 0 {
|
|
|
|
timeleft := linux.NsecToTimespec(remaining.Nanoseconds())
|
|
|
|
if err := copyTimespecOut(t, rem, &timeleft); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
2019-09-30 17:02:14 +00:00
|
|
|
// Arrange for a restart with the remaining duration.
|
2018-04-27 17:37:02 +00:00
|
|
|
t.SetSyscallRestartBlock(&clockNanosleepRestartBlock{
|
|
|
|
c: c,
|
|
|
|
duration: remaining,
|
|
|
|
rem: rem,
|
|
|
|
})
|
|
|
|
return kernel.ERESTART_RESTARTBLOCK
|
2019-09-30 17:02:14 +00:00
|
|
|
default:
|
|
|
|
panic(fmt.Sprintf("Impossible BlockWithTimer error %v", err))
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Nanosleep implements linux syscall Nanosleep(2).
|
|
|
|
func Nanosleep(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
|
|
|
addr := args[0].Pointer()
|
|
|
|
rem := args[1].Pointer()
|
|
|
|
|
|
|
|
ts, err := copyTimespecIn(t, addr)
|
|
|
|
if err != nil {
|
|
|
|
return 0, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if !ts.Valid() {
|
|
|
|
return 0, nil, syserror.EINVAL
|
|
|
|
}
|
|
|
|
|
|
|
|
// Just like linux, we cap the timeout with the max number that int64 can
|
|
|
|
// represent which is roughly 292 years.
|
|
|
|
dur := time.Duration(ts.ToNsecCapped()) * time.Nanosecond
|
|
|
|
return 0, nil, clockNanosleepFor(t, t.Kernel().MonotonicClock(), dur, rem)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ClockNanosleep implements linux syscall clock_nanosleep(2).
|
|
|
|
func ClockNanosleep(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
|
|
|
clockID := int32(args[0].Int())
|
|
|
|
flags := args[1].Int()
|
|
|
|
addr := args[2].Pointer()
|
|
|
|
rem := args[3].Pointer()
|
|
|
|
|
|
|
|
req, err := copyTimespecIn(t, addr)
|
|
|
|
if err != nil {
|
|
|
|
return 0, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if !req.Valid() {
|
|
|
|
return 0, nil, syserror.EINVAL
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only allow clock constants also allowed by Linux.
|
|
|
|
if clockID > 0 {
|
|
|
|
if clockID != linux.CLOCK_REALTIME &&
|
|
|
|
clockID != linux.CLOCK_MONOTONIC &&
|
|
|
|
clockID != linux.CLOCK_PROCESS_CPUTIME_ID {
|
|
|
|
return 0, nil, syserror.EINVAL
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
c, err := getClock(t, clockID)
|
|
|
|
if err != nil {
|
|
|
|
return 0, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if flags&linux.TIMER_ABSTIME != 0 {
|
|
|
|
return 0, nil, clockNanosleepUntil(t, c, req)
|
|
|
|
}
|
|
|
|
|
|
|
|
dur := time.Duration(req.ToNsecCapped()) * time.Nanosecond
|
|
|
|
return 0, nil, clockNanosleepFor(t, c, dur, rem)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Gettimeofday implements linux syscall gettimeofday(2).
|
|
|
|
func Gettimeofday(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
|
|
|
tv := args[0].Pointer()
|
|
|
|
tz := args[1].Pointer()
|
|
|
|
|
|
|
|
if tv != usermem.Addr(0) {
|
|
|
|
nowTv := t.Kernel().RealtimeClock().Now().Timeval()
|
|
|
|
if err := copyTimevalOut(t, tv, &nowTv); err != nil {
|
|
|
|
return 0, nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if tz != usermem.Addr(0) {
|
|
|
|
// Ask the time package for the timezone.
|
|
|
|
_, offset := time.Now().Zone()
|
|
|
|
// This int32 array mimics linux's struct timezone.
|
|
|
|
timezone := [2]int32{-int32(offset) / 60, 0}
|
|
|
|
_, err := t.CopyOut(tz, timezone)
|
|
|
|
return 0, nil, err
|
|
|
|
}
|
|
|
|
return 0, nil, nil
|
|
|
|
}
|