support policies, closes #12

This commit is contained in:
Cadey Ratio 2019-12-14 21:04:28 +00:00
parent 37093adeab
commit 7e44d75f68
14 changed files with 166 additions and 17 deletions

18
cmd/internal/policy.go Normal file
View File

@ -0,0 +1,18 @@
package internal
import (
"fmt"
"github.com/hashicorp/go-multierror"
"within.website/olin/policy"
)
func ValidatePolicy(pol policy.Policy) error {
var err error
if pol.RamPageLimit > 2048 {
err = multierror.Append(err, fmt.Errorf("ram page limit is %d, which is over the limit of 2048", pol.RamPageLimit))
}
return err
}

View File

@ -3,12 +3,13 @@ package internal
import "github.com/rogpeppe/go-internal/txtar"
// Topic name for wasmcloud -> executor communication
const TopicName = "wasmcloud-to-executor-09d7e475-71ac-4bdd-be37-050af7a81c58"
const TopicName = "exec"
type ExecRequest struct {
WASMCID string `json:"wasmcid"`
Name string `json:"name"`
Data []byte `json:"data"`
Policy []byte `json:"policy"`
ABI ABI `json:"abi"`
Env map[string]string `json:"env"`
UUID string `json:"uuid"`

View File

@ -8,6 +8,7 @@ const (
)
type Handler struct {
WASM []byte `json:"wasm"`
ABI string `json:"abi"`
WASM []byte `json:"wasm"`
Policy []byte `json:"policy"`
ABI string `json:"abi"`
}

View File

@ -21,6 +21,7 @@ import (
"github.com/rogpeppe/go-internal/txtar"
"tulpa.dev/within/wasmcloud/cmd/internal"
"tulpa.dev/within/wasmcloud/executor"
"within.website/olin/policy"
)
var (
@ -136,8 +137,17 @@ func waitForNewWASM(ctx context.Context, wg *sync.WaitGroup, sh *shell.Shell, nc
LogSink: logBuf,
}
pol, err := policy.Parse(er.Name+".policy", er.Policy)
if err != nil {
log.Printf("can't get policy: %v", err)
continue
}
c.Policy = &pol
result, err := executor.Run(c)
if err != nil {
fmt.Fprintln(logBuf, "can't run binary:", err)
log.Printf("can't run binary: %v", err)
}

View File

@ -15,10 +15,11 @@ import (
"github.com/google/subcommands"
"tulpa.dev/within/wasmcloud/cmd/internal"
"within.website/olin/policy"
)
type handlerCreateCmd struct {
abi string
abi, policyFile string
}
func (handlerCreateCmd) Name() string { return "create" }
@ -38,6 +39,7 @@ Flags:
func (h *handlerCreateCmd) SetFlags(fs *flag.FlagSet) {
fs.StringVar(&h.abi, "abi", "cwa", "WebAssembly ABI to use for the handler")
fs.StringVar(&h.policyFile, "policy", "", "if set, use this policy file for the handler")
}
func (h handlerCreateCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
@ -57,6 +59,25 @@ func (h handlerCreateCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...in
WASM: data,
}
if h.policyFile != "" {
data, err := ioutil.ReadFile(h.policyFile)
if err != nil {
log.Fatal(err)
}
pol, err := policy.Parse(h.policyFile, data)
if err != nil {
log.Fatal(err)
}
err = internal.ValidatePolicy(pol)
if err != nil {
log.Fatal(err)
}
hdlr.Policy = data
}
bodyData, _ := json.Marshal(hdlr)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, *apiServer+"/api/handler/create", bytes.NewBuffer(bodyData))
if err != nil {

View File

@ -15,10 +15,11 @@ import (
"github.com/google/subcommands"
"tulpa.dev/within/wasmcloud/cmd/internal"
"within.website/olin/policy"
)
type handlerUpdateCmd struct {
abi string
abi, policyFile string
}
func (handlerUpdateCmd) Name() string { return "update" }
@ -36,6 +37,7 @@ Flags:
func (h *handlerUpdateCmd) SetFlags(fs *flag.FlagSet) {
fs.StringVar(&h.abi, "abi", "cwa", "WebAssembly ABI to use for the handler")
fs.StringVar(&h.policyFile, "policy", "", "if set, use this policy file for the handler")
}
func (h handlerUpdateCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
@ -56,6 +58,25 @@ func (h handlerUpdateCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...in
WASM: data,
}
if h.policyFile != "" {
data, err := ioutil.ReadFile(h.policyFile)
if err != nil {
log.Fatal(err)
}
pol, err := policy.Parse(h.policyFile, data)
if err != nil {
log.Fatal(err)
}
err = internal.ValidatePolicy(pol)
if err != nil {
log.Fatal(err)
}
hdlr.Policy = data
}
bodyData, _ := json.Marshal(hdlr)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, *apiServer+"/api/handler/update?name="+hname, bytes.NewBuffer(bodyData))
if err != nil {

View File

@ -17,12 +17,12 @@ import (
"github.com/perlin-network/life/exec"
"github.com/rogpeppe/go-internal/txtar"
"tulpa.dev/within/wasmcloud/executor"
"within.website/olin/policy"
)
type runCmd struct {
funcName, abi string
gasLimit uint64
ramLimit int
policyFile string
}
func (runCmd) Name() string { return "run" }
@ -33,7 +33,6 @@ func (runCmd) Usage() string {
return `wasmcloud run [options] <file.wasm>
$ wasmcloud run olinfetch.wasm
$ wasmcloud run -abi dagger -func-name dagger_main hello_dagger.wasm
Run a given webassembly binary and return the output.
@ -47,8 +46,7 @@ Flags:
func (r *runCmd) SetFlags(fs *flag.FlagSet) {
fs.StringVar(&r.funcName, "func-name", "_start", "entrypoint function to call")
fs.StringVar(&r.abi, "abi", "cwa", "ABI to use")
fs.Uint64Var(&r.gasLimit, "gas-limit", 1048576, "number of wasm instructions per execution")
fs.IntVar(&r.ramLimit, "ram-limit", 128, "number of wasm pages that can be used")
fs.StringVar(&r.policyFile, "policy", "", "if set, the policy file to use")
}
func (r runCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
@ -86,9 +84,7 @@ func (r runCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...interface{})
var stdin bytes.Buffer
c := executor.Config{
VMConfig: exec.VMConfig{
GasLimit: r.gasLimit,
ReturnOnGasLimitExceeded: true,
MaxMemoryPages: r.ramLimit,
},
Name: filepath.Base(fname),
@ -101,6 +97,22 @@ func (r runCmd) Execute(ctx context.Context, fs *flag.FlagSet, _ ...interface{})
LogSink: logBuf,
}
if r.policyFile != "" {
data, err := ioutil.ReadFile(r.policyFile)
if err != nil {
log.Fatal(err)
}
pol, err := policy.Parse(r.policyFile, data)
if err != nil {
log.Fatal(err)
}
c.VMConfig.MaxMemoryPages = int(pol.RamPageLimit)
c.VMConfig.GasLimit = uint64(pol.GasLimit)
c.Policy = &pol
}
result, err := executor.Run(c)
if err != nil {
log.Printf("can't run binary: %v", err)

View File

@ -16,6 +16,7 @@ import (
"within.website/ln"
"within.website/ln/opname"
"within.website/olin/namegen"
"within.website/olin/policy"
)
func deleteHandler(w http.ResponseWriter, r *http.Request, u *User) {
@ -72,6 +73,15 @@ func updateHandler(w http.ResponseWriter, r *http.Request, u *User) {
return
}
if len(uHdlr.Policy) != 0 {
err = validatePolicy(name, uHdlr.Policy)
if err != nil {
ln.Error(ctx, err)
http.Error(w, "policy validation failure", http.StatusBadRequest)
return
}
}
cid, err := uploadHandler(uHdlr)
if err != nil {
ln.Error(ctx, err)
@ -79,6 +89,7 @@ func updateHandler(w http.ResponseWriter, r *http.Request, u *User) {
return
}
hdlr.Policy = uHdlr.Policy
hdlr.Path = cid
if err := db.Save(&hdlr).Error; err != nil {
ln.Error(ctx, err)
@ -89,6 +100,15 @@ func updateHandler(w http.ResponseWriter, r *http.Request, u *User) {
json.NewEncoder(w).Encode(hdlr)
}
func validatePolicy(name string, data []byte) error {
pol, err := policy.Parse(name+".policy", data)
if err != nil {
return err
}
return internal.ValidatePolicy(pol)
}
func uploadHandler(hdlr internal.Handler) (string, error) {
sh := shell.NewShell(*ipfsURL)
@ -135,6 +155,19 @@ func createHandler(w http.ResponseWriter, r *http.Request, u *User) {
return
}
n := namegen.Next()
if len(hdlr.Policy) == 0 {
hdlr.Policy = []byte(defaultPolicy)
}
err = validatePolicy(n, hdlr.Policy)
if err != nil {
ln.Error(ctx, err)
http.Error(w, "policy validation failure", http.StatusBadRequest)
return
}
cid, err := uploadHandler(hdlr)
if err != nil {
ln.Error(ctx, err)
@ -142,12 +175,12 @@ func createHandler(w http.ResponseWriter, r *http.Request, u *User) {
return
}
n := namegen.Next()
h := Handler{
Name: n,
User: *u,
UserID: u.ID,
Path: cid,
Policy: hdlr.Policy,
}
if err := db.Save(&h).Error; err != nil {

View File

@ -23,7 +23,8 @@ func runHandler(ctx context.Context, hdlr Handler, timeout time.Duration, messag
"RUN_ID": execID,
"MAGIC_CONCH": "yes",
},
UUID: execID,
UUID: execID,
Policy: hdlr.Policy,
}
encData, err := json.Marshal(er)

View File

@ -37,6 +37,7 @@ type Handler struct {
gorm.Model
Name string `gorm:"unique;not null"`
Path string
Policy []byte
UserID uint `json:"-"`
User User `json:"-"`
}

14
cmd/wasmcloudd/policy.go Normal file
View File

@ -0,0 +1,14 @@
package main
const defaultPolicy = `## The default policy
allow (
^null://$
^random://$
^zero://$
^https://xena.greedo.xeserv.us/files/hello_olin.txt$
)
ram-page-limit 128
gas-limit 1048576
`

View File

@ -15,6 +15,7 @@ import (
"github.com/perlin-network/life/exec"
"github.com/rogpeppe/go-internal/txtar"
"within.website/olin/abi/cwa"
"within.website/olin/policy"
)
var (
@ -24,6 +25,7 @@ var (
type Config struct {
exec.VMConfig
Policy *policy.Policy
Name string
FuncName string
Env map[string]string
@ -77,7 +79,8 @@ func Run(c Config) (*Result, error) {
p.Stdout = c.Stdout
p.Stderr = c.Stderr
p.Logger = log.New(io.MultiWriter(c.LogSink, os.Stdout), c.Name+" ", log.LstdFlags)
p.HC.Transport = WasmcloudBrandingTransport(c.Name, p.HC.Transport)
p.HC.Transport = WasmcloudBrandingTransport(c.Name, http.DefaultTransport)
p.Policy = c.Policy
gp := &compiler.SimpleGasPolicy{GasPerInstruction: 1}
vm, err := exec.NewVirtualMachine(c.Binary, c.VMConfig, p, gp)
@ -92,9 +95,13 @@ func Run(c Config) (*Result, error) {
pagesBefore := len(vm.Memory) / 65536
begin := time.Now()
ret, err := vm.Run(main)
ret, err := vm.RunWithGasLimit(main, int(c.Policy.GasLimit))
if err != nil {
return nil, err
vm.PrintStackTrace()
return &Result{
Status: -2,
StartTime: begin,
}, err
}
dur := time.Since(begin)

3
go.mod
View File

@ -11,8 +11,10 @@ require (
github.com/google/uuid v1.1.1
github.com/gorilla/mux v1.7.3
github.com/gosuri/uitable v0.0.4
github.com/hashicorp/go-multierror v1.0.0
github.com/ipfs/go-ipfs-api v0.0.2
github.com/jinzhu/gorm v1.9.11
github.com/kr/pretty v0.1.0
github.com/lib/pq v1.1.1
github.com/manifoldco/promptui v0.6.0
github.com/mattn/go-sqlite3 v2.0.1+incompatible
@ -20,6 +22,7 @@ require (
github.com/nats-io/nats.go v1.9.1
github.com/perlin-network/life v0.0.0-20191203030451-05c0e0f7eaea
github.com/rogpeppe/go-internal v1.5.0
github.com/rogpeppe/gohack v1.0.2 // indirect
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392
within.website/ln v0.7.0
within.website/olin v0.4.1-0.20191214133128-bde4927fad6b

6
go.sum
View File

@ -143,7 +143,9 @@ github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyF
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc=
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
@ -299,8 +301,11 @@ github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/go-internal v1.0.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.5.0 h1:Usqs0/lDK/NqTkvrmKSwA/3XkZAs7ZAW/eLeQ2MVBTw=
github.com/rogpeppe/go-internal v1.5.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/gohack v1.0.2 h1:lYiGLFzvZC3RvzeE4GoUV3nTecDxTpVusVsQY4nAXGc=
github.com/rogpeppe/gohack v1.0.2/go.mod h1:DE8wqaJRPvHU0fden5cSYy7ar2dTbbccPT/eeOYcbcE=
github.com/sendgrid/rest v2.4.1+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@ -434,6 +439,7 @@ gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20171010053543-63abe20a23e2/go.mo
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=