forked from TrueCloudLab/distribution
Fuzzing: Move over two fuzzers from cncf-fuzzing
Signed-off-by: AdamKorcz <adam@adalogics.com> Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
0ea92a1a8d
commit
e2a43ec8d3
20 changed files with 2181 additions and 31 deletions
8
go.mod
8
go.mod
|
@ -3,6 +3,7 @@ module github.com/distribution/distribution/v3
|
||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20221103172237-443f56ff4ba8
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0
|
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0
|
||||||
|
@ -30,7 +31,7 @@ require (
|
||||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c
|
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c
|
||||||
google.golang.org/api v0.30.0
|
google.golang.org/api v0.30.0
|
||||||
google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8
|
google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -43,6 +44,7 @@ require (
|
||||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b // indirect
|
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b // indirect
|
||||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 // indirect
|
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||||
|
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.1 // indirect
|
github.com/felixge/httpsnoop v1.0.1 // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
|
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||||
|
@ -51,8 +53,8 @@ require (
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5 // indirect
|
github.com/googleapis/gax-go/v2 v2.0.5 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/kr/pretty v0.1.0 // indirect
|
github.com/kr/pretty v0.2.1 // indirect
|
||||||
github.com/kr/text v0.1.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||||
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f // indirect
|
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f // indirect
|
||||||
|
|
17
go.sum
17
go.sum
|
@ -32,6 +32,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-20221103172237-443f56ff4ba8 h1:d+pBUmsteW5tM87xmVXHZ4+LibHRFn40SPAoZJOg2ak=
|
||||||
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20221103172237-443f56ff4ba8/go.mod h1:i9fr2JpcEcY/IHEvzCM3qXUZYOQHgR89dt4es1CgMhc=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0 h1:VuHAcMq8pU1IWNT/m5yRaGqbK0BiQKHT8X4DTp9CHdI=
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0 h1:VuHAcMq8pU1IWNT/m5yRaGqbK0BiQKHT8X4DTp9CHdI=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0/go.mod h1:tZoQYdDZNOiIjdSn0dVWVfl0NEPGOJqVLzSrcFk4Is0=
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0/go.mod h1:tZoQYdDZNOiIjdSn0dVWVfl0NEPGOJqVLzSrcFk4Is0=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1 h1:T8quHYlUGyb/oqtSTwqlCr1ilJHrDv+ZtpSfo+hm1BU=
|
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.1 h1:T8quHYlUGyb/oqtSTwqlCr1ilJHrDv+ZtpSfo+hm1BU=
|
||||||
|
@ -77,6 +79,9 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI=
|
||||||
|
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
@ -196,11 +201,13 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||||
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
|
@ -271,6 +278,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
@ -559,8 +567,9 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
@ -570,6 +579,8 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|
46
registry/auth/token/fuzz_test.go
Normal file
46
registry/auth/token/fuzz_test.go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package token
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
fuzz "github.com/AdaLogics/go-fuzz-headers"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FuzzToken1(f *testing.F) {
|
||||||
|
f.Fuzz(func(t *testing.T, data []byte) {
|
||||||
|
ff := fuzz.NewConsumer(data)
|
||||||
|
rawToken, err := ff.GetString()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
verifyOps := VerifyOptions{}
|
||||||
|
err = ff.GenerateStruct(&verifyOps)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
token, err := NewToken(rawToken)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
token.Verify(verifyOps)
|
||||||
|
_, _ = token.VerifySigningKey(verifyOps)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func FuzzToken2(f *testing.F) {
|
||||||
|
f.Fuzz(func(t *testing.T, data []byte) {
|
||||||
|
ff := fuzz.NewConsumer(data)
|
||||||
|
verifyOps := VerifyOptions{}
|
||||||
|
err := ff.GenerateStruct(&verifyOps)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
token := &Token{}
|
||||||
|
err = ff.GenerateStruct(token)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
token.Verify(verifyOps)
|
||||||
|
_, _ = token.VerifySigningKey(verifyOps)
|
||||||
|
})
|
||||||
|
}
|
201
vendor/github.com/AdaLogics/go-fuzz-headers/LICENSE
generated
vendored
Normal file
201
vendor/github.com/AdaLogics/go-fuzz-headers/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
93
vendor/github.com/AdaLogics/go-fuzz-headers/README.md
generated
vendored
Normal file
93
vendor/github.com/AdaLogics/go-fuzz-headers/README.md
generated
vendored
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
# go-fuzz-headers
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
Using go-fuzz-headers is easy. First create a new consumer with the bytes provided by the fuzzing engine:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
fuzz "github.com/AdaLogics/go-fuzz-headers"
|
||||||
|
)
|
||||||
|
data := []byte{'R', 'a', 'n', 'd', 'o', 'm'}
|
||||||
|
f := fuzz.NewConsumer(data)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
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)
|
||||||
|
```
|
||||||
|
|
||||||
|
This includes nested structs too. In this example, the fuzz Consumer will also insert values in `p.BestFriend`:
|
||||||
|
```go
|
||||||
|
type PersonI struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
BestFriend PersonII
|
||||||
|
}
|
||||||
|
type PersonII struct {
|
||||||
|
Name string
|
||||||
|
Age int
|
||||||
|
}
|
||||||
|
p := PersonI{}
|
||||||
|
err := f.GenerateStruct(&p)
|
||||||
|
```
|
||||||
|
|
||||||
|
If the consumer should insert values for unexported fields as well as exported, this can be enabled with:
|
||||||
|
|
||||||
|
```go
|
||||||
|
f.AllowUnexportedFields()
|
||||||
|
```
|
||||||
|
|
||||||
|
...and disabled with:
|
||||||
|
|
||||||
|
```go
|
||||||
|
f.DisallowUnexportedFields()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Other types:
|
||||||
|
|
||||||
|
Other useful APIs:
|
||||||
|
|
||||||
|
```go
|
||||||
|
createdString, err := f.GetString() // Gets a string
|
||||||
|
createdInt, err := f.GetInt() // Gets an integer
|
||||||
|
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).
|
932
vendor/github.com/AdaLogics/go-fuzz-headers/consumer.go
generated
vendored
Normal file
932
vendor/github.com/AdaLogics/go-fuzz-headers/consumer.go
generated
vendored
Normal file
|
@ -0,0 +1,932 @@
|
||||||
|
package gofuzzheaders
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
securejoin "github.com/cyphar/filepath-securejoin"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
MaxTotalLen = uint32(2000000)
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetMaxTotalLen(newLen uint32) {
|
||||||
|
MaxTotalLen = newLen
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConsumeFuzzer struct {
|
||||||
|
data []byte
|
||||||
|
CommandPart []byte
|
||||||
|
RestOfArray []byte
|
||||||
|
NumberOfCalls int
|
||||||
|
position uint32
|
||||||
|
fuzzUnexportedFields bool
|
||||||
|
Funcs map[reflect.Type]reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsDivisibleBy(n int, divisibleby int) bool {
|
||||||
|
return (n % divisibleby) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConsumer(fuzzData []byte) *ConsumeFuzzer {
|
||||||
|
fuzzMap := make(map[reflect.Type]reflect.Value)
|
||||||
|
f := &ConsumeFuzzer{data: fuzzData, position: 0, Funcs: fuzzMap}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) Split(minCalls, maxCalls int) error {
|
||||||
|
if len(f.data) == 0 {
|
||||||
|
return errors.New("Could not split")
|
||||||
|
}
|
||||||
|
numberOfCalls := int(f.data[0])
|
||||||
|
if numberOfCalls < minCalls || numberOfCalls > maxCalls {
|
||||||
|
return errors.New("Bad number of calls")
|
||||||
|
|
||||||
|
}
|
||||||
|
if len(f.data) < numberOfCalls+numberOfCalls+1 {
|
||||||
|
return errors.New("Length of data does not match required parameters")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define part 2 and 3 of the data array
|
||||||
|
commandPart := f.data[1 : numberOfCalls+1]
|
||||||
|
restOfArray := f.data[numberOfCalls+1:]
|
||||||
|
|
||||||
|
// Just a small check. It is necessary
|
||||||
|
if len(commandPart) != numberOfCalls {
|
||||||
|
return errors.New("Length of commandPart does not match number of calls")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if restOfArray is divisible by numberOfCalls
|
||||||
|
if !IsDivisibleBy(len(restOfArray), numberOfCalls) {
|
||||||
|
return errors.New("Length of commandPart does not match number of calls")
|
||||||
|
}
|
||||||
|
f.CommandPart = commandPart
|
||||||
|
f.RestOfArray = restOfArray
|
||||||
|
f.NumberOfCalls = numberOfCalls
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) AllowUnexportedFields() {
|
||||||
|
f.fuzzUnexportedFields = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) DisallowUnexportedFields() {
|
||||||
|
f.fuzzUnexportedFields = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) GenerateStruct(targetStruct interface{}) error {
|
||||||
|
v := reflect.ValueOf(targetStruct)
|
||||||
|
/*if !v.CanSet() {
|
||||||
|
return errors.New("This interface cannot be set")
|
||||||
|
}*/
|
||||||
|
e := v.Elem()
|
||||||
|
err := f.fuzzStruct(e, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
case reflect.Struct:
|
||||||
|
for i := 0; i < e.NumField(); i++ {
|
||||||
|
var v reflect.Value
|
||||||
|
if !e.Field(i).CanSet() {
|
||||||
|
if f.fuzzUnexportedFields {
|
||||||
|
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 {
|
||||||
|
/*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 = reflect.New(e.Field(i).Type())
|
||||||
|
err := f.fuzzStruct(v, customFunctions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
/*if e.Field(i).CanSet() {
|
||||||
|
e.Field(i).Set(v.Elem())
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
str, err := f.GetString()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if e.CanSet() {
|
||||||
|
e.SetString(str)
|
||||||
|
}
|
||||||
|
case reflect.Slice:
|
||||||
|
var maxElements uint32
|
||||||
|
// Byte slices should not be restricted
|
||||||
|
if e.Type().String() == "[]uint8" {
|
||||||
|
maxElements = 10000000
|
||||||
|
} else {
|
||||||
|
maxElements = 50
|
||||||
|
}
|
||||||
|
|
||||||
|
randQty, err := f.GetUint32()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var numOfElements uint32
|
||||||
|
numOfElements = randQty % maxElements
|
||||||
|
if (uint32(len(f.data)) - f.position) < numOfElements {
|
||||||
|
numOfElements = uint32(len(f.data)) - f.position
|
||||||
|
}
|
||||||
|
|
||||||
|
uu := reflect.MakeSlice(e.Type(), int(numOfElements), int(numOfElements))
|
||||||
|
|
||||||
|
for i := 0; i < int(numOfElements); i++ {
|
||||||
|
err := f.fuzzStruct(uu.Index(i), customFunctions)
|
||||||
|
// If we have more than 10, then we can proceed with that.
|
||||||
|
if err != nil {
|
||||||
|
if i >= 10 {
|
||||||
|
if e.CanSet() {
|
||||||
|
e.Set(uu)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if e.CanSet() {
|
||||||
|
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:
|
||||||
|
newInt, err := f.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if e.CanSet() {
|
||||||
|
e.SetUint(uint64(newInt))
|
||||||
|
}
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
newInt, err := f.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if e.CanSet() {
|
||||||
|
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:
|
||||||
|
if e.CanSet() {
|
||||||
|
e.Set(reflect.MakeMap(e.Type()))
|
||||||
|
maxElements := 50
|
||||||
|
randQty, err := f.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
numOfElements := randQty % maxElements
|
||||||
|
for i := 0; i < numOfElements; i++ {
|
||||||
|
key := reflect.New(e.Type().Key()).Elem()
|
||||||
|
err := f.fuzzStruct(key, customFunctions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
val := reflect.New(e.Type().Elem()).Elem()
|
||||||
|
err = f.fuzzStruct(val, customFunctions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
e.SetMapIndex(key, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Ptr:
|
||||||
|
if e.CanSet() {
|
||||||
|
e.Set(reflect.New(e.Type().Elem()))
|
||||||
|
err := f.fuzzStruct(e.Elem(), customFunctions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case reflect.Uint8:
|
||||||
|
b, err := f.GetByte()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if e.CanSet() {
|
||||||
|
e.SetUint(uint64(b))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) GetStringArray() (reflect.Value, error) {
|
||||||
|
// The max size of the array:
|
||||||
|
max := uint32(20)
|
||||||
|
|
||||||
|
arraySize := f.position
|
||||||
|
if arraySize > max {
|
||||||
|
arraySize = max
|
||||||
|
}
|
||||||
|
elemType := reflect.TypeOf("string")
|
||||||
|
stringArray := reflect.MakeSlice(reflect.SliceOf(elemType), int(arraySize), int(arraySize))
|
||||||
|
if f.position+arraySize >= uint32(len(f.data)) {
|
||||||
|
return stringArray, errors.New("Could not make string array")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < int(arraySize); i++ {
|
||||||
|
stringSize := uint32(f.data[f.position])
|
||||||
|
|
||||||
|
if f.position+stringSize >= uint32(len(f.data)) {
|
||||||
|
return stringArray, nil
|
||||||
|
}
|
||||||
|
stringToAppend := string(f.data[f.position : f.position+stringSize])
|
||||||
|
strVal := reflect.ValueOf(stringToAppend)
|
||||||
|
stringArray = reflect.Append(stringArray, strVal)
|
||||||
|
f.position = f.position + stringSize
|
||||||
|
}
|
||||||
|
return stringArray, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) GetInt() (int, error) {
|
||||||
|
if f.position >= uint32(len(f.data)) {
|
||||||
|
return 0, errors.New("Not enough bytes to create int")
|
||||||
|
}
|
||||||
|
returnInt := int(f.data[f.position])
|
||||||
|
f.position++
|
||||||
|
return returnInt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) GetByte() (byte, error) {
|
||||||
|
if len(f.data) == 0 {
|
||||||
|
return 0x00, errors.New("Not enough bytes to get byte")
|
||||||
|
}
|
||||||
|
if f.position >= uint32(len(f.data)) {
|
||||||
|
return 0x00, errors.New("Not enough bytes to get byte")
|
||||||
|
}
|
||||||
|
returnByte := f.data[f.position]
|
||||||
|
f.position += 1
|
||||||
|
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 >= uint32(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) {
|
||||||
|
if len(f.data) == 0 || f.position >= uint32(len(f.data)) {
|
||||||
|
return nil, errors.New("Not enough bytes to create byte array")
|
||||||
|
}
|
||||||
|
length, err := f.GetUint32()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("Not enough bytes to create byte array")
|
||||||
|
}
|
||||||
|
if f.position+length > MaxTotalLen {
|
||||||
|
return nil, errors.New("Created too large a string")
|
||||||
|
}
|
||||||
|
byteBegin := f.position - 1
|
||||||
|
if byteBegin >= uint32(len(f.data)) {
|
||||||
|
return nil, errors.New("Not enough bytes to create byte array")
|
||||||
|
}
|
||||||
|
if length == 0 {
|
||||||
|
return nil, errors.New("Zero-length is not supported")
|
||||||
|
}
|
||||||
|
if byteBegin+length >= uint32(len(f.data)) {
|
||||||
|
return nil, errors.New("Not enough bytes to create byte array")
|
||||||
|
}
|
||||||
|
if byteBegin+length < byteBegin {
|
||||||
|
return nil, errors.New("Nunmbers overflow. Returning")
|
||||||
|
}
|
||||||
|
b := f.data[byteBegin : byteBegin+length]
|
||||||
|
f.position = byteBegin + length
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) GetString() (string, error) {
|
||||||
|
if f.position >= uint32(len(f.data)) {
|
||||||
|
return "nil", errors.New("Not enough bytes to create string")
|
||||||
|
}
|
||||||
|
length, err := f.GetUint32()
|
||||||
|
if err != nil {
|
||||||
|
return "nil", errors.New("Not enough bytes to create string")
|
||||||
|
}
|
||||||
|
if f.position > MaxTotalLen {
|
||||||
|
return "nil", errors.New("Created too large a string")
|
||||||
|
}
|
||||||
|
byteBegin := f.position - 1
|
||||||
|
if byteBegin >= uint32(len(f.data)) {
|
||||||
|
return "nil", errors.New("Not enough bytes to create string")
|
||||||
|
}
|
||||||
|
if byteBegin+length > uint32(len(f.data)) {
|
||||||
|
return "nil", errors.New("Not enough bytes to create string")
|
||||||
|
}
|
||||||
|
if byteBegin > byteBegin+length {
|
||||||
|
return "nil", errors.New("Numbers overflow. Returning")
|
||||||
|
}
|
||||||
|
str := string(f.data[byteBegin : byteBegin+length])
|
||||||
|
f.position = byteBegin + length
|
||||||
|
return str, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) GetBool() (bool, error) {
|
||||||
|
if f.position >= uint32(len(f.data)) {
|
||||||
|
return false, errors.New("Not enough bytes to create bool")
|
||||||
|
}
|
||||||
|
if IsDivisibleBy(int(f.data[f.position]), 2) {
|
||||||
|
f.position++
|
||||||
|
return true, nil
|
||||||
|
} else {
|
||||||
|
f.position++
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) FuzzMap(m interface{}) error {
|
||||||
|
err := f.GenerateStruct(m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func returnTarBytes(buf []byte) ([]byte, error) {
|
||||||
|
reader := bytes.NewReader(buf)
|
||||||
|
tr := tar.NewReader(reader)
|
||||||
|
|
||||||
|
// Count files
|
||||||
|
var fileCounter int
|
||||||
|
fileCounter = 0
|
||||||
|
for {
|
||||||
|
_, err := tr.Next()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fileCounter++
|
||||||
|
}
|
||||||
|
if fileCounter > 4 {
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("Not enough files were created\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func setTarHeaderFormat(hdr *tar.Header, f *ConsumeFuzzer) error {
|
||||||
|
ind, err := f.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch ind % 4 {
|
||||||
|
case 0:
|
||||||
|
hdr.Format = tar.FormatUnknown
|
||||||
|
case 1:
|
||||||
|
hdr.Format = tar.FormatUSTAR
|
||||||
|
case 2:
|
||||||
|
hdr.Format = tar.FormatPAX
|
||||||
|
case 3:
|
||||||
|
hdr.Format = tar.FormatGNU
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setTarHeaderTypeflag(hdr *tar.Header, f *ConsumeFuzzer) error {
|
||||||
|
ind, err := f.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch ind % 13 {
|
||||||
|
case 0:
|
||||||
|
hdr.Typeflag = tar.TypeReg
|
||||||
|
case 1:
|
||||||
|
hdr.Typeflag = tar.TypeLink
|
||||||
|
linkname, err := f.GetString()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
hdr.Linkname = linkname
|
||||||
|
case 2:
|
||||||
|
hdr.Typeflag = tar.TypeSymlink
|
||||||
|
linkname, err := f.GetString()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
hdr.Linkname = linkname
|
||||||
|
case 3:
|
||||||
|
hdr.Typeflag = tar.TypeChar
|
||||||
|
case 4:
|
||||||
|
hdr.Typeflag = tar.TypeBlock
|
||||||
|
case 5:
|
||||||
|
hdr.Typeflag = tar.TypeDir
|
||||||
|
case 6:
|
||||||
|
hdr.Typeflag = tar.TypeFifo
|
||||||
|
case 7:
|
||||||
|
hdr.Typeflag = tar.TypeCont
|
||||||
|
case 8:
|
||||||
|
hdr.Typeflag = tar.TypeXHeader
|
||||||
|
case 9:
|
||||||
|
hdr.Typeflag = tar.TypeXGlobalHeader
|
||||||
|
case 10:
|
||||||
|
hdr.Typeflag = tar.TypeGNUSparse
|
||||||
|
case 11:
|
||||||
|
hdr.Typeflag = tar.TypeGNULongName
|
||||||
|
case 12:
|
||||||
|
hdr.Typeflag = tar.TypeGNULongLink
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConsumeFuzzer) createTarFileBody() ([]byte, error) {
|
||||||
|
if len(f.data) == 0 || f.position >= uint32(len(f.data)) {
|
||||||
|
return nil, errors.New("Not enough bytes to create byte array")
|
||||||
|
}
|
||||||
|
length, err := f.GetUint32()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("Not enough bytes to create byte array")
|
||||||
|
}
|
||||||
|
|
||||||
|
// A bit of optimization to attempt to create a file body
|
||||||
|
// when we don't have as many bytes left as "length"
|
||||||
|
remainingBytes := (uint32(len(f.data)) - f.position)
|
||||||
|
totalDataLen := uint32(len(f.data))
|
||||||
|
if uint32(len(f.data))-f.position < 50 {
|
||||||
|
if remainingBytes == 0 {
|
||||||
|
return nil, errors.New("Created too large a string")
|
||||||
|
}
|
||||||
|
length = length % remainingBytes
|
||||||
|
} else if len(f.data) < 500 {
|
||||||
|
if totalDataLen == 0 {
|
||||||
|
return nil, errors.New("Created too large a string")
|
||||||
|
}
|
||||||
|
length = length % totalDataLen
|
||||||
|
}
|
||||||
|
if f.position+length > MaxTotalLen {
|
||||||
|
return nil, errors.New("Created too large a string")
|
||||||
|
}
|
||||||
|
byteBegin := f.position - 1
|
||||||
|
if byteBegin >= uint32(len(f.data)) {
|
||||||
|
return nil, errors.New("Not enough bytes to create byte array")
|
||||||
|
}
|
||||||
|
if length == 0 {
|
||||||
|
return nil, errors.New("Zero-length is not supported")
|
||||||
|
}
|
||||||
|
if byteBegin+length >= uint32(len(f.data)) {
|
||||||
|
return nil, errors.New("Not enough bytes to create byte array")
|
||||||
|
}
|
||||||
|
if byteBegin+length < byteBegin {
|
||||||
|
return nil, errors.New("Nunmbers overflow. Returning")
|
||||||
|
}
|
||||||
|
filebody := f.data[byteBegin : byteBegin+length]
|
||||||
|
f.position = byteBegin + length
|
||||||
|
return filebody, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is similar to GetString(), but creates string based on the length
|
||||||
|
// of the length of f.data to increase the likelihood of not overflowing
|
||||||
|
// f.data
|
||||||
|
func (f *ConsumeFuzzer) getTarFilename() (string, error) {
|
||||||
|
if f.position >= uint32(len(f.data)) {
|
||||||
|
return "nil", errors.New("Not enough bytes to create string")
|
||||||
|
}
|
||||||
|
length, err := f.GetUint32()
|
||||||
|
if err != nil {
|
||||||
|
return "nil", errors.New("Not enough bytes to create string")
|
||||||
|
}
|
||||||
|
|
||||||
|
// A bit of optimization to attempt to create a file name
|
||||||
|
// when we don't have as many bytes left as "length"
|
||||||
|
remainingBytes := (uint32(len(f.data)) - f.position)
|
||||||
|
totalDataLen := uint32(len(f.data))
|
||||||
|
if uint32(len(f.data))-f.position < 50 {
|
||||||
|
if remainingBytes == 0 {
|
||||||
|
return "nil", errors.New("Created too large a string")
|
||||||
|
}
|
||||||
|
length = length % remainingBytes
|
||||||
|
} else if len(f.data) < 500 {
|
||||||
|
if totalDataLen == 0 {
|
||||||
|
return "nil", errors.New("Created too large a string")
|
||||||
|
}
|
||||||
|
length = length % totalDataLen
|
||||||
|
}
|
||||||
|
if f.position > MaxTotalLen {
|
||||||
|
return "nil", errors.New("Created too large a string")
|
||||||
|
}
|
||||||
|
byteBegin := f.position - 1
|
||||||
|
if byteBegin >= uint32(len(f.data)) {
|
||||||
|
return "nil", errors.New("Not enough bytes to create string")
|
||||||
|
}
|
||||||
|
if byteBegin+length > uint32(len(f.data)) {
|
||||||
|
return "nil", errors.New("Not enough bytes to create string")
|
||||||
|
}
|
||||||
|
if byteBegin > byteBegin+length {
|
||||||
|
return "nil", errors.New("Numbers overflow. Returning")
|
||||||
|
}
|
||||||
|
str := string(f.data[byteBegin : byteBegin+length])
|
||||||
|
f.position = byteBegin + length
|
||||||
|
return str, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TarBytes returns valid bytes for a tar archive
|
||||||
|
func (f *ConsumeFuzzer) TarBytes() ([]byte, error) {
|
||||||
|
numberOfFiles, err := f.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
tw := tar.NewWriter(&buf)
|
||||||
|
defer tw.Close()
|
||||||
|
|
||||||
|
maxNoOfFiles := 1000
|
||||||
|
for i := 0; i < numberOfFiles%maxNoOfFiles; i++ {
|
||||||
|
filename, err := f.getTarFilename()
|
||||||
|
if err != nil {
|
||||||
|
return returnTarBytes(buf.Bytes())
|
||||||
|
}
|
||||||
|
filebody, err := f.createTarFileBody()
|
||||||
|
if err != nil {
|
||||||
|
return returnTarBytes(buf.Bytes())
|
||||||
|
}
|
||||||
|
hdr := &tar.Header{}
|
||||||
|
|
||||||
|
err = setTarHeaderTypeflag(hdr, f)
|
||||||
|
if err != nil {
|
||||||
|
return returnTarBytes(buf.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
sec, err := f.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return returnTarBytes(buf.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
nsec, err := f.GetInt()
|
||||||
|
if err != nil {
|
||||||
|
return returnTarBytes(buf.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
hdr.ModTime = time.Unix(int64(sec), int64(nsec))
|
||||||
|
|
||||||
|
hdr.Name = filename
|
||||||
|
hdr.Size = int64(len(filebody))
|
||||||
|
hdr.Mode = 0600
|
||||||
|
|
||||||
|
err = setTarHeaderFormat(hdr, f)
|
||||||
|
if err != nil {
|
||||||
|
return returnTarBytes(buf.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tw.WriteHeader(hdr); err != nil {
|
||||||
|
return returnTarBytes(buf.Bytes())
|
||||||
|
}
|
||||||
|
if _, err := tw.Write(filebody); err != nil {
|
||||||
|
return returnTarBytes(buf.Bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return returnTarBytes(buf.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (uint32(len(f.data)) - f.position) < uint32(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` ##
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/cyphar/filepath-securejoin.svg?branch=master)](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) }
|
2
vendor/github.com/kr/pretty/License
generated
vendored
2
vendor/github.com/kr/pretty/License
generated
vendored
|
@ -1,5 +1,3 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright 2012 Keith Rarick
|
Copyright 2012 Keith Rarick
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
|
5
vendor/github.com/kr/pretty/formatter.go
generated
vendored
5
vendor/github.com/kr/pretty/formatter.go
generated
vendored
|
@ -37,7 +37,7 @@ func (fo formatter) passThrough(f fmt.State, c rune) {
|
||||||
s := "%"
|
s := "%"
|
||||||
for i := 0; i < 128; i++ {
|
for i := 0; i < 128; i++ {
|
||||||
if f.Flag(i) {
|
if f.Flag(i) {
|
||||||
s += string(i)
|
s += string(rune(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if w, ok := f.Width(); ok {
|
if w, ok := f.Width(); ok {
|
||||||
|
@ -125,7 +125,6 @@ func (p *printer) printValue(v reflect.Value, showType, quote bool) {
|
||||||
}
|
}
|
||||||
keys := v.MapKeys()
|
keys := v.MapKeys()
|
||||||
for i := 0; i < v.Len(); i++ {
|
for i := 0; i < v.Len(); i++ {
|
||||||
showTypeInStruct := true
|
|
||||||
k := keys[i]
|
k := keys[i]
|
||||||
mv := v.MapIndex(k)
|
mv := v.MapIndex(k)
|
||||||
pp.printValue(k, false, true)
|
pp.printValue(k, false, true)
|
||||||
|
@ -133,7 +132,7 @@ func (p *printer) printValue(v reflect.Value, showType, quote bool) {
|
||||||
if expand {
|
if expand {
|
||||||
writeByte(pp, '\t')
|
writeByte(pp, '\t')
|
||||||
}
|
}
|
||||||
showTypeInStruct = t.Elem().Kind() == reflect.Interface
|
showTypeInStruct := t.Elem().Kind() == reflect.Interface
|
||||||
pp.printValue(mv, showTypeInStruct, true)
|
pp.printValue(mv, showTypeInStruct, true)
|
||||||
if expand {
|
if expand {
|
||||||
io.WriteString(pp, ",\n")
|
io.WriteString(pp, ",\n")
|
||||||
|
|
2
vendor/github.com/kr/pretty/pretty.go
generated
vendored
2
vendor/github.com/kr/pretty/pretty.go
generated
vendored
|
@ -75,7 +75,7 @@ func Printf(format string, a ...interface{}) (n int, errno error) {
|
||||||
|
|
||||||
// Println pretty-prints its operands and writes to standard output.
|
// Println pretty-prints its operands and writes to standard output.
|
||||||
//
|
//
|
||||||
// Calling Print(x, y) is equivalent to
|
// Calling Println(x, y) is equivalent to
|
||||||
// fmt.Println(Formatter(x), Formatter(y)), but each operand is
|
// fmt.Println(Formatter(x), Formatter(y)), but each operand is
|
||||||
// formatted with "%# v".
|
// formatted with "%# v".
|
||||||
func Println(a ...interface{}) (n int, errno error) {
|
func Println(a ...interface{}) (n int, errno error) {
|
||||||
|
|
14
vendor/gopkg.in/check.v1/check.go
generated
vendored
14
vendor/gopkg.in/check.v1/check.go
generated
vendored
|
@ -11,7 +11,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -143,17 +143,11 @@ func (td *tempDir) newPath() string {
|
||||||
td.Lock()
|
td.Lock()
|
||||||
defer td.Unlock()
|
defer td.Unlock()
|
||||||
if td.path == "" {
|
if td.path == "" {
|
||||||
var err error
|
path, err := ioutil.TempDir("", "check-")
|
||||||
for i := 0; i != 100; i++ {
|
if err != nil {
|
||||||
path := fmt.Sprintf("%s%ccheck-%d", os.TempDir(), os.PathSeparator, rand.Int())
|
|
||||||
if err = os.Mkdir(path, 0700); err == nil {
|
|
||||||
td.path = path
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if td.path == "" {
|
|
||||||
panic("Couldn't create temporary directory: " + err.Error())
|
panic("Couldn't create temporary directory: " + err.Error())
|
||||||
}
|
}
|
||||||
|
td.path = path
|
||||||
}
|
}
|
||||||
result := filepath.Join(td.path, strconv.Itoa(td.counter))
|
result := filepath.Join(td.path, strconv.Itoa(td.counter))
|
||||||
td.counter++
|
td.counter++
|
||||||
|
|
10
vendor/gopkg.in/check.v1/helpers.go
generated
vendored
10
vendor/gopkg.in/check.v1/helpers.go
generated
vendored
|
@ -155,8 +155,9 @@ func (c *C) Fatalf(format string, args ...interface{}) {
|
||||||
//
|
//
|
||||||
// Some checkers may not need the expected argument (e.g. IsNil).
|
// Some checkers may not need the expected argument (e.g. IsNil).
|
||||||
//
|
//
|
||||||
// Extra arguments provided to the function are logged next to the reported
|
// If the last value in args implements CommentInterface, it is used to log
|
||||||
// problem when the matching fails.
|
// additional information instead of being passed to the checker (see Commentf
|
||||||
|
// for an example).
|
||||||
func (c *C) Check(obtained interface{}, checker Checker, args ...interface{}) bool {
|
func (c *C) Check(obtained interface{}, checker Checker, args ...interface{}) bool {
|
||||||
return c.internalCheck("Check", obtained, checker, args...)
|
return c.internalCheck("Check", obtained, checker, args...)
|
||||||
}
|
}
|
||||||
|
@ -167,8 +168,9 @@ func (c *C) Check(obtained interface{}, checker Checker, args ...interface{}) bo
|
||||||
//
|
//
|
||||||
// Some checkers may not need the expected argument (e.g. IsNil).
|
// Some checkers may not need the expected argument (e.g. IsNil).
|
||||||
//
|
//
|
||||||
// Extra arguments provided to the function are logged next to the reported
|
// If the last value in args implements CommentInterface, it is used to log
|
||||||
// problem when the matching fails.
|
// additional information instead of being passed to the checker (see Commentf
|
||||||
|
// for an example).
|
||||||
func (c *C) Assert(obtained interface{}, checker Checker, args ...interface{}) {
|
func (c *C) Assert(obtained interface{}, checker Checker, args ...interface{}) {
|
||||||
if !c.internalCheck("Assert", obtained, checker, args...) {
|
if !c.internalCheck("Assert", obtained, checker, args...) {
|
||||||
c.stopNow()
|
c.stopNow()
|
||||||
|
|
16
vendor/modules.txt
vendored
16
vendor/modules.txt
vendored
|
@ -1,6 +1,9 @@
|
||||||
# cloud.google.com/go v0.65.0
|
# cloud.google.com/go v0.65.0
|
||||||
## explicit; go 1.11
|
## explicit; go 1.11
|
||||||
cloud.google.com/go/compute/metadata
|
cloud.google.com/go/compute/metadata
|
||||||
|
# github.com/AdaLogics/go-fuzz-headers v0.0.0-20221103172237-443f56ff4ba8
|
||||||
|
## explicit; go 1.13
|
||||||
|
github.com/AdaLogics/go-fuzz-headers
|
||||||
# github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0
|
# github.com/Azure/azure-sdk-for-go/sdk/azcore v1.3.0
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore
|
github.com/Azure/azure-sdk-for-go/sdk/azcore
|
||||||
|
@ -143,6 +146,9 @@ github.com/bugsnag/panicwrap
|
||||||
# github.com/cespare/xxhash/v2 v2.1.2
|
# github.com/cespare/xxhash/v2 v2.1.2
|
||||||
## explicit; go 1.11
|
## explicit; go 1.11
|
||||||
github.com/cespare/xxhash/v2
|
github.com/cespare/xxhash/v2
|
||||||
|
# github.com/cyphar/filepath-securejoin v0.2.3
|
||||||
|
## explicit; go 1.13
|
||||||
|
github.com/cyphar/filepath-securejoin
|
||||||
# github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba
|
# github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba
|
||||||
## explicit
|
## explicit
|
||||||
github.com/denverdino/aliyungo/cdn/auth
|
github.com/denverdino/aliyungo/cdn/auth
|
||||||
|
@ -199,10 +205,10 @@ github.com/inconshreveable/mousetrap
|
||||||
# github.com/jmespath/go-jmespath v0.4.0
|
# github.com/jmespath/go-jmespath v0.4.0
|
||||||
## explicit; go 1.14
|
## explicit; go 1.14
|
||||||
github.com/jmespath/go-jmespath
|
github.com/jmespath/go-jmespath
|
||||||
# github.com/kr/pretty v0.1.0
|
# github.com/kr/pretty v0.2.1
|
||||||
## explicit
|
## explicit; go 1.12
|
||||||
github.com/kr/pretty
|
github.com/kr/pretty
|
||||||
# github.com/kr/text v0.1.0
|
# github.com/kr/text v0.2.0
|
||||||
## explicit
|
## explicit
|
||||||
github.com/kr/text
|
github.com/kr/text
|
||||||
# github.com/kylelemons/godebug v1.1.0
|
# github.com/kylelemons/godebug v1.1.0
|
||||||
|
@ -433,8 +439,8 @@ google.golang.org/protobuf/types/descriptorpb
|
||||||
google.golang.org/protobuf/types/known/anypb
|
google.golang.org/protobuf/types/known/anypb
|
||||||
google.golang.org/protobuf/types/known/durationpb
|
google.golang.org/protobuf/types/known/durationpb
|
||||||
google.golang.org/protobuf/types/known/timestamppb
|
google.golang.org/protobuf/types/known/timestamppb
|
||||||
# gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15
|
# gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
|
||||||
## explicit
|
## explicit; go 1.11
|
||||||
gopkg.in/check.v1
|
gopkg.in/check.v1
|
||||||
# gopkg.in/yaml.v2 v2.4.0
|
# gopkg.in/yaml.v2 v2.4.0
|
||||||
## explicit; go 1.15
|
## explicit; go 1.15
|
||||||
|
|
Loading…
Reference in a new issue