vendor: update runc to HEAD

Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
This commit is contained in:
Vincent Batts 2018-03-01 16:50:12 -05:00
parent 0b736bb43f
commit 033424e839
Signed by: vbatts
GPG key ID: 10937E57733F1362
15 changed files with 234 additions and 130 deletions

View file

@ -57,7 +57,7 @@ RUN mkdir -p /usr/src/criu \
&& rm -rf /usr/src/criu && rm -rf /usr/src/criu
# Install runc # Install runc
ENV RUNC_COMMIT 9f9c96235cc97674e935002fc3d78361b696a69e ENV RUNC_COMMIT ce80fa0a64803d52883955cb77b2708b438a0b28
RUN set -x \ RUN set -x \
&& export GOPATH="$(mktemp -d)" \ && export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/opencontainers/runc.git "$GOPATH/src/github.com/opencontainers/runc" \ && git clone https://github.com/opencontainers/runc.git "$GOPATH/src/github.com/opencontainers/runc" \

View file

@ -4,7 +4,7 @@
git: git:
repo: "https://github.com/opencontainers/runc.git" repo: "https://github.com/opencontainers/runc.git"
dest: "{{ ansible_env.GOPATH }}/src/github.com/opencontainers/runc" dest: "{{ ansible_env.GOPATH }}/src/github.com/opencontainers/runc"
version: "9f9c96235cc97674e935002fc3d78361b696a69e" version: "ce80fa0a64803d52883955cb77b2708b438a0b28"
- name: build runc - name: build runc
make: make:

View file

@ -21,7 +21,7 @@ google.golang.org/grpc v1.0.4 https://github.com/grpc/grpc-go
github.com/opencontainers/selinux b29023b86e4a69d1b46b7e7b4e2b6fda03f0b9cd github.com/opencontainers/selinux b29023b86e4a69d1b46b7e7b4e2b6fda03f0b9cd
github.com/opencontainers/go-digest v1.0.0-rc0 github.com/opencontainers/go-digest v1.0.0-rc0
github.com/opencontainers/runtime-tools 263fad0457d4a42d08aea3fb2bc4da7d2f8c3af7 github.com/opencontainers/runtime-tools 263fad0457d4a42d08aea3fb2bc4da7d2f8c3af7
github.com/opencontainers/runc 9f9c96235cc97674e935002fc3d78361b696a69e github.com/opencontainers/runc ce80fa0a64803d52883955cb77b2708b438a0b28
github.com/mrunalp/fileutils master github.com/mrunalp/fileutils master
github.com/vishvananda/netlink master github.com/vishvananda/netlink master
github.com/vishvananda/netns master github.com/vishvananda/netns master

View file

@ -41,8 +41,18 @@ make
sudo make install sudo make install
``` ```
You can also use `go get` to install to your `GOPATH`, assuming that you have a `github.com` parent folder already created under `src`:
```bash
go get github.com/opencontainers/runc
cd $GOPATH/src/github.com/opencontainers/runc
make
sudo make install
```
`runc` will be installed to `/usr/local/sbin/runc` on your system. `runc` will be installed to `/usr/local/sbin/runc` on your system.
#### Build Tags #### Build Tags
`runc` supports optional build tags for compiling support of various features. `runc` supports optional build tags for compiling support of various features.

View file

@ -4,7 +4,6 @@ package libcontainer
import ( import (
"fmt" "fmt"
"os"
"strings" "strings"
"github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/configs"
@ -72,7 +71,7 @@ func newContainerCapList(capConfig *configs.Capabilities) (*containerCapabilitie
} }
ambient = append(ambient, v) ambient = append(ambient, v)
} }
pid, err := capability.NewPid(os.Getpid()) pid, err := capability.NewPid(0)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -395,7 +395,7 @@ func joinCgroups(c *configs.Cgroup, pid int) error {
// systemd represents slice hierarchy using `-`, so we need to follow suit when // systemd represents slice hierarchy using `-`, so we need to follow suit when
// generating the path of slice. Essentially, test-a-b.slice becomes // generating the path of slice. Essentially, test-a-b.slice becomes
// test.slice/test-a.slice/test-a-b.slice. // /test.slice/test-a.slice/test-a-b.slice.
func ExpandSlice(slice string) (string, error) { func ExpandSlice(slice string) (string, error) {
suffix := ".slice" suffix := ".slice"
// Name has to end with ".slice", but can't be just ".slice". // Name has to end with ".slice", but can't be just ".slice".
@ -421,10 +421,9 @@ func ExpandSlice(slice string) (string, error) {
} }
// Append the component to the path and to the prefix. // Append the component to the path and to the prefix.
path += prefix + component + suffix + "/" path += "/" + prefix + component + suffix
prefix += component + "-" prefix += component + "-"
} }
return path, nil return path, nil
} }

