mirror of
https://github.com/criyle/go-judge.git
synced 2025-11-04 14:50:02 +08:00
Executor server can run without root privilege
- Docker `--privileged` is still required for unshare ...
This commit is contained in:
parent
b480bca277
commit
afd580cde3
@ -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
20
env/env_linux.go
vendored
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user