mirror of
https://github.com/criyle/go-judge.git
synced 2025-11-04 14:50:02 +08:00
Add MacOS support
This commit is contained in:
parent
5e5112a8ab
commit
9e127f669f
1
.gitignore
vendored
1
.gitignore
vendored
@ -27,3 +27,4 @@ package*.json
|
||||
|
||||
example.js
|
||||
executor_server.h
|
||||
/executor_server
|
||||
|
||||
@ -1,4 +1,22 @@
|
||||
package main
|
||||
|
||||
func initEnvPool() {
|
||||
import (
|
||||
"github.com/criyle/go-judge/pkg/macsandbox"
|
||||
"github.com/criyle/go-judge/pkg/pool"
|
||||
)
|
||||
|
||||
var defaultRead = []string{
|
||||
"/",
|
||||
}
|
||||
|
||||
var defaultWrite = []string{
|
||||
"/tmp",
|
||||
"/dev/null",
|
||||
"/var/tmp",
|
||||
}
|
||||
|
||||
func initEnvPool() {
|
||||
b := macsandbox.NewBuilder("", defaultRead, defaultWrite, *netShare)
|
||||
printLog("created mac sandbox at", "")
|
||||
envPool = pool.NewPool(b)
|
||||
}
|
||||
|
||||
@ -194,10 +194,16 @@ func prepareCmd(rc cmd) (*envexec.Cmd, map[string]bool, error) {
|
||||
}
|
||||
}
|
||||
|
||||
timeLimit := time.Duration(rc.CPULimit)
|
||||
if rc.RealCPULimit > rc.CPULimit {
|
||||
timeLimit = time.Duration(rc.RealCPULimit)
|
||||
}
|
||||
|
||||
return &envexec.Cmd{
|
||||
Args: rc.Args,
|
||||
Env: rc.Env,
|
||||
Files: files,
|
||||
TimeLimit: timeLimit,
|
||||
MemoryLimit: runner.Size(rc.MemoryLimit),
|
||||
ProcLimit: rc.ProcLimit,
|
||||
CopyIn: copyIn,
|
||||
|
||||
10
go.mod
10
go.mod
@ -3,13 +3,13 @@ module github.com/criyle/go-judge
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/criyle/go-sandbox v0.3.1
|
||||
github.com/gin-gonic/gin v1.6.2
|
||||
github.com/golang/protobuf v1.3.5 // indirect
|
||||
github.com/criyle/go-sandbox v0.4.2
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
github.com/golang/protobuf v1.4.2 // indirect
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
|
||||
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
)
|
||||
|
||||
50
go.sum
50
go.sum
@ -1,12 +1,14 @@
|
||||
github.com/criyle/go-sandbox v0.3.1 h1:M3xx4Gb/HZQxWfwtnkB49ypU3mnhQ94SGiKVLFthzeE=
|
||||
github.com/criyle/go-sandbox v0.3.1/go.mod h1:Dn0/RUjRolP3Swt3QkxOoF8zK7q6B2bB9nB73IEGlnI=
|
||||
github.com/criyle/go-sandbox v0.4.2 h1:1Ptrf+urY380hBRya5e77Iqsrk4lNK2lAk9LU00nt1s=
|
||||
github.com/criyle/go-sandbox v0.4.2/go.mod h1:0RvgBkgfnuZLQv/0QUJ/No5JrHnt6u9D0iH/DS1u52I=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/elastic/go-seccomp-bpf v1.1.0/go.mod h1:l+89Vy5BzjVcaX8USZRMOwmwwDScE+vxCFzzvQwN7T8=
|
||||
github.com/elastic/go-ucfg v0.7.0/go.mod h1:iaiY0NBIYeasNgycLyTvhJftQlQEUO2hpF+FX0JKxzo=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.6.2 h1:88crIK23zO6TqlQBt+f9FrPJNKm9ZEr7qjp9vl/d5TM=
|
||||
github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
@ -16,8 +18,17 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+
|
||||
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
@ -35,10 +46,9 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLD
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=
|
||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
@ -48,18 +58,34 @@ github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200316214734-08c61614bede h1:+jwX0O5IlL7Cj6iam25CdV2pKzCV737/4ewDRGFvwFQ=
|
||||
golang.org/x/sys v0.0.0-20200316214734-08c61614bede/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
|
||||
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 h1:YTzHMGlqJu67/uEo1lBv0n3wBXhXNeUbB1XfN2vmTm0=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
||||
63
pkg/macsandbox/builder_darwin.go
Normal file
63
pkg/macsandbox/builder_darwin.go
Normal file
@ -0,0 +1,63 @@
|
||||
package macsandbox
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/criyle/go-judge/pkg/pool"
|
||||
)
|
||||
|
||||
var _ pool.EnvBuilder = &Builder{}
|
||||
|
||||
// Builder to create sandbox environment
|
||||
type Builder struct {
|
||||
wd string
|
||||
readablePath, writablePath []string
|
||||
network bool
|
||||
}
|
||||
|
||||
// NewBuilder creates Builder to create sandbox environment
|
||||
func NewBuilder(wd string, readablePath, writablePath []string, network bool) pool.EnvBuilder {
|
||||
return &Builder{
|
||||
wd: wd,
|
||||
readablePath: readablePath,
|
||||
writablePath: writablePath,
|
||||
network: network,
|
||||
}
|
||||
}
|
||||
|
||||
// Build create a sandbox environment
|
||||
func (b *Builder) Build() (pool.Environment, error) {
|
||||
wd, err := ioutil.TempDir(b.wd, "es")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var rp, wp []string
|
||||
rp = append(rp, b.readablePath...)
|
||||
rp = append(rp, wd)
|
||||
|
||||
wp = append(wp, b.writablePath...)
|
||||
wp = append(wp, wd)
|
||||
|
||||
p := &Profile{
|
||||
WritableDir: wp,
|
||||
ReadableDir: rp,
|
||||
Network: b.network,
|
||||
}
|
||||
profile, err := p.Build()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wdf, err := os.Open(wd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &environment{
|
||||
profile: profile,
|
||||
wdPath: wd,
|
||||
wd: wdf,
|
||||
}, nil
|
||||
}
|
||||
172
pkg/macsandbox/environment_darwin.go
Normal file
172
pkg/macsandbox/environment_darwin.go
Normal file
@ -0,0 +1,172 @@
|
||||
package macsandbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/criyle/go-judge/pkg/envexec"
|
||||
"github.com/criyle/go-judge/pkg/pool"
|
||||
"github.com/criyle/go-sandbox/pkg/forkexec"
|
||||
"github.com/criyle/go-sandbox/runner"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var _ pool.Environment = &environment{}
|
||||
|
||||
type environment struct {
|
||||
profile string
|
||||
wdPath string
|
||||
wd *os.File
|
||||
}
|
||||
|
||||
func (e *environment) Execve(c context.Context, param envexec.ExecveParam) (envexec.Process, error) {
|
||||
ch := &forkexec.Runner{
|
||||
Args: param.Args,
|
||||
Env: param.Env,
|
||||
Files: param.Files,
|
||||
WorkDir: e.wdPath,
|
||||
SandboxProfile: e.profile,
|
||||
}
|
||||
|
||||
pid, err := ch.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p := &process{
|
||||
pid: pid,
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer close(p.done)
|
||||
|
||||
var sTime, mTime, fTime time.Time
|
||||
// handle cancel
|
||||
ctx, cancel := context.WithCancel(c)
|
||||
defer cancel()
|
||||
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
killAll(pid)
|
||||
}()
|
||||
|
||||
// collect potential zombies
|
||||
defer func() {
|
||||
killAll(pid)
|
||||
collectZombie(pid)
|
||||
}()
|
||||
|
||||
var (
|
||||
wstatus syscall.WaitStatus
|
||||
rusage syscall.Rusage
|
||||
)
|
||||
for {
|
||||
_, err = syscall.Wait4(pid, &wstatus, 0, &rusage)
|
||||
if err == syscall.EINTR {
|
||||
continue
|
||||
}
|
||||
fTime = time.Now()
|
||||
if err != nil {
|
||||
p.result.Error = err.Error()
|
||||
p.result.Status = runner.StatusRunnerError
|
||||
return
|
||||
}
|
||||
p.result = runner.Result{
|
||||
Status: runner.StatusNormal,
|
||||
Time: time.Duration(rusage.Utime.Nano()),
|
||||
Memory: runner.Size(rusage.Maxrss), // seems MacOS uses bytes instead of kb
|
||||
SetUpTime: mTime.Sub(sTime),
|
||||
RunningTime: fTime.Sub(mTime),
|
||||
}
|
||||
if p.result.Time > param.Limit.Time {
|
||||
p.result.Status = runner.StatusTimeLimitExceeded
|
||||
}
|
||||
if p.result.Memory > param.Limit.Memory {
|
||||
p.result.Status = runner.StatusMemoryLimitExceeded
|
||||
}
|
||||
|
||||
switch {
|
||||
case wstatus.Exited():
|
||||
if status := wstatus.ExitStatus(); status != 0 {
|
||||
p.result.Status = runner.StatusNonzeroExitStatus
|
||||
return
|
||||
}
|
||||
return
|
||||
|
||||
case wstatus.Signaled():
|
||||
sig := wstatus.Signal()
|
||||
switch sig {
|
||||
case unix.SIGXCPU, unix.SIGKILL:
|
||||
p.result.Status = runner.StatusTimeLimitExceeded
|
||||
case unix.SIGXFSZ:
|
||||
p.result.Status = runner.StatusOutputLimitExceeded
|
||||
case unix.SIGSYS:
|
||||
p.result.Status = runner.StatusDisallowedSyscall
|
||||
default:
|
||||
p.result.Status = runner.StatusSignalled
|
||||
}
|
||||
p.result.ExitStatus = int(sig)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (e *environment) WorkDir() *os.File {
|
||||
return e.wd
|
||||
}
|
||||
|
||||
func (e *environment) Open(p string, flags int, perm os.FileMode) (*os.File, error) {
|
||||
return os.OpenFile(path.Join(e.wdPath, p), flags, perm)
|
||||
}
|
||||
|
||||
func (e *environment) Destroy() error {
|
||||
e.wd.Close()
|
||||
return os.RemoveAll(e.wdPath)
|
||||
}
|
||||
|
||||
func (e *environment) Reset() error {
|
||||
return removeContents(e.wdPath)
|
||||
}
|
||||
|
||||
// removeContents delete content of a directory
|
||||
func removeContents(dir string) error {
|
||||
d, err := os.Open(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
names, err := d.Readdirnames(-1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
err = os.RemoveAll(path.Join(dir, name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func killAll(pid int) {
|
||||
syscall.Kill(pid, syscall.SIGKILL)
|
||||
}
|
||||
|
||||
// collect died child processes
|
||||
func collectZombie(pgid int) {
|
||||
var wstatus syscall.WaitStatus
|
||||
for {
|
||||
if _, err := syscall.Wait4(-pgid, &wstatus, syscall.WNOHANG, nil); err != syscall.EINTR && err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
27
pkg/macsandbox/process_darwin.go
Normal file
27
pkg/macsandbox/process_darwin.go
Normal file
@ -0,0 +1,27 @@
|
||||
package macsandbox
|
||||
|
||||
import (
|
||||
"github.com/criyle/go-judge/pkg/envexec"
|
||||
"github.com/criyle/go-sandbox/runner"
|
||||
)
|
||||
|
||||
var _ envexec.Process = &process{}
|
||||
|
||||
type process struct {
|
||||
pid int
|
||||
done chan struct{}
|
||||
result runner.Result
|
||||
}
|
||||
|
||||
func (p *process) Done() <-chan struct{} {
|
||||
return p.done
|
||||
}
|
||||
|
||||
func (p *process) Result() runner.Result {
|
||||
<-p.done
|
||||
return p.result
|
||||
}
|
||||
|
||||
func (p *process) Usage() envexec.Usage {
|
||||
return envexec.Usage{}
|
||||
}
|
||||
122
pkg/macsandbox/profile_darwin.go
Normal file
122
pkg/macsandbox/profile_darwin.go
Normal file
@ -0,0 +1,122 @@
|
||||
package macsandbox
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"path/filepath"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// Reference: https://github.com/chromium/chromium/blob/24d4eaa172c6a84974fe7cd4096a60a9b64abd9c/services/service_manager/sandbox/mac/common.sb
|
||||
const sandboxTemplate = `(version 1)
|
||||
|
||||
(deny default)
|
||||
|
||||
; allow posix ipc
|
||||
(allow ipc-posix*)
|
||||
|
||||
; allow execve
|
||||
(allow process-exec)
|
||||
|
||||
; allow fork
|
||||
(allow process-fork)
|
||||
|
||||
; allow signal to self
|
||||
(allow signal (target self))
|
||||
|
||||
; sysctls permitted.
|
||||
(allow sysctl-read
|
||||
(sysctl-name "hw.activecpu")
|
||||
(sysctl-name "hw.busfrequency_compat")
|
||||
(sysctl-name "hw.byteorder")
|
||||
(sysctl-name "hw.cachelinesize_compat")
|
||||
(sysctl-name "hw.cpufrequency_compat")
|
||||
(sysctl-name "hw.cputype")
|
||||
(sysctl-name "hw.logicalcpu_max")
|
||||
(sysctl-name "hw.machine")
|
||||
(sysctl-name "hw.ncpu")
|
||||
(sysctl-name "hw.pagesize_compat")
|
||||
(sysctl-name "hw.physicalcpu_max")
|
||||
(sysctl-name "hw.tbfrequency_compat")
|
||||
(sysctl-name "hw.vectorunit")
|
||||
(sysctl-name "kern.hostname")
|
||||
(sysctl-name "kern.maxfilesperproc")
|
||||
(sysctl-name "kern.osrelease")
|
||||
(sysctl-name "kern.ostype")
|
||||
(sysctl-name "kern.osvariant_status")
|
||||
(sysctl-name "kern.osversion")
|
||||
(sysctl-name "kern.usrstack64")
|
||||
(sysctl-name "kern.version")
|
||||
(sysctl-name "sysctl.proc_cputype")
|
||||
(sysctl-name "kern.proc.pid.CURRENT_PID")
|
||||
)
|
||||
|
||||
; allow read from dir
|
||||
{{- range $dir := .ReadableDir }}
|
||||
(allow file-read* (subpath "{{$dir}}"))
|
||||
{{- end }}
|
||||
|
||||
; deny users
|
||||
(deny file-read* (subpath "/Users"))
|
||||
|
||||
; allow write to dir
|
||||
{{- range $dir := .WritableDir }}
|
||||
(allow file-write* (subpath "{{$dir}}"))
|
||||
{{- end }}
|
||||
|
||||
{{- if .Network }}
|
||||
(allow network-outbound)
|
||||
{{- end }}
|
||||
`
|
||||
|
||||
var profileTpl = template.Must(template.New("profile").Parse(sandboxTemplate))
|
||||
|
||||
// Profile defines MacOS sandbox profile
|
||||
type Profile struct {
|
||||
WritableDir, ReadableDir []string
|
||||
Network bool
|
||||
}
|
||||
|
||||
// DefaultProfile defines the minimun default profile to run programs
|
||||
var DefaultProfile = Profile{
|
||||
ReadableDir: []string{"/usr/lib"},
|
||||
}
|
||||
|
||||
// Build generates the sandbox profile
|
||||
func (p *Profile) Build() (string, error) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
realRead, err := getRealPaths(p.ReadableDir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
realWrite, err := getRealPaths(p.WritableDir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
realProfile := Profile{
|
||||
WritableDir: realWrite,
|
||||
ReadableDir: realRead,
|
||||
Network: p.Network,
|
||||
}
|
||||
|
||||
if err := profileTpl.Execute(&buf, realProfile); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func getRealPath(s string) (string, error) {
|
||||
return filepath.EvalSymlinks(s)
|
||||
}
|
||||
|
||||
func getRealPaths(original []string) ([]string, error) {
|
||||
ret := make([]string, 0, len(original))
|
||||
for _, s := range original {
|
||||
t, err := getRealPath(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, t)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user