Skip to content

Commit

Permalink
Merge pull request #698 from Elizafox/binarylinter
Browse files Browse the repository at this point in the history
Add worldwrite linter
  • Loading branch information
imjasonh authored Sep 19, 2023
2 parents bbe0bc0 + d7d260b commit 1f35cc6
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 14 deletions.
38 changes: 31 additions & 7 deletions pkg/build/linter.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@ type linter struct {
}

var linterMap = map[string]linter{
"dev": linter{devLinter, "If this package is creating /dev nodes, it should use udev instead; otherwise, remove any files in /dev"},
"opt": linter{optLinter, "This package should be a -compat package"},
"setuidgid": linter{isSetUidOrGidLinter, "Unset the setuid/setgid bit on the relevant files, or remove this linter"},
"srv": linter{srvLinter, "This package should be a -compat package"},
"tempdir": linter{tempDirLinter, "Remove any offending files in temporary dirs in the pipeline"},
"usrlocal": linter{usrLocalLinter, "This package should be a -compat package"},
"varempty": linter{varEmptyLinter, "Remove any offending files in /var/empty in the pipeline"},
"dev": linter{devLinter, "If this package is creating /dev nodes, it should use udev instead; otherwise, remove any files in /dev"},
"opt": linter{optLinter, "This package should be a -compat package"},
"setuidgid": linter{isSetUidOrGidLinter, "Unset the setuid/setgid bit on the relevant files, or remove this linter"},
"srv": linter{srvLinter, "This package should be a -compat package"},
"tempdir": linter{tempDirLinter, "Remove any offending files in temporary dirs in the pipeline"},
"usrlocal": linter{usrLocalLinter, "This package should be a -compat package"},
"varempty": linter{varEmptyLinter, "Remove any offending files in /var/empty in the pipeline"},
"worldwrite": linter{worldWriteableLinter, "Change the permissions of any world-writeable files in the package, disable the linter, or make this a -compat package"},
}

var isDevRegex = regexp.MustCompile("^dev/")
Expand Down Expand Up @@ -117,6 +118,29 @@ func varEmptyLinter(_ LinterContext, path string, _ fs.DirEntry) error {
return nil
}

func worldWriteableLinter(_ LinterContext, path string, d fs.DirEntry) error {
if !d.Type().IsRegular() {
// Don't worry about non-files
return nil
}

info, err := d.Info()
if err != nil {
return err
}

mode := info.Mode()
if mode&0002 != 0 {
if mode&0111 != 0 {
return fmt.Errorf("World-writeable executable file found in package (security risk)")
} else {
return fmt.Errorf("World-writeable file found in package")
}
}

return nil
}

