github.com/criyle/go-sandbox@v0.10.3/runner/ptrace/handle_linux.go (about) 1 package ptrace 2 3 import ( 4 "fmt" 5 "os" 6 "path" 7 "syscall" 8 9 "github.com/criyle/go-sandbox/pkg/seccomp/libseccomp" 10 "github.com/criyle/go-sandbox/ptracer" 11 ) 12 13 type tracerHandler struct { 14 ShowDetails, Unsafe bool 15 Handler Handler 16 } 17 18 func (h *tracerHandler) Debug(v ...interface{}) { 19 if h.ShowDetails { 20 fmt.Fprintln(os.Stderr, v...) 21 } 22 } 23 24 func (h *tracerHandler) getString(ctx *ptracer.Context, addr uint) string { 25 return absPath(ctx.Pid, ctx.GetString(uintptr(addr))) 26 } 27 28 func (h *tracerHandler) checkOpen(ctx *ptracer.Context, addr uint, flags uint) ptracer.TraceAction { 29 fn := h.getString(ctx, addr) 30 isReadOnly := (flags&syscall.O_ACCMODE == syscall.O_RDONLY) && 31 (flags&syscall.O_CREAT == 0) && 32 (flags&syscall.O_EXCL == 0) && 33 (flags&syscall.O_TRUNC == 0) 34 35 h.Debug("open: ", fn, getFileMode(flags)) 36 if isReadOnly { 37 return h.Handler.CheckRead(fn) 38 } 39 return h.Handler.CheckWrite(fn) 40 } 41 42 func (h *tracerHandler) checkRead(ctx *ptracer.Context, addr uint) ptracer.TraceAction { 43 fn := h.getString(ctx, addr) 44 h.Debug("check read: ", fn) 45 return h.Handler.CheckRead(fn) 46 } 47 48 func (h *tracerHandler) checkWrite(ctx *ptracer.Context, addr uint) ptracer.TraceAction { 49 fn := h.getString(ctx, addr) 50 h.Debug("check write: ", fn) 51 return h.Handler.CheckWrite(fn) 52 } 53 54 func (h *tracerHandler) checkStat(ctx *ptracer.Context, addr uint) ptracer.TraceAction { 55 fn := h.getString(ctx, addr) 56 h.Debug("check stat: ", fn) 57 return h.Handler.CheckStat(fn) 58 } 59 60 func (h *tracerHandler) Handle(ctx *ptracer.Context) ptracer.TraceAction { 61 syscallNo := ctx.SyscallNo() 62 syscallName, err := libseccomp.ToSyscallName(syscallNo) 63 h.Debug("syscall:", syscallNo, syscallName, err) 64 if err != nil { 65 h.Debug("invalid syscall no") 66 return ptracer.TraceKill 67 } 68 69 action := ptracer.TraceKill 70 switch syscallName { 71 case "open": 72 action = h.checkOpen(ctx, ctx.Arg0(), ctx.Arg1()) 73 case "openat": 74 action = h.checkOpen(ctx, ctx.Arg1(), ctx.Arg2()) 75 76 case "readlink": 77 action = h.checkRead(ctx, ctx.Arg0()) 78 case "readlinkat": 79 action = h.checkRead(ctx, ctx.Arg1()) 80 81 case "unlink": 82 action = h.checkWrite(ctx, ctx.Arg0()) 83 case "unlinkat": 84 action = h.checkWrite(ctx, ctx.Arg1()) 85 86 case "access": 87 action = h.checkStat(ctx, ctx.Arg0()) 88 case "faccessat", "newfstatat": 89 action = h.checkStat(ctx, ctx.Arg1()) 90 91 case "stat", "stat64": 92 action = h.checkStat(ctx, ctx.Arg0()) 93 case "lstat", "lstat64": 94 action = h.checkStat(ctx, ctx.Arg0()) 95 96 case "execve": 97 action = h.checkRead(ctx, ctx.Arg0()) 98 case "execveat": 99 action = h.checkRead(ctx, ctx.Arg1()) 100 101 case "chmod": 102 action = h.checkWrite(ctx, ctx.Arg0()) 103 case "rename": 104 action = h.checkWrite(ctx, ctx.Arg0()) 105 106 default: 107 action = h.Handler.CheckSyscall(syscallName) 108 if h.Unsafe && action == ptracer.TraceKill { 109 action = ptracer.TraceBan 110 } 111 } 112 113 switch action { 114 case ptracer.TraceAllow: 115 return ptracer.TraceAllow 116 case ptracer.TraceBan: 117 h.Debug("<soft ban syscall>") 118 return softBanSyscall(ctx) 119 default: 120 return ptracer.TraceKill 121 } 122 } 123 124 func softBanSyscall(ctx *ptracer.Context) ptracer.TraceAction { 125 ctx.SetReturnValue(-int(BanRet)) 126 return ptracer.TraceBan 127 } 128 129 func getFileMode(flags uint) string { 130 switch flags & syscall.O_ACCMODE { 131 case syscall.O_RDONLY: 132 return "r " 133 case syscall.O_WRONLY: 134 return "w " 135 case syscall.O_RDWR: 136 return "wr" 137 default: 138 return "??" 139 } 140 } 141 142 // getProcCwd gets the process CWD 143 func getProcCwd(pid int) string { 144 fileName := "/proc/self/cwd" 145 if pid > 0 { 146 fileName = fmt.Sprintf("/proc/%d/cwd", pid) 147 } 148 s, err := os.Readlink(fileName) 149 if err != nil { 150 return "" 151 } 152 return s 153 } 154 155 // absPath calculates the absolute path for a process 156 // built-in function did the dirty works to resolve relative paths 157 func absPath(pid int, p string) string { 158 // if relative path 159 if !path.IsAbs(p) { 160 return path.Join(getProcCwd(pid), p) 161 } 162 return path.Clean(p) 163 }