mirror of
https://github.com/containers/skopeo.git
synced 2025-09-21 18:09:08 +00:00
vendor.conf,vendor: vndr update for containers/image
Signed-off-by: Erik Hollensbe <github@hollensbe.org>
This commit is contained in:
206
vendor/github.com/opencontainers/runc/README.md
generated
vendored
Normal file
206
vendor/github.com/opencontainers/runc/README.md
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
# runc
|
||||
|
||||
[](https://travis-ci.org/opencontainers/runc)
|
||||
[](https://goreportcard.com/report/github.com/opencontainers/runc)
|
||||
[](https://godoc.org/github.com/opencontainers/runc)
|
||||
|
||||
## Introduction
|
||||
|
||||
`runc` is a CLI tool for spawning and running containers according to the OCI specification.
|
||||
|
||||
## Releases
|
||||
|
||||
`runc` depends on and tracks the [runtime-spec](https://github.com/opencontainers/runtime-spec) repository.
|
||||
We will try to make sure that `runc` and the OCI specification major versions stay in lockstep.
|
||||
This means that `runc` 1.0.0 should implement the 1.0 version of the specification.
|
||||
|
||||
You can find official releases of `runc` on the [release](https://github.com/opencontainers/runc/releases) page.
|
||||
|
||||
### Security
|
||||
|
||||
If you wish to report a security issue, please disclose the issue responsibly
|
||||
to security@opencontainers.org.
|
||||
|
||||
## Building
|
||||
|
||||
`runc` currently supports the Linux platform with various architecture support.
|
||||
It must be built with Go version 1.6 or higher in order for some features to function properly.
|
||||
|
||||
In order to enable seccomp support you will need to install `libseccomp` on your platform.
|
||||
> e.g. `libseccomp-devel` for CentOS, or `libseccomp-dev` for Ubuntu
|
||||
|
||||
Otherwise, if you do not want to build `runc` with seccomp support you can add `BUILDTAGS=""` when running make.
|
||||
|
||||
```bash
|
||||
# create a 'github.com/opencontainers' in your GOPATH/src
|
||||
cd github.com/opencontainers
|
||||
git clone https://github.com/opencontainers/runc
|
||||
cd runc
|
||||
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
`runc` will be installed to `/usr/local/sbin/runc` on your system.
|
||||
|
||||
#### Build Tags
|
||||
|
||||
`runc` supports optional build tags for compiling support of various features.
|
||||
To add build tags to the make option the `BUILDTAGS` variable must be set.
|
||||
|
||||
```bash
|
||||
make BUILDTAGS='seccomp apparmor'
|
||||
```
|
||||
|
||||
| Build Tag | Feature | Dependency |
|
||||
|-----------|------------------------------------|-------------|
|
||||
| seccomp | Syscall filtering | libseccomp |
|
||||
| selinux | selinux process and mount labeling | <none> |
|
||||
| apparmor | apparmor profile support | libapparmor |
|
||||
| ambient | ambient capability support | kernel 4.3 |
|
||||
|
||||
|
||||
### Running the test suite
|
||||
|
||||
`runc` currently supports running its test suite via Docker.
|
||||
To run the suite just type `make test`.
|
||||
|
||||
```bash
|
||||
make test
|
||||
```
|
||||
|
||||
There are additional make targets for running the tests outside of a container but this is not recommended as the tests are written with the expectation that they can write and remove anywhere.
|
||||
|
||||
You can run a specific test case by setting the `TESTFLAGS` variable.
|
||||
|
||||
```bash
|
||||
# make test TESTFLAGS="-run=SomeTestFunction"
|
||||
```
|
||||
|
||||
### Dependencies Management
|
||||
|
||||
`runc` uses [vndr](https://github.com/LK4D4/vndr) for dependencies management.
|
||||
Please refer to [vndr](https://github.com/LK4D4/vndr) for how to add or update
|
||||
new dependencies.
|
||||
|
||||
## Using runc
|
||||
|
||||
### Creating an OCI Bundle
|
||||
|
||||
In order to use runc you must have your container in the format of an OCI bundle.
|
||||
If you have Docker installed you can use its `export` method to acquire a root filesystem from an existing Docker container.
|
||||
|
||||
```bash
|
||||
# create the top most bundle directory
|
||||
mkdir /mycontainer
|
||||
cd /mycontainer
|
||||
|
||||
# create the rootfs directory
|
||||
mkdir rootfs
|
||||
|
||||
# export busybox via Docker into the rootfs directory
|
||||
docker export $(docker create busybox) | tar -C rootfs -xvf -
|
||||
```
|
||||
|
||||
After a root filesystem is populated you just generate a spec in the format of a `config.json` file inside your bundle.
|
||||
`runc` provides a `spec` command to generate a base template spec that you are then able to edit.
|
||||
To find features and documentation for fields in the spec please refer to the [specs](https://github.com/opencontainers/runtime-spec) repository.
|
||||
|
||||
```bash
|
||||
runc spec
|
||||
```
|
||||
|
||||
### Running Containers
|
||||
|
||||
Assuming you have an OCI bundle from the previous step you can execute the container in two different ways.
|
||||
|
||||
The first way is to use the convenience command `run` that will handle creating, starting, and deleting the container after it exits.
|
||||
|
||||
```bash
|
||||
cd /mycontainer
|
||||
|
||||
runc run mycontainerid
|
||||
```
|
||||
|
||||
If you used the unmodified `runc spec` template this should give you a `sh` session inside the container.
|
||||
|
||||
The second way to start a container is using the specs lifecycle operations.
|
||||
This gives you more power over how the container is created and managed while it is running.
|
||||
This will also launch the container in the background so you will have to edit the `config.json` to remove the `terminal` setting for the simple examples here.
|
||||
Your process field in the `config.json` should look like this below with `"terminal": false` and `"args": ["sleep", "5"]`.
|
||||
|
||||
|
||||
```json
|
||||
"process": {
|
||||
"terminal": false,
|
||||
"user": {
|
||||
"uid": 0,
|
||||
"gid": 0
|
||||
},
|
||||
"args": [
|
||||
"sleep", "5"
|
||||
],
|
||||
"env": [
|
||||
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
"TERM=xterm"
|
||||
],
|
||||
"cwd": "/",
|
||||
"capabilities": [
|
||||
"CAP_AUDIT_WRITE",
|
||||
"CAP_KILL",
|
||||
"CAP_NET_BIND_SERVICE"
|
||||
],
|
||||
"rlimits": [
|
||||
{
|
||||
"type": "RLIMIT_NOFILE",
|
||||
"hard": 1024,
|
||||
"soft": 1024
|
||||
}
|
||||
],
|
||||
"noNewPrivileges": true
|
||||
},
|
||||
```
|
||||
|
||||
Now we can go though the lifecycle operations in your shell.
|
||||
|
||||
|
||||
```bash
|
||||
cd /mycontainer
|
||||
|
||||
runc create mycontainerid
|
||||
|
||||
# view the container is created and in the "created" state
|
||||
runc list
|
||||
|
||||
# start the process inside the container
|
||||
runc start mycontainerid
|
||||
|
||||
# after 5 seconds view that the container has exited and is now in the stopped state
|
||||
runc list
|
||||
|
||||
# now delete the container
|
||||
runc delete mycontainerid
|
||||
```
|
||||
|
||||
This adds more complexity but allows higher level systems to manage runc and provides points in the containers creation to setup various settings after the container has created and/or before it is deleted.
|
||||
This is commonly used to setup the container's network stack after `create` but before `start` where the user's defined process will be running.
|
||||
|
||||
#### Supervisors
|
||||
|
||||
`runc` can be used with process supervisors and init systems to ensure that containers are restarted when they exit.
|
||||
An example systemd unit file looks something like this.
|
||||
|
||||
```systemd
|
||||
[Unit]
|
||||
Description=Start My Container
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
ExecStart=/usr/local/sbin/runc run -d --pid-file /run/mycontainerid.pid mycontainerid
|
||||
ExecStopPost=/usr/local/sbin/runc delete mycontainerid
|
||||
WorkingDirectory=/mycontainer
|
||||
PIDFile=/run/mycontainerid.pid
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
262
vendor/github.com/opencontainers/runc/libcontainer/README.md
generated
vendored
Normal file
262
vendor/github.com/opencontainers/runc/libcontainer/README.md
generated
vendored
Normal file
@@ -0,0 +1,262 @@
|
||||
# libcontainer
|
||||
|
||||
[](https://godoc.org/github.com/opencontainers/runc/libcontainer)
|
||||
|
||||
Libcontainer provides a native Go implementation for creating containers
|
||||
with namespaces, cgroups, capabilities, and filesystem access controls.
|
||||
It allows you to manage the lifecycle of the container performing additional operations
|
||||
after the container is created.
|
||||
|
||||
|
||||
#### Container
|
||||
A container is a self contained execution environment that shares the kernel of the
|
||||
host system and which is (optionally) isolated from other containers in the system.
|
||||
|
||||
#### Using libcontainer
|
||||
|
||||
Because containers are spawned in a two step process you will need a binary that
|
||||
will be executed as the init process for the container. In libcontainer, we use
|
||||
the current binary (/proc/self/exe) to be executed as the init process, and use
|
||||
arg "init", we call the first step process "bootstrap", so you always need a "init"
|
||||
function as the entry of "bootstrap".
|
||||
|
||||
In addition to the go init function the early stage bootstrap is handled by importing
|
||||
[nsenter](https://github.com/opencontainers/runc/blob/master/libcontainer/nsenter/README.md).
|
||||
|
||||
```go
|
||||
import (
|
||||
_ "github.com/opencontainers/runc/libcontainer/nsenter"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if len(os.Args) > 1 && os.Args[1] == "init" {
|
||||
runtime.GOMAXPROCS(1)
|
||||
runtime.LockOSThread()
|
||||
factory, _ := libcontainer.New("")
|
||||
if err := factory.StartInitialization(); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
panic("--this line should have never been executed, congratulations--")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then to create a container you first have to initialize an instance of a factory
|
||||
that will handle the creation and initialization for a container.
|
||||
|
||||
```go
|
||||
factory, err := libcontainer.New("/var/lib/container", libcontainer.Cgroupfs, libcontainer.InitArgs(os.Args[0], "init"))
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
Once you have an instance of the factory created we can create a configuration
|
||||
struct describing how the container is to be created. A sample would look similar to this:
|
||||
|
||||
```go
|
||||
defaultMountFlags := syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
|
||||
config := &configs.Config{
|
||||
Rootfs: "/your/path/to/rootfs",
|
||||
Capabilities: []string{
|
||||
"CAP_CHOWN",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_FSETID",
|
||||
"CAP_FOWNER",
|
||||
"CAP_MKNOD",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_KILL",
|
||||
"CAP_AUDIT_WRITE",
|
||||
},
|
||||
Namespaces: configs.Namespaces([]configs.Namespace{
|
||||
{Type: configs.NEWNS},
|
||||
{Type: configs.NEWUTS},
|
||||
{Type: configs.NEWIPC},
|
||||
{Type: configs.NEWPID},
|
||||
{Type: configs.NEWUSER},
|
||||
{Type: configs.NEWNET},
|
||||
}),
|
||||
Cgroups: &configs.Cgroup{
|
||||
Name: "test-container",
|
||||
Parent: "system",
|
||||
Resources: &configs.Resources{
|
||||
MemorySwappiness: nil,
|
||||
AllowAllDevices: nil,
|
||||
AllowedDevices: configs.DefaultAllowedDevices,
|
||||
},
|
||||
},
|
||||
MaskPaths: []string{
|
||||
"/proc/kcore",
|
||||
"/sys/firmware",
|
||||
},
|
||||
ReadonlyPaths: []string{
|
||||
"/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus",
|
||||
},
|
||||
Devices: configs.DefaultAutoCreatedDevices,
|
||||
Hostname: "testing",
|
||||
Mounts: []*configs.Mount{
|
||||
{
|
||||
Source: "proc",
|
||||
Destination: "/proc",
|
||||
Device: "proc",
|
||||
Flags: defaultMountFlags,
|
||||
},
|
||||
{
|
||||
Source: "tmpfs",
|
||||
Destination: "/dev",
|
||||
Device: "tmpfs",
|
||||
Flags: syscall.MS_NOSUID | syscall.MS_STRICTATIME,
|
||||
Data: "mode=755",
|
||||
},
|
||||
{
|
||||
Source: "devpts",
|
||||
Destination: "/dev/pts",
|
||||
Device: "devpts",
|
||||
Flags: syscall.MS_NOSUID | syscall.MS_NOEXEC,
|
||||
Data: "newinstance,ptmxmode=0666,mode=0620,gid=5",
|
||||
},
|
||||
{
|
||||
Device: "tmpfs",
|
||||
Source: "shm",
|
||||
Destination: "/dev/shm",
|
||||
Data: "mode=1777,size=65536k",
|
||||
Flags: defaultMountFlags,
|
||||
},
|
||||
{
|
||||
Source: "mqueue",
|
||||
Destination: "/dev/mqueue",
|
||||
Device: "mqueue",
|
||||
Flags: defaultMountFlags,
|
||||
},
|
||||
{
|
||||
Source: "sysfs",
|
||||
Destination: "/sys",
|
||||
Device: "sysfs",
|
||||
Flags: defaultMountFlags | syscall.MS_RDONLY,
|
||||
},
|
||||
},
|
||||
UidMappings: []configs.IDMap{
|
||||
{
|
||||
ContainerID: 0,
|
||||
HostID: 1000,
|
||||
Size: 65536,
|
||||
},
|
||||
},
|
||||
GidMappings: []configs.IDMap{
|
||||
{
|
||||
ContainerID: 0,
|
||||
HostID: 1000,
|
||||
Size: 65536,
|
||||
},
|
||||
},
|
||||
Networks: []*configs.Network{
|
||||
{
|
||||
Type: "loopback",
|
||||
Address: "127.0.0.1/0",
|
||||
Gateway: "localhost",
|
||||
},
|
||||
},
|
||||
Rlimits: []configs.Rlimit{
|
||||
{
|
||||
Type: syscall.RLIMIT_NOFILE,
|
||||
Hard: uint64(1025),
|
||||
Soft: uint64(1025),
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Once you have the configuration populated you can create a container:
|
||||
|
||||
```go
|
||||
container, err := factory.Create("container-id", config)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
To spawn bash as the initial process inside the container and have the
|
||||
processes pid returned in order to wait, signal, or kill the process:
|
||||
|
||||
```go
|
||||
process := &libcontainer.Process{
|
||||
Args: []string{"/bin/bash"},
|
||||
Env: []string{"PATH=/bin"},
|
||||
User: "daemon",
|
||||
Stdin: os.Stdin,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
}
|
||||
|
||||
err := container.Run(process)
|
||||
if err != nil {
|
||||
container.Destroy()
|
||||
logrus.Fatal(err)
|
||||
return
|
||||
}
|
||||
|
||||
// wait for the process to finish.
|
||||
_, err := process.Wait()
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
// destroy the container.
|
||||
container.Destroy()
|
||||
```
|
||||
|
||||
Additional ways to interact with a running container are:
|
||||
|
||||
```go
|
||||
// return all the pids for all processes running inside the container.
|
||||
processes, err := container.Processes()
|
||||
|
||||
// get detailed cpu, memory, io, and network statistics for the container and
|
||||
// it's processes.
|
||||
stats, err := container.Stats()
|
||||
|
||||
// pause all processes inside the container.
|
||||
container.Pause()
|
||||
|
||||
// resume all paused processes.
|
||||
container.Resume()
|
||||
|
||||
// send signal to container's init process.
|
||||
container.Signal(signal)
|
||||
|
||||
// update container resource constraints.
|
||||
container.Set(config)
|
||||
|
||||
// get current status of the container.
|
||||
status, err := container.Status()
|
||||
|
||||
// get current container's state information.
|
||||
state, err := container.State()
|
||||
```
|
||||
|
||||
|
||||
#### Checkpoint & Restore
|
||||
|
||||
libcontainer now integrates [CRIU](http://criu.org/) for checkpointing and restoring containers.
|
||||
This let's you save the state of a process running inside a container to disk, and then restore
|
||||
that state into a new process, on the same machine or on another machine.
|
||||
|
||||
`criu` version 1.5.2 or higher is required to use checkpoint and restore.
|
||||
If you don't already have `criu` installed, you can build it from source, following the
|
||||
[online instructions](http://criu.org/Installation). `criu` is also installed in the docker image
|
||||
generated when building libcontainer with docker.
|
||||
|
||||
|
||||
## Copyright and license
|
||||
|
||||
Code and documentation copyright 2014 Docker, inc. Code released under the Apache 2.0 license.
|
||||
Docs released under Creative commons.
|
||||
|
20
vendor/github.com/opencontainers/runc/libcontainer/label/label_selinux.go
generated
vendored
20
vendor/github.com/opencontainers/runc/libcontainer/label/label_selinux.go
generated
vendored
@@ -33,19 +33,15 @@ func InitLabels(options []string) (string, string, error) {
|
||||
pcon := selinux.NewContext(processLabel)
|
||||
mcon := selinux.NewContext(mountLabel)
|
||||
for _, opt := range options {
|
||||
val := strings.SplitN(opt, "=", 2)
|
||||
if val[0] != "label" {
|
||||
continue
|
||||
}
|
||||
if len(val) < 2 {
|
||||
return "", "", fmt.Errorf("bad label option %q, valid options 'disable' or \n'user, role, level, type' followed by ':' and a value", opt)
|
||||
}
|
||||
if val[1] == "disable" {
|
||||
if opt == "disable" {
|
||||
return "", "", nil
|
||||
}
|
||||
con := strings.SplitN(val[1], ":", 2)
|
||||
if len(con) < 2 || !validOptions[con[0]] {
|
||||
return "", "", fmt.Errorf("bad label option %q, valid options 'disable, user, role, level, type'", con[0])
|
||||
if i := strings.Index(opt, ":"); i == -1 {
|
||||
return "", "", fmt.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type' followed by ':' and a value", opt)
|
||||
}
|
||||
con := strings.SplitN(opt, ":", 2)
|
||||
if !validOptions[con[0]] {
|
||||
return "", "", fmt.Errorf("Bad label option %q, valid options 'disable, user, role, level, type'", con[0])
|
||||
|
||||
}
|
||||
pcon[con[0]] = con[1]
|
||||
@@ -146,7 +142,7 @@ func Relabel(path string, fileLabel string, shared bool) error {
|
||||
fileLabel = c.Get()
|
||||
}
|
||||
if err := selinux.Chcon(path, fileLabel, true); err != nil {
|
||||
return fmt.Errorf("SELinux relabeling of %s is not allowed: %q", path, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
44
vendor/github.com/opencontainers/runc/libcontainer/nsenter/README.md
generated
vendored
Normal file
44
vendor/github.com/opencontainers/runc/libcontainer/nsenter/README.md
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
## nsenter
|
||||
|
||||
The `nsenter` package registers a special init constructor that is called before
|
||||
the Go runtime has a chance to boot. This provides us the ability to `setns` on
|
||||
existing namespaces and avoid the issues that the Go runtime has with multiple
|
||||
threads. This constructor will be called if this package is registered,
|
||||
imported, in your go application.
|
||||
|
||||
The `nsenter` package will `import "C"` and it uses [cgo](https://golang.org/cmd/cgo/)
|
||||
package. In cgo, if the import of "C" is immediately preceded by a comment, that comment,
|
||||
called the preamble, is used as a header when compiling the C parts of the package.
|
||||
So every time we import package `nsenter`, the C code function `nsexec()` would be
|
||||
called. And package `nsenter` is now only imported in `main_unix.go`, so every time
|
||||
before we call `cmd.Start` on linux, that C code would run.
|
||||
|
||||
Because `nsexec()` must be run before the Go runtime in order to use the
|
||||
Linux kernel namespace, you must `import` this library into a package if
|
||||
you plan to use `libcontainer` directly. Otherwise Go will not execute
|
||||
the `nsexec()` constructor, which means that the re-exec will not cause
|
||||
the namespaces to be joined. You can import it like this:
|
||||
|
||||
```go
|
||||
import _ "github.com/opencontainers/runc/libcontainer/nsenter"
|
||||
```
|
||||
|
||||
`nsexec()` will first get the file descriptor number for the init pipe
|
||||
from the environment variable `_LIBCONTAINER_INITPIPE` (which was opened
|
||||
by the parent and kept open across the fork-exec of the `nsexec()` init
|
||||
process). The init pipe is used to read bootstrap data (namespace paths,
|
||||
clone flags, uid and gid mappings, and the console path) from the parent
|
||||
process. `nsexec()` will then call `setns(2)` to join the namespaces
|
||||
provided in the bootstrap data (if available), `clone(2)` a child process
|
||||
with the provided clone flags, update the user and group ID mappings, do
|
||||
some further miscellaneous setup steps, and then send the PID of the
|
||||
child process to the parent of the `nsexec()` "caller". Finally,
|
||||
the parent `nsexec()` will exit and the child `nsexec()` process will
|
||||
return to allow the Go runtime take over.
|
||||
|
||||
NOTE: We do both `setns(2)` and `clone(2)` even if we don't have any
|
||||
CLONE_NEW* clone flags because we must fork a new process in order to
|
||||
enter the PID namespace.
|
||||
|
||||
|
||||
|
114
vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c
generated
vendored
114
vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c
generated
vendored
@@ -33,7 +33,8 @@ enum sync_t {
|
||||
SYNC_USERMAP_ACK = 0x41, /* Mapping finished by the parent. */
|
||||
SYNC_RECVPID_PLS = 0x42, /* Tell parent we're sending the PID. */
|
||||
SYNC_RECVPID_ACK = 0x43, /* PID was correctly received by parent. */
|
||||
SYNC_CHILD_READY = 0x44, /* The grandchild is ready to return. */
|
||||
SYNC_GRANDCHILD = 0x44, /* The grandchild is ready to run. */
|
||||
SYNC_CHILD_READY = 0x45, /* The child or grandchild is ready to return. */
|
||||
|
||||
/* XXX: This doesn't help with segfaults and other such issues. */
|
||||
SYNC_ERR = 0xFF, /* Fatal error, no turning back. The error code follows. */
|
||||
@@ -284,7 +285,7 @@ static void nl_parse(int fd, struct nlconfig_t *config)
|
||||
/* Retrieve the netlink header. */
|
||||
len = read(fd, &hdr, NLMSG_HDRLEN);
|
||||
if (len != NLMSG_HDRLEN)
|
||||
bail("invalid netlink header length %lu", len);
|
||||
bail("invalid netlink header length %zu", len);
|
||||
|
||||
if (hdr.nlmsg_type == NLMSG_ERROR)
|
||||
bail("failed to read netlink message");
|
||||
@@ -300,7 +301,7 @@ static void nl_parse(int fd, struct nlconfig_t *config)
|
||||
|
||||
len = read(fd, data, size);
|
||||
if (len != size)
|
||||
bail("failed to read netlink payload, %lu != %lu", len, size);
|
||||
bail("failed to read netlink payload, %zu != %zu", len, size);
|
||||
|
||||
/* Parse the netlink payload. */
|
||||
config->data = data;
|
||||
@@ -413,7 +414,7 @@ void nsexec(void)
|
||||
{
|
||||
int pipenum;
|
||||
jmp_buf env;
|
||||
int syncpipe[2];
|
||||
int sync_child_pipe[2], sync_grandchild_pipe[2];
|
||||
struct nlconfig_t config = {0};
|
||||
|
||||
/*
|
||||
@@ -433,9 +434,16 @@ void nsexec(void)
|
||||
nl_parse(pipenum, &config);
|
||||
|
||||
/* Pipe so we can tell the child when we've finished setting up. */
|
||||
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, syncpipe) < 0)
|
||||
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sync_child_pipe) < 0)
|
||||
bail("failed to setup sync pipe between parent and child");
|
||||
|
||||
/*
|
||||
* We need a new socketpair to sync with grandchild so we don't have
|
||||
* race condition with child.
|
||||
*/
|
||||
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sync_grandchild_pipe) < 0)
|
||||
bail("failed to setup sync pipe between parent and grandchild");
|
||||
|
||||
/* TODO: Currently we aren't dealing with child deaths properly. */
|
||||
|
||||
/*
|
||||
@@ -494,9 +502,10 @@ void nsexec(void)
|
||||
* process.
|
||||
*/
|
||||
case JUMP_PARENT: {
|
||||
int len, ready = 0;
|
||||
int len;
|
||||
pid_t child;
|
||||
char buf[JSON_MAX];
|
||||
bool ready = false;
|
||||
|
||||
/* For debugging. */
|
||||
prctl(PR_SET_NAME, (unsigned long) "runc:[0:PARENT]", 0, 0, 0);
|
||||
@@ -513,26 +522,23 @@ void nsexec(void)
|
||||
* ready, so we can receive all possible error codes
|
||||
* generated by children.
|
||||
*/
|
||||
while (ready < 2) {
|
||||
while (!ready) {
|
||||
enum sync_t s;
|
||||
int ret;
|
||||
|
||||
/* This doesn't need to be global, we're in the parent. */
|
||||
int syncfd = syncpipe[1];
|
||||
syncfd = sync_child_pipe[1];
|
||||
close(sync_child_pipe[0]);
|
||||
|
||||
if (read(syncfd, &s, sizeof(s)) != sizeof(s))
|
||||
bail("failed to sync with child: next state");
|
||||
|
||||
switch (s) {
|
||||
case SYNC_ERR: {
|
||||
/* We have to mirror the error code of the child. */
|
||||
int ret;
|
||||
case SYNC_ERR:
|
||||
/* We have to mirror the error code of the child. */
|
||||
if (read(syncfd, &ret, sizeof(ret)) != sizeof(ret))
|
||||
bail("failed to sync with child: read(error code)");
|
||||
|
||||
if (read(syncfd, &ret, sizeof(ret)) != sizeof(ret))
|
||||
bail("failed to sync with child: read(error code)");
|
||||
|
||||
exit(ret);
|
||||
}
|
||||
break;
|
||||
exit(ret);
|
||||
case SYNC_USERMAP_PLS:
|
||||
/* Enable setgroups(2) if we've been asked to. */
|
||||
if (config.is_setgroup)
|
||||
@@ -548,11 +554,6 @@ void nsexec(void)
|
||||
bail("failed to sync with child: write(SYNC_USERMAP_ACK)");
|
||||
}
|
||||
break;
|
||||
case SYNC_USERMAP_ACK:
|
||||
/* We should _never_ receive acks. */
|
||||
kill(child, SIGKILL);
|
||||
bail("failed to sync with child: unexpected SYNC_USERMAP_ACK");
|
||||
break;
|
||||
case SYNC_RECVPID_PLS: {
|
||||
pid_t old = child;
|
||||
|
||||
@@ -570,20 +571,46 @@ void nsexec(void)
|
||||
bail("failed to sync with child: write(SYNC_RECVPID_ACK)");
|
||||
}
|
||||
}
|
||||
|
||||
ready++;
|
||||
break;
|
||||
case SYNC_RECVPID_ACK:
|
||||
/* We should _never_ receive acks. */
|
||||
kill(child, SIGKILL);
|
||||
bail("failed to sync with child: unexpected SYNC_RECVPID_ACK");
|
||||
break;
|
||||
case SYNC_CHILD_READY:
|
||||
ready++;
|
||||
ready = true;
|
||||
break;
|
||||
default:
|
||||
bail("unexpected sync value");
|
||||
bail("unexpected sync value: %u", s);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now sync with grandchild. */
|
||||
|
||||
ready = false;
|
||||
while (!ready) {
|
||||
enum sync_t s;
|
||||
int ret;
|
||||
|
||||
syncfd = sync_grandchild_pipe[1];
|
||||
close(sync_grandchild_pipe[0]);
|
||||
|
||||
s = SYNC_GRANDCHILD;
|
||||
if (write(syncfd, &s, sizeof(s)) != sizeof(s)) {
|
||||
kill(child, SIGKILL);
|
||||
bail("failed to sync with child: write(SYNC_GRANDCHILD)");
|
||||
}
|
||||
|
||||
if (read(syncfd, &s, sizeof(s)) != sizeof(s))
|
||||
bail("failed to sync with child: next state");
|
||||
|
||||
switch (s) {
|
||||
case SYNC_ERR:
|
||||
/* We have to mirror the error code of the child. */
|
||||
if (read(syncfd, &ret, sizeof(ret)) != sizeof(ret))
|
||||
bail("failed to sync with child: read(error code)");
|
||||
|
||||
exit(ret);
|
||||
case SYNC_CHILD_READY:
|
||||
ready = true;
|
||||
break;
|
||||
default:
|
||||
bail("unexpected sync value: %u", s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -615,7 +642,8 @@ void nsexec(void)
|
||||
enum sync_t s;
|
||||
|
||||
/* We're in a child and thus need to tell the parent if we die. */
|
||||
syncfd = syncpipe[0];
|
||||
syncfd = sync_child_pipe[0];
|
||||
close(sync_child_pipe[1]);
|
||||
|
||||
/* For debugging. */
|
||||
prctl(PR_SET_NAME, (unsigned long) "runc:[1:CHILD]", 0, 0, 0);
|
||||
@@ -700,6 +728,12 @@ void nsexec(void)
|
||||
bail("failed to sync with parent: SYNC_RECVPID_ACK: got %u", s);
|
||||
}
|
||||
|
||||
s = SYNC_CHILD_READY;
|
||||
if (write(syncfd, &s, sizeof(s)) != sizeof(s)) {
|
||||
kill(child, SIGKILL);
|
||||
bail("failed to sync with parent: write(SYNC_CHILD_READY)");
|
||||
}
|
||||
|
||||
/* Our work is done. [Stage 2: JUMP_INIT] is doing the rest of the work. */
|
||||
exit(0);
|
||||
}
|
||||
@@ -718,11 +752,19 @@ void nsexec(void)
|
||||
enum sync_t s;
|
||||
|
||||
/* We're in a child and thus need to tell the parent if we die. */
|
||||
syncfd = syncpipe[0];
|
||||
syncfd = sync_grandchild_pipe[0];
|
||||
close(sync_grandchild_pipe[1]);
|
||||
close(sync_child_pipe[0]);
|
||||
close(sync_child_pipe[1]);
|
||||
|
||||
/* For debugging. */
|
||||
prctl(PR_SET_NAME, (unsigned long) "runc:[2:INIT]", 0, 0, 0);
|
||||
|
||||
if (read(syncfd, &s, sizeof(s)) != sizeof(s))
|
||||
bail("failed to sync with parent: read(SYNC_GRANDCHILD)");
|
||||
if (s != SYNC_GRANDCHILD)
|
||||
bail("failed to sync with parent: SYNC_GRANDCHILD: got %u", s);
|
||||
|
||||
if (setsid() < 0)
|
||||
bail("setsid failed");
|
||||
|
||||
@@ -740,8 +782,7 @@ void nsexec(void)
|
||||
bail("failed to sync with patent: write(SYNC_CHILD_READY)");
|
||||
|
||||
/* Close sync pipes. */
|
||||
close(syncpipe[0]);
|
||||
close(syncpipe[1]);
|
||||
close(sync_grandchild_pipe[0]);
|
||||
|
||||
/* Free netlink data. */
|
||||
nl_free(&config);
|
||||
@@ -751,7 +792,6 @@ void nsexec(void)
|
||||
}
|
||||
default:
|
||||
bail("unexpected jump value");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Should never be reached. */
|
||||
|
16
vendor/github.com/opencontainers/runc/libcontainer/selinux/selinux.go
generated
vendored
16
vendor/github.com/opencontainers/runc/libcontainer/selinux/selinux.go
generated
vendored
@@ -374,9 +374,7 @@ func uniqMcs(catRange uint32) string {
|
||||
continue
|
||||
} else {
|
||||
if c1 > c2 {
|
||||
t := c1
|
||||
c1 = c2
|
||||
c2 = t
|
||||
c1, c2 = c2, c1
|
||||
}
|
||||
}
|
||||
mcs = fmt.Sprintf("s0:c%d,c%d", c1, c2)
|
||||
@@ -498,7 +496,7 @@ func badPrefix(fpath string) error {
|
||||
|
||||
for _, prefix := range badprefixes {
|
||||
if fpath == prefix || strings.HasPrefix(fpath, fmt.Sprintf("%s/", prefix)) {
|
||||
return fmt.Errorf("Relabeling content in %s is not allowed.", prefix)
|
||||
return fmt.Errorf("relabeling content in %s is not allowed", prefix)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -538,14 +536,14 @@ func DupSecOpt(src string) []string {
|
||||
con["level"] == "" {
|
||||
return nil
|
||||
}
|
||||
return []string{"label=user:" + con["user"],
|
||||
"label=role:" + con["role"],
|
||||
"label=type:" + con["type"],
|
||||
"label=level:" + con["level"]}
|
||||
return []string{"user:" + con["user"],
|
||||
"role:" + con["role"],
|
||||
"type:" + con["type"],
|
||||
"level:" + con["level"]}
|
||||
}
|
||||
|
||||
// DisableSecOpt returns a security opt that can be used to disabling SELinux
|
||||
// labeling support for future container processes
|
||||
func DisableSecOpt() []string {
|
||||
return []string{"label=disable"}
|
||||
return []string{"disable"}
|
||||
}
|
||||
|
2
vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.c
generated
vendored
2
vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.c
generated
vendored
@@ -131,7 +131,7 @@ struct file_t recvfd(int sockfd)
|
||||
if (cmsg->cmsg_type != SCM_RIGHTS)
|
||||
error("recvfd: expected SCM_RIGHTS in cmsg: %d", cmsg->cmsg_type);
|
||||
if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)))
|
||||
error("recvfd: expected correct CMSG_LEN in cmsg: %lu", cmsg->cmsg_len);
|
||||
error("recvfd: expected correct CMSG_LEN in cmsg: %lu", (unsigned long)cmsg->cmsg_len);
|
||||
|
||||
fdptr = (int *) CMSG_DATA(cmsg);
|
||||
if (!fdptr || *fdptr < 0)
|
||||
|
Reference in New Issue
Block a user