Merge remote-tracking branch 'origin/master' into sf/base-type-impl
# Conflicts: # generator.go
This commit is contained in:
commit
3c5b43322e
3 changed files with 199 additions and 0 deletions
27
clusterfuzz/Dockerfile
Normal file
27
clusterfuzz/Dockerfile
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
FROM ubuntu:20.04
|
||||||
|
|
||||||
|
RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get upgrade -y && \
|
||||||
|
apt-get autoremove -y && \
|
||||||
|
apt-get install -y \
|
||||||
|
git \
|
||||||
|
python \
|
||||||
|
lsb-release \
|
||||||
|
locales \
|
||||||
|
sudo
|
||||||
|
|
||||||
|
|
||||||
|
RUN git clone https://github.com/google/clusterfuzz && \
|
||||||
|
cd clusterfuzz && \
|
||||||
|
git pull && \
|
||||||
|
git checkout tags/v2.6.0 && \
|
||||||
|
local/install_deps.bash
|
||||||
|
|
||||||
|
RUN pip --no-cache-dir install pipenv==2022.8.5
|
||||||
|
|
||||||
|
WORKDIR /clusterfuzz
|
||||||
|
|
||||||
|
CMD ["pipenv", "run", "python", "butler.py", "run_server", "--bootstrap"]
|
||||||
|
EXPOSE 9000
|
57
clusterfuzz/instruction.md
Normal file
57
clusterfuzz/instruction.md
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
# Инструкция по использованию [clusterfuzz](https://github.com/google/clusterfuzz)
|
||||||
|
|
||||||
|
Основывается на:
|
||||||
|
* https://google.github.io/clusterfuzz/
|
||||||
|
* https://google.github.io/oss-fuzz/getting-started/new-project-guide/go-lang/
|
||||||
|
* https://github.com/google/oss-fuzz/blob/master/infra/base-images/base-builder/compile_native_go_fuzzer
|
||||||
|
|
||||||
|
## Поднятие локального инстанса
|
||||||
|
|
||||||
|
Работает на следующих ОС:
|
||||||
|
|
||||||
|
* Ubuntu (16.04, 17.10, 18.04, 18.10, 20.04)
|
||||||
|
* Debian 8 (jessie) or later
|
||||||
|
* Recent versions of macOS with homebrew (experimental)
|
||||||
|
* Note: Only x86 architectures are currently supported
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/google/clusterfuzz
|
||||||
|
cd clusterfuzz
|
||||||
|
git pull
|
||||||
|
git checkout tags/v2.6.0
|
||||||
|
local/install_deps.bash
|
||||||
|
pipenv shell
|
||||||
|
python butler.py run_server --bootstrap
|
||||||
|
```
|
||||||
|
Флаг --bootstrap в последней команде необходим только при первом запуске локального сервера.
|
||||||
|
|
||||||
|
В выводе команды будет строка наподобие этой: `[INFO] Listening at: http://0.0.0.0:9000`.
|
||||||
|
По указанному адресу можно зайти на web интерфейс.
|
||||||
|
|
||||||
|
Далее необходимо поднять т.н. бота. Находясь в `pipenv shell` выполнить:
|
||||||
|
```bash
|
||||||
|
python butler.py run_bot --name my-bot ./my-bot
|
||||||
|
```
|
||||||
|
|
||||||
|
Для просмотра логов бота:
|
||||||
|
```bash
|
||||||
|
cd ./my-bot/clusterfuzz/bot/logs
|
||||||
|
tail -f bot.log
|
||||||
|
```
|
||||||
|
|
||||||
|
## Фаззинг проекта на go
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.frostfs.info/TrueCloudLab/policy-engine.git
|
||||||
|
go get git.frostfs.info/TrueCloudLab/policy-engine
|
||||||
|
go install github.com/AdamKorcz/go-118-fuzz-build@latest
|
||||||
|
go get github.com/AdamKorcz/go-118-fuzz-build/testing
|
||||||
|
go-118-fuzz-build -tags gofuzz -o fuzz_unmarshall.a -func FuzzUnmarshal ~/policy-engine/pkg/chain
|
||||||
|
clang++ -fsanitize=address,fuzzer fuzz_unmarshall.a -o ~/policy-engine/out/fuzz_unmarshall
|
||||||
|
zip fuzzer.zip fuzz_unmarshall
|
||||||
|
```
|
||||||
|
|
||||||
|
Полученный архив следует загрузить через интерфейс web интерфейс clusterfuzz.
|
||||||
|
|
||||||
|
Важно, что фаззинг go использует под капотом libFuzzer, поэтому в названии job для фаззинга это должно быть указано.
|
||||||
|
Можно также использовать встроенный шаблон для libFuzzer.
|
115
generator.go
115
generator.go
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Generator struct {
|
type Generator struct {
|
||||||
|
@ -119,6 +120,78 @@ func (g *Generator) fillAny(any reflect.Value) error {
|
||||||
any.Index(i).Set(arrayValue.Elem())
|
any.Index(i).Set(arrayValue.Elem())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case reflect.Bool:
|
||||||
|
newBool, err := g.GenerateBool()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
any.SetBool(newBool)
|
||||||
|
|
||||||
|
case reflect.Uint8:
|
||||||
|
newUInt8, err := g.GenerateUInt8()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
any.SetUint(uint64(newUInt8))
|
||||||
|
|
||||||
|
case reflect.Uint16:
|
||||||
|
newUInt16, err := g.GenerateUInt16()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
any.SetUint(uint64(newUInt16))
|
||||||
|
|
||||||
|
case reflect.Uint, reflect.Uint32:
|
||||||
|
newUInt32, err := g.GenerateUInt32()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
any.SetUint(uint64(newUInt32))
|
||||||
|
|
||||||
|
case reflect.Uint64, reflect.Uintptr:
|
||||||
|
newUInt64, err := g.GenerateUInt64()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
any.SetUint(newUInt64)
|
||||||
|
|
||||||
|
case reflect.Chan:
|
||||||
|
size, err := g.GenerateInt()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
channel := reflect.MakeChan(any.Type(), size)
|
||||||
|
for i := 0; i < size; i++ {
|
||||||
|
elem := reflect.New(channel.Type().Elem()).Elem()
|
||||||
|
err = g.fillAny(elem)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
channel.Send(elem)
|
||||||
|
}
|
||||||
|
any.Set(channel)
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
size, err := g.GenerateInt()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
slice := reflect.MakeSlice(any.Type(), size, size)
|
||||||
|
for i := 0; i < size; i++ {
|
||||||
|
err := g.fillAny(slice.Index(i))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
any.Set(slice)
|
||||||
|
|
||||||
|
case reflect.UnsafePointer:
|
||||||
|
addr, err := g.GenerateUInt64()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
any.SetPointer(unsafe.Pointer(uintptr(addr)))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic("unhandled default case")
|
panic("unhandled default case")
|
||||||
}
|
}
|
||||||
|
@ -218,3 +291,45 @@ func (g *Generator) GenerateFloat64() (float64, error) {
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *Generator) GenerateBool() (bool, error) {
|
||||||
|
if g.position >= g.dataSize {
|
||||||
|
return false, errors.New("the data bytes are over")
|
||||||
|
}
|
||||||
|
result := g.data[g.position]%2 == 0
|
||||||
|
g.position++
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Generator) GenerateUInt8() (uint8, error) {
|
||||||
|
if g.position >= g.dataSize {
|
||||||
|
return 0, errors.New("the data bytes are over")
|
||||||
|
}
|
||||||
|
result := g.data[g.position]
|
||||||
|
g.position++
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Generator) GenerateUInt16() (uint16, error) {
|
||||||
|
if g.position+1 >= g.dataSize {
|
||||||
|
return 0, errors.New("the data bytes are over")
|
||||||
|
}
|
||||||
|
result := uint16(0)
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
result = result<<8 | uint16(g.data[g.position])
|
||||||
|
g.position++
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Generator) GenerateUInt64() (uint64, error) {
|
||||||
|
if g.position+7 >= g.dataSize {
|
||||||
|
return 0, errors.New("the data bytes are over")
|
||||||
|
}
|
||||||
|
result := uint64(0)
|
||||||
|
for i := 0; i < 8; i++ {
|
||||||
|
result = result<<8 | uint64(g.data[g.position])
|
||||||
|
g.position++
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
Loading…
Reference in a new issue