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  }