selinux_linux.go 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306
  1. package selinux
  2. import (
  3. "bufio"
  4. "bytes"
  5. "crypto/rand"
  6. "encoding/binary"
  7. "errors"
  8. "fmt"
  9. "io"
  10. "io/ioutil"
  11. "math/big"
  12. "os"
  13. "os/user"
  14. "path"
  15. "path/filepath"
  16. "strconv"
  17. "strings"
  18. "sync"
  19. "golang.org/x/sys/unix"
  20. )
  21. const (
  22. minSensLen = 2
  23. contextFile = "/usr/share/containers/selinux/contexts"
  24. selinuxDir = "/etc/selinux/"
  25. selinuxUsersDir = "contexts/users"
  26. defaultContexts = "contexts/default_contexts"
  27. selinuxConfig = selinuxDir + "config"
  28. selinuxfsMount = "/sys/fs/selinux"
  29. selinuxTypeTag = "SELINUXTYPE"
  30. selinuxTag = "SELINUX"
  31. xattrNameSelinux = "security.selinux"
  32. )
  33. type selinuxState struct {
  34. enabledSet bool
  35. enabled bool
  36. selinuxfsOnce sync.Once
  37. selinuxfs string
  38. mcsList map[string]bool
  39. sync.Mutex
  40. }
  41. type level struct {
  42. sens uint
  43. cats *big.Int
  44. }
  45. type mlsRange struct {
  46. low *level
  47. high *level
  48. }
  49. type defaultSECtx struct {
  50. user, level, scon string
  51. userRdr, defaultRdr io.Reader
  52. verifier func(string) error
  53. }
  54. type levelItem byte
  55. const (
  56. sensitivity levelItem = 's'
  57. category levelItem = 'c'
  58. )
  59. var (
  60. readOnlyFileLabel string
  61. state = selinuxState{
  62. mcsList: make(map[string]bool),
  63. }
  64. // for attrPath()
  65. attrPathOnce sync.Once
  66. haveThreadSelf bool
  67. // for policyRoot()
  68. policyRootOnce sync.Once
  69. policyRootVal string
  70. // for label()
  71. loadLabelsOnce sync.Once
  72. labels map[string]string
  73. )
  74. func policyRoot() string {
  75. policyRootOnce.Do(func() {
  76. policyRootVal = filepath.Join(selinuxDir, readConfig(selinuxTypeTag))
  77. })
  78. return policyRootVal
  79. }
  80. func (s *selinuxState) setEnable(enabled bool) bool {
  81. s.Lock()
  82. defer s.Unlock()
  83. s.enabledSet = true
  84. s.enabled = enabled
  85. return s.enabled
  86. }
  87. func (s *selinuxState) getEnabled() bool {
  88. s.Lock()
  89. enabled := s.enabled
  90. enabledSet := s.enabledSet
  91. s.Unlock()
  92. if enabledSet {
  93. return enabled
  94. }
  95. enabled = false
  96. if fs := getSelinuxMountPoint(); fs != "" {
  97. if con, _ := CurrentLabel(); con != "kernel" {
  98. enabled = true
  99. }
  100. }
  101. return s.setEnable(enabled)
  102. }
  103. // setDisabled disables SELinux support for the package
  104. func setDisabled() {
  105. state.setEnable(false)
  106. }
  107. func verifySELinuxfsMount(mnt string) bool {
  108. var buf unix.Statfs_t
  109. for {
  110. err := unix.Statfs(mnt, &buf)
  111. if err == nil {
  112. break
  113. }
  114. if err == unix.EAGAIN || err == unix.EINTR { //nolint:errorlint // unix errors are bare
  115. continue
  116. }
  117. return false
  118. }
  119. if uint32(buf.Type) != uint32(unix.SELINUX_MAGIC) {
  120. return false
  121. }
  122. if (buf.Flags & unix.ST_RDONLY) != 0 {
  123. return false
  124. }
  125. return true
  126. }
  127. func findSELinuxfs() string {
  128. // fast path: check the default mount first
  129. if verifySELinuxfsMount(selinuxfsMount) {
  130. return selinuxfsMount
  131. }
  132. // check if selinuxfs is available before going the slow path
  133. fs, err := ioutil.ReadFile("/proc/filesystems")
  134. if err != nil {
  135. return ""
  136. }
  137. if !bytes.Contains(fs, []byte("\tselinuxfs\n")) {
  138. return ""
  139. }
  140. // slow path: try to find among the mounts
  141. f, err := os.Open("/proc/self/mountinfo")
  142. if err != nil {
  143. return ""
  144. }
  145. defer f.Close()
  146. scanner := bufio.NewScanner(f)
  147. for {
  148. mnt := findSELinuxfsMount(scanner)
  149. if mnt == "" { // error or not found
  150. return ""
  151. }
  152. if verifySELinuxfsMount(mnt) {
  153. return mnt
  154. }
  155. }
  156. }
  157. // findSELinuxfsMount returns a next selinuxfs mount point found,
  158. // if there is one, or an empty string in case of EOF or error.
  159. func findSELinuxfsMount(s *bufio.Scanner) string {
  160. for s.Scan() {
  161. txt := s.Bytes()
  162. // The first field after - is fs type.
  163. // Safe as spaces in mountpoints are encoded as \040
  164. if !bytes.Contains(txt, []byte(" - selinuxfs ")) {
  165. continue
  166. }
  167. const mPos = 5 // mount point is 5th field
  168. fields := bytes.SplitN(txt, []byte(" "), mPos+1)
  169. if len(fields) < mPos+1 {
  170. continue
  171. }
  172. return string(fields[mPos-1])
  173. }
  174. return ""
  175. }
  176. func (s *selinuxState) getSELinuxfs() string {
  177. s.selinuxfsOnce.Do(func() {
  178. s.selinuxfs = findSELinuxfs()
  179. })
  180. return s.selinuxfs
  181. }
  182. // getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs
  183. // filesystem or an empty string if no mountpoint is found. Selinuxfs is
  184. // a proc-like pseudo-filesystem that exposes the SELinux policy API to
  185. // processes. The existence of an selinuxfs mount is used to determine
  186. // whether SELinux is currently enabled or not.
  187. func getSelinuxMountPoint() string {
  188. return state.getSELinuxfs()
  189. }
  190. // getEnabled returns whether SELinux is currently enabled.
  191. func getEnabled() bool {
  192. return state.getEnabled()
  193. }
  194. func readConfig(target string) string {
  195. in, err := os.Open(selinuxConfig)
  196. if err != nil {
  197. return ""
  198. }
  199. defer in.Close()
  200. scanner := bufio.NewScanner(in)
  201. for scanner.Scan() {
  202. line := bytes.TrimSpace(scanner.Bytes())
  203. if len(line) == 0 {
  204. // Skip blank lines
  205. continue
  206. }
  207. if line[0] == ';' || line[0] == '#' {
  208. // Skip comments
  209. continue
  210. }
  211. fields := bytes.SplitN(line, []byte{'='}, 2)
  212. if len(fields) != 2 {
  213. continue
  214. }
  215. if bytes.Equal(fields[0], []byte(target)) {
  216. return string(bytes.Trim(fields[1], `"`))
  217. }
  218. }
  219. return ""
  220. }
  221. func isProcHandle(fh *os.File) error {
  222. var buf unix.Statfs_t
  223. for {
  224. err := unix.Fstatfs(int(fh.Fd()), &buf)
  225. if err == nil {
  226. break
  227. }
  228. if err != unix.EINTR { //nolint:errorlint // unix errors are bare
  229. return &os.PathError{Op: "fstatfs", Path: fh.Name(), Err: err}
  230. }
  231. }
  232. if buf.Type != unix.PROC_SUPER_MAGIC {
  233. return fmt.Errorf("file %q is not on procfs", fh.Name())
  234. }
  235. return nil
  236. }
  237. func readCon(fpath string) (string, error) {
  238. if fpath == "" {
  239. return "", ErrEmptyPath
  240. }
  241. in, err := os.Open(fpath)
  242. if err != nil {
  243. return "", err
  244. }
  245. defer in.Close()
  246. if err := isProcHandle(in); err != nil {
  247. return "", err
  248. }
  249. return readConFd(in)
  250. }
  251. func readConFd(in *os.File) (string, error) {
  252. data, err := ioutil.ReadAll(in)
  253. if err != nil {
  254. return "", err
  255. }
  256. return string(bytes.TrimSuffix(data, []byte{0})), nil
  257. }
  258. // classIndex returns the int index for an object class in the loaded policy,
  259. // or -1 and an error
  260. func classIndex(class string) (int, error) {
  261. permpath := fmt.Sprintf("class/%s/index", class)
  262. indexpath := filepath.Join(getSelinuxMountPoint(), permpath)
  263. indexB, err := ioutil.ReadFile(indexpath)
  264. if err != nil {
  265. return -1, err
  266. }
  267. index, err := strconv.Atoi(string(indexB))
  268. if err != nil {
  269. return -1, err
  270. }
  271. return index, nil
  272. }
  273. // lSetFileLabel sets the SELinux label for this path, not following symlinks,
  274. // or returns an error.
  275. func lSetFileLabel(fpath string, label string) error {
  276. if fpath == "" {
  277. return ErrEmptyPath
  278. }
  279. for {
  280. err := unix.Lsetxattr(fpath, xattrNameSelinux, []byte(label), 0)
  281. if err == nil {
  282. break
  283. }
  284. if err != unix.EINTR { //nolint:errorlint // unix errors are bare
  285. return &os.PathError{Op: "lsetxattr", Path: fpath, Err: err}
  286. }
  287. }
  288. return nil
  289. }
  290. // setFileLabel sets the SELinux label for this path, following symlinks,
  291. // or returns an error.
  292. func setFileLabel(fpath string, label string) error {
  293. if fpath == "" {
  294. return ErrEmptyPath
  295. }
  296. for {
  297. err := unix.Setxattr(fpath, xattrNameSelinux, []byte(label), 0)
  298. if err == nil {
  299. break
  300. }
  301. if err != unix.EINTR { //nolint:errorlint // unix errors are bare
  302. return &os.PathError{Op: "setxattr", Path: fpath, Err: err}
  303. }
  304. }
  305. return nil
  306. }
  307. // fileLabel returns the SELinux label for this path, following symlinks,
  308. // or returns an error.
  309. func fileLabel(fpath string) (string, error) {
  310. if fpath == "" {
  311. return "", ErrEmptyPath
  312. }
  313. label, err := getxattr(fpath, xattrNameSelinux)
  314. if err != nil {
  315. return "", &os.PathError{Op: "getxattr", Path: fpath, Err: err}
  316. }
  317. // Trim the NUL byte at the end of the byte buffer, if present.
  318. if len(label) > 0 && label[len(label)-1] == '\x00' {
  319. label = label[:len(label)-1]
  320. }
  321. return string(label), nil
  322. }
  323. // lFileLabel returns the SELinux label for this path, not following symlinks,
  324. // or returns an error.
  325. func lFileLabel(fpath string) (string, error) {
  326. if fpath == "" {
  327. return "", ErrEmptyPath
  328. }
  329. label, err := lgetxattr(fpath, xattrNameSelinux)
  330. if err != nil {
  331. return "", &os.PathError{Op: "lgetxattr", Path: fpath, Err: err}
  332. }
  333. // Trim the NUL byte at the end of the byte buffer, if present.
  334. if len(label) > 0 && label[len(label)-1] == '\x00' {
  335. label = label[:len(label)-1]
  336. }
  337. return string(label), nil
  338. }
  339. // setFSCreateLabel tells kernel the label to create all file system objects
  340. // created by this task. Setting label="" to return to default.
  341. func setFSCreateLabel(label string) error {
  342. return writeAttr("fscreate", label)
  343. }
  344. // fsCreateLabel returns the default label the kernel which the kernel is using
  345. // for file system objects created by this task. "" indicates default.
  346. func fsCreateLabel() (string, error) {
  347. return readAttr("fscreate")
  348. }
  349. // currentLabel returns the SELinux label of the current process thread, or an error.
  350. func currentLabel() (string, error) {
  351. return readAttr("current")
  352. }
  353. // pidLabel returns the SELinux label of the given pid, or an error.
  354. func pidLabel(pid int) (string, error) {
  355. return readCon(fmt.Sprintf("/proc/%d/attr/current", pid))
  356. }
  357. // ExecLabel returns the SELinux label that the kernel will use for any programs
  358. // that are executed by the current process thread, or an error.
  359. func execLabel() (string, error) {
  360. return readAttr("exec")
  361. }
  362. func writeCon(fpath, val string) error {
  363. if fpath == "" {
  364. return ErrEmptyPath
  365. }
  366. if val == "" {
  367. if !getEnabled() {
  368. return nil
  369. }
  370. }
  371. out, err := os.OpenFile(fpath, os.O_WRONLY, 0)
  372. if err != nil {
  373. return err
  374. }
  375. defer out.Close()
  376. if err := isProcHandle(out); err != nil {
  377. return err
  378. }
  379. if val != "" {
  380. _, err = out.Write([]byte(val))
  381. } else {
  382. _, err = out.Write(nil)
  383. }
  384. if err != nil {
  385. return err
  386. }
  387. return nil
  388. }
  389. func attrPath(attr string) string {
  390. // Linux >= 3.17 provides this
  391. const threadSelfPrefix = "/proc/thread-self/attr"
  392. attrPathOnce.Do(func() {
  393. st, err := os.Stat(threadSelfPrefix)
  394. if err == nil && st.Mode().IsDir() {
  395. haveThreadSelf = true
  396. }
  397. })
  398. if haveThreadSelf {
  399. return path.Join(threadSelfPrefix, attr)
  400. }
  401. return path.Join("/proc/self/task/", strconv.Itoa(unix.Gettid()), "/attr/", attr)
  402. }
  403. func readAttr(attr string) (string, error) {
  404. return readCon(attrPath(attr))
  405. }
  406. func writeAttr(attr, val string) error {
  407. return writeCon(attrPath(attr), val)
  408. }
  409. // canonicalizeContext takes a context string and writes it to the kernel
  410. // the function then returns the context that the kernel will use. Use this
  411. // function to check if two contexts are equivalent
  412. func canonicalizeContext(val string) (string, error) {
  413. return readWriteCon(filepath.Join(getSelinuxMountPoint(), "context"), val)
  414. }
  415. // computeCreateContext requests the type transition from source to target for
  416. // class from the kernel.
  417. func computeCreateContext(source string, target string, class string) (string, error) {
  418. classidx, err := classIndex(class)
  419. if err != nil {
  420. return "", err
  421. }
  422. return readWriteCon(filepath.Join(getSelinuxMountPoint(), "create"), fmt.Sprintf("%s %s %d", source, target, classidx))
  423. }
  424. // catsToBitset stores categories in a bitset.
  425. func catsToBitset(cats string) (*big.Int, error) {
  426. bitset := new(big.Int)
  427. catlist := strings.Split(cats, ",")
  428. for _, r := range catlist {
  429. ranges := strings.SplitN(r, ".", 2)
  430. if len(ranges) > 1 {
  431. catstart, err := parseLevelItem(ranges[0], category)
  432. if err != nil {
  433. return nil, err
  434. }
  435. catend, err := parseLevelItem(ranges[1], category)
  436. if err != nil {
  437. return nil, err
  438. }
  439. for i := catstart; i <= catend; i++ {
  440. bitset.SetBit(bitset, int(i), 1)
  441. }
  442. } else {
  443. cat, err := parseLevelItem(ranges[0], category)
  444. if err != nil {
  445. return nil, err
  446. }
  447. bitset.SetBit(bitset, int(cat), 1)
  448. }
  449. }
  450. return bitset, nil
  451. }
  452. // parseLevelItem parses and verifies that a sensitivity or category are valid
  453. func parseLevelItem(s string, sep levelItem) (uint, error) {
  454. if len(s) < minSensLen || levelItem(s[0]) != sep {
  455. return 0, ErrLevelSyntax
  456. }
  457. val, err := strconv.ParseUint(s[1:], 10, 32)
  458. if err != nil {
  459. return 0, err
  460. }
  461. return uint(val), nil
  462. }
  463. // parseLevel fills a level from a string that contains
  464. // a sensitivity and categories
  465. func (l *level) parseLevel(levelStr string) error {
  466. lvl := strings.SplitN(levelStr, ":", 2)
  467. sens, err := parseLevelItem(lvl[0], sensitivity)
  468. if err != nil {
  469. return fmt.Errorf("failed to parse sensitivity: %w", err)
  470. }
  471. l.sens = sens
  472. if len(lvl) > 1 {
  473. cats, err := catsToBitset(lvl[1])
  474. if err != nil {
  475. return fmt.Errorf("failed to parse categories: %w", err)
  476. }
  477. l.cats = cats
  478. }
  479. return nil
  480. }
  481. // rangeStrToMLSRange marshals a string representation of a range.
  482. func rangeStrToMLSRange(rangeStr string) (*mlsRange, error) {
  483. mlsRange := &mlsRange{}
  484. levelSlice := strings.SplitN(rangeStr, "-", 2)
  485. switch len(levelSlice) {
  486. // rangeStr that has a low and a high level, e.g. s4:c0.c1023-s6:c0.c1023
  487. case 2:
  488. mlsRange.high = &level{}
  489. if err := mlsRange.high.parseLevel(levelSlice[1]); err != nil {
  490. return nil, fmt.Errorf("failed to parse high level %q: %w", levelSlice[1], err)
  491. }
  492. fallthrough
  493. // rangeStr that is single level, e.g. s6:c0,c3,c5,c30.c1023
  494. case 1:
  495. mlsRange.low = &level{}
  496. if err := mlsRange.low.parseLevel(levelSlice[0]); err != nil {
  497. return nil, fmt.Errorf("failed to parse low level %q: %w", levelSlice[0], err)
  498. }
  499. }
  500. if mlsRange.high == nil {
  501. mlsRange.high = mlsRange.low
  502. }
  503. return mlsRange, nil
  504. }
  505. // bitsetToStr takes a category bitset and returns it in the
  506. // canonical selinux syntax
  507. func bitsetToStr(c *big.Int) string {
  508. var str string
  509. length := 0
  510. for i := int(c.TrailingZeroBits()); i < c.BitLen(); i++ {
  511. if c.Bit(i) == 0 {
  512. continue
  513. }
  514. if length == 0 {
  515. if str != "" {
  516. str += ","
  517. }
  518. str += "c" + strconv.Itoa(i)
  519. }
  520. if c.Bit(i+1) == 1 {
  521. length++
  522. continue
  523. }
  524. if length == 1 {
  525. str += ",c" + strconv.Itoa(i)
  526. } else if length > 1 {
  527. str += ".c" + strconv.Itoa(i)
  528. }
  529. length = 0
  530. }
  531. return str
  532. }
  533. func (l1 *level) equal(l2 *level) bool {
  534. if l2 == nil || l1 == nil {
  535. return l1 == l2
  536. }
  537. if l1.sens != l2.sens {
  538. return false
  539. }
  540. if l2.cats == nil || l1.cats == nil {
  541. return l2.cats == l1.cats
  542. }
  543. return l1.cats.Cmp(l2.cats) == 0
  544. }
  545. // String returns an mlsRange as a string.
  546. func (m mlsRange) String() string {
  547. low := "s" + strconv.Itoa(int(m.low.sens))
  548. if m.low.cats != nil && m.low.cats.BitLen() > 0 {
  549. low += ":" + bitsetToStr(m.low.cats)
  550. }
  551. if m.low.equal(m.high) {
  552. return low
  553. }
  554. high := "s" + strconv.Itoa(int(m.high.sens))
  555. if m.high.cats != nil && m.high.cats.BitLen() > 0 {
  556. high += ":" + bitsetToStr(m.high.cats)
  557. }
  558. return low + "-" + high
  559. }
  560. func max(a, b uint) uint {
  561. if a > b {
  562. return a
  563. }
  564. return b
  565. }
  566. func min(a, b uint) uint {
  567. if a < b {
  568. return a
  569. }
  570. return b
  571. }
  572. // calculateGlbLub computes the glb (greatest lower bound) and lub (least upper bound)
  573. // of a source and target range.
  574. // The glblub is calculated as the greater of the low sensitivities and
  575. // the lower of the high sensitivities and the and of each category bitset.
  576. func calculateGlbLub(sourceRange, targetRange string) (string, error) {
  577. s, err := rangeStrToMLSRange(sourceRange)
  578. if err != nil {
  579. return "", err
  580. }
  581. t, err := rangeStrToMLSRange(targetRange)
  582. if err != nil {
  583. return "", err
  584. }
  585. if s.high.sens < t.low.sens || t.high.sens < s.low.sens {
  586. /* these ranges have no common sensitivities */
  587. return "", ErrIncomparable
  588. }
  589. outrange := &mlsRange{low: &level{}, high: &level{}}
  590. /* take the greatest of the low */
  591. outrange.low.sens = max(s.low.sens, t.low.sens)
  592. /* take the least of the high */
  593. outrange.high.sens = min(s.high.sens, t.high.sens)
  594. /* find the intersecting categories */
  595. if s.low.cats != nil && t.low.cats != nil {
  596. outrange.low.cats = new(big.Int)
  597. outrange.low.cats.And(s.low.cats, t.low.cats)
  598. }
  599. if s.high.cats != nil && t.high.cats != nil {
  600. outrange.high.cats = new(big.Int)
  601. outrange.high.cats.And(s.high.cats, t.high.cats)
  602. }
  603. return outrange.String(), nil
  604. }
  605. func readWriteCon(fpath string, val string) (string, error) {
  606. if fpath == "" {
  607. return "", ErrEmptyPath
  608. }
  609. f, err := os.OpenFile(fpath, os.O_RDWR, 0)
  610. if err != nil {
  611. return "", err
  612. }
  613. defer f.Close()
  614. _, err = f.Write([]byte(val))
  615. if err != nil {
  616. return "", err
  617. }
  618. return readConFd(f)
  619. }
  620. // setExecLabel sets the SELinux label that the kernel will use for any programs
  621. // that are executed by the current process thread, or an error.
  622. func setExecLabel(label string) error {
  623. return writeAttr("exec", label)
  624. }
  625. // setTaskLabel sets the SELinux label for the current thread, or an error.
  626. // This requires the dyntransition permission.
  627. func setTaskLabel(label string) error {
  628. return writeAttr("current", label)
  629. }
  630. // setSocketLabel takes a process label and tells the kernel to assign the
  631. // label to the next socket that gets created
  632. func setSocketLabel(label string) error {
  633. return writeAttr("sockcreate", label)
  634. }
  635. // socketLabel retrieves the current socket label setting
  636. func socketLabel() (string, error) {
  637. return readAttr("sockcreate")
  638. }
  639. // peerLabel retrieves the label of the client on the other side of a socket
  640. func peerLabel(fd uintptr) (string, error) {
  641. label, err := unix.GetsockoptString(int(fd), unix.SOL_SOCKET, unix.SO_PEERSEC)
  642. if err != nil {
  643. return "", &os.PathError{Op: "getsockopt", Path: "fd " + strconv.Itoa(int(fd)), Err: err}
  644. }
  645. return label, nil
  646. }
  647. // setKeyLabel takes a process label and tells the kernel to assign the
  648. // label to the next kernel keyring that gets created
  649. func setKeyLabel(label string) error {
  650. err := writeCon("/proc/self/attr/keycreate", label)
  651. if errors.Is(err, os.ErrNotExist) {
  652. return nil
  653. }
  654. if label == "" && errors.Is(err, os.ErrPermission) {
  655. return nil
  656. }
  657. return err
  658. }
  659. // keyLabel retrieves the current kernel keyring label setting
  660. func keyLabel() (string, error) {
  661. return readCon("/proc/self/attr/keycreate")
  662. }
  663. // get returns the Context as a string
  664. func (c Context) get() string {
  665. if level := c["level"]; level != "" {
  666. return c["user"] + ":" + c["role"] + ":" + c["type"] + ":" + level
  667. }
  668. return c["user"] + ":" + c["role"] + ":" + c["type"]
  669. }
  670. // newContext creates a new Context struct from the specified label
  671. func newContext(label string) (Context, error) {
  672. c := make(Context)
  673. if len(label) != 0 {
  674. con := strings.SplitN(label, ":", 4)
  675. if len(con) < 3 {
  676. return c, InvalidLabel
  677. }
  678. c["user"] = con[0]
  679. c["role"] = con[1]
  680. c["type"] = con[2]
  681. if len(con) > 3 {
  682. c["level"] = con[3]
  683. }
  684. }
  685. return c, nil
  686. }
  687. // clearLabels clears all reserved labels
  688. func clearLabels() {
  689. state.Lock()
  690. state.mcsList = make(map[string]bool)
  691. state.Unlock()
  692. }
  693. // reserveLabel reserves the MLS/MCS level component of the specified label
  694. func reserveLabel(label string) {
  695. if len(label) != 0 {
  696. con := strings.SplitN(label, ":", 4)
  697. if len(con) > 3 {
  698. _ = mcsAdd(con[3])
  699. }
  700. }
  701. }
  702. func selinuxEnforcePath() string {
  703. return path.Join(getSelinuxMountPoint(), "enforce")
  704. }
  705. // enforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
  706. func enforceMode() int {
  707. var enforce int
  708. enforceB, err := ioutil.ReadFile(selinuxEnforcePath())
  709. if err != nil {
  710. return -1
  711. }
  712. enforce, err = strconv.Atoi(string(enforceB))
  713. if err != nil {
  714. return -1
  715. }
  716. return enforce
  717. }
  718. // setEnforceMode sets the current SELinux mode Enforcing, Permissive.
  719. // Disabled is not valid, since this needs to be set at boot time.
  720. func setEnforceMode(mode int) error {
  721. return ioutil.WriteFile(selinuxEnforcePath(), []byte(strconv.Itoa(mode)), 0o644)
  722. }
  723. // defaultEnforceMode returns the systems default SELinux mode Enforcing,
  724. // Permissive or Disabled. Note this is is just the default at boot time.
  725. // EnforceMode tells you the systems current mode.
  726. func defaultEnforceMode() int {
  727. switch readConfig(selinuxTag) {
  728. case "enforcing":
  729. return Enforcing
  730. case "permissive":
  731. return Permissive
  732. }
  733. return Disabled
  734. }
  735. func mcsAdd(mcs string) error {
  736. if mcs == "" {
  737. return nil
  738. }
  739. state.Lock()
  740. defer state.Unlock()
  741. if state.mcsList[mcs] {
  742. return ErrMCSAlreadyExists
  743. }
  744. state.mcsList[mcs] = true
  745. return nil
  746. }
  747. func mcsDelete(mcs string) {
  748. if mcs == "" {
  749. return
  750. }
  751. state.Lock()
  752. defer state.Unlock()
  753. state.mcsList[mcs] = false
  754. }
  755. func intToMcs(id int, catRange uint32) string {
  756. var (
  757. SETSIZE = int(catRange)
  758. TIER = SETSIZE
  759. ORD = id
  760. )
  761. if id < 1 || id > 523776 {
  762. return ""
  763. }
  764. for ORD > TIER {
  765. ORD -= TIER
  766. TIER--
  767. }
  768. TIER = SETSIZE - TIER
  769. ORD += TIER
  770. return fmt.Sprintf("s0:c%d,c%d", TIER, ORD)
  771. }
  772. func uniqMcs(catRange uint32) string {
  773. var (
  774. n uint32
  775. c1, c2 uint32
  776. mcs string
  777. )
  778. for {
  779. _ = binary.Read(rand.Reader, binary.LittleEndian, &n)
  780. c1 = n % catRange
  781. _ = binary.Read(rand.Reader, binary.LittleEndian, &n)
  782. c2 = n % catRange
  783. if c1 == c2 {
  784. continue
  785. } else if c1 > c2 {
  786. c1, c2 = c2, c1
  787. }
  788. mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2)
  789. if err := mcsAdd(mcs); err != nil {
  790. continue
  791. }
  792. break
  793. }
  794. return mcs
  795. }
  796. // releaseLabel un-reserves the MLS/MCS Level field of the specified label,
  797. // allowing it to be used by another process.
  798. func releaseLabel(label string) {
  799. if len(label) != 0 {
  800. con := strings.SplitN(label, ":", 4)
  801. if len(con) > 3 {
  802. mcsDelete(con[3])
  803. }
  804. }
  805. }
  806. // roFileLabel returns the specified SELinux readonly file label
  807. func roFileLabel() string {
  808. return readOnlyFileLabel
  809. }
  810. func openContextFile() (*os.File, error) {
  811. if f, err := os.Open(contextFile); err == nil {
  812. return f, nil
  813. }
  814. return os.Open(filepath.Join(policyRoot(), "/contexts/lxc_contexts"))
  815. }
  816. func loadLabels() {
  817. labels = make(map[string]string)
  818. in, err := openContextFile()
  819. if err != nil {
  820. return
  821. }
  822. defer in.Close()
  823. scanner := bufio.NewScanner(in)
  824. for scanner.Scan() {
  825. line := bytes.TrimSpace(scanner.Bytes())
  826. if len(line) == 0 {
  827. // Skip blank lines
  828. continue
  829. }
  830. if line[0] == ';' || line[0] == '#' {
  831. // Skip comments
  832. continue
  833. }
  834. fields := bytes.SplitN(line, []byte{'='}, 2)
  835. if len(fields) != 2 {
  836. continue
  837. }
  838. key, val := bytes.TrimSpace(fields[0]), bytes.TrimSpace(fields[1])
  839. labels[string(key)] = string(bytes.Trim(val, `"`))
  840. }
  841. con, _ := NewContext(labels["file"])
  842. con["level"] = fmt.Sprintf("s0:c%d,c%d", maxCategory-2, maxCategory-1)
  843. privContainerMountLabel = con.get()
  844. reserveLabel(privContainerMountLabel)
  845. }
  846. func label(key string) string {
  847. loadLabelsOnce.Do(func() {
  848. loadLabels()
  849. })
  850. return labels[key]
  851. }
  852. // kvmContainerLabels returns the default processLabel and mountLabel to be used
  853. // for kvm containers by the calling process.
  854. func kvmContainerLabels() (string, string) {
  855. processLabel := label("kvm_process")
  856. if processLabel == "" {
  857. processLabel = label("process")
  858. }
  859. return addMcs(processLabel, label("file"))
  860. }
  861. // initContainerLabels returns the default processLabel and file labels to be
  862. // used for containers running an init system like systemd by the calling process.
  863. func initContainerLabels() (string, string) {
  864. processLabel := label("init_process")
  865. if processLabel == "" {
  866. processLabel = label("process")
  867. }
  868. return addMcs(processLabel, label("file"))
  869. }
  870. // containerLabels returns an allocated processLabel and fileLabel to be used for
  871. // container labeling by the calling process.
  872. func containerLabels() (processLabel string, fileLabel string) {
  873. if !getEnabled() {
  874. return "", ""
  875. }
  876. processLabel = label("process")
  877. fileLabel = label("file")
  878. readOnlyFileLabel = label("ro_file")
  879. if processLabel == "" || fileLabel == "" {
  880. return "", fileLabel
  881. }
  882. if readOnlyFileLabel == "" {
  883. readOnlyFileLabel = fileLabel
  884. }
  885. return addMcs(processLabel, fileLabel)
  886. }
  887. func addMcs(processLabel, fileLabel string) (string, string) {
  888. scon, _ := NewContext(processLabel)
  889. if scon["level"] != "" {
  890. mcs := uniqMcs(CategoryRange)
  891. scon["level"] = mcs
  892. processLabel = scon.Get()
  893. scon, _ = NewContext(fileLabel)
  894. scon["level"] = mcs
  895. fileLabel = scon.Get()
  896. }
  897. return processLabel, fileLabel
  898. }
  899. // securityCheckContext validates that the SELinux label is understood by the kernel
  900. func securityCheckContext(val string) error {
  901. return ioutil.WriteFile(path.Join(getSelinuxMountPoint(), "context"), []byte(val), 0o644)
  902. }
  903. // copyLevel returns a label with the MLS/MCS level from src label replaced on
  904. // the dest label.
  905. func copyLevel(src, dest string) (string, error) {
  906. if src == "" {
  907. return "", nil
  908. }
  909. if err := SecurityCheckContext(src); err != nil {
  910. return "", err
  911. }
  912. if err := SecurityCheckContext(dest); err != nil {
  913. return "", err
  914. }
  915. scon, err := NewContext(src)
  916. if err != nil {
  917. return "", err
  918. }
  919. tcon, err := NewContext(dest)
  920. if err != nil {
  921. return "", err
  922. }
  923. mcsDelete(tcon["level"])
  924. _ = mcsAdd(scon["level"])
  925. tcon["level"] = scon["level"]
  926. return tcon.Get(), nil
  927. }
  928. // chcon changes the fpath file object to the SELinux label label.
  929. // If fpath is a directory and recurse is true, then chcon walks the
  930. // directory tree setting the label.
  931. func chcon(fpath string, label string, recurse bool) error {
  932. if fpath == "" {
  933. return ErrEmptyPath
  934. }
  935. if label == "" {
  936. return nil
  937. }
  938. exclude_paths := map[string]bool{
  939. "/": true,
  940. "/bin": true,
  941. "/boot": true,
  942. "/dev": true,
  943. "/etc": true,
  944. "/etc/passwd": true,
  945. "/etc/pki": true,
  946. "/etc/shadow": true,
  947. "/home": true,
  948. "/lib": true,
  949. "/lib64": true,
  950. "/media": true,
  951. "/opt": true,
  952. "/proc": true,
  953. "/root": true,
  954. "/run": true,
  955. "/sbin": true,
  956. "/srv": true,
  957. "/sys": true,
  958. "/tmp": true,
  959. "/usr": true,
  960. "/var": true,
  961. "/var/lib": true,
  962. "/var/log": true,
  963. }
  964. if home := os.Getenv("HOME"); home != "" {
  965. exclude_paths[home] = true
  966. }
  967. if sudoUser := os.Getenv("SUDO_USER"); sudoUser != "" {
  968. if usr, err := user.Lookup(sudoUser); err == nil {
  969. exclude_paths[usr.HomeDir] = true
  970. }
  971. }
  972. if fpath != "/" {
  973. fpath = strings.TrimSuffix(fpath, "/")
  974. }
  975. if exclude_paths[fpath] {
  976. return fmt.Errorf("SELinux relabeling of %s is not allowed", fpath)
  977. }
  978. if !recurse {
  979. err := lSetFileLabel(fpath, label)
  980. if err != nil {
  981. // Check if file doesn't exist, must have been removed
  982. if errors.Is(err, os.ErrNotExist) {
  983. return nil
  984. }
  985. // Check if current label is correct on disk
  986. flabel, nerr := lFileLabel(fpath)
  987. if nerr == nil && flabel == label {
  988. return nil
  989. }
  990. // Check if file doesn't exist, must have been removed
  991. if errors.Is(nerr, os.ErrNotExist) {
  992. return nil
  993. }
  994. return err
  995. }
  996. return nil
  997. }
  998. return rchcon(fpath, label)
  999. }
  1000. // dupSecOpt takes an SELinux process label and returns security options that
  1001. // can be used to set the SELinux Type and Level for future container processes.
  1002. func dupSecOpt(src string) ([]string, error) {
  1003. if src == "" {
  1004. return nil, nil
  1005. }
  1006. con, err := NewContext(src)
  1007. if err != nil {
  1008. return nil, err
  1009. }
  1010. if con["user"] == "" ||
  1011. con["role"] == "" ||
  1012. con["type"] == "" {
  1013. return nil, nil
  1014. }
  1015. dup := []string{
  1016. "user:" + con["user"],
  1017. "role:" + con["role"],
  1018. "type:" + con["type"],
  1019. }
  1020. if con["level"] != "" {
  1021. dup = append(dup, "level:"+con["level"])
  1022. }
  1023. return dup, nil
  1024. }
  1025. // disableSecOpt returns a security opt that can be used to disable SELinux
  1026. // labeling support for future container processes.
  1027. func disableSecOpt() []string {
  1028. return []string{"disable"}
  1029. }
  1030. // findUserInContext scans the reader for a valid SELinux context
  1031. // match that is verified with the verifier. Invalid contexts are
  1032. // skipped. It returns a matched context or an empty string if no
  1033. // match is found. If a scanner error occurs, it is returned.
  1034. func findUserInContext(context Context, r io.Reader, verifier func(string) error) (string, error) {
  1035. fromRole := context["role"]
  1036. fromType := context["type"]
  1037. scanner := bufio.NewScanner(r)
  1038. for scanner.Scan() {
  1039. fromConns := strings.Fields(scanner.Text())
  1040. if len(fromConns) == 0 {
  1041. // Skip blank lines
  1042. continue
  1043. }
  1044. line := fromConns[0]
  1045. if line[0] == ';' || line[0] == '#' {
  1046. // Skip comments
  1047. continue
  1048. }
  1049. // user context files contexts are formatted as
  1050. // role_r:type_t:s0 where the user is missing.
  1051. lineArr := strings.SplitN(line, ":", 4)
  1052. // skip context with typo, or role and type do not match
  1053. if len(lineArr) != 3 ||
  1054. lineArr[0] != fromRole ||
  1055. lineArr[1] != fromType {
  1056. continue
  1057. }
  1058. for _, cc := range fromConns[1:] {
  1059. toConns := strings.SplitN(cc, ":", 4)
  1060. if len(toConns) != 3 {
  1061. continue
  1062. }
  1063. context["role"] = toConns[0]
  1064. context["type"] = toConns[1]
  1065. outConn := context.get()
  1066. if err := verifier(outConn); err != nil {
  1067. continue
  1068. }
  1069. return outConn, nil
  1070. }
  1071. }
  1072. if err := scanner.Err(); err != nil {
  1073. return "", fmt.Errorf("failed to scan for context: %w", err)
  1074. }
  1075. return "", nil
  1076. }
  1077. func getDefaultContextFromReaders(c *defaultSECtx) (string, error) {
  1078. if c.verifier == nil {
  1079. return "", ErrVerifierNil
  1080. }
  1081. context, err := newContext(c.scon)
  1082. if err != nil {
  1083. return "", fmt.Errorf("failed to create label for %s: %w", c.scon, err)
  1084. }
  1085. // set so the verifier validates the matched context with the provided user and level.
  1086. context["user"] = c.user
  1087. context["level"] = c.level
  1088. conn, err := findUserInContext(context, c.userRdr, c.verifier)
  1089. if err != nil {
  1090. return "", err
  1091. }
  1092. if conn != "" {
  1093. return conn, nil
  1094. }
  1095. conn, err = findUserInContext(context, c.defaultRdr, c.verifier)
  1096. if err != nil {
  1097. return "", err
  1098. }
  1099. if conn != "" {
  1100. return conn, nil
  1101. }
  1102. return "", fmt.Errorf("context %q not found: %w", c.scon, ErrContextMissing)
  1103. }
  1104. func getDefaultContextWithLevel(user, level, scon string) (string, error) {
  1105. userPath := filepath.Join(policyRoot(), selinuxUsersDir, user)
  1106. fu, err := os.Open(userPath)
  1107. if err != nil {
  1108. return "", err
  1109. }
  1110. defer fu.Close()
  1111. defaultPath := filepath.Join(policyRoot(), defaultContexts)
  1112. fd, err := os.Open(defaultPath)
  1113. if err != nil {
  1114. return "", err
  1115. }
  1116. defer fd.Close()
  1117. c := defaultSECtx{
  1118. user: user,
  1119. level: level,
  1120. scon: scon,
  1121. userRdr: fu,
  1122. defaultRdr: fd,
  1123. verifier: securityCheckContext,
  1124. }
  1125. return getDefaultContextFromReaders(&c)
  1126. }