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"
|
||||
"math"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Generator struct {
|
||||
|
@ -119,6 +120,78 @@ func (g *Generator) fillAny(any reflect.Value) error {
|
|||
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:
|
||||
panic("unhandled default case")
|
||||
}
|
||||
|
@ -216,5 +289,47 @@ func (g *Generator) GenerateFloat64() (float64, error) {
|
|||
|
||||
result := math.Float64frombits(bits)
|
||||
|
||||
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