goCreateMountSources spawns a goroutine which creates open_tree(2)-style mountfds based on the requested configs.Mount configuration. The returned requestFn and cancelFn are used to interact with the goroutine. The caller of the returned mountSourceRequestFn is responsible for closing the returned
(ctx context.Context)
| 679 | // The caller of the returned mountSourceRequestFn is responsible for closing |
| 680 | // the returned file. |
| 681 | func (p *initProcess) goCreateMountSources(ctx context.Context) (mountSourceRequestFn, context.CancelFunc, error) { |
| 682 | type response struct { |
| 683 | src *mountSource |
| 684 | err error |
| 685 | } |
| 686 | |
| 687 | errCh := make(chan error, 1) |
| 688 | requestCh := make(chan *configs.Mount) |
| 689 | responseCh := make(chan response) |
| 690 | |
| 691 | ctx, cancelFn := context.WithTimeout(ctx, 1*time.Minute) |
| 692 | context.AfterFunc(ctx, func() { close(requestCh) }) |
| 693 | |
| 694 | go func() { |
| 695 | // We lock this thread because we need to setns(2) here. There is no |
| 696 | // UnlockOSThread() here, to ensure that the Go runtime will kill this |
| 697 | // thread once this goroutine returns (ensuring no other goroutines run |
| 698 | // in this context). |
| 699 | runtime.LockOSThread() |
| 700 | |
| 701 | // Detach from the shared fs of the rest of the Go process in order to |
| 702 | // be able to CLONE_NEWNS. |
| 703 | if err := unix.Unshare(unix.CLONE_FS); err != nil { |
| 704 | err = os.NewSyscallError("unshare(CLONE_FS)", err) |
| 705 | errCh <- fmt.Errorf("mount source thread: %w", err) |
| 706 | return |
| 707 | } |
| 708 | |
| 709 | // Attach to the container's mount namespace. |
| 710 | nsFd, err := os.Open(fmt.Sprintf("/proc/%d/ns/mnt", p.pid())) |
| 711 | if err != nil { |
| 712 | errCh <- fmt.Errorf("mount source thread: open container mntns: %w", err) |
| 713 | return |
| 714 | } |
| 715 | defer nsFd.Close() |
| 716 | if err := unix.Setns(int(nsFd.Fd()), unix.CLONE_NEWNS); err != nil { |
| 717 | err = os.NewSyscallError("setns", err) |
| 718 | errCh <- fmt.Errorf("mount source thread: join container mntns: %w", err) |
| 719 | return |
| 720 | } |
| 721 | |
| 722 | // No errors during setup! |
| 723 | close(errCh) |
| 724 | logrus.Debugf("mount source thread: successfully running in container mntns") |
| 725 | |
| 726 | nsHandles := new(userns.Handles) |
| 727 | defer nsHandles.Release() |
| 728 | loop: |
| 729 | for { |
| 730 | select { |
| 731 | case m, ok := <-requestCh: |
| 732 | if !ok { |
| 733 | break loop |
| 734 | } |
| 735 | src, err := mountFd(nsHandles, m) |
| 736 | logrus.Debugf("mount source thread: handling request for %q: %v %v", m.Source, src, err) |
| 737 | responseCh <- response{ |
| 738 | src: src, |