Documentation
¶
Overview ¶
Package pcontrol allows you to attach to a running process and call system calls from inside the attached process.
It works on Linux and internally uses ptrace.
Index ¶
- Constants
- Variables
- func EqualFds(fd1, fd2 int) (bool, errors.E)
- type Process
- func (p *Process) Attach() (errE errors.E)
- func (p *Process) Detach() errors.E
- func (p *Process) GetFds(processFds []int) (hostFds []int, errE errors.E)
- func (p *Process) SetFd(hostFd int, processFd int) (errE errors.E)
- func (p *Process) SysAccept(fd, flags int) (int, errors.E)
- func (p *Process) SysBindUnix(fd int, path string) errors.E
- func (p *Process) SysClose(fd int) errors.E
- func (p *Process) SysConnectUnix(fd int, path string) errors.E
- func (p *Process) SysDup3(oldFd, newFd int) errors.E
- func (p *Process) SysGetpid() (int, errors.E)
- func (p *Process) SysListen(fd, backlog int) errors.E
- func (p *Process) SysRecvmsg(fd int, iov, control []byte, flags int) (int, int, int, errors.E)
- func (p *Process) SysSendmsg(fd int, iov, control []byte, flags int) (int, int, errors.E)
- func (p *Process) SysSocket(domain, typ, proto int) (int, errors.E)
- func (p *Process) Syscall(call int, args func(start uint64) ([]byte, [6]uint64, errors.E)) (uint64, errors.E)
Examples ¶
Constants ¶
const DefaultMemorySize = 4096
DefaultMemorySize is the default memory size of the allocated private working memory when attaching to the process.
Variables ¶
var ( ErrProcessAlreadyAttached = errors.Base("process already attached") ErrProcessNotAttached = errors.Base("process not attached") ErrOutOfMemory = errors.Base("syscall payload is larger than available memory") ErrUnexpectedRead = errors.Base("unexpected bytes read") ErrUnexpectedWrite = errors.Base("unexpected bytes written") ErrUnexpectedWaitStatus = errors.Base("unexpected wait status") )
Functions ¶
Types ¶
type Process ¶
type Process struct { // Pid of the process to control (and attach to). Pid int // MemorySize of the allocated private working memory. Default is DefaultMemorySize. MemorySize uint64 // LogWarnf is a function to call with any warning logging messages. LogWarnf func(msg string, args ...any) // contains filtered or unexported fields }
func (*Process) Attach ¶
Attach attaches to the process and allocates private working memory in it.
While the process is attached to, its regular execution is paused and only signal processing happens in the process.
func (*Process) Detach ¶
Detach detaches from the process and frees the allocated private working memory in it.
func (*Process) GetFds ¶
GetFds does a cross-process duplication of file descriptors from the (attached) process into this (host) process.
It uses an abstract unix domain socket to get processFds from the process. If any of processFds are not found in the process, -1 is used in hostFds for it instead and no error is reported.
You should close processFds afterwards if they are not needed anymore in the (attached) process. Same for hostFds in this (host) process.
func (*Process) SetFd ¶
SetFd does a cross-process duplication of a file descriptor from this (host) process into the (attached) process.
It uses an abstract unix domain socket to send hostFd to the process and then dup3 syscall to set that file descriptor to processFd in the process (any previous processFd is closed by dup3).
You should close hostFd afterwards if it is not needed anymore in this (host) process. Same for processFd in the (attached) process.
func (*Process) SysBindUnix ¶
SysBindUnix invokes bind syscall in the (attached) process for AF_UNIX socket path.
If path starts with @, it is replaced with null character to bind to an abstract unix domain socket.
func (*Process) SysConnectUnix ¶
SysConnectUnix invokes connect syscall in the (attached) process for AF_UNIX socket path.
If path starts with @, it is replaced with null character to connect to an abstract unix domain socket.
func (*Process) SysGetpid ¶
Getpid invokes getpid syscall in the (attached) process.
Example ¶
cmd := exec.Command("/bin/sleep", "infinity") e := cmd.Start() if e != nil { panic(e) } defer cmd.Process.Wait() //nolint:errcheck defer cmd.Process.Kill() //nolint:errcheck p := Process{ Pid: cmd.Process.Pid, } err := p.Attach() if err != nil { panic(err) } defer func() { err = p.Detach() if err != nil { panic(err) } }() pid, err := p.SysGetpid() if err != nil { panic(err) } fmt.Println(cmd.Process.Pid == pid)
Output: true
func (*Process) SysRecvmsg ¶
SysRecvmsg invokes recvmsg syscall in the (attached) process.
func (*Process) SysSendmsg ¶
SysSendmsg invokes sendmsg syscall in the (attached) process.
func (*Process) Syscall ¶
func (p *Process) Syscall(call int, args func(start uint64) ([]byte, [6]uint64, errors.E)) (uint64, errors.E)
Syscall invokes a syscall with given arguments and returns its return value.
Arguments are returned from the args callback and can be provided through a byte slice or through 6 uint64 arguments. The byte slice is copied to the (attached) process memory (into allocated private working memory) at start and you can then reference that memory through 6 uint64 arguments.
Return value is -1 on error and a corresponding errno value is returned as error.