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.
|
|
|
|
|
|
|
|
// +build amd64
|
|
|
|
|
|
|
|
package ptrace
|
|
|
|
|
|
|
|
import (
|
2019-06-12 17:47:38 +00:00
|
|
|
"fmt"
|
|
|
|
"strings"
|
2018-04-27 17:37:02 +00:00
|
|
|
"syscall"
|
|
|
|
|
2019-06-13 23:49:09 +00:00
|
|
|
"gvisor.dev/gvisor/pkg/sentry/arch"
|
2018-04-27 17:37:02 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// maximumUserAddress is the largest possible user address.
|
|
|
|
maximumUserAddress = 0x7ffffffff000
|
|
|
|
|
2019-08-09 20:16:46 +00:00
|
|
|
// stubInitAddress is the initial attempt link address for the stub.
|
|
|
|
stubInitAddress = 0x7fffffff0000
|
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
// initRegsRipAdjustment is the size of the syscall instruction.
|
|
|
|
initRegsRipAdjustment = 2
|
|
|
|
)
|
|
|
|
|
|
|
|
// resetSysemuRegs sets up emulation registers.
|
|
|
|
//
|
|
|
|
// This should be called prior to calling sysemu.
|
2018-10-11 05:39:32 +00:00
|
|
|
func (t *thread) resetSysemuRegs(regs *syscall.PtraceRegs) {
|
|
|
|
regs.Cs = t.initRegs.Cs
|
|
|
|
regs.Ss = t.initRegs.Ss
|
|
|
|
regs.Ds = t.initRegs.Ds
|
|
|
|
regs.Es = t.initRegs.Es
|
|
|
|
regs.Fs = t.initRegs.Fs
|
|
|
|
regs.Gs = t.initRegs.Gs
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// createSyscallRegs sets up syscall registers.
|
|
|
|
//
|
|
|
|
// This should be called to generate registers for a system call.
|
|
|
|
func createSyscallRegs(initRegs *syscall.PtraceRegs, sysno uintptr, args ...arch.SyscallArgument) syscall.PtraceRegs {
|
2018-10-11 05:39:32 +00:00
|
|
|
// Copy initial registers.
|
2018-04-27 17:37:02 +00:00
|
|
|
regs := *initRegs
|
|
|
|
|
|
|
|
// Set our syscall number.
|
|
|
|
regs.Rax = uint64(sysno)
|
|
|
|
if len(args) >= 1 {
|
|
|
|
regs.Rdi = args[0].Uint64()
|
|
|
|
}
|
|
|
|
if len(args) >= 2 {
|
|
|
|
regs.Rsi = args[1].Uint64()
|
|
|
|
}
|
|
|
|
if len(args) >= 3 {
|
|
|
|
regs.Rdx = args[2].Uint64()
|
|
|
|
}
|
|
|
|
if len(args) >= 4 {
|
|
|
|
regs.R10 = args[3].Uint64()
|
|
|
|
}
|
|
|
|
if len(args) >= 5 {
|
|
|
|
regs.R8 = args[4].Uint64()
|
|
|
|
}
|
|
|
|
if len(args) >= 6 {
|
|
|
|
regs.R9 = args[5].Uint64()
|
|
|
|
}
|
|
|
|
|
|
|
|
return regs
|
|
|
|
}
|
|
|
|
|
|
|
|
// isSingleStepping determines if the registers indicate single-stepping.
|
|
|
|
func isSingleStepping(regs *syscall.PtraceRegs) bool {
|
|
|
|
return (regs.Eflags & arch.X86TrapFlag) != 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// updateSyscallRegs updates registers after finishing sysemu.
|
|
|
|
func updateSyscallRegs(regs *syscall.PtraceRegs) {
|
|
|
|
// Ptrace puts -ENOSYS in rax on syscall-enter-stop.
|
|
|
|
regs.Rax = regs.Orig_rax
|
|
|
|
}
|
|
|
|
|
|
|
|
// syscallReturnValue extracts a sensible return from registers.
|
|
|
|
func syscallReturnValue(regs *syscall.PtraceRegs) (uintptr, error) {
|
|
|
|
rval := int64(regs.Rax)
|
|
|
|
if rval < 0 {
|
|
|
|
return 0, syscall.Errno(-rval)
|
|
|
|
}
|
|
|
|
return uintptr(rval), nil
|
|
|
|
}
|
2019-06-12 17:47:38 +00:00
|
|
|
|
|
|
|
func dumpRegs(regs *syscall.PtraceRegs) string {
|
|
|
|
var m strings.Builder
|
|
|
|
|
|
|
|
fmt.Fprintf(&m, "Registers:\n")
|
|
|
|
fmt.Fprintf(&m, "\tR15\t = %016x\n", regs.R15)
|
|
|
|
fmt.Fprintf(&m, "\tR14\t = %016x\n", regs.R14)
|
|
|
|
fmt.Fprintf(&m, "\tR13\t = %016x\n", regs.R13)
|
|
|
|
fmt.Fprintf(&m, "\tR12\t = %016x\n", regs.R12)
|
|
|
|
fmt.Fprintf(&m, "\tRbp\t = %016x\n", regs.Rbp)
|
|
|
|
fmt.Fprintf(&m, "\tRbx\t = %016x\n", regs.Rbx)
|
|
|
|
fmt.Fprintf(&m, "\tR11\t = %016x\n", regs.R11)
|
|
|
|
fmt.Fprintf(&m, "\tR10\t = %016x\n", regs.R10)
|
|
|
|
fmt.Fprintf(&m, "\tR9\t = %016x\n", regs.R9)
|
|
|
|
fmt.Fprintf(&m, "\tR8\t = %016x\n", regs.R8)
|
|
|
|
fmt.Fprintf(&m, "\tRax\t = %016x\n", regs.Rax)
|
|
|
|
fmt.Fprintf(&m, "\tRcx\t = %016x\n", regs.Rcx)
|
|
|
|
fmt.Fprintf(&m, "\tRdx\t = %016x\n", regs.Rdx)
|
|
|
|
fmt.Fprintf(&m, "\tRsi\t = %016x\n", regs.Rsi)
|
|
|
|
fmt.Fprintf(&m, "\tRdi\t = %016x\n", regs.Rdi)
|
|
|
|
fmt.Fprintf(&m, "\tOrig_rax = %016x\n", regs.Orig_rax)
|
|
|
|
fmt.Fprintf(&m, "\tRip\t = %016x\n", regs.Rip)
|
|
|
|
fmt.Fprintf(&m, "\tCs\t = %016x\n", regs.Cs)
|
|
|
|
fmt.Fprintf(&m, "\tEflags\t = %016x\n", regs.Eflags)
|
|
|
|
fmt.Fprintf(&m, "\tRsp\t = %016x\n", regs.Rsp)
|
|
|
|
fmt.Fprintf(&m, "\tSs\t = %016x\n", regs.Ss)
|
|
|
|
fmt.Fprintf(&m, "\tFs_base\t = %016x\n", regs.Fs_base)
|
|
|
|
fmt.Fprintf(&m, "\tGs_base\t = %016x\n", regs.Gs_base)
|
|
|
|
fmt.Fprintf(&m, "\tDs\t = %016x\n", regs.Ds)
|
|
|
|
fmt.Fprintf(&m, "\tEs\t = %016x\n", regs.Es)
|
|
|
|
fmt.Fprintf(&m, "\tFs\t = %016x\n", regs.Fs)
|
|
|
|
fmt.Fprintf(&m, "\tGs\t = %016x\n", regs.Gs)
|
|
|
|
|
|
|
|
return m.String()
|
|
|
|
}
|
2019-08-09 20:16:46 +00:00
|
|
|
|
|
|
|
// adjustInitregsRip adjust the current register RIP value to
|
|
|
|
// be just before the system call instruction excution
|
|
|
|
func (t *thread) adjustInitRegsRip() {
|
|
|
|
t.initRegs.Rip -= initRegsRipAdjustment
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pass the expected PPID to the child via R15 when creating stub process
|
|
|
|
func initChildProcessPPID(initregs *syscall.PtraceRegs, ppid int32) {
|
|
|
|
initregs.R15 = uint64(ppid)
|
|
|
|
}
|