From 2cd9647fcc098cd743b4e569009614aae6820620 Mon Sep 17 00:00:00 2001 From: Darren Kelly Date: Mon, 8 Jan 2024 16:09:31 +0000 Subject: [PATCH 1/9] chore: add go linting --- .github/workflows/lint-go.yaml | 62 ++++++++++++++++++++++++++++++++++ builtin/gen/bindata.go | 23 +++++++++---- cache/rnd_cache.go | 24 ++++++++----- cmd/thor/utils.go | 12 +++++-- comm/peer.go | 20 +++++++---- p2psrv/rpc/rpc.go | 22 +++++++----- txpool/blocklist.go | 7 ++++ txpool/tx_pool.go | 9 +++-- 8 files changed, 145 insertions(+), 34 deletions(-) create mode 100644 .github/workflows/lint-go.yaml diff --git a/.github/workflows/lint-go.yaml b/.github/workflows/lint-go.yaml new file mode 100644 index 000000000..6ebb8aeaf --- /dev/null +++ b/.github/workflows/lint-go.yaml @@ -0,0 +1,62 @@ +name: Go Lint + +on: + push: + branches: + - master + pull_request: + +permissions: + contents: read + +jobs: + golangci: + name: golangci-lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v4 + with: + go-version: '1.21' + cache: false + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + version: v1.54 + + # Optional: working directory, useful for monorepos + # working-directory: somedir + + # Optional: golangci-lint command line arguments. + # + # Note: By default, the `.golangci.yml` file should be at the root of the repository. + # The location of the configuration file can be changed by using `--config=` + args: --timeout=30m + + # Optional: show only new issues if it's a pull request. The default value is `false`. + only-new-issues: ${{ github.event_name == 'pull_request' }} + + # Optional: if set to true, then all caching functionality will be completely disabled, + # takes precedence over all other caching options. + skip-cache: true + + # Optional: if set to true, then the action won't cache or restore ~/go/pkg. + skip-pkg-cache: true + + # Optional: if set to true, then the action won't cache or restore ~/.cache/go-build. + skip-build-cache: true + + # Optional: The mode to install golangci-lint. It can be 'binary' or 'goinstall'. + # install-mode: "goinstall" + + gosec: + name: gosec-lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Run Gosec Security Scanner + uses: securego/gosec@master + with: + # excluding G104: Audit errors not checked + args: --exclude=G104 ./... diff --git a/builtin/gen/bindata.go b/builtin/gen/bindata.go index 8f1ffbc5d..04c86073c 100644 --- a/builtin/gen/bindata.go +++ b/builtin/gen/bindata.go @@ -44,21 +44,28 @@ import ( "time" ) +const ( + maxDecompressedSize = 1 << 20 // 1MB +) + func bindataRead(data []byte, name string) ([]byte, error) { gz, err := gzip.NewReader(bytes.NewBuffer(data)) if err != nil { return nil, fmt.Errorf("Read %q: %v", name, err) } + // Limit the number of bytes read from the decompressor + limitedReader := io.LimitReader(gz, maxDecompressedSize) + var buf bytes.Buffer - _, err = io.Copy(&buf, gz) + _, err = io.Copy(&buf, limitedReader) clErr := gz.Close() if err != nil { return nil, fmt.Errorf("Read %q: %v", name, err) } if clErr != nil { - return nil, err + return nil, clErr } return buf.Bytes(), nil @@ -794,11 +801,13 @@ var _bindata = map[string]func() (*asset, error){ // directory embedded in the file by go-bindata. // For example if you run go-bindata on data/... and data contains the // following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png +// +// data/ +// foo.txt +// img/ +// a.png +// b.png +// // then AssetDir("data") would return []string{"foo.txt", "img"} // AssetDir("data/img") would return []string{"a.png", "b.png"} // AssetDir("foo.txt") and AssetDir("notexist") would return an error diff --git a/cache/rnd_cache.go b/cache/rnd_cache.go index 661546497..c8aa7aa0d 100644 --- a/cache/rnd_cache.go +++ b/cache/rnd_cache.go @@ -6,15 +6,11 @@ package cache import ( - "math/rand" + "crypto/rand" + "math/big" "sync" - "time" ) -func init() { - rand.Seed(time.Now().UnixNano()) -} - // RandCache a simple cache which randomly evicts entries when // length exceeds limit. type RandCache struct { @@ -106,7 +102,13 @@ func (rc *RandCache) Pick() *Entry { if len(rc.s) == 0 { return nil } - ent := rc.s[rand.Intn(len(rc.s))] + + randomIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(rc.s)))) + if err != nil { + return nil + } + + ent := rc.s[randomIndex.Uint64()] cpy := ent.Entry return &cpy } @@ -141,6 +143,12 @@ func (rc *RandCache) randDrop() { if len(rc.s) == 0 { return } - ent := rc.s[rand.Intn(len(rc.s))] + + randomIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(rc.s)))) + if err != nil { + return + } + + ent := rc.s[randomIndex.Uint64()] rc.remove(ent.Key) } diff --git a/cmd/thor/utils.go b/cmd/thor/utils.go index 9765705c5..728545b94 100644 --- a/cmd/thor/utils.go +++ b/cmd/thor/utils.go @@ -203,6 +203,10 @@ func selectGenesis(ctx *cli.Context) (*genesis.Genesis, thor.ForkConfig, error) gene := genesis.NewMainnet() return gene, thor.GetForkConfig(gene.ID()), nil default: + network = filepath.Clean(network) + if _, err := os.Stat(network); os.IsNotExist(err) { + return nil, thor.ForkConfig{}, errors.New(fmt.Sprintf("the specified genesis file [%v] does not exist", network)) + } file, err := os.Open(network) if err != nil { return nil, thor.ForkConfig{}, errors.Wrap(err, "open genesis file") @@ -444,8 +448,12 @@ func newP2PComm(ctx *cli.Context, repo *chain.Repository, txPool *txpool.TxPool, } peersCachePath := filepath.Join(instanceDir, "peers.cache") + peersCachePath = filepath.Clean(peersCachePath) + if _, err := os.Stat(peersCachePath); os.IsNotExist(err) { + log.Warn("failed to load peers cache", "err", err) + } - if data, err := ioutil.ReadFile(peersCachePath); err != nil { + if data, err := os.ReadFile(peersCachePath); err != nil { if !os.IsNotExist(err) { log.Warn("failed to load peers cache", "err", err) } @@ -518,7 +526,7 @@ func startAPIServer(ctx *cli.Context, handler http.Handler, genesisID thor.Bytes handler = handleXGenesisID(handler, genesisID) handler = handleXThorestVersion(handler) handler = requestBodyLimit(handler) - srv := &http.Server{Handler: handler} + srv := &http.Server{Handler: handler, ReadHeaderTimeout: time.Millisecond * time.Duration(timeout)} var goes co.Goes goes.Go(func() { srv.Serve(listener) diff --git a/comm/peer.go b/comm/peer.go index b5f397a84..4f60c9415 100644 --- a/comm/peer.go +++ b/comm/peer.go @@ -6,7 +6,9 @@ package comm import ( - "math/rand" + "crypto/rand" + "math/big" + mathRand "math/rand" "sync" "time" @@ -24,10 +26,6 @@ const ( maxKnownBlocks = 1024 // Maximum block IDs to keep in the known list (prevent DOS) ) -func init() { - rand.Seed(time.Now().UnixNano()) -} - // Peer extends p2p.Peer with RPC integrated. type Peer struct { *p2p.Peer @@ -84,7 +82,15 @@ func (p *Peer) UpdateHead(id thor.Bytes32, totalScore uint64) { // MarkTransaction marks a transaction to known. func (p *Peer) MarkTransaction(hash thor.Bytes32) { // that's 10~100 block intervals - expiration := mclock.AbsTime(time.Second * time.Duration(thor.BlockInterval*uint64(rand.Intn(91)+10))) + randomValue, err := rand.Int(rand.Reader, big.NewInt(91)) + if err != nil { + log.Warn("failed to generate random value", "err", err) + return + } + + // Add 10 to the random value to get a number in the range [10, 100]. + interval := randomValue.Int64() + 10 + expiration := mclock.AbsTime(time.Second * time.Duration(thor.BlockInterval*uint64(interval))) deadline := mclock.Now() + expiration p.knownTxs.Add(hash, deadline) @@ -183,7 +189,7 @@ func (ps *PeerSet) Slice() Peers { defer ps.lock.Unlock() ret := make(Peers, len(ps.m)) - perm := rand.Perm(len(ps.m)) + perm := mathRand.Perm(len(ps.m)) i := 0 for _, s := range ps.m { // randomly diff --git a/p2psrv/rpc/rpc.go b/p2psrv/rpc/rpc.go index a7d6fdecf..f76dc91d5 100644 --- a/p2psrv/rpc/rpc.go +++ b/p2psrv/rpc/rpc.go @@ -7,7 +7,8 @@ package rpc import ( "context" - "math/rand" + "crypto/rand" + "math/big" "sync" "time" @@ -17,11 +18,6 @@ import ( "github.com/pkg/errors" ) -func init() { - // required when generate call id - rand.Seed(time.Now().UnixNano()) -} - const ( rpcDefaultTimeout = time.Second * 10 ) @@ -154,12 +150,22 @@ func (r *RPC) handleResult(callID uint32, msg *p2p.Msg) error { return nil } +// generateRandomID generates a cryptographically secure random uint32. +func generateRandomID() (uint32, error) { + maxInt := big.NewInt(1<<32 - 1) + randomID, err := rand.Int(rand.Reader, maxInt) + if err != nil { + return 0, err + } + return uint32(randomID.Int64()), nil +} + func (r *RPC) prepareCall(msgCode uint64, onResult func(*p2p.Msg) error) uint32 { r.lock.Lock() defer r.lock.Unlock() for { - id := rand.Uint32() - if id == 0 { + id, err := generateRandomID() + if id == 0 || err != nil { // 0 id is taken by Notify continue } diff --git a/txpool/blocklist.go b/txpool/blocklist.go index b87238410..43bcfb341 100644 --- a/txpool/blocklist.go +++ b/txpool/blocklist.go @@ -8,11 +8,13 @@ package txpool import ( "bufio" "context" + "errors" "fmt" "io" "io/ioutil" "net/http" "os" + "path/filepath" "strings" "sync" @@ -27,6 +29,10 @@ type blocklist struct { // Load load list from local file. func (bl *blocklist) Load(path string) error { + path = filepath.Clean(path) + if _, err := os.Stat(path); os.IsNotExist(err) { + return errors.New(fmt.Sprintf("the path [%v] does not exist", path)) + } file, err := os.Open(path) if err != nil { return err @@ -47,6 +53,7 @@ func (bl *blocklist) Load(path string) error { // Save save list to local file. func (bl *blocklist) Save(path string) error { + path = filepath.Clean(path) file, err := os.Create(path) if err != nil { return err diff --git a/txpool/tx_pool.go b/txpool/tx_pool.go index c8170b571..46f93cec2 100644 --- a/txpool/tx_pool.go +++ b/txpool/tx_pool.go @@ -7,7 +7,8 @@ package txpool import ( "context" - "math/rand" + "crypto/rand" + "encoding/binary" "os" "sync/atomic" "time" @@ -180,8 +181,12 @@ func (p *TxPool) fetchBlocklistLoop() { fetch() for { + + var seconds uint64 + binary.Read(rand.Reader, binary.LittleEndian, &seconds) + // delay 1~2 min - delay := time.Second * time.Duration(rand.Int()%60+60) + delay := time.Second * time.Duration(seconds%60+60) select { case <-p.ctx.Done(): return From 81d66301619b05ef217add3dd7f25f9dd3a77e2d Mon Sep 17 00:00:00 2001 From: Darren Kelly Date: Mon, 8 Jan 2024 16:22:08 +0000 Subject: [PATCH 2/9] fix: ci errors --- txpool/tx_pool.go | 15 +++++++++------ vm/bn256/cloudflare/gfp_decl.go | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/txpool/tx_pool.go b/txpool/tx_pool.go index 46f93cec2..807d5b600 100644 --- a/txpool/tx_pool.go +++ b/txpool/tx_pool.go @@ -8,7 +8,8 @@ package txpool import ( "context" "crypto/rand" - "encoding/binary" + "errors" + "math/big" "os" "sync/atomic" "time" @@ -162,7 +163,7 @@ func (p *TxPool) fetchBlocklistLoop() { var eTag string fetch := func() { if err := p.blocklist.Fetch(p.ctx, url, &eTag); err != nil { - if err == context.Canceled { + if errors.Is(err, context.Canceled) { return } log.Warn("blocklist fetch failed", "error", err, "url", url) @@ -182,11 +183,13 @@ func (p *TxPool) fetchBlocklistLoop() { for { - var seconds uint64 - binary.Read(rand.Reader, binary.LittleEndian, &seconds) - // delay 1~2 min - delay := time.Second * time.Duration(seconds%60+60) + randomNum, err := rand.Int(rand.Reader, new(big.Int).Sub(big.NewInt(60), big.NewInt(121))) + if err != nil { + randomNum = big.NewInt(90) + } + + delay := time.Second * time.Duration(randomNum.Int64()) select { case <-p.ctx.Done(): return diff --git a/vm/bn256/cloudflare/gfp_decl.go b/vm/bn256/cloudflare/gfp_decl.go index fdea5c11a..d35c23c80 100644 --- a/vm/bn256/cloudflare/gfp_decl.go +++ b/vm/bn256/cloudflare/gfp_decl.go @@ -12,7 +12,7 @@ import ( //nolint:varcheck var hasBMI2 = cpu.X86.HasBMI2 -// go:noescape +//go:noescape func gfpNeg(c, a *gfP) //go:noescape From 906f3d8ea54bb89601132872d00b7eb05ef491a4 Mon Sep 17 00:00:00 2001 From: Darren Kelly Date: Mon, 8 Jan 2024 16:25:13 +0000 Subject: [PATCH 3/9] chore: fix linting issue --- txpool/blocklist.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/txpool/blocklist.go b/txpool/blocklist.go index 43bcfb341..adcb4fea2 100644 --- a/txpool/blocklist.go +++ b/txpool/blocklist.go @@ -8,7 +8,6 @@ package txpool import ( "bufio" "context" - "errors" "fmt" "io" "io/ioutil" @@ -31,7 +30,7 @@ type blocklist struct { func (bl *blocklist) Load(path string) error { path = filepath.Clean(path) if _, err := os.Stat(path); os.IsNotExist(err) { - return errors.New(fmt.Sprintf("the path [%v] does not exist", path)) + return fmt.Errorf("the path [%v] does not exist", path) } file, err := os.Open(path) if err != nil { From 5bd237ef73fd95a3c5ee98015c6724fad23c500b Mon Sep 17 00:00:00 2001 From: Darren Kelly Date: Mon, 8 Jan 2024 16:31:55 +0000 Subject: [PATCH 4/9] chore: update gosec actions version --- .github/workflows/lint-go.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-go.yaml b/.github/workflows/lint-go.yaml index 6ebb8aeaf..eb1ed8341 100644 --- a/.github/workflows/lint-go.yaml +++ b/.github/workflows/lint-go.yaml @@ -56,7 +56,7 @@ jobs: - uses: actions/checkout@v3 - name: Run Gosec Security Scanner - uses: securego/gosec@master + uses: securego/gosec@2.18.2 with: # excluding G104: Audit errors not checked args: --exclude=G104 ./... From ecf683276aa452fff43c5aabb55c43bc106d52a2 Mon Sep 17 00:00:00 2001 From: Darren Kelly <107671032+darrenvechain@users.noreply.github.com> Date: Mon, 8 Jan 2024 16:47:30 +0000 Subject: [PATCH 5/9] Create codeql.yml --- .github/workflows/codeql.yml | 55 ++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 000000000..d4c442f1a --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,55 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + analyze: + name: Analyze + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'c-cpp', 'go', 'javascript-typescript' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + + - name: Install Go + uses: actions/setup-go@v4 + with: + go-version: 1.21 + + - name: Make all + run: make all + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" From 165cbae1ac302f63c1d1906ad9949c8aa658a283 Mon Sep 17 00:00:00 2001 From: Darren Kelly Date: Mon, 8 Jan 2024 16:51:06 +0000 Subject: [PATCH 6/9] fix: update actions version --- .github/workflows/lint-go.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-go.yaml b/.github/workflows/lint-go.yaml index eb1ed8341..2edf2f746 100644 --- a/.github/workflows/lint-go.yaml +++ b/.github/workflows/lint-go.yaml @@ -56,7 +56,7 @@ jobs: - uses: actions/checkout@v3 - name: Run Gosec Security Scanner - uses: securego/gosec@2.18.2 + uses: securego/gosec@v2.18.2 with: # excluding G104: Audit errors not checked args: --exclude=G104 ./... From 619e84e150c88060315135899db62d09aa6bf9da Mon Sep 17 00:00:00 2001 From: Darren Kelly Date: Mon, 8 Jan 2024 17:18:46 +0000 Subject: [PATCH 7/9] fix: update codeql --- .github/workflows/codeql.yml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index d4c442f1a..de8980465 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -30,8 +30,8 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'c-cpp', 'go', 'javascript-typescript' ] - + language: [ 'go'] + steps: - name: Checkout repository uses: actions/checkout@v4 @@ -41,11 +41,6 @@ jobs: with: languages: ${{ matrix.language }} - - name: Install Go - uses: actions/setup-go@v4 - with: - go-version: 1.21 - - name: Make all run: make all From c50f9cf94d432fece994e6fac1f6ee0ca9f9b4a1 Mon Sep 17 00:00:00 2001 From: Darren Kelly Date: Mon, 8 Jan 2024 17:32:58 +0000 Subject: [PATCH 8/9] fix: update codeql --- txpool/tx_pool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/txpool/tx_pool.go b/txpool/tx_pool.go index 807d5b600..0251957a1 100644 --- a/txpool/tx_pool.go +++ b/txpool/tx_pool.go @@ -184,7 +184,7 @@ func (p *TxPool) fetchBlocklistLoop() { for { // delay 1~2 min - randomNum, err := rand.Int(rand.Reader, new(big.Int).Sub(big.NewInt(60), big.NewInt(121))) + randomNum, err := rand.Int(rand.Reader, new(big.Int).Sub(big.NewInt(121), big.NewInt(60))) if err != nil { randomNum = big.NewInt(90) } From 60e9deaa8a580f28298a50fb0ba9e5a1e3490a79 Mon Sep 17 00:00:00 2001 From: Darren Kelly Date: Tue, 9 Jan 2024 09:26:49 +0000 Subject: [PATCH 9/9] fix: linting setup@ --- .github/workflows/codeql.yml | 11 ----------- .github/workflows/lint-go.yaml | 12 ------------ .golangci.yml | 19 +++++++++++++++++++ 3 files changed, 19 insertions(+), 23 deletions(-) create mode 100644 .golangci.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index de8980465..1391e832b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,14 +1,3 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# name: "CodeQL" on: diff --git a/.github/workflows/lint-go.yaml b/.github/workflows/lint-go.yaml index 2edf2f746..9fdd4ca04 100644 --- a/.github/workflows/lint-go.yaml +++ b/.github/workflows/lint-go.yaml @@ -48,15 +48,3 @@ jobs: # Optional: The mode to install golangci-lint. It can be 'binary' or 'goinstall'. # install-mode: "goinstall" - - gosec: - name: gosec-lint - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Run Gosec Security Scanner - uses: securego/gosec@v2.18.2 - with: - # excluding G104: Audit errors not checked - args: --exclude=G104 ./... diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 000000000..d0cc50c43 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,19 @@ +# Please refer to the official golangci-lint config documentation for more details: +# https://golangci-lint.run/usage/configuration/ +# https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml + +linters: + enable-all: true + +linters-settings: + gci: + sections: + - standard + - default + +run: + timeout: 10m + tests: false + +issues: + max-issues-per-linter: 1000