selinux_linux.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. // +build selinux,linux
  2. package selinux
  3. import (
  4. "bufio"
  5. "bytes"
  6. "crypto/rand"
  7. "encoding/binary"
  8. "errors"
  9. "fmt"
  10. "io"
  11. "io/ioutil"
  12. "os"
  13. "path/filepath"
  14. "regexp"
  15. "strconv"
  16. "strings"
  17. "sync"
  18. "syscall"
  19. )
  20. const (
  21. // Enforcing constant indicate SELinux is in enforcing mode
  22. Enforcing = 1
  23. // Permissive constant to indicate SELinux is in permissive mode
  24. Permissive = 0
  25. // Disabled constant to indicate SELinux is disabled
  26. Disabled = -1
  27. selinuxDir = "/etc/selinux/"
  28. selinuxConfig = selinuxDir + "config"
  29. selinuxfsMount = "/sys/fs/selinux"
  30. selinuxTypeTag = "SELINUXTYPE"
  31. selinuxTag = "SELINUX"
  32. xattrNameSelinux = "security.selinux"
  33. stRdOnly = 0x01
  34. selinuxfsMagic = 0xf97cff8c
  35. )
  36. type selinuxState struct {
  37. enabledSet bool
  38. enabled bool
  39. selinuxfsSet bool
  40. selinuxfs string
  41. mcsList map[string]bool
  42. sync.Mutex
  43. }
  44. var (
  45. // ErrMCSAlreadyExists is returned when trying to allocate a duplicate MCS.
  46. ErrMCSAlreadyExists = errors.New("MCS label already exists")
  47. // ErrEmptyPath is returned when an empty path has been specified.
  48. ErrEmptyPath = errors.New("empty path")
  49. // InvalidLabel is returned when an invalid label is specified.
  50. InvalidLabel = errors.New("Invalid Label")
  51. assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`)
  52. roFileLabel string
  53. state = selinuxState{
  54. mcsList: make(map[string]bool),
  55. }
  56. )
  57. // Context is a representation of the SELinux label broken into 4 parts
  58. type Context map[string]string
  59. func (s *selinuxState) setEnable(enabled bool) bool {
  60. s.Lock()
  61. defer s.Unlock()
  62. s.enabledSet = true
  63. s.enabled = enabled
  64. return s.enabled
  65. }
  66. func (s *selinuxState) getEnabled() bool {
  67. s.Lock()
  68. enabled := s.enabled
  69. enabledSet := s.enabledSet
  70. s.Unlock()
  71. if enabledSet {
  72. return enabled
  73. }
  74. enabled = false
  75. if fs := getSelinuxMountPoint(); fs != "" {
  76. if con, _ := CurrentLabel(); con != "kernel" {
  77. enabled = true
  78. }
  79. }
  80. return s.setEnable(enabled)
  81. }
  82. // SetDisabled disables selinux support for the package
  83. func SetDisabled() {
  84. state.setEnable(false)
  85. }
  86. func (s *selinuxState) setSELinuxfs(selinuxfs string) string {
  87. s.Lock()
  88. defer s.Unlock()
  89. s.selinuxfsSet = true
  90. s.selinuxfs = selinuxfs
  91. return s.selinuxfs
  92. }
  93. func verifySELinuxfsMount(mnt string) bool {
  94. var buf syscall.Statfs_t
  95. for {
  96. err := syscall.Statfs(mnt, &buf)
  97. if err == nil {
  98. break
  99. }
  100. if err == syscall.EAGAIN {
  101. continue
  102. }
  103. return false
  104. }
  105. if uint32(buf.Type) != uint32(selinuxfsMagic) {
  106. return false
  107. }
  108. if (buf.Flags & stRdOnly) != 0 {
  109. return false
  110. }
  111. return true
  112. }
  113. func findSELinuxfs() string {
  114. // fast path: check the default mount first
  115. if verifySELinuxfsMount(selinuxfsMount) {
  116. return selinuxfsMount
  117. }
  118. // check if selinuxfs is available before going the slow path
  119. fs, err := ioutil.ReadFile("/proc/filesystems")
  120. if err != nil {
  121. return ""
  122. }
  123. if !bytes.Contains(fs, []byte("\tselinuxfs\n")) {
  124. return ""
  125. }
  126. // slow path: try to find among the mounts
  127. f, err := os.Open("/proc/self/mountinfo")
  128. if err != nil {
  129. return ""
  130. }
  131. defer f.Close()
  132. scanner := bufio.NewScanner(f)
  133. for {
  134. mnt := findSELinuxfsMount(scanner)
  135. if mnt == "" { // error or not found
  136. return ""
  137. }
  138. if verifySELinuxfsMount(mnt) {
  139. return mnt
  140. }
  141. }
  142. }
  143. // findSELinuxfsMount returns a next selinuxfs mount point found,
  144. // if there is one, or an empty string in case of EOF or error.
  145. func findSELinuxfsMount(s *bufio.Scanner) string {
  146. for s.Scan() {
  147. txt := s.Text()
  148. // The first field after - is fs type.
  149. // Safe as spaces in mountpoints are encoded as \040
  150. if !strings.Contains(txt, " - selinuxfs ") {
  151. continue
  152. }
  153. const mPos = 5 // mount point is 5th field
  154. fields := strings.SplitN(txt, " ", mPos+1)
  155. if len(fields) < mPos+1 {
  156. continue
  157. }
  158. return fields[mPos-1]
  159. }
  160. return ""
  161. }
  162. func (s *selinuxState) getSELinuxfs() string {
  163. s.Lock()
  164. selinuxfs := s.selinuxfs
  165. selinuxfsSet := s.selinuxfsSet
  166. s.Unlock()
  167. if selinuxfsSet {
  168. return selinuxfs
  169. }
  170. return s.setSELinuxfs(findSELinuxfs())
  171. }
  172. // getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs
  173. // filesystem or an empty string if no mountpoint is found. Selinuxfs is
  174. // a proc-like pseudo-filesystem that exposes the selinux policy API to
  175. // processes. The existence of an selinuxfs mount is used to determine
  176. // whether selinux is currently enabled or not.
  177. func getSelinuxMountPoint() string {
  178. return state.getSELinuxfs()
  179. }
  180. // GetEnabled returns whether selinux is currently enabled.
  181. func GetEnabled() bool {
  182. return state.getEnabled()
  183. }
  184. func readConfig(target string) string {
  185. var (
  186. val, key string
  187. bufin *bufio.Reader
  188. )
  189. in, err := os.Open(selinuxConfig)
  190. if err != nil {
  191. return ""
  192. }
  193. defer in.Close()
  194. bufin = bufio.NewReader(in)
  195. for done := false; !done; {
  196. var line string
  197. if line, err = bufin.ReadString('\n'); err != nil {
  198. if err != io.EOF {
  199. return ""
  200. }
  201. done = true
  202. }
  203. line = strings.TrimSpace(line)
  204. if len(line) == 0 {
  205. // Skip blank lines
  206. continue
  207. }
  208. if line[0] == ';' || line[0] == '#' {
  209. // Skip comments
  210. continue
  211. }
  212. if groups := assignRegex.FindStringSubmatch(line); groups != nil {
  213. key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
  214. if key == target {
  215. return strings.Trim(val, "\"")
  216. }
  217. }
  218. }
  219. return ""
  220. }
  221. func getSELinuxPolicyRoot() string {
  222. return filepath.Join(selinuxDir, readConfig(selinuxTypeTag))
  223. }
  224. func readCon(fpath string) (string, error) {
  225. if fpath == "" {
  226. return "", ErrEmptyPath
  227. }
  228. in, err := os.Open(fpath)
  229. if err != nil {
  230. return "", err
  231. }
  232. defer in.Close()
  233. var retval string
  234. if _, err := fmt.Fscanf(in, "%s", &retval); err != nil {
  235. return "", err
  236. }
  237. return strings.Trim(retval, "\x00"), nil
  238. }
  239. // SetFileLabel sets the SELinux label for this path or returns an error.
  240. func SetFileLabel(fpath string, label string) error {
  241. if fpath == "" {
  242. return ErrEmptyPath
  243. }
  244. return lsetxattr(fpath, xattrNameSelinux, []byte(label), 0)
  245. }
  246. // FileLabel returns the SELinux label for this path or returns an error.
  247. func FileLabel(fpath string) (string, error) {
  248. if fpath == "" {
  249. return "", ErrEmptyPath
  250. }
  251. label, err := lgetxattr(fpath, xattrNameSelinux)
  252. if err != nil {
  253. return "", err
  254. }
  255. // Trim the NUL byte at the end of the byte buffer, if present.
  256. if len(label) > 0 && label[len(label)-1] == '\x00' {
  257. label = label[:len(label)-1]
  258. }
  259. return string(label), nil
  260. }
  261. /*
  262. SetFSCreateLabel tells kernel the label to create all file system objects
  263. created by this task. Setting label="" to return to default.
  264. */
  265. func SetFSCreateLabel(label string) error {
  266. return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", syscall.Gettid()), label)
  267. }
  268. /*
  269. FSCreateLabel returns the default label the kernel which the kernel is using
  270. for file system objects created by this task. "" indicates default.
  271. */
  272. func FSCreateLabel() (string, error) {
  273. return readCon(fmt.Sprintf("/proc/self/task/%d/attr/fscreate", syscall.Gettid()))
  274. }
  275. // CurrentLabel returns the SELinux label of the current process thread, or an error.
  276. func CurrentLabel() (string, error) {
  277. return readCon(fmt.Sprintf("/proc/self/task/%d/attr/current", syscall.Gettid()))
  278. }
  279. // PidLabel returns the SELinux label of the given pid, or an error.
  280. func PidLabel(pid int) (string, error) {
  281. return readCon(fmt.Sprintf("/proc/%d/attr/current", pid))
  282. }
  283. /*
  284. ExecLabel returns the SELinux label that the kernel will use for any programs
  285. that are executed by the current process thread, or an error.
  286. */
  287. func ExecLabel() (string, error) {
  288. return readCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()))
  289. }
  290. func writeCon(fpath string, val string) error {
  291. if fpath == "" {
  292. return ErrEmptyPath
  293. }
  294. if val == "" {
  295. if !GetEnabled() {
  296. return nil
  297. }
  298. }
  299. out, err := os.OpenFile(fpath, os.O_WRONLY, 0)
  300. if err != nil {
  301. return err
  302. }
  303. defer out.Close()
  304. if val != "" {
  305. _, err = out.Write([]byte(val))
  306. } else {
  307. _, err = out.Write(nil)
  308. }
  309. return err
  310. }
  311. /*
  312. CanonicalizeContext takes a context string and writes it to the kernel
  313. the function then returns the context that the kernel will use. This function
  314. can be used to see if two contexts are equivalent
  315. */
  316. func CanonicalizeContext(val string) (string, error) {
  317. return readWriteCon(filepath.Join(getSelinuxMountPoint(), "context"), val)
  318. }
  319. func readWriteCon(fpath string, val string) (string, error) {
  320. if fpath == "" {
  321. return "", ErrEmptyPath
  322. }
  323. f, err := os.OpenFile(fpath, os.O_RDWR, 0)
  324. if err != nil {
  325. return "", err
  326. }
  327. defer f.Close()
  328. _, err = f.Write([]byte(val))
  329. if err != nil {
  330. return "", err
  331. }
  332. var retval string
  333. if _, err := fmt.Fscanf(f, "%s", &retval); err != nil {
  334. return "", err
  335. }
  336. return strings.Trim(retval, "\x00"), nil
  337. }
  338. /*
  339. SetExecLabel sets the SELinux label that the kernel will use for any programs
  340. that are executed by the current process thread, or an error.
  341. */
  342. func SetExecLabel(label string) error {
  343. return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), label)
  344. }
  345. // SetSocketLabel takes a process label and tells the kernel to assign the
  346. // label to the next socket that gets created
  347. func SetSocketLabel(label string) error {
  348. return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/sockcreate", syscall.Gettid()), label)
  349. }
  350. // SocketLabel retrieves the current socket label setting
  351. func SocketLabel() (string, error) {
  352. return readCon(fmt.Sprintf("/proc/self/task/%d/attr/sockcreate", syscall.Gettid()))
  353. }
  354. // SetKeyLabel takes a process label and tells the kernel to assign the
  355. // label to the next kernel keyring that gets created
  356. func SetKeyLabel(label string) error {
  357. err := writeCon("/proc/self/attr/keycreate", label)
  358. if os.IsNotExist(err) {
  359. return nil
  360. }
  361. if label == "" && os.IsPermission(err) && !GetEnabled() {
  362. return nil
  363. }
  364. return err
  365. }
  366. // KeyLabel retrieves the current kernel keyring label setting
  367. func KeyLabel() (string, error) {
  368. return readCon("/proc/self/attr/keycreate")
  369. }
  370. // Get returns the Context as a string
  371. func (c Context) Get() string {
  372. if c["level"] != "" {
  373. return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"])
  374. }
  375. return fmt.Sprintf("%s:%s:%s", c["user"], c["role"], c["type"])
  376. }
  377. // NewContext creates a new Context struct from the specified label
  378. func NewContext(label string) (Context, error) {
  379. c := make(Context)
  380. if len(label) != 0 {
  381. con := strings.SplitN(label, ":", 4)
  382. if len(con) < 3 {
  383. return c, InvalidLabel
  384. }
  385. c["user"] = con[0]
  386. c["role"] = con[1]
  387. c["type"] = con[2]
  388. if len(con) > 3 {
  389. c["level"] = con[3]
  390. }
  391. }
  392. return c, nil
  393. }
  394. // ClearLabels clears all reserved labels
  395. func ClearLabels() {
  396. state.Lock()
  397. state.mcsList = make(map[string]bool)
  398. state.Unlock()
  399. }
  400. // ReserveLabel reserves the MLS/MCS level component of the specified label
  401. func ReserveLabel(label string) {
  402. if len(label) != 0 {
  403. con := strings.SplitN(label, ":", 4)
  404. if len(con) > 3 {
  405. mcsAdd(con[3])
  406. }
  407. }
  408. }
  409. func selinuxEnforcePath() string {
  410. return fmt.Sprintf("%s/enforce", getSelinuxMountPoint())
  411. }
  412. // EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
  413. func EnforceMode() int {
  414. var enforce int
  415. enforceS, err := readCon(selinuxEnforcePath())
  416. if err != nil {
  417. return -1
  418. }
  419. enforce, err = strconv.Atoi(string(enforceS))
  420. if err != nil {
  421. return -1
  422. }
  423. return enforce
  424. }
  425. /*
  426. SetEnforceMode sets the current SELinux mode Enforcing, Permissive.
  427. Disabled is not valid, since this needs to be set at boot time.
  428. */
  429. func SetEnforceMode(mode int) error {
  430. return writeCon(selinuxEnforcePath(), fmt.Sprintf("%d", mode))
  431. }
  432. /*
  433. DefaultEnforceMode returns the systems default SELinux mode Enforcing,
  434. Permissive or Disabled. Note this is is just the default at boot time.
  435. EnforceMode tells you the systems current mode.
  436. */
  437. func DefaultEnforceMode() int {
  438. switch readConfig(selinuxTag) {
  439. case "enforcing":
  440. return Enforcing
  441. case "permissive":
  442. return Permissive
  443. }
  444. return Disabled
  445. }
  446. func mcsAdd(mcs string) error {
  447. if mcs == "" {
  448. return nil
  449. }
  450. state.Lock()
  451. defer state.Unlock()
  452. if state.mcsList[mcs] {
  453. return ErrMCSAlreadyExists
  454. }
  455. state.mcsList[mcs] = true
  456. return nil
  457. }
  458. func mcsDelete(mcs string) {
  459. if mcs == "" {
  460. return
  461. }
  462. state.Lock()
  463. defer state.Unlock()
  464. state.mcsList[mcs] = false
  465. }
  466. func intToMcs(id int, catRange uint32) string {
  467. var (
  468. SETSIZE = int(catRange)
  469. TIER = SETSIZE
  470. ORD = id
  471. )
  472. if id < 1 || id > 523776 {
  473. return ""
  474. }
  475. for ORD > TIER {
  476. ORD = ORD - TIER
  477. TIER--
  478. }
  479. TIER = SETSIZE - TIER
  480. ORD = ORD + TIER
  481. return fmt.Sprintf("s0:c%d,c%d", TIER, ORD)
  482. }
  483. func uniqMcs(catRange uint32) string {
  484. var (
  485. n uint32
  486. c1, c2 uint32
  487. mcs string
  488. )
  489. for {
  490. binary.Read(rand.Reader, binary.LittleEndian, &n)
  491. c1 = n % catRange
  492. binary.Read(rand.Reader, binary.LittleEndian, &n)
  493. c2 = n % catRange
  494. if c1 == c2 {
  495. continue
  496. } else {
  497. if c1 > c2 {
  498. c1, c2 = c2, c1
  499. }
  500. }
  501. mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2)
  502. if err := mcsAdd(mcs); err != nil {
  503. continue
  504. }
  505. break
  506. }
  507. return mcs
  508. }
  509. /*
  510. ReleaseLabel will unreserve the MLS/MCS Level field of the specified label.
  511. Allowing it to be used by another process.
  512. */
  513. func ReleaseLabel(label string) {
  514. if len(label) != 0 {
  515. con := strings.SplitN(label, ":", 4)
  516. if len(con) > 3 {
  517. mcsDelete(con[3])
  518. }
  519. }
  520. }
  521. // ROFileLabel returns the specified SELinux readonly file label
  522. func ROFileLabel() string {
  523. return roFileLabel
  524. }
  525. /*
  526. ContainerLabels returns an allocated processLabel and fileLabel to be used for
  527. container labeling by the calling process.
  528. */
  529. func ContainerLabels() (processLabel string, fileLabel string) {
  530. var (
  531. val, key string
  532. bufin *bufio.Reader
  533. )
  534. if !GetEnabled() {
  535. return "", ""
  536. }
  537. lxcPath := fmt.Sprintf("%s/contexts/lxc_contexts", getSELinuxPolicyRoot())
  538. in, err := os.Open(lxcPath)
  539. if err != nil {
  540. return "", ""
  541. }
  542. defer in.Close()
  543. bufin = bufio.NewReader(in)
  544. for done := false; !done; {
  545. var line string
  546. if line, err = bufin.ReadString('\n'); err != nil {
  547. if err == io.EOF {
  548. done = true
  549. } else {
  550. goto exit
  551. }
  552. }
  553. line = strings.TrimSpace(line)
  554. if len(line) == 0 {
  555. // Skip blank lines
  556. continue
  557. }
  558. if line[0] == ';' || line[0] == '#' {
  559. // Skip comments
  560. continue
  561. }
  562. if groups := assignRegex.FindStringSubmatch(line); groups != nil {
  563. key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
  564. if key == "process" {
  565. processLabel = strings.Trim(val, "\"")
  566. }
  567. if key == "file" {
  568. fileLabel = strings.Trim(val, "\"")
  569. }
  570. if key == "ro_file" {
  571. roFileLabel = strings.Trim(val, "\"")
  572. }
  573. }
  574. }
  575. if processLabel == "" || fileLabel == "" {
  576. return "", ""
  577. }
  578. if roFileLabel == "" {
  579. roFileLabel = fileLabel
  580. }
  581. exit:
  582. scon, _ := NewContext(processLabel)
  583. if scon["level"] != "" {
  584. mcs := uniqMcs(1024)
  585. scon["level"] = mcs
  586. processLabel = scon.Get()
  587. scon, _ = NewContext(fileLabel)
  588. scon["level"] = mcs
  589. fileLabel = scon.Get()
  590. }
  591. return processLabel, fileLabel
  592. }
  593. // SecurityCheckContext validates that the SELinux label is understood by the kernel
  594. func SecurityCheckContext(val string) error {
  595. return writeCon(fmt.Sprintf("%s/context", getSelinuxMountPoint()), val)
  596. }
  597. /*
  598. CopyLevel returns a label with the MLS/MCS level from src label replaced on
  599. the dest label.
  600. */
  601. func CopyLevel(src, dest string) (string, error) {
  602. if src == "" {
  603. return "", nil
  604. }
  605. if err := SecurityCheckContext(src); err != nil {
  606. return "", err
  607. }
  608. if err := SecurityCheckContext(dest); err != nil {
  609. return "", err
  610. }
  611. scon, err := NewContext(src)
  612. if err != nil {
  613. return "", err
  614. }
  615. tcon, err := NewContext(dest)
  616. if err != nil {
  617. return "", err
  618. }
  619. mcsDelete(tcon["level"])
  620. mcsAdd(scon["level"])
  621. tcon["level"] = scon["level"]
  622. return tcon.Get(), nil
  623. }
  624. // Prevent users from relabing system files
  625. func badPrefix(fpath string) error {
  626. if fpath == "" {
  627. return ErrEmptyPath
  628. }
  629. badPrefixes := []string{"/usr"}
  630. for _, prefix := range badPrefixes {
  631. if strings.HasPrefix(fpath, prefix) {
  632. return fmt.Errorf("relabeling content in %s is not allowed", prefix)
  633. }
  634. }
  635. return nil
  636. }
  637. // Chcon changes the `fpath` file object to the SELinux label `label`.
  638. // If `fpath` is a directory and `recurse`` is true, Chcon will walk the
  639. // directory tree setting the label.
  640. func Chcon(fpath string, label string, recurse bool) error {
  641. if fpath == "" {
  642. return ErrEmptyPath
  643. }
  644. if label == "" {
  645. return nil
  646. }
  647. if err := badPrefix(fpath); err != nil {
  648. return err
  649. }
  650. callback := func(p string, info os.FileInfo, err error) error {
  651. e := SetFileLabel(p, label)
  652. if os.IsNotExist(e) {
  653. return nil
  654. }
  655. return e
  656. }
  657. if recurse {
  658. return filepath.Walk(fpath, callback)
  659. }
  660. return SetFileLabel(fpath, label)
  661. }
  662. // DupSecOpt takes an SELinux process label and returns security options that
  663. // can be used to set the SELinux Type and Level for future container processes.
  664. func DupSecOpt(src string) ([]string, error) {
  665. if src == "" {
  666. return nil, nil
  667. }
  668. con, err := NewContext(src)
  669. if err != nil {
  670. return nil, err
  671. }
  672. if con["user"] == "" ||
  673. con["role"] == "" ||
  674. con["type"] == "" {
  675. return nil, nil
  676. }
  677. dup := []string{"user:" + con["user"],
  678. "role:" + con["role"],
  679. "type:" + con["type"],
  680. }
  681. if con["level"] != "" {
  682. dup = append(dup, "level:"+con["level"])
  683. }
  684. return dup, nil
  685. }
  686. // DisableSecOpt returns a security opt that can be used to disable SELinux
  687. // labeling support for future container processes.
  688. func DisableSecOpt() []string {
  689. return []string{"disable"}
  690. }