diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index e7984e3..88a1741 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -10,7 +10,7 @@ on: jobs: commit: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 # Only check commits on pull requests. if: github.event_name == 'pull_request' steps: @@ -28,16 +28,15 @@ jobs: error: 'Subject too long (max 72)' lint: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: 1.22.x - cache: false # golangci-lint-action does its own caching - uses: golangci/golangci-lint-action@v6 with: - version: v1.56 + version: v1.61 codespell: runs-on: ubuntu-22.04 @@ -50,7 +49,7 @@ jobs: run: codespell cross: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - name: cross @@ -63,10 +62,9 @@ jobs: - uses: actions/setup-go@v5 with: go-version: 1.22.x - cache: false # golangci-lint-action does its own caching - uses: golangci/golangci-lint-action@v6 with: - version: v1.56 + version: v1.61 - name: test-stubs run: make test @@ -74,9 +72,9 @@ jobs: strategy: fail-fast: false matrix: - go-version: [1.21.x, 1.22.x] + go-version: [1.21.x, 1.22.x, 1.23.x] race: ["-race", ""] - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -90,3 +88,78 @@ jobs: - name: test run: make TESTFLAGS="${{ matrix.race }}" test + + - name: test 32-bit + if: ${{ matrix.race }} == "" # -race is not supported on linux/386 + run: make GOARCH=386 test + + test-actuated: + runs-on: actuated-arm64-6cpu-8gb + steps: +# https://gist.github.com/alexellis/1f33e581c75e11e161fe613c46180771#file-metering-gha-md +# vmmeter start + - name: Prepare arkade + uses: alexellis/arkade-get@master + with: + crane: latest + print-summary: false + + - name: Install vmmeter + run: | + crane export --platform linux/arm64 ghcr.io/openfaasltd/vmmeter:latest | sudo tar -xvf - -C /usr/local/bin + + - name: Run vmmeter + uses: self-actuated/vmmeter-action@master +# vmmeter end + + - uses: actions/checkout@v4 + + - name: enable selinux + run: | + sudo apt update + sudo apt install -y policycoreutils selinux-basics selinux-policy-default selinux-utils + sudo selinux-activate + #------------ + sestatus + #------------ + + - name: host info + run: | + set -x + # Sync `set -x` outputs with command ouputs + exec 2>&1 + # Version + uname -a + cat /etc/os-release + # SELinux + sestatus + + - name: install Go + uses: actions/setup-go@v5 + with: + go-version: 1.23.x + + - name: build + run: make build + + - name: test + run: make test + + - name: test -race + run: make TESTFLAGS="-race" test + + - name: test 32-bit + run: make GOARCH=arm test + + all-done: + needs: + - commit + - lint + - codespell + - cross + - test-stubs + - test + - test-actuated + runs-on: ubuntu-22.04 + steps: + - run: echo "All jobs completed" diff --git a/.golangci.yml b/.golangci.yml index a570a2e..9fe4df6 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -6,7 +6,6 @@ linters: enable: - dupword # Detects duplicate words. - errorlint # Detects code that may cause problems with Go 1.13 error wrapping. - - exportloopref # Detects pointers to enclosing loop variables. - gocritic # Metalinter; detects bugs, performance, and styling issues. - gofumpt # Detects whether code was gofumpt-ed. - gosec # Detects security problems. @@ -22,7 +21,6 @@ linters: - unconvert # Detects unnecessary type conversions. linters-settings: govet: - check-shadowing: true enable-all: true settings: shadow: diff --git a/go-selinux/selinux_linux.go b/go-selinux/selinux_linux.go index c80c109..08d837d 100644 --- a/go-selinux/selinux_linux.go +++ b/go-selinux/selinux_linux.go @@ -45,7 +45,7 @@ type selinuxState struct { type level struct { cats *big.Int - sens uint + sens int } type mlsRange struct { @@ -138,7 +138,7 @@ func verifySELinuxfsMount(mnt string) bool { return false } - if uint32(buf.Type) != uint32(unix.SELINUX_MAGIC) { + if uint32(buf.Type) != uint32(unix.SELINUX_MAGIC) { //nolint:gosec return false } if (buf.Flags & unix.ST_RDONLY) != 0 { @@ -501,14 +501,14 @@ func catsToBitset(cats string) (*big.Int, error) { return nil, err } for i := catstart; i <= catend; i++ { - bitset.SetBit(bitset, int(i), 1) + bitset.SetBit(bitset, i, 1) } } else { cat, err := parseLevelItem(ranges[0], category) if err != nil { return nil, err } - bitset.SetBit(bitset, int(cat), 1) + bitset.SetBit(bitset, cat, 1) } } @@ -516,16 +516,17 @@ func catsToBitset(cats string) (*big.Int, error) { } // parseLevelItem parses and verifies that a sensitivity or category are valid -func parseLevelItem(s string, sep levelItem) (uint, error) { +func parseLevelItem(s string, sep levelItem) (int, error) { if len(s) < minSensLen || levelItem(s[0]) != sep { return 0, ErrLevelSyntax } - val, err := strconv.ParseUint(s[1:], 10, 32) + const bitSize = 31 // Make sure the result fits into signed int32. + val, err := strconv.ParseUint(s[1:], 10, bitSize) if err != nil { return 0, err } - return uint(val), nil + return int(val), nil //nolint:gosec } // parseLevel fills a level from a string that contains @@ -582,7 +583,8 @@ func bitsetToStr(c *big.Int) string { var str string length := 0 - for i := int(c.TrailingZeroBits()); i < c.BitLen(); i++ { + i0 := int(c.TrailingZeroBits()) //nolint:gosec + for i := i0; i < c.BitLen(); i++ { if c.Bit(i) == 0 { continue } @@ -622,7 +624,7 @@ func (l *level) equal(l2 *level) bool { // String returns an mlsRange as a string. func (m mlsRange) String() string { - low := "s" + strconv.Itoa(int(m.low.sens)) + low := "s" + strconv.Itoa(m.low.sens) if m.low.cats != nil && m.low.cats.BitLen() > 0 { low += ":" + bitsetToStr(m.low.cats) } @@ -631,7 +633,7 @@ func (m mlsRange) String() string { return low } - high := "s" + strconv.Itoa(int(m.high.sens)) + high := "s" + strconv.Itoa(m.high.sens) if m.high.cats != nil && m.high.cats.BitLen() > 0 { high += ":" + bitsetToStr(m.high.cats) } @@ -639,21 +641,6 @@ func (m mlsRange) String() string { return low + "-" + high } -// TODO: remove min and max once Go < 1.21 is not supported. -func max(a, b uint) uint { - if a > b { - return a - } - return b -} - -func min(a, b uint) uint { - if a < b { - return a - } - return b -} - // calculateGlbLub computes the glb (greatest lower bound) and lub (least upper bound) // of a source and target range. // The glblub is calculated as the greater of the low sensitivities and diff --git a/go.mod b/go.mod index 56328f1..404b3d1 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,5 @@ module github.com/opencontainers/selinux -go 1.19 +go 1.21 require golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 diff --git a/pkg/pwalk/pwalk_test.go b/pkg/pwalk/pwalk_test.go index 66f6def..21adce4 100644 --- a/pkg/pwalk/pwalk_test.go +++ b/pkg/pwalk/pwalk_test.go @@ -12,21 +12,22 @@ import ( ) func TestWalk(t *testing.T) { - var count uint32 + var ac atomic.Uint32 concurrency := runtime.NumCPU() * 2 dir, total := prepareTestSet(t, 3, 2, 1) err := WalkN(dir, func(_ string, _ os.FileInfo, _ error) error { - atomic.AddUint32(&count, 1) + ac.Add(1) return nil }, concurrency) if err != nil { t.Errorf("Walk failed: %v", err) } - if count != uint32(total) { + count := ac.Load() + if count != total { t.Errorf("File count mismatch: found %d, expected %d", count, total) } @@ -41,7 +42,7 @@ func TestWalkTopLevelErrNotExistNotIgnored(t *testing.T) { // https://github.com/opencontainers/selinux/issues/199 func TestWalkRaceWithRemoval(t *testing.T) { - var count uint32 + var ac atomic.Uint32 concurrency := runtime.NumCPU() * 2 // This test is still on a best-effort basis, meaning it can still pass // when there is a bug in the code, but the larger the test set is, the @@ -55,10 +56,11 @@ func TestWalkRaceWithRemoval(t *testing.T) { go os.RemoveAll(dir) err := WalkN(dir, func(_ string, _ os.FileInfo, _ error) error { - atomic.AddUint32(&count, 1) + ac.Add(1) return nil }, concurrency) + count := int(ac.Load()) t.Logf("found %d of %d files", count, total) if err != nil { t.Fatalf("expected nil, got %v", err) @@ -66,30 +68,31 @@ func TestWalkRaceWithRemoval(t *testing.T) { } func TestWalkDirManyErrors(t *testing.T) { - var count uint32 + var ac atomic.Uint32 dir, total := prepareTestSet(t, 3, 3, 2) - max := uint32(total / 2) + maxFiles := total / 2 e42 := errors.New("42") err := Walk(dir, func(_ string, _ os.FileInfo, _ error) error { - if atomic.AddUint32(&count, 1) > max { + if ac.Add(1) > maxFiles { return e42 } return nil }) + count := ac.Load() t.Logf("found %d of %d files", count, total) if err == nil { t.Errorf("Walk succeeded, but error is expected") - if count != uint32(total) { + if count != total { t.Errorf("File count mismatch: found %d, expected %d", count, total) } } } -func makeManyDirs(prefix string, levels, dirs, files int) (count int, err error) { +func makeManyDirs(prefix string, levels, dirs, files int) (count uint32, err error) { for d := 0; d < dirs; d++ { var dir string dir, err = os.MkdirTemp(prefix, "d-") @@ -109,7 +112,7 @@ func makeManyDirs(prefix string, levels, dirs, files int) (count int, err error) if levels == 0 { continue } - var c int + var c uint32 if c, err = makeManyDirs(dir, levels-1, dirs, files); err != nil { return } @@ -124,7 +127,7 @@ func makeManyDirs(prefix string, levels, dirs, files int) (count int, err error) // // Total dirs: dirs^levels + dirs^(levels-1) + ... + dirs^1 // Total files: total_dirs * files -func prepareTestSet(tb testing.TB, levels, dirs, files int) (dir string, total int) { +func prepareTestSet(tb testing.TB, levels, dirs, files int) (dir string, total uint32) { tb.Helper() var err error diff --git a/pkg/pwalkdir/pwalkdir_test.go b/pkg/pwalkdir/pwalkdir_test.go index 35e7655..7c0aa0f 100644 --- a/pkg/pwalkdir/pwalkdir_test.go +++ b/pkg/pwalkdir/pwalkdir_test.go @@ -16,20 +16,21 @@ import ( ) func TestWalkDir(t *testing.T) { - var count uint32 + var ac atomic.Uint32 concurrency := runtime.NumCPU() * 2 dir, total := prepareTestSet(t, 3, 2, 1) err := WalkN(dir, func(_ string, _ fs.DirEntry, _ error) error { - atomic.AddUint32(&count, 1) + ac.Add(1) return nil }, concurrency) if err != nil { t.Errorf("Walk failed: %v", err) } - if count != uint32(total) { + count := ac.Load() + if count != total { t.Errorf("File count mismatch: found %d, expected %d", count, total) } @@ -45,7 +46,7 @@ func TestWalkDirTopLevelErrNotExistNotIgnored(t *testing.T) { // https://github.com/opencontainers/selinux/issues/199 func TestWalkDirRaceWithRemoval(t *testing.T) { - var count uint32 + var ac atomic.Uint32 concurrency := runtime.NumCPU() * 2 // This test is still on a best-effort basis, meaning it can still pass // when there is a bug in the code, but the larger the test set is, the @@ -59,10 +60,11 @@ func TestWalkDirRaceWithRemoval(t *testing.T) { go os.RemoveAll(dir) err := WalkN(dir, func(_ string, _ fs.DirEntry, _ error) error { - atomic.AddUint32(&count, 1) + ac.Add(1) return nil }, concurrency) + count := ac.Load() t.Logf("found %d of %d files", count, total) if err != nil { t.Fatalf("expected nil, got %v", err) @@ -70,29 +72,30 @@ func TestWalkDirRaceWithRemoval(t *testing.T) { } func TestWalkDirManyErrors(t *testing.T) { - var count uint32 + var ac atomic.Uint32 dir, total := prepareTestSet(t, 3, 3, 2) - max := uint32(total / 2) + maxFiles := total / 2 e42 := errors.New("42") err := Walk(dir, func(_ string, _ fs.DirEntry, _ error) error { - if atomic.AddUint32(&count, 1) > max { + if ac.Add(1) > maxFiles { return e42 } return nil }) + count := ac.Load() t.Logf("found %d of %d files", count, total) if err == nil { t.Error("Walk succeeded, but error is expected") - if count != uint32(total) { + if count != total { t.Errorf("File count mismatch: found %d, expected %d", count, total) } } } -func makeManyDirs(prefix string, levels, dirs, files int) (count int, err error) { +func makeManyDirs(prefix string, levels, dirs, files int) (count uint32, err error) { for d := 0; d < dirs; d++ { var dir string dir, err = os.MkdirTemp(prefix, "d-") @@ -112,7 +115,7 @@ func makeManyDirs(prefix string, levels, dirs, files int) (count int, err error) if levels == 0 { continue } - var c int + var c uint32 if c, err = makeManyDirs(dir, levels-1, dirs, files); err != nil { return } @@ -127,7 +130,7 @@ func makeManyDirs(prefix string, levels, dirs, files int) (count int, err error) // // Total dirs: dirs^levels + dirs^(levels-1) + ... + dirs^1 // Total files: total_dirs * files -func prepareTestSet(tb testing.TB, levels, dirs, files int) (dir string, total int) { +func prepareTestSet(tb testing.TB, levels, dirs, files int) (dir string, total uint32) { tb.Helper() var err error