Skip to content

Commit

Permalink
Add LFileLabel and LSetFileLabel
Browse files Browse the repository at this point in the history
SELinux C library has two functions for dealing with file labels, one
which follows symlinks and one that does not.

Golang bindings should work the same way.  The lack of this function is
resulting in containers/buildah#3630 which has
to hack around the problem.

Signed-off-by: Daniel J Walsh <[email protected]>
  • Loading branch information
rhatdan committed Nov 16, 2021
1 parent 3e29a7d commit 8434dd6
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 1 deletion.
13 changes: 13 additions & 0 deletions go-selinux/selinux.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,28 @@ func ClassIndex(class string) (int, error) {
}

// SetFileLabel sets the SELinux label for this path or returns an error.
// follow symlinks
func SetFileLabel(fpath string, label string) error {
return setFileLabel(fpath, label)
}

// SetFileLabel sets the SELinux label for this path or returns an error.
// does not follow symlinks
func LSetFileLabel(fpath string, label string) error {
return lsetFileLabel(fpath, label)
}

// FileLabel returns the SELinux label for this path or returns an error.
func FileLabel(fpath string) (string, error) {
return fileLabel(fpath)
}

// LFileLabel returns the SELinux label for this path does not follow symlinks
// or returns an error.
func LFileLabel(fpath string) (string, error) {
return lfileLabel(fpath)
}

// 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
Expand Down
37 changes: 36 additions & 1 deletion go-selinux/selinux_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ func classIndex(class string) (int, error) {
}

// setFileLabel sets the SELinux label for this path or returns an error.
func setFileLabel(fpath string, label string) error {
func lsetFileLabel(fpath string, label string) error {
if fpath == "" {
return ErrEmptyPath
}
Expand All @@ -334,12 +334,47 @@ func setFileLabel(fpath string, label string) error {
return nil
}

// setFileLabel sets the SELinux label for this path or returns an error.
func setFileLabel(fpath string, label string) error {
if fpath == "" {
return ErrEmptyPath
}
for {
err := unix.Setxattr(fpath, xattrNameSelinux, []byte(label), 0)
if err == nil {
break
}
if err != unix.EINTR { //nolint:errorlint // unix errors are bare
return &os.PathError{Op: "lsetxattr", Path: fpath, Err: err}
}
}

return nil
}

// fileLabel returns the SELinux label for this path or returns an error.
func fileLabel(fpath string) (string, error) {
if fpath == "" {
return "", ErrEmptyPath
}

label, err := getxattr(fpath, xattrNameSelinux)
if err != nil {
return "", &os.PathError{Op: "lgetxattr", Path: fpath, Err: err}
}
// Trim the NUL byte at the end of the byte buffer, if present.
if len(label) > 0 && label[len(label)-1] == '\x00' {
label = label[:len(label)-1]
}
return string(label), nil
}

// fileLabel returns the SELinux label for this path or returns an error.
func lfileLabel(fpath string) (string, error) {
if fpath == "" {
return "", ErrEmptyPath
}

label, err := lgetxattr(fpath, xattrNameSelinux)
if err != nil {
return "", &os.PathError{Op: "lgetxattr", Path: fpath, Err: err}
Expand Down
8 changes: 8 additions & 0 deletions go-selinux/selinux_stub.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,18 @@ func setFileLabel(fpath string, label string) error {
return nil
}

func lsetFileLabel(fpath string, label string) error {
return nil
}

func fileLabel(fpath string) (string, error) {
return "", nil
}

func lfileLabel(fpath string) (string, error) {
return "", nil
}

func setFSCreateLabel(label string) error {
return nil
}
Expand Down
33 changes: 33 additions & 0 deletions go-selinux/xattrs_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,36 @@ func doLgetxattr(path, attr string, dest []byte) (int, error) {
}
}
}

// getxattr returns a []byte slice containing the value of
// an extended attribute attr set for path.
func getxattr(path, attr string) ([]byte, error) {
// Start with a 128 length byte array
dest := make([]byte, 128)
sz, errno := dogetxattr(path, attr, dest)
for errno == unix.ERANGE { //nolint:errorlint // unix errors are bare
// Buffer too small, use zero-sized buffer to get the actual size
sz, errno = dogetxattr(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
}

// dogetxattr is a wrapper that retries on EINTR
func dogetxattr(path, attr string, dest []byte) (int, error) {
for {
sz, err := unix.Lgetxattr(path, attr, dest)
if err != unix.EINTR { //nolint:errorlint // unix errors are bare
return sz, err
}
}
}

0 comments on commit 8434dd6

Please sign in to comment.