Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add worldwrite linter #698

Merged
merged 2 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading