rootfs_linux.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. // +build linux
  2. package libcontainer
  3. import (
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "os"
  8. "os/exec"
  9. "path"
  10. "path/filepath"
  11. "strings"
  12. "syscall"
  13. "time"
  14. "github.com/docker/docker/pkg/mount"
  15. "github.com/docker/docker/pkg/symlink"
  16. "github.com/opencontainers/runc/libcontainer/cgroups"
  17. "github.com/opencontainers/runc/libcontainer/configs"
  18. "github.com/opencontainers/runc/libcontainer/label"
  19. "github.com/opencontainers/runc/libcontainer/system"
  20. libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils"
  21. )
  22. const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
  23. // setupDev returns true if /dev needs to be set up.
  24. func needsSetupDev(config *configs.Config) bool {
  25. for _, m := range config.Mounts {
  26. if m.Device == "bind" && (m.Destination == "/dev" || m.Destination == "/dev/") {
  27. return false
  28. }
  29. }
  30. return true
  31. }
  32. // setupRootfs sets up the devices, mount points, and filesystems for use inside a
  33. // new mount namespace.
  34. func setupRootfs(config *configs.Config, console *linuxConsole, pipe io.ReadWriter) (err error) {
  35. if err := prepareRoot(config); err != nil {
  36. return newSystemError(err)
  37. }
  38. setupDev := needsSetupDev(config)
  39. for _, m := range config.Mounts {
  40. for _, precmd := range m.PremountCmds {
  41. if err := mountCmd(precmd); err != nil {
  42. return newSystemError(err)
  43. }
  44. }
  45. if err := mountToRootfs(m, config.Rootfs, config.MountLabel); err != nil {
  46. return newSystemError(err)
  47. }
  48. for _, postcmd := range m.PostmountCmds {
  49. if err := mountCmd(postcmd); err != nil {
  50. return newSystemError(err)
  51. }
  52. }
  53. }
  54. if setupDev {
  55. if err := createDevices(config); err != nil {
  56. return newSystemError(err)
  57. }
  58. if err := setupPtmx(config, console); err != nil {
  59. return newSystemError(err)
  60. }
  61. if err := setupDevSymlinks(config.Rootfs); err != nil {
  62. return newSystemError(err)
  63. }
  64. }
  65. // Signal the parent to run the pre-start hooks.
  66. // The hooks are run after the mounts are setup, but before we switch to the new
  67. // root, so that the old root is still available in the hooks for any mount
  68. // manipulations.
  69. if err := syncParentHooks(pipe); err != nil {
  70. return err
  71. }
  72. if err := syscall.Chdir(config.Rootfs); err != nil {
  73. return newSystemError(err)
  74. }
  75. if config.NoPivotRoot {
  76. err = msMoveRoot(config.Rootfs)
  77. } else {
  78. err = pivotRoot(config.Rootfs, config.PivotDir)
  79. }
  80. if err != nil {
  81. return newSystemError(err)
  82. }
  83. if setupDev {
  84. if err := reOpenDevNull(); err != nil {
  85. return newSystemError(err)
  86. }
  87. }
  88. // remount dev as ro if specifed
  89. for _, m := range config.Mounts {
  90. if m.Destination == "/dev" {
  91. if m.Flags&syscall.MS_RDONLY != 0 {
  92. if err := remountReadonly(m.Destination); err != nil {
  93. return newSystemError(err)
  94. }
  95. }
  96. break
  97. }
  98. }
  99. // set rootfs ( / ) as readonly
  100. if config.Readonlyfs {
  101. if err := setReadonly(); err != nil {
  102. return newSystemError(err)
  103. }
  104. }
  105. syscall.Umask(0022)
  106. return nil
  107. }
  108. func mountCmd(cmd configs.Command) error {
  109. command := exec.Command(cmd.Path, cmd.Args[:]...)
  110. command.Env = cmd.Env
  111. command.Dir = cmd.Dir
  112. if out, err := command.CombinedOutput(); err != nil {
  113. return fmt.Errorf("%#v failed: %s: %v", cmd, string(out), err)
  114. }
  115. return nil
  116. }
  117. func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
  118. var (
  119. dest = m.Destination
  120. )
  121. if !strings.HasPrefix(dest, rootfs) {
  122. dest = filepath.Join(rootfs, dest)
  123. }
  124. switch m.Device {
  125. case "proc", "sysfs":
  126. if err := os.MkdirAll(dest, 0755); err != nil {
  127. return err
  128. }
  129. // Selinux kernels do not support labeling of /proc or /sys
  130. return mountPropagate(m, rootfs, "")
  131. case "mqueue":
  132. if err := os.MkdirAll(dest, 0755); err != nil {
  133. return err
  134. }
  135. if err := mountPropagate(m, rootfs, mountLabel); err != nil {
  136. // older kernels do not support labeling of /dev/mqueue
  137. if err := mountPropagate(m, rootfs, ""); err != nil {
  138. return err
  139. }
  140. return label.SetFileLabel(dest, mountLabel)
  141. }
  142. return nil
  143. case "tmpfs":
  144. stat, err := os.Stat(dest)
  145. if err != nil {
  146. if err := os.MkdirAll(dest, 0755); err != nil {
  147. return err
  148. }
  149. }
  150. if err := mountPropagate(m, rootfs, mountLabel); err != nil {
  151. return err
  152. }
  153. if stat != nil {
  154. if err = os.Chmod(dest, stat.Mode()); err != nil {
  155. return err
  156. }
  157. }
  158. return nil
  159. case "bind":
  160. stat, err := os.Stat(m.Source)
  161. if err != nil {
  162. // error out if the source of a bind mount does not exist as we will be
  163. // unable to bind anything to it.
  164. return err
  165. }
  166. // ensure that the destination of the bind mount is resolved of symlinks at mount time because
  167. // any previous mounts can invalidate the next mount's destination.
  168. // this can happen when a user specifies mounts within other mounts to cause breakouts or other
  169. // evil stuff to try to escape the container's rootfs.
  170. if dest, err = symlink.FollowSymlinkInScope(filepath.Join(rootfs, m.Destination), rootfs); err != nil {
  171. return err
  172. }
  173. if err := checkMountDestination(rootfs, dest); err != nil {
  174. return err
  175. }
  176. // update the mount with the correct dest after symlinks are resolved.
  177. m.Destination = dest
  178. if err := createIfNotExists(dest, stat.IsDir()); err != nil {
  179. return err
  180. }
  181. if err := mountPropagate(m, rootfs, mountLabel); err != nil {
  182. return err
  183. }
  184. // bind mount won't change mount options, we need remount to make mount options effective.
  185. // first check that we have non-default options required before attempting a remount
  186. if m.Flags&^(syscall.MS_REC|syscall.MS_REMOUNT|syscall.MS_BIND) != 0 {
  187. // only remount if unique mount options are set
  188. if err := remount(m, rootfs); err != nil {
  189. return err
  190. }
  191. }
  192. if m.Relabel != "" {
  193. if err := label.Validate(m.Relabel); err != nil {
  194. return err
  195. }
  196. shared := label.IsShared(m.Relabel)
  197. if err := label.Relabel(m.Source, mountLabel, shared); err != nil {
  198. return err
  199. }
  200. }
  201. case "cgroup":
  202. binds, err := getCgroupMounts(m)
  203. if err != nil {
  204. return err
  205. }
  206. var merged []string
  207. for _, b := range binds {
  208. ss := filepath.Base(b.Destination)
  209. if strings.Contains(ss, ",") {
  210. merged = append(merged, ss)
  211. }
  212. }
  213. tmpfs := &configs.Mount{
  214. Source: "tmpfs",
  215. Device: "tmpfs",
  216. Destination: m.Destination,
  217. Flags: defaultMountFlags,
  218. Data: "mode=755",
  219. PropagationFlags: m.PropagationFlags,
  220. }
  221. if err := mountToRootfs(tmpfs, rootfs, mountLabel); err != nil {
  222. return err
  223. }
  224. for _, b := range binds {
  225. if err := mountToRootfs(b, rootfs, mountLabel); err != nil {
  226. return err
  227. }
  228. }
  229. // create symlinks for merged cgroups
  230. cwd, err := os.Getwd()
  231. if err != nil {
  232. return err
  233. }
  234. if err := os.Chdir(filepath.Join(rootfs, m.Destination)); err != nil {
  235. return err
  236. }
  237. for _, mc := range merged {
  238. for _, ss := range strings.Split(mc, ",") {
  239. if err := os.Symlink(mc, ss); err != nil {
  240. // if cgroup already exists, then okay(it could have been created before)
  241. if os.IsExist(err) {
  242. continue
  243. }
  244. os.Chdir(cwd)
  245. return err
  246. }
  247. }
  248. }
  249. if err := os.Chdir(cwd); err != nil {
  250. return err
  251. }
  252. if m.Flags&syscall.MS_RDONLY != 0 {
  253. // remount cgroup root as readonly
  254. mcgrouproot := &configs.Mount{
  255. Destination: m.Destination,
  256. Flags: defaultMountFlags | syscall.MS_RDONLY,
  257. }
  258. if err := remount(mcgrouproot, rootfs); err != nil {
  259. return err
  260. }
  261. }
  262. default:
  263. if err := os.MkdirAll(dest, 0755); err != nil {
  264. return err
  265. }
  266. return mountPropagate(m, rootfs, mountLabel)
  267. }
  268. return nil
  269. }
  270. func getCgroupMounts(m *configs.Mount) ([]*configs.Mount, error) {
  271. mounts, err := cgroups.GetCgroupMounts()
  272. if err != nil {
  273. return nil, err
  274. }
  275. cgroupPaths, err := cgroups.ParseCgroupFile("/proc/self/cgroup")
  276. if err != nil {
  277. return nil, err
  278. }
  279. var binds []*configs.Mount
  280. for _, mm := range mounts {
  281. dir, err := mm.GetThisCgroupDir(cgroupPaths)
  282. if err != nil {
  283. return nil, err
  284. }
  285. relDir, err := filepath.Rel(mm.Root, dir)
  286. if err != nil {
  287. return nil, err
  288. }
  289. binds = append(binds, &configs.Mount{
  290. Device: "bind",
  291. Source: filepath.Join(mm.Mountpoint, relDir),
  292. Destination: filepath.Join(m.Destination, strings.Join(mm.Subsystems, ",")),
  293. Flags: syscall.MS_BIND | syscall.MS_REC | m.Flags,
  294. PropagationFlags: m.PropagationFlags,
  295. })
  296. }
  297. return binds, nil
  298. }
  299. // checkMountDestination checks to ensure that the mount destination is not over the top of /proc.
  300. // dest is required to be an abs path and have any symlinks resolved before calling this function.
  301. func checkMountDestination(rootfs, dest string) error {
  302. if libcontainerUtils.CleanPath(rootfs) == libcontainerUtils.CleanPath(dest) {
  303. return fmt.Errorf("mounting into / is prohibited")
  304. }
  305. invalidDestinations := []string{
  306. "/proc",
  307. }
  308. // White list, it should be sub directories of invalid destinations
  309. validDestinations := []string{
  310. // These entries can be bind mounted by files emulated by fuse,
  311. // so commands like top, free displays stats in container.
  312. "/proc/cpuinfo",
  313. "/proc/diskstats",
  314. "/proc/meminfo",
  315. "/proc/stat",
  316. "/proc/net/dev",
  317. }
  318. for _, valid := range validDestinations {
  319. path, err := filepath.Rel(filepath.Join(rootfs, valid), dest)
  320. if err != nil {
  321. return err
  322. }
  323. if path == "." {
  324. return nil
  325. }
  326. }
  327. for _, invalid := range invalidDestinations {
  328. path, err := filepath.Rel(filepath.Join(rootfs, invalid), dest)
  329. if err != nil {
  330. return err
  331. }
  332. if path == "." || !strings.HasPrefix(path, "..") {
  333. return fmt.Errorf("%q cannot be mounted because it is located inside %q", dest, invalid)
  334. }
  335. }
  336. return nil
  337. }
  338. func setupDevSymlinks(rootfs string) error {
  339. var links = [][2]string{
  340. {"/proc/self/fd", "/dev/fd"},
  341. {"/proc/self/fd/0", "/dev/stdin"},
  342. {"/proc/self/fd/1", "/dev/stdout"},
  343. {"/proc/self/fd/2", "/dev/stderr"},
  344. }
  345. // kcore support can be toggled with CONFIG_PROC_KCORE; only create a symlink
  346. // in /dev if it exists in /proc.
  347. if _, err := os.Stat("/proc/kcore"); err == nil {
  348. links = append(links, [2]string{"/proc/kcore", "/dev/core"})
  349. }
  350. for _, link := range links {
  351. var (
  352. src = link[0]
  353. dst = filepath.Join(rootfs, link[1])
  354. )
  355. if err := os.Symlink(src, dst); err != nil && !os.IsExist(err) {
  356. return fmt.Errorf("symlink %s %s %s", src, dst, err)
  357. }
  358. }
  359. return nil
  360. }
  361. // If stdin, stdout, and/or stderr are pointing to `/dev/null` in the parent's rootfs
  362. // this method will make them point to `/dev/null` in this container's rootfs. This
  363. // needs to be called after we chroot/pivot into the container's rootfs so that any
  364. // symlinks are resolved locally.
  365. func reOpenDevNull() error {
  366. var stat, devNullStat syscall.Stat_t
  367. file, err := os.OpenFile("/dev/null", os.O_RDWR, 0)
  368. if err != nil {
  369. return fmt.Errorf("Failed to open /dev/null - %s", err)
  370. }
  371. defer file.Close()
  372. if err := syscall.Fstat(int(file.Fd()), &devNullStat); err != nil {
  373. return err
  374. }
  375. for fd := 0; fd < 3; fd++ {
  376. if err := syscall.Fstat(fd, &stat); err != nil {
  377. return err
  378. }
  379. if stat.Rdev == devNullStat.Rdev {
  380. // Close and re-open the fd.
  381. if err := syscall.Dup3(int(file.Fd()), fd, 0); err != nil {
  382. return err
  383. }
  384. }
  385. }
  386. return nil
  387. }
  388. // Create the device nodes in the container.
  389. func createDevices(config *configs.Config) error {
  390. useBindMount := system.RunningInUserNS() || config.Namespaces.Contains(configs.NEWUSER)
  391. oldMask := syscall.Umask(0000)
  392. for _, node := range config.Devices {
  393. // containers running in a user namespace are not allowed to mknod
  394. // devices so we can just bind mount it from the host.
  395. if err := createDeviceNode(config.Rootfs, node, useBindMount); err != nil {
  396. syscall.Umask(oldMask)
  397. return err
  398. }
  399. }
  400. syscall.Umask(oldMask)
  401. return nil
  402. }
  403. func bindMountDeviceNode(dest string, node *configs.Device) error {
  404. f, err := os.Create(dest)
  405. if err != nil && !os.IsExist(err) {
  406. return err
  407. }
  408. if f != nil {
  409. f.Close()
  410. }
  411. return syscall.Mount(node.Path, dest, "bind", syscall.MS_BIND, "")
  412. }
  413. // Creates the device node in the rootfs of the container.
  414. func createDeviceNode(rootfs string, node *configs.Device, bind bool) error {
  415. dest := filepath.Join(rootfs, node.Path)
  416. if err := os.MkdirAll(filepath.Dir(dest), 0755); err != nil {
  417. return err
  418. }
  419. if bind {
  420. return bindMountDeviceNode(dest, node)
  421. }
  422. if err := mknodDevice(dest, node); err != nil {
  423. if os.IsExist(err) {
  424. return nil
  425. } else if os.IsPermission(err) {
  426. return bindMountDeviceNode(dest, node)
  427. }
  428. return err
  429. }
  430. return nil
  431. }
  432. func mknodDevice(dest string, node *configs.Device) error {
  433. fileMode := node.FileMode
  434. switch node.Type {
  435. case 'c':
  436. fileMode |= syscall.S_IFCHR
  437. case 'b':
  438. fileMode |= syscall.S_IFBLK
  439. default:
  440. return fmt.Errorf("%c is not a valid device type for device %s", node.Type, node.Path)
  441. }
  442. if err := syscall.Mknod(dest, uint32(fileMode), node.Mkdev()); err != nil {
  443. return err
  444. }
  445. return syscall.Chown(dest, int(node.Uid), int(node.Gid))
  446. }
  447. func getMountInfo(mountinfo []*mount.Info, dir string) *mount.Info {
  448. for _, m := range mountinfo {
  449. if m.Mountpoint == dir {
  450. return m
  451. }
  452. }
  453. return nil
  454. }
  455. // Get the parent mount point of directory passed in as argument. Also return
  456. // optional fields.
  457. func getParentMount(rootfs string) (string, string, error) {
  458. var path string
  459. mountinfos, err := mount.GetMounts()
  460. if err != nil {
  461. return "", "", err
  462. }
  463. mountinfo := getMountInfo(mountinfos, rootfs)
  464. if mountinfo != nil {
  465. return rootfs, mountinfo.Optional, nil
  466. }
  467. path = rootfs
  468. for {
  469. path = filepath.Dir(path)
  470. mountinfo = getMountInfo(mountinfos, path)
  471. if mountinfo != nil {
  472. return path, mountinfo.Optional, nil
  473. }
  474. if path == "/" {
  475. break
  476. }
  477. }
  478. // If we are here, we did not find parent mount. Something is wrong.
  479. return "", "", fmt.Errorf("Could not find parent mount of %s", rootfs)
  480. }
  481. // Make parent mount private if it was shared
  482. func rootfsParentMountPrivate(config *configs.Config) error {
  483. sharedMount := false
  484. parentMount, optionalOpts, err := getParentMount(config.Rootfs)
  485. if err != nil {
  486. return err
  487. }
  488. optsSplit := strings.Split(optionalOpts, " ")
  489. for _, opt := range optsSplit {
  490. if strings.HasPrefix(opt, "shared:") {
  491. sharedMount = true
  492. break
  493. }
  494. }
  495. // Make parent mount PRIVATE if it was shared. It is needed for two
  496. // reasons. First of all pivot_root() will fail if parent mount is
  497. // shared. Secondly when we bind mount rootfs it will propagate to
  498. // parent namespace and we don't want that to happen.
  499. if sharedMount {
  500. return syscall.Mount("", parentMount, "", syscall.MS_PRIVATE, "")
  501. }
  502. return nil
  503. }
  504. func prepareRoot(config *configs.Config) error {
  505. flag := syscall.MS_SLAVE | syscall.MS_REC
  506. if config.RootPropagation != 0 {
  507. flag = config.RootPropagation
  508. }
  509. if err := syscall.Mount("", "/", "", uintptr(flag), ""); err != nil {
  510. return err
  511. }
  512. if err := rootfsParentMountPrivate(config); err != nil {
  513. return err
  514. }
  515. return syscall.Mount(config.Rootfs, config.Rootfs, "bind", syscall.MS_BIND|syscall.MS_REC, "")
  516. }
  517. func setReadonly() error {
  518. return syscall.Mount("/", "/", "bind", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC, "")
  519. }
  520. func setupPtmx(config *configs.Config, console *linuxConsole) error {
  521. ptmx := filepath.Join(config.Rootfs, "dev/ptmx")
  522. if err := os.Remove(ptmx); err != nil && !os.IsNotExist(err) {
  523. return err
  524. }
  525. if err := os.Symlink("pts/ptmx", ptmx); err != nil {
  526. return fmt.Errorf("symlink dev ptmx %s", err)
  527. }
  528. if console != nil {
  529. return console.mount(config.Rootfs, config.MountLabel)
  530. }
  531. return nil
  532. }
  533. func pivotRoot(rootfs, pivotBaseDir string) (err error) {
  534. if pivotBaseDir == "" {
  535. pivotBaseDir = "/"
  536. }
  537. tmpDir := filepath.Join(rootfs, pivotBaseDir)
  538. if err := os.MkdirAll(tmpDir, 0755); err != nil {
  539. return fmt.Errorf("can't create tmp dir %s, error %v", tmpDir, err)
  540. }
  541. pivotDir, err := ioutil.TempDir(tmpDir, ".pivot_root")
  542. if err != nil {
  543. return fmt.Errorf("can't create pivot_root dir %s, error %v", pivotDir, err)
  544. }
  545. defer func() {
  546. errVal := os.Remove(pivotDir)
  547. if err == nil {
  548. err = errVal
  549. }
  550. }()
  551. if err := syscall.PivotRoot(rootfs, pivotDir); err != nil {
  552. return fmt.Errorf("pivot_root %s", err)
  553. }
  554. if err := syscall.Chdir("/"); err != nil {
  555. return fmt.Errorf("chdir / %s", err)
  556. }
  557. // path to pivot dir now changed, update
  558. pivotDir = filepath.Join(pivotBaseDir, filepath.Base(pivotDir))
  559. // Make pivotDir rprivate to make sure any of the unmounts don't
  560. // propagate to parent.
  561. if err := syscall.Mount("", pivotDir, "", syscall.MS_PRIVATE|syscall.MS_REC, ""); err != nil {
  562. return err
  563. }
  564. if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil {
  565. return fmt.Errorf("unmount pivot_root dir %s", err)
  566. }
  567. return nil
  568. }
  569. func msMoveRoot(rootfs string) error {
  570. if err := syscall.Mount(rootfs, "/", "", syscall.MS_MOVE, ""); err != nil {
  571. return err
  572. }
  573. if err := syscall.Chroot("."); err != nil {
  574. return err
  575. }
  576. return syscall.Chdir("/")
  577. }
  578. // createIfNotExists creates a file or a directory only if it does not already exist.
  579. func createIfNotExists(path string, isDir bool) error {
  580. if _, err := os.Stat(path); err != nil {
  581. if os.IsNotExist(err) {
  582. if isDir {
  583. return os.MkdirAll(path, 0755)
  584. }
  585. if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
  586. return err
  587. }
  588. f, err := os.OpenFile(path, os.O_CREATE, 0755)
  589. if err != nil {
  590. return err
  591. }
  592. f.Close()
  593. }
  594. }
  595. return nil
  596. }
  597. // remountReadonly will bind over the top of an existing path and ensure that it is read-only.
  598. func remountReadonly(path string) error {
  599. for i := 0; i < 5; i++ {
  600. if err := syscall.Mount("", path, "", syscall.MS_REMOUNT|syscall.MS_RDONLY, ""); err != nil && !os.IsNotExist(err) {
  601. switch err {
  602. case syscall.EINVAL:
  603. // Probably not a mountpoint, use bind-mount
  604. if err := syscall.Mount(path, path, "", syscall.MS_BIND, ""); err != nil {
  605. return err
  606. }
  607. return syscall.Mount(path, path, "", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC|defaultMountFlags, "")
  608. case syscall.EBUSY:
  609. time.Sleep(100 * time.Millisecond)
  610. continue
  611. default:
  612. return err
  613. }
  614. }
  615. return nil
  616. }
  617. return fmt.Errorf("unable to mount %s as readonly max retries reached", path)
  618. }
  619. // maskFile bind mounts /dev/null over the top of the specified path inside a container
  620. // to avoid security issues from processes reading information from non-namespace aware mounts ( proc/kcore ).
  621. func maskFile(path string) error {
  622. if err := syscall.Mount("/dev/null", path, "", syscall.MS_BIND, ""); err != nil && !os.IsNotExist(err) {
  623. return err
  624. }
  625. return nil
  626. }
  627. // writeSystemProperty writes the value to a path under /proc/sys as determined from the key.
  628. // For e.g. net.ipv4.ip_forward translated to /proc/sys/net/ipv4/ip_forward.
  629. func writeSystemProperty(key, value string) error {
  630. keyPath := strings.Replace(key, ".", "/", -1)
  631. return ioutil.WriteFile(path.Join("/proc/sys", keyPath), []byte(value), 0644)
  632. }
  633. func remount(m *configs.Mount, rootfs string) error {
  634. var (
  635. dest = m.Destination
  636. )
  637. if !strings.HasPrefix(dest, rootfs) {
  638. dest = filepath.Join(rootfs, dest)
  639. }
  640. if err := syscall.Mount(m.Source, dest, m.Device, uintptr(m.Flags|syscall.MS_REMOUNT), ""); err != nil {
  641. return err
  642. }
  643. return nil
  644. }
  645. // Do the mount operation followed by additional mounts required to take care
  646. // of propagation flags.
  647. func mountPropagate(m *configs.Mount, rootfs string, mountLabel string) error {
  648. var (
  649. dest = m.Destination
  650. data = label.FormatMountLabel(m.Data, mountLabel)
  651. flags = m.Flags
  652. )
  653. if dest == "/dev" {
  654. flags &= ^syscall.MS_RDONLY
  655. }
  656. if !strings.HasPrefix(dest, rootfs) {
  657. dest = filepath.Join(rootfs, dest)
  658. }
  659. if err := syscall.Mount(m.Source, dest, m.Device, uintptr(flags), data); err != nil {
  660. return err
  661. }
  662. for _, pflag := range m.PropagationFlags {
  663. if err := syscall.Mount("", dest, "", uintptr(pflag), ""); err != nil {
  664. return err
  665. }
  666. }
  667. return nil
  668. }