mirror of
https://github.com/containers/podman.git
synced 2025-08-06 11:32:07 +08:00

This includes two new hidden commands: a 9p server, `podman machine server9p`, and a 9p client, `podman machine client9p` with `server9p` currently only configured to run on Windows and serve 9p via HyperV vsock, and `client9p` only configured to run on Linux. The server is run by `podman machine start` and has the same lifespan as gvproxy (waits for the gvproxy PID to die before shutting down). The client is run inside the VM, also by `podman machine start`, and mounts uses kernel 9p mount code to complete the mount. It's unfortunately not possible to use mount directly without the wrapper; we need to set up the vsock and pass it to mount as an FD. In theory this can be generalized so that the server can run anywhere and over almost any transport, but I haven't done this here as I don't think we have a usecase other than HyperV right now. [NO NEW TESTS NEEDED] This requires changes to Podman in the VM, so we need to wait until a build with this lands in FCOS to test. Signed-off-by: Matthew Heon <matthew.heon@pm.me>
151 lines
4.0 KiB
Go
151 lines
4.0 KiB
Go
// 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
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// A VM is an emulated BPF virtual machine.
|
|
type VM struct {
|
|
filter []Instruction
|
|
}
|
|
|
|
// NewVM returns a new VM using the input BPF program.
|
|
func NewVM(filter []Instruction) (*VM, error) {
|
|
if len(filter) == 0 {
|
|
return nil, errors.New("one or more Instructions must be specified")
|
|
}
|
|
|
|
for i, ins := range filter {
|
|
check := len(filter) - (i + 1)
|
|
switch ins := ins.(type) {
|
|
// Check for out-of-bounds jumps in instructions
|
|
case Jump:
|
|
if check <= int(ins.Skip) {
|
|
return nil, fmt.Errorf("cannot jump %d instructions; jumping past program bounds", ins.Skip)
|
|
}
|
|
case JumpIf:
|
|
if check <= int(ins.SkipTrue) {
|
|
return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue)
|
|
}
|
|
if check <= int(ins.SkipFalse) {
|
|
return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse)
|
|
}
|
|
case JumpIfX:
|
|
if check <= int(ins.SkipTrue) {
|
|
return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue)
|
|
}
|
|
if check <= int(ins.SkipFalse) {
|
|
return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse)
|
|
}
|
|
// Check for division or modulus by zero
|
|
case ALUOpConstant:
|
|
if ins.Val != 0 {
|
|
break
|
|
}
|
|
|
|
switch ins.Op {
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Make sure last instruction is a return instruction
|
|
switch filter[len(filter)-1].(type) {
|
|
case RetA, RetConstant:
|
|
default:
|
|
return nil, errors.New("BPF program must end with RetA or RetConstant")
|
|
}
|
|
|
|
// Though our VM works using disassembled instructions, we
|
|
// attempt to assemble the input filter anyway to ensure it is compatible
|
|
// with an operating system VM.
|
|
_, err := Assemble(filter)
|
|
|
|
return &VM{
|
|
filter: filter,
|
|
}, err
|
|
}
|
|
|
|
// Run runs the VM's BPF program against the input bytes.
|
|
// Run returns the number of bytes accepted by the BPF program, and any errors
|
|
// which occurred while processing the program.
|
|
func (v *VM) Run(in []byte) (int, error) {
|
|
var (
|
|
// Registers of the virtual machine
|
|
regA uint32
|
|
regX uint32
|
|
regScratch [16]uint32
|
|
|
|
// OK is true if the program should continue processing the next
|
|
// instruction, or false if not, causing the loop to break
|
|
ok = true
|
|
)
|
|
|
|
// TODO(mdlayher): implement:
|
|
// - NegateA:
|
|
// - would require a change from uint32 registers to int32
|
|
// registers
|
|
|
|
// TODO(mdlayher): add interop tests that check signedness of ALU
|
|
// operations against kernel implementation, and make sure Go
|
|
// implementation matches behavior
|
|
|
|
for i := 0; i < len(v.filter) && ok; i++ {
|
|
ins := v.filter[i]
|
|
|
|
switch ins := ins.(type) {
|
|
case ALUOpConstant:
|
|
regA = aluOpConstant(ins, regA)
|
|
case ALUOpX:
|
|
regA, ok = aluOpX(ins, regA, regX)
|
|
case Jump:
|
|
i += int(ins.Skip)
|
|
case JumpIf:
|
|
jump := jumpIf(ins, regA)
|
|
i += jump
|
|
case JumpIfX:
|
|
jump := jumpIfX(ins, regA, regX)
|
|
i += jump
|
|
case LoadAbsolute:
|
|
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:
|
|
regX, ok = loadMemShift(ins, in)
|
|
case LoadScratch:
|
|
regA, regX = loadScratch(ins, regScratch, regA, regX)
|
|
case RetA:
|
|
return int(regA), nil
|
|
case RetConstant:
|
|
return int(ins.Val), nil
|
|
case StoreScratch:
|
|
regScratch = storeScratch(ins, regScratch, regA, regX)
|
|
case TAX:
|
|
regX = regA
|
|
case TXA:
|
|
regA = regX
|
|
default:
|
|
return 0, fmt.Errorf("unknown Instruction at index %d: %T", i, ins)
|
|
}
|
|
}
|
|
|
|
return 0, nil
|
|
}
|