func lintPackageFs(lctx LinterContext, fsys fs.FS, linters []string) error {
// If this is a compat package, do nothing.
if isCompatPackage.MatchString(lctx.pkgname) {
Expand Down
69 changes: 62 additions & 7 deletions pkg/build/linter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func Test_usrLocalLinter(t *testing.T) {
Epoch: 0,
Checks: config.Checks{
Enabled: []string{"usrlocal"},
Disabled: []string{"dev", "opt", "setuidgid", "srv", "tempdir", "varempty"},
Disabled: []string{"dev", "opt", "setuidgid", "srv", "tempdir", "varempty", "worldwrite"},
},
},
}
Expand Down Expand Up @@ -66,7 +66,7 @@ func Test_varEmptyLinter(t *testing.T) {
Epoch: 0,
Checks: config.Checks{
Enabled: []string{"varempty"},
Disabled: []string{"dev", "opt", "setuidgid", "srv", "tempdir", "usrlocal"},
Disabled: []string{"dev", "opt", "setuidgid", "srv", "tempdir", "usrlocal", "worldwrite"},
},
},
}
Expand Down Expand Up @@ -96,7 +96,7 @@ func Test_devLinter(t *testing.T) {
Epoch: 0,
Checks: config.Checks{
Enabled: []string{"dev"},
Disabled: []string{"opt", "setuidgid", "srv", "tempdir", "usrlocal", "varempty"},
Disabled: []string{"opt", "setuidgid", "srv", "tempdir", "usrlocal", "varempty", "worldwrite"},
},
},
}
Expand Down Expand Up @@ -126,7 +126,7 @@ func Test_optLinter(t *testing.T) {
Epoch: 0,
Checks: config.Checks{
Enabled: []string{"opt"},
Disabled: []string{"dev", "setuidgid", "srv", "tempdir", "usrlocal", "varempty"},
Disabled: []string{"dev", "setuidgid", "srv", "tempdir", "usrlocal", "varempty", "worldwrite"},
},
},
}
Expand Down Expand Up @@ -156,7 +156,7 @@ func Test_srvLinter(t *testing.T) {
Epoch: 0,
Checks: config.Checks{
Enabled: []string{"srv"},
Disabled: []string{"dev", "opt", "setuidgid", "tempdir", "usrlocal", "varempty"},
Disabled: []string{"dev", "opt", "setuidgid", "tempdir", "usrlocal", "varempty", "worldwrite"},
},
},
}
Expand Down Expand Up @@ -186,7 +186,7 @@ func Test_tempDirLinter(t *testing.T) {
Epoch: 0,
Checks: config.Checks{
Enabled: []string{"tempdir"},
Disabled: []string{"dev", "opt", "setuidgid", "srv", "usrlocal", "varempty"},
Disabled: []string{"dev", "opt", "setuidgid", "srv", "usrlocal", "varempty", "worldwrite"},
},
},
}
Expand Down Expand Up @@ -247,7 +247,7 @@ func Test_setUidGidLinter(t *testing.T) {
Epoch: 0,
Checks: config.Checks{
Enabled: []string{"setuidgid"},
Disabled: []string{"dev", "opt", "srv", "tempdir", "usrlocal", "varempty"},
Disabled: []string{"dev", "opt", "srv", "tempdir", "usrlocal", "varempty", "worldwrite"},
},
},
}
Expand All @@ -271,6 +271,61 @@ func Test_setUidGidLinter(t *testing.T) {
assert.Error(t, lintPackageFs(lctx, fsys, linters))
}

func Test_worldWriteLinter(t *testing.T) {
dir, err := os.MkdirTemp("", "melange.XXXXX")
defer os.RemoveAll(dir)
assert.NoError(t, err)

cfg := config.Configuration{
Package: config.Package{
Name: "test",
Version: "4.2.0",
Epoch: 0,
Checks: config.Checks{
Enabled: []string{"worldwrite"},
Disabled: []string{"dev", "opt", "srv", "setuidgid", "tempdir", "usrlocal", "varempty"},
},
},
}

usrLocalDirPath := filepath.Join(dir, "usr", "lib")
err = os.MkdirAll(usrLocalDirPath, 0777)
assert.NoError(t, err)

// Ensure 777 dirs don't trigger it
linters := cfg.Package.Checks.GetLinters()
assert.Equal(t, linters, []string{"worldwrite"})
fsys := os.DirFS(dir)
lctx := LinterContext{cfg.Package.Name, &cfg, &cfg.Package.Checks}
assert.NoError(t, lintPackageFs(lctx, fsys, linters))

// Create test file
filePath := filepath.Join(usrLocalDirPath, "test.txt")
_, err = os.Create(filepath.Join(filePath))
assert.NoError(t, err)

// Set writeable and executable bits for non-world
err = os.Chmod(filePath, 0770)
assert.NoError(t, err)

// Linter should not trigger
assert.NoError(t, lintPackageFs(lctx, fsys, linters))

// Set writeable bit (but not executable bit)
err = os.Chmod(filePath, 0776)
assert.NoError(t, err)

// Linter should trigger
assert.Error(t, lintPackageFs(lctx, fsys, linters))

// Set writeable and executable bit
err = os.Chmod(filePath, 0777)
assert.NoError(t, err)

// Linter should trigger
assert.Error(t, lintPackageFs(lctx, fsys, linters))
}

func Test_disableDefaultLinter(t *testing.T) {
dir, err := os.MkdirTemp("", "melange.XXXXX")
defer os.RemoveAll(dir)
Expand Down
1 change: 1 addition & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ var defaultLinters = []string{
"tempdir",
"usrlocal",
"varempty",
"worldwrite",
}

type VarTransforms struct {
Expand Down

0 comments on commit 1f35cc6

Please sign in to comment.