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 <dwalsh@redhat.com>
  • Loading branch information
rhatdan committed Nov 18, 2021
1 parent 0cb05ae commit 1b18907
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 5 deletions.
18 changes: 16 additions & 2 deletions go-selinux/selinux.go
Expand Up @@ -61,16 +61,30 @@ func ClassIndex(class string) (int, error) {
return classIndex(class)
}

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

// FileLabel returns the SELinux label for this path or returns an error.
// LsetFileLabel sets the SELinux label for this path, not following symlinks,
// or returns an error.
func LsetFileLabel(fpath string, label string) error {
return lSetFileLabel(fpath, label)
}

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

// LfileLabel returns the SELinux label for this path, not following 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
45 changes: 42 additions & 3 deletions go-selinux/selinux_linux.go
Expand Up @@ -316,8 +316,9 @@ func classIndex(class string) (int, error) {
return index, nil
}

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

// fileLabel returns the SELinux label for this path or returns an error.
// setFileLabel sets the SELinux label for this path, following symlinks,
// 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: "setxattr", Path: fpath, Err: err}
}
}

return nil
}

// fileLabel returns the SELinux label for this path, following symlinks,
// 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: "getxattr", 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
}

// lFileLabel returns the SELinux label for this path, not following symlinks,
// 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
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
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 = dogetxattr(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.Getxattr(path, attr, dest)
if err != unix.EINTR { //nolint:errorlint // unix errors are bare
return sz, err
}
}
}

0 comments on commit 1b18907

Please sign in to comment.