diff -Nru golang-github-opencontainers-selinux-1.6.0/debian/changelog golang-github-opencontainers-selinux-1.8.0/debian/changelog --- golang-github-opencontainers-selinux-1.6.0/debian/changelog 2020-08-17 15:10:54.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/debian/changelog 2021-01-06 15:11:06.000000000 +0000 @@ -1,3 +1,13 @@ +golang-github-opencontainers-selinux (1.8.0-1) unstable; urgency=medium + + * Team upload + * New upstream version 1.8.0 + * Drop build tag selinux + * Set section to golang + * Update gitlab-ci.yml + + -- Arnaud Rebillout Wed, 06 Jan 2021 22:11:06 +0700 + golang-github-opencontainers-selinux (1.6.0-1) unstable; urgency=medium * Team upload. diff -Nru golang-github-opencontainers-selinux-1.6.0/debian/control golang-github-opencontainers-selinux-1.8.0/debian/control --- golang-github-opencontainers-selinux-1.6.0/debian/control 2020-08-17 15:10:54.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/debian/control 2021-01-06 15:11:06.000000000 +0000 @@ -1,5 +1,5 @@ Source: golang-github-opencontainers-selinux -Section: devel +Section: golang Maintainer: Debian Go Packaging Team Priority: optional Standards-Version: 4.5.0 diff -Nru golang-github-opencontainers-selinux-1.6.0/debian/gitlab-ci.yml golang-github-opencontainers-selinux-1.8.0/debian/gitlab-ci.yml --- golang-github-opencontainers-selinux-1.6.0/debian/gitlab-ci.yml 2020-08-17 15:10:54.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/debian/gitlab-ci.yml 2021-01-06 15:11:06.000000000 +0000 @@ -1,9 +1,7 @@ - # auto-generated, DO NOT MODIFY. # The authoritative copy of this file lives at: -# https://salsa.debian.org/go-team/ci/blob/master/cmd/ci/gitlabciyml.go +# https://salsa.debian.org/go-team/ci/blob/master/config/gitlabciyml.go -# TODO: publish under debian-go-team/ci image: stapelberg/ci2 test_the_archive: diff -Nru golang-github-opencontainers-selinux-1.6.0/debian/rules golang-github-opencontainers-selinux-1.8.0/debian/rules --- golang-github-opencontainers-selinux-1.6.0/debian/rules 2020-08-17 15:10:54.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/debian/rules 2021-01-06 15:11:06.000000000 +0000 @@ -2,6 +2,3 @@ %: dh $@ --buildsystem=golang --with=golang - -override_dh_auto_build: - dh_auto_build -- -tags selinux diff -Nru golang-github-opencontainers-selinux-1.6.0/.golangci.yml golang-github-opencontainers-selinux-1.8.0/.golangci.yml --- golang-github-opencontainers-selinux-1.6.0/.golangci.yml 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/.golangci.yml 2020-12-15 10:24:31.000000000 +0000 @@ -1,22 +1,8 @@ --- run: - build-tags: - - selinux concurrency: 6 deadline: 5m linters: - enable-all: true - disable: - - errcheck - - funlen - - gochecknoglobals - - gocognit - - gocritic - - golint - - gomnd - - ineffassign - - lll - - staticcheck - - stylecheck + enable: - whitespace - - wsl + - gocritic diff -Nru golang-github-opencontainers-selinux-1.6.0/go.mod golang-github-opencontainers-selinux-1.8.0/go.mod --- golang-github-opencontainers-selinux-1.6.0/go.mod 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/go.mod 2020-12-15 10:24:31.000000000 +0000 @@ -4,6 +4,6 @@ require ( github.com/pkg/errors v0.9.1 - github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243 + github.com/willf/bitset v1.1.11 golang.org/x/sys v0.0.0-20191115151921-52ab43148777 ) diff -Nru golang-github-opencontainers-selinux-1.6.0/go-selinux/doc.go golang-github-opencontainers-selinux-1.8.0/go-selinux/doc.go --- golang-github-opencontainers-selinux-1.6.0/go-selinux/doc.go 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/go-selinux/doc.go 2020-12-15 10:24:31.000000000 +0000 @@ -5,9 +5,6 @@ allows non-linux and linux users who do not have selinux support to still use tools that rely on this library. -To compile with full selinux support use the -tags=selinux option in your build -and test commands. - Usage: import "github.com/opencontainers/selinux/go-selinux" diff -Nru golang-github-opencontainers-selinux-1.6.0/go-selinux/label/label_linux.go golang-github-opencontainers-selinux-1.8.0/go-selinux/label/label_linux.go --- golang-github-opencontainers-selinux-1.6.0/go-selinux/label/label_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/go-selinux/label/label_linux.go 2020-12-15 10:24:31.000000000 +0000 @@ -0,0 +1,190 @@ +package label + +import ( + "os" + "os/user" + "strings" + + "github.com/opencontainers/selinux/go-selinux" + "github.com/pkg/errors" +) + +// Valid Label Options +var validOptions = map[string]bool{ + "disable": true, + "type": true, + "filetype": true, + "user": true, + "role": true, + "level": true, +} + +var ErrIncompatibleLabel = errors.New("Bad SELinux option z and Z can not be used together") + +// InitLabels returns the process label and file labels to be used within +// the container. A list of options can be passed into this function to alter +// the labels. The labels returned will include a random MCS String, that is +// guaranteed to be unique. +func InitLabels(options []string) (plabel string, mlabel string, retErr error) { + if !selinux.GetEnabled() { + return "", "", nil + } + processLabel, mountLabel := selinux.ContainerLabels() + if processLabel != "" { + defer func() { + if retErr != nil { + selinux.ReleaseLabel(mountLabel) + } + }() + pcon, err := selinux.NewContext(processLabel) + if err != nil { + return "", "", err + } + mcsLevel := pcon["level"] + mcon, err := selinux.NewContext(mountLabel) + if err != nil { + return "", "", err + } + for _, opt := range options { + if opt == "disable" { + return "", mountLabel, nil + } + if i := strings.Index(opt, ":"); i == -1 { + return "", "", errors.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type, filetype' followed by ':' and a value", opt) + } + con := strings.SplitN(opt, ":", 2) + if !validOptions[con[0]] { + return "", "", errors.Errorf("Bad label option %q, valid options 'disable, user, role, level, type, filetype'", con[0]) + } + if con[0] == "filetype" { + mcon["type"] = con[1] + continue + } + pcon[con[0]] = con[1] + if con[0] == "level" || con[0] == "user" { + mcon[con[0]] = con[1] + } + } + if pcon.Get() != processLabel { + if pcon["level"] != mcsLevel { + selinux.ReleaseLabel(processLabel) + } + processLabel = pcon.Get() + selinux.ReserveLabel(processLabel) + } + mountLabel = mcon.Get() + } + return processLabel, mountLabel, nil +} + +// Deprecated: The GenLabels function is only to be used during the transition +// to the official API. Use InitLabels(strings.Fields(options)) instead. +func GenLabels(options string) (string, string, error) { + return InitLabels(strings.Fields(options)) +} + +// SetFileLabel modifies the "path" label to the specified file label +func SetFileLabel(path string, fileLabel string) error { + if !selinux.GetEnabled() || fileLabel == "" { + return nil + } + return selinux.SetFileLabel(path, fileLabel) +} + +// SetFileCreateLabel tells the kernel the label for all files to be created +func SetFileCreateLabel(fileLabel string) error { + if !selinux.GetEnabled() { + return nil + } + return selinux.SetFSCreateLabel(fileLabel) +} + +// Relabel changes the label of path to the filelabel string. +// It changes the MCS label to s0 if shared is true. +// This will allow all containers to share the content. +func Relabel(path string, fileLabel string, shared bool) error { + if !selinux.GetEnabled() || fileLabel == "" { + return nil + } + + exclude_paths := map[string]bool{ + "/": true, + "/bin": true, + "/boot": true, + "/dev": true, + "/etc": true, + "/etc/passwd": true, + "/etc/pki": true, + "/etc/shadow": true, + "/home": true, + "/lib": true, + "/lib64": true, + "/media": true, + "/opt": true, + "/proc": true, + "/root": true, + "/run": true, + "/sbin": true, + "/srv": true, + "/sys": true, + "/tmp": true, + "/usr": true, + "/var": true, + "/var/lib": true, + "/var/log": true, + } + + if home := os.Getenv("HOME"); home != "" { + exclude_paths[home] = true + } + + if sudoUser := os.Getenv("SUDO_USER"); sudoUser != "" { + if usr, err := user.Lookup(sudoUser); err == nil { + exclude_paths[usr.HomeDir] = true + } + } + + if path != "/" { + path = strings.TrimSuffix(path, "/") + } + if exclude_paths[path] { + return errors.Errorf("SELinux relabeling of %s is not allowed", path) + } + + if shared { + c, err := selinux.NewContext(fileLabel) + if err != nil { + return err + } + + c["level"] = "s0" + fileLabel = c.Get() + } + if err := selinux.Chcon(path, fileLabel, true); err != nil { + return err + } + return nil +} + +// DisableSecOpt returns a security opt that can disable labeling +// support for future container processes +// Deprecated: use selinux.DisableSecOpt +var DisableSecOpt = selinux.DisableSecOpt + +// Validate checks that the label does not include unexpected options +func Validate(label string) error { + if strings.Contains(label, "z") && strings.Contains(label, "Z") { + return ErrIncompatibleLabel + } + return nil +} + +// RelabelNeeded checks whether the user requested a relabel +func RelabelNeeded(label string) bool { + return strings.Contains(label, "z") || strings.Contains(label, "Z") +} + +// IsShared checks that the label includes a "shared" mark +func IsShared(label string) bool { + return strings.Contains(label, "z") +} diff -Nru golang-github-opencontainers-selinux-1.6.0/go-selinux/label/label_linux_test.go golang-github-opencontainers-selinux-1.8.0/go-selinux/label/label_linux_test.go --- golang-github-opencontainers-selinux-1.6.0/go-selinux/label/label_linux_test.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/go-selinux/label/label_linux_test.go 2020-12-15 10:24:31.000000000 +0000 @@ -0,0 +1,230 @@ +package label + +import ( + "io/ioutil" + "os" + "strings" + "testing" + + "github.com/opencontainers/selinux/go-selinux" +) + +func TestInit(t *testing.T) { + if !selinux.GetEnabled() { + return + } + var testNull []string + _, _, err := InitLabels(testNull) + if err != nil { + t.Log("InitLabels Failed") + t.Fatal(err) + } + testDisabled := []string{"disable"} + roMountLabel := ROMountLabel() + if roMountLabel == "" { + t.Errorf("ROMountLabel Failed") + } + plabel, _, err := InitLabels(testDisabled) + if err != nil { + t.Log("InitLabels Disabled Failed") + t.Fatal(err) + } + if plabel != "" { + t.Log("InitLabels Disabled Failed") + t.FailNow() + } + testUser := []string{"user:user_u", "role:user_r", "type:user_t", "level:s0:c1,c15"} + plabel, mlabel, err := InitLabels(testUser) + if err != nil { + t.Log("InitLabels User Failed") + t.Fatal(err) + } + if plabel != "user_u:user_r:user_t:s0:c1,c15" || (mlabel != "user_u:object_r:container_file_t:s0:c1,c15" && mlabel != "user_u:object_r:svirt_sandbox_file_t:s0:c1,c15") { + t.Logf("InitLabels User Match Failed %s, %s", plabel, mlabel) + t.Log(plabel, mlabel) + t.Fatal(err) + } + + testBadData := []string{"user", "role:user_r", "type:user_t", "level:s0:c1,c15"} + if _, _, err = InitLabels(testBadData); err == nil { + t.Log("InitLabels Bad Failed") + t.Fatal(err) + } +} + +func TestDuplicateLabel(t *testing.T) { + secopt, err := DupSecOpt("system_u:system_r:container_t:s0:c1,c2") + if err != nil { + t.Fatal(err) + } + for _, opt := range secopt { + con := strings.SplitN(opt, ":", 2) + if con[0] == "user" { + if con[1] != "system_u" { + t.Errorf("DupSecOpt Failed user incorrect") + } + continue + } + if con[0] == "role" { + if con[1] != "system_r" { + t.Errorf("DupSecOpt Failed role incorrect") + } + continue + } + if con[0] == "type" { + if con[1] != "container_t" { + t.Errorf("DupSecOpt Failed type incorrect") + } + continue + } + if con[0] == "level" { + if con[1] != "s0:c1,c2" { + t.Errorf("DupSecOpt Failed level incorrect") + } + continue + } + t.Errorf("DupSecOpt Failed invalid field %q", con[0]) + } + secopt = DisableSecOpt() + if secopt[0] != "disable" { + t.Errorf("DisableSecOpt Failed level incorrect %q", secopt[0]) + } +} +func TestRelabel(t *testing.T) { + if !selinux.GetEnabled() { + return + } + testdir, err := ioutil.TempDir("/tmp", "") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(testdir) + label := "system_u:object_r:container_file_t:s0:c1,c2" + if err := Relabel(testdir, "", true); err != nil { + t.Fatalf("Relabel with no label failed: %v", err) + } + if err := Relabel(testdir, label, true); err != nil { + t.Fatalf("Relabel shared failed: %v", err) + } + if err := Relabel(testdir, label, false); err != nil { + t.Fatalf("Relabel unshared failed: %v", err) + } + if err := Relabel("/etc", label, false); err == nil { + t.Fatalf("Relabel /etc succeeded") + } + if err := Relabel("/", label, false); err == nil { + t.Fatalf("Relabel / succeeded") + } + if err := Relabel("/usr", label, false); err == nil { + t.Fatalf("Relabel /usr succeeded") + } + if err := Relabel("/usr/", label, false); err == nil { + t.Fatalf("Relabel /usr/ succeeded") + } + if err := Relabel("/etc/passwd", label, false); err == nil { + t.Fatalf("Relabel /etc/passwd succeeded") + } + if home := os.Getenv("HOME"); home != "" { + if err := Relabel(home, label, false); err == nil { + t.Fatalf("Relabel %s succeeded", home) + } + } +} +func TestValidate(t *testing.T) { + if err := Validate("zZ"); err != ErrIncompatibleLabel { + t.Fatalf("Expected incompatible error, got %v", err) + } + if err := Validate("Z"); err != nil { + t.Fatal(err) + } + if err := Validate("z"); err != nil { + t.Fatal(err) + } + if err := Validate(""); err != nil { + t.Fatal(err) + } +} + +func TestIsShared(t *testing.T) { + if shared := IsShared("Z"); shared { + t.Fatalf("Expected label `Z` to not be shared, got %v", shared) + } + if shared := IsShared("z"); !shared { + t.Fatalf("Expected label `z` to be shared, got %v", shared) + } + if shared := IsShared("Zz"); !shared { + t.Fatalf("Expected label `Zz` to be shared, got %v", shared) + } +} + +func TestSELinuxNoLevel(t *testing.T) { + if !selinux.GetEnabled() { + return + } + tlabel := "system_u:system_r:container_t" + dup, err := DupSecOpt(tlabel) + if err != nil { + t.Fatal(err) + } + + if len(dup) != 3 { + t.Errorf("DupSecOpt Failed on non mls label") + } + con, err := selinux.NewContext(tlabel) + if err != nil { + t.Fatal(err) + } + if con.Get() != tlabel { + t.Errorf("NewContaxt and con.Get() Failed on non mls label") + } +} + +func TestSocketLabel(t *testing.T) { + if !selinux.GetEnabled() { + return + } + label := "system_u:object_r:container_t:s0:c1,c2" + if err := selinux.SetSocketLabel(label); err != nil { + t.Fatal(err) + } + nlabel, err := selinux.SocketLabel() + if err != nil { + t.Fatal(err) + } + if label != nlabel { + t.Errorf("SocketLabel %s != %s", nlabel, label) + } +} + +func TestKeyLabel(t *testing.T) { + if !selinux.GetEnabled() { + return + } + label := "system_u:object_r:container_t:s0:c1,c2" + if err := selinux.SetKeyLabel(label); err != nil { + t.Fatal(err) + } + nlabel, err := selinux.KeyLabel() + if err != nil { + t.Fatal(err) + } + if label != nlabel { + t.Errorf("KeyLabel %s != %s", nlabel, label) + } +} + +func TestFileLabel(t *testing.T) { + if !selinux.GetEnabled() { + return + } + testUser := []string{"filetype:test_file_t", "level:s0:c1,c15"} + _, mlabel, err := InitLabels(testUser) + if err != nil { + t.Log("InitLabels User Failed") + t.Fatal(err) + } + if mlabel != "system_u:object_r:test_file_t:s0:c1,c15" { + t.Log("InitLabels filetype Failed") + t.Fatal(err) + } +} diff -Nru golang-github-opencontainers-selinux-1.6.0/go-selinux/label/label_selinux.go golang-github-opencontainers-selinux-1.8.0/go-selinux/label/label_selinux.go --- golang-github-opencontainers-selinux-1.6.0/go-selinux/label/label_selinux.go 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/go-selinux/label/label_selinux.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,193 +0,0 @@ -// +build selinux,linux - -package label - -import ( - "os" - "os/user" - "strings" - - "github.com/opencontainers/selinux/go-selinux" - "github.com/pkg/errors" -) - -// Valid Label Options -var validOptions = map[string]bool{ - "disable": true, - "type": true, - "filetype": true, - "user": true, - "role": true, - "level": true, -} - -var ErrIncompatibleLabel = errors.New("Bad SELinux option z and Z can not be used together") - -// InitLabels returns the process label and file labels to be used within -// the container. A list of options can be passed into this function to alter -// the labels. The labels returned will include a random MCS String, that is -// guaranteed to be unique. -func InitLabels(options []string) (plabel string, mlabel string, Err error) { - if !selinux.GetEnabled() { - return "", "", nil - } - processLabel, mountLabel := selinux.ContainerLabels() - if processLabel != "" { - defer func() { - if Err != nil { - selinux.ReleaseLabel(mountLabel) - } - }() - pcon, err := selinux.NewContext(processLabel) - if err != nil { - return "", "", err - } - mcsLevel := pcon["level"] - mcon, err := selinux.NewContext(mountLabel) - if err != nil { - return "", "", err - } - for _, opt := range options { - if opt == "disable" { - return "", mountLabel, nil - } - if i := strings.Index(opt, ":"); i == -1 { - return "", "", errors.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type, filetype' followed by ':' and a value", opt) - } - con := strings.SplitN(opt, ":", 2) - if !validOptions[con[0]] { - return "", "", errors.Errorf("Bad label option %q, valid options 'disable, user, role, level, type, filetype'", con[0]) - - } - if con[0] == "filetype" { - mcon["type"] = con[1] - continue - } - pcon[con[0]] = con[1] - if con[0] == "level" || con[0] == "user" { - mcon[con[0]] = con[1] - } - } - if pcon.Get() != processLabel { - if pcon["level"] != mcsLevel { - selinux.ReleaseLabel(processLabel) - } - processLabel = pcon.Get() - selinux.ReserveLabel(processLabel) - } - mountLabel = mcon.Get() - } - return processLabel, mountLabel, nil -} - -// Deprecated: The GenLabels function is only to be used during the transition -// to the official API. Use InitLabels(strings.Fields(options)) instead. -func GenLabels(options string) (string, string, error) { - return InitLabels(strings.Fields(options)) -} - -// SetFileLabel modifies the "path" label to the specified file label -func SetFileLabel(path string, fileLabel string) error { - if !selinux.GetEnabled() || fileLabel == "" { - return nil - } - return selinux.SetFileLabel(path, fileLabel) -} - -// SetFileCreateLabel tells the kernel the label for all files to be created -func SetFileCreateLabel(fileLabel string) error { - if !selinux.GetEnabled() { - return nil - } - return selinux.SetFSCreateLabel(fileLabel) -} - -// Relabel changes the label of path to the filelabel string. -// It changes the MCS label to s0 if shared is true. -// This will allow all containers to share the content. -func Relabel(path string, fileLabel string, shared bool) error { - if !selinux.GetEnabled() || fileLabel == "" { - return nil - } - - exclude_paths := map[string]bool{ - "/": true, - "/bin": true, - "/boot": true, - "/dev": true, - "/etc": true, - "/etc/passwd": true, - "/etc/pki": true, - "/etc/shadow": true, - "/home": true, - "/lib": true, - "/lib64": true, - "/media": true, - "/opt": true, - "/proc": true, - "/root": true, - "/run": true, - "/sbin": true, - "/srv": true, - "/sys": true, - "/tmp": true, - "/usr": true, - "/var": true, - "/var/lib": true, - "/var/log": true, - } - - if home := os.Getenv("HOME"); home != "" { - exclude_paths[home] = true - } - - if sudoUser := os.Getenv("SUDO_USER"); sudoUser != "" { - if usr, err := user.Lookup(sudoUser); err == nil { - exclude_paths[usr.HomeDir] = true - } - } - - if path != "/" { - path = strings.TrimSuffix(path, "/") - } - if exclude_paths[path] { - return errors.Errorf("SELinux relabeling of %s is not allowed", path) - } - - if shared { - c, err := selinux.NewContext(fileLabel) - if err != nil { - return err - } - - c["level"] = "s0" - fileLabel = c.Get() - } - if err := selinux.Chcon(path, fileLabel, true); err != nil { - return err - } - return nil -} - -// DisableSecOpt returns a security opt that can disable labeling -// support for future container processes -// Deprecated: use selinux.DisableSecOpt -var DisableSecOpt = selinux.DisableSecOpt - -// Validate checks that the label does not include unexpected options -func Validate(label string) error { - if strings.Contains(label, "z") && strings.Contains(label, "Z") { - return ErrIncompatibleLabel - } - return nil -} - -// RelabelNeeded checks whether the user requested a relabel -func RelabelNeeded(label string) bool { - return strings.Contains(label, "z") || strings.Contains(label, "Z") -} - -// IsShared checks that the label includes a "shared" mark -func IsShared(label string) bool { - return strings.Contains(label, "z") -} diff -Nru golang-github-opencontainers-selinux-1.6.0/go-selinux/label/label_selinux_test.go golang-github-opencontainers-selinux-1.8.0/go-selinux/label/label_selinux_test.go --- golang-github-opencontainers-selinux-1.6.0/go-selinux/label/label_selinux_test.go 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/go-selinux/label/label_selinux_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,233 +0,0 @@ -// +build selinux,linux - -package label - -import ( - "io/ioutil" - "os" - "strings" - "testing" - - "github.com/opencontainers/selinux/go-selinux" -) - -func TestInit(t *testing.T) { - if !selinux.GetEnabled() { - return - } - var testNull []string - plabel, mlabel, err := InitLabels(testNull) - if err != nil { - t.Log("InitLabels Failed") - t.Fatal(err) - } - testDisabled := []string{"disable"} - roMountLabel := ROMountLabel() - if roMountLabel == "" { - t.Errorf("ROMountLabel Failed") - } - plabel, mlabel, err = InitLabels(testDisabled) - if err != nil { - t.Log("InitLabels Disabled Failed") - t.Fatal(err) - } - if plabel != "" { - t.Log("InitLabels Disabled Failed") - t.FailNow() - } - testUser := []string{"user:user_u", "role:user_r", "type:user_t", "level:s0:c1,c15"} - plabel, mlabel, err = InitLabels(testUser) - if err != nil { - t.Log("InitLabels User Failed") - t.Fatal(err) - } - if plabel != "user_u:user_r:user_t:s0:c1,c15" || (mlabel != "user_u:object_r:container_file_t:s0:c1,c15" && mlabel != "user_u:object_r:svirt_sandbox_file_t:s0:c1,c15") { - t.Logf("InitLabels User Match Failed %s, %s", plabel, mlabel) - t.Log(plabel, mlabel) - t.Fatal(err) - } - - testBadData := []string{"user", "role:user_r", "type:user_t", "level:s0:c1,c15"} - if _, _, err = InitLabels(testBadData); err == nil { - t.Log("InitLabels Bad Failed") - t.Fatal(err) - } -} - -func TestDuplicateLabel(t *testing.T) { - secopt, err := DupSecOpt("system_u:system_r:container_t:s0:c1,c2") - if err != nil { - t.Fatal(err) - } - for _, opt := range secopt { - con := strings.SplitN(opt, ":", 2) - if con[0] == "user" { - if con[1] != "system_u" { - t.Errorf("DupSecOpt Failed user incorrect") - } - continue - } - if con[0] == "role" { - if con[1] != "system_r" { - t.Errorf("DupSecOpt Failed role incorrect") - } - continue - } - if con[0] == "type" { - if con[1] != "container_t" { - t.Errorf("DupSecOpt Failed type incorrect") - } - continue - } - if con[0] == "level" { - if con[1] != "s0:c1,c2" { - t.Errorf("DupSecOpt Failed level incorrect") - } - continue - } - t.Errorf("DupSecOpt Failed invalid field %q", con[0]) - } - secopt = DisableSecOpt() - if secopt[0] != "disable" { - t.Errorf("DisableSecOpt Failed level incorrect %q", secopt[0]) - } -} -func TestRelabel(t *testing.T) { - if !selinux.GetEnabled() { - return - } - testdir, err := ioutil.TempDir("/tmp", "") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(testdir) - label := "system_u:object_r:container_file_t:s0:c1,c2" - if err := Relabel(testdir, "", true); err != nil { - t.Fatalf("Relabel with no label failed: %v", err) - } - if err := Relabel(testdir, label, true); err != nil { - t.Fatalf("Relabel shared failed: %v", err) - } - if err := Relabel(testdir, label, false); err != nil { - t.Fatalf("Relabel unshared failed: %v", err) - } - if err := Relabel("/etc", label, false); err == nil { - t.Fatalf("Relabel /etc succeeded") - } - if err := Relabel("/", label, false); err == nil { - t.Fatalf("Relabel / succeeded") - } - if err := Relabel("/usr", label, false); err == nil { - t.Fatalf("Relabel /usr succeeded") - } - if err := Relabel("/usr/", label, false); err == nil { - t.Fatalf("Relabel /usr/ succeeded") - } - if err := Relabel("/etc/passwd", label, false); err == nil { - t.Fatalf("Relabel /etc/passwd succeeded") - } - if home := os.Getenv("HOME"); home != "" { - if err := Relabel(home, label, false); err == nil { - t.Fatalf("Relabel %s succeeded", home) - } - } -} -func TestValidate(t *testing.T) { - if err := Validate("zZ"); err != ErrIncompatibleLabel { - t.Fatalf("Expected incompatible error, got %v", err) - } - if err := Validate("Z"); err != nil { - t.Fatal(err) - } - if err := Validate("z"); err != nil { - t.Fatal(err) - } - if err := Validate(""); err != nil { - t.Fatal(err) - } -} - -func TestIsShared(t *testing.T) { - if shared := IsShared("Z"); shared { - t.Fatalf("Expected label `Z` to not be shared, got %v", shared) - } - if shared := IsShared("z"); !shared { - t.Fatalf("Expected label `z` to be shared, got %v", shared) - } - if shared := IsShared("Zz"); !shared { - t.Fatalf("Expected label `Zz` to be shared, got %v", shared) - } - -} - -func TestSELinuxNoLevel(t *testing.T) { - if !selinux.GetEnabled() { - return - } - tlabel := "system_u:system_r:container_t" - dup, err := DupSecOpt(tlabel) - if err != nil { - t.Fatal(err) - } - - if len(dup) != 3 { - t.Errorf("DupSecOpt Failed on non mls label") - } - con, err := selinux.NewContext(tlabel) - if err != nil { - t.Fatal(err) - } - if con.Get() != tlabel { - t.Errorf("NewContaxt and con.Get() Failed on non mls label") - } -} - -func TestSocketLabel(t *testing.T) { - if !selinux.GetEnabled() { - return - } - label := "system_u:object_r:container_t:s0:c1,c2" - if err := selinux.SetSocketLabel(label); err != nil { - t.Fatal(err) - } - nlabel, err := selinux.SocketLabel() - if err != nil { - t.Fatal(err) - } - if label != nlabel { - t.Errorf("SocketLabel %s != %s", nlabel, label) - } -} - -func TestKeyLabel(t *testing.T) { - if !selinux.GetEnabled() { - return - } - label := "system_u:object_r:container_t:s0:c1,c2" - if err := selinux.SetKeyLabel(label); err != nil { - t.Fatal(err) - } - nlabel, err := selinux.KeyLabel() - if err != nil { - t.Fatal(err) - } - if label != nlabel { - t.Errorf("KeyLabel %s != %s", nlabel, label) - } -} - -func TestFileLabel(t *testing.T) { - if !selinux.GetEnabled() { - return - } - testUser := []string{"filetype:test_file_t", "level:s0:c1,c15"} - _, mlabel, err := InitLabels(testUser) - if err != nil { - t.Log("InitLabels User Failed") - t.Fatal(err) - } - if mlabel != "system_u:object_r:test_file_t:s0:c1,c15" { - t.Log("InitLabels filetype Failed") - t.Fatal(err) - } -} diff -Nru golang-github-opencontainers-selinux-1.6.0/go-selinux/label/label_stub.go golang-github-opencontainers-selinux-1.8.0/go-selinux/label/label_stub.go --- golang-github-opencontainers-selinux-1.6.0/go-selinux/label/label_stub.go 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/go-selinux/label/label_stub.go 2020-12-15 10:24:31.000000000 +0000 @@ -1,4 +1,4 @@ -// +build !selinux !linux +// +build !linux package label diff -Nru golang-github-opencontainers-selinux-1.6.0/go-selinux/label/label_stub_test.go golang-github-opencontainers-selinux-1.8.0/go-selinux/label/label_stub_test.go --- golang-github-opencontainers-selinux-1.6.0/go-selinux/label/label_stub_test.go 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/go-selinux/label/label_stub_test.go 2020-12-15 10:24:31.000000000 +0000 @@ -1,4 +1,4 @@ -// +build !selinux !linux +// +build !linux package label @@ -32,7 +32,7 @@ t.FailNow() } testUser := []string{"user:user_u", "role:user_r", "type:user_t", "level:s0:c1,c15"} - plabel, _, err = InitLabels(testUser) + _, _, err = InitLabels(testUser) if err != nil { t.Log("InitLabels User Failed") t.Fatal(err) @@ -112,7 +112,7 @@ t.Fatal(err) } - DupSecOpt("foobar") + _, _ = DupSecOpt("foobar") DisableSecOpt() if err := Validate("foobar"); err != nil { diff -Nru golang-github-opencontainers-selinux-1.6.0/go-selinux/selinux.go golang-github-opencontainers-selinux-1.8.0/go-selinux/selinux.go --- golang-github-opencontainers-selinux-1.6.0/go-selinux/selinux.go 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/go-selinux/selinux.go 2020-12-15 10:24:31.000000000 +0000 @@ -30,6 +30,11 @@ // ErrLevelSyntax is returned when a sensitivity or category do not have correct syntax in a level ErrLevelSyntax = errors.New("invalid level syntax") + // ErrContextMissing is returned if a requested context is not found in a file. + ErrContextMissing = errors.New("context does not have a match") + // ErrVerifierNil is returned when a context verifier function is nil. + ErrVerifierNil = errors.New("verifier function is nil") + // CategoryRange allows the upper bound on the category range to be adjusted CategoryRange = DefaultCategoryRange ) @@ -63,8 +68,12 @@ return fileLabel(fpath) } -// SetFSCreateLabel tells kernel the label to create all file system objects -// created by this task. Setting label="" to return to default. +// SetFSCreateLabel tells the kernel what label to use for all file system objects +// created by this task. +// Set the label to an empty string to return to the default label. Calls to SetFSCreateLabel +// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until file system +// objects created by this task are finished to guarantee another goroutine does not migrate +// to the current thread before execution is complete. func SetFSCreateLabel(label string) error { return setFSCreateLabel(label) } @@ -113,19 +122,27 @@ } // SetExecLabel sets the SELinux label that the kernel will use for any programs -// that are executed by the current process thread, or an error. +// that are executed by the current process thread, or an error. Calls to SetExecLabel +// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until execution +// of the program is finished to guarantee another goroutine does not migrate to the current +// thread before execution is complete. func SetExecLabel(label string) error { return setExecLabel(label) } // SetTaskLabel sets the SELinux label for the current thread, or an error. -// This requires the dyntransition permission. +// This requires the dyntransition permission. Calls to SetTaskLabel should +// be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() to guarantee +// the current thread does not run in a new mislabeled thread. func SetTaskLabel(label string) error { return setTaskLabel(label) } // SetSocketLabel takes a process label and tells the kernel to assign the -// label to the next socket that gets created +// label to the next socket that gets created. Calls to SetSocketLabel +// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until +// the the socket is created to guarantee another goroutine does not migrate +// to the current thread before execution is complete. func SetSocketLabel(label string) error { return setSocketLabel(label) } @@ -141,7 +158,10 @@ } // SetKeyLabel takes a process label and tells the kernel to assign the -// label to the next kernel keyring that gets created +// label to the next kernel keyring that gets created. Calls to SetKeyLabel +// should be wrapped in runtime.LockOSThread()/runtime.UnlockOSThread() until +// the kernel keyring is created to guarantee another goroutine does not migrate +// to the current thread before execution is complete. func SetKeyLabel(label string) error { return setKeyLabel(label) } @@ -247,3 +267,12 @@ func DisableSecOpt() []string { return disableSecOpt() } + +// GetDefaultContextWithLevel gets a single context for the specified SELinux user +// identity that is reachable from the specified scon context. The context is based +// on the per-user /etc/selinux/{SELINUXTYPE}/contexts/users/ if it exists, +// and falls back to the global /etc/selinux/{SELINUXTYPE}/contexts/default_contexts +// file. +func GetDefaultContextWithLevel(user, level, scon string) (string, error) { + return getDefaultContextWithLevel(user, level, scon) +} diff -Nru golang-github-opencontainers-selinux-1.6.0/go-selinux/selinux_linux.go golang-github-opencontainers-selinux-1.8.0/go-selinux/selinux_linux.go --- golang-github-opencontainers-selinux-1.6.0/go-selinux/selinux_linux.go 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/go-selinux/selinux_linux.go 2020-12-15 10:24:31.000000000 +0000 @@ -1,5 +1,3 @@ -// +build selinux,linux - package selinux import ( @@ -28,6 +26,8 @@ minSensLen = 2 contextFile = "/usr/share/containers/selinux/contexts" selinuxDir = "/etc/selinux/" + selinuxUsersDir = "contexts/users" + defaultContexts = "contexts/default_contexts" selinuxConfig = selinuxDir + "config" selinuxfsMount = "/sys/fs/selinux" selinuxTypeTag = "SELINUXTYPE" @@ -35,6 +35,8 @@ xattrNameSelinux = "security.selinux" ) +var policyRoot = filepath.Join(selinuxDir, readConfig(selinuxTypeTag)) + type selinuxState struct { enabledSet bool enabled bool @@ -54,6 +56,13 @@ high *level } +type defaultSECtx struct { + user, level, scon string + userRdr, defaultRdr io.Reader + + verifier func(string) error +} + type levelItem byte const ( @@ -111,7 +120,7 @@ if err == nil { break } - if err == unix.EAGAIN { + if err == unix.EAGAIN || err == unix.EINTR { continue } return false @@ -205,28 +214,16 @@ } func readConfig(target string) string { - var ( - val, key string - bufin *bufio.Reader - ) - in, err := os.Open(selinuxConfig) if err != nil { return "" } defer in.Close() - bufin = bufio.NewReader(in) + scanner := bufio.NewScanner(in) - for done := false; !done; { - var line string - if line, err = bufin.ReadString('\n'); err != nil { - if err != io.EOF { - return "" - } - done = true - } - line = strings.TrimSpace(line) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) if len(line) == 0 { // Skip blank lines continue @@ -236,7 +233,7 @@ continue } if groups := assignRegex.FindStringSubmatch(line); groups != nil { - key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) + key, val := strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) if key == target { return strings.Trim(val, "\"") } @@ -245,15 +242,17 @@ return "" } -func getSELinuxPolicyRoot() string { - return filepath.Join(selinuxDir, readConfig(selinuxTypeTag)) -} - func isProcHandle(fh *os.File) error { var buf unix.Statfs_t - err := unix.Fstatfs(int(fh.Fd()), &buf) - if err != nil { - return errors.Wrapf(err, "statfs(%q) failed", fh.Name()) + + for { + err := unix.Fstatfs(int(fh.Fd()), &buf) + if err == nil { + break + } + if err != unix.EINTR { + return errors.Wrapf(err, "statfs(%q) failed", fh.Name()) + } } if buf.Type != unix.PROC_SUPER_MAGIC { return errors.Errorf("file %q is not on procfs", fh.Name()) @@ -307,9 +306,16 @@ if fpath == "" { return ErrEmptyPath } - if err := unix.Lsetxattr(fpath, xattrNameSelinux, []byte(label), 0); err != nil { - return errors.Wrapf(err, "failed to set file label on %s", fpath) + for { + err := unix.Lsetxattr(fpath, xattrNameSelinux, []byte(label), 0) + if err == nil { + break + } + if err != unix.EINTR { + return errors.Wrapf(err, "failed to set file label on %s", fpath) + } } + return nil } @@ -751,7 +757,7 @@ if len(label) != 0 { con := strings.SplitN(label, ":", 4) if len(con) > 3 { - mcsAdd(con[3]) + _ = mcsAdd(con[3]) } } } @@ -828,11 +834,11 @@ } for ORD > TIER { - ORD = ORD - TIER + ORD -= TIER TIER-- } TIER = SETSIZE - TIER - ORD = ORD + TIER + ORD += TIER return fmt.Sprintf("s0:c%d,c%d", TIER, ORD) } @@ -844,16 +850,14 @@ ) for { - binary.Read(rand.Reader, binary.LittleEndian, &n) + _ = binary.Read(rand.Reader, binary.LittleEndian, &n) c1 = n % catRange - binary.Read(rand.Reader, binary.LittleEndian, &n) + _ = binary.Read(rand.Reader, binary.LittleEndian, &n) c2 = n % catRange if c1 == c2 { continue - } else { - if c1 > c2 { - c1, c2 = c2, c1 - } + } else if c1 > c2 { + c1, c2 = c2, c1 } mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2) if err := mcsAdd(mcs); err != nil { @@ -884,18 +888,13 @@ if f, err := os.Open(contextFile); err == nil { return f, nil } - lxcPath := filepath.Join(getSELinuxPolicyRoot(), "/contexts/lxc_contexts") + lxcPath := filepath.Join(policyRoot, "/contexts/lxc_contexts") return os.Open(lxcPath) } var labels = loadLabels() func loadLabels() map[string]string { - var ( - val, key string - bufin *bufio.Reader - ) - labels := make(map[string]string) in, err := openContextFile() if err != nil { @@ -903,18 +902,10 @@ } defer in.Close() - bufin = bufio.NewReader(in) + scanner := bufio.NewScanner(in) - for done := false; !done; { - var line string - if line, err = bufin.ReadString('\n'); err != nil { - if err == io.EOF { - done = true - } else { - break - } - } - line = strings.TrimSpace(line) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) if len(line) == 0 { // Skip blank lines continue @@ -924,7 +915,7 @@ continue } if groups := assignRegex.FindStringSubmatch(line); groups != nil { - key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) + key, val := strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2]) labels[key] = strings.Trim(val, "\"") } } @@ -1015,7 +1006,7 @@ return "", err } mcsDelete(tcon["level"]) - mcsAdd(scon["level"]) + _ = mcsAdd(scon["level"]) tcon["level"] = scon["level"] return tcon.Get(), nil } @@ -1095,3 +1086,124 @@ func disableSecOpt() []string { return []string{"disable"} } + +// findUserInContext scans the reader for a valid SELinux context +// match that is verified with the verifier. Invalid contexts are +// skipped. It returns a matched context or an empty string if no +// match is found. If a scanner error occurs, it is returned. +func findUserInContext(context Context, r io.Reader, verifier func(string) error) (string, error) { + fromRole := context["role"] + fromType := context["type"] + scanner := bufio.NewScanner(r) + + for scanner.Scan() { + fromConns := strings.Fields(scanner.Text()) + if len(fromConns) == 0 { + // Skip blank lines + continue + } + + line := fromConns[0] + + if line[0] == ';' || line[0] == '#' { + // Skip comments + continue + } + + // user context files contexts are formatted as + // role_r:type_t:s0 where the user is missing. + lineArr := strings.SplitN(line, ":", 4) + // skip context with typo, or role and type do not match + if len(lineArr) != 3 || + lineArr[0] != fromRole || + lineArr[1] != fromType { + continue + } + + for _, cc := range fromConns[1:] { + toConns := strings.SplitN(cc, ":", 4) + if len(toConns) != 3 { + continue + } + + context["role"] = toConns[0] + context["type"] = toConns[1] + + outConn := context.get() + if err := verifier(outConn); err != nil { + continue + } + + return outConn, nil + } + } + + if err := scanner.Err(); err != nil { + return "", errors.Wrap(err, "failed to scan for context") + } + + return "", nil +} + +func getDefaultContextFromReaders(c *defaultSECtx) (string, error) { + if c.verifier == nil { + return "", ErrVerifierNil + } + + context, err := newContext(c.scon) + if err != nil { + return "", errors.Wrapf(err, "failed to create label for %s", c.scon) + } + + // set so the verifier validates the matched context with the provided user and level. + context["user"] = c.user + context["level"] = c.level + + conn, err := findUserInContext(context, c.userRdr, c.verifier) + if err != nil { + return "", err + } + + if conn != "" { + return conn, nil + } + + conn, err = findUserInContext(context, c.defaultRdr, c.verifier) + if err != nil { + return "", err + } + + if conn != "" { + return conn, nil + } + + return "", errors.Wrapf(ErrContextMissing, "context not found: %q", c.scon) +} + +func getDefaultContextWithLevel(user, level, scon string) (string, error) { + userPath := filepath.Join(policyRoot, selinuxUsersDir, user) + defaultPath := filepath.Join(policyRoot, defaultContexts) + + fu, err := os.Open(userPath) + if err != nil { + return "", err + } + defer fu.Close() + + fd, err := os.Open(defaultPath) + if err != nil { + return "", err + } + defer fd.Close() + + c := defaultSECtx{ + user: user, + level: level, + scon: scon, + userRdr: fu, + defaultRdr: fd, + verifier: securityCheckContext, + } + + return getDefaultContextFromReaders(&c) +} diff -Nru golang-github-opencontainers-selinux-1.6.0/go-selinux/selinux_linux_test.go golang-github-opencontainers-selinux-1.8.0/go-selinux/selinux_linux_test.go --- golang-github-opencontainers-selinux-1.6.0/go-selinux/selinux_linux_test.go 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/go-selinux/selinux_linux_test.go 2020-12-15 10:24:31.000000000 +0000 @@ -1,10 +1,9 @@ -// +build selinux,linux - package selinux import ( "bufio" "bytes" + "fmt" "os" "path/filepath" "strconv" @@ -48,7 +47,6 @@ plabel, flabel := KVMContainerLabels() if plabel == "" { t.Log("Failed to read kvm label") - } t.Log(plabel) t.Log(flabel) @@ -140,7 +138,9 @@ t.Log("Enforcing Mode:", EnforceMode()) mode := DefaultEnforceMode() t.Log("Default Enforce Mode:", mode) - defer SetEnforceMode(mode) + defer func() { + _ = SetEnforceMode(mode) + }() if err := SetEnforceMode(Enforcing); err != nil { t.Fatalf("setting selinux mode to enforcing failed: %v", err) @@ -261,12 +261,12 @@ t.Errorf("ClassIndex unexpected answer %d, possibly not reference policy", idx) } - idx, err = ClassIndex("foobar") + _, err = ClassIndex("foobar") if err == nil { t.Errorf("ClassIndex(\"foobar\") succeeded, expected to fail:") } - } + func TestComputeCreateContext(t *testing.T) { if !GetEnabled() { t.Skip("SELinux not enabled, skipping.") @@ -289,11 +289,10 @@ process := "process" // Test to ensure that a bad context returns an error t.Logf("ComputeCreateContext(%s, %s, %s)", badcon, tmp, process) - context, err = ComputeCreateContext(badcon, tmp, process) + _, err = ComputeCreateContext(badcon, tmp, process) if err == nil { t.Errorf("ComputeCreateContext(%s, %s, %s) succeeded, expected failure", badcon, tmp, process) } - } func TestGlbLub(t *testing.T) { @@ -412,6 +411,89 @@ } } +func TestContextWithLevel(t *testing.T) { + want := "bob:sysadm_r:sysadm_t:SystemLow-SystemHigh" + + goodDefaultBuff := ` +foo_r:foo_t:s0 sysadm_r:sysadm_t:s0 +staff_r:staff_t:s0 baz_r:baz_t:s0 sysadm_r:sysadm_t:s0 +` + + verifier := func(con string) error { + if con != want { + return fmt.Errorf("invalid context %s", con) + } + + return nil + } + + tests := []struct { + name, userBuff, defaultBuff string + }{ + { + name: "match exists in user context file", + userBuff: `# COMMENT +foo_r:foo_t:s0 sysadm_r:sysadm_t:s0 + +staff_r:staff_t:s0 baz_r:baz_t:s0 sysadm_r:sysadm_t:s0 +`, + defaultBuff: goodDefaultBuff, + }, + { + name: "match exists in default context file, but not in user file", + userBuff: `# COMMENT +foo_r:foo_t:s0 sysadm_r:sysadm_t:s0 +fake_r:fake_t:s0 baz_r:baz_t:s0 sysadm_r:sysadm_t:s0 +`, + defaultBuff: goodDefaultBuff, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := defaultSECtx{ + user: "bob", + level: "SystemLow-SystemHigh", + scon: "system_u:staff_r:staff_t:s0", + userRdr: bytes.NewBufferString(tt.userBuff), + defaultRdr: bytes.NewBufferString(tt.defaultBuff), + verifier: verifier, + } + + got, err := getDefaultContextFromReaders(&c) + if err != nil { + t.Fatalf("err should not exist but is: %v", err) + } + + if got != want { + t.Fatalf("got context: %q but expected %q", got, want) + } + }) + } + + t.Run("no match in user or default context files", func(t *testing.T) { + badUserBuff := "" + + badDefaultBuff := ` + foo_r:foo_t:s0 sysadm_r:sysadm_t:s0 + dne_r:dne_t:s0 baz_r:baz_t:s0 sysadm_r:sysadm_t:s0 + ` + c := defaultSECtx{ + user: "bob", + level: "SystemLow-SystemHigh", + scon: "system_u:staff_r:staff_t:s0", + userRdr: bytes.NewBufferString(badUserBuff), + defaultRdr: bytes.NewBufferString(badDefaultBuff), + verifier: verifier, + } + + _, err := getDefaultContextFromReaders(&c) + if err == nil { + t.Fatalf("err was expected") + } + }) +} + func BenchmarkChcon(b *testing.B) { file, err := filepath.Abs(os.Args[0]) if err != nil { @@ -425,6 +507,8 @@ b.Logf("Chcon(%q, %q)", dir, con) b.ResetTimer() for n := 0; n < b.N; n++ { - Chcon(dir, con, true) + if err := Chcon(dir, con, true); err != nil { + b.Fatal(err) + } } } diff -Nru golang-github-opencontainers-selinux-1.6.0/go-selinux/selinux_stub.go golang-github-opencontainers-selinux-1.8.0/go-selinux/selinux_stub.go --- golang-github-opencontainers-selinux-1.6.0/go-selinux/selinux_stub.go 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/go-selinux/selinux_stub.go 2020-12-15 10:24:31.000000000 +0000 @@ -1,4 +1,4 @@ -// +build !selinux !linux +// +build !linux package selinux @@ -146,3 +146,7 @@ func disableSecOpt() []string { return []string{"disable"} } + +func getDefaultContextWithLevel(user, level, scon string) (string, error) { + return "", nil +} diff -Nru golang-github-opencontainers-selinux-1.6.0/go-selinux/selinux_stub_test.go golang-github-opencontainers-selinux-1.8.0/go-selinux/selinux_stub_test.go --- golang-github-opencontainers-selinux-1.6.0/go-selinux/selinux_stub_test.go 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/go-selinux/selinux_stub_test.go 2020-12-15 10:24:31.000000000 +0000 @@ -1,4 +1,4 @@ -// +build !selinux !linux +// +build !linux package selinux @@ -8,7 +8,7 @@ func TestSELinux(t *testing.T) { if GetEnabled() { - t.Fatal("SELinux enabled with build-tag !selinux.") + t.Fatal("SELinux enabled on non-linux.") } if _, err := FileLabel("/etc"); err != nil { @@ -38,7 +38,7 @@ ReserveLabel("foobar") ReleaseLabel("foobar") - DupSecOpt("foobar") + _, _ = DupSecOpt("foobar") DisableSecOpt() SetDisabled() if enabled := GetEnabled(); enabled { diff -Nru golang-github-opencontainers-selinux-1.6.0/go-selinux/xattrs.go golang-github-opencontainers-selinux-1.8.0/go-selinux/xattrs.go --- golang-github-opencontainers-selinux-1.6.0/go-selinux/xattrs.go 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/go-selinux/xattrs.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,30 +0,0 @@ -// +build selinux,linux - -package selinux - -import ( - "golang.org/x/sys/unix" -) - -// Returns a []byte slice if the xattr is set and nil otherwise -// Requires path and its attribute as arguments -func lgetxattr(path string, attr string) ([]byte, error) { - // Start with a 128 length byte array - dest := make([]byte, 128) - sz, errno := unix.Lgetxattr(path, attr, dest) - for errno == unix.ERANGE { - // Buffer too small, use zero-sized buffer to get the actual size - sz, errno = unix.Lgetxattr(path, attr, []byte{}) - if errno != nil { - return nil, errno - } - - dest = make([]byte, sz) - sz, errno = unix.Lgetxattr(path, attr, dest) - } - if errno != nil { - return nil, errno - } - - return dest[:sz], nil -} diff -Nru golang-github-opencontainers-selinux-1.6.0/go-selinux/xattrs_linux.go golang-github-opencontainers-selinux-1.8.0/go-selinux/xattrs_linux.go --- golang-github-opencontainers-selinux-1.6.0/go-selinux/xattrs_linux.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/go-selinux/xattrs_linux.go 2020-12-15 10:24:31.000000000 +0000 @@ -0,0 +1,38 @@ +package selinux + +import ( + "golang.org/x/sys/unix" +) + +// lgetxattr returns a []byte slice containing the value of +// an extended attribute attr set for path. +func lgetxattr(path, attr string) ([]byte, error) { + // Start with a 128 length byte array + dest := make([]byte, 128) + sz, errno := doLgetxattr(path, attr, dest) + for errno == unix.ERANGE { + // Buffer too small, use zero-sized buffer to get the actual size + sz, errno = doLgetxattr(path, attr, []byte{}) + if errno != nil { + return nil, errno + } + + dest = make([]byte, sz) + sz, errno = doLgetxattr(path, attr, dest) + } + if errno != nil { + return nil, errno + } + + return dest[:sz], nil +} + +// doLgetxattr is a wrapper that retries on EINTR +func doLgetxattr(path, attr string, dest []byte) (int, error) { + for { + sz, err := unix.Lgetxattr(path, attr, dest) + if err != unix.EINTR { + return sz, err + } + } +} diff -Nru golang-github-opencontainers-selinux-1.6.0/go.sum golang-github-opencontainers-selinux-1.8.0/go.sum --- golang-github-opencontainers-selinux-1.6.0/go.sum 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/go.sum 2020-12-15 10:24:31.000000000 +0000 @@ -1,6 +1,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243 h1:R43TdZy32XXSXjJn7M/HhALJ9imq6ztLnChfYJpVDnM= -github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.11 h1:N7Z7E9UvjW+sGsEl7k/SJrvY2reP1A07MrGuCjIOjRE= +github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= golang.org/x/sys v0.0.0-20191115151921-52ab43148777 h1:wejkGHRTr38uaKRqECZlsCsJ1/TGxIyFbH32x5zUdu4= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff -Nru golang-github-opencontainers-selinux-1.6.0/Makefile golang-github-opencontainers-selinux-1.8.0/Makefile --- golang-github-opencontainers-selinux-1.6.0/Makefile 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/Makefile 2020-12-15 10:24:31.000000000 +0000 @@ -1,22 +1,16 @@ -export GO111MODULE=off GO ?= go -BUILDTAGS := selinux all: build build-cross define go-build - GOOS=$(1) GOARCH=$(2) $(GO) build -tags $(BUILDTAGS) ./... -endef - -define go-build-noselinux GOOS=$(1) GOARCH=$(2) $(GO) build ./... endef -.PHONY: +.PHONY: build build: $(call go-build,linux,amd64) -.PHONY: +.PHONY: build-cross build-cross: $(call go-build,linux,386) $(call go-build,linux,arm) @@ -25,18 +19,14 @@ $(call go-build,linux,s390x) $(call go-build,windows,amd64) $(call go-build,windows,386) - $(call go-build-noselinux,linux,amd64) - $(call go-build-noselinux,linux,arm) - $(call go-build-noselinux,linux,arm64) - $(call go-build-noselinux,linux,ppc64le) - $(call go-build-noselinux,linux,s390x) - $(call go-build-noselinux,windows,amd64) - $(call go-build-noselinux,windows,386) BUILD_PATH := $(shell pwd)/build BUILD_BIN_PATH := ${BUILD_PATH}/bin GOLANGCI_LINT := ${BUILD_BIN_PATH}/golangci-lint +GOLANGCI_INSTALL := https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh +GOLANGCI_VERSION := v1.31.0 +.PHONY: check-gopath check-gopath: ifndef GOPATH $(error GOPATH is not set) @@ -44,24 +34,19 @@ .PHONY: test test: check-gopath - go test -timeout 3m -tags "${BUILDTAGS}" ${TESTFLAGS} -v ./... go test -timeout 3m ${TESTFLAGS} -v ./... ${GOLANGCI_LINT}: - export \ - VERSION=v1.23.7 \ - URL=https://raw.githubusercontent.com/golangci/golangci-lint \ - BINDIR=${BUILD_BIN_PATH} && \ - curl -sfL $$URL/$$VERSION/install.sh | sh -s $$VERSION + curl -sSfL ${GOLANGCI_INSTALL} | sh -s -- -b ${BUILD_BIN_PATH} ${GOLANGCI_VERSION} -.PHONY: +.PHONY: lint lint: ${GOLANGCI_LINT} ${GOLANGCI_LINT} version ${GOLANGCI_LINT} linters ${GOLANGCI_LINT} run +.PHONY: vendor vendor: - export GO111MODULE=on \ - $(GO) mod tidy && \ - $(GO) mod vendor && \ - $(GO) mod verify + $(GO) mod tidy + $(GO) mod vendor + $(GO) mod verify diff -Nru golang-github-opencontainers-selinux-1.6.0/pkg/pwalk/pwalk.go golang-github-opencontainers-selinux-1.8.0/pkg/pwalk/pwalk.go --- golang-github-opencontainers-selinux-1.6.0/pkg/pwalk/pwalk.go 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/pkg/pwalk/pwalk.go 2020-12-15 10:24:31.000000000 +0000 @@ -20,17 +20,16 @@ // // Note that this implementation only supports primitive error handling: // -// * no errors are ever passed to WalkFn +// - no errors are ever passed to WalkFn; // -// * once a walkFn returns any error, all further processing stops -// and the error is returned to the caller of Walk; +// - once a walkFn returns any error, all further processing stops +// and the error is returned to the caller of Walk; // -// * filepath.SkipDir is not supported; -// -// * if more than one walkFn instance will return an error, only one -// of such errors will be propagated and returned by Walk, others -// will be silently discarded. +// - filepath.SkipDir is not supported; // +// - if more than one walkFn instance will return an error, only one +// of such errors will be propagated and returned by Walk, others +// will be silently discarded. func Walk(root string, walkFn WalkFunc) error { return WalkN(root, walkFn, runtime.NumCPU()*2) } @@ -38,6 +37,8 @@ // WalkN is a wrapper for filepath.Walk which can call multiple walkFn // in parallel, allowing to handle each item concurrently. A maximum of // num walkFn will be called at any one time. +// +// Please see Walk documentation for caveats of using this function. func WalkN(root string, walkFn WalkFunc, num int) error { // make sure limit is sensible if num < 1 { diff -Nru golang-github-opencontainers-selinux-1.6.0/README.md golang-github-opencontainers-selinux-1.8.0/README.md --- golang-github-opencontainers-selinux-1.6.0/README.md 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/README.md 2020-12-15 10:24:31.000000000 +0000 @@ -6,7 +6,8 @@ ## Usage -When compiling consumers of this project, the `selinux` build tag must be used to enable selinux functionality. +Prior to v1.8.0, the `selinux` build tag had to be used to enable selinux functionality for compiling consumers of this project. +Starting with v1.8.0, the `selinux` build tag is no longer needed. For complete documentation, see [godoc](https://godoc.org/github.com/opencontainers/selinux). @@ -18,5 +19,5 @@ If you find an issue, please follow the [security][security] protocol to report it. -[security]: https://github.com/opencontainers/org/blob/master/security +[security]: https://github.com/opencontainers/org/blob/master/SECURITY.md [code-of-conduct]: https://github.com/opencontainers/org/blob/master/CODE_OF_CONDUCT.md diff -Nru golang-github-opencontainers-selinux-1.6.0/.travis.yml golang-github-opencontainers-selinux-1.8.0/.travis.yml --- golang-github-opencontainers-selinux-1.6.0/.travis.yml 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/.travis.yml 2020-12-15 10:24:31.000000000 +0000 @@ -1,29 +1,21 @@ language: go go: - - 1.12.x - - 1.13.x + - 1.15.x + - 1.14.x - tip +arch: + - amd64 + - ppc64le -before_install: - - go get -u github.com/vbatts/git-validation - -stages: - - validate - - build - - lint - - test +script: + - make lint build test jobs: + allow_failures: + - go: tip include: - - stage: build - script: make - - - stage: lint - script: make lint BUILDTAGS="" - - - stage: test - script: make test BUILDTAGS="" - - stage: validate - script: | - git-validation -run DCO,short-subject -v -range ${TRAVIS_COMMIT_RANGE} + before_script: go get -u github.com/vbatts/git-validation + script: git-validation -run DCO,short-subject -v -range ${TRAVIS_COMMIT_RANGE} + - stage: build-cross + script: make build-cross diff -Nru golang-github-opencontainers-selinux-1.6.0/VERSION golang-github-opencontainers-selinux-1.8.0/VERSION --- golang-github-opencontainers-selinux-1.6.0/VERSION 2020-07-07 09:56:17.000000000 +0000 +++ golang-github-opencontainers-selinux-1.8.0/VERSION 2020-12-15 10:24:31.000000000 +0000 @@ -1 +1 @@ -1.6.0 +1.8.0