From 497925a94dbe83373ed0cf329df0087a7f7dba63 Mon Sep 17 00:00:00 2001 From: AdamKorcz Date: Thu, 11 Mar 2021 14:36:23 +0000 Subject: [PATCH] Added new fuzzer --- libcontainer/libcontainer_fuzzer.go | 85 +++++++++ tests/fuzzing/corpus/state_fuzzer_seed_1 | 180 ++++++++++++++++++ .../dictionaries/state_api_fuzzer.dict | 29 +++ tests/fuzzing/oss_fuzz_build.sh | 4 + 4 files changed, 298 insertions(+) create mode 100644 libcontainer/libcontainer_fuzzer.go create mode 100644 tests/fuzzing/corpus/state_fuzzer_seed_1 create mode 100644 tests/fuzzing/dictionaries/state_api_fuzzer.dict diff --git a/libcontainer/libcontainer_fuzzer.go b/libcontainer/libcontainer_fuzzer.go new file mode 100644 index 00000000000..ba84a9a9266 --- /dev/null +++ b/libcontainer/libcontainer_fuzzer.go @@ -0,0 +1,85 @@ +// +build gofuzz + +package libcontainer + +import ( + "bytes" + "crypto/md5" + "encoding/hex" + "encoding/json" + "errors" + "os" + "strings" + "time" + + "github.com/opencontainers/runc/libcontainer/configs" +) + +func checkRootInData(data []byte, dir string) error { + for i := 0; i < len(dir); i++ { + if !strings.Contains(string(data), dir[:i]) { + return errors.New(dir[:i] + " not found in " + string(data)) + } + } + return nil +} + +func FuzzStateApi(data []byte) int { + if len(data) < 3 { + return -1 + } + if strings.Contains(string(data), "null") { + return -1 + } + root, err := newTestRoot() + if err != nil { + return -1 + } + + // The path to our root dir MUST be found + // in our input + err = checkRootInData(data, root) + if err != nil { + return -1 + } + var config *configs.Config + reader := bytes.NewReader(data) + if err := json.NewDecoder(reader).Decode(&config); err != nil { + return 0 + } + container, err := newContainer(root, config) + if err != nil { + return 0 + } + defer container.Destroy() + _, _ = container.State() + return 1 +} +func newContainer(root string, config *configs.Config) (Container, error) { + h := md5.New() + h.Write([]byte(time.Now().String())) + return newContainerWithName(hex.EncodeToString(h.Sum(nil)), root, config) +} + +func newContainerWithName(name, root string, config *configs.Config) (Container, error) { + f, err := New(root, Cgroupfs) + if err != nil { + return nil, err + } + if config.Cgroups != nil && config.Cgroups.Parent == "system.slice" { + f, err = New(root, SystemdCgroups) + if err != nil { + return nil, err + } + } + return f.Create(name, config) +} + +func newTestRoot() (string, error) { + dir := "/tmp/fuzzing" + if err := os.MkdirAll(dir, 0700); err != nil { + return "", err + } + defer os.RemoveAll(dir) + return dir, nil +} diff --git a/tests/fuzzing/corpus/state_fuzzer_seed_1 b/tests/fuzzing/corpus/state_fuzzer_seed_1 new file mode 100644 index 00000000000..b2ec53a8574 --- /dev/null +++ b/tests/fuzzing/corpus/state_fuzzer_seed_1 @@ -0,0 +1,180 @@ +&configs.Config{ + Rootfs: "/tmp/fuzzing", + Capabilities: &configs.Capabilities{ + Bounding: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Effective: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Inheritable: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Permitted: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + Ambient: []string{ + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_FSETID", + "CAP_FOWNER", + "CAP_MKNOD", + "CAP_NET_RAW", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETFCAP", + "CAP_SETPCAP", + "CAP_NET_BIND_SERVICE", + "CAP_SYS_CHROOT", + "CAP_KILL", + "CAP_AUDIT_WRITE", + }, + }, + Namespaces: configs.Namespaces([]configs.Namespace{ + {Type: configs.NEWNS}, + {Type: configs.NEWUTS}, + {Type: configs.NEWIPC}, + {Type: configs.NEWPID}, + {Type: configs.NEWUSER}, + {Type: configs.NEWNET}, + {Type: configs.NEWCGROUP}, + }), + Cgroups: &configs.Cgroup{ + Name: "test-container", + Parent: "system", + Resources: &configs.Resources{ + MemorySwappiness: nil, + Devices: devices, + }, + }, + MaskPaths: []string{ + "/proc/kcore", + "/sys/firmware", + }, + ReadonlyPaths: []string{ + "/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus", + }, + Devices: specconv.AllowedDevices, + Hostname: "testing", + Mounts: []*configs.Mount{ + { + Source: "proc", + Destination: "/proc", + Device: "proc", + Flags: defaultMountFlags, + }, + { + Source: "tmpfs", + Destination: "/dev", + Device: "tmpfs", + Flags: unix.MS_NOSUID | unix.MS_STRICTATIME, + Data: "mode=755", + }, + { + Source: "devpts", + Destination: "/dev/pts", + Device: "devpts", + Flags: unix.MS_NOSUID | unix.MS_NOEXEC, + Data: "newinstance,ptmxmode=0666,mode=0620,gid=5", + }, + { + Device: "tmpfs", + Source: "shm", + Destination: "/dev/shm", + Data: "mode=1777,size=65536k", + Flags: defaultMountFlags, + }, + { + Source: "mqueue", + Destination: "/dev/mqueue", + Device: "mqueue", + Flags: defaultMountFlags, + }, + { + Source: "sysfs", + Destination: "/sys", + Device: "sysfs", + Flags: defaultMountFlags | unix.MS_RDONLY, + }, + }, + UidMappings: []configs.IDMap{ + { + ContainerID: 0, + HostID: 1000, + Size: 65536, + }, + }, + GidMappings: []configs.IDMap{ + { + ContainerID: 0, + HostID: 1000, + Size: 65536, + }, + }, + Networks: []*configs.Network{ + { + Type: "loopback", + Address: "127.0.0.1/0", + Gateway: "localhost", + }, + }, + Rlimits: []configs.Rlimit{ + { + Type: unix.RLIMIT_NOFILE, + Hard: uint64(1025), + Soft: uint64(1025), + }, + }, +} \ No newline at end of file diff --git a/tests/fuzzing/dictionaries/state_api_fuzzer.dict b/tests/fuzzing/dictionaries/state_api_fuzzer.dict new file mode 100644 index 00000000000..dc6b8cead11 --- /dev/null +++ b/tests/fuzzing/dictionaries/state_api_fuzzer.dict @@ -0,0 +1,29 @@ +"Rootfs" +"/tmp/fuzzing" +"Capabilities" +"Bounding" +"Effective" +"Inheritable" +"Permitted" +"Ambient" +"Namespaces" +"Cgroups" +"Name" +"Parent" +"Resources" +"MemorySwappiness" +"Devices" +"MaskPaths" +"ReadonlyPaths" +"Devices" +"Hostname" +"Mounts" +"UidMappings" +"GidMappings" +"Networks" +"Rlimits" +"Type" +"[]string{" +"}" +":" +"[]configs.Namespace{" diff --git a/tests/fuzzing/oss_fuzz_build.sh b/tests/fuzzing/oss_fuzz_build.sh index f0750e254b1..09d50f48167 100755 --- a/tests/fuzzing/oss_fuzz_build.sh +++ b/tests/fuzzing/oss_fuzz_build.sh @@ -11,3 +11,7 @@ compile_go_fuzzer ./libcontainer/system FuzzUIDMap id_map_fuzzer linux compile_go_fuzzer ./libcontainer/user FuzzUser user_fuzzer compile_go_fuzzer ./libcontainer/configs FuzzUnmarshalJSON configs_fuzzer +compile_go_fuzzer ./libcontainer FuzzStateApi state_api_fuzzer + +zip $OUT/state_api_fuzzer_seed_corpus.zip $SRC/runc/tests/fuzzing/corpus/state_fuzzer_seed_1 +mv $SRC/runc/tests/fuzzing/dictionaries/state_api_fuzzer.dict $OUT/