WIP: Golang Proot code #1
@@ -37,13 +37,13 @@ typedef struct binding {
|
||||
bool must_exist;
|
||||
|
||||
struct {
|
||||
CIRCLEQ_ENTRY(binding) pending;
|
||||
CIRCLEQ_ENTRY(binding) guest;
|
||||
CIRCLEQ_ENTRY(binding) host;
|
||||
struct { struct binding *cqe_next; struct binding *cqe_prev; } pending;
|
||||
struct { struct binding *cqe_next; struct binding *cqe_prev; } guest;
|
||||
struct { struct binding *cqe_next; struct binding *cqe_prev; } host;
|
||||
} link;
|
||||
} Binding;
|
||||
|
||||
typedef CIRCLEQ_HEAD(bindings, binding) Bindings;
|
||||
typedef struct bindings { struct binding *cqh_first; struct binding *cqh_last; } Bindings;
|
||||
|
||||
extern Binding *insort_binding3(const Tracee *tracee, const TALLOC_CTX *context,
|
||||
const char host_path[PATH_MAX], const char guest_path[PATH_MAX]);
|
||||
|
@@ -48,8 +48,7 @@
|
||||
* Compute the offset of the register @reg_name in the USER area.
|
||||
*/
|
||||
#define USER_REGS_OFFSET(reg_name) \
|
||||
(offsetof(struct user, regs) \
|
||||
+ offsetof(struct user_regs_struct, reg_name))
|
||||
(offsetof(struct user, regs) + offsetof(struct user_regs_struct, reg_name))
|
||||
|
||||
#define REG(tracee, version, index) \
|
||||
(*(word_t*) (((uint8_t *) &tracee->_regs[version]) + reg_offset[index]))
|
||||
@@ -182,8 +181,7 @@ word_t peek_reg(const Tracee *tracee, RegVersion version, Reg reg)
|
||||
|
||||
result = REG(tracee, version, reg);
|
||||
|
||||
/* Use only the 32 least significant bits (LSB) when running
|
||||
* 32-bit processes on a 64-bit kernel. */
|
||||
/* Use only the 32 least significant bits (LSB) when running 32-bit processes on a 64-bit kernel. */
|
||||
if (is_32on64_mode(tracee))
|
||||
result &= 0xFFFFFFFF;
|
||||
|
||||
|
@@ -93,7 +93,7 @@ typedef struct tracee {
|
||||
**********************************************************************/
|
||||
|
||||
/* Link for the list of all tracees. */
|
||||
LIST_ENTRY(tracee) link;
|
||||
struct { struct tracee *le_next; struct tracee **le_prev; } link;
|
||||
|
||||
/* Process identifier. */
|
||||
pid_t pid;
|
||||
|
233
proot/proot/execve/elf.go
Normal file
233
proot/proot/execve/elf.go
Normal file
@@ -0,0 +1,233 @@
|
||||
package execve
|
||||
|
||||
/*
|
||||
#define EI_NIDENT 16
|
||||
|
||||
typedef struct {
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
uint16_t e_type;
|
||||
uint16_t e_machine;
|
||||
uint32_t e_version;
|
||||
uint32_t e_entry;
|
||||
uint32_t e_phoff;
|
||||
uint32_t e_shoff;
|
||||
uint32_t e_flags;
|
||||
uint16_t e_ehsize;
|
||||
uint16_t e_phentsize;
|
||||
uint16_t e_phnum;
|
||||
uint16_t e_shentsize;
|
||||
uint16_t e_shnum;
|
||||
uint16_t e_shstrndx;
|
||||
} ElfHeader32;
|
||||
|
||||
typedef struct {
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
uint16_t e_type;
|
||||
uint16_t e_machine;
|
||||
uint32_t e_version;
|
||||
uint64_t e_entry;
|
||||
uint64_t e_phoff;
|
||||
uint64_t e_shoff;
|
||||
uint32_t e_flags;
|
||||
uint16_t e_ehsize;
|
||||
uint16_t e_phentsize;
|
||||
uint16_t e_phnum;
|
||||
uint16_t e_shentsize;
|
||||
uint16_t e_shnum;
|
||||
uint16_t e_shstrndx;
|
||||
} ElfHeader64;
|
||||
|
||||
typedef union {
|
||||
ElfHeader32 class32;
|
||||
ElfHeader64 class64;
|
||||
} ElfHeader;
|
||||
|
||||
typedef struct {
|
||||
uint32_t p_type;
|
||||
uint32_t p_offset;
|
||||
uint32_t p_vaddr;
|
||||
uint32_t p_paddr;
|
||||
uint32_t p_filesz;
|
||||
uint32_t p_memsz;
|
||||
uint32_t p_flags;
|
||||
uint32_t p_align;
|
||||
} ProgramHeader32;
|
||||
|
||||
typedef struct {
|
||||
uint32_t p_type;
|
||||
uint32_t p_flags;
|
||||
uint64_t p_offset;
|
||||
uint64_t p_vaddr;
|
||||
uint64_t p_paddr;
|
||||
uint64_t p_filesz;
|
||||
uint64_t p_memsz;
|
||||
uint64_t p_align;
|
||||
} ProgramHeader64;
|
||||
|
||||
typedef union {
|
||||
ProgramHeader32 class32;
|
||||
ProgramHeader64 class64;
|
||||
} ProgramHeader;
|
||||
|
||||
// Object type:
|
||||
#define ET_REL 1
|
||||
#define ET_EXEC 2
|
||||
#define ET_DYN 3
|
||||
#define ET_CORE 4
|
||||
|
||||
// Segment flags:
|
||||
#define PF_X 1
|
||||
#define PF_W 2
|
||||
#define PF_R 4
|
||||
|
||||
typedef enum {
|
||||
PT_LOAD = 1,
|
||||
PT_DYNAMIC = 2,
|
||||
PT_INTERP = 3,
|
||||
PT_GNU_STACK = 0x6474e551,
|
||||
} SegmentType;
|
||||
|
||||
typedef struct {
|
||||
int32_t d_tag;
|
||||
uint32_t d_val;
|
||||
} DynamicEntry32;
|
||||
|
||||
typedef struct {
|
||||
int64_t d_tag;
|
||||
uint64_t d_val;
|
||||
} DynamicEntry64;
|
||||
|
||||
typedef union {
|
||||
DynamicEntry32 class32;
|
||||
DynamicEntry64 class64;
|
||||
} DynamicEntry;
|
||||
|
||||
typedef enum {
|
||||
DT_STRTAB = 5,
|
||||
DT_RPATH = 15,
|
||||
DT_RUNPATH = 29
|
||||
} DynamicType;
|
||||
|
||||
// The following macros are also compatible with ELF 64-bit.
|
||||
#define ELF_IDENT(header, index) (header).class32.e_ident[(index)]
|
||||
#define ELF_CLASS(header) ELF_IDENT(header, 4)
|
||||
#define IS_CLASS32(header) (ELF_CLASS(header) == 1)
|
||||
#define IS_CLASS64(header) (ELF_CLASS(header) == 2)
|
||||
|
||||
// Helper to access a @field of the structure ElfHeaderXX.
|
||||
#define ELF_FIELD(header, field) \
|
||||
(IS_CLASS64(header) \
|
||||
? (header).class64. e_ ## field \
|
||||
: (header).class32. e_ ## field)
|
||||
|
||||
// Helper to access a @field of the structure ProgramHeaderXX
|
||||
#define PROGRAM_FIELD(ehdr, phdr, field) \
|
||||
(IS_CLASS64(ehdr) \
|
||||
? (phdr).class64. p_ ## field \
|
||||
: (phdr).class32. p_ ## field)
|
||||
|
||||
// Helper to access a @field of the structure DynamicEntryXX
|
||||
#define DYNAMIC_FIELD(ehdr, dynent, field) \
|
||||
(IS_CLASS64(ehdr) \
|
||||
? (dynent).class64. d_ ## field \
|
||||
: (dynent).class32. d_ ## field)
|
||||
|
||||
#define KNOWN_PHENTSIZE(header, size) \
|
||||
( (IS_CLASS32(header) && (size) == sizeof(ProgramHeader32)) \
|
||||
|| (IS_CLASS64(header) && (size) == sizeof(ProgramHeader64)))
|
||||
|
||||
#define IS_POSITION_INDENPENDANT(elf_header) \
|
||||
(ELF_FIELD((elf_header), type) == ET_DYN)
|
||||
|
||||
*/
|
||||
|
||||
const EI_NIDENT = 16
|
||||
|
||||
type ElfHeader32 struct {
|
||||
Ident [EI_NIDENT]byte
|
||||
Type uint16
|
||||
Machine uint16
|
||||
Version uint32
|
||||
Entry uint32
|
||||
Phoff uint32
|
||||
Shoff uint32
|
||||
Flags uint32
|
||||
Ehsize uint16
|
||||
Phentsize uint16
|
||||
Phnum uint16
|
||||
Shentsize uint16
|
||||
Shnum uint16
|
||||
Shstrndx uint16
|
||||
}
|
||||
|
||||
type ElfHeader64 struct {
|
||||
Ident [EI_NIDENT]byte
|
||||
Type uint16
|
||||
Machine uint16
|
||||
Version uint32
|
||||
Entry uint64
|
||||
Phoff uint64
|
||||
Shoff uint64
|
||||
Flags uint32
|
||||
Ehsize uint16
|
||||
Phentsize uint16
|
||||
Phnum uint16
|
||||
Shentsize uint16
|
||||
Shnum uint16
|
||||
Shstrndx uint16
|
||||
}
|
||||
|
||||
type ElfHeader struct {
|
||||
class32 ElfHeader32
|
||||
class64 ElfHeader64
|
||||
}
|
||||
|
||||
type ProgramHeader32 struct {
|
||||
Type uint32
|
||||
Offset uint32
|
||||
Vaddr uint32
|
||||
Paddr uint32
|
||||
Filesz uint32
|
||||
Memsz uint32
|
||||
Flags uint32
|
||||
Align uint32
|
||||
}
|
||||
|
||||
type ProgramHeader64 struct {
|
||||
Type uint32
|
||||
Flags uint32
|
||||
Offset uint64
|
||||
Vaddr uint64
|
||||
Paddr uint64
|
||||
Filesz uint64
|
||||
Memsz uint64
|
||||
Align uint64
|
||||
}
|
||||
|
||||
type ProgramHeader struct {
|
||||
class32 ProgramHeader32
|
||||
class64 ProgramHeader64
|
||||
}
|
||||
|
||||
type DynamicEntry32 struct {
|
||||
Tag int32
|
||||
Val uint32
|
||||
}
|
||||
|
||||
type DynamicEntry64 struct {
|
||||
Tag int64
|
||||
Val uint64
|
||||
}
|
||||
|
||||
type DynamicEntry struct {
|
||||
class32 DynamicEntry32
|
||||
class64 DynamicEntry64
|
||||
}
|
||||
|
||||
type DynamicType int32
|
||||
|
||||
const (
|
||||
DT_STRTAB DynamicType = 5
|
||||
DT_RPATH DynamicType = 15
|
||||
DT_RUNPATH DynamicType = 29
|
||||
)
|
14
proot/proot/execve/execve.go
Normal file
14
proot/proot/execve/execve.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package execve
|
||||
|
||||
type Mapping struct {
|
||||
Addr, Lenght, ClearLength, Prot, Flags, FD, Offset uint64
|
||||
}
|
||||
|
||||
type LoadInfo struct {
|
||||
HostPath, UserPath, RawPath string
|
||||
Mappings *Mapping
|
||||
ElfHeader *ElfHeader
|
||||
needsExecutableStack bool
|
||||
|
||||
Interp *LoadInfo
|
||||
}
|
31
proot/proot/path/binding.go
Normal file
31
proot/proot/path/binding.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package path
|
||||
|
||||
type LinkBinding struct {
|
||||
Next, Prev *Binding
|
||||
}
|
||||
|
||||
type Binding struct {
|
||||
Host, Guest Path
|
||||
|
||||
NeedSubstitution, MustExist bool
|
||||
|
||||
Link struct {
|
||||
Pending, Guest, Host LinkBinding
|
||||
}
|
||||
}
|
||||
|
||||
// struct bindings { struct binding *cqh_first; struct binding *cqh_last; } Bindings
|
||||
type Bindings struct {
|
||||
First, Last *Binding
|
||||
}
|
||||
|
||||
/*
|
||||
extern Binding *insort_binding3(const Tracee *tracee, const TALLOC_CTX *context, const char host_path[PATH_MAX], const char guest_path[PATH_MAX]);
|
||||
extern Binding *new_binding(Tracee *tracee, const char *host, const char *guest, bool must_exist);
|
||||
extern int initialize_bindings(Tracee *tracee);
|
||||
extern const char *get_path_binding(const Tracee* tracee, Side side, const char path[PATH_MAX]);
|
||||
extern Binding *get_binding(const Tracee *tracee, Side side, const char path[PATH_MAX]);
|
||||
extern const char *get_root(const Tracee* tracee);
|
||||
extern int substitute_binding(const Tracee* tracee, Side side, char path[PATH_MAX]);
|
||||
extern void remove_binding_from_all_lists(const Tracee *tracee, Binding *binding);
|
||||
*/
|
3
proot/proot/path/glue.go
Normal file
3
proot/proot/path/glue.go
Normal file
@@ -0,0 +1,3 @@
|
||||
package path
|
||||
|
||||
// extern mode_t build_glue(Tracee *tracee, const char *guest_path, char host_path[PATH_MAX], Finality finality);
|
76
proot/proot/path/path.go
Normal file
76
proot/proot/path/path.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package path
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type Side int
|
||||
type Type int
|
||||
type Finality int
|
||||
type Comparison int
|
||||
|
||||
const (
|
||||
Guest Side = iota
|
||||
Host
|
||||
|
||||
// Used for bindings as specified by the user but not canonicalized yet (new_binding, initialize_binding).
|
||||
Pedding
|
||||
)
|
||||
|
||||
// Type type
|
||||
const (
|
||||
Regular Type = iota
|
||||
Symlink
|
||||
)
|
||||
|
||||
// Path ending type.
|
||||
const (
|
||||
NOT_FINAL Finality = iota
|
||||
FINAL_NORMAL
|
||||
FINAL_SLASH
|
||||
FINAL_DOT
|
||||
)
|
||||
|
||||
// Comparison between two paths.
|
||||
const (
|
||||
PATHS_ARE_EQUAL Comparison = iota
|
||||
PATH1_IS_PREFIX
|
||||
PATH2_IS_PREFIX
|
||||
PATHS_ARE_NOT_COMPARABLE
|
||||
)
|
||||
|
||||
type Path struct {
|
||||
Path [syscall.PathMax]byte
|
||||
Length int
|
||||
Side Side
|
||||
}
|
||||
|
||||
/*
|
||||
extern int which(Tracee *tracee, const char *paths, char host_path[PATH_MAX], const char *command);
|
||||
extern int realpath2(Tracee *tracee, char host_path[PATH_MAX], const char *path, bool deref_final);
|
||||
extern int getcwd2(Tracee *tracee, char guest_path[PATH_MAX]);
|
||||
extern void chop_finality(char *path);
|
||||
|
||||
extern int translate_path(Tracee *tracee, char host_path[PATH_MAX], int dir_fd, const char *guest_path, bool deref_final);
|
||||
|
||||
extern int detranslate_path(Tracee *tracee, char path[PATH_MAX], const char t_referrer[PATH_MAX]);
|
||||
extern bool belongs_to_guestfs(const Tracee *tracee, const char *path);
|
||||
|
||||
extern int join_paths(int number_paths, char result[PATH_MAX], ...);
|
||||
extern int list_open_fd(const Tracee *tracee);
|
||||
|
||||
extern Comparison compare_paths(const char *path1, const char *path2);
|
||||
extern Comparison compare_paths2(const char *path1, size_t length1, const char *path2, size_t length2);
|
||||
|
||||
extern size_t substitute_path_prefix(char path[PATH_MAX], size_t old_prefix_length, const char *new_prefix, size_t new_prefix_length);
|
||||
|
||||
extern int readlink_proc_pid_fd(pid_t pid, int fd, char path[PATH_MAX]);
|
||||
*/
|
||||
|
||||
// #define AT_FD(dirfd, path) ((dirfd) != AT_FDCWD && ((path) != NULL && (path)[0] != '/'))
|
||||
/* Check if path interpretable relatively to dirfd, see openat(2) for details. */
|
||||
func IsAtFD(dirfd int, path string) bool {
|
||||
return dirfd != unix.AT_FDCWD && path[0] != '/'
|
||||
}
|
16
proot/proot/path/proc.go
Normal file
16
proot/proot/path/proc.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package path
|
||||
|
||||
type Action int
|
||||
|
||||
// Action to do after a call to readlink_proc().
|
||||
const (
|
||||
DEFAULT Action = iota // Nothing special to do, treat it as a regular link.
|
||||
CANONICALIZE // The symlink was dereferenced, now canonicalize it.
|
||||
DONT_CANONICALIZE // The symlink shouldn't be dereferenced nor canonicalized.
|
||||
)
|
||||
|
||||
/*
|
||||
extern Action readlink_proc(const Tracee *tracee, char result[PATH_MAX], const char path[PATH_MAX], const char component[NAME_MAX], Comparison comparison);
|
||||
|
||||
extern ssize_t readlink_proc2(const Tracee *tracee, char result[PATH_MAX], const char path[PATH_MAX]);
|
||||
*/
|
40
proot/proot/syscall/syscall.go
Normal file
40
proot/proot/syscall/syscall.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package syscall
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
origin_tracee "sirherobrine23.com.br/go-bds/exec/proot/proot/tracee"
|
||||
)
|
||||
|
||||
type Tracee origin_tracee.Tracee
|
||||
|
||||
func (tracee *Tracee) TranslateSyscall() {
|
||||
isEnterStage := tracee.Status == 0
|
||||
if tracee.Exe == "" {
|
||||
panic("Empty exe")
|
||||
}
|
||||
|
||||
if err := (*origin_tracee.Tracee)(tracee).FetchRegs(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var status error
|
||||
if isEnterStage {
|
||||
if tracee.Chain.Syscalls == nil {
|
||||
(*origin_tracee.Tracee)(tracee).SaveCurrentRegs(origin_tracee.ORIGINAL)
|
||||
// status = tracee.TranslateSyscallEnter()
|
||||
(*origin_tracee.Tracee)(tracee).SaveCurrentRegs(origin_tracee.MODIFIED)
|
||||
} else {
|
||||
// notify_extensions
|
||||
// status = (*origin_tracee.Tracee)(tracee).NotifyExtensions()
|
||||
tracee.RestartHow = unix.PTRACE_SYSCALL
|
||||
}
|
||||
|
||||
if status != nil {
|
||||
// tracee.SetSysnum(origin_tracee.PR_void)
|
||||
(*origin_tracee.Tracee)(tracee).PokeReg(origin_tracee.CURRENT, origin_tracee.SYSARG_RESULT, uint64(status.(syscall.Errno)))
|
||||
tracee.Status = int(status.(syscall.Errno))
|
||||
}
|
||||
}
|
||||
}
|
19
proot/proot/tracee/abi.go
Normal file
19
proot/proot/tracee/abi.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package tracee
|
||||
|
||||
import "unsafe"
|
||||
|
||||
type Abi uint8
|
||||
|
||||
const (
|
||||
ABI_DEFAULT Abi = iota
|
||||
ABI_2 // x86_32 on x86_64.
|
||||
ABI_3 // x32 on x86_64.
|
||||
NB_MAX_ABIS
|
||||
)
|
||||
|
||||
func (tracee *Tracee) SizeofWord() int {
|
||||
if tracee.Is32On64() {
|
||||
return int(unsafe.Sizeof(uint64(0))) / 2
|
||||
}
|
||||
return int(unsafe.Sizeof(uint64(0)))
|
||||
}
|
28
proot/proot/tracee/abi_amd64.go
Normal file
28
proot/proot/tracee/abi_amd64.go
Normal file
@@ -0,0 +1,28 @@
|
||||
//go:build amd64 && (linux || android)
|
||||
|
||||
package tracee
|
||||
|
||||
func (tracee *Tracee) GetAbi() Abi {
|
||||
switch tracee.Regs[ORIGINAL].Cs {
|
||||
case 0x23:
|
||||
return ABI_2
|
||||
case 0x33:
|
||||
if tracee.Regs[ORIGINAL].Ds == 0x2b {
|
||||
return ABI_3
|
||||
}
|
||||
}
|
||||
return ABI_DEFAULT
|
||||
}
|
||||
|
||||
func (tracee *Tracee) Is32On64() bool {
|
||||
switch tracee.Regs[ORIGINAL].Cs {
|
||||
case 0x23:
|
||||
return tracee.Regs[ORIGINAL].Ds == 0x2b
|
||||
case 0x33:
|
||||
if tracee.Regs[ORIGINAL].Ds == 0x2b {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
6
proot/proot/tracee/abi_other.go
Normal file
6
proot/proot/tracee/abi_other.go
Normal file
@@ -0,0 +1,6 @@
|
||||
//go:build !amd64 && (linux || android)
|
||||
|
||||
package tracee
|
||||
|
||||
func (tracee *Tracee) GetAbi() Abi { return ABI_DEFAULT }
|
||||
func (tracee *Tracee) Is32On64() bool { return false }
|
317
proot/proot/tracee/event.go
Normal file
317
proot/proot/tracee/event.go
Normal file
@@ -0,0 +1,317 @@
|
||||
package tracee
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
|
||||
_, _, e1 := unix.Syscall6(unix.SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
|
||||
if e1 != 0 {
|
||||
err = syscall.Errno(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (tracee *Tracee) RestartTracee(signal syscall.Signal) bool {
|
||||
if tracee.AsPtracer.WaitPID != 0 || signal == -1 {
|
||||
return false
|
||||
} else if err := ptrace(tracee.RestartHow, tracee.PID, 0, uintptr(signal)); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
tracee.RestartHow = 0
|
||||
tracee.Running = true
|
||||
return true
|
||||
}
|
||||
|
||||
func (tracee *Tracee) LaunchProces(cmd *exec.Cmd) error {
|
||||
if cmd.SysProcAttr == nil {
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
}
|
||||
cmd.SysProcAttr.Ptrace = true
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !tracee.RootConfig.NoSeccmp {
|
||||
// tracee.EnableSyscallFiltering()
|
||||
}
|
||||
|
||||
tracee.PID = cmd.Process.Pid
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tracee *Tracee) EventLoop() error { return nil }
|
||||
|
||||
func isKernel4_8() bool {
|
||||
var uts unix.Utsname
|
||||
if err := unix.Uname(&uts); err != nil {
|
||||
return false
|
||||
}
|
||||
var major, minor int
|
||||
fmt.Sscanf(string(uts.Release[:]), "%d.%d", &major, &minor)
|
||||
return major == 4 && minor >= 8 || major > 4
|
||||
}
|
||||
|
||||
const PTRACE_EVENT_SECCOMP2 = unix.PTRACE_EVENT_SECCOMP + 1
|
||||
const defaultPtraceOption = unix.PTRACE_O_TRACESYSGOOD |
|
||||
unix.PTRACE_O_TRACEFORK |
|
||||
unix.PTRACE_O_TRACEVFORK |
|
||||
unix.PTRACE_O_TRACEVFORKDONE |
|
||||
unix.PTRACE_O_TRACEEXEC |
|
||||
unix.PTRACE_O_TRACECLONE |
|
||||
unix.PTRACE_O_TRACEEXIT
|
||||
|
||||
func (tracee *Tracee) HandleTraceeEvent4_8(traceeStatus unix.WaitStatus) error {
|
||||
if tracee.RestartHow == 0 {
|
||||
if tracee.Seccomp == Enabled && !tracee.SysexitPending {
|
||||
tracee.RestartHow = unix.PTRACE_CONT
|
||||
} else {
|
||||
tracee.RestartHow = unix.PTRACE_SYSCALL
|
||||
}
|
||||
}
|
||||
|
||||
var seccomp_detected, seccomp_enabled bool
|
||||
var signal syscall.Errno
|
||||
|
||||
if traceeStatus.Exited() {
|
||||
tracee.RootConfig.LastExitStatus = traceeStatus.ExitStatus()
|
||||
tracee.TerminateTracee()
|
||||
return nil
|
||||
} else if traceeStatus.Signaled() {
|
||||
// check_architecture(tracee);
|
||||
tracee.TerminateTracee()
|
||||
} else if traceeStatus.Stopped() {
|
||||
deliverSigtrap := false
|
||||
signal = syscall.Errno(traceeStatus&0xfff00) >> 8
|
||||
// static bool deliver_sigtrap = false;
|
||||
fall_t:
|
||||
switch signal {
|
||||
case syscall.Errno(unix.SIGTRAP):
|
||||
if deliverSigtrap {
|
||||
break
|
||||
}
|
||||
deliverSigtrap = true
|
||||
|
||||
err := ptrace(unix.PTRACE_SETOPTIONS, tracee.PID, 0, defaultPtraceOption|unix.PTRACE_O_TRACESECCOMP)
|
||||
if err == nil {
|
||||
if !tracee.RootConfig.NoSeccmp {
|
||||
seccomp_enabled = true
|
||||
}
|
||||
} else {
|
||||
seccomp_enabled = false
|
||||
if err = ptrace(unix.PTRACE_SETOPTIONS, tracee.PID, 0, defaultPtraceOption); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
goto fall_t
|
||||
case syscall.Errno(unix.SIGTRAP) | PTRACE_EVENT_SECCOMP2<<8,
|
||||
syscall.Errno(unix.SIGTRAP) | unix.PTRACE_EVENT_SECCOMP<<8:
|
||||
if !seccomp_detected && seccomp_enabled {
|
||||
tracee.Seccomp = Enabled
|
||||
seccomp_detected = true
|
||||
}
|
||||
|
||||
if signal == (syscall.Errno(unix.SIGTRAP)|PTRACE_EVENT_SECCOMP2<<8) || signal == (syscall.Errno(unix.SIGTRAP)|unix.PTRACE_EVENT_SECCOMP<<8) {
|
||||
flags := 0
|
||||
signal = 0
|
||||
if tracee.Seccomp != Enabled {
|
||||
break
|
||||
}
|
||||
|
||||
err := ptrace(unix.PTRACE_GETEVENTMSG, tracee.PID, 0, uintptr(unsafe.Pointer(&flags)))
|
||||
if err != nil {
|
||||
break
|
||||
} else if flags&0x1 == 0 {
|
||||
tracee.RestartHow = unix.PTRACE_CONT
|
||||
tracee.TranslateSyscall()
|
||||
if tracee.Seccomp == Disabling {
|
||||
tracee.RestartHow = unix.PTRACE_SYSCALL
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
goto fall_t
|
||||
case syscall.Errno(unix.SIGTRAP) | 0x80:
|
||||
signal = 0
|
||||
if tracee.Exe == "" {
|
||||
tracee.RestartHow = unix.PTRACE_CONT
|
||||
return nil
|
||||
}
|
||||
|
||||
switch tracee.Seccomp {
|
||||
case Enabled:
|
||||
if tracee.Status == 0 {
|
||||
tracee.RestartHow = unix.PTRACE_SYSCALL
|
||||
tracee.SysexitPending = true
|
||||
} else {
|
||||
tracee.RestartHow = unix.PTRACE_CONT
|
||||
tracee.SysexitPending = false
|
||||
}
|
||||
fallthrough
|
||||
case Disable:
|
||||
// tracee.TranslateSyscall()
|
||||
if tracee.Seccomp == Disabling {
|
||||
tracee.RestartHow = unix.PTRACE_SYSCALL
|
||||
tracee.Seccomp = Disable
|
||||
}
|
||||
case Disabling:
|
||||
tracee.Seccomp = Disable
|
||||
if tracee.Status == 0 {
|
||||
tracee.Status = 1
|
||||
}
|
||||
}
|
||||
case syscall.Errno(unix.SIGTRAP) | unix.PTRACE_EVENT_VFORK<<8:
|
||||
signal = 0
|
||||
tracee.NewChild(unix.PTRACE_EVENT_VFORK)
|
||||
case syscall.Errno(unix.SIGTRAP) | unix.PTRACE_EVENT_FORK<<8,
|
||||
syscall.Errno(unix.SIGTRAP) | unix.PTRACE_EVENT_CLONE<<8:
|
||||
signal = 0
|
||||
tracee.NewChild(0)
|
||||
case syscall.Errno(unix.SIGTRAP) | unix.PTRACE_EVENT_VFORK_DONE<<8,
|
||||
syscall.Errno(unix.SIGTRAP) | unix.PTRACE_EVENT_EXEC<<8,
|
||||
syscall.Errno(unix.SIGTRAP) | unix.PTRACE_EVENT_EXIT<<8:
|
||||
signal = 0
|
||||
case syscall.Errno(unix.SIGSTOP):
|
||||
if tracee.Exe == "" {
|
||||
tracee.Sigstop = SIGSTOP_PENDING
|
||||
// signal = -1
|
||||
signal = 0
|
||||
}
|
||||
if tracee.Sigstop == SIGSTOP_IGNORED {
|
||||
tracee.Sigstop = SIGSTOP_ALLOWED
|
||||
signal = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tracee.AsPtracee.Event4.Proot.Pending = true
|
||||
|
||||
return signal
|
||||
}
|
||||
|
||||
func (tracee *Tracee) HandleTraceeEvent(traceeStatus unix.WaitStatus) error {
|
||||
if isKernel4_8() {
|
||||
return tracee.HandleTraceeEvent4_8(traceeStatus)
|
||||
}
|
||||
|
||||
if tracee.RestartHow == 0 {
|
||||
if tracee.Seccomp == Enabled && !tracee.SysexitPending {
|
||||
tracee.RestartHow = unix.PTRACE_CONT
|
||||
} else {
|
||||
tracee.RestartHow = unix.PTRACE_SYSCALL
|
||||
}
|
||||
}
|
||||
|
||||
seccomp_dected := false
|
||||
|
||||
var signal error
|
||||
if traceeStatus.Exited() {
|
||||
tracee.RootConfig.LastExitStatus = traceeStatus.ExitStatus()
|
||||
tracee.TerminateTracee()
|
||||
return nil
|
||||
} else if traceeStatus.Signaled() {
|
||||
// check_architecture(tracee);
|
||||
tracee.TerminateTracee()
|
||||
} else if traceeStatus.Stopped() {
|
||||
deliverSigtrap := false
|
||||
signal = syscall.Errno(traceeStatus&0xfff00) >> 8
|
||||
|
||||
godo:
|
||||
switch signal {
|
||||
case syscall.Errno(unix.SIGTRAP):
|
||||
if deliverSigtrap {
|
||||
break
|
||||
}
|
||||
deliverSigtrap = true
|
||||
|
||||
status := ptrace(unix.PTRACE_SETOPTIONS, tracee.PID, 0, defaultPtraceOption|unix.PTRACE_O_TRACESECCOMP)
|
||||
if status != nil {
|
||||
status = ptrace(unix.PTRACE_SETOPTIONS, tracee.PID, 0, defaultPtraceOption)
|
||||
if status != nil {
|
||||
return status
|
||||
}
|
||||
}
|
||||
goto godo
|
||||
case syscall.Errno(unix.SIGTRAP) | 0x80:
|
||||
signal = unix.Errno(0)
|
||||
if tracee.Exe == "" {
|
||||
tracee.RestartHow = unix.PTRACE_CONT
|
||||
return nil
|
||||
}
|
||||
|
||||
switch tracee.Seccomp {
|
||||
case Enabled:
|
||||
if tracee.Status == 0 {
|
||||
tracee.RestartHow = unix.PTRACE_SYSCALL
|
||||
tracee.SysexitPending = true
|
||||
} else {
|
||||
tracee.RestartHow = unix.PTRACE_CONT
|
||||
tracee.SysexitPending = false
|
||||
}
|
||||
fallthrough
|
||||
case Disable:
|
||||
tracee.TranslateSyscall()
|
||||
if tracee.Seccomp == Disabling {
|
||||
tracee.RestartHow = unix.PTRACE_SYSCALL
|
||||
tracee.Seccomp = Disable
|
||||
}
|
||||
case Disabling:
|
||||
tracee.Seccomp = Disable
|
||||
if tracee.Status == 0 {
|
||||
tracee.Status = 1
|
||||
}
|
||||
}
|
||||
case syscall.Errno(unix.SIGTRAP) | PTRACE_EVENT_SECCOMP2<<8,
|
||||
syscall.Errno(unix.SIGTRAP) | unix.PTRACE_EVENT_SECCOMP<<8:
|
||||
flags := 0
|
||||
signal = unix.Errno(0)
|
||||
|
||||
if !seccomp_dected {
|
||||
tracee.Seccomp = Enabled
|
||||
seccomp_dected = true
|
||||
}
|
||||
if tracee.Seccomp != Enabled {
|
||||
break
|
||||
}
|
||||
err := ptrace(unix.PTRACE_GETEVENTMSG, tracee.PID, 0, uintptr(unsafe.Pointer(&flags)))
|
||||
if err != nil {
|
||||
break
|
||||
} else if flags&0x1 != 0 {
|
||||
tracee.RestartHow = unix.PTRACE_SYSCALL
|
||||
break
|
||||
}
|
||||
tracee.RestartHow = unix.PTRACE_CONT
|
||||
tracee.TranslateSyscall()
|
||||
if tracee.Seccomp == Disabling {
|
||||
tracee.RestartHow = unix.PTRACE_SYSCALL
|
||||
}
|
||||
case syscall.Errno(unix.SIGTRAP) | unix.PTRACE_EVENT_VFORK<<8:
|
||||
signal = unix.Errno(0)
|
||||
tracee.NewChild(unix.PTRACE_EVENT_VFORK)
|
||||
case syscall.Errno(unix.SIGTRAP) | unix.PTRACE_EVENT_FORK<<8, syscall.Errno(unix.SIGTRAP) | unix.PTRACE_EVENT_CLONE<<8:
|
||||
signal = unix.Errno(0)
|
||||
tracee.NewChild(0)
|
||||
case syscall.Errno(unix.SIGTRAP) | unix.PTRACE_EVENT_VFORK_DONE<<8, syscall.Errno(unix.SIGTRAP) | unix.PTRACE_EVENT_EXEC<<8, syscall.Errno(unix.SIGTRAP) | unix.PTRACE_EVENT_EXIT<<8:
|
||||
signal = unix.Errno(0)
|
||||
case syscall.Errno(unix.SIGSTOP):
|
||||
if tracee.Exe == "" {
|
||||
tracee.Sigstop = SIGSTOP_PENDING
|
||||
signal = unix.Errno(0)
|
||||
}
|
||||
if tracee.Sigstop == SIGSTOP_IGNORED {
|
||||
tracee.Sigstop = SIGSTOP_ALLOWED
|
||||
signal = unix.Errno(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tracee.AsPtracee.Event4.Proot.Pending = false
|
||||
return signal
|
||||
}
|
1
proot/proot/tracee/mem.go
Normal file
1
proot/proot/tracee/mem.go
Normal file
@@ -0,0 +1 @@
|
||||
package tracee
|
79
proot/proot/tracee/reg.go
Normal file
79
proot/proot/tracee/reg.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package tracee
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
type RegVersion int
|
||||
|
||||
const (
|
||||
CURRENT RegVersion = iota
|
||||
ORIGINAL
|
||||
MODIFIED
|
||||
NB_REG_VERSION
|
||||
)
|
||||
|
||||
type Reg int
|
||||
|
||||
const (
|
||||
SYSARG_NUM Reg = iota
|
||||
SYSARG_1
|
||||
SYSARG_2
|
||||
SYSARG_3
|
||||
SYSARG_4
|
||||
SYSARG_5
|
||||
SYSARG_6
|
||||
SYSARG_RESULT
|
||||
STACK_POINTER
|
||||
INSTR_POINTER
|
||||
RTLD_FINI
|
||||
STATE_FLAGS
|
||||
USERARG_1
|
||||
)
|
||||
|
||||
var __user = &unix.PtraceRegs{}
|
||||
|
||||
func (tracee *Tracee) PeekReg(Version RegVersion, Reg Reg) (result uint64) {
|
||||
if Version < NB_REG_VERSION {
|
||||
panic("invalid version")
|
||||
}
|
||||
|
||||
// result = REG(tracee, version, reg);
|
||||
result = tracee.Reg(Version, Reg)
|
||||
|
||||
// Use only the 32 least significant bits (LSB) when running 32-bit processes on a 64-bit kernel.
|
||||
if tracee.Is32On64() {
|
||||
result &= 0xFFFFFFFF
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Save the @tracee's current register bank into the @version register bank.
|
||||
func (tracee *Tracee) SaveCurrentRegs(Ver RegVersion) {
|
||||
if Ver == ORIGINAL {
|
||||
tracee.RegsWereChanged = false
|
||||
}
|
||||
tracee.Regs[Ver] = tracee.Regs[CURRENT]
|
||||
}
|
||||
|
||||
func (tracee *Tracee) FetchRegs() error {
|
||||
return unix.PtraceGetRegs(tracee.PID, &tracee.Regs[CURRENT])
|
||||
}
|
||||
|
||||
func (tracee *Tracee) PushRegs() error {
|
||||
if tracee.RegsWereChanged {
|
||||
if tracee.RestoreOrigianlRegs {
|
||||
tracee.Restore(SYSARG_NUM)
|
||||
tracee.Restore(SYSARG_1)
|
||||
tracee.Restore(SYSARG_2)
|
||||
tracee.Restore(SYSARG_3)
|
||||
tracee.Restore(SYSARG_4)
|
||||
tracee.Restore(SYSARG_5)
|
||||
tracee.Restore(SYSARG_6)
|
||||
tracee.Restore(STACK_POINTER)
|
||||
}
|
||||
|
||||
return unix.PtraceSetRegs(tracee.PID, &tracee.Regs[CURRENT])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
66
proot/proot/tracee/reg_386.go
Normal file
66
proot/proot/tracee/reg_386.go
Normal file
@@ -0,0 +1,66 @@
|
||||
//go:build 386 && (linux || android)
|
||||
|
||||
package tracee
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
/**
|
||||
* Compute the offset of the register @reg_name in the USER area.
|
||||
*/
|
||||
// #define USER_REGS_OFFSET(reg_name) \
|
||||
// (offsetof(struct user, regs) \
|
||||
// + offsetof(struct user_regs_struct, reg_name))
|
||||
|
||||
// #define REG(tracee, version, index) \
|
||||
// (*(word_t*) (((uint8_t *) &tracee->_regs[version]) + reg_offset[index]))
|
||||
|
||||
// static off_t reg_offset[] = {
|
||||
// [SYSARG_NUM] = USER_REGS_OFFSET(orig_eax),
|
||||
// [SYSARG_1] = USER_REGS_OFFSET(ebx),
|
||||
// [SYSARG_2] = USER_REGS_OFFSET(ecx),
|
||||
// [SYSARG_3] = USER_REGS_OFFSET(edx),
|
||||
// [SYSARG_4] = USER_REGS_OFFSET(esi),
|
||||
// [SYSARG_5] = USER_REGS_OFFSET(edi),
|
||||
// [SYSARG_6] = USER_REGS_OFFSET(ebp),
|
||||
// [SYSARG_RESULT] = USER_REGS_OFFSET(eax),
|
||||
// [STACK_POINTER] = USER_REGS_OFFSET(esp),
|
||||
// [INSTR_POINTER] = USER_REGS_OFFSET(eip),
|
||||
// [RTLD_FINI] = USER_REGS_OFFSET(edx),
|
||||
// [STATE_FLAGS] = USER_REGS_OFFSET(eflags),
|
||||
// [USERARG_1] = USER_REGS_OFFSET(eax),
|
||||
// };
|
||||
|
||||
var RegOffset = []uintptr{
|
||||
SYSARG_NUM: unsafe.Offsetof(__user.Orig_eax),
|
||||
SYSARG_1: unsafe.Offsetof(__user.Ebx),
|
||||
SYSARG_2: unsafe.Offsetof(__user.Ecx),
|
||||
SYSARG_3: unsafe.Offsetof(__user.Edx),
|
||||
SYSARG_4: unsafe.Offsetof(__user.Esi),
|
||||
SYSARG_5: unsafe.Offsetof(__user.Edi),
|
||||
SYSARG_6: unsafe.Offsetof(__user.Ebp),
|
||||
SYSARG_RESULT: unsafe.Offsetof(__user.Eax),
|
||||
STACK_POINTER: unsafe.Offsetof(__user.Esp),
|
||||
INSTR_POINTER: unsafe.Offsetof(__user.Eip),
|
||||
RTLD_FINI: unsafe.Offsetof(__user.Edx),
|
||||
STATE_FLAGS: unsafe.Offsetof(__user.Eflags),
|
||||
USERARG_1: unsafe.Offsetof(__user.Eax),
|
||||
}
|
||||
|
||||
func (tracee *Tracee) Reg(Version RegVersion, Reg Reg) uint64 {
|
||||
return uint64(uintptr(unsafe.Pointer(&tracee.Regs[Version])) + uintptr(RegOffset[Reg]))
|
||||
}
|
||||
|
||||
func (tracee *Tracee) PokeReg(Version RegVersion, Reg Reg, Value uint64) {
|
||||
if tracee.PeekReg(CURRENT, Reg) == Value {
|
||||
return
|
||||
}
|
||||
|
||||
// REG(tracee, CURRENT, reg) = value;
|
||||
*(*uint64)(unsafe.Add(unsafe.Pointer(&tracee.Regs[Version]), int(RegOffset[Reg]))) = Value
|
||||
tracee.RegsWereChanged = true
|
||||
}
|
||||
func (tracee *Tracee) Restore(Reg Reg) {
|
||||
(*(*uint64)(unsafe.Add(unsafe.Pointer(&tracee.Regs[CURRENT]), int(RegOffset[Reg])))) = tracee.Reg(ORIGINAL, Reg)
|
||||
}
|
119
proot/proot/tracee/reg_amd64.go
Normal file
119
proot/proot/tracee/reg_amd64.go
Normal file
@@ -0,0 +1,119 @@
|
||||
//go:build amd64 && (linux || android)
|
||||
|
||||
package tracee
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// /**
|
||||
// * Compute the offset of the register @reg_name in the USER area.
|
||||
// */
|
||||
// #define USER_REGS_OFFSET(reg_name) \
|
||||
// (offsetof(struct user, regs) \
|
||||
// + offsetof(struct user_regs_struct, reg_name))
|
||||
|
||||
// static off_t reg_offset[] = {
|
||||
// [SYSARG_NUM] = USER_REGS_OFFSET(orig_rax),
|
||||
// [SYSARG_1] = USER_REGS_OFFSET(rdi),
|
||||
// [SYSARG_2] = USER_REGS_OFFSET(rsi),
|
||||
// [SYSARG_3] = USER_REGS_OFFSET(rdx),
|
||||
// [SYSARG_4] = USER_REGS_OFFSET(r10),
|
||||
// [SYSARG_5] = USER_REGS_OFFSET(r8),
|
||||
// [SYSARG_6] = USER_REGS_OFFSET(r9),
|
||||
// [SYSARG_RESULT] = USER_REGS_OFFSET(rax),
|
||||
// [STACK_POINTER] = USER_REGS_OFFSET(rsp),
|
||||
// [INSTR_POINTER] = USER_REGS_OFFSET(rip),
|
||||
// [RTLD_FINI] = USER_REGS_OFFSET(rdx),
|
||||
// [STATE_FLAGS] = USER_REGS_OFFSET(eflags),
|
||||
// [USERARG_1] = USER_REGS_OFFSET(rdi),
|
||||
// };
|
||||
|
||||
// static off_t reg_offset_x86[] = {
|
||||
// [SYSARG_NUM] = USER_REGS_OFFSET(orig_rax),
|
||||
// [SYSARG_1] = USER_REGS_OFFSET(rbx),
|
||||
// [SYSARG_2] = USER_REGS_OFFSET(rcx),
|
||||
// [SYSARG_3] = USER_REGS_OFFSET(rdx),
|
||||
// [SYSARG_4] = USER_REGS_OFFSET(rsi),
|
||||
// [SYSARG_5] = USER_REGS_OFFSET(rdi),
|
||||
// [SYSARG_6] = USER_REGS_OFFSET(rbp),
|
||||
// [SYSARG_RESULT] = USER_REGS_OFFSET(rax),
|
||||
// [STACK_POINTER] = USER_REGS_OFFSET(rsp),
|
||||
// [INSTR_POINTER] = USER_REGS_OFFSET(rip),
|
||||
// [RTLD_FINI] = USER_REGS_OFFSET(rdx),
|
||||
// [STATE_FLAGS] = USER_REGS_OFFSET(eflags),
|
||||
// [USERARG_1] = USER_REGS_OFFSET(rax),
|
||||
// };
|
||||
|
||||
// #define REG(tracee, version, index) \
|
||||
// (*(word_t*) (tracee->_regs[version].cs == 0x23 \
|
||||
// ? (((uint8_t *) &tracee->_regs[version]) + reg_offset_x86[index]) \
|
||||
// : (((uint8_t *) &tracee->_regs[version]) + reg_offset[index])))
|
||||
|
||||
var (
|
||||
RegOffset = []uintptr{
|
||||
SYSARG_NUM: unsafe.Offsetof(__user.Orig_rax),
|
||||
SYSARG_1: unsafe.Offsetof(__user.Rdi),
|
||||
SYSARG_2: unsafe.Offsetof(__user.Rsi),
|
||||
SYSARG_3: unsafe.Offsetof(__user.Rdx),
|
||||
SYSARG_4: unsafe.Offsetof(__user.R10),
|
||||
SYSARG_5: unsafe.Offsetof(__user.R8),
|
||||
SYSARG_6: unsafe.Offsetof(__user.R9),
|
||||
SYSARG_RESULT: unsafe.Offsetof(__user.Rax),
|
||||
STACK_POINTER: unsafe.Offsetof(__user.Rsp),
|
||||
INSTR_POINTER: unsafe.Offsetof(__user.Rip),
|
||||
RTLD_FINI: unsafe.Offsetof(__user.Rdx),
|
||||
STATE_FLAGS: unsafe.Offsetof(__user.Eflags),
|
||||
USERARG_1: unsafe.Offsetof(__user.Rdi),
|
||||
}
|
||||
RegOffsetX86 = []uintptr{
|
||||
SYSARG_NUM: unsafe.Offsetof(__user.Orig_rax),
|
||||
SYSARG_1: unsafe.Offsetof(__user.Rbx),
|
||||
SYSARG_2: unsafe.Offsetof(__user.Rcx),
|
||||
SYSARG_3: unsafe.Offsetof(__user.Rdx),
|
||||
SYSARG_4: unsafe.Offsetof(__user.Rsi),
|
||||
SYSARG_5: unsafe.Offsetof(__user.Rdi),
|
||||
SYSARG_6: unsafe.Offsetof(__user.Rbp),
|
||||
SYSARG_RESULT: unsafe.Offsetof(__user.Rax),
|
||||
STACK_POINTER: unsafe.Offsetof(__user.Rsp),
|
||||
INSTR_POINTER: unsafe.Offsetof(__user.Rip),
|
||||
RTLD_FINI: unsafe.Offsetof(__user.Rdx),
|
||||
STATE_FLAGS: unsafe.Offsetof(__user.Eflags),
|
||||
USERARG_1: unsafe.Offsetof(__user.Rax),
|
||||
}
|
||||
)
|
||||
|
||||
func (tracee *Tracee) Reg(Version RegVersion, Reg Reg) uint64 {
|
||||
if Version < NB_REG_VERSION {
|
||||
panic("invalid version")
|
||||
}
|
||||
|
||||
if tracee.Regs[Version].Cs == 0x23 {
|
||||
return uint64(uintptr(unsafe.Pointer(&tracee.Regs[Version])) + uintptr(RegOffsetX86[Reg]))
|
||||
}
|
||||
return uint64(uintptr(unsafe.Pointer(&tracee.Regs[Version])) + uintptr(RegOffset[Reg]))
|
||||
}
|
||||
|
||||
func (tracee *Tracee) PokeReg(Version RegVersion, Reg Reg, Value uint64) {
|
||||
if tracee.PeekReg(CURRENT, Reg) == Value {
|
||||
return
|
||||
}
|
||||
|
||||
// REG(tracee, CURRENT, reg) = value;
|
||||
var unpoint unsafe.Pointer
|
||||
if tracee.Regs[Version].Cs == 0x23 {
|
||||
unpoint = unsafe.Add(unsafe.Pointer(&tracee.Regs[Version]), int(RegOffsetX86[Reg]))
|
||||
} else {
|
||||
unpoint = unsafe.Add(unsafe.Pointer(&tracee.Regs[Version]), int(RegOffset[Reg]))
|
||||
}
|
||||
|
||||
*(*uint64)(unpoint) = Value
|
||||
tracee.RegsWereChanged = true
|
||||
}
|
||||
|
||||
func (tracee *Tracee) Restore(Reg Reg) {
|
||||
if tracee.Regs[CURRENT].Cs == 0x23 {
|
||||
(*(*uint64)(unsafe.Add(unsafe.Pointer(&tracee.Regs[CURRENT]), int(RegOffsetX86[Reg])))) = tracee.Reg(ORIGINAL, Reg)
|
||||
}
|
||||
(*(*uint64)(unsafe.Add(unsafe.Pointer(&tracee.Regs[CURRENT]), int(RegOffset[Reg])))) = tracee.Reg(ORIGINAL, Reg)
|
||||
}
|
66
proot/proot/tracee/reg_arm.go
Normal file
66
proot/proot/tracee/reg_arm.go
Normal file
@@ -0,0 +1,66 @@
|
||||
//go:build arm && (linux || android)
|
||||
|
||||
package tracee
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// /**
|
||||
// * Compute the offset of the register @reg_name in the USER area.
|
||||
// */
|
||||
// #define USER_REGS_OFFSET(reg_name) \
|
||||
// (offsetof(struct user, regs) \
|
||||
// + offsetof(struct user_regs_struct, reg_name))
|
||||
|
||||
// #define REG(tracee, version, index) \
|
||||
// (*(word_t*) (((uint8_t *) &tracee->_regs[version]) + reg_offset[index]))
|
||||
|
||||
// off_t reg_offset[] = {
|
||||
// [SYSARG_NUM] = USER_REGS_OFFSET(uregs[7]),
|
||||
// [SYSARG_1] = USER_REGS_OFFSET(uregs[0]),
|
||||
// [SYSARG_2] = USER_REGS_OFFSET(uregs[1]),
|
||||
// [SYSARG_3] = USER_REGS_OFFSET(uregs[2]),
|
||||
// [SYSARG_4] = USER_REGS_OFFSET(uregs[3]),
|
||||
// [SYSARG_5] = USER_REGS_OFFSET(uregs[4]),
|
||||
// [SYSARG_6] = USER_REGS_OFFSET(uregs[5]),
|
||||
// [SYSARG_RESULT] = USER_REGS_OFFSET(uregs[0]),
|
||||
// [STACK_POINTER] = USER_REGS_OFFSET(uregs[13]),
|
||||
// [INSTR_POINTER] = USER_REGS_OFFSET(uregs[15]),
|
||||
// [USERARG_1] = USER_REGS_OFFSET(uregs[0]),
|
||||
// };
|
||||
|
||||
var RegOffset = []uintptr{
|
||||
SYSARG_NUM: unsafe.Offsetof(__user.Uregs) + uintptr(7*unsafe.Sizeof(__user.Uregs[0])),
|
||||
SYSARG_1: unsafe.Offsetof(__user.Uregs) + uintptr(0*unsafe.Sizeof(__user.Uregs[0])),
|
||||
SYSARG_2: unsafe.Offsetof(__user.Uregs) + uintptr(1*unsafe.Sizeof(__user.Uregs[0])),
|
||||
SYSARG_3: unsafe.Offsetof(__user.Uregs) + uintptr(2*unsafe.Sizeof(__user.Uregs[0])),
|
||||
SYSARG_4: unsafe.Offsetof(__user.Uregs) + uintptr(3*unsafe.Sizeof(__user.Uregs[0])),
|
||||
SYSARG_5: unsafe.Offsetof(__user.Uregs) + uintptr(4*unsafe.Sizeof(__user.Uregs[0])),
|
||||
SYSARG_6: unsafe.Offsetof(__user.Uregs) + uintptr(5*unsafe.Sizeof(__user.Uregs[0])),
|
||||
SYSARG_RESULT: unsafe.Offsetof(__user.Uregs) + uintptr(0*unsafe.Sizeof(__user.Uregs[0])),
|
||||
STACK_POINTER: unsafe.Offsetof(__user.Uregs) + uintptr(13*unsafe.Sizeof(__user.Uregs[0])),
|
||||
INSTR_POINTER: unsafe.Offsetof(__user.Uregs) + uintptr(15*unsafe.Sizeof(__user.Uregs[0])),
|
||||
USERARG_1: unsafe.Offsetof(__user.Uregs) + uintptr(0*unsafe.Sizeof(__user.Uregs[0])),
|
||||
}
|
||||
|
||||
func (tracee *Tracee) Reg(Version RegVersion, Reg Reg) uint64 {
|
||||
return uint64(uintptr(unsafe.Pointer(&tracee.Regs[Version])) + uintptr(RegOffset[Reg]))
|
||||
}
|
||||
|
||||
func (tracee *Tracee) PokeReg(Version RegVersion, Reg Reg, Value uint64) {
|
||||
if tracee.PeekReg(CURRENT, Reg) == Value {
|
||||
return
|
||||
}
|
||||
|
||||
// REG(tracee, CURRENT, reg) = value;
|
||||
*(*uint64)(unsafe.Add(unsafe.Pointer(&tracee.Regs[Version]), int(RegOffset[Reg]))) = Value
|
||||
tracee.RegsWereChanged = true
|
||||
}
|
||||
|
||||
// #define RESTORE(sysarg) (void) (reg_offset[SYSARG_RESULT] != reg_offset[sysarg] && (REG(tracee, CURRENT, sysarg) = REG(tracee, ORIGINAL, sysarg)))
|
||||
func (tracee *Tracee) Restore(Reg Reg) {
|
||||
if RegOffset[SYSARG_RESULT] != RegOffset[Reg] {
|
||||
(*(*uint64)(unsafe.Add(unsafe.Pointer(&tracee.Regs[CURRENT]), int(RegOffset[Reg])))) = tracee.Reg(ORIGINAL, Reg)
|
||||
}
|
||||
}
|
67
proot/proot/tracee/reg_arm64.go
Normal file
67
proot/proot/tracee/reg_arm64.go
Normal file
@@ -0,0 +1,67 @@
|
||||
//go:build arm64 && (linux || android)
|
||||
|
||||
package tracee
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
/**
|
||||
* Compute the offset of the register @reg_name in the USER area.
|
||||
*/
|
||||
// #define USER_REGS_OFFSET(reg_name) \
|
||||
// (offsetof(struct user, regs) \
|
||||
// + offsetof(struct user_regs_struct, reg_name))
|
||||
|
||||
// #define REG(tracee, version, index) \
|
||||
// (*(word_t*) (((uint8_t *) &tracee->_regs[version]) + reg_offset[index]))
|
||||
|
||||
// #undef USER_REGS_OFFSET
|
||||
// #define USER_REGS_OFFSET(reg_name) offsetof(struct user_regs_struct, reg_name)
|
||||
|
||||
// static off_t reg_offset[] = {
|
||||
// [SYSARG_NUM] = USER_REGS_OFFSET(regs[8]),
|
||||
// [SYSARG_1] = USER_REGS_OFFSET(regs[0]),
|
||||
// [SYSARG_2] = USER_REGS_OFFSET(regs[1]),
|
||||
// [SYSARG_3] = USER_REGS_OFFSET(regs[2]),
|
||||
// [SYSARG_4] = USER_REGS_OFFSET(regs[3]),
|
||||
// [SYSARG_5] = USER_REGS_OFFSET(regs[4]),
|
||||
// [SYSARG_6] = USER_REGS_OFFSET(regs[5]),
|
||||
// [SYSARG_RESULT] = USER_REGS_OFFSET(regs[0]),
|
||||
// [STACK_POINTER] = USER_REGS_OFFSET(sp),
|
||||
// [INSTR_POINTER] = USER_REGS_OFFSET(pc),
|
||||
// [USERARG_1] = USER_REGS_OFFSET(regs[0]),
|
||||
// };
|
||||
|
||||
var RegOffset = []uintptr{
|
||||
// + uintptr(7*unsafe.Sizeof(__user.Uregs[0]))
|
||||
SYSARG_NUM: unsafe.Offsetof(__user.Regs) + uintptr(8*unsafe.Sizeof(__user.Regs[0])),
|
||||
SYSARG_1: unsafe.Offsetof(__user.Regs) + uintptr(0*unsafe.Sizeof(__user.Regs[0])),
|
||||
SYSARG_2: unsafe.Offsetof(__user.Regs) + uintptr(1*unsafe.Sizeof(__user.Regs[0])),
|
||||
SYSARG_3: unsafe.Offsetof(__user.Regs) + uintptr(2*unsafe.Sizeof(__user.Regs[0])),
|
||||
SYSARG_4: unsafe.Offsetof(__user.Regs) + uintptr(3*unsafe.Sizeof(__user.Regs[0])),
|
||||
SYSARG_5: unsafe.Offsetof(__user.Regs) + uintptr(4*unsafe.Sizeof(__user.Regs[0])),
|
||||
SYSARG_6: unsafe.Offsetof(__user.Regs) + uintptr(5*unsafe.Sizeof(__user.Regs[0])),
|
||||
SYSARG_RESULT: unsafe.Offsetof(__user.Regs) + uintptr(0*unsafe.Sizeof(__user.Regs[0])),
|
||||
STACK_POINTER: unsafe.Offsetof(__user.Sp),
|
||||
INSTR_POINTER: unsafe.Offsetof(__user.Pc),
|
||||
USERARG_1: unsafe.Offsetof(__user.Regs) + uintptr(0*unsafe.Sizeof(__user.Regs[0])),
|
||||
}
|
||||
|
||||
func (tracee *Tracee) Reg(Version RegVersion, Reg Reg) uint64 {
|
||||
return uint64(uintptr(unsafe.Pointer(&tracee.Regs[Version])) + uintptr(RegOffset[Reg]))
|
||||
}
|
||||
func (tracee *Tracee) PokeReg(Version RegVersion, Reg Reg, Value uint64) {
|
||||
if tracee.PeekReg(CURRENT, Reg) == Value {
|
||||
return
|
||||
}
|
||||
|
||||
// REG(tracee, CURRENT, reg) = value;
|
||||
*(*uint64)(unsafe.Add(unsafe.Pointer(&tracee.Regs[Version]), int(RegOffset[Reg]))) = Value
|
||||
tracee.RegsWereChanged = true
|
||||
}
|
||||
func (tracee *Tracee) Restore(Reg Reg) {
|
||||
if RegOffset[SYSARG_RESULT] != RegOffset[Reg] {
|
||||
(*(*uint64)(unsafe.Add(unsafe.Pointer(&tracee.Regs[CURRENT]), int(RegOffset[Reg])))) = tracee.Reg(ORIGINAL, Reg)
|
||||
}
|
||||
}
|
379
proot/proot/tracee/tracee.go
Normal file
379
proot/proot/tracee/tracee.go
Normal file
@@ -0,0 +1,379 @@
|
||||
//go:build linux || android
|
||||
|
||||
package tracee
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"sirherobrine23.com.br/go-bds/exec/proot/proot/execve"
|
||||
"sirherobrine23.com.br/go-bds/exec/proot/proot/path"
|
||||
)
|
||||
|
||||
const HostRootfs string = "/host-rootfs"
|
||||
|
||||
// struct { struct tracee *le_next; struct tracee **le_prev; }
|
||||
type TraceeLink struct {
|
||||
Next *Tracee
|
||||
Prev **Tracee
|
||||
}
|
||||
|
||||
type WaitsIn int
|
||||
|
||||
const (
|
||||
DOESNT_WAIT = iota
|
||||
WAITS_IN_KERNEL
|
||||
WAITS_IN_PROOT
|
||||
)
|
||||
|
||||
type AsPtracer struct {
|
||||
NbPtracees int
|
||||
Zombies struct{ lh_first *Tracee }
|
||||
WaitPID int
|
||||
WaitOption uint
|
||||
|
||||
WaitsIn WaitsIn
|
||||
}
|
||||
|
||||
type AsPtracerEvent struct {
|
||||
Value int
|
||||
Pending bool
|
||||
}
|
||||
|
||||
type AsPtracee struct {
|
||||
Ptracer *Tracee
|
||||
Event4 struct {
|
||||
Proot AsPtracerEvent
|
||||
Ptracer AsPtracerEvent
|
||||
}
|
||||
|
||||
TracingStarted bool
|
||||
IgnoreLoeaderSyscall bool
|
||||
IgnoreSyscall bool
|
||||
Option uint
|
||||
IsZombie bool
|
||||
}
|
||||
|
||||
type Sigstop int
|
||||
|
||||
const (
|
||||
SIGSTOP_IGNORED Sigstop = iota
|
||||
SIGSTOP_ALLOWED
|
||||
SIGSTOP_PENDING
|
||||
)
|
||||
|
||||
type Seccomp int
|
||||
|
||||
const (
|
||||
Disable Seccomp = iota
|
||||
Disabling
|
||||
Enabled
|
||||
)
|
||||
|
||||
// Information related to a file-system name-space.
|
||||
type FileSystemNameSpace struct {
|
||||
Cwd string // Current working directory, à la /proc/self/pwd.
|
||||
|
||||
Bindings struct {
|
||||
// List of bindings as specified by the user but not canonicalized yet.
|
||||
Pending *path.Bindings
|
||||
|
||||
// List of bindings canonicalized and sorted in the "guest" order.
|
||||
Guest *path.Binding
|
||||
|
||||
// List of bindings canonicalized and sorted in the "host" order.
|
||||
Host *path.Bindings
|
||||
}
|
||||
}
|
||||
|
||||
// Virtual heap, emulated with a regular memory mapping.
|
||||
type Heap struct {
|
||||
Base uint64
|
||||
Size uint64
|
||||
Disabled bool
|
||||
}
|
||||
|
||||
type Tracees struct {
|
||||
First *Tracee
|
||||
}
|
||||
|
||||
type TraceeRoot struct {
|
||||
Tracees Tracees
|
||||
NextVPID uint
|
||||
NoSeccmp bool
|
||||
LastExitStatus int
|
||||
}
|
||||
|
||||
// Information related to a tracee process.
|
||||
type Tracee struct {
|
||||
RootConfig *TraceeRoot
|
||||
|
||||
Link TraceeLink // Link for the list of all tracees.
|
||||
PID int // Process identifier.
|
||||
Vpid uint // Unique tracee identifier.
|
||||
Running bool // Is it currently running or not?
|
||||
Terminated bool // Is this tracee ready to be freed? TODO: move to a list dedicated to terminated tracees instead.
|
||||
KillallOnExit bool // Whether termination of this tracee implies an immediate kill of all tracees.
|
||||
Parent *Tracee // Parent of this tracee, NULL if none.
|
||||
Clone bool // Is it a "clone", i.e has the same parent as its creator.
|
||||
AsPtracer AsPtracer // Support for ptrace emulation (tracer side).
|
||||
AsPtracee AsPtracee // Support for ptrace emulation (tracee side).
|
||||
|
||||
/* Current status:
|
||||
* 0: enter syscall
|
||||
* 1: exit syscall no error
|
||||
* -errno: exit syscall with error.
|
||||
*/
|
||||
Status int
|
||||
|
||||
/*
|
||||
#define IS_IN_SYSENTER(tracee) ((tracee)->status == 0)
|
||||
#define IS_IN_SYSEXIT(tracee) (!IS_IN_SYSENTER(tracee))
|
||||
#define IS_IN_SYSEXIT2(tracee, sysnum) (IS_IN_SYSEXIT(tracee) && get_sysnum((tracee), ORIGINAL) == sysnum)
|
||||
*/
|
||||
|
||||
// PTRACE_REQUEST_TYPE
|
||||
|
||||
RestartHow int // How this tracee is restarted.
|
||||
|
||||
/* Value of the tracee's general purpose registers. */
|
||||
// struct user_regs_struct _regs[NB_REG_VERSION];
|
||||
// bool _regs_were_changed;
|
||||
// bool restore_original_regs;
|
||||
RestoreOrigianlRegs bool
|
||||
RegsWereChanged bool
|
||||
Regs [NB_REG_VERSION]unix.PtraceRegs
|
||||
|
||||
Sigstop Sigstop // State for the special handling of SIGSTOP.
|
||||
|
||||
GlueType uint // Specify the type of the final component during the initialization of a binding. This variable is first defined in bind_path() then used in build_glue().
|
||||
|
||||
// During a sub-reconfiguration, the new setup is relatively to @tracee's file-system name-space. Also, @paths holds its $PATH environment variable in order to emulate the execvp(3) behavior.
|
||||
Reconf struct {
|
||||
Tracee *Tracee
|
||||
paths string
|
||||
}
|
||||
|
||||
// Unrequested syscalls inserted by PRoot after an actual syscall.
|
||||
Chain struct {
|
||||
// struct chained_syscalls *syscalls;
|
||||
Syscalls *any // Assuming chained_syscalls is a slice of some `any`
|
||||
ForceFinalResult bool
|
||||
FinalResult uint64
|
||||
}
|
||||
|
||||
// Load info generated during execve sysenter and used during execve sysexit.
|
||||
LoadInfo *execve.LoadInfo
|
||||
|
||||
MixedMode bool // Disable mixed-execution (native host) check
|
||||
Verbose int // Verbosity level.
|
||||
Seccomp Seccomp // State of the seccomp acceleration for this tracee.
|
||||
SysexitPending bool // Ensure the sysexit stage is always hit under seccomp.
|
||||
|
||||
FS *FileSystemNameSpace // Information related to a file-system name-space.
|
||||
Heap *Heap // Virtual heap, emulated with a regular memory mapping.
|
||||
|
||||
// Path to the executable, à la /proc/self/exe.
|
||||
Exe, NewExe string
|
||||
|
||||
Qemu *string // Runner command-line.
|
||||
Glue string // Path to glue between the guest rootfs and the host rootfs.
|
||||
|
||||
// List of extensions enabled for this tracee.
|
||||
// struct extensions *extensions;
|
||||
|
||||
HostLDSOPaths, GuestLDSOPaths string // For the mixed-mode, the guest LD_LIBRARY_PATH is saved during the "guest -> host" transition, in order to be restored during the "host -> guest" transition (only if the host LD_LIBRARY_PATH hasn't changed).
|
||||
ToolName string // For diagnostic purpose.
|
||||
}
|
||||
|
||||
/*
|
||||
extern Tracee *get_tracee(const Tracee *tracee, pid_t pid, bool create);
|
||||
extern Tracee *get_ptracee(const Tracee *ptracer, pid_t pid, bool only_stopped, bool only_with_pevent, word_t wait_options);
|
||||
extern Tracee *get_stopped_ptracee(const Tracee *ptracer, pid_t pid, bool only_with_pevent, word_t wait_options);
|
||||
extern bool has_ptracees(const Tracee *ptracer, pid_t pid, word_t wait_options);
|
||||
extern int new_child(Tracee *parent, word_t clone_flags);
|
||||
extern Tracee *new_dummy_tracee(TALLOC_CTX *context);
|
||||
extern void terminate_tracee(Tracee *tracee);
|
||||
extern void free_terminated_tracees(Tracee *tracee);
|
||||
extern int swap_config(Tracee *tracee1, Tracee *tracee2);
|
||||
extern void kill_all_tracees(Tracee *tracee);
|
||||
*/
|
||||
|
||||
// #define PTRACEE (ptracee->as_ptracee)
|
||||
// #define PTRACER (ptracer->as_ptracer)
|
||||
|
||||
func (tracee *Tracee) Ptracer() *AsPtracer { return &tracee.AsPtracer }
|
||||
func (tracee *Tracee) Ptracee() *AsPtracee { return &tracee.AsPtracee }
|
||||
|
||||
func NewDummyTracee() (tracee *Tracee) {
|
||||
tracee = new(Tracee)
|
||||
tracee.Link = TraceeLink{}
|
||||
|
||||
tracee.FS = new(FileSystemNameSpace)
|
||||
tracee.Heap = new(Heap)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func newTracee(pid int, currentTracee *Tracee) *Tracee {
|
||||
if currentTracee == nil {
|
||||
currentTracee = NewDummyTracee()
|
||||
currentTracee.RootConfig = &TraceeRoot{Tracees: Tracees{}, NextVPID: 1}
|
||||
}
|
||||
|
||||
tracee := NewDummyTracee()
|
||||
tracee.PID = pid
|
||||
currentTracee.RootConfig.NextVPID++
|
||||
tracee.Vpid = currentTracee.RootConfig.NextVPID
|
||||
|
||||
/*
|
||||
do {
|
||||
if (((tracee)->link.le_next = (current_tracee->RootConfig->tracees)->lh_first) != ((void *)0)) {
|
||||
(current_tracee->RootConfig->tracees)->lh_first->link.le_prev = &(tracee)->link.le_next;
|
||||
}
|
||||
|
||||
(current_tracee->RootConfig->tracees)->lh_first = (tracee);
|
||||
(tracee)->link.le_prev = &(current_tracee->RootConfig->tracees)->lh_first;
|
||||
} while(true)
|
||||
*/
|
||||
if tracee.Link.Next = currentTracee.RootConfig.Tracees.First; tracee.Link.Next != nil {
|
||||
tracee.Link.Next.Link.Prev = &tracee.Link.Next
|
||||
}
|
||||
currentTracee.RootConfig.Tracees.First = tracee
|
||||
tracee.Link.Prev = ¤tTracee.RootConfig.Tracees.First
|
||||
|
||||
return tracee
|
||||
}
|
||||
|
||||
// Return the entry related to the tracee @pid. If no entry were found, a new one is created if @create is true, otherwise NULL is returned.
|
||||
func (tracee *Tracee) GetTracee(Pid int, create bool) *Tracee {
|
||||
if tracee != nil && tracee.PID == Pid {
|
||||
return tracee
|
||||
}
|
||||
|
||||
for tracee := tracee.RootConfig.Tracees.First; tracee != nil; tracee = tracee.Link.Next {
|
||||
if tracee.PID == Pid {
|
||||
return tracee
|
||||
}
|
||||
}
|
||||
|
||||
if create {
|
||||
return newTracee(Pid, tracee)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// #define EXPECTED_WAIT_CLONE(wait_options, tracee) \
|
||||
// ((((wait_options) & __WALL) != 0) || ((((wait_options) & __WCLONE) != 0) && (tracee)->clone) || ((((wait_options) & __WCLONE) == 0) && !(tracee)->clone))
|
||||
func ExpectedWaitClone(wait_options uint, tracee *Tracee) bool {
|
||||
return (((wait_options & syscall.WALL) != 0) ||
|
||||
(((wait_options & syscall.WCLONE) != 0) && tracee.Clone) ||
|
||||
(((wait_options & syscall.WCLONE) == 0) && !tracee.Clone))
|
||||
}
|
||||
|
||||
// Return the first [stopped?] tracee with the given @pid (-1 for any) which has the given @ptracer,
|
||||
// and which has a pending event for its ptracer if @only_with_pevent is true.
|
||||
// See wait(2) manual for the meaning of @wait_options. This function returns NULL if there's no such ptracee.
|
||||
func (tracee *Tracee) GetPtracee(Pid int, onlyStopped, onlyWithPevent bool, wait_options uint) *Tracee {
|
||||
if tracee == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Zombies first
|
||||
// for
|
||||
for ptracee := tracee.AsPtracer.Zombies.lh_first; ptracee != nil; ptracee = ptracee.Link.Next {
|
||||
if ptracee.PID != Pid {
|
||||
continue
|
||||
}
|
||||
|
||||
if !ExpectedWaitClone(wait_options, ptracee) {
|
||||
continue
|
||||
}
|
||||
|
||||
return ptracee
|
||||
}
|
||||
|
||||
for ptracee := tracee.RootConfig.Tracees.First; ptracee != nil; ptracee = ptracee.Link.Next {
|
||||
// if ((ptracee->as_ptracee).ptracer != ptracer)
|
||||
// continue;
|
||||
// if (pid != ptracee->pid && pid != -1)
|
||||
// continue;
|
||||
// if (!EXPECTED_WAIT_CLONE(wait_options, ptracee))
|
||||
// continue;
|
||||
// if (!only_stopped)
|
||||
// return ptracee;
|
||||
// if (ptracee->running)
|
||||
// continue;
|
||||
// if ((ptracee->as_ptracee).event4.ptracer.pending || !only_with_pevent)
|
||||
// return ptracee;
|
||||
// if (pid == ptracee->pid)
|
||||
// return NULL;
|
||||
|
||||
if ptracee.PID != Pid {
|
||||
continue
|
||||
}
|
||||
if !ExpectedWaitClone(wait_options, ptracee) {
|
||||
continue
|
||||
}
|
||||
if !onlyStopped {
|
||||
return ptracee
|
||||
}
|
||||
if ptracee.Running {
|
||||
continue
|
||||
}
|
||||
if ptracee.AsPtracee.Event4.Ptracer.Pending || !onlyWithPevent {
|
||||
return ptracee
|
||||
}
|
||||
if ptracee.PID == Pid {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Wrapper for get_ptracee(), this ensures only a stopped tracee is returned (or NULL).
|
||||
func (tracee *Tracee) GetStoppedPtracee(Pid int, onlyWithPevent bool, wait_options uint) *Tracee {
|
||||
return tracee.GetPtracee(Pid, true, onlyWithPevent, wait_options)
|
||||
}
|
||||
|
||||
// Wrapper for get_ptracee(), this ensures no running tracee is returned.
|
||||
func (tracee *Tracee) HasPtracees(Pid int, wait_options uint) bool {
|
||||
return tracee.GetPtracee(Pid, false, false, wait_options) != nil
|
||||
}
|
||||
|
||||
// Mark tracee as terminated and optionally take action.
|
||||
func (tracee *Tracee) TerminateTracee() {
|
||||
tracee.Terminated = true
|
||||
if tracee.KillallOnExit {
|
||||
tracee.KillAllTracees()
|
||||
}
|
||||
}
|
||||
|
||||
// Free all tracees marked as terminated.
|
||||
func (tracee *Tracee) FreeTerminatedTracees() {
|
||||
next := tracee.RootConfig.Tracees.First
|
||||
for next != nil {
|
||||
tracee := next
|
||||
next = tracee.Link.Next
|
||||
if tracee.Terminated {
|
||||
tracee.TerminateTracee()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Send the KILL signal to all tracees.
|
||||
func (tracee *Tracee) KillAllTracees() {
|
||||
for tracee := tracee.RootConfig.Tracees.First; tracee != nil; tracee = tracee.Link.Next {
|
||||
syscall.Kill(tracee.PID, syscall.SIGKILL)
|
||||
}
|
||||
}
|
||||
|
||||
// Make new @parent's child inherit from it. Depending on @clone_flags,
|
||||
// some information are copied or shared.
|
||||
// This function returns -errno if an error occured, otherwise 0.
|
||||
func (tracee *Tracee) NewChild(cloneFlags uint) error {
|
||||
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user