|
4 | 4 | package cniprovider
|
5 | 5 |
|
6 | 6 | import (
|
| 7 | + "fmt" |
7 | 8 | "os"
|
8 | 9 | "path/filepath"
|
| 10 | + "runtime" |
9 | 11 | "syscall"
|
10 |
| - "unsafe" |
11 | 12 |
|
12 | 13 | "github.com/containerd/containerd/oci"
|
13 | 14 | "github.com/moby/buildkit/util/bklog"
|
@@ -38,63 +39,51 @@ func cleanOldNamespaces(c *cniProvider) {
|
38 | 39 | }()
|
39 | 40 | }
|
40 | 41 |
|
41 |
| -func createNetNS(c *cniProvider, id string) (string, error) { |
| 42 | +// unshareAndMount needs to be called in a separate thread |
| 43 | +func unshareAndMountNetNS(target string) error { |
| 44 | + if err := syscall.Unshare(syscall.CLONE_NEWNET); err != nil { |
| 45 | + return err |
| 46 | + } |
| 47 | + |
| 48 | + return syscall.Mount(fmt.Sprintf("/proc/self/task/%d/ns/net", syscall.Gettid()), target, "", syscall.MS_BIND, "") |
| 49 | +} |
| 50 | + |
| 51 | +func createNetNS(c *cniProvider, id string) (_ string, err error) { |
42 | 52 | nsPath := filepath.Join(c.root, "net/cni", id)
|
43 | 53 | if err := os.MkdirAll(filepath.Dir(nsPath), 0700); err != nil {
|
44 | 54 | return "", err
|
45 | 55 | }
|
46 | 56 |
|
47 | 57 | f, err := os.Create(nsPath)
|
48 | 58 | if err != nil {
|
49 |
| - deleteNetNS(nsPath) |
50 | 59 | return "", err
|
51 | 60 | }
|
| 61 | + defer func() { |
| 62 | + if err != nil { |
| 63 | + deleteNetNS(nsPath) |
| 64 | + } |
| 65 | + }() |
52 | 66 | if err := f.Close(); err != nil {
|
53 |
| - deleteNetNS(nsPath) |
54 |
| - return "", err |
55 |
| - } |
56 |
| - procNetNSBytes, err := syscall.BytePtrFromString("/proc/self/ns/net") |
57 |
| - if err != nil { |
58 |
| - deleteNetNS(nsPath) |
59 | 67 | return "", err
|
60 | 68 | }
|
61 |
| - nsPathBytes, err := syscall.BytePtrFromString(nsPath) |
62 |
| - if err != nil { |
63 |
| - deleteNetNS(nsPath) |
64 |
| - return "", err |
65 |
| - } |
66 |
| - beforeFork() |
67 | 69 |
|
68 |
| - pid, _, errno := syscall.RawSyscall6(syscall.SYS_CLONE, uintptr(syscall.SIGCHLD)|unix.CLONE_NEWNET, 0, 0, 0, 0, 0) |
69 |
| - if errno != 0 { |
70 |
| - afterFork() |
71 |
| - deleteNetNS(nsPath) |
72 |
| - return "", errno |
73 |
| - } |
| 70 | + errCh := make(chan error) |
74 | 71 |
|
75 |
| - if pid != 0 { |
76 |
| - afterFork() |
77 |
| - var ws unix.WaitStatus |
78 |
| - _, err = unix.Wait4(int(pid), &ws, 0, nil) |
79 |
| - for err == syscall.EINTR { |
80 |
| - _, err = unix.Wait4(int(pid), &ws, 0, nil) |
81 |
| - } |
| 72 | + go func() { |
| 73 | + defer close(errCh) |
| 74 | + runtime.LockOSThread() |
82 | 75 |
|
83 |
| - if err != nil { |
84 |
| - deleteNetNS(nsPath) |
85 |
| - return "", errors.Wrapf(err, "failed to find pid=%d process", pid) |
| 76 | + if err := unshareAndMountNetNS(nsPath); err != nil { |
| 77 | + errCh <- err |
86 | 78 | }
|
87 |
| - errno = syscall.Errno(ws.ExitStatus()) |
88 |
| - if errno != 0 { |
89 |
| - deleteNetNS(nsPath) |
90 |
| - return "", errors.Wrapf(errno, "failed to mount %s (pid=%d)", nsPath, pid) |
91 |
| - } |
92 |
| - return nsPath, nil |
| 79 | + |
| 80 | + // we leave the thread locked so go runtime terminates the thread |
| 81 | + }() |
| 82 | + |
| 83 | + if err := <-errCh; err != nil { |
| 84 | + return "", err |
93 | 85 | }
|
94 |
| - afterForkInChild() |
95 |
| - _, _, errno = syscall.RawSyscall6(syscall.SYS_MOUNT, uintptr(unsafe.Pointer(procNetNSBytes)), uintptr(unsafe.Pointer(nsPathBytes)), 0, uintptr(unix.MS_BIND), 0, 0) |
96 |
| - syscall.RawSyscall(syscall.SYS_EXIT, uintptr(errno), 0, 0) |
97 |
| - panic("unreachable") |
| 86 | + return nsPath, nil |
98 | 87 | }
|
99 | 88 |
|
100 | 89 | func setNetNS(s *specs.Spec, nsPath string) error {
|
|
0 commit comments