github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/platform/systrap/systrap_unsafe.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 systrap
    16  
    17  import (
    18  	"unsafe"
    19  
    20  	"golang.org/x/sys/unix"
    21  	"github.com/nicocha30/gvisor-ligolo/pkg/abi/linux"
    22  	"github.com/nicocha30/gvisor-ligolo/pkg/hostarch"
    23  	"github.com/nicocha30/gvisor-ligolo/pkg/sentry/arch"
    24  )
    25  
    26  // getRegs gets the general purpose register set.
    27  func (t *thread) getRegs(regs *arch.Registers) error {
    28  	iovec := unix.Iovec{
    29  		Base: (*byte)(unsafe.Pointer(regs)),
    30  		Len:  uint64(unsafe.Sizeof(*regs)),
    31  	}
    32  	_, _, errno := unix.RawSyscall6(
    33  		unix.SYS_PTRACE,
    34  		unix.PTRACE_GETREGSET,
    35  		uintptr(t.tid),
    36  		linux.NT_PRSTATUS,
    37  		uintptr(unsafe.Pointer(&iovec)),
    38  		0, 0)
    39  	if errno != 0 {
    40  		return errno
    41  	}
    42  	return nil
    43  }
    44  
    45  // setRegs sets the general purpose register set.
    46  func (t *thread) setRegs(regs *arch.Registers) error {
    47  	iovec := unix.Iovec{
    48  		Base: (*byte)(unsafe.Pointer(regs)),
    49  		Len:  uint64(unsafe.Sizeof(*regs)),
    50  	}
    51  	_, _, errno := unix.RawSyscall6(
    52  		unix.SYS_PTRACE,
    53  		unix.PTRACE_SETREGSET,
    54  		uintptr(t.tid),
    55  		linux.NT_PRSTATUS,
    56  		uintptr(unsafe.Pointer(&iovec)),
    57  		0, 0)
    58  	if errno != 0 {
    59  		return errno
    60  	}
    61  	return nil
    62  }
    63  
    64  // getSignalInfo retrieves information about the signal that caused the stop.
    65  func (t *thread) getSignalInfo(si *linux.SignalInfo) error {
    66  	_, _, errno := unix.RawSyscall6(
    67  		unix.SYS_PTRACE,
    68  		unix.PTRACE_GETSIGINFO,
    69  		uintptr(t.tid),
    70  		0,
    71  		uintptr(unsafe.Pointer(si)),
    72  		0, 0)
    73  	if errno != 0 {
    74  		return errno
    75  	}
    76  	return nil
    77  }
    78  
    79  // clone creates a new sysmsg thread from this one.
    80  //
    81  // The returned thread will be stopped and available for any system thread to
    82  // call attach on it.
    83  //
    84  // Precondition: the OS thread must be locked and own t.
    85  func (t *thread) clone() (*thread, error) {
    86  	r, ok := hostarch.Addr(stackPointer(&t.initRegs)).RoundUp()
    87  	if !ok {
    88  		return nil, unix.EINVAL
    89  	}
    90  	var flags uintptr
    91  	// Create a sysmsg thread.
    92  	//
    93  	// CLONE_THREAD isn't set, because a stub process has SIGSTOP
    94  	// in its queue. A sysmsg thread will not be traced by ptrace,
    95  	// so it will be stopped immediately if it will share signal
    96  	// queue with its stub process.
    97  	flags = uintptr(
    98  		unix.CLONE_FILES |
    99  			unix.CLONE_FS |
   100  			unix.CLONE_PTRACE |
   101  			unix.CLONE_VM)
   102  	rval, err := t.syscallIgnoreInterrupt(
   103  		&t.initRegs,
   104  		unix.SYS_CLONE,
   105  		arch.SyscallArgument{Value: flags},
   106  		// The stack pointer is just made up, but we have it be
   107  		// something sensible so the kernel doesn't think we're
   108  		// up to no good. Which we are.
   109  		arch.SyscallArgument{Value: uintptr(r)},
   110  		arch.SyscallArgument{},
   111  		arch.SyscallArgument{},
   112  		// We use these registers initially, but really they
   113  		// could be anything. We're going to stop immediately.
   114  		arch.SyscallArgument{Value: uintptr(unsafe.Pointer(&t.initRegs))})
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  
   119  	return &thread{
   120  		tgid: int32(rval),
   121  		tid:  int32(rval),
   122  	}, nil
   123  }
   124  
   125  // getEventMessage retrieves a message about the ptrace event that just happened.
   126  func (t *thread) getEventMessage() (uintptr, error) {
   127  	var msg uintptr
   128  	_, _, errno := unix.RawSyscall6(
   129  		unix.SYS_PTRACE,
   130  		unix.PTRACE_GETEVENTMSG,
   131  		uintptr(t.tid),
   132  		0,
   133  		uintptr(unsafe.Pointer(&msg)),
   134  		0, 0)
   135  	if errno != 0 {
   136  		return msg, errno
   137  	}
   138  	return msg, nil
   139  }