Upgrade github.com/AdaLogics/go-fuzz-headers
Signed-off-by: Kazuyoshi Kato <katokazu@amazon.com>
This commit is contained in:
parent
c4b1b368ad
commit
b316318596
3
go.mod
3
go.mod
@ -3,7 +3,7 @@ module github.com/containerd/containerd
|
|||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20220706123152-fef3fe1bab07
|
||||||
github.com/Microsoft/go-winio v0.5.2
|
github.com/Microsoft/go-winio v0.5.2
|
||||||
github.com/Microsoft/hcsshim v0.9.2
|
github.com/Microsoft/hcsshim v0.9.2
|
||||||
github.com/container-orchestrated-devices/container-device-interface v0.3.1
|
github.com/container-orchestrated-devices/container-device-interface v0.3.1
|
||||||
@ -85,6 +85,7 @@ require (
|
|||||||
github.com/containernetworking/cni v1.1.1 // indirect
|
github.com/containernetworking/cni v1.1.1 // indirect
|
||||||
github.com/containers/ocicrypt v1.1.3 // indirect
|
github.com/containers/ocicrypt v1.1.3 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
||||||
|
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
||||||
github.com/emicklei/go-restful v2.9.5+incompatible // indirect
|
github.com/emicklei/go-restful v2.9.5+incompatible // indirect
|
||||||
github.com/go-logr/logr v1.2.3 // indirect
|
github.com/go-logr/logr v1.2.3 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
|
4
go.sum
4
go.sum
@ -40,8 +40,9 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
|
|||||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8 h1:V8krnnfGj4pV65YLUm3C0/8bl7V5Nry2Pwvy3ru/wLc=
|
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg=
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg=
|
||||||
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20220706123152-fef3fe1bab07 h1:7dZd6IhJApT69RGnt+YHRRVHXkO9fA6tAdl5E7iG9EU=
|
||||||
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20220706123152-fef3fe1bab07/go.mod h1:i9fr2JpcEcY/IHEvzCM3qXUZYOQHgR89dt4es1CgMhc=
|
||||||
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||||
@ -322,6 +323,7 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do
|
|||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
||||||
|
github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||||
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
|
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
|
||||||
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
|
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
|
||||||
|
@ -19,7 +19,7 @@ require (
|
|||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a
|
||||||
)
|
)
|
||||||
|
|
||||||
require github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8
|
require github.com/AdaLogics/go-fuzz-headers v0.0.0-20220706123152-fef3fe1bab07
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||||
@ -30,6 +30,7 @@ require (
|
|||||||
github.com/containerd/continuity v0.3.0 // indirect
|
github.com/containerd/continuity v0.3.0 // indirect
|
||||||
github.com/containerd/fifo v1.0.0 // indirect
|
github.com/containerd/fifo v1.0.0 // indirect
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||||
|
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
|
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
|
||||||
github.com/docker/go-units v0.4.0 // indirect
|
github.com/docker/go-units v0.4.0 // indirect
|
||||||
|
@ -38,8 +38,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
|
|||||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8 h1:V8krnnfGj4pV65YLUm3C0/8bl7V5Nry2Pwvy3ru/wLc=
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20220706123152-fef3fe1bab07 h1:7dZd6IhJApT69RGnt+YHRRVHXkO9fA6tAdl5E7iG9EU=
|
||||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg=
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20220706123152-fef3fe1bab07/go.mod h1:i9fr2JpcEcY/IHEvzCM3qXUZYOQHgR89dt4es1CgMhc=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||||
@ -186,6 +186,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
|
|||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
||||||
|
github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI=
|
||||||
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||||
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
|
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
|
||||||
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
|
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
|
||||||
|
114
vendor/github.com/AdaLogics/go-fuzz-headers/README.md
generated
vendored
114
vendor/github.com/AdaLogics/go-fuzz-headers/README.md
generated
vendored
@ -1,49 +1,93 @@
|
|||||||
# go-fuzz-headers
|
# go-fuzz-headers
|
||||||
This repository contains various helper functions to be used with [go-fuzz](https://github.com/dvyukov/go-fuzz).
|
This repository contains various helper functions for go fuzzing. It is mostly used in combination with [go-fuzz](https://github.com/dvyukov/go-fuzz), but compatibility with fuzzing in the standard library will also be supported. Any coverage guided fuzzing engine that provides an array or slice of bytes can be used with go-fuzz-headers.
|
||||||
|
|
||||||
## Goal
|
|
||||||
|
|
||||||
The current goal of go-fuzz-headers is:
|
|
||||||
To maintain a series of helper utilities that can be used for golang projects that are integrated into OSS-fuzz and use the go-fuzz engine to fuzz more complicated types than merely strings and data arrays.
|
|
||||||
While go-fuzz-headers can be used when using go-fuzz outside of OSS-fuzz, we do not test such usage and cannot confirm that it is supported.
|
|
||||||
|
|
||||||
## Status
|
|
||||||
|
|
||||||
The project is under development and will be updated regularly.
|
|
||||||
|
|
||||||
Fuzzers that use `GenerateStruct` will not require modifications as more types get supported.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
To make use of the helper functions, a ConsumeFuzzer has to be instantiated:
|
Using go-fuzz-headers is easy. First create a new consumer with the bytes provided by the fuzzing engine:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
f := NewConsumer(data)
|
import (
|
||||||
|
fuzz "github.com/AdaLogics/go-fuzz-headers"
|
||||||
|
)
|
||||||
|
data := []byte{'R', 'a', 'n', 'd', 'o', 'm'}
|
||||||
|
f := fuzz.NewConsumer(data)
|
||||||
|
|
||||||
```
|
```
|
||||||
To split the input data from the fuzzer into a random set of equally large chunks:
|
|
||||||
|
This creates a `Consumer` that consumes the bytes of the input as it uses them to fuzz different types.
|
||||||
|
|
||||||
|
After that, `f` can be used to easily create fuzzed instances of different types. Below are some examples:
|
||||||
|
|
||||||
|
### Structs
|
||||||
|
One of the most useful features of go-fuzz-headers is its ability to fill structs with the data provided by the fuzzing engine. This is done with a single line:
|
||||||
```go
|
```go
|
||||||
err := f.Split(3, 6)
|
type Person struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p := Person{}
|
||||||
|
// Fill p with values based on the data provided by the fuzzing engine:
|
||||||
|
err := f.GenerateStruct(&p)
|
||||||
```
|
```
|
||||||
...after which the consumer has the following available attributes:
|
|
||||||
|
This includes nested structs too. In this example, the fuzz Consumer will also insert values in `p.BestFriend`:
|
||||||
```go
|
```go
|
||||||
f.CommandPart = commandPart
|
type PersonI struct {
|
||||||
f.RestOfArray = restOfArray
|
Name string
|
||||||
f.NumberOfCalls = numberOfCalls
|
Age int
|
||||||
|
BestFriend PersonII
|
||||||
|
}
|
||||||
|
type PersonII struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p := PersonI{}
|
||||||
|
err := f.GenerateStruct(&p)
|
||||||
```
|
```
|
||||||
To pass the input data from the fuzzer into a struct:
|
|
||||||
|
If the consumer should insert values for unexported fields as well as exported, this can be enabled with:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
ts := new(target_struct)
|
f.AllowUnexportedFields()
|
||||||
err :=f.GenerateStruct(ts)
|
|
||||||
```
|
```
|
||||||
or:
|
|
||||||
|
...and disabled with:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
ts := target_struct{}
|
f.DisallowUnexportedFields()
|
||||||
err = f.GenerateStruct(&ts)
|
|
||||||
```
|
```
|
||||||
`GenerateStruct` will pass data from the input data to the targeted struct. Currently the following field types are supported:
|
|
||||||
1. `string`
|
### Other types:
|
||||||
2. `bool`
|
|
||||||
3. `int`
|
Other useful APIs:
|
||||||
4. `[]string`
|
|
||||||
5. `byte`
|
```go
|
||||||
5. `[]byte`
|
createdString, err := f.GetString() // Gets a string
|
||||||
6. custom structures
|
createdInt, err := f.GetInt() // Gets an integer
|
||||||
7. `map`
|
createdByte, err := f.GetByte() // Gets a byte
|
||||||
|
createdBytes, err := f.GetBytes() // Gets a byte slice
|
||||||
|
createdBool, err := f.GetBool() // Gets a boolean
|
||||||
|
err := f.FuzzMap(target_map) // Fills a map
|
||||||
|
createdTarBytes, err := f.TarBytes() // Gets bytes of a valid tar archive
|
||||||
|
err := f.CreateFiles(inThisDir) // Fills inThisDir with files
|
||||||
|
createdString, err := f.GetStringFrom("anyCharInThisString", ofThisLength) // Gets a string that consists of chars from "anyCharInThisString" and has the exact length "ofThisLength"
|
||||||
|
```
|
||||||
|
|
||||||
|
Most APIs are added as they are needed.
|
||||||
|
|
||||||
|
## Projects that use go-fuzz-headers
|
||||||
|
- [runC](https://github.com/opencontainers/runc)
|
||||||
|
- [Istio](https://github.com/istio/istio)
|
||||||
|
- [Vitess](https://github.com/vitessio/vitess)
|
||||||
|
- [Containerd](https://github.com/containerd/containerd)
|
||||||
|
|
||||||
|
Feel free to add your own project to the list, if you use go-fuzz-headers to fuzz it.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Status
|
||||||
|
The project is under development and will be updated regularly.
|
||||||
|
|
||||||
|
## References
|
||||||
|
go-fuzz-headers' approach to fuzzing structs is strongly inspired by [gofuzz](https://github.com/google/gofuzz).
|
390
vendor/github.com/AdaLogics/go-fuzz-headers/consumer.go
generated
vendored
390
vendor/github.com/AdaLogics/go-fuzz-headers/consumer.go
generated
vendored
@ -3,10 +3,17 @@ package gofuzzheaders
|
|||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
//"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
securejoin "github.com/cyphar/filepath-securejoin"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConsumeFuzzer struct {
|
type ConsumeFuzzer struct {
|
||||||
@ -16,14 +23,20 @@ type ConsumeFuzzer struct {
|
|||||||
NumberOfCalls int
|
NumberOfCalls int
|
||||||
position int
|
position int
|
||||||
fuzzUnexportedFields bool
|
fuzzUnexportedFields bool
|
||||||
|
Funcs map[reflect.Type]reflect.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsDivisibleBy(n int, divisibleby int) bool {
|
func IsDivisibleBy(n int, divisibleby int) bool {
|
||||||
return (n % divisibleby) == 0
|
return (n % divisibleby) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) BytesLeft() int {
|
||||||
|
return len(f.data) - f.position
|
||||||
|
}
|
||||||
|
|
||||||
func NewConsumer(fuzzData []byte) *ConsumeFuzzer {
|
func NewConsumer(fuzzData []byte) *ConsumeFuzzer {
|
||||||
f := &ConsumeFuzzer{data: fuzzData, position: 0}
|
fuzzMap := make(map[reflect.Type]reflect.Value)
|
||||||
|
f := &ConsumeFuzzer{data: fuzzData, position: 0, Funcs: fuzzMap}
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,31 +86,99 @@ func (f *ConsumeFuzzer) GenerateStruct(targetStruct interface{}) error {
|
|||||||
return errors.New("This interface cannot be set")
|
return errors.New("This interface cannot be set")
|
||||||
}*/
|
}*/
|
||||||
e := v.Elem()
|
e := v.Elem()
|
||||||
err := f.fuzzStruct(e)
|
err := f.fuzzStruct(e, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *ConsumeFuzzer) fuzzStruct(e reflect.Value) error {
|
func (f *ConsumeFuzzer) setCustom(v reflect.Value) error {
|
||||||
|
// First: see if we have a fuzz function for it.
|
||||||
|
doCustom, ok := f.Funcs[v.Type()]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Could not find a custom function")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Ptr:
|
||||||
|
if v.IsNil() {
|
||||||
|
if !v.CanSet() {
|
||||||
|
return fmt.Errorf("Could not use a custom function")
|
||||||
|
}
|
||||||
|
v.Set(reflect.New(v.Type().Elem()))
|
||||||
|
}
|
||||||
|
case reflect.Map:
|
||||||
|
if v.IsNil() {
|
||||||
|
if !v.CanSet() {
|
||||||
|
return fmt.Errorf("Could not use a custom function")
|
||||||
|
}
|
||||||
|
v.Set(reflect.MakeMap(v.Type()))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("Could not use a custom function")
|
||||||
|
}
|
||||||
|
|
||||||
|
verr := doCustom.Call([]reflect.Value{v, reflect.ValueOf(Continue{
|
||||||
|
F: f,
|
||||||
|
})})
|
||||||
|
// check if we return an error
|
||||||
|
if verr[0].IsNil() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Could not use a custom function")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) fuzzStruct(e reflect.Value, customFunctions bool) error {
|
||||||
|
|
||||||
|
// We check if we should check for custom functions
|
||||||
|
if customFunctions {
|
||||||
|
if e.IsValid() {
|
||||||
|
if e.CanAddr() {
|
||||||
|
err := f.setCustom(e.Addr())
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* return f.setCustom(e)
|
||||||
|
_, ok := f.Funcs[e.Type()]
|
||||||
|
if ok {
|
||||||
|
if e.CanAddr() {
|
||||||
|
err := f.setCustom(e.Addr())
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
//return f.setCustom(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch e.Kind() {
|
switch e.Kind() {
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
for i := 0; i < e.NumField(); i++ {
|
for i := 0; i < e.NumField(); i++ {
|
||||||
// Useful for debugging, so we leave it for now:
|
|
||||||
//vt := e.Type().Field(i).Name
|
|
||||||
//fmt.Println("vt:::::::::::::::::::::: ", vt)
|
|
||||||
var v reflect.Value
|
var v reflect.Value
|
||||||
if !e.Field(i).CanSet() {
|
if !e.Field(i).CanSet() {
|
||||||
if f.fuzzUnexportedFields {
|
if f.fuzzUnexportedFields {
|
||||||
v = reflect.NewAt(e.Field(i).Type(), unsafe.Pointer(e.Field(i).UnsafeAddr())).Elem()
|
v = reflect.NewAt(e.Field(i).Type(), unsafe.Pointer(e.Field(i).UnsafeAddr())).Elem()
|
||||||
}
|
}
|
||||||
|
err := f.fuzzStruct(v, customFunctions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/*if e.Field(i).Kind() == reflect.Struct {
|
||||||
|
//e = reflect.NewAt(e.Type(), unsafe.Pointer(e.UnsafeAddr())).Elem()
|
||||||
|
//e.Field(i).Set(reflect.New(e.Field(i).Type()))
|
||||||
|
}*/
|
||||||
v = e.Field(i)
|
v = e.Field(i)
|
||||||
}
|
//v = reflect.New(e.Field(i).Type())
|
||||||
err := f.fuzzStruct(v)
|
err := f.fuzzStruct(v, customFunctions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
|
/*if e.Field(i).CanSet() {
|
||||||
|
e.Field(i).Set(v.Elem())
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
@ -119,7 +200,7 @@ func (f *ConsumeFuzzer) fuzzStruct(e reflect.Value) error {
|
|||||||
uu := reflect.MakeSlice(e.Type(), numOfElements, numOfElements)
|
uu := reflect.MakeSlice(e.Type(), numOfElements, numOfElements)
|
||||||
|
|
||||||
for i := 0; i < numOfElements; i++ {
|
for i := 0; i < numOfElements; i++ {
|
||||||
err := f.fuzzStruct(uu.Index(i))
|
err := f.fuzzStruct(uu.Index(i), customFunctions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -127,6 +208,22 @@ func (f *ConsumeFuzzer) fuzzStruct(e reflect.Value) error {
|
|||||||
if e.CanSet() {
|
if e.CanSet() {
|
||||||
e.Set(uu)
|
e.Set(uu)
|
||||||
}
|
}
|
||||||
|
case reflect.Uint16:
|
||||||
|
newInt, err := f.GetUint16()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if e.CanSet() {
|
||||||
|
e.SetUint(uint64(newInt))
|
||||||
|
}
|
||||||
|
case reflect.Uint32:
|
||||||
|
newInt, err := f.GetUint32()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if e.CanSet() {
|
||||||
|
e.SetUint(uint64(newInt))
|
||||||
|
}
|
||||||
case reflect.Uint64:
|
case reflect.Uint64:
|
||||||
newInt, err := f.GetInt()
|
newInt, err := f.GetInt()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -135,7 +232,7 @@ func (f *ConsumeFuzzer) fuzzStruct(e reflect.Value) error {
|
|||||||
if e.CanSet() {
|
if e.CanSet() {
|
||||||
e.SetUint(uint64(newInt))
|
e.SetUint(uint64(newInt))
|
||||||
}
|
}
|
||||||
case reflect.Int:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
newInt, err := f.GetInt()
|
newInt, err := f.GetInt()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -143,6 +240,22 @@ func (f *ConsumeFuzzer) fuzzStruct(e reflect.Value) error {
|
|||||||
if e.CanSet() {
|
if e.CanSet() {
|
||||||
e.SetInt(int64(newInt))
|
e.SetInt(int64(newInt))
|
||||||
}
|
}
|
||||||
|
case reflect.Float32:
|
||||||
|
newFloat, err := f.GetFloat32()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if e.CanSet() {
|
||||||
|
e.SetFloat(float64(newFloat))
|
||||||
|
}
|
||||||
|
case reflect.Float64:
|
||||||
|
newFloat, err := f.GetFloat64()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if e.CanSet() {
|
||||||
|
e.SetFloat(float64(newFloat))
|
||||||
|
}
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
if e.CanSet() {
|
if e.CanSet() {
|
||||||
e.Set(reflect.MakeMap(e.Type()))
|
e.Set(reflect.MakeMap(e.Type()))
|
||||||
@ -154,12 +267,12 @@ func (f *ConsumeFuzzer) fuzzStruct(e reflect.Value) error {
|
|||||||
numOfElements := randQty % maxElements
|
numOfElements := randQty % maxElements
|
||||||
for i := 0; i < numOfElements; i++ {
|
for i := 0; i < numOfElements; i++ {
|
||||||
key := reflect.New(e.Type().Key()).Elem()
|
key := reflect.New(e.Type().Key()).Elem()
|
||||||
err := f.fuzzStruct(key)
|
err := f.fuzzStruct(key, customFunctions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
val := reflect.New(e.Type().Elem()).Elem()
|
val := reflect.New(e.Type().Elem()).Elem()
|
||||||
err = f.fuzzStruct(val)
|
err = f.fuzzStruct(val, customFunctions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -169,7 +282,7 @@ func (f *ConsumeFuzzer) fuzzStruct(e reflect.Value) error {
|
|||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
if e.CanSet() {
|
if e.CanSet() {
|
||||||
e.Set(reflect.New(e.Type().Elem()))
|
e.Set(reflect.New(e.Type().Elem()))
|
||||||
err := f.fuzzStruct(e.Elem())
|
err := f.fuzzStruct(e.Elem(), customFunctions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -238,6 +351,75 @@ func (f *ConsumeFuzzer) GetByte() (byte, error) {
|
|||||||
return returnByte, nil
|
return returnByte, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) GetNBytes(numberOfBytes int) ([]byte, error) {
|
||||||
|
returnBytes := make([]byte, 0)
|
||||||
|
if len(f.data) == 0 {
|
||||||
|
return returnBytes, errors.New("Not enough bytes to get byte")
|
||||||
|
}
|
||||||
|
if f.position >= len(f.data) {
|
||||||
|
return returnBytes, errors.New("Not enough bytes to get byte")
|
||||||
|
}
|
||||||
|
for i := 0; i < numberOfBytes; i++ {
|
||||||
|
newByte, err := f.GetByte()
|
||||||
|
if err != nil {
|
||||||
|
return returnBytes, err
|
||||||
|
}
|
||||||
|
returnBytes = append(returnBytes, newByte)
|
||||||
|
}
|
||||||
|
return returnBytes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) GetUint16() (uint16, error) {
|
||||||
|
u16, err := f.GetNBytes(2)
|
||||||
|
if err != nil {
|
||||||
|
return uint16(0), err
|
||||||
|
}
|
||||||
|
littleEndian, err := f.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
return uint16(0), err
|
||||||
|
}
|
||||||
|
if littleEndian {
|
||||||
|
u16LE := binary.LittleEndian.Uint16(u16)
|
||||||
|
return u16LE, nil
|
||||||
|
}
|
||||||
|
u16BE := binary.BigEndian.Uint16(u16)
|
||||||
|
return u16BE, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) GetUint32() (uint32, error) {
|
||||||
|
u32, err := f.GetNBytes(4)
|
||||||
|
if err != nil {
|
||||||
|
return uint32(0), err
|
||||||
|
}
|
||||||
|
littleEndian, err := f.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
return uint32(0), err
|
||||||
|
}
|
||||||
|
if littleEndian {
|
||||||
|
u32LE := binary.LittleEndian.Uint32(u32)
|
||||||
|
return u32LE, nil
|
||||||
|
}
|
||||||
|
u32BE := binary.BigEndian.Uint32(u32)
|
||||||
|
return u32BE, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) GetUint64() (uint64, error) {
|
||||||
|
u64, err := f.GetNBytes(8)
|
||||||
|
if err != nil {
|
||||||
|
return uint64(0), err
|
||||||
|
}
|
||||||
|
littleEndian, err := f.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
return uint64(0), err
|
||||||
|
}
|
||||||
|
if littleEndian {
|
||||||
|
u64LE := binary.LittleEndian.Uint64(u64)
|
||||||
|
return u64LE, nil
|
||||||
|
}
|
||||||
|
u64BE := binary.BigEndian.Uint64(u64)
|
||||||
|
return u64BE, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (f *ConsumeFuzzer) GetBytes() ([]byte, error) {
|
func (f *ConsumeFuzzer) GetBytes() ([]byte, error) {
|
||||||
if len(f.data) == 0 || f.position >= len(f.data) {
|
if len(f.data) == 0 || f.position >= len(f.data) {
|
||||||
return nil, errors.New("Not enough bytes to create byte array")
|
return nil, errors.New("Not enough bytes to create byte array")
|
||||||
@ -296,7 +478,7 @@ func (f *ConsumeFuzzer) FuzzMap(m interface{}) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TarBytes returns valid tar bytes for a tar archive
|
// TarBytes returns valid bytes for a tar archive
|
||||||
func (f *ConsumeFuzzer) TarBytes() ([]byte, error) {
|
func (f *ConsumeFuzzer) TarBytes() ([]byte, error) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
tw := tar.NewWriter(&buf)
|
tw := tar.NewWriter(&buf)
|
||||||
@ -334,6 +516,178 @@ func (f *ConsumeFuzzer) TarBytes() ([]byte, error) {
|
|||||||
if err := tw.Close(); err != nil {
|
if err := tw.Close(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
//fmt.Println(string(buf.Bytes()))
|
|
||||||
return buf.Bytes(), nil
|
return buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates pseudo-random files in rootDir.
|
||||||
|
// Will create subdirs and place the files there.
|
||||||
|
// It is the callers responsibility to ensure that
|
||||||
|
// rootDir exists.
|
||||||
|
func (f *ConsumeFuzzer) CreateFiles(rootDir string) error {
|
||||||
|
var noOfCreatedFiles int
|
||||||
|
noOfCreatedFiles = 0
|
||||||
|
numberOfFiles, err := f.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
maxNumberOfFiles := numberOfFiles % 4000 // This is completely arbitrary
|
||||||
|
if maxNumberOfFiles == 0 {
|
||||||
|
return errors.New("maxNumberOfFiles is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < maxNumberOfFiles; i++ {
|
||||||
|
// The file to create:
|
||||||
|
fileName, err := f.GetString()
|
||||||
|
if err != nil {
|
||||||
|
if noOfCreatedFiles > 0 {
|
||||||
|
// If files have been created, we don't return
|
||||||
|
// an error
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
return errors.New("Could not get fileName")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var fullFilePath string
|
||||||
|
fullFilePath, err = securejoin.SecureJoin(rootDir, fileName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the subdirectory of the file
|
||||||
|
subDir := filepath.Dir(fileName)
|
||||||
|
if subDir != "" && subDir != "." {
|
||||||
|
// create the dir first
|
||||||
|
|
||||||
|
// Avoid going outside the root dir
|
||||||
|
if strings.Contains(subDir, "../") || (len(subDir) > 0 && subDir[0] == 47) || strings.Contains(subDir, "\\") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dirPath := filepath.Join(rootDir, subDir)
|
||||||
|
dirPath, err := securejoin.SecureJoin(rootDir, subDir)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(dirPath); os.IsNotExist(err) {
|
||||||
|
err2 := os.MkdirAll(dirPath, 0777)
|
||||||
|
if err2 != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fullFilePath, err = securejoin.SecureJoin(dirPath, fileName)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Create symlink
|
||||||
|
createSymlink, err := f.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
if noOfCreatedFiles > 0 {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
return errors.New("Could not create the symlink")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if createSymlink {
|
||||||
|
symlinkTarget, err := f.GetString()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
os.Symlink(symlinkTarget, fullFilePath)
|
||||||
|
// stop loop here, since a symlink needs no further action
|
||||||
|
noOfCreatedFiles++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// We create a normal file
|
||||||
|
fileContents, err := f.GetBytes()
|
||||||
|
if err != nil {
|
||||||
|
if noOfCreatedFiles > 0 {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
return errors.New("Could not create the file")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createdFile, err := os.Create(fullFilePath)
|
||||||
|
if err != nil {
|
||||||
|
createdFile.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, err = createdFile.Write(fileContents)
|
||||||
|
if err != nil {
|
||||||
|
createdFile.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
createdFile.Close()
|
||||||
|
noOfCreatedFiles++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a string that can only consists of characters that are
|
||||||
|
// included in possibleChars. Will return an error if the created
|
||||||
|
// string does not have the specified length
|
||||||
|
func (f *ConsumeFuzzer) GetStringFrom(possibleChars string, length int) (string, error) {
|
||||||
|
returnString := ""
|
||||||
|
if (len(f.data) - f.position) < length {
|
||||||
|
return returnString, errors.New("Not enough bytes to create a string")
|
||||||
|
}
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
charIndex, err := f.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return returnString, err
|
||||||
|
}
|
||||||
|
charToAdd := string(possibleChars[charIndex%len(possibleChars)])
|
||||||
|
returnString = fmt.Sprintf(returnString + charToAdd)
|
||||||
|
}
|
||||||
|
return returnString, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) GetRune() ([]rune, error) {
|
||||||
|
stringToConvert, err := f.GetString()
|
||||||
|
if err != nil {
|
||||||
|
return []rune("nil"), err
|
||||||
|
}
|
||||||
|
return []rune(stringToConvert), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) GetFloat32() (float32, error) {
|
||||||
|
u32, err := f.GetNBytes(4)
|
||||||
|
if err != nil {
|
||||||
|
return float32(0.0), err
|
||||||
|
}
|
||||||
|
littleEndian, err := f.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
return float32(0.0), err
|
||||||
|
}
|
||||||
|
if littleEndian {
|
||||||
|
u32LE := binary.LittleEndian.Uint32(u32)
|
||||||
|
return math.Float32frombits(u32LE), nil
|
||||||
|
}
|
||||||
|
u32BE := binary.BigEndian.Uint32(u32)
|
||||||
|
return math.Float32frombits(u32BE), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) GetFloat64() (float64, error) {
|
||||||
|
u64, err := f.GetNBytes(8)
|
||||||
|
if err != nil {
|
||||||
|
return float64(0.0), err
|
||||||
|
}
|
||||||
|
littleEndian, err := f.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
return float64(0.0), err
|
||||||
|
}
|
||||||
|
if littleEndian {
|
||||||
|
u64LE := binary.LittleEndian.Uint64(u64)
|
||||||
|
return math.Float64frombits(u64LE), nil
|
||||||
|
}
|
||||||
|
u64BE := binary.BigEndian.Uint64(u64)
|
||||||
|
return math.Float64frombits(u64BE), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) CreateSlice(targetSlice interface{}) error {
|
||||||
|
err := f.GenerateStruct(targetSlice)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
57
vendor/github.com/AdaLogics/go-fuzz-headers/funcs.go
generated
vendored
Normal file
57
vendor/github.com/AdaLogics/go-fuzz-headers/funcs.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package gofuzzheaders
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Continue struct {
|
||||||
|
F *ConsumeFuzzer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) AddFuncs(fuzzFuncs []interface{}) {
|
||||||
|
for i := range fuzzFuncs {
|
||||||
|
v := reflect.ValueOf(fuzzFuncs[i])
|
||||||
|
if v.Kind() != reflect.Func {
|
||||||
|
panic("Need only funcs!")
|
||||||
|
}
|
||||||
|
t := v.Type()
|
||||||
|
if t.NumIn() != 2 || t.NumOut() != 1 {
|
||||||
|
fmt.Println(t.NumIn(), t.NumOut())
|
||||||
|
|
||||||
|
panic("Need 2 in and 1 out params. In must be the type. Out must be an error")
|
||||||
|
}
|
||||||
|
argT := t.In(0)
|
||||||
|
switch argT.Kind() {
|
||||||
|
case reflect.Ptr, reflect.Map:
|
||||||
|
default:
|
||||||
|
panic("fuzzFunc must take pointer or map type")
|
||||||
|
}
|
||||||
|
if t.In(1) != reflect.TypeOf(Continue{}) {
|
||||||
|
panic("fuzzFunc's second parameter must be type Continue")
|
||||||
|
}
|
||||||
|
f.Funcs[argT] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) GenerateWithCustom(targetStruct interface{}) error {
|
||||||
|
v := reflect.ValueOf(targetStruct)
|
||||||
|
e := v.Elem()
|
||||||
|
return f.fuzzStruct(e, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Continue) GenerateStruct(targetStruct interface{}) error {
|
||||||
|
err := c.F.GenerateStruct(targetStruct)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Continue) GenerateStructWithCustom(targetStruct interface{}) error {
|
||||||
|
err := c.F.GenerateWithCustom(targetStruct)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
524
vendor/github.com/AdaLogics/go-fuzz-headers/sql.go
generated
vendored
Normal file
524
vendor/github.com/AdaLogics/go-fuzz-headers/sql.go
generated
vendored
Normal file
@ -0,0 +1,524 @@
|
|||||||
|
package gofuzzheaders
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// returns a keyword by index
|
||||||
|
func getKeyword(f *ConsumeFuzzer) (string, error) {
|
||||||
|
index, err := f.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return keywords[0], err
|
||||||
|
}
|
||||||
|
for i, k := range keywords {
|
||||||
|
if i == index {
|
||||||
|
return k, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keywords[0], fmt.Errorf("Could not get a kw")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple utility function to check if a string
|
||||||
|
// slice contains a string.
|
||||||
|
func containsString(s []string, e string) bool {
|
||||||
|
for _, a := range s {
|
||||||
|
if a == e {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// These keywords are used specifically for fuzzing Vitess
|
||||||
|
var keywords = []string{
|
||||||
|
"accessible", "action", "add", "after", "against", "algorithm",
|
||||||
|
"all", "alter", "always", "analyze", "and", "as", "asc", "asensitive",
|
||||||
|
"auto_increment", "avg_row_length", "before", "begin", "between",
|
||||||
|
"bigint", "binary", "_binary", "_utf8mb4", "_utf8", "_latin1", "bit",
|
||||||
|
"blob", "bool", "boolean", "both", "by", "call", "cancel", "cascade",
|
||||||
|
"cascaded", "case", "cast", "channel", "change", "char", "character",
|
||||||
|
"charset", "check", "checksum", "coalesce", "code", "collate", "collation",
|
||||||
|
"column", "columns", "comment", "committed", "commit", "compact", "complete",
|
||||||
|
"compressed", "compression", "condition", "connection", "constraint", "continue",
|
||||||
|
"convert", "copy", "cume_dist", "substr", "substring", "create", "cross",
|
||||||
|
"csv", "current_date", "current_time", "current_timestamp", "current_user",
|
||||||
|
"cursor", "data", "database", "databases", "day", "day_hour", "day_microsecond",
|
||||||
|
"day_minute", "day_second", "date", "datetime", "dec", "decimal", "declare",
|
||||||
|
"default", "definer", "delay_key_write", "delayed", "delete", "dense_rank",
|
||||||
|
"desc", "describe", "deterministic", "directory", "disable", "discard",
|
||||||
|
"disk", "distinct", "distinctrow", "div", "double", "do", "drop", "dumpfile",
|
||||||
|
"duplicate", "dynamic", "each", "else", "elseif", "empty", "enable",
|
||||||
|
"enclosed", "encryption", "end", "enforced", "engine", "engines", "enum",
|
||||||
|
"error", "escape", "escaped", "event", "exchange", "exclusive", "exists",
|
||||||
|
"exit", "explain", "expansion", "export", "extended", "extract", "false",
|
||||||
|
"fetch", "fields", "first", "first_value", "fixed", "float", "float4",
|
||||||
|
"float8", "flush", "for", "force", "foreign", "format", "from", "full",
|
||||||
|
"fulltext", "function", "general", "generated", "geometry", "geometrycollection",
|
||||||
|
"get", "global", "gtid_executed", "grant", "group", "grouping", "groups",
|
||||||
|
"group_concat", "having", "header", "high_priority", "hosts", "hour", "hour_microsecond",
|
||||||
|
"hour_minute", "hour_second", "if", "ignore", "import", "in", "index", "indexes",
|
||||||
|
"infile", "inout", "inner", "inplace", "insensitive", "insert", "insert_method",
|
||||||
|
"int", "int1", "int2", "int3", "int4", "int8", "integer", "interval",
|
||||||
|
"into", "io_after_gtids", "is", "isolation", "iterate", "invoker", "join",
|
||||||
|
"json", "json_table", "key", "keys", "keyspaces", "key_block_size", "kill", "lag",
|
||||||
|
"language", "last", "last_value", "last_insert_id", "lateral", "lead", "leading",
|
||||||
|
"leave", "left", "less", "level", "like", "limit", "linear", "lines",
|
||||||
|
"linestring", "load", "local", "localtime", "localtimestamp", "lock", "logs",
|
||||||
|
"long", "longblob", "longtext", "loop", "low_priority", "manifest",
|
||||||
|
"master_bind", "match", "max_rows", "maxvalue", "mediumblob", "mediumint",
|
||||||
|
"mediumtext", "memory", "merge", "microsecond", "middleint", "min_rows", "minute",
|
||||||
|
"minute_microsecond", "minute_second", "mod", "mode", "modify", "modifies",
|
||||||
|
"multilinestring", "multipoint", "multipolygon", "month", "name",
|
||||||
|
"names", "natural", "nchar", "next", "no", "none", "not", "no_write_to_binlog",
|
||||||
|
"nth_value", "ntile", "null", "numeric", "of", "off", "offset", "on",
|
||||||
|
"only", "open", "optimize", "optimizer_costs", "option", "optionally",
|
||||||
|
"or", "order", "out", "outer", "outfile", "over", "overwrite", "pack_keys",
|
||||||
|
"parser", "partition", "partitioning", "password", "percent_rank", "plugins",
|
||||||
|
"point", "polygon", "precision", "primary", "privileges", "processlist",
|
||||||
|
"procedure", "query", "quarter", "range", "rank", "read", "reads", "read_write",
|
||||||
|
"real", "rebuild", "recursive", "redundant", "references", "regexp", "relay",
|
||||||
|
"release", "remove", "rename", "reorganize", "repair", "repeat", "repeatable",
|
||||||
|
"replace", "require", "resignal", "restrict", "return", "retry", "revert",
|
||||||
|
"revoke", "right", "rlike", "rollback", "row", "row_format", "row_number",
|
||||||
|
"rows", "s3", "savepoint", "schema", "schemas", "second", "second_microsecond",
|
||||||
|
"security", "select", "sensitive", "separator", "sequence", "serializable",
|
||||||
|
"session", "set", "share", "shared", "show", "signal", "signed", "slow",
|
||||||
|
"smallint", "spatial", "specific", "sql", "sqlexception", "sqlstate",
|
||||||
|
"sqlwarning", "sql_big_result", "sql_cache", "sql_calc_found_rows",
|
||||||
|
"sql_no_cache", "sql_small_result", "ssl", "start", "starting",
|
||||||
|
"stats_auto_recalc", "stats_persistent", "stats_sample_pages", "status",
|
||||||
|
"storage", "stored", "straight_join", "stream", "system", "vstream",
|
||||||
|
"table", "tables", "tablespace", "temporary", "temptable", "terminated",
|
||||||
|
"text", "than", "then", "time", "timestamp", "timestampadd", "timestampdiff",
|
||||||
|
"tinyblob", "tinyint", "tinytext", "to", "trailing", "transaction", "tree",
|
||||||
|
"traditional", "trigger", "triggers", "true", "truncate", "uncommitted",
|
||||||
|
"undefined", "undo", "union", "unique", "unlock", "unsigned", "update",
|
||||||
|
"upgrade", "usage", "use", "user", "user_resources", "using", "utc_date",
|
||||||
|
"utc_time", "utc_timestamp", "validation", "values", "variables", "varbinary",
|
||||||
|
"varchar", "varcharacter", "varying", "vgtid_executed", "virtual", "vindex",
|
||||||
|
"vindexes", "view", "vitess", "vitess_keyspaces", "vitess_metadata",
|
||||||
|
"vitess_migration", "vitess_migrations", "vitess_replication_status",
|
||||||
|
"vitess_shards", "vitess_tablets", "vschema", "warnings", "when",
|
||||||
|
"where", "while", "window", "with", "without", "work", "write", "xor",
|
||||||
|
"year", "year_month", "zerofill"}
|
||||||
|
|
||||||
|
// Keywords that could get an additional keyword
|
||||||
|
var needCustomString = []string{
|
||||||
|
"DISTINCTROW", "FROM", // Select keywords:
|
||||||
|
"GROUP BY", "HAVING", "WINDOW",
|
||||||
|
"FOR",
|
||||||
|
"ORDER BY", "LIMIT",
|
||||||
|
"INTO", "PARTITION", "AS", // Insert Keywords:
|
||||||
|
"ON DUPLICATE KEY UPDATE",
|
||||||
|
"WHERE", "LIMIT", // Delete keywords
|
||||||
|
"INFILE", "INTO TABLE", "CHARACTER SET", // Load keywords
|
||||||
|
"TERMINATED BY", "ENCLOSED BY",
|
||||||
|
"ESCAPED BY", "STARTING BY",
|
||||||
|
"TERMINATED BY", "STARTING BY",
|
||||||
|
"IGNORE",
|
||||||
|
"VALUE", "VALUES", // Replace tokens
|
||||||
|
"SET", // Update tokens
|
||||||
|
"ENGINE =", // Drop tokens
|
||||||
|
"DEFINER =", "ON SCHEDULE", "RENAME TO", // Alter tokens
|
||||||
|
"COMMENT", "DO", "INITIAL_SIZE = ", "OPTIONS",
|
||||||
|
}
|
||||||
|
|
||||||
|
var alterTableTokens = [][]string{
|
||||||
|
{"CUSTOM_FUZZ_STRING"},
|
||||||
|
{"CUSTOM_ALTTER_TABLE_OPTIONS"},
|
||||||
|
{"PARTITION_OPTIONS_FOR_ALTER_TABLE"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var alterTokens = [][]string{
|
||||||
|
{"DATABASE", "SCHEMA", "DEFINER = ", "EVENT", "FUNCTION", "INSTANCE",
|
||||||
|
"LOGFILE GROUP", "PROCEDURE", "SERVER"},
|
||||||
|
{"CUSTOM_FUZZ_STRING"},
|
||||||
|
{"ON SCHEDULE", "ON COMPLETION PRESERVE", "ON COMPLETION NOT PRESERVE",
|
||||||
|
"ADD UNDOFILE", "OPTIONS"},
|
||||||
|
{"RENAME TO", "INITIAL_SIZE = "},
|
||||||
|
{"ENABLE", "DISABLE", "DISABLE ON SLAVE", "ENGINE"},
|
||||||
|
{"COMMENT"},
|
||||||
|
{"DO"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var setTokens = [][]string{
|
||||||
|
{"CHARACTER SET", "CHARSET", "CUSTOM_FUZZ_STRING", "NAMES"},
|
||||||
|
{"CUSTOM_FUZZ_STRING", "DEFAULT", "="},
|
||||||
|
{"CUSTOM_FUZZ_STRING"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var dropTokens = [][]string{
|
||||||
|
{"TEMPORARY", "UNDO"},
|
||||||
|
{"DATABASE", "SCHEMA", "EVENT", "INDEX", "LOGFILE GROUP",
|
||||||
|
"PROCEDURE", "FUNCTION", "SERVER", "SPATIAL REFERENCE SYSTEM",
|
||||||
|
"TABLE", "TABLESPACE", "TRIGGER", "VIEW"},
|
||||||
|
{"IF EXISTS"},
|
||||||
|
{"CUSTOM_FUZZ_STRING"},
|
||||||
|
{"ON", "ENGINE = ", "RESTRICT", "CASCADE"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var renameTokens = [][]string{
|
||||||
|
{"TABLE"},
|
||||||
|
{"CUSTOM_FUZZ_STRING"},
|
||||||
|
{"TO"},
|
||||||
|
{"CUSTOM_FUZZ_STRING"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var truncateTokens = [][]string{
|
||||||
|
{"TABLE"},
|
||||||
|
{"CUSTOM_FUZZ_STRING"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var createTokens = [][]string{
|
||||||
|
{"OR REPLACE", "TEMPORARY", "UNDO"}, // For create spatial reference system
|
||||||
|
{"UNIQUE", "FULLTEXT", "SPATIAL", "ALGORITHM = UNDEFINED", "ALGORITHM = MERGE",
|
||||||
|
"ALGORITHM = TEMPTABLE"},
|
||||||
|
{"DATABASE", "SCHEMA", "EVENT", "FUNCTION", "INDEX", "LOGFILE GROUP",
|
||||||
|
"PROCEDURE", "SERVER", "SPATIAL REFERENCE SYSTEM", "TABLE", "TABLESPACE",
|
||||||
|
"TRIGGER", "VIEW"},
|
||||||
|
{"IF NOT EXISTS"},
|
||||||
|
{"CUSTOM_FUZZ_STRING"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var updateTokens = [][]string{
|
||||||
|
{"LOW_PRIORITY"},
|
||||||
|
{"IGNORE"},
|
||||||
|
{"SET"},
|
||||||
|
{"WHERE"},
|
||||||
|
{"ORDER BY"},
|
||||||
|
{"LIMIT"},
|
||||||
|
}
|
||||||
|
var replaceTokens = [][]string{
|
||||||
|
{"LOW_PRIORITY", "DELAYED"},
|
||||||
|
{"INTO"},
|
||||||
|
{"PARTITION"},
|
||||||
|
{"CUSTOM_FUZZ_STRING"},
|
||||||
|
{"VALUES", "VALUE"},
|
||||||
|
}
|
||||||
|
var loadTokens = [][]string{
|
||||||
|
{"DATA"},
|
||||||
|
{"LOW_PRIORITY", "CONCURRENT", "LOCAL"},
|
||||||
|
{"INFILE"},
|
||||||
|
{"REPLACE", "IGNORE"},
|
||||||
|
{"INTO TABLE"},
|
||||||
|
{"PARTITION"},
|
||||||
|
{"CHARACTER SET"},
|
||||||
|
{"FIELDS", "COLUMNS"},
|
||||||
|
{"TERMINATED BY"},
|
||||||
|
{"OPTIONALLY"},
|
||||||
|
{"ENCLOSED BY"},
|
||||||
|
{"ESCAPED BY"},
|
||||||
|
{"LINES"},
|
||||||
|
{"STARTING BY"},
|
||||||
|
{"TERMINATED BY"},
|
||||||
|
{"IGNORE"},
|
||||||
|
{"LINES", "ROWS"},
|
||||||
|
{"CUSTOM_FUZZ_STRING"},
|
||||||
|
}
|
||||||
|
|
||||||
|
// These Are everything that comes after "INSERT"
|
||||||
|
var insertTokens = [][]string{
|
||||||
|
{"LOW_PRIORITY", "DELAYED", "HIGH_PRIORITY", "IGNORE"},
|
||||||
|
{"INTO"},
|
||||||
|
{"PARTITION"},
|
||||||
|
{"CUSTOM_FUZZ_STRING"},
|
||||||
|
{"AS"},
|
||||||
|
{"ON DUPLICATE KEY UPDATE"},
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are everything that comes after "SELECT"
|
||||||
|
var selectTokens = [][]string{
|
||||||
|
{"*", "CUSTOM_FUZZ_STRING", "DISTINCTROW"},
|
||||||
|
{"HIGH_PRIORITY"},
|
||||||
|
{"STRAIGHT_JOIN"},
|
||||||
|
{"SQL_SMALL_RESULT", "SQL_BIG_RESULT", "SQL_BUFFER_RESULT"},
|
||||||
|
{"SQL_NO_CACHE", "SQL_CALC_FOUND_ROWS"},
|
||||||
|
{"CUSTOM_FUZZ_STRING"},
|
||||||
|
{"FROM"},
|
||||||
|
{"WHERE"},
|
||||||
|
{"GROUP BY"},
|
||||||
|
{"HAVING"},
|
||||||
|
{"WINDOW"},
|
||||||
|
{"ORDER BY"},
|
||||||
|
{"LIMIT"},
|
||||||
|
{"CUSTOM_FUZZ_STRING"},
|
||||||
|
{"FOR"},
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are everything that comes after "DELETE"
|
||||||
|
var deleteTokens = [][]string{
|
||||||
|
{"LOW_PRIORITY", "QUICK", "IGNORE", "FROM", "AS"},
|
||||||
|
{"PARTITION"},
|
||||||
|
{"WHERE"},
|
||||||
|
{"ORDER BY"},
|
||||||
|
{"LIMIT"},
|
||||||
|
}
|
||||||
|
|
||||||
|
var alter_table_options = []string{
|
||||||
|
"ADD", "COLUMN", "FIRST", "AFTER", "INDEX", "KEY", "FULLTEXT", "SPATIAL",
|
||||||
|
"CONSTRAINT", "UNIQUE", "FOREIGN KEY", "CHECK", "ENFORCED", "DROP", "ALTER",
|
||||||
|
"NOT", "INPLACE", "COPY", "SET", "VISIBLE", "INVISIBLE", "DEFAULT", "CHANGE",
|
||||||
|
"CHARACTER SET", "COLLATE", "DISABLE", "ENABLE", "KEYS", "TABLESPACE", "LOCK",
|
||||||
|
"FORCE", "MODIFY", "SHARED", "EXCLUSIVE", "NONE", "ORDER BY", "RENAME COLUMN",
|
||||||
|
"AS", "=", "ASC", "DESC", "WITH", "WITHOUT", "VALIDATION", "ADD PARTITION",
|
||||||
|
"DROP PARTITION", "DISCARD PARTITION", "IMPORT PARTITION", "TRUNCATE PARTITION",
|
||||||
|
"COALESCE PARTITION", "REORGANIZE PARTITION", "EXCHANGE PARTITION",
|
||||||
|
"ANALYZE PARTITION", "CHECK PARTITION", "OPTIMIZE PARTITION", "REBUILD PARTITION",
|
||||||
|
"REPAIR PARTITION", "REMOVE PARTITIONING", "USING", "BTREE", "HASH", "COMMENT",
|
||||||
|
"KEY_BLOCK_SIZE", "WITH PARSER", "AUTOEXTEND_SIZE", "AUTO_INCREMENT", "AVG_ROW_LENGTH",
|
||||||
|
"CHECKSUM", "INSERT_METHOD", "ROW_FORMAT", "DYNAMIC", "FIXED", "COMPRESSED", "REDUNDANT",
|
||||||
|
"COMPACT", "SECONDARY_ENGINE_ATTRIBUTE", "STATS_AUTO_RECALC", "STATS_PERSISTENT",
|
||||||
|
"STATS_SAMPLE_PAGES", "ZLIB", "LZ4", "ENGINE_ATTRIBUTE", "KEY_BLOCK_SIZE", "MAX_ROWS",
|
||||||
|
"MIN_ROWS", "PACK_KEYS", "PASSWORD", "COMPRESSION", "CONNECTION", "DIRECTORY",
|
||||||
|
"DELAY_KEY_WRITE", "ENCRYPTION", "STORAGE", "DISK", "MEMORY", "UNION"}
|
||||||
|
|
||||||
|
// Creates an 'alter table' statement. 'alter table' is an exception
|
||||||
|
// in that it has its own function. The majority of statements
|
||||||
|
// are created by 'createStmt()'.
|
||||||
|
func createAlterTableStmt(f *ConsumeFuzzer) (string, error) {
|
||||||
|
var stmt strings.Builder
|
||||||
|
stmt.WriteString("ALTER TABLE ")
|
||||||
|
maxArgs, err := f.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
maxArgs = maxArgs % 30
|
||||||
|
if maxArgs == 0 {
|
||||||
|
return "", fmt.Errorf("Could not create alter table stmt")
|
||||||
|
}
|
||||||
|
for i := 0; i < maxArgs; i++ {
|
||||||
|
// Calculate if we get existing token or custom string
|
||||||
|
tokenType, err := f.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if tokenType%4 == 1 {
|
||||||
|
customString, err := f.GetString()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
stmt.WriteString(fmt.Sprintf(" %s", customString))
|
||||||
|
} else {
|
||||||
|
tokenIndex, err := f.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
stmt.WriteString(fmt.Sprintf(" %s", alter_table_options[tokenIndex%len(alter_table_options)]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stmt.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func chooseToken(tokens []string, f *ConsumeFuzzer) (string, error) {
|
||||||
|
index, err := f.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
var token strings.Builder
|
||||||
|
token.WriteString(fmt.Sprintf(" %s", tokens[index%len(tokens)]))
|
||||||
|
if token.String() == "CUSTOM_FUZZ_STRING" {
|
||||||
|
customFuzzString, err := f.GetString()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return customFuzzString, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if token requires an argument
|
||||||
|
if containsString(needCustomString, token.String()) {
|
||||||
|
customFuzzString, err := f.GetString()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
token.WriteString(fmt.Sprintf(" %s", customFuzzString))
|
||||||
|
}
|
||||||
|
return token.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var stmtTypes = map[string][][]string{
|
||||||
|
"DELETE": deleteTokens,
|
||||||
|
"INSERT": insertTokens,
|
||||||
|
"SELECT": selectTokens,
|
||||||
|
"LOAD": loadTokens,
|
||||||
|
"REPLACE": replaceTokens,
|
||||||
|
"CREATE": createTokens,
|
||||||
|
"DROP": dropTokens,
|
||||||
|
"RENAME": renameTokens,
|
||||||
|
"TRUNCATE": truncateTokens,
|
||||||
|
"SET": setTokens,
|
||||||
|
"ALTER": alterTokens,
|
||||||
|
"ALTER TABLE": alterTableTokens, // ALTER TABLE has its own set of tokens
|
||||||
|
}
|
||||||
|
|
||||||
|
var stmtTypeEnum = map[int]string{
|
||||||
|
0: "DELETE",
|
||||||
|
1: "INSERT",
|
||||||
|
2: "SELECT",
|
||||||
|
3: "LOAD",
|
||||||
|
4: "REPLACE",
|
||||||
|
5: "CREATE",
|
||||||
|
6: "DROP",
|
||||||
|
7: "RENAME",
|
||||||
|
8: "TRUNCATE",
|
||||||
|
9: "SET",
|
||||||
|
10: "ALTER",
|
||||||
|
11: "ALTER TABLE",
|
||||||
|
}
|
||||||
|
|
||||||
|
func createStmt(f *ConsumeFuzzer) (string, error) {
|
||||||
|
stmtIndex, err := f.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
stmtIndex = stmtIndex % len(stmtTypes)
|
||||||
|
|
||||||
|
queryType := stmtTypeEnum[stmtIndex]
|
||||||
|
tokens := stmtTypes[queryType]
|
||||||
|
|
||||||
|
// We have custom creator for ALTER TABLE
|
||||||
|
if queryType == "ALTER TABLE" {
|
||||||
|
query, err := createAlterTableStmt(f)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return query, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here we are creating a query that is not
|
||||||
|
// an 'alter table' query. For available
|
||||||
|
// queries, see "stmtTypes"
|
||||||
|
|
||||||
|
// First specify the first query keyword:
|
||||||
|
var query strings.Builder
|
||||||
|
query.WriteString(queryType)
|
||||||
|
|
||||||
|
// Next create the args for the
|
||||||
|
queryArgs, err := createStmtArgs(tokens, f)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
query.WriteString(fmt.Sprintf(" %s", queryArgs))
|
||||||
|
return query.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates the arguments of a statements. In a select statement
|
||||||
|
// that would be everything after "select".
|
||||||
|
func createStmtArgs(tokenslice [][]string, f *ConsumeFuzzer) (string, error) {
|
||||||
|
var query strings.Builder
|
||||||
|
var token strings.Builder
|
||||||
|
|
||||||
|
// We go through the tokens in the tokenslice,
|
||||||
|
// create the respective token and add it to
|
||||||
|
// "query"
|
||||||
|
for _, tokens := range tokenslice {
|
||||||
|
|
||||||
|
// For extra randomization, the fuzzer can
|
||||||
|
// choose to not include this token.
|
||||||
|
includeThisToken, err := f.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if !includeThisToken {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// There may be several tokens to choose from:
|
||||||
|
if len(tokens) > 1 {
|
||||||
|
chosenToken, err := chooseToken(tokens, f)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
query.WriteString(fmt.Sprintf(" %s", chosenToken))
|
||||||
|
} else {
|
||||||
|
token.WriteString(tokens[0])
|
||||||
|
|
||||||
|
// In case the token is "CUSTOM_FUZZ_STRING"
|
||||||
|
// we will then create a non-structured string
|
||||||
|
if token.String() == "CUSTOM_FUZZ_STRING" {
|
||||||
|
customFuzzString, err := f.GetString()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
query.WriteString(fmt.Sprintf(" %s", customFuzzString))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if token requires an argument.
|
||||||
|
// Tokens that take an argument can be found
|
||||||
|
// in 'needCustomString'. If so, we add a
|
||||||
|
// non-structured string to the token.
|
||||||
|
if containsString(needCustomString, token.String()) {
|
||||||
|
customFuzzString, err := f.GetString()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
token.WriteString(fmt.Sprintf(" %s", customFuzzString))
|
||||||
|
}
|
||||||
|
query.WriteString(fmt.Sprintf(" %s", token.String()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return query.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a semi-structured query. It creates a string
|
||||||
|
// that is a combination of the keywords and random strings.
|
||||||
|
func createQuery(f *ConsumeFuzzer) (string, error) {
|
||||||
|
queryLen, err := f.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
maxLen := queryLen % 60
|
||||||
|
if maxLen == 0 {
|
||||||
|
return "", fmt.Errorf("Could not create a query")
|
||||||
|
}
|
||||||
|
var query strings.Builder
|
||||||
|
for i := 0; i < maxLen; i++ {
|
||||||
|
// Get a new token:
|
||||||
|
useKeyword, err := f.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if useKeyword {
|
||||||
|
keyword, err := getKeyword(f)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
query.WriteString(fmt.Sprintf(" %s", keyword))
|
||||||
|
} else {
|
||||||
|
customString, err := f.GetString()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
query.WriteString(fmt.Sprintf(" %s", customString))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if query.String() == "" {
|
||||||
|
return "", fmt.Errorf("Could not create a query")
|
||||||
|
}
|
||||||
|
return query.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the API that users will interact with.
|
||||||
|
// Usage:
|
||||||
|
// f := NewConsumer(data)
|
||||||
|
// sqlString, err := f.GetSQLString()
|
||||||
|
func (f *ConsumeFuzzer) GetSQLString() (string, error) {
|
||||||
|
var query string
|
||||||
|
veryStructured, err := f.GetBool()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if veryStructured {
|
||||||
|
query, err = createStmt(f)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
query, err = createQuery(f)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return query, nil
|
||||||
|
}
|
21
vendor/github.com/cyphar/filepath-securejoin/.travis.yml
generated
vendored
Normal file
21
vendor/github.com/cyphar/filepath-securejoin/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Copyright (C) 2017 SUSE LLC. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style
|
||||||
|
# license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.13.x
|
||||||
|
- 1.16.x
|
||||||
|
- tip
|
||||||
|
arch:
|
||||||
|
- AMD64
|
||||||
|
- ppc64le
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
- osx
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go test -cover -v ./...
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email: false
|
28
vendor/github.com/cyphar/filepath-securejoin/LICENSE
generated
vendored
Normal file
28
vendor/github.com/cyphar/filepath-securejoin/LICENSE
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
|
||||||
|
Copyright (C) 2017 SUSE LLC. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
79
vendor/github.com/cyphar/filepath-securejoin/README.md
generated
vendored
Normal file
79
vendor/github.com/cyphar/filepath-securejoin/README.md
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
## `filepath-securejoin` ##
|
||||||
|
|
||||||
|
[](https://travis-ci.org/cyphar/filepath-securejoin)
|
||||||
|
|
||||||
|
An implementation of `SecureJoin`, a [candidate for inclusion in the Go
|
||||||
|
standard library][go#20126]. The purpose of this function is to be a "secure"
|
||||||
|
alternative to `filepath.Join`, and in particular it provides certain
|
||||||
|
guarantees that are not provided by `filepath.Join`.
|
||||||
|
|
||||||
|
> **NOTE**: This code is *only* safe if you are not at risk of other processes
|
||||||
|
> modifying path components after you've used `SecureJoin`. If it is possible
|
||||||
|
> for a malicious process to modify path components of the resolved path, then
|
||||||
|
> you will be vulnerable to some fairly trivial TOCTOU race conditions. [There
|
||||||
|
> are some Linux kernel patches I'm working on which might allow for a better
|
||||||
|
> solution.][lwn-obeneath]
|
||||||
|
>
|
||||||
|
> In addition, with a slightly modified API it might be possible to use
|
||||||
|
> `O_PATH` and verify that the opened path is actually the resolved one -- but
|
||||||
|
> I have not done that yet. I might add it in the future as a helper function
|
||||||
|
> to help users verify the path (we can't just return `/proc/self/fd/<foo>`
|
||||||
|
> because that doesn't always work transparently for all users).
|
||||||
|
|
||||||
|
This is the function prototype:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func SecureJoin(root, unsafePath string) (string, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
This library **guarantees** the following:
|
||||||
|
|
||||||
|
* If no error is set, the resulting string **must** be a child path of
|
||||||
|
`root` and will not contain any symlink path components (they will all be
|
||||||
|
expanded).
|
||||||
|
|
||||||
|
* When expanding symlinks, all symlink path components **must** be resolved
|
||||||
|
relative to the provided root. In particular, this can be considered a
|
||||||
|
userspace implementation of how `chroot(2)` operates on file paths. Note that
|
||||||
|
these symlinks will **not** be expanded lexically (`filepath.Clean` is not
|
||||||
|
called on the input before processing).
|
||||||
|
|
||||||
|
* Non-existent path components are unaffected by `SecureJoin` (similar to
|
||||||
|
`filepath.EvalSymlinks`'s semantics).
|
||||||
|
|
||||||
|
* The returned path will always be `filepath.Clean`ed and thus not contain any
|
||||||
|
`..` components.
|
||||||
|
|
||||||
|
A (trivial) implementation of this function on GNU/Linux systems could be done
|
||||||
|
with the following (note that this requires root privileges and is far more
|
||||||
|
opaque than the implementation in this library, and also requires that
|
||||||
|
`readlink` is inside the `root` path):
|
||||||
|
|
||||||
|
```go
|
||||||
|
package securejoin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SecureJoin(root, unsafePath string) (string, error) {
|
||||||
|
unsafePath = string(filepath.Separator) + unsafePath
|
||||||
|
cmd := exec.Command("chroot", root,
|
||||||
|
"readlink", "--canonicalize-missing", "--no-newline", unsafePath)
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
expanded := string(output)
|
||||||
|
return filepath.Join(root, expanded), nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
[lwn-obeneath]: https://lwn.net/Articles/767547/
|
||||||
|
[go#20126]: https://github.com/golang/go/issues/20126
|
||||||
|
|
||||||
|
### License ###
|
||||||
|
|
||||||
|
The license of this project is the same as Go, which is a BSD 3-clause license
|
||||||
|
available in the `LICENSE` file.
|
1
vendor/github.com/cyphar/filepath-securejoin/VERSION
generated
vendored
Normal file
1
vendor/github.com/cyphar/filepath-securejoin/VERSION
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
0.2.3
|
115
vendor/github.com/cyphar/filepath-securejoin/join.go
generated
vendored
Normal file
115
vendor/github.com/cyphar/filepath-securejoin/join.go
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
// Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
|
||||||
|
// Copyright (C) 2017 SUSE LLC. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package securejoin is an implementation of the hopefully-soon-to-be-included
|
||||||
|
// SecureJoin helper that is meant to be part of the "path/filepath" package.
|
||||||
|
// The purpose of this project is to provide a PoC implementation to make the
|
||||||
|
// SecureJoin proposal (https://github.com/golang/go/issues/20126) more
|
||||||
|
// tangible.
|
||||||
|
package securejoin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsNotExist tells you if err is an error that implies that either the path
|
||||||
|
// accessed does not exist (or path components don't exist). This is
|
||||||
|
// effectively a more broad version of os.IsNotExist.
|
||||||
|
func IsNotExist(err error) bool {
|
||||||
|
// Check that it's not actually an ENOTDIR, which in some cases is a more
|
||||||
|
// convoluted case of ENOENT (usually involving weird paths).
|
||||||
|
return errors.Is(err, os.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) || errors.Is(err, syscall.ENOENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecureJoinVFS joins the two given path components (similar to Join) except
|
||||||
|
// that the returned path is guaranteed to be scoped inside the provided root
|
||||||
|
// path (when evaluated). Any symbolic links in the path are evaluated with the
|
||||||
|
// given root treated as the root of the filesystem, similar to a chroot. The
|
||||||
|
// filesystem state is evaluated through the given VFS interface (if nil, the
|
||||||
|
// standard os.* family of functions are used).
|
||||||
|
//
|
||||||
|
// Note that the guarantees provided by this function only apply if the path
|
||||||
|
// components in the returned string are not modified (in other words are not
|
||||||
|
// replaced with symlinks on the filesystem) after this function has returned.
|
||||||
|
// Such a symlink race is necessarily out-of-scope of SecureJoin.
|
||||||
|
func SecureJoinVFS(root, unsafePath string, vfs VFS) (string, error) {
|
||||||
|
// Use the os.* VFS implementation if none was specified.
|
||||||
|
if vfs == nil {
|
||||||
|
vfs = osVFS{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var path bytes.Buffer
|
||||||
|
n := 0
|
||||||
|
for unsafePath != "" {
|
||||||
|
if n > 255 {
|
||||||
|
return "", &os.PathError{Op: "SecureJoin", Path: root + "/" + unsafePath, Err: syscall.ELOOP}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next path component, p.
|
||||||
|
i := strings.IndexRune(unsafePath, filepath.Separator)
|
||||||
|
var p string
|
||||||
|
if i == -1 {
|
||||||
|
p, unsafePath = unsafePath, ""
|
||||||
|
} else {
|
||||||
|
p, unsafePath = unsafePath[:i], unsafePath[i+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a cleaned path, using the lexical semantics of /../a, to
|
||||||
|
// create a "scoped" path component which can safely be joined to fullP
|
||||||
|
// for evaluation. At this point, path.String() doesn't contain any
|
||||||
|
// symlink components.
|
||||||
|
cleanP := filepath.Clean(string(filepath.Separator) + path.String() + p)
|
||||||
|
if cleanP == string(filepath.Separator) {
|
||||||
|
path.Reset()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fullP := filepath.Clean(root + cleanP)
|
||||||
|
|
||||||
|
// Figure out whether the path is a symlink.
|
||||||
|
fi, err := vfs.Lstat(fullP)
|
||||||
|
if err != nil && !IsNotExist(err) {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// Treat non-existent path components the same as non-symlinks (we
|
||||||
|
// can't do any better here).
|
||||||
|
if IsNotExist(err) || fi.Mode()&os.ModeSymlink == 0 {
|
||||||
|
path.WriteString(p)
|
||||||
|
path.WriteRune(filepath.Separator)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only increment when we actually dereference a link.
|
||||||
|
n++
|
||||||
|
|
||||||
|
// It's a symlink, expand it by prepending it to the yet-unparsed path.
|
||||||
|
dest, err := vfs.Readlink(fullP)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// Absolute symlinks reset any work we've already done.
|
||||||
|
if filepath.IsAbs(dest) {
|
||||||
|
path.Reset()
|
||||||
|
}
|
||||||
|
unsafePath = dest + string(filepath.Separator) + unsafePath
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have to clean path.String() here because it may contain '..'
|
||||||
|
// components that are entirely lexical, but would be misleading otherwise.
|
||||||
|
// And finally do a final clean to ensure that root is also lexically
|
||||||
|
// clean.
|
||||||
|
fullP := filepath.Clean(string(filepath.Separator) + path.String())
|
||||||
|
return filepath.Clean(root + fullP), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecureJoin is a wrapper around SecureJoinVFS that just uses the os.* library
|
||||||
|
// of functions as the VFS. If in doubt, use this function over SecureJoinVFS.
|
||||||
|
func SecureJoin(root, unsafePath string) (string, error) {
|
||||||
|
return SecureJoinVFS(root, unsafePath, nil)
|
||||||
|
}
|
41
vendor/github.com/cyphar/filepath-securejoin/vfs.go
generated
vendored
Normal file
41
vendor/github.com/cyphar/filepath-securejoin/vfs.go
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// Copyright (C) 2017 SUSE LLC. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package securejoin
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
// In future this should be moved into a separate package, because now there
|
||||||
|
// are several projects (umoci and go-mtree) that are using this sort of
|
||||||
|
// interface.
|
||||||
|
|
||||||
|
// VFS is the minimal interface necessary to use SecureJoinVFS. A nil VFS is
|
||||||
|
// equivalent to using the standard os.* family of functions. This is mainly
|
||||||
|
// used for the purposes of mock testing, but also can be used to otherwise use
|
||||||
|
// SecureJoin with VFS-like system.
|
||||||
|
type VFS interface {
|
||||||
|
// Lstat returns a FileInfo describing the named file. If the file is a
|
||||||
|
// symbolic link, the returned FileInfo describes the symbolic link. Lstat
|
||||||
|
// makes no attempt to follow the link. These semantics are identical to
|
||||||
|
// os.Lstat.
|
||||||
|
Lstat(name string) (os.FileInfo, error)
|
||||||
|
|
||||||
|
// Readlink returns the destination of the named symbolic link. These
|
||||||
|
// semantics are identical to os.Readlink.
|
||||||
|
Readlink(name string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// osVFS is the "nil" VFS, in that it just passes everything through to the os
|
||||||
|
// module.
|
||||||
|
type osVFS struct{}
|
||||||
|
|
||||||
|
// Lstat returns a FileInfo describing the named file. If the file is a
|
||||||
|
// symbolic link, the returned FileInfo describes the symbolic link. Lstat
|
||||||
|
// makes no attempt to follow the link. These semantics are identical to
|
||||||
|
// os.Lstat.
|
||||||
|
func (o osVFS) Lstat(name string) (os.FileInfo, error) { return os.Lstat(name) }
|
||||||
|
|
||||||
|
// Readlink returns the destination of the named symbolic link. These
|
||||||
|
// semantics are identical to os.Readlink.
|
||||||
|
func (o osVFS) Readlink(name string) (string, error) { return os.Readlink(name) }
|
5
vendor/modules.txt
vendored
5
vendor/modules.txt
vendored
@ -1,4 +1,4 @@
|
|||||||
# github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8
|
# github.com/AdaLogics/go-fuzz-headers v0.0.0-20220706123152-fef3fe1bab07
|
||||||
## explicit; go 1.13
|
## explicit; go 1.13
|
||||||
github.com/AdaLogics/go-fuzz-headers
|
github.com/AdaLogics/go-fuzz-headers
|
||||||
# github.com/Microsoft/go-winio v0.5.2
|
# github.com/Microsoft/go-winio v0.5.2
|
||||||
@ -166,6 +166,9 @@ github.com/coreos/go-systemd/v22/dbus
|
|||||||
# github.com/cpuguy83/go-md2man/v2 v2.0.1
|
# github.com/cpuguy83/go-md2man/v2 v2.0.1
|
||||||
## explicit; go 1.11
|
## explicit; go 1.11
|
||||||
github.com/cpuguy83/go-md2man/v2/md2man
|
github.com/cpuguy83/go-md2man/v2/md2man
|
||||||
|
# github.com/cyphar/filepath-securejoin v0.2.3
|
||||||
|
## explicit; go 1.13
|
||||||
|
github.com/cyphar/filepath-securejoin
|
||||||
# github.com/davecgh/go-spew v1.1.1
|
# github.com/davecgh/go-spew v1.1.1
|
||||||
## explicit
|
## explicit
|
||||||
github.com/davecgh/go-spew/spew
|
github.com/davecgh/go-spew/spew
|
||||||
|
Loading…
Reference in New Issue
Block a user