Merge pull request #3795 from AdamKorcz/fuzz222
Fuzzing: Move over two fuzzers from cncf-fuzzing
This commit is contained in:
commit
4adbb690c1
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
|
||||
|
||||
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/azidentity v1.2.1
|
||||
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
|
||||
google.golang.org/api v0.30.0
|
||||
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
|
||||
)
|
||||
|
||||
|
@ -43,6 +44,7 @@ require (
|
|||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b // indirect
|
||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 // 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/golang-jwt/jwt/v4 v4.4.2 // 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/inconshreveable/mousetrap v1.0.1 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/kr/text v0.1.0 // indirect
|
||||
github.com/kr/pretty v0.2.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // 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.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=
|
||||
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/go.mod h1:tZoQYdDZNOiIjdSn0dVWVfl0NEPGOJqVLzSrcFk4Is0=
|
||||
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/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/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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
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.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/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.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/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.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/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
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.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.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
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.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/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-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-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/yaml.v2 v2.2.1/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.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
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
|
||||
|
||||
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 := "%"
|
||||
for i := 0; i < 128; i++ {
|
||||
if f.Flag(i) {
|
||||
s += string(i)
|
||||
s += string(rune(i))
|
||||
}
|
||||
}
|
||||
if w, ok := f.Width(); ok {
|
||||
|
@ -125,7 +125,6 @@ func (p *printer) printValue(v reflect.Value, showType, quote bool) {
|
|||
}
|
||||
keys := v.MapKeys()
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
showTypeInStruct := true
|
||||
k := keys[i]
|
||||
mv := v.MapIndex(k)
|
||||
pp.printValue(k, false, true)
|
||||
|
@ -133,7 +132,7 @@ func (p *printer) printValue(v reflect.Value, showType, quote bool) {
|
|||
if expand {
|
||||
writeByte(pp, '\t')
|
||||
}
|
||||
showTypeInStruct = t.Elem().Kind() == reflect.Interface
|
||||
showTypeInStruct := t.Elem().Kind() == reflect.Interface
|
||||
pp.printValue(mv, showTypeInStruct, true)
|
||||
if expand {
|
||||
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.
|
||||
//
|
||||
// Calling Print(x, y) is equivalent to
|
||||
// Calling Println(x, y) is equivalent to
|
||||
// fmt.Println(Formatter(x), Formatter(y)), but each operand is
|
||||
// formatted with "%# v".
|
||||
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"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
@ -143,17 +143,11 @@ func (td *tempDir) newPath() string {
|
|||
td.Lock()
|
||||
defer td.Unlock()
|
||||
if td.path == "" {
|
||||
var err error
|
||||
for i := 0; i != 100; i++ {
|
||||
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 == "" {
|
||||
path, err := ioutil.TempDir("", "check-")
|
||||
if err != nil {
|
||||
panic("Couldn't create temporary directory: " + err.Error())
|
||||
}
|
||||
td.path = path
|
||||
}
|
||||
result := filepath.Join(td.path, strconv.Itoa(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).
|
||||
//
|
||||
// Extra arguments provided to the function are logged next to the reported
|
||||
// problem when the matching fails.
|
||||
// If the last value in args implements CommentInterface, it is used to log
|
||||
// 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 {
|
||||
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).
|
||||
//
|
||||
// Extra arguments provided to the function are logged next to the reported
|
||||
// problem when the matching fails.
|
||||
// If the last value in args implements CommentInterface, it is used to log
|
||||
// additional information instead of being passed to the checker (see Commentf
|
||||
// for an example).
|
||||
func (c *C) Assert(obtained interface{}, checker Checker, args ...interface{}) {
|
||||
if !c.internalCheck("Assert", obtained, checker, args...) {
|
||||
c.stopNow()
|
||||
|
|
16
vendor/modules.txt
vendored
16
vendor/modules.txt
vendored
|
@ -1,6 +1,9 @@
|
|||
# cloud.google.com/go v0.65.0
|
||||
## explicit; go 1.11
|
||||
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
|
||||
## explicit; go 1.18
|
||||
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
|
||||
## explicit; go 1.11
|
||||
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
|
||||
## explicit
|
||||
github.com/denverdino/aliyungo/cdn/auth
|
||||
|
@ -199,10 +205,10 @@ github.com/inconshreveable/mousetrap
|
|||
# github.com/jmespath/go-jmespath v0.4.0
|
||||
## explicit; go 1.14
|
||||
github.com/jmespath/go-jmespath
|
||||
# github.com/kr/pretty v0.1.0
|
||||
## explicit
|
||||
# github.com/kr/pretty v0.2.1
|
||||
## explicit; go 1.12
|
||||
github.com/kr/pretty
|
||||
# github.com/kr/text v0.1.0
|
||||
# github.com/kr/text v0.2.0
|
||||
## explicit
|
||||
github.com/kr/text
|
||||
# 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/durationpb
|
||||
google.golang.org/protobuf/types/known/timestamppb
|
||||
# gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15
|
||||
## explicit
|
||||
# gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
|
||||
## explicit; go 1.11
|
||||
gopkg.in/check.v1
|
||||
# gopkg.in/yaml.v2 v2.4.0
|
||||
## explicit; go 1.15
|
||||
|
|
Loading…
Reference in a new issue