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
|
||||
}
|
||||
|
||||
func getFileMode(flags uint64) string {
|
||||
func getFileMode(flags uint) string {
|
||||
switch flags & syscall.O_ACCMODE {
|
||||
case syscall.O_RDONLY:
|
||||
return "r "
|
||||
@ -49,8 +49,8 @@ func getHandle(t *tracer.Tracer, pType string, addRead []string, addWrite []stri
|
||||
return tracer.TraceKill
|
||||
}
|
||||
|
||||
checkOpen := func(ctx *tracer.Context, addr uint64, flags uint64) tracer.TraceAction {
|
||||
fn := ctx.GetString(addr)
|
||||
checkOpen := func(ctx *tracer.Context, addr uint, flags uint) tracer.TraceAction {
|
||||
fn := ctx.GetString(uintptr(addr))
|
||||
isReadOnly := (flags&syscall.O_ACCMODE == syscall.O_RDONLY) &&
|
||||
(flags&syscall.O_CREAT == 0) &&
|
||||
(flags&syscall.O_EXCL == 0) &&
|
||||
@ -69,8 +69,8 @@ func getHandle(t *tracer.Tracer, pType string, addRead []string, addWrite []stri
|
||||
return tracer.TraceAllow
|
||||
}
|
||||
|
||||
checkRead := func(ctx *tracer.Context, addr uint64) tracer.TraceAction {
|
||||
fn := ctx.GetString(addr)
|
||||
checkRead := func(ctx *tracer.Context, addr uint) tracer.TraceAction {
|
||||
fn := ctx.GetString(uintptr(addr))
|
||||
print("check read: ", fn)
|
||||
if !fs.isReadableFile(&fn) {
|
||||
return onDgsFileDetect(ctx, fn)
|
||||
@ -78,8 +78,8 @@ func getHandle(t *tracer.Tracer, pType string, addRead []string, addWrite []stri
|
||||
return tracer.TraceAllow
|
||||
}
|
||||
|
||||
checkWrite := func(ctx *tracer.Context, addr uint64) tracer.TraceAction {
|
||||
fn := ctx.GetString(addr)
|
||||
checkWrite := func(ctx *tracer.Context, addr uint) tracer.TraceAction {
|
||||
fn := ctx.GetString(uintptr(addr))
|
||||
print("check write: ", fn)
|
||||
if !fs.isWritableFile(&fn) {
|
||||
return onDgsFileDetect(ctx, fn)
|
||||
@ -87,8 +87,8 @@ func getHandle(t *tracer.Tracer, pType string, addRead []string, addWrite []stri
|
||||
return tracer.TraceAllow
|
||||
}
|
||||
|
||||
checkStat := func(ctx *tracer.Context, addr uint64) tracer.TraceAction {
|
||||
fn := ctx.GetString(addr)
|
||||
checkStat := func(ctx *tracer.Context, addr uint) tracer.TraceAction {
|
||||
fn := ctx.GetString(uintptr(addr))
|
||||
print("check stat: ", fn)
|
||||
if !fs.isStatableFile(&fn) {
|
||||
return onDgsFileDetect(ctx, fn)
|
||||
|
||||
@ -76,6 +76,10 @@ func main() {
|
||||
}
|
||||
|
||||
rt, err := t.StartTrace()
|
||||
if t.ShowDetails {
|
||||
fmt.Fprintln(os.Stderr, "Used process_vm_readv: ", tracer.UseVMReadv)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
c, ok := err.(tracer.TraceCode)
|
||||
if !ok {
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
package tracer
|
||||
|
||||
import "syscall"
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Context is the context for current syscall trap
|
||||
// used to retrive syscall number and arguments
|
||||
@ -11,13 +14,15 @@ type Context struct {
|
||||
regs syscall.PtraceRegs
|
||||
}
|
||||
|
||||
func clen(b []byte) int {
|
||||
for i := 0; i < len(b); i++ {
|
||||
if b[i] == 0 {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return len(b) + 1
|
||||
var (
|
||||
// UseVMReadv determine whether use ProcessVMReadv syscall to read str
|
||||
// initial true and becomes false if tried and failed with ENOSYS
|
||||
UseVMReadv = true
|
||||
pageSize = 4 << 10
|
||||
)
|
||||
|
||||
func init() {
|
||||
pageSize = os.Getpagesize()
|
||||
}
|
||||
|
||||
func getTrapContext(pid int) (*Context, error) {
|
||||
@ -31,3 +36,22 @@ func getTrapContext(pid int) (*Context, error) {
|
||||
regs: regs,
|
||||
}, 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
|
||||
|
||||
import "syscall"
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
unix "golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// SyscallNo get current syscall no
|
||||
func (c *Context) SyscallNo() int {
|
||||
return int(c.regs.Orig_rax)
|
||||
func (c *Context) SyscallNo() uint {
|
||||
return uint(c.regs.Orig_rax)
|
||||
}
|
||||
|
||||
// Arg0 gets the arg0 for the current syscall
|
||||
func (c *Context) Arg0() uint64 {
|
||||
return c.regs.Rdi
|
||||
func (c *Context) Arg0() uint {
|
||||
return uint(c.regs.Rdi)
|
||||
}
|
||||
|
||||
// Arg1 gets the arg1 for the current syscall
|
||||
func (c *Context) Arg1() uint64 {
|
||||
return c.regs.Rsi
|
||||
func (c *Context) Arg1() uint {
|
||||
return uint(c.regs.Rsi)
|
||||
}
|
||||
|
||||
// Arg2 gets the arg2 for the current syscall
|
||||
func (c *Context) Arg2() uint64 {
|
||||
return c.regs.Rdx
|
||||
func (c *Context) Arg2() uint {
|
||||
return uint(c.regs.Rdx)
|
||||
}
|
||||
|
||||
// Arg3 gets the arg3 for the current syscall
|
||||
func (c *Context) Arg3() uint64 {
|
||||
return c.regs.R10
|
||||
func (c *Context) Arg3() uint {
|
||||
return uint(c.regs.R10)
|
||||
}
|
||||
|
||||
// Arg4 gets the arg4 for the current syscall
|
||||
func (c *Context) Arg4() uint64 {
|
||||
return c.regs.R8
|
||||
func (c *Context) Arg4() uint {
|
||||
return uint(c.regs.R8)
|
||||
}
|
||||
|
||||
// Arg5 gets the arg5 for the current syscall
|
||||
func (c *Context) Arg5() uint64 {
|
||||
return 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)])
|
||||
func (c *Context) Arg5() uint {
|
||||
return uint(c.regs.R9)
|
||||
}
|
||||
|
||||
// SetReturnValue set the return value if skip the syscall
|
||||
@ -50,6 +47,15 @@ func (c *Context) SetReturnValue(retval int) {
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
func NewTracer() Tracer {
|
||||
allow := make([]string, len(defaultAllows))
|
||||
copy(allow, defaultAllows)
|
||||
|
||||
trace := make([]string, len(defaultTraces))
|
||||
copy(trace, defaultTraces)
|
||||
// default settings
|
||||
return Tracer{
|
||||
TimeLimit: 1,
|
||||
@ -101,7 +96,7 @@ func NewTracer() Tracer {
|
||||
OutputLimit: 64,
|
||||
StackLimit: 1024,
|
||||
|
||||
Allow: allow,
|
||||
Trace: trace,
|
||||
Allow: append([]string{}, defaultAllows...),
|
||||
Trace: append([]string{}, defaultTraces...),
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user