pcontrol

package module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 6, 2024 License: Apache-2.0 Imports: 10 Imported by: 0

README

Control another process

pkg.go.dev Go Report Card pipeline status coverage report

A Go package that 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.

It was made for use in dinit to change stdout and stderr of running processes, but maybe it comes handy to somebody else as well.

Installation

This is a Go package. You can add it to your project using go get:

go get gitlab.com/tozd/go/pcontrol

It requires Go 1.23 or newer.

Usage

See full package documentation with examples on pkg.go.dev.

GitHub mirror

There is also a read-only GitHub mirror available, if you need to fork the project there.

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

Examples

Constants

View Source
const DefaultMemorySize = 4096

DefaultMemorySize is the default memory size of the allocated private working memory when attaching to the process.

Variables

View Source
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

func EqualFds

func EqualFds(fd1, fd2 int) (bool, errors.E)

EqualFds returns true if both file descriptors point to the same underlying file.

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

func (p *Process) Attach() (errE errors.E)

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

func (p *Process) Detach() errors.E

Detach detaches from the process and frees the allocated private working memory in it.

func (*Process) GetFds

func (p *Process) GetFds(processFds []int) (hostFds []int, errE errors.E)

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

func (p *Process) SetFd(hostFd int, processFd int) (errE errors.E)

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) SysAccept

func (p *Process) SysAccept(fd, flags int) (int, errors.E)

SysAccept invokes accept syscall in the (attached) process.

func (*Process) SysBindUnix

func (p *Process) SysBindUnix(fd int, path string) errors.E

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) SysClose

func (p *Process) SysClose(fd int) errors.E

SysClose invokes close syscall in the (attached) process.

func (*Process) SysConnectUnix

func (p *Process) SysConnectUnix(fd int, path string) errors.E

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) SysDup3 added in v0.2.0

func (p *Process) SysDup3(oldFd, newFd int) errors.E

SysDup3 invokes dup3 syscall in the (attached) process.

func (*Process) SysGetpid

func (p *Process) SysGetpid() (int, errors.E)

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) SysListen

func (p *Process) SysListen(fd, backlog int) errors.E

SysListen invokes listen syscall in the (attached) process.

func (*Process) SysRecvmsg

func (p *Process) SysRecvmsg(fd int, iov, control []byte, flags int) (int, int, int, errors.E)

SysRecvmsg invokes recvmsg syscall in the (attached) process.

func (*Process) SysSendmsg

func (p *Process) SysSendmsg(fd int, iov, control []byte, flags int) (int, int, errors.E)

SysSendmsg invokes sendmsg syscall in the (attached) process.

func (*Process) SysSocket

func (p *Process) SysSocket(domain, typ, proto int) (int, errors.E)

SysSocket invokes socket 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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL