author | Matt Layher
<mdlayher@gmail.com> 2016-06-20 20:30:30 UTC |
committer | Mikio Hara
<mikioh.mikioh@gmail.com> 2016-06-20 21:42:44 UTC |
parent | 8bf2b39827dbadfd566c4fae7a8790d12be8b23c |
bpf/vm.go | +9 | -3 |
bpf/vm_extension_test.go | +49 | -0 |
bpf/vm_instructions.go | +9 | -0 |
diff --git a/bpf/vm.go b/bpf/vm.go index 957c95d..4c656f1 100644 --- a/bpf/vm.go +++ b/bpf/vm.go @@ -45,6 +45,13 @@ func NewVM(filter []Instruction) (*VM, error) { case ALUOpDiv, ALUOpMod: return nil, errors.New("cannot divide by zero using ALUOpConstant") } + // Check for unknown extensions + case LoadExtension: + switch ins.Num { + case ExtLen: + default: + return nil, fmt.Errorf("extension %d not implemented", ins.Num) + } } } @@ -84,9 +91,6 @@ func (v *VM) Run(in []byte) (int, error) { // - NegateA: // - would require a change from uint32 registers to int32 // registers - // - Extension: - // - implement extensions that do not depend on kernel-specific - // functionality, such as 'rand' // TODO(mdlayher): add interop tests that check signedness of ALU // operations against kernel implementation, and make sure Go @@ -109,6 +113,8 @@ func (v *VM) Run(in []byte) (int, error) { regA, ok = loadAbsolute(ins, in) case LoadConstant: regA, regX = loadConstant(ins, regA, regX) + case LoadExtension: + regA = loadExtension(ins, in) case LoadIndirect: regA, ok = loadIndirect(ins, in, regX) case LoadMemShift: diff --git a/bpf/vm_extension_test.go b/bpf/vm_extension_test.go new file mode 100644 index 0000000..7a48c82 --- /dev/null +++ b/bpf/vm_extension_test.go @@ -0,0 +1,49 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bpf_test + +import ( + "testing" + + "golang.org/x/net/bpf" +) + +func TestVMLoadExtensionNotImplemented(t *testing.T) { + _, _, err := testVM(t, []bpf.Instruction{ + bpf.LoadExtension{ + Num: 100, + }, + bpf.RetA{}, + }) + if errStr(err) != "extension 100 not implemented" { + t.Fatalf("unexpected error: %v", err) + } +} + +func TestVMLoadExtensionExtLen(t *testing.T) { + vm, done, err := testVM(t, []bpf.Instruction{ + bpf.LoadExtension{ + Num: bpf.ExtLen, + }, + bpf.RetA{}, + }) + if err != nil { + t.Fatalf("failed to load BPF program: %v", err) + } + defer done() + + out, err := vm.Run([]byte{ + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0, 1, 2, 3, + }) + if err != nil { + t.Fatalf("unexpected error while running program: %v", err) + } + if want, got := 4, out; want != got { + t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d", + want, got) + } +} diff --git a/bpf/vm_instructions.go b/bpf/vm_instructions.go index 7507923..516f946 100644 --- a/bpf/vm_instructions.go +++ b/bpf/vm_instructions.go @@ -103,6 +103,15 @@ func loadConstant(ins LoadConstant, regA uint32, regX uint32) (uint32, uint32) { return regA, regX } +func loadExtension(ins LoadExtension, in []byte) uint32 { + switch ins.Num { + case ExtLen: + return uint32(len(in)) + default: + panic(fmt.Sprintf("unimplemented extension: %d", ins.Num)) + } +} + func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) { offset := int(ins.Off) + int(regX) size := int(ins.Size)