(c *mountConfig, m mountEntry)
| 608 | } |
| 609 | |
| 610 | func mountToRootfs(c *mountConfig, m mountEntry) error { |
| 611 | defer func() { |
| 612 | if m.dstFile != nil { |
| 613 | _ = m.dstFile.Close() |
| 614 | m.dstFile = nil |
| 615 | } |
| 616 | }() |
| 617 | |
| 618 | // procfs and sysfs are special because we need to ensure they are actually |
| 619 | // mounted on a specific path in a container without any funny business. |
| 620 | switch m.Device { |
| 621 | case "proc", "sysfs": |
| 622 | // If the destination already exists and is not a directory, we bail |
| 623 | // out. This is to avoid mounting through a symlink or similar -- which |
| 624 | // has been a "fun" attack scenario in the past. |
| 625 | // TODO: This won't be necessary once we switch to libpathrs and we can |
| 626 | // stop all of these symlink-exchange attacks. |
| 627 | rootfs := c.root.Name() |
| 628 | dest := filepath.Clean(m.Destination) |
| 629 | if !pathrs.IsLexicallyInRoot(rootfs, dest) { |
| 630 | // Do not use securejoin as it resolves symlinks. |
| 631 | dest = filepath.Join(rootfs, dest) |
| 632 | } |
| 633 | if err := checkProcMount(rootfs, dest, m); err != nil { |
| 634 | return err |
| 635 | } |
| 636 | if fi, err := os.Lstat(dest); err != nil { |
| 637 | if !errors.Is(err, os.ErrNotExist) { |
| 638 | return err |
| 639 | } |
| 640 | } else if !fi.IsDir() { |
| 641 | return fmt.Errorf("filesystem %q must be mounted on ordinary directory", m.Device) |
| 642 | } |
| 643 | dstFile, err := pathrs.MkdirAllInRoot(c.root, dest, 0o755) |
| 644 | if err != nil { |
| 645 | return err |
| 646 | } |
| 647 | defer dstFile.Close() |
| 648 | // "proc" and "sys" mounts need special handling (without resolving the |
| 649 | // destination) to avoid attacks. |
| 650 | m.dstFile = dstFile |
| 651 | return m.mountPropagate(c.root, "") |
| 652 | } |
| 653 | |
| 654 | mountLabel := c.label |
| 655 | if err := m.createOpenMountpoint(c.root); err != nil { |
| 656 | return fmt.Errorf("create mountpoint for %s mount: %w", m.Destination, err) |
| 657 | } |
| 658 | |
| 659 | switch m.Device { |
| 660 | case "mqueue": |
| 661 | if err := m.mountPropagate(c.root, ""); err != nil { |
| 662 | return err |
| 663 | } |
| 664 | return utils.WithProcfdFile(m.dstFile, func(dstFd string) error { |
| 665 | return label.SetFileLabel(dstFd, mountLabel) |
| 666 | }) |
| 667 | case "tmpfs": |
no test coverage detected
searching dependent graphs…