mirror of
https://github.com/criyle/go-sandbox.git
synced 2025-11-04 14:49:53 +08:00
add process_vm_readv for blocked read
This commit is contained in:
parent
600acacbd5
commit
80f9a1a2d4
@ -14,7 +14,7 @@ func softBanSyscall(ctx *tracer.Context) tracer.TraceAction {
|
|||||||
return tracer.TraceBan
|
return tracer.TraceBan
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFileMode(flags uint64) string {
|
func getFileMode(flags uint) string {
|
||||||
switch flags & syscall.O_ACCMODE {
|
switch flags & syscall.O_ACCMODE {
|
||||||
case syscall.O_RDONLY:
|
case syscall.O_RDONLY:
|
||||||
return "r "
|
return "r "
|
||||||
@ -49,8 +49,8 @@ func getHandle(t *tracer.Tracer, pType string, addRead []string, addWrite []stri
|
|||||||
return tracer.TraceKill
|
return tracer.TraceKill
|
||||||
}
|
}
|
||||||
|
|
||||||
checkOpen := func(ctx *tracer.Context, addr uint64, flags uint64) tracer.TraceAction {
|
checkOpen := func(ctx *tracer.Context, addr uint, flags uint) tracer.TraceAction {
|
||||||
fn := ctx.GetString(addr)
|
fn := ctx.GetString(uintptr(addr))
|
||||||
isReadOnly := (flags&syscall.O_ACCMODE == syscall.O_RDONLY) &&
|
isReadOnly := (flags&syscall.O_ACCMODE == syscall.O_RDONLY) &&
|
||||||
(flags&syscall.O_CREAT == 0) &&
|
(flags&syscall.O_CREAT == 0) &&
|
||||||
(flags&syscall.O_EXCL == 0) &&
|
(flags&syscall.O_EXCL == 0) &&
|
||||||
@ -69,8 +69,8 @@ func getHandle(t *tracer.Tracer, pType string, addRead []string, addWrite []stri
|
|||||||
return tracer.TraceAllow
|
return tracer.TraceAllow
|
||||||
}
|
}
|
||||||
|
|
||||||
checkRead := func(ctx *tracer.Context, addr uint64) tracer.TraceAction {
|
checkRead := func(ctx *tracer.Context, addr uint) tracer.TraceAction {
|
||||||
fn := ctx.GetString(addr)
|
fn := ctx.GetString(uintptr(addr))
|
||||||
print("check read: ", fn)
|
print("check read: ", fn)
|
||||||
if !fs.isReadableFile(&fn) {
|
if !fs.isReadableFile(&fn) {
|
||||||
return onDgsFileDetect(ctx, fn)
|
return onDgsFileDetect(ctx, fn)
|
||||||
@ -78,8 +78,8 @@ func getHandle(t *tracer.Tracer, pType string, addRead []string, addWrite []stri
|
|||||||
return tracer.TraceAllow
|
return tracer.TraceAllow
|
||||||
}
|
}
|
||||||
|
|
||||||
checkWrite := func(ctx *tracer.Context, addr uint64) tracer.TraceAction {
|
checkWrite := func(ctx *tracer.Context, addr uint) tracer.TraceAction {
|
||||||
fn := ctx.GetString(addr)
|
fn := ctx.GetString(uintptr(addr))
|
||||||
print("check write: ", fn)
|
print("check write: ", fn)
|
||||||
if !fs.isWritableFile(&fn) {
|
if !fs.isWritableFile(&fn) {
|
||||||
return onDgsFileDetect(ctx, fn)
|
return onDgsFileDetect(ctx, fn)
|
||||||
@ -87,8 +87,8 @@ func getHandle(t *tracer.Tracer, pType string, addRead []string, addWrite []stri
|
|||||||
return tracer.TraceAllow
|
return tracer.TraceAllow
|
||||||
}
|
}
|
||||||
|
|
||||||
checkStat := func(ctx *tracer.Context, addr uint64) tracer.TraceAction {
|
checkStat := func(ctx *tracer.Context, addr uint) tracer.TraceAction {
|
||||||
fn := ctx.GetString(addr)
|
fn := ctx.GetString(uintptr(addr))
|
||||||
print("check stat: ", fn)
|
print("check stat: ", fn)
|
||||||
if !fs.isStatableFile(&fn) {
|
if !fs.isStatableFile(&fn) {
|
||||||
return onDgsFileDetect(ctx, fn)
|
return onDgsFileDetect(ctx, fn)
|
||||||
|
|||||||
@ -76,6 +76,10 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rt, err := t.StartTrace()
|
rt, err := t.StartTrace()
|
||||||
|
if t.ShowDetails {
|
||||||
|
fmt.Fprintln(os.Stderr, "Used process_vm_readv: ", tracer.UseVMReadv)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c, ok := err.(tracer.TraceCode)
|
c, ok := err.(tracer.TraceCode)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
package tracer
|
package tracer
|
||||||
|
|
||||||
import "syscall"
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
// Context is the context for current syscall trap
|
// Context is the context for current syscall trap
|
||||||
// used to retrive syscall number and arguments
|
// used to retrive syscall number and arguments
|
||||||
@ -11,13 +14,15 @@ type Context struct {
|
|||||||
regs syscall.PtraceRegs
|
regs syscall.PtraceRegs
|
||||||
}
|
}
|
||||||
|
|
||||||
func clen(b []byte) int {
|
var (
|
||||||
for i := 0; i < len(b); i++ {
|
// UseVMReadv determine whether use ProcessVMReadv syscall to read str
|
||||||
if b[i] == 0 {
|
// initial true and becomes false if tried and failed with ENOSYS
|
||||||
return i
|
UseVMReadv = true
|
||||||
}
|
pageSize = 4 << 10
|
||||||
}
|
)
|
||||||
return len(b) + 1
|
|
||||||
|
func init() {
|
||||||
|
pageSize = os.Getpagesize()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTrapContext(pid int) (*Context, error) {
|
func getTrapContext(pid int) (*Context, error) {
|
||||||
@ -31,3 +36,22 @@ func getTrapContext(pid int) (*Context, error) {
|
|||||||
regs: regs,
|
regs: regs,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetString get the string from process data segment
|
||||||
|
func (c *Context) GetString(addr uintptr) string {
|
||||||
|
buff := make([]byte, syscall.PathMax)
|
||||||
|
if UseVMReadv {
|
||||||
|
if err := vmReadStr(c.Pid, addr, buff); err != nil {
|
||||||
|
// if ENOSYS, then disable this function
|
||||||
|
if no, ok := err.(syscall.Errno); ok {
|
||||||
|
if no == syscall.ENOSYS {
|
||||||
|
UseVMReadv = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return string(buff[:clen(buff)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syscall.PtracePeekData(c.Pid, addr, buff)
|
||||||
|
return string(buff[:clen(buff)])
|
||||||
|
}
|
||||||
|
|||||||
@ -1,47 +1,44 @@
|
|||||||
package tracer
|
package tracer
|
||||||
|
|
||||||
import "syscall"
|
import (
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
unix "golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
// SyscallNo get current syscall no
|
// SyscallNo get current syscall no
|
||||||
func (c *Context) SyscallNo() int {
|
func (c *Context) SyscallNo() uint {
|
||||||
return int(c.regs.Orig_rax)
|
return uint(c.regs.Orig_rax)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arg0 gets the arg0 for the current syscall
|
// Arg0 gets the arg0 for the current syscall
|
||||||
func (c *Context) Arg0() uint64 {
|
func (c *Context) Arg0() uint {
|
||||||
return c.regs.Rdi
|
return uint(c.regs.Rdi)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arg1 gets the arg1 for the current syscall
|
// Arg1 gets the arg1 for the current syscall
|
||||||
func (c *Context) Arg1() uint64 {
|
func (c *Context) Arg1() uint {
|
||||||
return c.regs.Rsi
|
return uint(c.regs.Rsi)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arg2 gets the arg2 for the current syscall
|
// Arg2 gets the arg2 for the current syscall
|
||||||
func (c *Context) Arg2() uint64 {
|
func (c *Context) Arg2() uint {
|
||||||
return c.regs.Rdx
|
return uint(c.regs.Rdx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arg3 gets the arg3 for the current syscall
|
// Arg3 gets the arg3 for the current syscall
|
||||||
func (c *Context) Arg3() uint64 {
|
func (c *Context) Arg3() uint {
|
||||||
return c.regs.R10
|
return uint(c.regs.R10)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arg4 gets the arg4 for the current syscall
|
// Arg4 gets the arg4 for the current syscall
|
||||||
func (c *Context) Arg4() uint64 {
|
func (c *Context) Arg4() uint {
|
||||||
return c.regs.R8
|
return uint(c.regs.R8)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arg5 gets the arg5 for the current syscall
|
// Arg5 gets the arg5 for the current syscall
|
||||||
func (c *Context) Arg5() uint64 {
|
func (c *Context) Arg5() uint {
|
||||||
return c.regs.R9
|
return uint(c.regs.R9)
|
||||||
}
|
|
||||||
|
|
||||||
// GetString get the string from process data segment
|
|
||||||
func (c *Context) GetString(addr uint64) string {
|
|
||||||
buff := make([]byte, syscall.PathMax)
|
|
||||||
syscall.PtracePeekData(c.Pid, uintptr(addr), buff)
|
|
||||||
return string(buff[:clen(buff)])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetReturnValue set the return value if skip the syscall
|
// SetReturnValue set the return value if skip the syscall
|
||||||
@ -50,6 +47,15 @@ func (c *Context) SetReturnValue(retval int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) skipSyscall() error {
|
func (c *Context) skipSyscall() error {
|
||||||
c.regs.Orig_rax = uint64(1<<64 - 1) //-1
|
c.regs.Orig_rax = ^uint64(0) //-1
|
||||||
return syscall.PtraceSetRegs(c.Pid, &c.regs)
|
return syscall.PtraceSetRegs(c.Pid, &c.regs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getIovecs(base *byte, l int) []unix.Iovec {
|
||||||
|
return []unix.Iovec{
|
||||||
|
unix.Iovec{
|
||||||
|
Base: base,
|
||||||
|
Len: uint64(l),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
76
tracer/context_helper.go
Normal file
76
tracer/context_helper.go
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
package tracer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
unix "golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: make this method not to call ptrace too much
|
||||||
|
func ptraceReadStr(pid int, addr uintptr, buff []byte) {
|
||||||
|
syscall.PtracePeekData(pid, addr, buff)
|
||||||
|
}
|
||||||
|
|
||||||
|
func processVMReadv(pid int, localIov, remoteIov []unix.Iovec,
|
||||||
|
flags uintptr) (r1, r2 uintptr, err syscall.Errno) {
|
||||||
|
return syscall.Syscall6(unix.SYS_PROCESS_VM_READV, uintptr(pid),
|
||||||
|
uintptr(unsafe.Pointer(&localIov[0])), uintptr(len(localIov)),
|
||||||
|
uintptr(unsafe.Pointer(&remoteIov[0])), uintptr(len(remoteIov)),
|
||||||
|
flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func vmRead(pid int, addr uintptr, buff []byte) (int, error) {
|
||||||
|
l := len(buff)
|
||||||
|
localIov := getIovecs(&buff[0], l)
|
||||||
|
remoteIov := getIovecs((*byte)(unsafe.Pointer(addr)), l)
|
||||||
|
n, _, err := processVMReadv(pid, localIov, remoteIov, uintptr(0))
|
||||||
|
return int(n), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func vmReadStr(pid int, addr uintptr, buff []byte) error {
|
||||||
|
// Deal with unaligned addr
|
||||||
|
n := 0
|
||||||
|
r := pageSize - int(addr%uintptr(pageSize))
|
||||||
|
if r == 0 {
|
||||||
|
r = pageSize
|
||||||
|
}
|
||||||
|
|
||||||
|
for len(buff) > 0 {
|
||||||
|
if l := len(buff); r < l {
|
||||||
|
r = l
|
||||||
|
}
|
||||||
|
|
||||||
|
nn, err := vmRead(pid, addr+uintptr(n), buff[:r])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasNull(buff[:nn]) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
n += nn
|
||||||
|
buff = buff[nn:]
|
||||||
|
r = pageSize
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasNull(buff []byte) bool {
|
||||||
|
for _, b := range buff {
|
||||||
|
if b == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func clen(b []byte) int {
|
||||||
|
for i := 0; i < len(b); i++ {
|
||||||
|
if b[i] == 0 {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len(b) + 1
|
||||||
|
}
|
||||||
@ -88,11 +88,6 @@ type TraceResult struct {
|
|||||||
|
|
||||||
// NewTracer return new Tracer with default setting
|
// NewTracer return new Tracer with default setting
|
||||||
func NewTracer() Tracer {
|
func NewTracer() Tracer {
|
||||||
allow := make([]string, len(defaultAllows))
|
|
||||||
copy(allow, defaultAllows)
|
|
||||||
|
|
||||||
trace := make([]string, len(defaultTraces))
|
|
||||||
copy(trace, defaultTraces)
|
|
||||||
// default settings
|
// default settings
|
||||||
return Tracer{
|
return Tracer{
|
||||||
TimeLimit: 1,
|
TimeLimit: 1,
|
||||||
@ -101,7 +96,7 @@ func NewTracer() Tracer {
|
|||||||
OutputLimit: 64,
|
OutputLimit: 64,
|
||||||
StackLimit: 1024,
|
StackLimit: 1024,
|
||||||
|
|
||||||
Allow: allow,
|
Allow: append([]string{}, defaultAllows...),
|
||||||
Trace: trace,
|
Trace: append([]string{}, defaultTraces...),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user