Forráskód Böngészése

Update libcontainer to 6460fd79667466d2d9ec03f77f3

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
Michael Crosby 10 éve
szülő
commit
115d8bac60

+ 1 - 1
project/vendor.sh

@@ -68,7 +68,7 @@ if [ "$1" = '--go' ]; then
 	mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar
 fi
 
-clone git github.com/docker/libcontainer be02944484da197166020d6b3f08a19d7d7d244c
+clone git github.com/docker/libcontainer 6460fd79667466d2d9ec03f77f319a241c58d40b
 # see src/github.com/docker/libcontainer/update-vendor.sh which is the "source of truth" for libcontainer deps (just like this file)
 rm -rf src/github.com/docker/libcontainer/vendor
 eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli')"

+ 1 - 1
vendor/src/github.com/docker/libcontainer/cgroups/fs/apply_raw.go

@@ -105,7 +105,7 @@ func GetStats(systemPaths map[string]string) (*cgroups.Stats, error) {
 	stats := cgroups.NewStats()
 	for name, path := range systemPaths {
 		sys, ok := subsystems[name]
-		if !ok {
+		if !ok || !cgroups.PathExists(path) {
 			continue
 		}
 		if err := sys.GetStats(path, stats); err != nil {

+ 2 - 2
vendor/src/github.com/docker/libcontainer/cgroups/utils.go

@@ -174,7 +174,7 @@ func ParseCgroupFile(subsystem string, r io.Reader) (string, error) {
 	return "", NewNotFoundError(subsystem)
 }
 
-func pathExists(path string) bool {
+func PathExists(path string) bool {
 	if _, err := os.Stat(path); err != nil {
 		return false
 	}
@@ -183,7 +183,7 @@ func pathExists(path string) bool {
 
 func EnterPid(cgroupPaths map[string]string, pid int) error {
 	for _, path := range cgroupPaths {
-		if pathExists(path) {
+		if PathExists(path) {
 			if err := ioutil.WriteFile(filepath.Join(path, "cgroup.procs"),
 				[]byte(strconv.Itoa(pid)), 0700); err != nil {
 				return err

+ 4 - 0
vendor/src/github.com/docker/libcontainer/config.go

@@ -120,6 +120,10 @@ type Config struct {
 	// Rlimits specifies the resource limits, such as max open files, to set in the container
 	// If Rlimits are not set, the container will inherit rlimits from the parent process
 	Rlimits []Rlimit `json:"rlimits,omitempty"`
+
+	// AdditionalGroups specifies the gids that should be added to supplementary groups
+	// in addition to those that the user belongs to.
+	AdditionalGroups []int `json:"additional_groups,omitempty"`
 }
 
 // Routes can be specified to create entries in the route table as the container is started

+ 33 - 2
vendor/src/github.com/docker/libcontainer/integration/exec_test.go

@@ -67,7 +67,7 @@ func TestIPCPrivate(t *testing.T) {
 	}
 
 	if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual == l {
-		t.Fatalf("ipc link should be private to the conatiner but equals host %q %q", actual, l)
+		t.Fatalf("ipc link should be private to the container but equals host %q %q", actual, l)
 	}
 }
 
@@ -152,7 +152,7 @@ func TestIPCBadPath(t *testing.T) {
 
 	_, _, err = runContainer(config, "", "true")
 	if err == nil {
-		t.Fatal("container succeded with bad ipc path")
+		t.Fatal("container succeeded with bad ipc path")
 	}
 }
 
@@ -176,3 +176,34 @@ func TestRlimit(t *testing.T) {
 		t.Fatalf("expected rlimit to be 1024, got %s", limit)
 	}
 }
+
+func TestPIDNSPrivate(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	rootfs, err := newRootFs()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer remove(rootfs)
+
+	l, err := os.Readlink("/proc/1/ns/pid")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	config := newTemplateConfig(rootfs)
+	buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/pid")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if exitCode != 0 {
+		t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr)
+	}
+
+	if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual == l {
+		t.Fatalf("pid link should be private to the container but equals host %q %q", actual, l)
+	}
+}

+ 35 - 0
vendor/src/github.com/docker/libcontainer/namespaces/exec.go

@@ -110,9 +110,44 @@ func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Wri
 			return -1, err
 		}
 	}
+	if !container.Namespaces.Contains(libcontainer.NEWPID) {
+		killAllPids(container)
+	}
 	return command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil
 }
 
+// killAllPids itterates over all of the container's processes
+// sending a SIGKILL to each process.
+func killAllPids(container *libcontainer.Config) error {
+	var (
+		procs   []*os.Process
+		freeze  = fs.Freeze
+		getPids = fs.GetPids
+	)
+	if systemd.UseSystemd() {
+		freeze = systemd.Freeze
+		getPids = systemd.GetPids
+	}
+	freeze(container.Cgroups, cgroups.Frozen)
+	pids, err := getPids(container.Cgroups)
+	if err != nil {
+		return err
+	}
+	for _, pid := range pids {
+		// TODO: log err without aborting if we are unable to find
+		// a single PID
+		if p, err := os.FindProcess(pid); err == nil {
+			procs = append(procs, p)
+			p.Kill()
+		}
+	}
+	freeze(container.Cgroups, cgroups.Thawed)
+	for _, p := range procs {
+		p.Wait()
+	}
+	return err
+}
+
 // DefaultCreateCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces
 // defined on the container's configuration and use the current binary as the init with the
 // args provided

+ 6 - 4
vendor/src/github.com/docker/libcontainer/namespaces/init.go

@@ -170,7 +170,7 @@ func RestoreParentDeathSignal(old int) error {
 }
 
 // SetupUser changes the groups, gid, and uid for the user inside the container
-func SetupUser(u string) error {
+func SetupUser(container *libcontainer.Config) error {
 	// Set up defaults.
 	defaultExecUser := user.ExecUser{
 		Uid:  syscall.Getuid(),
@@ -188,12 +188,14 @@ func SetupUser(u string) error {
 		return err
 	}
 
-	execUser, err := user.GetExecUserPath(u, &defaultExecUser, passwdPath, groupPath)
+	execUser, err := user.GetExecUserPath(container.User, &defaultExecUser, passwdPath, groupPath)
 	if err != nil {
 		return fmt.Errorf("get supplementary groups %s", err)
 	}
 
-	if err := syscall.Setgroups(execUser.Sgids); err != nil {
+	suppGroups := append(execUser.Sgids, container.AdditionalGroups...)
+
+	if err := syscall.Setgroups(suppGroups); err != nil {
 		return fmt.Errorf("setgroups %s", err)
 	}
 
@@ -273,7 +275,7 @@ func FinalizeNamespace(container *libcontainer.Config) error {
 		return fmt.Errorf("set keep caps %s", err)
 	}
 
-	if err := SetupUser(container.User); err != nil {
+	if err := SetupUser(container); err != nil {
 		return fmt.Errorf("setup user %s", err)
 	}
 

+ 43 - 30
vendor/src/github.com/docker/libcontainer/namespaces/nsenter/nsenter.c

@@ -15,6 +15,8 @@
 #include <unistd.h>
 #include <getopt.h>
 
+#define pr_perror(fmt, ...) fprintf(stderr, "nsenter: " fmt ": %m\n", ##__VA_ARGS__)
+
 static const kBufSize = 256;
 static const char *kNsEnter = "nsenter";
 
@@ -22,6 +24,10 @@ void get_args(int *argc, char ***argv)
 {
 	// Read argv
 	int fd = open("/proc/self/cmdline", O_RDONLY);
+	if (fd < 0) {
+		pr_perror("Unable to open /proc/self/cmdline");
+		exit(1);
+	}
 
 	// Read the whole commandline.
 	ssize_t contents_size = 0;
@@ -34,6 +40,10 @@ void get_args(int *argc, char ***argv)
 		bytes_read =
 		    read(fd, contents + contents_offset,
 			 contents_size - contents_offset);
+		if (bytes_read < 0) {
+			pr_perror("Unable to read from /proc/self/cmdline");
+			exit(1);
+		}
 		contents_offset += bytes_read;
 	}
 	while (bytes_read > 0);
@@ -91,8 +101,7 @@ void nsenter()
 
 	#ifdef PR_SET_CHILD_SUBREAPER
 	if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0) == -1) {
-		fprintf(stderr, "nsenter: failed to set child subreaper: %s",
-			strerror(errno));
+		pr_perror("Failed to set child subreaper");
 		exit(1);
 	}
 	#endif
@@ -124,9 +133,8 @@ void nsenter()
 
 	init_pid = strtol(init_pid_str, NULL, 10);
 	if ((init_pid == 0 && errno == EINVAL) || errno == ERANGE) {
-		fprintf(stderr,
-			"nsenter: Failed to parse PID from \"%s\" with output \"%d\" and error: \"%s\"\n",
-			init_pid_str, init_pid, strerror(errno));
+		pr_perror("Failed to parse PID from \"%s\" with output \"%d\"",
+			init_pid_str, init_pid);
 		print_usage();
 		exit(1);
 	}
@@ -135,7 +143,7 @@ void nsenter()
 	argv += 3;
 
 	if (setsid() == -1) {
-		fprintf(stderr, "setsid failed. Error: %s\n", strerror(errno));
+		pr_perror("setsid failed");
 		exit(1);
 	}
 	// before we setns we need to dup the console
@@ -143,9 +151,7 @@ void nsenter()
 	if (console != NULL) {
 		consolefd = open(console, O_RDWR);
 		if (consolefd < 0) {
-			fprintf(stderr,
-				"nsenter: failed to open console %s %s\n",
-				console, strerror(errno));
+			pr_perror("Failed to open console %s", console);
 			exit(1);
 		}
 	}
@@ -154,51 +160,60 @@ void nsenter()
 	memset(ns_dir, 0, PATH_MAX);
 	snprintf(ns_dir, PATH_MAX - 1, "/proc/%d/ns/", init_pid);
 
+	int ns_dir_fd;
+	ns_dir_fd = open(ns_dir, O_RDONLY | O_DIRECTORY);
+	if (ns_dir_fd < 0) {
+		pr_perror("Unable to open %s", ns_dir);
+		exit(1);
+	}
+
 	char *namespaces[] = { "ipc", "uts", "net", "pid", "mnt" };
 	const int num = sizeof(namespaces) / sizeof(char *);
 	int i;
 	for (i = 0; i < num; i++) {
-		char buf[PATH_MAX];
-		memset(buf, 0, PATH_MAX);
-		snprintf(buf, PATH_MAX - 1, "%s%s", ns_dir, namespaces[i]);
-		int fd = open(buf, O_RDONLY);
-		if (fd == -1) {
-			// Ignore nonexistent namespaces.
+		// A zombie process has links on namespaces, but they can't be opened
+		struct stat st;
+		if (fstatat(ns_dir_fd, namespaces[i], &st, AT_SYMLINK_NOFOLLOW) == -1) {
 			if (errno == ENOENT)
 				continue;
+			pr_perror("Failed to stat ns file %s for ns %s",
+				ns_dir, namespaces[i]);
+			exit(1);
+		}
 
-			fprintf(stderr,
-				"nsenter: Failed to open ns file \"%s\" for ns \"%s\" with error: \"%s\"\n",
-				buf, namespaces[i], strerror(errno));
+		int fd = openat(ns_dir_fd, namespaces[i], O_RDONLY);
+		if (fd == -1) {
+			pr_perror("Failed to open ns file %s for ns %s",
+				ns_dir, namespaces[i]);
 			exit(1);
 		}
 		// Set the namespace.
 		if (setns(fd, 0) == -1) {
-			fprintf(stderr,
-				"nsenter: Failed to setns for \"%s\" with error: \"%s\"\n",
-				namespaces[i], strerror(errno));
+			pr_perror("Failed to setns for %s", namespaces[i]);
 			exit(1);
 		}
 		close(fd);
 	}
+	close(ns_dir_fd);
 
 	// We must fork to actually enter the PID namespace.
 	int child = fork();
+	if (child == -1) {
+		pr_perror("Unable to fork a process");
+		exit(1);
+	}
 	if (child == 0) {
 		if (consolefd != -1) {
 			if (dup2(consolefd, STDIN_FILENO) != 0) {
-				fprintf(stderr, "nsenter: failed to dup 0 %s\n",
-					strerror(errno));
+				pr_perror("Failed to dup 0");
 				exit(1);
 			}
 			if (dup2(consolefd, STDOUT_FILENO) != STDOUT_FILENO) {
-				fprintf(stderr, "nsenter: failed to dup 1 %s\n",
-					strerror(errno));
+				pr_perror("Failed to dup 1");
 				exit(1);
 			}
 			if (dup2(consolefd, STDERR_FILENO) != STDERR_FILENO) {
-				fprintf(stderr, "nsenter: failed to dup 2 %s\n",
-					strerror(errno));
+				pr_perror("Failed to dup 2\n");
 				exit(1);
 			}
 		}
@@ -208,9 +223,7 @@ void nsenter()
 		// Parent, wait for the child.
 		int status = 0;
 		if (waitpid(child, &status, 0) == -1) {
-			fprintf(stderr,
-				"nsenter: Failed to waitpid with error: \"%s\"\n",
-				strerror(errno));
+			pr_perror("nsenter: Failed to waitpid with error");
 			exit(1);
 		}
 		// Forward the child's exit code or re-send its death signal.

+ 70 - 0
vendor/src/github.com/docker/libcontainer/namespaces/nsenter/nsenter_test.go

@@ -0,0 +1,70 @@
+package nsenter
+
+import (
+	"fmt"
+	"os"
+	"os/exec"
+	"os/signal"
+	"strings"
+	"syscall"
+	"testing"
+)
+
+func TestNsenterAlivePid(t *testing.T) {
+	args := []string{"nsenter-exec", "--nspid", fmt.Sprintf("%d", os.Getpid())}
+
+	cmd := &exec.Cmd{
+		Path: os.Args[0],
+		Args: args,
+	}
+
+	err := cmd.Run()
+	if err != nil {
+		t.Fatal("nsenter exits with a non-zero exit status")
+	}
+}
+
+func TestNsenterInvalidPid(t *testing.T) {
+	args := []string{"nsenter-exec", "--nspid", "-1"}
+
+	cmd := &exec.Cmd{
+		Path: os.Args[0],
+		Args: args,
+	}
+
+	err := cmd.Run()
+	if err == nil {
+		t.Fatal("nsenter exits with a zero exit status")
+	}
+}
+
+func TestNsenterDeadPid(t *testing.T) {
+
+	c := make(chan os.Signal)
+	signal.Notify(c, syscall.SIGCHLD)
+	dead_cmd := exec.Command("true")
+	if err := dead_cmd.Start(); err != nil {
+		t.Fatal(err)
+	}
+	defer dead_cmd.Wait()
+	<-c // dead_cmd is zombie
+
+	args := []string{"nsenter-exec", "--nspid", fmt.Sprintf("%d", dead_cmd.Process.Pid)}
+
+	cmd := &exec.Cmd{
+		Path: os.Args[0],
+		Args: args,
+	}
+
+	err := cmd.Run()
+	if err == nil {
+		t.Fatal("nsenter exits with a zero exit status")
+	}
+}
+
+func init() {
+	if strings.HasPrefix(os.Args[0], "nsenter-") {
+		os.Exit(0)
+	}
+	return
+}

+ 200 - 0
vendor/src/github.com/docker/libcontainer/sample_configs/host-pid.json

@@ -0,0 +1,200 @@
+{
+    "capabilities": [
+        "CHOWN",
+        "DAC_OVERRIDE",
+        "FOWNER",
+        "MKNOD",
+        "NET_RAW",
+        "SETGID",
+        "SETUID",
+        "SETFCAP",
+        "SETPCAP",
+        "NET_BIND_SERVICE",
+        "SYS_CHROOT",
+        "KILL"
+    ],
+    "cgroups": {
+        "allowed_devices": [
+            {
+                "cgroup_permissions": "m",
+                "major_number": -1,
+                "minor_number": -1,
+                "type": 99
+            },
+            {
+                "cgroup_permissions": "m",
+                "major_number": -1,
+                "minor_number": -1,
+                "type": 98
+            },
+            {
+                "cgroup_permissions": "rwm",
+                "major_number": 5,
+                "minor_number": 1,
+                "path": "/dev/console",
+                "type": 99
+            },
+            {
+                "cgroup_permissions": "rwm",
+                "major_number": 4,
+                "path": "/dev/tty0",
+                "type": 99
+            },
+            {
+                "cgroup_permissions": "rwm",
+                "major_number": 4,
+                "minor_number": 1,
+                "path": "/dev/tty1",
+                "type": 99
+            },
+            {
+                "cgroup_permissions": "rwm",
+                "major_number": 136,
+                "minor_number": -1,
+                "type": 99
+            },
+            {
+                "cgroup_permissions": "rwm",
+                "major_number": 5,
+                "minor_number": 2,
+                "type": 99
+            },
+            {
+                "cgroup_permissions": "rwm",
+                "major_number": 10,
+                "minor_number": 200,
+                "type": 99
+            },
+            {
+                "cgroup_permissions": "rwm",
+                "file_mode": 438,
+                "major_number": 1,
+                "minor_number": 3,
+                "path": "/dev/null",
+                "type": 99
+            },
+            {
+                "cgroup_permissions": "rwm",
+                "file_mode": 438,
+                "major_number": 1,
+                "minor_number": 5,
+                "path": "/dev/zero",
+                "type": 99
+            },
+            {
+                "cgroup_permissions": "rwm",
+                "file_mode": 438,
+                "major_number": 1,
+                "minor_number": 7,
+                "path": "/dev/full",
+                "type": 99
+            },
+            {
+                "cgroup_permissions": "rwm",
+                "file_mode": 438,
+                "major_number": 5,
+                "path": "/dev/tty",
+                "type": 99
+            },
+            {
+                "cgroup_permissions": "rwm",
+                "file_mode": 438,
+                "major_number": 1,
+                "minor_number": 9,
+                "path": "/dev/urandom",
+                "type": 99
+            },
+            {
+                "cgroup_permissions": "rwm",
+                "file_mode": 438,
+                "major_number": 1,
+                "minor_number": 8,
+                "path": "/dev/random",
+                "type": 99
+            }
+        ],
+        "name": "docker-koye",
+        "parent": "docker"
+    },
+    "restrict_sys": true,
+    "mount_config": {
+        "device_nodes": [
+            {
+                "cgroup_permissions": "rwm",
+                "file_mode": 438,
+                "major_number": 1,
+                "minor_number": 3,
+                "path": "/dev/null",
+                "type": 99
+            },
+            {
+                "cgroup_permissions": "rwm",
+                "file_mode": 438,
+                "major_number": 1,
+                "minor_number": 5,
+                "path": "/dev/zero",
+                "type": 99
+            },
+            {
+                "cgroup_permissions": "rwm",
+                "file_mode": 438,
+                "major_number": 1,
+                "minor_number": 7,
+                "path": "/dev/full",
+                "type": 99
+            },
+            {
+                "cgroup_permissions": "rwm",
+                "file_mode": 438,
+                "major_number": 5,
+                "path": "/dev/tty",
+                "type": 99
+            },
+            {
+                "cgroup_permissions": "rwm",
+                "file_mode": 438,
+                "major_number": 1,
+                "minor_number": 9,
+                "path": "/dev/urandom",
+                "type": 99
+            },
+            {
+                "cgroup_permissions": "rwm",
+                "file_mode": 438,
+                "major_number": 1,
+                "minor_number": 8,
+                "path": "/dev/random",
+                "type": 99
+            }
+        ],
+        "mounts": [
+            {
+                "type": "tmpfs",
+                "destination": "/tmp"
+            }
+        ]
+    },
+    "environment": [
+        "HOME=/",
+        "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
+        "HOSTNAME=koye",
+        "TERM=xterm"
+    ],
+    "hostname": "koye",
+    "namespaces": [
+        {"type": "NEWIPC"},
+        {"type": "NEWNET"},
+        {"type": "NEWNS"},
+        {"type": "NEWUTS"}
+    ],
+    "networks": [
+        {
+            "address": "127.0.0.1/0",
+            "gateway": "localhost",
+            "mtu": 1500,
+            "type": "loopback"
+        }
+    ],
+    "tty": true,
+    "user": "daemon"
+}