diff --git a/go-selinux/selinux_linux.go b/go-selinux/selinux_linux.go index 90d65c1..38a001e 100644 --- a/go-selinux/selinux_linux.go +++ b/go-selinux/selinux_linux.go @@ -11,6 +11,7 @@ import ( "io" "io/ioutil" "os" + "path" "path/filepath" "regexp" "strconv" @@ -37,7 +38,6 @@ const ( selinuxTag = "SELINUX" xattrNameSelinux = "security.selinux" stRdOnly = 0x01 - selinuxfsMagic = 0xf97cff8c ) type selinuxState struct { @@ -118,7 +118,8 @@ func verifySELinuxfsMount(mnt string) bool { } return false } - if uint32(buf.Type) != uint32(selinuxfsMagic) { + + if buf.Type != unix.SELINUX_MAGIC { return false } if (buf.Flags & stRdOnly) != 0 { @@ -254,10 +255,17 @@ func getSELinuxPolicyRoot() string { return filepath.Join(selinuxDir, readConfig(selinuxTypeTag)) } -func isProcHandle(fh *os.File) (bool, error) { +func isProcHandle(fh *os.File) error { var buf unix.Statfs_t err := unix.Fstatfs(int(fh.Fd()), &buf) - return buf.Type == unix.PROC_SUPER_MAGIC, err + if err != nil { + return fmt.Errorf("statfs(%q) failed: %v", fh.Name(), err) + } + if buf.Type != unix.PROC_SUPER_MAGIC { + return fmt.Errorf("file %q is not on procfs", fh.Name()) + } + + return nil } func readCon(fpath string) (string, error) { @@ -271,10 +279,8 @@ func readCon(fpath string) (string, error) { } defer in.Close() - if ok, err := isProcHandle(in); err != nil { + if err := isProcHandle(in); err != nil { return "", err - } else if !ok { - return "", fmt.Errorf("%s not on procfs", fpath) } var retval string @@ -346,7 +352,7 @@ func ExecLabel() (string, error) { return readCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid())) } -func writeCon(fpath string, val string) error { +func writeCon(fpath, val string) error { if fpath == "" { return ErrEmptyPath } @@ -362,10 +368,8 @@ func writeCon(fpath string, val string) error { } defer out.Close() - if ok, err := isProcHandle(out); err != nil { + if err := isProcHandle(out); err != nil { return err - } else if !ok { - return fmt.Errorf("%s not on procfs", fpath) } if val != "" { @@ -505,19 +509,18 @@ func ReserveLabel(label string) { } func selinuxEnforcePath() string { - return fmt.Sprintf("%s/enforce", getSelinuxMountPoint()) + return path.Join(getSelinuxMountPoint(), "enforce") } // EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled func EnforceMode() int { var enforce int - enforceS, err := readCon(selinuxEnforcePath()) + enforceB, err := ioutil.ReadFile(selinuxEnforcePath()) if err != nil { return -1 } - - enforce, err = strconv.Atoi(string(enforceS)) + enforce, err = strconv.Atoi(string(enforceB)) if err != nil { return -1 } @@ -529,7 +532,7 @@ SetEnforceMode sets the current SELinux mode Enforcing, Permissive. Disabled is not valid, since this needs to be set at boot time. */ func SetEnforceMode(mode int) error { - return writeCon(selinuxEnforcePath(), fmt.Sprintf("%d", mode)) + return ioutil.WriteFile(selinuxEnforcePath(), []byte(strconv.Itoa(mode)), 0644) } /* @@ -711,7 +714,7 @@ exit: // SecurityCheckContext validates that the SELinux label is understood by the kernel func SecurityCheckContext(val string) error { - return writeCon(fmt.Sprintf("%s/context", getSelinuxMountPoint()), val) + return ioutil.WriteFile(path.Join(getSelinuxMountPoint(), "context"), []byte(val), 0644) } /* diff --git a/go-selinux/selinux_linux_test.go b/go-selinux/selinux_linux_test.go index 866ecc3..945acf3 100644 --- a/go-selinux/selinux_linux_test.go +++ b/go-selinux/selinux_linux_test.go @@ -53,9 +53,6 @@ func TestSELinux(t *testing.T) { t.Log(plabel) t.Log(flabel) ReleaseLabel(plabel) - t.Log("Enforcing Mode", EnforceMode()) - mode := DefaultEnforceMode() - t.Log("Default Enforce Mode ", mode) plabel, flabel = ContainerLabels() t.Log(plabel) @@ -67,15 +64,6 @@ func TestSELinux(t *testing.T) { t.Log(flabel) ReleaseLabel(plabel) - defer SetEnforceMode(mode) - if err := SetEnforceMode(Enforcing); err != nil { - t.Fatalf("enforcing selinux failed: %v", err) - } - if err := SetEnforceMode(Permissive); err != nil { - t.Fatalf("setting selinux mode to permissive failed: %v", err) - } - SetEnforceMode(mode) - pid := os.Getpid() t.Logf("PID:%d MCS:%s\n", pid, intToMcs(pid, 1023)) err = SetFSCreateLabel("unconfined_u:unconfined_r:unconfined_t:s0") @@ -95,6 +83,27 @@ func TestSELinux(t *testing.T) { t.Log(PidLabel(1)) } +func TestSetEnforceMode(t *testing.T) { + if !GetEnabled() { + t.Skip("SELinux not enabled, skipping.") + } + if os.Geteuid() != 0 { + t.Skip("root required, skipping") + } + + t.Log("Enforcing Mode:", EnforceMode()) + mode := DefaultEnforceMode() + t.Log("Default Enforce Mode:", mode) + defer SetEnforceMode(mode) + + if err := SetEnforceMode(Enforcing); err != nil { + t.Fatalf("setting selinux mode to enforcing failed: %v", err) + } + if err := SetEnforceMode(Permissive); err != nil { + t.Fatalf("setting selinux mode to permissive failed: %v", err) + } +} + func TestCanonicalizeContext(t *testing.T) { if !GetEnabled() { t.Skip("SELinux not enabled, skipping.") @@ -166,3 +175,28 @@ func TestFindSELinuxfsInMountinfo(t *testing.T) { } } } + +func TestSecurityCheckContext(t *testing.T) { + if !GetEnabled() { + t.Skip("SELinux not enabled, skipping.") + } + + // check with valid context + context, err := CurrentLabel() + if err != nil { + t.Fatalf("CurrentLabel() error: %v", err) + } + if context != "" { + t.Logf("SecurityCheckContext(%q)", context) + err = SecurityCheckContext(context) + if err != nil { + t.Errorf("SecurityCheckContext(%q) error: %v", context, err) + } + } + + context = "not-syntactically-valid" + err = SecurityCheckContext(context) + if err == nil { + t.Errorf("SecurityCheckContext(%q) succeeded, expected to fail", context) + } +}