Skip to content

Commit

Permalink
Use fgetxattr to get selinux labels
Browse files Browse the repository at this point in the history
Instead of using lgetxattr on a fd path (/proc/self/fd/<num>), directly
use `fgetxattr`.

It turns out that `lgetxattr` does not return a consistent result on all
kernel version when used on a filedescriptor path.

This is often not an issue. It would just mean that virt-handler would
label a few devices in its namespces on every start, even if it would
not have to. But on some operating systems (e.g. Centos8, but not
Centos8 stream) we then fail on the not needed relabeling attempt.

Before:

lgetxattr sometimes returns weird resources on a file descroptor path:

```
Error: error relabeling file /proc/self/fd/7 from label system_u:system_r:spc_t:s0 to label system_u:object_r:container_file_t:s0. Reason: operation not supported
[...]
error relabeling file /proc/self/fd/7 from label system_u:system_r:spc_t:s0 to label system_u:object_r:container_file_t:s0. Reason: operation not supported
```

After:

Successful detection of matching labels results in no action:

```
root@virt-handler-gk5vb:~# ./virt-chroot selinux relabel system_u:object_r:container_file_t:s0 /dev/net/tun
```

Mismatches are still detected as expected:

```
root@virt-handler-gk5vb:~# ./virt-chroot selinux relabel system_u:object_r:container_file_t:s1 /dev/net/tun
Error: error relabeling file /proc/self/fd/7 from label system_u:object_r:container_file_t:s0 to label system_u:object_r:container_file_t:s1. Reason: operation not supported

[...]
error relabeling file /proc/self/fd/7 from label system_u:object_r:container_file_t:s0 to label system_u:object_r:container_file_t:s1. Reason: operation not supported
```

Signed-off-by: Roman Mohr <[email protected]>
  • Loading branch information
rmohr authored and kylealexlane committed Oct 12, 2022
1 parent f17ec12 commit b832389
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 6 deletions.
1 change: 0 additions & 1 deletion cmd/virt-chroot/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ go_library(
"//vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs:go_default_library",
"//vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2:go_default_library",
"//vendor/github.com/opencontainers/runc/libcontainer/configs:go_default_library",
"//vendor/github.com/opencontainers/selinux/go-selinux:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/github.com/vishvananda/netlink:go_default_library",
"//vendor/golang.org/x/sys/unix:go_default_library",
Expand Down
29 changes: 24 additions & 5 deletions cmd/virt-chroot/selinux.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"os"
"path/filepath"

"github.com/opencontainers/selinux/go-selinux"
"github.com/spf13/cobra"
"golang.org/x/sys/unix"

Expand Down Expand Up @@ -67,17 +66,18 @@ func RelabelCommand() *cobra.Command {

defer fd.Close()
filePath := fd.SafePath()
currentFileLabel, err := selinux.FileLabel(filePath)
if err != nil {
return fmt.Errorf("could not retrieve label of file %s. Reason: %v", filePath, err)
}

writeableFD, err := os.OpenFile(filePath, os.O_APPEND|unix.S_IWRITE, os.ModePerm)
if err != nil {
return fmt.Errorf("error reopening file %s to write label %s. Reason: %v", filePath, label, err)
}
defer writeableFD.Close()

currentFileLabel, err := getLabel(writeableFD)
if err != nil {
return fmt.Errorf("faild to get selinux label for file %v: %v", filePath, err)
}

if currentFileLabel != label {
if err := unix.Fsetxattr(int(writeableFD.Fd()), xattrNameSelinux, []byte(label), 0); err != nil {
return fmt.Errorf("error relabeling file %s with label %s. Reason: %v", filePath, label, err)
Expand All @@ -90,3 +90,22 @@ func RelabelCommand() *cobra.Command {
relabelCommad.Flags().StringVar(&root, "root", "/", "safe root path which will be prepended to passed in files")
return relabelCommad
}

func getLabel(file *os.File) (string, error) {
// let's first find out the actual buffer size
var buffer []byte
labelLength, err := unix.Fgetxattr(int(file.Fd()), xattrNameSelinux, buffer)
if err != nil {
return "", fmt.Errorf("error reading fgetxattr: %v", err)
}
// now ask with the needed size
buffer = make([]byte, labelLength)
labelLength, err = unix.Fgetxattr(int(file.Fd()), xattrNameSelinux, buffer)
if err != nil {
return "", fmt.Errorf("error reading fgetxattr: %v", err)
}
if labelLength > 0 && buffer[labelLength-1] == '\x00' {
labelLength = labelLength - 1
}
return string(buffer[:labelLength]), nil
}

0 comments on commit b832389

Please sign in to comment.