github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/contrib/cmd/fs-idmap/fs-idmap.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"os/exec"
     7  	"syscall"
     8  
     9  	"golang.org/x/sys/unix"
    10  )
    11  
    12  func main() {
    13  	if len(os.Args) != 2 {
    14  		fmt.Fprintln(os.Stderr, "usage:", os.Args[0], "path_to_mount_set_attr")
    15  		os.Exit(1)
    16  	}
    17  	src := os.Args[1]
    18  	if err := supportsIDMap(src); err != nil {
    19  		fmt.Fprintln(os.Stderr, "fatal error:", err)
    20  		os.Exit(1)
    21  	}
    22  }
    23  
    24  func supportsIDMap(src string) error {
    25  	treeFD, err := unix.OpenTree(unix.AT_FDCWD, src, uint(unix.OPEN_TREE_CLONE|unix.OPEN_TREE_CLOEXEC|unix.AT_EMPTY_PATH))
    26  	if err != nil {
    27  		return fmt.Errorf("error calling open_tree %q: %w", src, err)
    28  	}
    29  	defer unix.Close(treeFD)
    30  
    31  	cmd := exec.Command("sleep", "5")
    32  	cmd.SysProcAttr = &syscall.SysProcAttr{
    33  		Cloneflags:  syscall.CLONE_NEWUSER,
    34  		UidMappings: []syscall.SysProcIDMap{{ContainerID: 0, HostID: 65536, Size: 65536}},
    35  		GidMappings: []syscall.SysProcIDMap{{ContainerID: 0, HostID: 65536, Size: 65536}},
    36  	}
    37  	if err := cmd.Start(); err != nil {
    38  		return fmt.Errorf("failed to run the helper binary: %w", err)
    39  	}
    40  	defer func() {
    41  		_ = cmd.Process.Kill()
    42  		_ = cmd.Wait()
    43  	}()
    44  
    45  	path := fmt.Sprintf("/proc/%d/ns/user", cmd.Process.Pid)
    46  	var userNsFile *os.File
    47  	if userNsFile, err = os.Open(path); err != nil {
    48  		return fmt.Errorf("unable to get user ns file descriptor: %w", err)
    49  	}
    50  	defer userNsFile.Close()
    51  
    52  	attr := unix.MountAttr{
    53  		Attr_set:  unix.MOUNT_ATTR_IDMAP,
    54  		Userns_fd: uint64(userNsFile.Fd()),
    55  	}
    56  	if err := unix.MountSetattr(treeFD, "", unix.AT_EMPTY_PATH, &attr); err != nil {
    57  		return fmt.Errorf("error calling mount_setattr: %w", err)
    58  	}
    59  
    60  	return nil
    61  }