diff --git a/main.go b/main.go index 87baccf..cf0ad24 100644 --- a/main.go +++ b/main.go @@ -21,13 +21,37 @@ var ( "writeBytes": writeBytesFuzz, "writeNum": writeNumFuzz, } - fuzzTimeout = 500 * time.Millisecond + fuzzTimeout = 500 * time.Millisecond + walkerPlugins []walker.Fuzzer ) +func appInit(c *cli.Context) error { + matches, err := filepath.Glob(c.String("plugins")) + if err != nil { + return err + } + for _, match := range matches { + ff, err := walker.LoadPlugin(match) + if err != nil { + return err + } + walkerPlugins = append(walkerPlugins, ff) + } + return nil +} + func main() { app := cli.NewApp() app.Name = "fuzz-walker" app.Usage = "a walker to poke and prod at /proc and /sys" + app.Before = appInit + app.Flags = []cli.Flag{ + cli.StringFlag{ + Name: "plugins", + Value: "*.so", + Usage: "pattern to glob walker plugins", + }, + } app.Action = func(c *cli.Context) error { hasError := false for _, dir := range dirs { diff --git a/walker/func.go b/walker/func.go index e4304da..3795255 100644 --- a/walker/func.go +++ b/walker/func.go @@ -1,8 +1,34 @@ package walker import ( + "fmt" "os" + "plugin" "time" ) +// LoadPlugin loads the file path and returns a Fuzzer +func LoadPlugin(path string) (Fuzzer, error) { + p, err := plugin.Open(path) + if err != nil { + return nil, err + } + sym, err := p.Lookup("MyFuzzerFunc") + if err != nil { + return nil, err + } + mff, ok := sym.(Fuzzer) + if !ok { + return nil, fmt.Errorf("plugin at %q did not provide a FuzzFunc named MyFuzzerFunc", path) + } + return mff, nil +} + +// Fuzzer is a struct that produces a FuzzFunc +type Fuzzer interface { + Name() string + Func() FuzzFunc +} + +// FuzzFunc is like filepath.WalkerFunc, but for poking at `path` type FuzzFunc func(path string, info os.FileInfo, timeout time.Duration) error