View file

@ -1804,7 +1804,7 @@ func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Na
// The following only applies if we are root. // The following only applies if we are root.
if !c.config.Rootless { if !c.config.Rootless {
// check if we have CAP_SETGID to setgroup properly // check if we have CAP_SETGID to setgroup properly
pid, err := capability.NewPid(os.Getpid()) pid, err := capability.NewPid(0)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -22,7 +22,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <linux/limits.h> #include <linux/limits.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/types.h> #include <linux/types.h>
@ -32,15 +31,15 @@
/* Synchronisation values. */ /* Synchronisation values. */
enum sync_t { enum sync_t {
SYNC_USERMAP_PLS = 0x40, /* Request parent to map our users. */ SYNC_USERMAP_PLS = 0x40, /* Request parent to map our users. */
SYNC_USERMAP_ACK = 0x41, /* Mapping finished by the parent. */ SYNC_USERMAP_ACK = 0x41, /* Mapping finished by the parent. */
SYNC_RECVPID_PLS = 0x42, /* Tell parent we're sending the PID. */ SYNC_RECVPID_PLS = 0x42, /* Tell parent we're sending the PID. */
SYNC_RECVPID_ACK = 0x43, /* PID was correctly received by parent. */ SYNC_RECVPID_ACK = 0x43, /* PID was correctly received by parent. */
SYNC_GRANDCHILD = 0x44, /* The grandchild is ready to run. */ SYNC_GRANDCHILD = 0x44, /* The grandchild is ready to run. */
SYNC_CHILD_READY = 0x45, /* The child or grandchild is ready to return. */ SYNC_CHILD_READY = 0x45, /* The child or grandchild is ready to return. */
/* XXX: This doesn't help with segfaults and other such issues. */ /* XXX: This doesn't help with segfaults and other such issues. */
SYNC_ERR = 0xFF, /* Fatal error, no turning back. The error code follows. */ SYNC_ERR = 0xFF, /* Fatal error, no turning back. The error code follows. */
}; };
/* longjmp() arguments. */ /* longjmp() arguments. */
@ -73,7 +72,7 @@ struct nlconfig_t {
char *oom_score_adj; char *oom_score_adj;
size_t oom_score_adj_len; size_t oom_score_adj_len;
/* User namespace settings.*/ /* User namespace settings. */
char *uidmap; char *uidmap;
size_t uidmap_len; size_t uidmap_len;
char *gidmap; char *gidmap;
@ -82,7 +81,7 @@ struct nlconfig_t {
size_t namespaces_len; size_t namespaces_len;
uint8_t is_setgroup; uint8_t is_setgroup;
/* Rootless container settings.*/ /* Rootless container settings. */
uint8_t is_rootless; uint8_t is_rootless;
char *uidmappath; char *uidmappath;
size_t uidmappath_len; size_t uidmappath_len;
@ -167,7 +166,7 @@ static int write_file(char *data, size_t data_len, char *pathfmt, ...)
goto out; goto out;
} }
out: out:
close(fd); close(fd);
return ret; return ret;
} }
@ -184,16 +183,16 @@ static void update_setgroups(int pid, enum policy_t setgroup)
char *policy; char *policy;
switch (setgroup) { switch (setgroup) {
case SETGROUPS_ALLOW: case SETGROUPS_ALLOW:
policy = "allow"; policy = "allow";
break; break;
case SETGROUPS_DENY: case SETGROUPS_DENY:
policy = "deny"; policy = "deny";
break; break;
case SETGROUPS_DEFAULT: case SETGROUPS_DEFAULT:
default: default:
/* Nothing to do. */ /* Nothing to do. */
return; return;
} }
if (write_file(policy, strlen(policy), "/proc/%d/setgroups", pid) < 0) { if (write_file(policy, strlen(policy), "/proc/%d/setgroups", pid) < 0) {
@ -226,14 +225,14 @@ static int try_mapping_tool(const char *app, int pid, char *map, size_t map_len)
if (!child) { if (!child) {
#define MAX_ARGV 20 #define MAX_ARGV 20
char *argv[MAX_ARGV]; char *argv[MAX_ARGV];
char *envp[] = {NULL}; char *envp[] = { NULL };
char pid_fmt[16]; char pid_fmt[16];
int argc = 0; int argc = 0;
char *next; char *next;
snprintf(pid_fmt, 16, "%d", pid); snprintf(pid_fmt, 16, "%d", pid);
argv[argc++] = (char *) app; argv[argc++] = (char *)app;
argv[argc++] = pid_fmt; argv[argc++] = pid_fmt;
/* /*
* Convert the map string into a list of argument that * Convert the map string into a list of argument that
@ -319,7 +318,7 @@ static int clone_parent(jmp_buf *env, int jmpval) __attribute__ ((noinline));
static int clone_parent(jmp_buf *env, int jmpval) static int clone_parent(jmp_buf *env, int jmpval)
{ {
struct clone_t ca = { struct clone_t ca = {
.env = env, .env = env,
.jmpval = jmpval, .jmpval = jmpval,
}; };
@ -533,7 +532,7 @@ void nsexec(void)
int pipenum; int pipenum;
jmp_buf env; jmp_buf env;
int sync_child_pipe[2], sync_grandchild_pipe[2]; int sync_child_pipe[2], sync_grandchild_pipe[2];
struct nlconfig_t config = {0}; struct nlconfig_t config = { 0 };
/* /*
* If we don't have an init pipe, just return to the go routine. * If we don't have an init pipe, just return to the go routine.
@ -630,21 +629,21 @@ void nsexec(void)
*/ */
switch (setjmp(env)) { switch (setjmp(env)) {
/* /*
* Stage 0: We're in the parent. Our job is just to create a new child * Stage 0: We're in the parent. Our job is just to create a new child
* (stage 1: JUMP_CHILD) process and write its uid_map and * (stage 1: JUMP_CHILD) process and write its uid_map and
* gid_map. That process will go on to create a new process, then * gid_map. That process will go on to create a new process, then
* it will send us its PID which we will send to the bootstrap * it will send us its PID which we will send to the bootstrap
* process. * process.
*/ */
case JUMP_PARENT: { case JUMP_PARENT:{
int len; int len;
pid_t child, first_child = -1; pid_t child, first_child = -1;
char buf[JSON_MAX]; char buf[JSON_MAX];
bool ready = false; bool ready = false;
/* For debugging. */ /* For debugging. */
prctl(PR_SET_NAME, (unsigned long) "runc:[0:PARENT]", 0, 0, 0); prctl(PR_SET_NAME, (unsigned long)"runc:[0:PARENT]", 0, 0, 0);
/* Start the process of getting a container. */ /* Start the process of getting a container. */
child = clone_parent(&env, JUMP_CHILD); child = clone_parent(&env, JUMP_CHILD);
@ -702,7 +701,7 @@ void nsexec(void)
bail("failed to sync with child: write(SYNC_USERMAP_ACK)"); bail("failed to sync with child: write(SYNC_USERMAP_ACK)");
} }
break; break;
case SYNC_RECVPID_PLS: { case SYNC_RECVPID_PLS:{
first_child = child; first_child = child;
/* Get the init_func pid. */ /* Get the init_func pid. */
@ -781,16 +780,16 @@ void nsexec(void)
exit(0); exit(0);
} }
/* /*
* Stage 1: We're in the first child process. Our job is to join any * Stage 1: We're in the first child process. Our job is to join any
* provided namespaces in the netlink payload and unshare all * provided namespaces in the netlink payload and unshare all
* of the requested namespaces. If we've been asked to * of the requested namespaces. If we've been asked to
* CLONE_NEWUSER, we will ask our parent (stage 0) to set up * CLONE_NEWUSER, we will ask our parent (stage 0) to set up
* our user mappings for us. Then, we create a new child * our user mappings for us. Then, we create a new child
* (stage 2: JUMP_INIT) for PID namespace. We then send the * (stage 2: JUMP_INIT) for PID namespace. We then send the
* child's PID to our parent (stage 0). * child's PID to our parent (stage 0).
*/ */
case JUMP_CHILD: { case JUMP_CHILD:{
pid_t child; pid_t child;
enum sync_t s; enum sync_t s;
@ -799,7 +798,7 @@ void nsexec(void)
close(sync_child_pipe[1]); close(sync_child_pipe[1]);
/* For debugging. */ /* For debugging. */
prctl(PR_SET_NAME, (unsigned long) "runc:[1:CHILD]", 0, 0, 0); prctl(PR_SET_NAME, (unsigned long)"runc:[1:CHILD]", 0, 0, 0);
/* /*
* We need to setns first. We cannot do this earlier (in stage 0) * We need to setns first. We cannot do this earlier (in stage 0)
@ -901,13 +900,13 @@ void nsexec(void)
exit(0); exit(0);
} }
/* /*
* Stage 2: We're the final child process, and the only process that will * Stage 2: We're the final child process, and the only process that will
* actually return to the Go runtime. Our job is to just do the * actually return to the Go runtime. Our job is to just do the
* final cleanup steps and then return to the Go runtime to allow * final cleanup steps and then return to the Go runtime to allow
* init_linux.go to run. * init_linux.go to run.
*/ */
case JUMP_INIT: { case JUMP_INIT:{
/* /*
* We're inside the child now, having jumped from the * We're inside the child now, having jumped from the
* start_child() code after forking in the parent. * start_child() code after forking in the parent.
@ -921,7 +920,7 @@ void nsexec(void)
close(sync_child_pipe[1]); close(sync_child_pipe[1]);
/* For debugging. */ /* For debugging. */
prctl(PR_SET_NAME, (unsigned long) "runc:[2:INIT]", 0, 0, 0); prctl(PR_SET_NAME, (unsigned long)"runc:[2:INIT]", 0, 0, 0);
if (read(syncfd, &s, sizeof(s)) != sizeof(s)) if (read(syncfd, &s, sizeof(s)) != sizeof(s))
bail("failed to sync with parent: read(SYNC_GRANDCHILD)"); bail("failed to sync with parent: read(SYNC_GRANDCHILD)");

View file

@ -100,8 +100,10 @@ func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) {
if config.NoPivotRoot { if config.NoPivotRoot {
err = msMoveRoot(config.Rootfs) err = msMoveRoot(config.Rootfs)
} else { } else if config.Namespaces.Contains(configs.NEWNS) {
err = pivotRoot(config.Rootfs) err = pivotRoot(config.Rootfs)
} else {
err = chroot(config.Rootfs)
} }
if err != nil { if err != nil {
return newSystemErrorWithCause(err, "jailing process inside rootfs") return newSystemErrorWithCause(err, "jailing process inside rootfs")
@ -702,6 +704,10 @@ func msMoveRoot(rootfs string) error {
if err := unix.Mount(rootfs, "/", "", unix.MS_MOVE, ""); err != nil { if err := unix.Mount(rootfs, "/", "", unix.MS_MOVE, ""); err != nil {
return err return err
} }
return chroot(rootfs)
}
func chroot(rootfs string) error {
if err := unix.Chroot("."); err != nil { if err := unix.Chroot("."); err != nil {
return err return err
} }

View file

@ -65,14 +65,9 @@ func (l *linuxStandardInit) Init() error {
} }
label.Init() label.Init()
if err := prepareRootfs(l.pipe, l.config); err != nil {
// prepareRootfs() can be executed only for a new mount namespace. return err
if l.config.Config.Namespaces.Contains(configs.NEWNS) {
if err := prepareRootfs(l.pipe, l.config); err != nil {
return err
}
} }
// Set up the console. This has to be done *before* we finalize the rootfs, // Set up the console. This has to be done *before* we finalize the rootfs,
// but *after* we've given the user the chance to set up all of the mounts // but *after* we've given the user the chance to set up all of the mounts
// they wanted. // they wanted.

View file

@ -12,84 +12,30 @@ var (
ErrNoGroupEntries = errors.New("no matching entries in group file") ErrNoGroupEntries = errors.New("no matching entries in group file")
) )
func lookupUser(filter func(u User) bool) (User, error) {
// Get operating system-specific passwd reader-closer.
passwd, err := GetPasswd()
if err != nil {
return User{}, err
}
defer passwd.Close()
// Get the users.
users, err := ParsePasswdFilter(passwd, filter)
if err != nil {
return User{}, err
}
// No user entries found.
if len(users) == 0 {
return User{}, ErrNoPasswdEntries
}
// Assume the first entry is the "correct" one.
return users[0], nil
}
// LookupUser looks up a user by their username in /etc/passwd. If the user // LookupUser looks up a user by their username in /etc/passwd. If the user
// cannot be found (or there is no /etc/passwd file on the filesystem), then // cannot be found (or there is no /etc/passwd file on the filesystem), then
// LookupUser returns an error. // LookupUser returns an error.
func LookupUser(username string) (User, error) { func LookupUser(username string) (User, error) {
return lookupUser(func(u User) bool { return lookupUser(username)
return u.Name == username
})
} }
// LookupUid looks up a user by their user id in /etc/passwd. If the user cannot // LookupUid looks up a user by their user id in /etc/passwd. If the user cannot
// be found (or there is no /etc/passwd file on the filesystem), then LookupId // be found (or there is no /etc/passwd file on the filesystem), then LookupId
// returns an error. // returns an error.
func LookupUid(uid int) (User, error) { func LookupUid(uid int) (User, error) {
return lookupUser(func(u User) bool { return lookupUid(uid)
return u.Uid == uid
})
}
func lookupGroup(filter func(g Group) bool) (Group, error) {
// Get operating system-specific group reader-closer.
group, err := GetGroup()
if err != nil {
return Group{}, err
}
defer group.Close()
// Get the users.
groups, err := ParseGroupFilter(group, filter)
if err != nil {
return Group{}, err
}
// No user entries found.
if len(groups) == 0 {
return Group{}, ErrNoGroupEntries
}
// Assume the first entry is the "correct" one.
return groups[0], nil
} }
// LookupGroup looks up a group by its name in /etc/group. If the group cannot // LookupGroup looks up a group by its name in /etc/group. If the group cannot
// be found (or there is no /etc/group file on the filesystem), then LookupGroup // be found (or there is no /etc/group file on the filesystem), then LookupGroup
// returns an error. // returns an error.
func LookupGroup(groupname string) (Group, error) { func LookupGroup(groupname string) (Group, error) {
return lookupGroup(func(g Group) bool { return lookupGroup(groupname)
return g.Name == groupname
})
} }
// LookupGid looks up a group by its group id in /etc/group. If the group cannot // LookupGid looks up a group by its group id in /etc/group. If the group cannot
// be found (or there is no /etc/group file on the filesystem), then LookupGid // be found (or there is no /etc/group file on the filesystem), then LookupGid
// returns an error. // returns an error.
func LookupGid(gid int) (Group, error) { func LookupGid(gid int) (Group, error) {
return lookupGroup(func(g Group) bool { return lookupGid(gid)
return g.Gid == gid
})
} }

View file

@ -15,6 +15,76 @@ const (
unixGroupPath = "/etc/group" unixGroupPath = "/etc/group"
) )
func lookupUser(username string) (User, error) {
return lookupUserFunc(func(u User) bool {
return u.Name == username
})
}
func lookupUid(uid int) (User, error) {
return lookupUserFunc(func(u User) bool {
return u.Uid == uid
})
}
func lookupUserFunc(filter func(u User) bool) (User, error) {
// Get operating system-specific passwd reader-closer.
passwd, err := GetPasswd()
if err != nil {
return User{}, err
}
defer passwd.Close()
// Get the users.
users, err := ParsePasswdFilter(passwd, filter)
if err != nil {
return User{}, err
}
// No user entries found.
if len(users) == 0 {
return User{}, ErrNoPasswdEntries
}
// Assume the first entry is the "correct" one.
return users[0], nil
}
func lookupGroup(groupname string) (Group, error) {
return lookupGroupFunc(func(g Group) bool {
return g.Name == groupname
})
}
func lookupGid(gid int) (Group, error) {
return lookupGroupFunc(func(g Group) bool {
return g.Gid == gid
})
}
func lookupGroupFunc(filter func(g Group) bool) (Group, error) {
// Get operating system-specific group reader-closer.
group, err := GetGroup()
if err != nil {
return Group{}, err
}
defer group.Close()
// Get the users.
groups, err := ParseGroupFilter(group, filter)
if err != nil {
return Group{}, err
}
// No user entries found.
if len(groups) == 0 {
return Group{}, ErrNoGroupEntries
}
// Assume the first entry is the "correct" one.
return groups[0], nil
}
func GetPasswdPath() (string, error) { func GetPasswdPath() (string, error) {
return unixPasswdPath, nil return unixPasswdPath, nil
} }

View file

@ -0,0 +1,40 @@
// +build windows
package user
import (
"fmt"
"os/user"
)
func lookupUser(username string) (User, error) {
u, err := user.Lookup(username)
if err != nil {
return User{}, err
}
return userFromOS(u)
}
func lookupUid(uid int) (User, error) {
u, err := user.LookupId(fmt.Sprintf("%d", uid))
if err != nil {
return User{}, err
}
return userFromOS(u)
}
func lookupGroup(groupname string) (Group, error) {
g, err := user.LookupGroup(groupname)
if err != nil {
return Group{}, err
}
return groupFromOS(g)
}
func lookupGid(gid int) (Group, error) {
g, err := user.LookupGroupId(fmt.Sprintf("%d", gid))
if err != nil {
return Group{}, err
}
return groupFromOS(g)
}

View file

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"os/user"
"strconv" "strconv"
"strings" "strings"
) )
@ -28,6 +29,28 @@ type User struct {
Shell string Shell string
} }
// userFromOS converts an os/user.(*User) to local User
//
// (This does not include Pass, Shell or Gecos)
func userFromOS(u *user.User) (User, error) {
newUser := User{
Name: u.Username,
Home: u.HomeDir,
}
id, err := strconv.Atoi(u.Uid)
if err != nil {
return newUser, err
}
newUser.Uid = id
id, err = strconv.Atoi(u.Gid)
if err != nil {
return newUser, err
}
newUser.Gid = id
return newUser, nil
}
type Group struct { type Group struct {
Name string Name string
Pass string Pass string
@ -35,6 +58,23 @@ type Group struct {
List []string List []string
} }
// groupFromOS converts an os/user.(*Group) to local Group
//
// (This does not include Pass, Shell or Gecos)
func groupFromOS(g *user.Group) (Group, error) {
newGroup := Group{
Name: g.Name,
}
id, err := strconv.Atoi(g.Gid)
if err != nil {
return newGroup, err
}
newGroup.Gid = id
return newGroup, nil
}
func parseLine(line string, v ...interface{}) { func parseLine(line string, v ...interface{}) {
if line == "" { if line == "" {
return return

View file

@ -21,5 +21,5 @@ github.com/urfave/cli d53eb991652b1d438abdd34ce4bfa3ef1539108e
golang.org/x/sys 7ddbeae9ae08c6a06a59597f0c9edbc5ff2444ce https://github.com/golang/sys golang.org/x/sys 7ddbeae9ae08c6a06a59597f0c9edbc5ff2444ce https://github.com/golang/sys
# console dependencies # console dependencies
github.com/containerd/console 84eeaae905fa414d03e07bcd6c8d3f19e7cf180e github.com/containerd/console 2748ece16665b45a47f884001d5831ec79703880
github.com/pkg/errors v0.8.0 github.com/pkg/errors v0.8.0