go-sandbox/runprogram/handle.go

138 lines
3.1 KiB
Go

package runprogram
import (
"fmt"
"os"
"syscall"
libseccomp "github.com/seccomp/libseccomp-golang"
"github.com/criyle/go-judger/tracer"
)
type tracerHandler struct {
ShowDetails, Unsafe bool
Handler Handler
}
func (h *tracerHandler) Debug(v ...interface{}) {
if h.ShowDetails {
fmt.Fprintln(os.Stderr, v...)
}
}
func (h *tracerHandler) checkOpen(ctx *tracer.Context, addr uint, flags uint) TraceAction {
fn := ctx.GetString(uintptr(addr))
isReadOnly := (flags&syscall.O_ACCMODE == syscall.O_RDONLY) &&
(flags&syscall.O_CREAT == 0) &&
(flags&syscall.O_EXCL == 0) &&
(flags&syscall.O_TRUNC == 0)
h.Debug("open: ", fn, getFileMode(flags))
if isReadOnly {
return h.Handler.CheckRead(fn)
}
return h.Handler.CheckWrite(fn)
}
func (h *tracerHandler) checkRead(ctx *tracer.Context, addr uint) TraceAction {
fn := ctx.GetString(uintptr(addr))
h.Debug("check read: ", fn)
return h.Handler.CheckRead(fn)
}
func (h *tracerHandler) checkWrite(ctx *tracer.Context, addr uint) TraceAction {
fn := ctx.GetString(uintptr(addr))
h.Debug("check write: ", fn)
return h.Handler.CheckWrite(fn)
}
func (h *tracerHandler) checkStat(ctx *tracer.Context, addr uint) TraceAction {
fn := ctx.GetString(uintptr(addr))
h.Debug("check stat: ", fn)
return h.Handler.CheckStat(fn)
}
func (h *tracerHandler) Handle(ctx *tracer.Context) tracer.TraceAction {
var (
action TraceAction
syscallNo = ctx.SyscallNo()
syscallName, err = libseccomp.ScmpSyscall(syscallNo).GetName()
)
h.Debug("syscall: ", syscallNo, syscallName, err)
switch syscallName {
case "open":
action = h.checkOpen(ctx, ctx.Arg0(), ctx.Arg1())
case "openat":
action = h.checkOpen(ctx, ctx.Arg1(), ctx.Arg2())
case "readlink":
action = h.checkRead(ctx, ctx.Arg0())
case "readlinkat":
action = h.checkRead(ctx, ctx.Arg1())
case "unlink":
action = h.checkWrite(ctx, ctx.Arg0())
case "unlinkat":
action = h.checkWrite(ctx, ctx.Arg1())
case "access":
action = h.checkStat(ctx, ctx.Arg0())
case "stat", "stat64":
action = h.checkStat(ctx, ctx.Arg0())
case "lstat", "lstat64":
action = h.checkStat(ctx, ctx.Arg0())
case "execve":
action = h.checkRead(ctx, ctx.Arg0())
case "chmod":
action = h.checkWrite(ctx, ctx.Arg0())
case "rename":
action = h.checkWrite(ctx, ctx.Arg0())
default:
action = h.Handler.CheckSyscall(syscallName)
}
switch action {
case TraceAllow:
return tracer.TraceAllow
case TraceBan:
return softBanSyscall(ctx)
default:
return tracer.TraceKill
}
}
func (h *tracerHandler) GetSyscallName(ctx *tracer.Context) (string, error) {
syscallNo := ctx.SyscallNo()
return libseccomp.ScmpSyscall(syscallNo).GetName()
}
func (h *tracerHandler) HandlerDisallow(name string) error {
if !h.Unsafe {
return tracer.TraceCodeBan
}
return nil
}
func softBanSyscall(ctx *tracer.Context) tracer.TraceAction {
ctx.SetReturnValue(-int(BanRet))
return tracer.TraceBan
}
func getFileMode(flags uint) string {
switch flags & syscall.O_ACCMODE {
case syscall.O_RDONLY:
return "r "
case syscall.O_WRONLY:
return "w "
case syscall.O_RDWR:
return "wr"
default:
return "??"
}
}