Need to setup labeling of kernel keyrings.

Work is ongoing in the kernel to support different kernel
keyrings per user namespace.  We want to allow SELinux to manage
kernel keyrings inside of the container.

Currently when runc creates the kernel keyring it gets the label which runc is
running with ususally `container_runtime_t`, with this change the kernel keyring
will be labeled with the container process label container_t:s0:C1,c2.

Container running as container_t:s0:c1,c2 can manage keyrings with the same label.

This change required a revendoring or the SELinux go bindings.

github.com/opencontainers/selinux.

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
Daniel J Walsh
2019-03-12 16:54:48 -04:00
parent 2b18fe1d88
commit cd96170c10
9 changed files with 629 additions and 110 deletions

View File

@@ -4,6 +4,8 @@ package label
import (
"fmt"
"os"
"os/user"
"strings"
"github.com/opencontainers/selinux/go-selinux"
@@ -24,17 +26,29 @@ var ErrIncompatibleLabel = fmt.Errorf("Bad SELinux option z and Z can not be use
// 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) (string, string, error) {
func InitLabels(options []string) (plabel string, mlabel string, Err error) {
if !selinux.GetEnabled() {
return "", "", nil
}
processLabel, mountLabel := selinux.ContainerLabels()
if processLabel != "" {
pcon := selinux.NewContext(processLabel)
mcon := selinux.NewContext(mountLabel)
defer func() {
if Err != nil {
ReleaseLabel(mountLabel)
}
}()
pcon, err := selinux.NewContext(processLabel)
if err != nil {
return "", "", err
}
mcon, err := selinux.NewContext(mountLabel)
if err != nil {
return "", "", err
}
for _, opt := range options {
if opt == "disable" {
return "", "", nil
return "", mountLabel, nil
}
if i := strings.Index(opt, ":"); i == -1 {
return "", "", fmt.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type' followed by ':' and a value", opt)
@@ -49,8 +63,10 @@ func InitLabels(options []string) (string, string, error) {
mcon[con[0]] = con[1]
}
}
_ = ReleaseLabel(processLabel)
processLabel = pcon.Get()
mountLabel = mcon.Get()
_ = ReserveLabel(processLabel)
}
return processLabel, mountLabel, nil
}
@@ -85,12 +101,31 @@ func FormatMountLabel(src, mountLabel string) string {
// SetProcessLabel takes a process label and tells the kernel to assign the
// label to the next program executed by the current process.
func SetProcessLabel(processLabel string) error {
if processLabel == "" {
return nil
}
return selinux.SetExecLabel(processLabel)
}
// SetSocketLabel takes a process label and tells the kernel to assign the
// label to the next socket that gets created
func SetSocketLabel(processLabel string) error {
return selinux.SetSocketLabel(processLabel)
}
// SocketLabel retrieves the current default socket label setting
func SocketLabel() (string, error) {
return selinux.SocketLabel()
}
// SetKeyLabel takes a process label and tells the kernel to assign the
// label to the next kernel keyring that gets created
func SetKeyLabel(processLabel string) error {
return selinux.SetKeyLabel(processLabel)
}
// KeyLabel retrieves the current default kernel keyring label setting
func KeyLabel() (string, error) {
return selinux.KeyLabel()
}
// ProcessLabel returns the process label that the kernel will assign
// to the next program executed by the current process. If "" is returned
// this indicates that the default labeling will happen for the process.
@@ -98,7 +133,7 @@ func ProcessLabel() (string, error) {
return selinux.ExecLabel()
}
// GetFileLabel returns the label for specified path
// FileLabel returns the label for specified path
func FileLabel(path string) (string, error) {
return selinux.FileLabel(path)
}
@@ -131,13 +166,56 @@ func Relabel(path string, fileLabel string, shared bool) error {
return nil
}
exclude_paths := map[string]bool{"/": true, "/usr": true, "/etc": true}
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 fmt.Errorf("SELinux relabeling of %s is not allowed", path)
}
if shared {
c := selinux.NewContext(fileLabel)
c, err := selinux.NewContext(fileLabel)
if err != nil {
return err
}
c["level"] = "s0"
fileLabel = c.Get()
}
@@ -157,6 +235,11 @@ func Init() {
selinux.GetEnabled()
}
// ClearLabels will clear all reserved labels
func ClearLabels() {
selinux.ClearLabels()
}
// ReserveLabel will record the fact that the MCS label has already been used.
// This will prevent InitLabels from using the MCS label in a newly created
// container
@@ -175,7 +258,7 @@ func ReleaseLabel(label string) error {
// DupSecOpt takes a process label and returns security options that
// can be used to set duplicate labels on future container processes
func DupSecOpt(src string) []string {
func DupSecOpt(src string) ([]string, error) {
return selinux.DupSecOpt(src)
}