Executor server can run without root privilege

- Docker `--privileged` is still required for unshare ...
This commit is contained in:
criyle 2020-05-19 17:28:49 -04:00
parent b480bca277
commit afd580cde3
5 changed files with 59 additions and 20 deletions

View File

@ -505,9 +505,11 @@ Compile On Windows (cygwin):
- [x] Github actions to auto build
- [x] Configure mounts using YAML config file
- [ ] Investigate root-free running mechanism (no cgroup && not set uid / gid)
- [ ] Investigate RLimit settings (cpu, data, fsize, stack, noFile)
- [x] Investigate root-free running mechanism (no cgroup && not set uid / gid)
- [x] Investigate RLimit settings (cpu, data, fsize, stack, noFile)
- [x] Add WebSocket for job submission
- [x] Windows support
- [x] MacOS support
- [ ] GRPC + protobuf support
- [ ] Token-based authentication

20
env/env_linux.go vendored
View File

@ -39,10 +39,16 @@ func NewBuilder(cinitPath, mountConf, tmpFsConf string, netShare bool, printLog
unshareFlags ^= syscall.CLONE_NEWNET
}
// use setuid container only if running in root privilege
var credGen container.CredGenerator
if os.Getuid() == 0 {
credGen = newCredGen()
}
b := &container.Builder{
Root: root,
Mounts: m,
CredGenerator: newCredGen(),
CredGenerator: credGen,
Stderr: true,
CloneFlags: unshareFlags,
ExecFile: cinitPath,
@ -52,8 +58,18 @@ func NewBuilder(cinitPath, mountConf, tmpFsConf string, netShare bool, printLog
return nil, err
}
printLog("Created cgroup builder with:", cgb)
if cg, err := cgb.Build(); err != nil {
printLog("Tested created cgroup with error", err)
printLog("Failed back to rlimit / rusage mode")
cgb = nil
} else {
cg.Destroy()
}
cgroupPool := pool.NewFakeCgroupPool(cgb)
var cgroupPool pool.CgroupPool
if cgb != nil {
cgroupPool = pool.NewFakeCgroupPool(cgb)
}
return pool.NewEnvBuilder(b, cgroupPool), nil
}

View File

@ -70,8 +70,8 @@ func runSingle(m Environment, c *Cmd, fds []*os.File, ptc []pipeCollector) (resu
Memory: rt.Memory,
Files: files,
}
// collect error
if err != nil && result.Error == "" {
// collect error (only if the process exits normally)
if rt.Status == runner.StatusNormal && err != nil && result.Error == "" {
switch err := err.(type) {
case runner.Status:
result.Status = convertStatus(err)

View File

@ -34,12 +34,21 @@ func (c *environ) Reset() error {
// Execve execute process inside the environment
func (c *environ) Execve(ctx context.Context, param envexec.ExecveParam) (envexec.Process, error) {
cg, err := c.cgPool.Get()
if err != nil {
return nil, fmt.Errorf("execve: failed to get cgroup %v", err)
var (
cg Cgroup
syncFunc func(int) error
err error
)
if c.cgPool != nil {
cg, err = c.cgPool.Get()
if err != nil {
return nil, fmt.Errorf("execve: failed to get cgroup %v", err)
}
cg.SetMemoryLimit(param.Limit.Memory)
cg.SetProcLimit(param.Limit.Proc)
syncFunc = cg.AddProc
}
cg.SetMemoryLimit(param.Limit.Memory)
cg.SetProcLimit(param.Limit.Proc)
rLimits := rlimit.RLimits{
CPU: uint64(param.Limit.Time.Truncate(time.Second)/time.Second) + 1,
@ -54,7 +63,7 @@ func (c *environ) Execve(ctx context.Context, param envexec.ExecveParam) (envexe
Files: param.Files,
ExecFile: param.ExecFile,
RLimits: rLimits.PrepareRLimit(),
SyncFunc: cg.AddProc,
SyncFunc: syncFunc,
}
rt := c.Environment.Execve(ctx, p)
return newProcess(rt, cg, c.cgPool), nil

View File

@ -1,6 +1,8 @@
package pool
import (
"time"
"github.com/criyle/go-judge/pkg/envexec"
"github.com/criyle/go-sandbox/runner"
)
@ -21,13 +23,17 @@ func newProcess(ch <-chan runner.Result, cg Cgroup, cgPool CgroupPool) *process
}
go func() {
defer close(p.done)
defer cgPool.Put(cg)
p.rt = <-ch
if t, err := cg.CPUUsage(); err == nil {
p.rt.Time = t
if cgPool != nil {
defer cgPool.Put(cg)
}
if m, err := cg.MemoryUsage(); err == nil {
p.rt.Memory = m
p.rt = <-ch
if cg != nil {
if t, err := cg.CPUUsage(); err == nil {
p.rt.Time = t
}
if m, err := cg.MemoryUsage(); err == nil {
p.rt.Memory = m
}
}
}()
return p
@ -43,8 +49,14 @@ func (p *process) Result() runner.Result {
}
func (p *process) Usage() envexec.Usage {
t, _ := p.cg.CPUUsage()
m, _ := p.cg.MemoryUsage()
var (
t time.Duration
m runner.Size
)
if p.cg != nil {
t, _ = p.cg.CPUUsage()
m, _ = p.cg.MemoryUsage()
}
return envexec.Usage{
Time: t,
Memory: m,