Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BPF 'cpu' #299

Open
wants to merge 12 commits into
base: unstable
Choose a base branch
from
Open

Add BPF 'cpu' #299

wants to merge 12 commits into from

Conversation

Grazfather
Copy link
Contributor

This change is still a WiP, but it adds a BPF emulator and a command that loads a filter and a packet and runs the filter against it.

@Grazfather Grazfather changed the base branch from master to unstable April 12, 2018 01:17
Makefile Outdated
@echo "$(GOBUILD) -o bpf ./go/cmd/bpf"
@sh -c "PATH=$(PATHX) $(GOBUILD) -o bpf ./go/cmd/bpf"
$(FIXRPATH) bpf

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're ending up with a lot of commands... there must be a better way than just copy pasting this a hundred times :D (I was considering doing a busybox-style combined command for the main binary)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suck at makefiles, but could we do a sub on ALL_TARGETS .to make a phony target, and then

%: %.bla .gopath
	@echo "$(GOBUILD) -o $@ ./go/cmd/$@"
	@sh -c "PATH=$(PATHX) $(GOBUILD) -o $@ ./go/cmd/$@"+	$(FIXRPATH) $@

"A": bpf.A,
"X": bpf.X,
"PC": bpf.PC,
},
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could totally generate this table with reflection on a Regs struct


DefaultRegs: []string{
"M0", "M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9",
"M10", "M11", "M12", "M13", "M14", "M15", "A", "X", "PC"},
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could default to Regs, it's basically just a list of regs to print while debugging (e.g. potentially everything but PC and SP)

return nil
},
Interrupt: func(_ models.Usercorn, _ uint32) {},
})
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, any feedback on the RegisterOS api for weird things that don't really have OS flavors?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't looked into it much. I think for ebpf extensions we may want an OS, but before I considered this, I thought about creating a 'noos' or 'nullos' that basically panics in functions.

"github.com/pkg/errors"
"os"

usercorn "github.com/lunixbochs/usercorn/go"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this already import as usercorn? Are you just being explicit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vim-go decided to format it this way when I ran :GoImports. I can fix it.

}

c.MakeUsercorn = func(filter string) (models.Usercorn, error) {
// TODO: Why is packet never parsing out (always the default!)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep I've tried. I confirmed it's being called and they are being parsed before reading from it, but no luck. I can dig in more later.

return nil
}

func (c *BpfCpu) Backend() interface{} {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one isn't super important, as there's no backend handle for homemade cpus (it's used elsewhere to pull back the curtain and access unicorn internals)

ins := code[0].(*ins)
fmt.Printf("%04x: %s\n", pc, ins)

c.OnCode(uint64(pc), uint32(len(ins.bytes)))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're missing OnBlock

op uint16
jt uint8
jf uint8
k uint32 // Depends on addressing mode?
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why store as 32-bit if values can be 64-bit in other addressing modes? mem and regs backends will enforce sizes for you at runtime

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is old. K is at most 32 bits.

i.op = binary.LittleEndian.Uint16(i.bytes)
i.jt = i.bytes[2]
i.jf = i.bytes[3]
i.k = binary.LittleEndian.Uint32(i.bytes[4:])
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it would be a really good use of struc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned on slack: There might be a bug in struc, but I couldn't get this to work properly without putting these fields into a sub-struct. I think it might have to do with struc bailing out when it first sees a non-exported field.

case A_A:
arg = &regA{}
case A_LEN:
arg = nil // TODO
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, this is for BPF extensions which I don't yet support. Will properly note.

i.arg = arg
return i
} else {
// TODO: Remove this once we have all legal opcodes
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still a TODO? should error/panic if so

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Converted string to be arg to panic.

Addr: 0x80000000,
Size: uint64(r.codesize),
Prot: cpu.PROT_READ | cpu.PROT_EXEC,
DataFunc: func() ([]byte, error) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you file an issue to generalize this usage of DataFunc?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you want it generalized?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants