github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/runc/libcontainer/label/label_selinux.go (about)

     1  // +build selinux,linux
     2  
     3  package label
     4  
     5  import (
     6  	"fmt"
     7  	"strings"
     8  
     9  	"github.com/opencontainers/runc/libcontainer/selinux"
    10  )
    11  
    12  // Valid Label Options
    13  var validOptions = map[string]bool{
    14  	"disable": true,
    15  	"type":    true,
    16  	"user":    true,
    17  	"role":    true,
    18  	"level":   true,
    19  }
    20  
    21  var ErrIncompatibleLabel = fmt.Errorf("Bad SELinux option z and Z can not be used together")
    22  
    23  // InitLabels returns the process label and file labels to be used within
    24  // the container.  A list of options can be passed into this function to alter
    25  // the labels.  The labels returned will include a random MCS String, that is
    26  // guaranteed to be unique.
    27  func InitLabels(options []string) (string, string, error) {
    28  	if !selinux.SelinuxEnabled() {
    29  		return "", "", nil
    30  	}
    31  	processLabel, mountLabel := selinux.GetLxcContexts()
    32  	if processLabel != "" {
    33  		pcon := selinux.NewContext(processLabel)
    34  		mcon := selinux.NewContext(mountLabel)
    35  		for _, opt := range options {
    36  			val := strings.SplitN(opt, "=", 2)
    37  			if val[0] != "label" {
    38  				continue
    39  			}
    40  			if len(val) < 2 {
    41  				return "", "", fmt.Errorf("bad label option %q, valid options 'disable' or \n'user, role, level, type' followed by ':' and a value", opt)
    42  			}
    43  			if val[1] == "disable" {
    44  				return "", "", nil
    45  			}
    46  			con := strings.SplitN(val[1], ":", 2)
    47  			if len(con) < 2 || !validOptions[con[0]] {
    48  				return "", "", fmt.Errorf("bad label option %q, valid options 'disable, user, role, level, type'", con[0])
    49  
    50  			}
    51  			pcon[con[0]] = con[1]
    52  			if con[0] == "level" || con[0] == "user" {
    53  				mcon[con[0]] = con[1]
    54  			}
    55  		}
    56  		processLabel = pcon.Get()
    57  		mountLabel = mcon.Get()
    58  	}
    59  	return processLabel, mountLabel, nil
    60  }
    61  
    62  func GetROMountLabel() string {
    63  	return selinux.GetROFileLabel()
    64  }
    65  
    66  // DEPRECATED: The GenLabels function is only to be used during the transition to the official API.
    67  func GenLabels(options string) (string, string, error) {
    68  	return InitLabels(strings.Fields(options))
    69  }
    70  
    71  // FormatMountLabel returns a string to be used by the mount command.
    72  // The format of this string will be used to alter the labeling of the mountpoint.
    73  // The string returned is suitable to be used as the options field of the mount command.
    74  // If you need to have additional mount point options, you can pass them in as
    75  // the first parameter.  Second parameter is the label that you wish to apply
    76  // to all content in the mount point.
    77  func FormatMountLabel(src, mountLabel string) string {
    78  	if mountLabel != "" {
    79  		switch src {
    80  		case "":
    81  			src = fmt.Sprintf("context=%q", mountLabel)
    82  		default:
    83  			src = fmt.Sprintf("%s,context=%q", src, mountLabel)
    84  		}
    85  	}
    86  	return src
    87  }
    88  
    89  // SetProcessLabel takes a process label and tells the kernel to assign the
    90  // label to the next program executed by the current process.
    91  func SetProcessLabel(processLabel string) error {
    92  	if processLabel == "" {
    93  		return nil
    94  	}
    95  	return selinux.Setexeccon(processLabel)
    96  }
    97  
    98  // GetProcessLabel returns the process label that the kernel will assign
    99  // to the next program executed by the current process.  If "" is returned
   100  // this indicates that the default labeling will happen for the process.
   101  func GetProcessLabel() (string, error) {
   102  	return selinux.Getexeccon()
   103  }
   104  
   105  // GetFileLabel returns the label for specified path
   106  func GetFileLabel(path string) (string, error) {
   107  	return selinux.Getfilecon(path)
   108  }
   109  
   110  // SetFileLabel modifies the "path" label to the specified file label
   111  func SetFileLabel(path string, fileLabel string) error {
   112  	if selinux.SelinuxEnabled() && fileLabel != "" {
   113  		return selinux.Setfilecon(path, fileLabel)
   114  	}
   115  	return nil
   116  }
   117  
   118  // SetFileCreateLabel tells the kernel the label for all files to be created
   119  func SetFileCreateLabel(fileLabel string) error {
   120  	if selinux.SelinuxEnabled() {
   121  		return selinux.Setfscreatecon(fileLabel)
   122  	}
   123  	return nil
   124  }
   125  
   126  // Relabel changes the label of path to the filelabel string.
   127  // It changes the MCS label to s0 if shared is true.
   128  // This will allow all containers to share the content.
   129  func Relabel(path string, fileLabel string, shared bool) error {
   130  	if !selinux.SelinuxEnabled() {
   131  		return nil
   132  	}
   133  
   134  	if fileLabel == "" {
   135  		return nil
   136  	}
   137  
   138  	exclude_paths := map[string]bool{"/": true, "/usr": true, "/etc": true}
   139  	if exclude_paths[path] {
   140  		return fmt.Errorf("SELinux relabeling of %s is not allowed", path)
   141  	}
   142  
   143  	if shared {
   144  		c := selinux.NewContext(fileLabel)
   145  		c["level"] = "s0"
   146  		fileLabel = c.Get()
   147  	}
   148  	if err := selinux.Chcon(path, fileLabel, true); err != nil {
   149  		return fmt.Errorf("SELinux relabeling of %s is not allowed: %q", path, err)
   150  	}
   151  	return nil
   152  }
   153  
   154  // GetPidLabel will return the label of the process running with the specified pid
   155  func GetPidLabel(pid int) (string, error) {
   156  	return selinux.Getpidcon(pid)
   157  }
   158  
   159  // Init initialises the labeling system
   160  func Init() {
   161  	selinux.SelinuxEnabled()
   162  }
   163  
   164  // ReserveLabel will record the fact that the MCS label has already been used.
   165  // This will prevent InitLabels from using the MCS label in a newly created
   166  // container
   167  func ReserveLabel(label string) error {
   168  	selinux.ReserveLabel(label)
   169  	return nil
   170  }
   171  
   172  // UnreserveLabel will remove the reservation of the MCS label.
   173  // This will allow InitLabels to use the MCS label in a newly created
   174  // containers
   175  func UnreserveLabel(label string) error {
   176  	selinux.FreeLxcContexts(label)
   177  	return nil
   178  }
   179  
   180  // DupSecOpt takes an process label and returns security options that
   181  // can be used to set duplicate labels on future container processes
   182  func DupSecOpt(src string) []string {
   183  	return selinux.DupSecOpt(src)
   184  }
   185  
   186  // DisableSecOpt returns a security opt that can disable labeling
   187  // support for future container processes
   188  func DisableSecOpt() []string {
   189  	return selinux.DisableSecOpt()
   190  }
   191  
   192  // Validate checks that the label does not include unexpected options
   193  func Validate(label string) error {
   194  	if strings.Contains(label, "z") && strings.Contains(label, "Z") {
   195  		return ErrIncompatibleLabel
   196  	}
   197  	return nil
   198  }
   199  
   200  // RelabelNeeded checks whether the user requested a relabel
   201  func RelabelNeeded(label string) bool {
   202  	return strings.Contains(label, "z") || strings.Contains(label, "Z")
   203  }
   204  
   205  // IsShared checks that the label includes a "shared" mark
   206  func IsShared(label string) bool {
   207  	return strings.Contains(label, "z")
   208  }