setupChildExec does the child-side setup for a token-scoped test and re-execs the test binary. The function never returns.
()
| 250 | // setupChildExec does the child-side setup for a token-scoped test and re-execs |
| 251 | // the test binary. The function never returns. |
| 252 | func setupChildExec() { |
| 253 | // Create a new bpffs file system context. |
| 254 | bpffsCtx, err := unix.Fsopen("bpf", unix.FSOPEN_CLOEXEC) |
| 255 | if err != nil { |
| 256 | panicf("create bpffs context: %v", err) |
| 257 | } |
| 258 | |
| 259 | // Send the bpffs fd to the parent process so it can delegate permissions to |
| 260 | // it. |
| 261 | if err := sendFD(toParentFd, bpffsCtx); err != nil { |
| 262 | panicf("send bpffs fd to parent: %v", err) |
| 263 | } |
| 264 | |
| 265 | // Wait for the parent's ready signal delegation is done. |
| 266 | if err := waitReady(toParentFd); err != nil { |
| 267 | panicf("wait for parent's reply: %v", err) |
| 268 | } |
| 269 | |
| 270 | if err := unix.Close(toParentFd); err != nil { |
| 271 | panicf("close child socket: %v", err) |
| 272 | } |
| 273 | |
| 274 | // Turn the filesystem context into an anonymous mount. |
| 275 | bpffsMnt, err := unix.Fsmount(bpffsCtx, unix.FSMOUNT_CLOEXEC, 0) |
| 276 | if err != nil { |
| 277 | panicf("mount bpffs: %v", err) |
| 278 | } |
| 279 | |
| 280 | if err := unix.Close(bpffsCtx); err != nil { |
| 281 | panicf("close bpffs context: %v", err) |
| 282 | } |
| 283 | |
| 284 | // Move the detached mount to /sys/fs/bpf, the default location. |
| 285 | if err := unix.MoveMount(bpffsMnt, "", unix.AT_FDCWD, "/sys/fs/bpf", unix.MOVE_MOUNT_F_EMPTY_PATH); err != nil { |
| 286 | panicf("move mount: %v", err) |
| 287 | } |
| 288 | |
| 289 | if err := unix.Close(bpffsMnt); err != nil { |
| 290 | panicf("close bpffs mount fd: %v", err) |
| 291 | } |
| 292 | |
| 293 | // Drop all but the following capabilities: |
| 294 | // |
| 295 | // - CAP_BPF for making BPF() syscalls with a token |
| 296 | // - CAP_DAC_READ_SEARCH for reading files owned by the user running the test, |
| 297 | // as we'll be `nobody` in the user namespace. |
| 298 | const caps = (uint64(1) << CAP_BPF) | (uint64(1) << CAP_DAC_READ_SEARCH) |
| 299 | if err := capset(capUserData{caps, caps, caps}); err != nil { |
| 300 | panicf("drop capabilities in child: %v", err) |
| 301 | } |
| 302 | |
| 303 | // Setup done, re-exec and signal the child to run the function under test. |
| 304 | if err := os.Setenv(testUserNS, "true"); err != nil { |
| 305 | panicf("set test environment variable: %v", err) |
| 306 | } |
| 307 | |
| 308 | if err := syscall.Exec(os.Args[0], os.Args, os.Environ()); err != nil { |
| 309 | panicf("re-exec child process: %v", err) |
no test coverage detected
searching dependent graphs…