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 }