github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/userns/userns_maps.c (about) 1 #define _GNU_SOURCE 2 #include <fcntl.h> 3 #include <sched.h> 4 #include <stdio.h> 5 #include <unistd.h> 6 #include <stdarg.h> 7 #include <stdlib.h> 8 9 /* 10 * All of the code here is run inside an aync-signal-safe context, so we need 11 * to be careful to not call any functions that could cause issues. In theory, 12 * since we are a Go program, there are fewer restrictions in practice, it's 13 * better to be safe than sorry. 14 * 15 * The only exception is exit, which we need to call to make sure we don't 16 * return into runc. 17 */ 18 19 void bail(int pipefd, const char *fmt, ...) 20 { 21 va_list args; 22 23 va_start(args, fmt); 24 vdprintf(pipefd, fmt, args); 25 va_end(args); 26 27 exit(1); 28 } 29 30 int spawn_userns_cat(char *userns_path, char *path, int outfd, int errfd) 31 { 32 char buffer[4096] = { 0 }; 33 34 pid_t child = fork(); 35 if (child != 0) 36 return child; 37 /* in child */ 38 39 /* Join the target userns. */ 40 int nsfd = open(userns_path, O_RDONLY); 41 if (nsfd < 0) 42 bail(errfd, "open userns path %s failed: %m", userns_path); 43 44 int err = setns(nsfd, CLONE_NEWUSER); 45 if (err < 0) 46 bail(errfd, "setns %s failed: %m", userns_path); 47 48 close(nsfd); 49 50 /* Pipe the requested file contents. */ 51 int fd = open(path, O_RDONLY); 52 if (fd < 0) 53 bail(errfd, "open %s in userns %s failed: %m", path, userns_path); 54 55 int nread, ntotal = 0; 56 while ((nread = read(fd, buffer, sizeof(buffer))) != 0) { 57 if (nread < 0) 58 bail(errfd, "read bytes from %s failed (after %d total bytes read): %m", path, ntotal); 59 ntotal += nread; 60 61 int nwritten = 0; 62 while (nwritten < nread) { 63 int n = write(outfd, buffer, nread - nwritten); 64 if (n < 0) 65 bail(errfd, "write %d bytes from %s failed (after %d bytes written): %m", 66 nread - nwritten, path, nwritten); 67 nwritten += n; 68 } 69 if (nread != nwritten) 70 bail(errfd, "mismatch for bytes read and written: %d read != %d written", nread, nwritten); 71 } 72 73 close(fd); 74 close(outfd); 75 close(errfd); 76 77 /* We must exit here, otherwise we would return into a forked runc. */ 78 exit(0); 79 }