!1 runc: package init

Merge pull request !1 from Grooooot/master
This commit is contained in:
openeuler-ci-bot 2019-12-29 16:36:17 +08:00 committed by Gitee
commit b862929a21
114 changed files with 138801 additions and 0 deletions

24
apply-patch Normal file
View File

@ -0,0 +1,24 @@
#!/bin/bash
# Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved.
# Description: This shell script is used to apply patches for the project
# Author: jingrui@huawei.com
# Create: 2019-03-02
pkg=runc-1.0.0-rc3
cwd=$PWD
src=$cwd/$pkg
unzip $pkg.zip
series=$cwd/series.conf
while IPF= read -r line
do
if [[ "$line" =~ ^0.* ]]; then
cd $src && patch -p1 < $cwd/patch/$line
fi
done <"$series"
cd $cwd
cp -rf $src/* .
rm -rf runc-1.0.0-rc3

View File

@ -0,0 +1,40 @@
From 3eb678a633ddf3be06851a1b8c69a98650e9a367 Mon Sep 17 00:00:00 2001
From: "W. Trevor King" <wking@tremily.us>
Date: Tue, 21 Mar 2017 11:48:39 -0700
Subject: [PATCH 01/94] .travis.yml: Don't require FETCH_HEAD
Master builds only have a 'git clone ...' [1] so FETCH_HEAD isn't
defined and git-validation crashes [2]. We don't want to be
hard-coding a range here, and should update git-validation to handle
these cases automatically.
Also echo TRAVIS_* variables during testing to make debugging
git-validation easier.
[1]: https://travis-ci.org/opencontainers/runc/jobs/213508696#L243
[2]: https://travis-ci.org/opencontainers/runc/jobs/213508696#L347
Change-Id: I325ae392323133b123f0ef7577a4464ae10a54cb
Signed-off-by: W. Trevor King <wking@tremily.us>
---
.travis.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index 04f71f5..244c643 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -23,8 +23,9 @@ before_install:
- go get -u github.com/golang/lint/golint
- go get -u github.com/vbatts/git-validation
- go get -u github.com/mvdan/sh/cmd/shfmt
+ - env | grep TRAVIS_
script:
- - git-validation -run DCO,short-subject -v -range ${TRAVIS_BRANCH}..FETCH_HEAD
+ - git-validation -run DCO,short-subject -v
- make BUILDTAGS="${BUILDTAGS}"
- make BUILDTAGS="${BUILDTAGS}" clean validate test
--
2.7.4.3

View File

@ -0,0 +1,43 @@
From 4ccbadc228c9e4fc0fd20690ca13517f02aab59d Mon Sep 17 00:00:00 2001
From: Andrei Vagin <avagin@virtuozzo.com>
Date: Thu, 23 Mar 2017 01:43:39 +0300
Subject: [PATCH 02/94] Don't try to read freezer.state from the
current directory
If we try to pause a container on the system without freezer cgroups,
we can found that runc tries to open ./freezer.state. It is obviously wrong.
$ ./runc pause test
no such directory for freezer.state
$ echo FROZEN > freezer.state
$ ./runc pause test
container not running or created: paused
Change-Id: Ia7eba3a300a7ca6f1e8e10e4b1cbb4360e083e33
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
---
libcontainer/container_linux.go | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 28dff86..cd9235d 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -1284,7 +1284,12 @@ func (c *linuxContainer) runType() (Status, error) {
}
func (c *linuxContainer) isPaused() (bool, error) {
- data, err := ioutil.ReadFile(filepath.Join(c.cgroupManager.GetPaths()["freezer"], "freezer.state"))
+ fcg := c.cgroupManager.GetPaths()["freezer"]
+ if fcg == "" {
+ // A container doesn't have a freezer cgroup
+ return false, nil
+ }
+ data, err := ioutil.ReadFile(filepath.Join(fcg, "freezer.state"))
if err != nil {
// If freezer cgroup is not mounted, the container would just be not paused.
if os.IsNotExist(err) {
--
2.7.4.3

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,272 @@
From 511eb03806523b4f51cbde7daedd563a3b5810e4 Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <asarai@suse.de>
Date: Tue, 17 Jan 2017 12:25:21 +1100
Subject: [PATCH 04/94] *: handle unprivileged operations and
!dumpable
Effectively, !dumpable makes implementing rootless containers quite
hard, due to a bunch of different operations on /proc/self no longer
being possible without reordering everything.
!dumpable only really makes sense when you are switching between
different security contexts, which is only the case when we are joining
namespaces. Unfortunately this means that !dumpable will still have
issues in this instance, and it should only be necessary to set
!dumpable if we are not joining USER namespaces (new kernels have
protections that make !dumpable no longer necessary). But that's a topic
for another time.
This also includes code to unset and then re-set dumpable when doing the
USER namespace mappings. This should also be safe because in principle
processes in a container can't see us until after we fork into the PID
namespace (which happens after the user mapping).
In rootless containers, it is not possible to set a non-dumpable
process's /proc/self/oom_score_adj (it's owned by root and thus not
writeable). Thus, it needs to be set inside nsexec before we set
ourselves as non-dumpable.
Change-Id: Iab9e2d9bf3997284253b4b33a504e8581fd787ae
Signed-off-by: Aleksa Sarai <asarai@suse.de>
---
libcontainer/container_linux.go | 6 ++++
libcontainer/init_linux.go | 8 ------
libcontainer/message_linux.go | 14 +++++----
libcontainer/nsenter/nsexec.c | 64 ++++++++++++++++++++++++++++++++++-------
libcontainer/process_linux.go | 8 ------
5 files changed, 68 insertions(+), 32 deletions(-)
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index cd9235d..d2e0e2b 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -1460,5 +1460,11 @@ func (c *linuxContainer) bootstrapData(cloneFlags uintptr, nsMaps map[configs.Na
}
}
+ // write oom_score_adj
+ r.AddData(&Bytemsg{
+ Type: OomScoreAdjAttr,
+ Value: []byte(fmt.Sprintf("%d", c.config.OomScoreAdj)),
+ })
+
return bytes.NewReader(r.Serialize()), nil
}
diff --git a/libcontainer/init_linux.go b/libcontainer/init_linux.go
index 39b83a4..0f5d412 100644
--- a/libcontainer/init_linux.go
+++ b/libcontainer/init_linux.go
@@ -6,10 +6,8 @@ import (
"encoding/json"
"fmt"
"io"
- "io/ioutil"
"net"
"os"
- "strconv"
"strings"
"syscall"
"unsafe"
@@ -369,12 +367,6 @@ func setupRlimits(limits []configs.Rlimit, pid int) error {
return nil
}
-func setOomScoreAdj(oomScoreAdj int, pid int) error {
- path := fmt.Sprintf("/proc/%d/oom_score_adj", pid)
-
- return ioutil.WriteFile(path, []byte(strconv.Itoa(oomScoreAdj)), 0600)
-}
-
const _P_PID = 1
type siginfo struct {
diff --git a/libcontainer/message_linux.go b/libcontainer/message_linux.go
index a189c72..321d664 100644
--- a/libcontainer/message_linux.go
+++ b/libcontainer/message_linux.go
@@ -11,12 +11,14 @@ import (
// list of known message types we want to send to bootstrap program
// The number is randomly chosen to not conflict with known netlink types
const (
- InitMsg uint16 = 62000
- CloneFlagsAttr uint16 = 27281
- NsPathsAttr uint16 = 27282
- UidmapAttr uint16 = 27283
- GidmapAttr uint16 = 27284
- SetgroupAttr uint16 = 27285
+ InitMsg uint16 = 62000
+ CloneFlagsAttr uint16 = 27281
+ NsPathsAttr uint16 = 27282
+ UidmapAttr uint16 = 27283
+ GidmapAttr uint16 = 27284
+ SetgroupAttr uint16 = 27285
+ OomScoreAdjAttr uint16 = 27286
+
// When syscall.NLA_HDRLEN is in gccgo, take this out.
syscall_NLA_HDRLEN = (syscall.SizeofNlAttr + syscall.NLA_ALIGNTO - 1) & ^(syscall.NLA_ALIGNTO - 1)
)
diff --git a/libcontainer/nsenter/nsexec.c b/libcontainer/nsenter/nsexec.c
index 51bd1e3..9630206 100644
--- a/libcontainer/nsenter/nsexec.c
+++ b/libcontainer/nsenter/nsexec.c
@@ -72,18 +72,21 @@ struct nlconfig_t {
char *namespaces;
size_t namespaces_len;
uint8_t is_setgroup;
+ char *oom_score_adj;
+ size_t oom_score_adj_len;
};
/*
* List of netlink message types sent to us as part of bootstrapping the init.
* These constants are defined in libcontainer/message_linux.go.
*/
-#define INIT_MSG 62000
+#define INIT_MSG 62000
#define CLONE_FLAGS_ATTR 27281
#define NS_PATHS_ATTR 27282
-#define UIDMAP_ATTR 27283
-#define GIDMAP_ATTR 27284
+#define UIDMAP_ATTR 27283
+#define GIDMAP_ATTR 27284
#define SETGROUP_ATTR 27285
+#define OOM_SCORE_ADJ_ATTR 27286
/*
* Use the raw syscall for versions of glibc which don't include a function for
@@ -186,7 +189,7 @@ static void update_setgroups(int pid, enum policy_t setgroup)
}
}
-static void update_uidmap(int pid, char *map, int map_len)
+static void update_uidmap(int pid, char *map, size_t map_len)
{
if (map == NULL || map_len <= 0)
return;
@@ -195,7 +198,7 @@ static void update_uidmap(int pid, char *map, int map_len)
bail("failed to update /proc/%d/uid_map", pid);
}
-static void update_gidmap(int pid, char *map, int map_len)
+static void update_gidmap(int pid, char *map, size_t map_len)
{
if (map == NULL || map_len <= 0)
return;
@@ -204,6 +207,15 @@ static void update_gidmap(int pid, char *map, int map_len)
bail("failed to update /proc/%d/gid_map", pid);
}
+static void update_oom_score_adj(char *data, size_t len)
+{
+ if (data == NULL || len <= 0)
+ return;
+
+ if (write_file(data, len, "/proc/self/oom_score_adj") < 0)
+ bail("failed to update /proc/self/oom_score_adj");
+}
+
/* A dummy function that just jumps to the given jumpval. */
static int child_func(void *arg) __attribute__ ((noinline));
static int child_func(void *arg)
@@ -317,6 +329,10 @@ static void nl_parse(int fd, struct nlconfig_t *config)
case CLONE_FLAGS_ATTR:
config->cloneflags = readint32(current);
break;
+ case OOM_SCORE_ADJ_ATTR:
+ config->oom_score_adj = current;
+ config->oom_score_adj_len = payload_len;
+ break;
case NS_PATHS_ATTR:
config->namespaces = current;
config->namespaces_len = payload_len;
@@ -425,14 +441,32 @@ void nsexec(void)
if (pipenum == -1)
return;
- /* make the process non-dumpable */
- if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) != 0) {
- bail("failed to set process as non-dumpable");
- }
-
/* Parse all of the netlink configuration. */
nl_parse(pipenum, &config);
+ /* Set oom_score_adj. This has to be done before !dumpable because
+ * /proc/self/oom_score_adj is not writeable unless you're an privileged
+ * user (if !dumpable is set). All children inherit their parent's
+ * oom_score_adj value on fork(2) so this will always be propagated
+ * properly.
+ */
+ update_oom_score_adj(config.oom_score_adj, config.oom_score_adj_len);
+
+ /*
+ * Make the process non-dumpable, to avoid various race conditions that
+ * could cause processes in namespaces we're joining to access host
+ * resources (or potentially execute code).
+ *
+ * However, if the number of namespaces we are joining is 0, we are not
+ * going to be switching to a different security context. Thus setting
+ * ourselves to be non-dumpable only breaks things (like rootless
+ * containers), which is the recommendation from the kernel folks.
+ */
+ if (config.namespaces) {
+ if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) < 0)
+ bail("failed to set process as non-dumpable");
+ }
+
/* Pipe so we can tell the child when we've finished setting up. */
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sync_child_pipe) < 0)
bail("failed to setup sync pipe between parent and child");
@@ -681,6 +715,11 @@ void nsexec(void)
* clone_parent rant). So signal our parent to hook us up.
*/
+ /* Switching is only necessary if we joined namespaces. */
+ if (config.namespaces) {
+ if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0)
+ bail("failed to set process as dumpable");
+ }
s = SYNC_USERMAP_PLS;
if (write(syncfd, &s, sizeof(s)) != sizeof(s))
bail("failed to sync with parent: write(SYNC_USERMAP_PLS)");
@@ -691,6 +730,11 @@ void nsexec(void)
bail("failed to sync with parent: read(SYNC_USERMAP_ACK)");
if (s != SYNC_USERMAP_ACK)
bail("failed to sync with parent: SYNC_USERMAP_ACK: got %u", s);
+ /* Switching is only necessary if we joined namespaces. */
+ if (config.namespaces) {
+ if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) < 0)
+ bail("failed to set process as dumpable");
+ }
}
/*
diff --git a/libcontainer/process_linux.go b/libcontainer/process_linux.go
index 0f79a38..c60f473 100644
--- a/libcontainer/process_linux.go
+++ b/libcontainer/process_linux.go
@@ -85,10 +85,6 @@ func (p *setnsProcess) start() (err error) {
return newSystemErrorWithCausef(err, "adding pid %d to cgroups", p.pid())
}
}
- // set oom_score_adj
- if err := setOomScoreAdj(p.config.Config.OomScoreAdj, p.pid()); err != nil {
- return newSystemErrorWithCause(err, "setting oom score")
- }
// set rlimits, this has to be done here because we lose permissions
// to raise the limits once we enter a user-namespace
if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil {
@@ -285,10 +281,6 @@ func (p *initProcess) start() error {
if err := p.manager.Set(p.config.Config); err != nil {
return newSystemErrorWithCause(err, "setting cgroup config for ready process")
}
- // set oom_score_adj
- if err := setOomScoreAdj(p.config.Config.OomScoreAdj, p.pid()); err != nil {
- return newSystemErrorWithCause(err, "setting oom score for ready process")
- }
// set rlimits, this has to be done here because we lose permissions
// to raise the limits once we enter a user-namespace
if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil {
--
2.7.4.3

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,421 @@
From 6c69b3f5c8eb23eb47917371b4ae69a76912ec83 Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <asarai@suse.de>
Date: Tue, 26 Apr 2016 02:19:39 +1000
Subject: [PATCH 06/94] rootless: add rootless cgroup manager
The rootless cgroup manager acts as a noop for all set and apply
operations. It is just used for rootless setups. Currently this is far
too simple (we need to add opportunistic cgroup management), but is good
enough as a first-pass at a noop cgroup manager.
Change-Id: Iae5668680e5e2896246792fe6f2ac1bb37eab1d5
Signed-off-by: Aleksa Sarai <asarai@suse.de>
---
libcontainer/cgroups/fs/apply_raw.go | 24 +----
libcontainer/cgroups/rootless/rootless.go | 128 ++++++++++++++++++++++++++
libcontainer/cgroups/systemd/apply_systemd.go | 2 +-
libcontainer/cgroups/utils.go | 41 ++++++++-
libcontainer/container_linux.go | 8 ++
libcontainer/factory_linux.go | 22 +++++
libcontainer/process_linux.go | 20 ++--
libcontainer/rootfs_linux.go | 2 +-
8 files changed, 210 insertions(+), 37 deletions(-)
create mode 100644 libcontainer/cgroups/rootless/rootless.go
diff --git a/libcontainer/cgroups/fs/apply_raw.go b/libcontainer/cgroups/fs/apply_raw.go
index d316313..22d82ac 100644
--- a/libcontainer/cgroups/fs/apply_raw.go
+++ b/libcontainer/cgroups/fs/apply_raw.go
@@ -267,25 +267,8 @@ func getCgroupData(c *configs.Cgroup, pid int) (*cgroupData, error) {
}, nil
}
-func (raw *cgroupData) parentPath(subsystem, mountpoint, root string) (string, error) {
- // Use GetThisCgroupDir instead of GetInitCgroupDir, because the creating
- // process could in container and shared pid namespace with host, and
- // /proc/1/cgroup could point to whole other world of cgroups.
- initPath, err := cgroups.GetThisCgroupDir(subsystem)
- if err != nil {
- return "", err
- }
- // This is needed for nested containers, because in /proc/self/cgroup we
- // see pathes from host, which don't exist in container.
- relDir, err := filepath.Rel(root, initPath)
- if err != nil {
- return "", err
- }
- return filepath.Join(mountpoint, relDir), nil
-}
-
func (raw *cgroupData) path(subsystem string) (string, error) {
- mnt, root, err := cgroups.FindCgroupMountpointAndRoot(subsystem)
+ mnt, err := cgroups.FindCgroupMountpoint(subsystem)
// If we didn't mount the subsystem, there is no point we make the path.
if err != nil {
return "", err
@@ -297,7 +280,10 @@ func (raw *cgroupData) path(subsystem string) (string, error) {
return filepath.Join(raw.root, filepath.Base(mnt), raw.innerPath), nil
}
- parentPath, err := raw.parentPath(subsystem, mnt, root)
+ // Use GetOwnCgroupPath instead of GetInitCgroupPath, because the creating
+ // process could in container and shared pid namespace with host, and
+ // /proc/1/cgroup could point to whole other world of cgroups.
+ parentPath, err := cgroups.GetOwnCgroupPath(subsystem)
if err != nil {
return "", err
}
diff --git a/libcontainer/cgroups/rootless/rootless.go b/libcontainer/cgroups/rootless/rootless.go
new file mode 100644
index 0000000..b1efbfd
--- /dev/null
+++ b/libcontainer/cgroups/rootless/rootless.go
@@ -0,0 +1,128 @@
+// +build linux
+
+package rootless
+
+import (
+ "fmt"
+
+ "github.com/opencontainers/runc/libcontainer/cgroups"
+ "github.com/opencontainers/runc/libcontainer/cgroups/fs"
+ "github.com/opencontainers/runc/libcontainer/configs"
+ "github.com/opencontainers/runc/libcontainer/configs/validate"
+)
+
+// TODO: This is copied from libcontainer/cgroups/fs, which duplicates this code
+// needlessly. We should probably export this list.
+
+var subsystems = []subsystem{
+ &fs.CpusetGroup{},
+ &fs.DevicesGroup{},
+ &fs.MemoryGroup{},
+ &fs.CpuGroup{},
+ &fs.CpuacctGroup{},
+ &fs.PidsGroup{},
+ &fs.BlkioGroup{},
+ &fs.HugetlbGroup{},
+ &fs.NetClsGroup{},
+ &fs.NetPrioGroup{},
+ &fs.PerfEventGroup{},
+ &fs.FreezerGroup{},
+ &fs.NameGroup{GroupName: "name=systemd"},
+}
+
+type subsystem interface {
+ // Name returns the name of the subsystem.
+ Name() string
+
+ // Returns the stats, as 'stats', corresponding to the cgroup under 'path'.
+ GetStats(path string, stats *cgroups.Stats) error
+}
+
+// The noop cgroup manager is used for rootless containers, because we currently
+// cannot manage cgroups if we are in a rootless setup. This manager is chosen
+// by factory if we are in rootless mode. We error out if any cgroup options are
+// set in the config -- this may change in the future with upcoming kernel features
+// like the cgroup namespace.
+
+type Manager struct {
+ Cgroups *configs.Cgroup
+ Paths map[string]string
+}
+
+func (m *Manager) Apply(pid int) error {
+ // If there are no cgroup settings, there's nothing to do.
+ if m.Cgroups == nil {
+ return nil
+ }
+
+ // We can't set paths.
+ // TODO(cyphar): Implement the case where the runner of a rootless container
+ // owns their own cgroup, which would allow us to set up a
+ // cgroup for each path.
+ if m.Cgroups.Paths != nil {
+ return fmt.Errorf("cannot change cgroup path in rootless container")
+ }
+
+ // We load the paths into the manager.
+ paths := make(map[string]string)
+ for _, sys := range subsystems {
+ name := sys.Name()
+
+ path, err := cgroups.GetOwnCgroupPath(name)
+ if err != nil {
+ // Ignore paths we couldn't resolve.
+ continue
+ }
+
+ paths[name] = path
+ }
+
+ m.Paths = paths
+ return nil
+}
+
+func (m *Manager) GetPaths() map[string]string {
+ return m.Paths
+}
+
+func (m *Manager) Set(container *configs.Config) error {
+ // We have to re-do the validation here, since someone might decide to
+ // update a rootless container.
+ return validate.New().Validate(container)
+}
+
+func (m *Manager) GetPids() ([]int, error) {
+ dir, err := cgroups.GetOwnCgroupPath("devices")
+ if err != nil {
+ return nil, err
+ }
+ return cgroups.GetPids(dir)
+}
+
+func (m *Manager) GetAllPids() ([]int, error) {
+ dir, err := cgroups.GetOwnCgroupPath("devices")
+ if err != nil {
+ return nil, err
+ }
+ return cgroups.GetAllPids(dir)
+}
+
+func (m *Manager) GetStats() (*cgroups.Stats, error) {
+ // TODO(cyphar): We can make this work if we figure out a way to allow usage
+ // of cgroups with a rootless container. While this doesn't
+ // actually require write access to a cgroup directory, the
+ // statistics are not useful if they can be affected by
+ // non-container processes.
+ return nil, fmt.Errorf("cannot get cgroup stats in rootless container")
+}
+
+func (m *Manager) Freeze(state configs.FreezerState) error {
+ // TODO(cyphar): We can make this work if we figure out a way to allow usage
+ // of cgroups with a rootless container.
+ return fmt.Errorf("cannot use freezer cgroup in rootless container")
+}
+
+func (m *Manager) Destroy() error {
+ // We don't have to do anything here because we didn't do any setup.
+ return nil
+}
diff --git a/libcontainer/cgroups/systemd/apply_systemd.go b/libcontainer/cgroups/systemd/apply_systemd.go
index 2872bfa..456c57d 100644
--- a/libcontainer/cgroups/systemd/apply_systemd.go
+++ b/libcontainer/cgroups/systemd/apply_systemd.go
@@ -426,7 +426,7 @@ func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) {
return "", err
}
- initPath, err := cgroups.GetInitCgroupDir(subsystem)
+ initPath, err := cgroups.GetInitCgroup(subsystem)
if err != nil {
return "", err
}
diff --git a/libcontainer/cgroups/utils.go b/libcontainer/cgroups/utils.go
index 52fc87e..5db3734 100644
--- a/libcontainer/cgroups/utils.go
+++ b/libcontainer/cgroups/utils.go
@@ -109,7 +109,7 @@ type Mount struct {
Subsystems []string
}
-func (m Mount) GetThisCgroupDir(cgroups map[string]string) (string, error) {
+func (m Mount) GetOwnCgroup(cgroups map[string]string) (string, error) {
if len(m.Subsystems) == 0 {
return "", fmt.Errorf("no subsystem for mount")
}
@@ -203,8 +203,8 @@ func GetAllSubsystems() ([]string, error) {
return subsystems, nil
}
-// GetThisCgroupDir returns the relative path to the cgroup docker is running in.
-func GetThisCgroupDir(subsystem string) (string, error) {
+// GetOwnCgroup returns the relative path to the cgroup docker is running in.
+func GetOwnCgroup(subsystem string) (string, error) {
cgroups, err := ParseCgroupFile("/proc/self/cgroup")
if err != nil {
return "", err
@@ -213,8 +213,16 @@ func GetThisCgroupDir(subsystem string) (string, error) {
return getControllerPath(subsystem, cgroups)
}
-func GetInitCgroupDir(subsystem string) (string, error) {
+func GetOwnCgroupPath(subsystem string) (string, error) {
+ cgroup, err := GetOwnCgroup(subsystem)
+ if err != nil {
+ return "", err
+ }
+ return getCgroupPathHelper(subsystem, cgroup)
+}
+
+func GetInitCgroup(subsystem string) (string, error) {
cgroups, err := ParseCgroupFile("/proc/1/cgroup")
if err != nil {
return "", err
@@ -223,6 +231,31 @@ func GetInitCgroupDir(subsystem string) (string, error) {
return getControllerPath(subsystem, cgroups)
}
+func GetInitCgroupPath(subsystem string) (string, error) {
+ cgroup, err := GetInitCgroup(subsystem)
+ if err != nil {
+ return "", err
+ }
+
+ return getCgroupPathHelper(subsystem, cgroup)
+}
+
+func getCgroupPathHelper(subsystem, cgroup string) (string, error) {
+ mnt, root, err := FindCgroupMountpointAndRoot(subsystem)
+ if err != nil {
+ return "", err
+ }
+
+ // This is needed for nested containers, because in /proc/self/cgroup we
+ // see pathes from host, which don't exist in container.
+ relCgroup, err := filepath.Rel(root, cgroup)
+ if err != nil {
+ return "", err
+ }
+
+ return filepath.Join(mnt, relCgroup), nil
+}
+
func readProcsFile(dir string) ([]int, error) {
f, err := os.Open(filepath.Join(dir, CgroupProcesses))
if err != nil {
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 372763a..d847f18 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -520,10 +520,18 @@ func (c *linuxContainer) Resume() error {
}
func (c *linuxContainer) NotifyOOM() (<-chan struct{}, error) {
+ // XXX(cyphar): This requires cgroups.
+ if c.config.Rootless {
+ return nil, fmt.Errorf("cannot get OOM notifications from rootless container")
+ }
return notifyOnOOM(c.cgroupManager.GetPaths())
}
func (c *linuxContainer) NotifyMemoryPressure(level PressureLevel) (<-chan struct{}, error) {
+ // XXX(cyphar): This requires cgroups.
+ if c.config.Rootless {
+ return nil, fmt.Errorf("cannot get memory pressure notifications from rootless container")
+ }
return notifyMemoryPressure(c.cgroupManager.GetPaths(), level)
}
diff --git a/libcontainer/factory_linux.go b/libcontainer/factory_linux.go
index d553287..1f965e6 100644
--- a/libcontainer/factory_linux.go
+++ b/libcontainer/factory_linux.go
@@ -15,6 +15,7 @@ import (
"github.com/docker/docker/pkg/mount"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/cgroups/fs"
+ "github.com/opencontainers/runc/libcontainer/cgroups/rootless"
"github.com/opencontainers/runc/libcontainer/cgroups/systemd"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/configs/validate"
@@ -73,6 +74,20 @@ func Cgroupfs(l *LinuxFactory) error {
return nil
}
+// RootlessCgroups is an options func to configure a LinuxFactory to
+// return containers that use the "rootless" cgroup manager, which will
+// fail to do any operations not possible to do with an unprivileged user.
+// It should only be used in conjunction with rootless containers.
+func RootlessCgroups(l *LinuxFactory) error {
+ l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
+ return &rootless.Manager{
+ Cgroups: config,
+ Paths: paths,
+ }
+ }
+ return nil
+}
+
// TmpfsRoot is an option func to mount LinuxFactory.Root to tmpfs.
func TmpfsRoot(l *LinuxFactory) error {
mounted, err := mount.Mounted(l.Root)
@@ -169,6 +184,9 @@ func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, err
if err := os.Chown(containerRoot, uid, gid); err != nil {
return nil, newGenericError(err, SystemError)
}
+ if config.Rootless {
+ RootlessCgroups(l)
+ }
c := &linuxContainer{
id: id,
root: containerRoot,
@@ -195,6 +213,10 @@ func (l *LinuxFactory) Load(id string) (Container, error) {
processStartTime: state.InitProcessStartTime,
fds: state.ExternalDescriptors,
}
+ // We have to use the RootlessManager.
+ if state.Rootless {
+ RootlessCgroups(l)
+ }
c := &linuxContainer{
initProcess: r,
initProcessStartTime: state.InitProcessStartTime,
diff --git a/libcontainer/process_linux.go b/libcontainer/process_linux.go
index e8b7506..bfe9955 100644
--- a/libcontainer/process_linux.go
+++ b/libcontainer/process_linux.go
@@ -254,15 +254,14 @@ func (p *initProcess) start() error {
return newSystemErrorWithCausef(err, "getting pipe fds for pid %d", p.pid())
}
p.setExternalDescriptors(fds)
- if !p.container.config.Rootless {
- // Do this before syncing with child so that no children can escape the
- // cgroup. We can't do this if we're not running as root.
- if err := p.manager.Apply(p.pid()); err != nil {
- return newSystemErrorWithCause(err, "applying cgroup configuration for process")
- }
+ // Do this before syncing with child so that no children can escape the
+ // cgroup. We don't need to worry about not doing this and not being root
+ // because we'd be using the rootless cgroup manager in that case.
+ if err := p.manager.Apply(p.pid()); err != nil {
+ return newSystemErrorWithCause(err, "applying cgroup configuration for process")
}
defer func() {
- if err != nil && !p.container.config.Rootless {
+ if err != nil {
// TODO: should not be the responsibility to call here
p.manager.Destroy()
}
@@ -281,11 +280,8 @@ func (p *initProcess) start() error {
ierr := parseSync(p.parentPipe, func(sync *syncT) error {
switch sync.Type {
case procReady:
- // We can't set cgroups if we're in a rootless container.
- if !p.container.config.Rootless {
- if err := p.manager.Set(p.config.Config); err != nil {
- return newSystemErrorWithCause(err, "setting cgroup config for ready process")
- }
+ if err := p.manager.Set(p.config.Config); err != nil {
+ return newSystemErrorWithCause(err, "setting cgroup config for ready process")
}
// set rlimits, this has to be done here because we lose permissions
// to raise the limits once we enter a user-namespace
diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go
index 1045a45..d507373 100644
--- a/libcontainer/rootfs_linux.go
+++ b/libcontainer/rootfs_linux.go
@@ -348,7 +348,7 @@ func getCgroupMounts(m *configs.Mount) ([]*configs.Mount, error) {
var binds []*configs.Mount
for _, mm := range mounts {
- dir, err := mm.GetThisCgroupDir(cgroupPaths)
+ dir, err := mm.GetOwnCgroup(cgroupPaths)
if err != nil {
return nil, err
}
--
2.7.4.3

View File

@ -0,0 +1,256 @@
From f139024bb220e087a20e8089b5dbd4fb4c06c4a8 Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <asarai@suse.de>
Date: Sat, 18 Mar 2017 04:32:16 +1100
Subject: [PATCH 07/94] libcontainer: configs: add proper HostUID and
HostGID
Previously Host{U,G}ID only gave you the root mapping, which isn't very
useful if you are trying to do other things with the IDMaps.
Change-Id: Idceb42455e258e5514c966fe8363693adb9d0028
Signed-off-by: Aleksa Sarai <asarai@suse.de>
---
libcontainer/configs/config_unix.go | 40 ++++++++++++++++++++-----------
libcontainer/configs/config_unix_test.go | 16 ++++++-------
libcontainer/configs/validate/rootless.go | 4 ++--
libcontainer/container_linux.go | 4 ++--
libcontainer/factory_linux.go | 4 ++--
libcontainer/specconv/spec_linux.go | 4 ++--
utils_linux.go | 4 ++--
7 files changed, 44 insertions(+), 32 deletions(-)
diff --git a/libcontainer/configs/config_unix.go b/libcontainer/configs/config_unix.go
index a60554a..8446399 100644
--- a/libcontainer/configs/config_unix.go
+++ b/libcontainer/configs/config_unix.go
@@ -4,38 +4,50 @@ package configs
import "fmt"
-// HostUID gets the root uid for the process on host which could be non-zero
-// when user namespaces are enabled.
-func (c Config) HostUID() (int, error) {
+// HostUID gets the translated uid for the process on host which could be
+// different when user namespaces are enabled.
+func (c Config) HostUID(containerId int) (int, error) {
if c.Namespaces.Contains(NEWUSER) {
if c.UidMappings == nil {
- return -1, fmt.Errorf("User namespaces enabled, but no user mappings found.")
+ return -1, fmt.Errorf("User namespaces enabled, but no uid mappings found.")
}
- id, found := c.hostIDFromMapping(0, c.UidMappings)
+ id, found := c.hostIDFromMapping(containerId, c.UidMappings)
if !found {
- return -1, fmt.Errorf("User namespaces enabled, but no root user mapping found.")
+ return -1, fmt.Errorf("User namespaces enabled, but no user mapping found.")
}
return id, nil
}
- // Return default root uid 0
- return 0, nil
+ // Return unchanged id.
+ return containerId, nil
}
-// HostGID gets the root gid for the process on host which could be non-zero
+// HostRootUID gets the root uid for the process on host which could be non-zero
// when user namespaces are enabled.
-func (c Config) HostGID() (int, error) {
+func (c Config) HostRootUID() (int, error) {
+ return c.HostUID(0)
+}
+
+// HostGID gets the translated gid for the process on host which could be
+// different when user namespaces are enabled.
+func (c Config) HostGID(containerId int) (int, error) {
if c.Namespaces.Contains(NEWUSER) {
if c.GidMappings == nil {
return -1, fmt.Errorf("User namespaces enabled, but no gid mappings found.")
}
- id, found := c.hostIDFromMapping(0, c.GidMappings)
+ id, found := c.hostIDFromMapping(containerId, c.GidMappings)
if !found {
- return -1, fmt.Errorf("User namespaces enabled, but no root group mapping found.")
+ return -1, fmt.Errorf("User namespaces enabled, but no group mapping found.")
}
return id, nil
}
- // Return default root gid 0
- return 0, nil
+ // Return unchanged id.
+ return containerId, nil
+}
+
+// HostRootGID gets the root gid for the process on host which could be non-zero
+// when user namespaces are enabled.
+func (c Config) HostRootGID() (int, error) {
+ return c.HostGID(0)
}
// Utility function that gets a host ID for a container ID from user namespace map
diff --git a/libcontainer/configs/config_unix_test.go b/libcontainer/configs/config_unix_test.go
index dc01cd0..7f96615 100644
--- a/libcontainer/configs/config_unix_test.go
+++ b/libcontainer/configs/config_unix_test.go
@@ -65,11 +65,11 @@ func TestRemoveNamespace(t *testing.T) {
}
}
-func TestHostUIDNoUSERNS(t *testing.T) {
+func TestHostRootUIDNoUSERNS(t *testing.T) {
config := &Config{
Namespaces: Namespaces{},
}
- uid, err := config.HostUID()
+ uid, err := config.HostRootUID()
if err != nil {
t.Fatal(err)
}
@@ -78,7 +78,7 @@ func TestHostUIDNoUSERNS(t *testing.T) {
}
}
-func TestHostUIDWithUSERNS(t *testing.T) {
+func TestHostRootUIDWithUSERNS(t *testing.T) {
config := &Config{
Namespaces: Namespaces{{Type: NEWUSER}},
UidMappings: []IDMap{
@@ -89,7 +89,7 @@ func TestHostUIDWithUSERNS(t *testing.T) {
},
},
}
- uid, err := config.HostUID()
+ uid, err := config.HostRootUID()
if err != nil {
t.Fatal(err)
}
@@ -98,11 +98,11 @@ func TestHostUIDWithUSERNS(t *testing.T) {
}
}
-func TestHostGIDNoUSERNS(t *testing.T) {
+func TestHostRootGIDNoUSERNS(t *testing.T) {
config := &Config{
Namespaces: Namespaces{},
}
- uid, err := config.HostGID()
+ uid, err := config.HostRootGID()
if err != nil {
t.Fatal(err)
}
@@ -111,7 +111,7 @@ func TestHostGIDNoUSERNS(t *testing.T) {
}
}
-func TestHostGIDWithUSERNS(t *testing.T) {
+func TestHostRootGIDWithUSERNS(t *testing.T) {
config := &Config{
Namespaces: Namespaces{{Type: NEWUSER}},
GidMappings: []IDMap{
@@ -122,7 +122,7 @@ func TestHostGIDWithUSERNS(t *testing.T) {
},
},
}
- uid, err := config.HostGID()
+ uid, err := config.HostRootGID()
if err != nil {
t.Fatal(err)
}
diff --git a/libcontainer/configs/validate/rootless.go b/libcontainer/configs/validate/rootless.go
index 1e83ced..0cebfaf 100644
--- a/libcontainer/configs/validate/rootless.go
+++ b/libcontainer/configs/validate/rootless.go
@@ -37,7 +37,7 @@ func (v *ConfigValidator) rootless(config *configs.Config) error {
}
func rootlessMappings(config *configs.Config) error {
- rootuid, err := config.HostUID()
+ rootuid, err := config.HostRootUID()
if err != nil {
return fmt.Errorf("failed to get root uid from uidMappings: %v", err)
}
@@ -50,7 +50,7 @@ func rootlessMappings(config *configs.Config) error {
}
}
- rootgid, err := config.HostGID()
+ rootgid, err := config.HostRootGID()
if err != nil {
return fmt.Errorf("failed to get root gid from gidMappings: %v", err)
}
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index d847f18..71fa682 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -307,11 +307,11 @@ func (c *linuxContainer) Signal(s os.Signal, all bool) error {
}
func (c *linuxContainer) createExecFifo() error {
- rootuid, err := c.Config().HostUID()
+ rootuid, err := c.Config().HostRootUID()
if err != nil {
return err
}
- rootgid, err := c.Config().HostGID()
+ rootgid, err := c.Config().HostRootGID()
if err != nil {
return err
}
diff --git a/libcontainer/factory_linux.go b/libcontainer/factory_linux.go
index 1f965e6..6a0f855 100644
--- a/libcontainer/factory_linux.go
+++ b/libcontainer/factory_linux.go
@@ -164,11 +164,11 @@ func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, err
if err := l.Validator.Validate(config); err != nil {
return nil, newGenericError(err, ConfigInvalid)
}
- uid, err := config.HostUID()
+ uid, err := config.HostRootUID()
if err != nil {
return nil, newGenericError(err, SystemError)
}
- gid, err := config.HostGID()
+ gid, err := config.HostRootGID()
if err != nil {
return nil, newGenericError(err, SystemError)
}
diff --git a/libcontainer/specconv/spec_linux.go b/libcontainer/specconv/spec_linux.go
index 346b268..1575ae0 100644
--- a/libcontainer/specconv/spec_linux.go
+++ b/libcontainer/specconv/spec_linux.go
@@ -610,11 +610,11 @@ func setupUserNamespace(spec *specs.Spec, config *configs.Config) error {
for _, m := range spec.Linux.GIDMappings {
config.GidMappings = append(config.GidMappings, create(m))
}
- rootUID, err := config.HostUID()
+ rootUID, err := config.HostRootUID()
if err != nil {
return err
}
- rootGID, err := config.HostGID()
+ rootGID, err := config.HostRootGID()
if err != nil {
return err
}
diff --git a/utils_linux.go b/utils_linux.go
index 767015e..c6a8c02 100644
--- a/utils_linux.go
+++ b/utils_linux.go
@@ -242,12 +242,12 @@ func (r *runner) run(config *specs.Process) (int, error) {
for i := baseFd; i < baseFd+r.preserveFDs; i++ {
process.ExtraFiles = append(process.ExtraFiles, os.NewFile(uintptr(i), "PreserveFD:"+strconv.Itoa(i)))
}
- rootuid, err := r.container.Config().HostUID()
+ rootuid, err := r.container.Config().HostRootUID()
if err != nil {
r.destroy()
return -1, err
}
- rootgid, err := r.container.Config().HostGID()
+ rootgid, err := r.container.Config().HostRootGID()
if err != nil {
r.destroy()
return -1, err
--
2.7.4.3

View File

@ -0,0 +1,64 @@
From f4158e00cac1f576f61904a73530c373c15354e2 Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <asarai@suse.de>
Date: Sat, 18 Mar 2017 04:33:14 +1100
Subject: [PATCH 08/94] libcontainer: init: fix unmapped console
fchown
If the stdio of the container is owned by a group which is not mapped in
the user namespace, attempting to fchown the file descriptor will result
in EINVAL. Counteract this by simply not doing an fchown if the group
owner of the file descriptor has no host mapping according to the
configured GIDMappings.
Change-Id: I7a7911f398a38b2d21e1bb6bc4b3131f6504ca8d
Signed-off-by: Aleksa Sarai <asarai@suse.de>
---
libcontainer/init_linux.go | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/libcontainer/init_linux.go b/libcontainer/init_linux.go
index 1187835..99cc02c 100644
--- a/libcontainer/init_linux.go
+++ b/libcontainer/init_linux.go
@@ -277,7 +277,7 @@ func setupUser(config *initConfig) error {
// before we change to the container's user make sure that the processes STDIO
// is correctly owned by the user that we are switching to.
- if err := fixStdioPermissions(execUser); err != nil {
+ if err := fixStdioPermissions(config, execUser); err != nil {
return err
}
@@ -312,7 +312,7 @@ func setupUser(config *initConfig) error {
// fixStdioPermissions fixes the permissions of PID 1's STDIO within the container to the specified user.
// The ownership needs to match because it is created outside of the container and needs to be
// localized.
-func fixStdioPermissions(u *user.ExecUser) error {
+func fixStdioPermissions(config *initConfig, u *user.ExecUser) error {
var null syscall.Stat_t
if err := syscall.Stat("/dev/null", &null); err != nil {
return err
@@ -326,10 +326,20 @@ func fixStdioPermissions(u *user.ExecUser) error {
if err := syscall.Fstat(int(fd), &s); err != nil {
return err
}
+
// Skip chown of /dev/null if it was used as one of the STDIO fds.
if s.Rdev == null.Rdev {
continue
}
+
+ // Skip chown if s.Gid is actually an unmapped gid in the host. While
+ // this is a bit dodgy if it just so happens that the console _is_
+ // owned by overflow_gid, there's no way for us to disambiguate this as
+ // a userspace program.
+ if _, err := config.Config.HostGID(int(s.Gid)); err != nil {
+ continue
+ }
+
// We only change the uid owner (as it is possible for the mount to
// prefer a different gid, and there's no reason for us to change it).
// The reason why we don't just leave the default uid=X mount setup is
--
2.7.4.3

View File

@ -0,0 +1,203 @@
From bdc84a618b475cc21a39dfa2fe57eae68b6110b6 Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <asarai@suse.de>
Date: Mon, 9 May 2016 21:26:11 +1000
Subject: [PATCH 09/94] rootless: add autogenerated rootless config
from `runc spec`
Since this is a runC-specific feature, this belongs here over in
opencontainers/ocitools (which is for generic OCI runtimes).
In addition, we don't create a new network namespace. This is because
currently if you want to set up a veth bridge you need CAP_NET_ADMIN in
both network namespaces' pinned user namespace to create the necessary
interfaces in each network namespace.
Change-Id: I682b9c82f75c04b58d523ddb084b6adbb543e3d1
Signed-off-by: Aleksa Sarai <asarai@suse.de>
---
libcontainer/specconv/example.go | 73 ++++++++++++++++++++++++++++++--
libcontainer/specconv/spec_linux_test.go | 30 +++----------
spec.go | 11 ++++-
3 files changed, 85 insertions(+), 29 deletions(-)
diff --git a/libcontainer/specconv/example.go b/libcontainer/specconv/example.go
index 44fad97..9a4460c 100644
--- a/libcontainer/specconv/example.go
+++ b/libcontainer/specconv/example.go
@@ -1,16 +1,18 @@
package specconv
import (
+ "os"
"runtime"
+ "strings"
"github.com/opencontainers/runtime-spec/specs-go"
)
func sPtr(s string) *string { return &s }
-// ExampleSpec returns an example spec file, with many options set so a user
-// can see what a standard spec file looks like.
-func ExampleSpec() *specs.Spec {
+// Example returns an example spec file, with many options set so a user can
+// see what a standard spec file looks like.
+func Example() *specs.Spec {
return &specs.Spec{
Version: specs.Version,
Platform: specs.Platform{
@@ -158,3 +160,68 @@ func ExampleSpec() *specs.Spec {
},
}
}
+
+// ExampleRootless returns an example spec file that works with rootless
+// containers. It's essentially a modified version of the specfile from
+// Example().
+func ToRootless(spec *specs.Spec) {
+ var namespaces []specs.LinuxNamespace
+
+ // Remove networkns from the spec.
+ for _, ns := range spec.Linux.Namespaces {
+ switch ns.Type {
+ case specs.NetworkNamespace, specs.UserNamespace:
+ // Do nothing.
+ default:
+ namespaces = append(namespaces, ns)
+ }
+ }
+ // Add userns to the spec.
+ namespaces = append(namespaces, specs.LinuxNamespace{
+ Type: specs.UserNamespace,
+ })
+ spec.Linux.Namespaces = namespaces
+
+ // Add mappings for the current user.
+ spec.Linux.UIDMappings = []specs.LinuxIDMapping{{
+ HostID: uint32(os.Geteuid()),
+ ContainerID: 0,
+ Size: 1,
+ }}
+ spec.Linux.GIDMappings = []specs.LinuxIDMapping{{
+ HostID: uint32(os.Getegid()),
+ ContainerID: 0,
+ Size: 1,
+ }}
+
+ // Fix up mounts.
+ var mounts []specs.Mount
+ for _, mount := range spec.Mounts {
+ // Ignore all mounts that are under /sys.
+ if strings.HasPrefix(mount.Destination, "/sys") {
+ continue
+ }
+
+ // Remove all gid= and uid= mappings.
+ var options []string
+ for _, option := range mount.Options {
+ if !strings.HasPrefix(option, "gid=") && !strings.HasPrefix(option, "uid=") {
+ options = append(options, option)
+ }
+ }
+
+ mount.Options = options
+ mounts = append(mounts, mount)
+ }
+ // Add the sysfs mount as an rbind.
+ mounts = append(mounts, specs.Mount{
+ Source: "/sys",
+ Destination: "/sys",
+ Type: "none",
+ Options: []string{"rbind", "nosuid", "noexec", "nodev", "ro"},
+ })
+ spec.Mounts = mounts
+
+ // Remove cgroup settings.
+ spec.Linux.Resources = nil
+}
diff --git a/libcontainer/specconv/spec_linux_test.go b/libcontainer/specconv/spec_linux_test.go
index 741fae6..f7292f3 100644
--- a/libcontainer/specconv/spec_linux_test.go
+++ b/libcontainer/specconv/spec_linux_test.go
@@ -3,7 +3,6 @@
package specconv
import (
- "os"
"testing"
"github.com/opencontainers/runc/libcontainer/configs/validate"
@@ -53,8 +52,9 @@ func TestLinuxCgroupsPathNotSpecified(t *testing.T) {
}
func TestSpecconvExampleValidate(t *testing.T) {
- spec := ExampleSpec()
+ spec := Example()
spec.Root.Path = "/"
+
opts := &CreateOpts{
CgroupName: "ContainerID",
UseSystemdCgroup: false,
@@ -97,29 +97,9 @@ func TestDupNamespaces(t *testing.T) {
}
func TestRootlessSpecconvValidate(t *testing.T) {
- spec := &specs.Spec{
- Linux: specs.Linux{
- Namespaces: []specs.Namespace{
- {
- Type: specs.UserNamespace,
- },
- },
- UIDMappings: []specs.IDMapping{
- {
- HostID: uint32(os.Geteuid()),
- ContainerID: 0,
- Size: 1,
- },
- },
- GIDMappings: []specs.IDMapping{
- {
- HostID: uint32(os.Getegid()),
- ContainerID: 0,
- Size: 1,
- },
- },
- },
- }
+ spec := Example()
+ spec.Root.Path = "/"
+ ToRootless(spec)
opts := &CreateOpts{
CgroupName: "ContainerID",
diff --git a/spec.go b/spec.go
index d7df312..9024ad4 100644
--- a/spec.go
+++ b/spec.go
@@ -64,12 +64,21 @@ container on your host.`,
Value: "",
Usage: "path to the root of the bundle directory",
},
+ cli.BoolFlag{
+ Name: "rootless",
+ Usage: "generate a configuration for a rootless container",
+ },
},
Action: func(context *cli.Context) error {
if err := checkArgs(context, 0, exactArgs); err != nil {
return err
}
- spec := specconv.ExampleSpec()
+ spec := specconv.Example()
+
+ rootless := context.Bool("rootless")
+ if rootless {
+ specconv.ToRootless(spec)
+ }
checkNoFile := func(name string) error {
_, err := os.Stat(name)
--
2.7.4.3

View File

@ -0,0 +1,143 @@
From 7c81f032861f5654e9063e5af82c7794401682f4 Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <asarai@suse.de>
Date: Tue, 10 May 2016 22:22:13 +1000
Subject: [PATCH 10/94] integration: added root requires
This is in preperation of allowing us to run the integration test suite
on rootless containers.
Change-Id: I38f7115df4f931857659892b07745c86507d14bf
Signed-off-by: Aleksa Sarai <asarai@suse.de>
---
tests/integration/cgroups.bats | 8 ++++++--
tests/integration/checkpoint.bats | 3 ++-
tests/integration/helpers.bash | 10 +++++++++-
tests/integration/kill.bats | 1 -
tests/integration/pause.bats | 6 ++++++
tests/integration/update.bats | 6 +++++-
6 files changed, 28 insertions(+), 6 deletions(-)
diff --git a/tests/integration/cgroups.bats b/tests/integration/cgroups.bats
index 9ab6f43..90095a7 100644
--- a/tests/integration/cgroups.bats
+++ b/tests/integration/cgroups.bats
@@ -28,7 +28,9 @@ function check_cgroup_value() {
}
@test "runc update --kernel-memory (initialized)" {
- requires cgroups_kmem
+ # XXX: currently cgroups require root containers.
+ requires cgroups_kmem root
+
# Add cgroup path
sed -i 's/\("linux": {\)/\1\n "cgroupsPath": "\/runc-cgroups-integration-test",/' ${BUSYBOX_BUNDLE}/config.json
@@ -56,7 +58,9 @@ EOF
}
@test "runc update --kernel-memory (uninitialized)" {
- requires cgroups_kmem
+ # XXX: currently cgroups require root containers.
+ requires cgroups_kmem root
+
# Add cgroup path
sed -i 's/\("linux": {\)/\1\n "cgroupsPath": "\/runc-cgroups-integration-test",/' ${BUSYBOX_BUNDLE}/config.json
diff --git a/tests/integration/checkpoint.bats b/tests/integration/checkpoint.bats
index 34d1b03..e91fd65 100644
--- a/tests/integration/checkpoint.bats
+++ b/tests/integration/checkpoint.bats
@@ -12,7 +12,8 @@ function teardown() {
}
@test "checkpoint and restore" {
- requires criu
+ # XXX: currently criu require root containers.
+ requires criu root
# criu does not work with external terminals so..
# setting terminal and root:readonly: to false
diff --git a/tests/integration/helpers.bash b/tests/integration/helpers.bash
index e4c2cb9..6548333 100644
--- a/tests/integration/helpers.bash
+++ b/tests/integration/helpers.bash
@@ -40,6 +40,9 @@ CGROUP_CPU_BASE_PATH=$(grep "cgroup" /proc/self/mountinfo | gawk 'toupper($NF) ~
KMEM="${CGROUP_MEMORY_BASE_PATH}/memory.kmem.limit_in_bytes"
RT_PERIOD="${CGROUP_CPU_BASE_PATH}/cpu.rt_period_us"
+# Check if we're in rootless mode.
+ROOTLESS=$(id -u)
+
# Wrapper for runc.
function runc() {
run __runc "$@"
@@ -68,7 +71,12 @@ function requires() {
case $var in
criu)
if [ ! -e "$CRIU" ]; then
- skip "Test requires ${var}."
+ skip "test requires ${var}"
+ fi
+ ;;
+ root)
+ if [ "$ROOTLESS" -ne 0 ]; then
+ skip "test requires ${var}"
fi
;;
cgroups_kmem)
diff --git a/tests/integration/kill.bats b/tests/integration/kill.bats
index a049de6..74246fa 100644
--- a/tests/integration/kill.bats
+++ b/tests/integration/kill.bats
@@ -13,7 +13,6 @@ function teardown() {
@test "kill detached busybox" {
-
# run busybox detached
runc run -d --console-socket $CONSOLE_SOCKET test_busybox
[ "$status" -eq 0 ]
diff --git a/tests/integration/pause.bats b/tests/integration/pause.bats
index 2f46a6c..30d98b5 100644
--- a/tests/integration/pause.bats
+++ b/tests/integration/pause.bats
@@ -12,6 +12,9 @@ function teardown() {
}
@test "runc pause and resume" {
+ # XXX: currently cgroups require root containers.
+ requires root
+
# run busybox detached
runc run -d --console-socket $CONSOLE_SOCKET test_busybox
[ "$status" -eq 0 ]
@@ -34,6 +37,9 @@ function teardown() {
}
@test "runc pause and resume with nonexist container" {
+ # XXX: currently cgroups require root containers.
+ requires root
+
# run test_busybox detached
runc run -d --console-socket $CONSOLE_SOCKET test_busybox
[ "$status" -eq 0 ]
diff --git a/tests/integration/update.bats b/tests/integration/update.bats
index 9aaf1b9..4a6bf7f 100644
--- a/tests/integration/update.bats
+++ b/tests/integration/update.bats
@@ -50,7 +50,11 @@ function check_cgroup_value() {
# TODO: test rt cgroup updating
@test "update" {
- requires cgroups_kmem
+ # XXX: currently cgroups require root containers.
+ # XXX: Also, this test should be split into separate sections so that we
+ # can skip kmem without skipping update tests overall.
+ requires cgroups_kmem root
+
# run a few busyboxes detached
runc run -d --console-socket $CONSOLE_SOCKET test_update
[ "$status" -eq 0 ]
--
2.7.4.3

View File

@ -0,0 +1,449 @@
From c62d731fc7e928e944e0290df318042c46e80526 Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <asarai@suse.de>
Date: Wed, 11 May 2016 17:45:00 +1000
Subject: [PATCH 11/94] tests: add rootless integration tests
This adds targets for rootless integration tests, as well as all of the
required setup in order to get the tests to run. This includes quite a
few changes, because of a lot of assumptions about things running as
root within the bats scripts (which is not true when setting up rootless
containers).
Change-Id: I2fab9fd3ac984e06a7d3e1e1ac0cd888b1543801
Signed-off-by: Aleksa Sarai <asarai@suse.de>
---
Dockerfile | 7 ++++++
Makefile | 11 +++++++--
tests/integration/checkpoint.bats | 5 +++--
tests/integration/delete.bats | 2 ++
tests/integration/events.bats | 12 ++++++++++
tests/integration/exec.bats | 3 +++
tests/integration/help.bats | 1 +
tests/integration/helpers.bash | 23 ++++++++++++++-----
tests/integration/ps.bats | 11 ++++++++-
tests/integration/spec.bats | 4 ++--
tests/integration/start_detached.bats | 3 +++
tests/integration/start_hello.bats | 3 +++
tests/integration/state.bats | 42 ++++++++++++++++++++++++++---------
tests/integration/tty.bats | 14 ++++++++++++
14 files changed, 117 insertions(+), 24 deletions(-)
diff --git a/Dockerfile b/Dockerfile
index c971448..fd9be94 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -6,6 +6,7 @@ RUN echo 'deb http://httpredir.debian.org/debian jessie-backports main' > /etc/a
RUN apt-get update && apt-get install -y \
build-essential \
curl \
+ sudo \
gawk \
iptables \
jq \
@@ -22,6 +23,12 @@ RUN apt-get update && apt-get install -y \
--no-install-recommends \
&& apt-get clean
+# Add a dummy user for the rootless integration tests. While runC does
+# not require an entry in /etc/passwd to operate, one of the tests uses
+# `git clone` -- and `git clone` does not allow you to clone a
+# repository if the current uid does not have an entry in /etc/passwd.
+RUN useradd -u1000 -m -d/home/rootless -s/bin/bash rootless
+
# install bats
RUN cd /tmp \
&& git clone https://github.com/sstephenson/bats.git \
diff --git a/Makefile b/Makefile
index 5fff515..1cecca1 100644
--- a/Makefile
+++ b/Makefile
@@ -79,10 +79,10 @@ runcimage:
docker build -t $(RUNC_IMAGE) .
test:
- make unittest integration
+ make unittest integration rootlessintegration
localtest:
- make localunittest localintegration
+ make localunittest localintegration localrootlessintegration
unittest: runcimage
docker run -e TESTFLAGS -t --privileged --rm -v $(CURDIR):/go/src/$(PROJECT) $(RUNC_IMAGE) make localunittest
@@ -96,6 +96,13 @@ integration: runcimage
localintegration: all
bats -t tests/integration${TESTFLAGS}
+rootlessintegration: runcimage
+ docker run -e TESTFLAGS -t --privileged --rm -v $(CURDIR):/go/src/$(PROJECT) --cap-drop=ALL -u rootless $(RUNC_IMAGE) make localintegration
+
+# FIXME: This should not be separate from rootlessintegration's method of running.
+localrootlessintegration: all
+ sudo -u rootless -H PATH="${PATH}" bats -t tests/integration${TESTFLAGS}
+
shell: all
docker run -e TESTFLAGS -ti --privileged --rm -v $(CURDIR):/go/src/$(PROJECT) $(RUNC_IMAGE) bash
diff --git a/tests/integration/checkpoint.bats b/tests/integration/checkpoint.bats
index e91fd65..cd969a8 100644
--- a/tests/integration/checkpoint.bats
+++ b/tests/integration/checkpoint.bats
@@ -59,8 +59,9 @@ function teardown() {
[[ "${output}" == *"running"* ]]
}
-@test "checkpoint(pre-dump) and restore" {
- requires criu
+@test "checkpoint --pre-dump and restore" {
+ # XXX: currently criu require root containers.
+ requires criu root
# criu does not work with external terminals so..
# setting terminal and root:readonly: to false
diff --git a/tests/integration/delete.bats b/tests/integration/delete.bats
index cdadd7d..2c11e79 100644
--- a/tests/integration/delete.bats
+++ b/tests/integration/delete.bats
@@ -22,11 +22,13 @@ function teardown() {
testcontainer test_busybox running
runc kill test_busybox KILL
+ [ "$status" -eq 0 ]
# wait for busybox to be in the destroyed state
retry 10 1 eval "__runc state test_busybox | grep -q 'stopped'"
# delete test_busybox
runc delete test_busybox
+ [ "$status" -eq 0 ]
runc state test_busybox
[ "$status" -ne 0 ]
diff --git a/tests/integration/events.bats b/tests/integration/events.bats
index 182b721..2350073 100644
--- a/tests/integration/events.bats
+++ b/tests/integration/events.bats
@@ -12,6 +12,9 @@ function teardown() {
}
@test "events --stats" {
+ # XXX: currently cgroups require root containers.
+ requires root
+
# run busybox detached
runc run -d --console-socket $CONSOLE_SOCKET test_busybox
[ "$status" -eq 0 ]
@@ -27,6 +30,9 @@ function teardown() {
}
@test "events --interval default " {
+ # XXX: currently cgroups require root containers.
+ requires root
+
# run busybox detached
runc run -d --console-socket $CONSOLE_SOCKET test_busybox
[ "$status" -eq 0 ]
@@ -54,6 +60,9 @@ function teardown() {
}
@test "events --interval 1s " {
+ # XXX: currently cgroups require root containers.
+ requires root
+
# run busybox detached
runc run -d --console-socket $CONSOLE_SOCKET test_busybox
[ "$status" -eq 0 ]
@@ -80,6 +89,9 @@ function teardown() {
}
@test "events --interval 100ms " {
+ # XXX: currently cgroups require root containers.
+ requires root
+
# run busybox detached
runc run -d --console-socket $CONSOLE_SOCKET test_busybox
[ "$status" -eq 0 ]
diff --git a/tests/integration/exec.bats b/tests/integration/exec.bats
index ba60ea1..f172f9b 100644
--- a/tests/integration/exec.bats
+++ b/tests/integration/exec.bats
@@ -112,6 +112,9 @@ function teardown() {
}
@test "runc exec --user" {
+ # --user can't work in rootless containers
+ requires root
+
# run busybox detached
runc run -d --console-socket $CONSOLE_SOCKET test_busybox
[ "$status" -eq 0 ]
diff --git a/tests/integration/help.bats b/tests/integration/help.bats
index ca404f3..163de2d 100644
--- a/tests/integration/help.bats
+++ b/tests/integration/help.bats
@@ -57,6 +57,7 @@ load helpers
[ "$status" -eq 0 ]
[[ ${lines[1]} =~ runc\ resume+ ]]
+ # We don't use runc_spec here, because we're just testing the help page.
runc spec -h
[ "$status" -eq 0 ]
[[ ${lines[1]} =~ runc\ spec+ ]]
diff --git a/tests/integration/helpers.bash b/tests/integration/helpers.bash
index 6548333..fc8c290 100644
--- a/tests/integration/helpers.bash
+++ b/tests/integration/helpers.bash
@@ -4,7 +4,7 @@
INTEGRATION_ROOT=$(dirname "$(readlink -f "$BASH_SOURCE")")
RUNC="${INTEGRATION_ROOT}/../../runc"
RECVTTY="${INTEGRATION_ROOT}/../../contrib/cmd/recvtty/recvtty"
-GOPATH="${INTEGRATION_ROOT}/../../../.."
+GOPATH="$(mktemp -d --tmpdir runc-integration-gopath.XXXXXX)"
# Test data path.
TESTDATA="${INTEGRATION_ROOT}/testdata"
@@ -27,7 +27,7 @@ KERNEL_MINOR="${KERNEL_VERSION#$KERNEL_MAJOR.}"
KERNEL_MINOR="${KERNEL_MINOR%%.*}"
# Root state path.
-ROOT="$BATS_TMPDIR/runc"
+ROOT=$(mktemp -d "$BATS_TMPDIR/runc.XXXXXX")
# Path to console socket.
CONSOLE_SOCKET="$BATS_TMPDIR/console.sock"
@@ -58,6 +58,17 @@ function __runc() {
"$RUNC" --root "$ROOT" "$@"
}
+# Wrapper for runc spec.
+function runc_spec() {
+ local args=""
+
+ if [ "$ROOTLESS" -ne 0 ]; then
+ args+="--rootless"
+ fi
+
+ runc spec $args "$@"
+}
+
# Fails the current test, providing the error given.
function fail() {
echo "$@" >&2
@@ -187,18 +198,18 @@ function setup_busybox() {
if [ ! -e $BUSYBOX_IMAGE ]; then
curl -o $BUSYBOX_IMAGE -sSL 'https://github.com/docker-library/busybox/raw/a0558a9006ce0dd6f6ec5d56cfd3f32ebeeb815f/glibc/busybox.tar.xz'
fi
- tar -C "$BUSYBOX_BUNDLE"/rootfs -xf "$BUSYBOX_IMAGE"
+ tar --exclude './dev/*' -C "$BUSYBOX_BUNDLE"/rootfs -xf "$BUSYBOX_IMAGE"
cd "$BUSYBOX_BUNDLE"
- runc spec
+ runc_spec
}
function setup_hello() {
setup_recvtty
run mkdir "$HELLO_BUNDLE"
run mkdir "$HELLO_BUNDLE"/rootfs
- tar -C "$HELLO_BUNDLE"/rootfs -xf "$HELLO_IMAGE"
+ tar --exclude './dev/*' -C "$HELLO_BUNDLE"/rootfs -xf "$HELLO_IMAGE"
cd "$HELLO_BUNDLE"
- runc spec
+ runc_spec
sed -i 's;"sh";"/hello";' config.json
}
diff --git a/tests/integration/ps.bats b/tests/integration/ps.bats
index 7a20015..c000af6 100644
--- a/tests/integration/ps.bats
+++ b/tests/integration/ps.bats
@@ -12,6 +12,9 @@ function teardown() {
}
@test "ps" {
+ # ps is not supported, it requires cgroups
+ requires root
+
# start busybox detached
runc run -d --console-socket $CONSOLE_SOCKET test_busybox
[ "$status" -eq 0 ]
@@ -24,10 +27,13 @@ function teardown() {
runc ps test_busybox
[ "$status" -eq 0 ]
[[ ${lines[0]} =~ UID\ +PID\ +PPID\ +C\ +STIME\ +TTY\ +TIME\ +CMD+ ]]
- [[ "${lines[1]}" == *"root"*[0-9]* ]]
+ [[ "${lines[1]}" == *"$(id -un 2>/dev/null)"*[0-9]* ]]
}
@test "ps -f json" {
+ # ps is not supported, it requires cgroups
+ requires root
+
# start busybox detached
runc run -d --console-socket $CONSOLE_SOCKET test_busybox
[ "$status" -eq 0 ]
@@ -43,6 +49,9 @@ function teardown() {
}
@test "ps -e -x" {
+ # ps is not supported, it requires cgroups
+ requires root
+
# start busybox detached
runc run -d --console-socket $CONSOLE_SOCKET test_busybox
[ "$status" -eq 0 ]
diff --git a/tests/integration/spec.bats b/tests/integration/spec.bats
index 79bb690..e9f28fb 100644
--- a/tests/integration/spec.bats
+++ b/tests/integration/spec.bats
@@ -26,7 +26,7 @@ function teardown() {
[ ! -e config.json ]
# test generation of spec does not return an error
- runc spec
+ runc_spec
[ "$status" -eq 0 ]
# test generation of spec created our config.json (spec)
@@ -51,7 +51,7 @@ function teardown() {
[ ! -e "$HELLO_BUNDLE"/config.json ]
# test generation of spec does not return an error
- runc spec --bundle "$HELLO_BUNDLE"
+ runc_spec --bundle "$HELLO_BUNDLE"
[ "$status" -eq 0 ]
# test generation of spec created our config.json (spec)
diff --git a/tests/integration/start_detached.bats b/tests/integration/start_detached.bats
index 605fde2..08036dd 100644
--- a/tests/integration/start_detached.bats
+++ b/tests/integration/start_detached.bats
@@ -23,6 +23,9 @@ function teardown() {
}
@test "runc run detached ({u,g}id != 0)" {
+ # cannot start containers as another user in rootless setup
+ requires root
+
# replace "uid": 0 with "uid": 1000
# and do a similar thing for gid.
sed -i 's;"uid": 0;"uid": 1000;g' config.json
diff --git a/tests/integration/start_hello.bats b/tests/integration/start_hello.bats
index 6de65e0..2e93572 100644
--- a/tests/integration/start_hello.bats
+++ b/tests/integration/start_hello.bats
@@ -21,6 +21,9 @@ function teardown() {
}
@test "runc run ({u,g}id != 0)" {
+ # cannot start containers as another user in rootless setup
+ requires root
+
# replace "uid": 0 with "uid": 1000
# and do a similar thing for gid.
sed -i 's;"uid": 0;"uid": 1000;g' config.json
diff --git a/tests/integration/state.bats b/tests/integration/state.bats
index eed2eb3..3772c1e 100644
--- a/tests/integration/state.bats
+++ b/tests/integration/state.bats
@@ -11,7 +11,37 @@ function teardown() {
teardown_busybox
}
-@test "state" {
+@test "state (kill + delete)" {
+ runc state test_busybox
+ [ "$status" -ne 0 ]
+
+ # run busybox detached
+ runc run -d --console-socket $CONSOLE_SOCKET test_busybox
+ [ "$status" -eq 0 ]
+
+ # check state
+ wait_for_container 15 1 test_busybox
+
+ testcontainer test_busybox running
+
+ runc kill test_busybox KILL
+ [ "$status" -eq 0 ]
+
+ # wait for busybox to be in the destroyed state
+ retry 10 1 eval "__runc state test_busybox | grep -q 'stopped'"
+
+ # delete test_busybox
+ runc delete test_busybox
+ [ "$status" -eq 0 ]
+
+ runc state test_busybox
+ [ "$status" -ne 0 ]
+}
+
+@test "state (pause + resume)" {
+ # XXX: pause and resume require cgroups.
+ requires root
+
runc state test_busybox
[ "$status" -ne 0 ]
@@ -37,14 +67,4 @@ function teardown() {
# test state of busybox is back to running
testcontainer test_busybox running
-
- runc kill test_busybox KILL
- # wait for busybox to be in the destroyed state
- retry 10 1 eval "__runc state test_busybox | grep -q 'stopped'"
-
- # delete test_busybox
- runc delete test_busybox
-
- runc state test_busybox
- [ "$status" -ne 0 ]
}
diff --git a/tests/integration/tty.bats b/tests/integration/tty.bats
index b9a1f10..9e817db 100644
--- a/tests/integration/tty.bats
+++ b/tests/integration/tty.bats
@@ -24,6 +24,10 @@ function teardown() {
}
@test "runc run [tty owner]" {
+ # tty chmod is not doable in rootless containers.
+ # TODO: this can be made as a change to the gid test.
+ requires root
+
# Replace sh script with stat.
sed -i 's/"sh"/"sh", "-c", "stat -c %u:%g $(tty) | tr : \\\\\\\\n"/' config.json
@@ -36,6 +40,9 @@ function teardown() {
}
@test "runc run [tty owner] ({u,g}id != 0)" {
+ # tty chmod is not doable in rootless containers.
+ requires root
+
# replace "uid": 0 with "uid": 1000
# and do a similar thing for gid.
sed -i 's;"uid": 0;"uid": 1000;g' config.json
@@ -72,6 +79,10 @@ function teardown() {
}
@test "runc exec [tty owner]" {
+ # tty chmod is not doable in rootless containers.
+ # TODO: this can be made as a change to the gid test.
+ requires root
+
# run busybox detached
runc run -d --console-socket $CONSOLE_SOCKET test_busybox
[ "$status" -eq 0 ]
@@ -90,6 +101,9 @@ function teardown() {
}
@test "runc exec [tty owner] ({u,g}id != 0)" {
+ # tty chmod is not doable in rootless containers.
+ requires root
+
# replace "uid": 0 with "uid": 1000
# and do a similar thing for gid.
sed -i 's;"uid": 0;"uid": 1000;g' config.json
--
2.7.4.3

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,327 @@
From c13a4de91dc2a3db4b9085015dbce2f8e050d7ca Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <asarai@suse.de>
Date: Wed, 29 Mar 2017 22:39:05 +1100
Subject: [PATCH 13/94] libcontainer: rewrite cmsg to use sys/unix
The original implementation is in C, which increases cognitive load and
possibly might cause us problems in the future. Since sys/unix is better
maintained than the syscall standard library switching makes more sense.
Change-Id: I8d91c2d7b28116d3d9be49e328f9383b9b7052d7
Signed-off-by: Aleksa Sarai <asarai@suse.de>
---
libcontainer/utils/cmsg.c | 148 ---------------------------------------------
libcontainer/utils/cmsg.go | 74 +++++++++++++++++------
libcontainer/utils/cmsg.h | 36 -----------
3 files changed, 56 insertions(+), 202 deletions(-)
delete mode 100644 libcontainer/utils/cmsg.c
delete mode 100644 libcontainer/utils/cmsg.h
diff --git a/libcontainer/utils/cmsg.c b/libcontainer/utils/cmsg.c
deleted file mode 100644
index 0ded494..0000000
--- a/libcontainer/utils/cmsg.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2016 SUSE LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "cmsg.h"
-
-#define error(fmt, ...) \
- ({ \
- fprintf(stderr, "nsenter: " fmt ": %m\n", ##__VA_ARGS__); \
- errno = ECOMM; \
- goto err; /* return value */ \
- })
-
-/*
- * Sends a file descriptor along the sockfd provided. Returns the return
- * value of sendmsg(2). Any synchronisation and preparation of state
- * should be done external to this (we expect the other side to be in
- * recvfd() in the code).
- */
-ssize_t sendfd(int sockfd, struct file_t file)
-{
- struct msghdr msg = {0};
- struct iovec iov[1] = {0};
- struct cmsghdr *cmsg;
- int *fdptr;
- int ret;
-
- union {
- char buf[CMSG_SPACE(sizeof(file.fd))];
- struct cmsghdr align;
- } u;
-
- /*
- * We need to send some other data along with the ancillary data,
- * otherwise the other side won't recieve any data. This is very
- * well-hidden in the documentation (and only applies to
- * SOCK_STREAM). See the bottom part of unix(7).
- */
- iov[0].iov_base = file.name;
- iov[0].iov_len = strlen(file.name) + 1;
-
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = iov;
- msg.msg_iovlen = 1;
- msg.msg_control = u.buf;
- msg.msg_controllen = sizeof(u.buf);
-
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
-
- fdptr = (int *) CMSG_DATA(cmsg);
- memcpy(fdptr, &file.fd, sizeof(int));
-
- return sendmsg(sockfd, &msg, 0);
-}
-
-/*
- * Receives a file descriptor from the sockfd provided. Returns the file
- * descriptor as sent from sendfd(). It will return the file descriptor
- * or die (literally) trying. Any synchronisation and preparation of
- * state should be done external to this (we expect the other side to be
- * in sendfd() in the code).
- */
-struct file_t recvfd(int sockfd)
-{
- struct msghdr msg = {0};
- struct iovec iov[1] = {0};
- struct cmsghdr *cmsg;
- struct file_t file = {0};
- int *fdptr;
- int olderrno;
-
- union {
- char buf[CMSG_SPACE(sizeof(file.fd))];
- struct cmsghdr align;
- } u;
-
- /* Allocate a buffer. */
- /* TODO: Make this dynamic with MSG_PEEK. */
- file.name = malloc(TAG_BUFFER);
- if (!file.name)
- error("recvfd: failed to allocate file.tag buffer\n");
-
- /*
- * We need to "recieve" the non-ancillary data even though we don't
- * plan to use it at all. Otherwise, things won't work as expected.
- * See unix(7) and other well-hidden documentation.
- */
- iov[0].iov_base = file.name;
- iov[0].iov_len = TAG_BUFFER;
-
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = iov;
- msg.msg_iovlen = 1;
- msg.msg_control = u.buf;
- msg.msg_controllen = sizeof(u.buf);
-
- ssize_t ret = recvmsg(sockfd, &msg, 0);
- if (ret < 0)
- goto err;
-
- cmsg = CMSG_FIRSTHDR(&msg);
- if (!cmsg)
- error("recvfd: got NULL from CMSG_FIRSTHDR");
- if (cmsg->cmsg_level != SOL_SOCKET)
- error("recvfd: expected SOL_SOCKET in cmsg: %d", cmsg->cmsg_level);
- 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", (unsigned long)cmsg->cmsg_len);
-
- fdptr = (int *) CMSG_DATA(cmsg);
- if (!fdptr || *fdptr < 0)
- error("recvfd: recieved invalid pointer");
-
- file.fd = *fdptr;
- return file;
-
-err:
- olderrno = errno;
- free(file.name);
- errno = olderrno;
- return (struct file_t){0};
-}
diff --git a/libcontainer/utils/cmsg.go b/libcontainer/utils/cmsg.go
index ee89374..2cbb649 100644
--- a/libcontainer/utils/cmsg.go
+++ b/libcontainer/utils/cmsg.go
@@ -3,7 +3,7 @@
package utils
/*
- * Copyright 2016 SUSE LLC
+ * Copyright 2016, 2017 SUSE LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,28 +18,66 @@ package utils
* limitations under the License.
*/
-/*
-#include <errno.h>
-#include <stdlib.h>
-#include "cmsg.h"
-*/
-import "C"
-
import (
+ "fmt"
"os"
- "unsafe"
+
+ "golang.org/x/sys/unix"
)
+// MaxSendfdLen is the maximum length of the name of a file descriptor being
+// sent using SendFd. The name of the file handle returned by RecvFd will never
+// be larger than this value.
+const MaxNameLen = 4096
+
+// oobSpace is the size of the oob slice required to store a single FD. Note
+// that unix.UnixRights appears to make the assumption that fd is always int32,
+// so sizeof(fd) = 4.
+var oobSpace = unix.CmsgSpace(4)
+
// RecvFd waits for a file descriptor to be sent over the given AF_UNIX
// socket. The file name of the remote file descriptor will be recreated
// locally (it is sent as non-auxiliary data in the same payload).
func RecvFd(socket *os.File) (*os.File, error) {
- file, err := C.recvfd(C.int(socket.Fd()))
+ // For some reason, unix.Recvmsg uses the length rather than the capacity
+ // when passing the msg_controllen and other attributes to recvmsg. So we
+ // have to actually set the length.
+ name := make([]byte, MaxNameLen)
+ oob := make([]byte, oobSpace)
+
+ sockfd := socket.Fd()
+ n, oobn, _, _, err := unix.Recvmsg(int(sockfd), name, oob, 0)
if err != nil {
return nil, err
}
- defer C.free(unsafe.Pointer(file.name))
- return os.NewFile(uintptr(file.fd), C.GoString(file.name)), nil
+
+ if n >= MaxNameLen || oobn != oobSpace {
+ return nil, fmt.Errorf("recvfd: incorrect number of bytes read (n=%d oobn=%d)", n, oobn)
+ }
+
+ // Truncate.
+ name = name[:n]
+ oob = oob[:oobn]
+
+ scms, err := unix.ParseSocketControlMessage(oob)
+ if err != nil {
+ return nil, err
+ }
+ if len(scms) != 1 {
+ return nil, fmt.Errorf("recvfd: number of SCMs is not 1: %d", len(scms))
+ }
+ scm := scms[0]
+
+ fds, err := unix.ParseUnixRights(&scm)
+ if err != nil {
+ return nil, err
+ }
+ if len(fds) != 1 {
+ return nil, fmt.Errorf("recvfd: number of fds is not 1: %d", len(fds))
+ }
+ fd := uintptr(fds[0])
+
+ return os.NewFile(fd, string(name)), nil
}
// SendFd sends a file descriptor over the given AF_UNIX socket. In
@@ -47,11 +85,11 @@ func RecvFd(socket *os.File) (*os.File, error) {
// non-auxiliary data in the same payload (allowing to send contextual
// information for a file descriptor).
func SendFd(socket, file *os.File) error {
- var cfile C.struct_file_t
- cfile.fd = C.int(file.Fd())
- cfile.name = C.CString(file.Name())
- defer C.free(unsafe.Pointer(cfile.name))
+ name := []byte(file.Name())
+ if len(name) >= MaxNameLen {
+ return fmt.Errorf("sendfd: filename too long: %s", file.Name())
+ }
+ oob := unix.UnixRights(int(file.Fd()))
- _, err := C.sendfd(C.int(socket.Fd()), cfile)
- return err
+ return unix.Sendmsg(int(socket.Fd()), name, oob, nil, 0)
}
diff --git a/libcontainer/utils/cmsg.h b/libcontainer/utils/cmsg.h
deleted file mode 100644
index 3fe7642..0000000
--- a/libcontainer/utils/cmsg.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2016 SUSE LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#if !defined(CMSG_H)
-#define CMSG_H
-
-#include <sys/types.h>
-
-/* TODO: Implement this properly with MSG_PEEK. */
-#define TAG_BUFFER 4096
-
-/* This mirrors Go's (*os.File). */
-struct file_t {
- char *name;
- int fd;
-};
-
-struct file_t recvfd(int sockfd);
-ssize_t sendfd(int sockfd, struct file_t file);
-
-#endif /* !defined(CMSG_H) */
--
2.7.4.3

View File

@ -0,0 +1,39 @@
From b9b6667861bcc98579489aa6cec8012249fedbab Mon Sep 17 00:00:00 2001
From: Harshal Patil <harshal.patil@in.ibm.com>
Date: Tue, 4 Apr 2017 15:08:04 +0530
Subject: [PATCH 14/94] Set container state only once during start
Change-Id: Iae2bcd397cbc40c540e32807d946c3ec81783803
Signed-off-by: Harshal Patil <harshal.patil@in.ibm.com>
---
libcontainer/container_linux.go | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 71fa682..26e51ae 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -263,9 +263,6 @@ func (c *linuxContainer) start(process *Process, isInit bool) error {
}
// generate a timestamp indicating when the container was started
c.created = time.Now().UTC()
- c.state = &runningState{
- c: c,
- }
if isInit {
c.state = &createdState{
c: c,
@@ -292,6 +289,10 @@ func (c *linuxContainer) start(process *Process, isInit bool) error {
}
}
}
+ } else {
+ c.state = &runningState{
+ c: c,
+ }
}
return nil
}
--
2.7.4.3

View File

@ -0,0 +1,161 @@
From 6397990e4ee68389c05fa2a0c89d1c4d4e5e5677 Mon Sep 17 00:00:00 2001
From: Adrian Reber <areber@redhat.com>
Date: Tue, 14 Mar 2017 20:21:58 +0000
Subject: [PATCH 15/94] checkpoint: check if system supports
pre-dumping
Instead of relying on version numbers it is possible to check if CRIU
actually supports certain features. This introduces an initial
implementation to check if CRIU and the underlying kernel actually
support dirty memory tracking for memory pre-dumping.
Upstream CRIU also supports the lazy-page migration feature check and
additional feature checks can be included in CRIU to reduce the version
number parsing. There are also certain CRIU features which depend on one
side on the CRIU version but also require certain kernel versions to
actually work. CRIU knows if it can do certain things on the kernel it
is running on and using the feature check RPC interface makes it easier
for runc to decide if the criu+kernel combination will support that
feature.
Feature checking was introduced with CRIU 1.8. Running with older CRIU
versions will ignore the feature check functionality and behave just
like it used to.
v2:
- Do not use reflection to compare requested and responded
features. Checking which feature is available is now hardcoded
and needs to be adapted for every new feature check. The code
is now much more readable and simpler.
v3:
- Move the variable criuFeat out of the linuxContainer struct,
as it is not container specific. Now it is a global variable.
Change-Id: Ide44007d031d1bc4572dab1e88d78762944b379b
Signed-off-by: Adrian Reber <areber@redhat.com>
---
libcontainer/container_linux.go | 85 ++++++++++++++++++++++++++++++++++++-----
1 file changed, 76 insertions(+), 9 deletions(-)
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 26e51ae..705472a 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -536,6 +536,56 @@ func (c *linuxContainer) NotifyMemoryPressure(level PressureLevel) (<-chan struc
return notifyMemoryPressure(c.cgroupManager.GetPaths(), level)
}
+var criuFeatures *criurpc.CriuFeatures
+
+func (c *linuxContainer) checkCriuFeatures(criuOpts *CriuOpts, rpcOpts *criurpc.CriuOpts, criuFeat *criurpc.CriuFeatures) error {
+
+ var t criurpc.CriuReqType
+ t = criurpc.CriuReqType_FEATURE_CHECK
+
+ if err := c.checkCriuVersion("1.8"); err != nil {
+ // Feature checking was introduced with CRIU 1.8.
+ // Ignore the feature check if an older CRIU version is used
+ // and just act as before.
+ // As all automated PR testing is done using CRIU 1.7 this
+ // code will not be tested by automated PR testing.
+ return nil
+ }
+
+ // make sure the features we are looking for are really not from
+ // some previous check
+ criuFeatures = nil
+
+ req := &criurpc.CriuReq{
+ Type: &t,
+ // Theoretically this should not be necessary but CRIU
+ // segfaults if Opts is empty.
+ // Fixed in CRIU 2.12
+ Opts: rpcOpts,
+ Features: criuFeat,
+ }
+
+ err := c.criuSwrk(nil, req, criuOpts, false)
+ if err != nil {
+ logrus.Debugf("%s", err)
+ return fmt.Errorf("CRIU feature check failed")
+ }
+
+ logrus.Debugf("Feature check says: %s", criuFeatures)
+ missingFeatures := false
+
+ if *criuFeat.MemTrack && !*criuFeatures.MemTrack {
+ missingFeatures = true
+ logrus.Debugf("CRIU does not support MemTrack")
+ }
+
+ if missingFeatures {
+ return fmt.Errorf("CRIU is missing features")
+ }
+
+ return nil
+}
+
// checkCriuVersion checks Criu version greater than or equal to minVersion
func (c *linuxContainer) checkCriuVersion(minVersion string) error {
var x, y, z, versionReq int
@@ -718,6 +768,14 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
var t criurpc.CriuReqType
if criuOpts.PreDump {
+ feat := criurpc.CriuFeatures{
+ MemTrack: proto.Bool(true),
+ }
+
+ if err := c.checkCriuFeatures(criuOpts, &rpcOpts, &feat); err != nil {
+ return err
+ }
+
t = criurpc.CriuReqType_PRE_DUMP
} else {
t = criurpc.CriuReqType_DUMP
@@ -1019,16 +1077,21 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *
}
logrus.Debugf("Using CRIU in %s mode", req.GetType().String())
- val := reflect.ValueOf(req.GetOpts())
- v := reflect.Indirect(val)
- for i := 0; i < v.NumField(); i++ {
- st := v.Type()
- name := st.Field(i).Name
- if strings.HasPrefix(name, "XXX_") {
- continue
+ // In the case of criurpc.CriuReqType_FEATURE_CHECK req.GetOpts()
+ // should be empty. For older CRIU versions it still will be
+ // available but empty.
+ if req.GetType() != criurpc.CriuReqType_FEATURE_CHECK {
+ val := reflect.ValueOf(req.GetOpts())
+ v := reflect.Indirect(val)
+ for i := 0; i < v.NumField(); i++ {
+ st := v.Type()
+ name := st.Field(i).Name
+ if strings.HasPrefix(name, "XXX_") {
+ continue
+ }
+ value := val.MethodByName("Get" + name).Call([]reflect.Value{})
+ logrus.Debugf("CRIU option %s with value %v", name, value[0])
}
- value := val.MethodByName("Get" + name).Call([]reflect.Value{})
- logrus.Debugf("CRIU option %s with value %v", name, value[0])
}
data, err := proto.Marshal(req)
if err != nil {
@@ -1064,6 +1127,10 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *
t := resp.GetType()
switch {
+ case t == criurpc.CriuReqType_FEATURE_CHECK:
+ logrus.Debugf("Feature check says: %s", resp)
+ criuFeatures = resp.GetFeatures()
+ break
case t == criurpc.CriuReqType_NOTIFY:
if err := c.criuNotifications(resp, process, opts, extFds); err != nil {
return err
--
2.7.4.3

View File

@ -0,0 +1,129 @@
From 17199cf842a86765a21e2054e10e0c64f28353c8 Mon Sep 17 00:00:00 2001
From: Christy Perez <christy@linux.vnet.ibm.com>
Date: Mon, 27 Mar 2017 16:46:57 -0500
Subject: [PATCH 16/94] Fix console syscalls
Fixes opencontainers/runc/issues/1364
Change-Id: Ic12237e2ce327f4d9eab3145d0c4c2cff9fb641a
Signed-off-by: Christy Perez <christy@linux.vnet.ibm.com>
---
libcontainer/console_linux.go | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/libcontainer/console_linux.go b/libcontainer/console_linux.go
index e431766..5e364a8 100644
--- a/libcontainer/console_linux.go
+++ b/libcontainer/console_linux.go
@@ -3,8 +3,9 @@ package libcontainer
import (
"fmt"
"os"
- "syscall"
"unsafe"
+
+ "golang.org/x/sys/unix"
)
func ConsoleFromFile(f *os.File) Console {
@@ -16,7 +17,7 @@ func ConsoleFromFile(f *os.File) Console {
// newConsole returns an initialized console that can be used within a container by copying bytes
// from the master side to the slave that is attached as the tty for the container's init process.
func newConsole() (Console, error) {
- master, err := os.OpenFile("/dev/ptmx", syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_CLOEXEC, 0)
+ master, err := os.OpenFile("/dev/ptmx", unix.O_RDWR|unix.O_NOCTTY|unix.O_CLOEXEC, 0)
if err != nil {
return nil, err
}
@@ -68,8 +69,8 @@ func (c *linuxConsole) Close() error {
// mount initializes the console inside the rootfs mounting with the specified mount label
// and applying the correct ownership of the console.
func (c *linuxConsole) mount() error {
- oldMask := syscall.Umask(0000)
- defer syscall.Umask(oldMask)
+ oldMask := unix.Umask(0000)
+ defer unix.Umask(oldMask)
f, err := os.Create("/dev/console")
if err != nil && !os.IsExist(err) {
return err
@@ -77,19 +78,19 @@ func (c *linuxConsole) mount() error {
if f != nil {
f.Close()
}
- return syscall.Mount(c.slavePath, "/dev/console", "bind", syscall.MS_BIND, "")
+ return unix.Mount(c.slavePath, "/dev/console", "bind", unix.MS_BIND, "")
}
// dupStdio opens the slavePath for the console and dups the fds to the current
// processes stdio, fd 0,1,2.
func (c *linuxConsole) dupStdio() error {
- slave, err := c.open(syscall.O_RDWR)
+ slave, err := c.open(unix.O_RDWR)
if err != nil {
return err
}
fd := int(slave.Fd())
for _, i := range []int{0, 1, 2} {
- if err := syscall.Dup3(fd, i, 0); err != nil {
+ if err := unix.Dup3(fd, i, 0); err != nil {
return err
}
}
@@ -98,7 +99,7 @@ func (c *linuxConsole) dupStdio() error {
// open is a clone of os.OpenFile without the O_CLOEXEC used to open the pty slave.
func (c *linuxConsole) open(flag int) (*os.File, error) {
- r, e := syscall.Open(c.slavePath, flag, 0)
+ r, e := unix.Open(c.slavePath, flag, 0)
if e != nil {
return nil, &os.PathError{
Op: "open",
@@ -110,7 +111,7 @@ func (c *linuxConsole) open(flag int) (*os.File, error) {
}
func ioctl(fd uintptr, flag, data uintptr) error {
- if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, flag, data); err != 0 {
+ if _, _, err := unix.Syscall(unix.SYS_IOCTL, fd, flag, data); err != 0 {
return err
}
return nil
@@ -120,13 +121,13 @@ func ioctl(fd uintptr, flag, data uintptr) error {
// unlockpt should be called before opening the slave side of a pty.
func unlockpt(f *os.File) error {
var u int32
- return ioctl(f.Fd(), syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u)))
+ return ioctl(f.Fd(), unix.TIOCSPTLCK, uintptr(unsafe.Pointer(&u)))
}
// ptsname retrieves the name of the first available pts for the given master.
func ptsname(f *os.File) (string, error) {
var n int32
- if err := ioctl(f.Fd(), syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))); err != nil {
+ if err := ioctl(f.Fd(), unix.TIOCGPTN, uintptr(unsafe.Pointer(&n))); err != nil {
return "", err
}
return fmt.Sprintf("/dev/pts/%d", n), nil
@@ -139,16 +140,16 @@ func ptsname(f *os.File) (string, error) {
// also relay that funky line discipline.
func saneTerminal(terminal *os.File) error {
// Go doesn't have a wrapper for any of the termios ioctls.
- var termios syscall.Termios
+ var termios unix.Termios
- if err := ioctl(terminal.Fd(), syscall.TCGETS, uintptr(unsafe.Pointer(&termios))); err != nil {
+ if err := ioctl(terminal.Fd(), unix.TCGETS, uintptr(unsafe.Pointer(&termios))); err != nil {
return fmt.Errorf("ioctl(tty, tcgets): %s", err.Error())
}
// Set -onlcr so we don't have to deal with \r.
- termios.Oflag &^= syscall.ONLCR
+ termios.Oflag &^= unix.ONLCR
- if err := ioctl(terminal.Fd(), syscall.TCSETS, uintptr(unsafe.Pointer(&termios))); err != nil {
+ if err := ioctl(terminal.Fd(), unix.TCSETS, uintptr(unsafe.Pointer(&termios))); err != nil {
return fmt.Errorf("ioctl(tty, tcsets): %s", err.Error())
}
--
2.7.4.3

View File

@ -0,0 +1,34 @@
From 7b92e178267794e026f5c38e632d82a00f038e96 Mon Sep 17 00:00:00 2001
From: Andrei Vagin <avagin@virtuozzo.com>
Date: Fri, 7 Apr 2017 02:34:41 +0300
Subject: [PATCH 17/94] restore: apply resource limits
When C/R was implemented, it was enough to call manager.Set to apply
limits and to move a task. Now .Set() and .Apply() have to be called
separately.
Change-Id: I4786732a1779a65eeb902fc1ef42b194ba8dd3b4
Fixes: 8a740d5391a7 ("libcontainer: cgroups: don't Set in Apply")
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
---
libcontainer/container_linux.go | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 705472a..b5563d6 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -1008,6 +1008,10 @@ func (c *linuxContainer) criuApplyCgroups(pid int, req *criurpc.CriuReq) error {
return err
}
+ if err := c.cgroupManager.Set(c.config); err != nil {
+ return newSystemError(err)
+ }
+
path := fmt.Sprintf("/proc/%d/cgroup", pid)
cgroupsPaths, err := cgroups.ParseCgroupFile(path)
if err != nil {
--
2.7.4.3

View File

@ -0,0 +1,35 @@
From d8ea288801363d61c46a5eecfe7e1a9001767bc7 Mon Sep 17 00:00:00 2001
From: CuiHaozhi <cuihz@wise2c.com>
Date: Fri, 7 Apr 2017 07:39:41 -0400
Subject: [PATCH 18/94] could load a stopped container.
Change-Id: Ieabdef66ad7e9488a44b718093acf23f8aa947c4
Signed-off-by: CuiHaozhi <cuihz@wise2c.com>
---
libcontainer/factory.go | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/libcontainer/factory.go b/libcontainer/factory.go
index f0ccb52..0986cd7 100644
--- a/libcontainer/factory.go
+++ b/libcontainer/factory.go
@@ -10,7 +10,7 @@ type Factory interface {
// between 1 and 1024 characters, inclusive.
//
// The id must not already be in use by an existing container. Containers created using
- // a factory with the same path (and file system) must have distinct ids.
+ // a factory with the same path (and filesystem) must have distinct ids.
//
// Returns the new container with a running process.
//
@@ -28,7 +28,6 @@ type Factory interface {
//
// errors:
// Path does not exist
- // Container is stopped
// System error
Load(id string) (Container, error)
--
2.7.4.3

View File

@ -0,0 +1,32 @@
From a90e91c5fc8e6fb016d26666361e6d1bfd3f56c8 Mon Sep 17 00:00:00 2001
From: Michael Crosby <crosbymichael@gmail.com>
Date: Fri, 14 Apr 2017 10:15:33 -0700
Subject: [PATCH 19/94] Revert back to using /sbin
This was changed in
https://github.com/opencontainers/runc/commit/d2f49696#diff-b67911656ef5d18c4ae36cb6741b7965R7
and is causing install problems for people building runc and having it
installed in /bin and /sbin.
Change-Id: Ibaef1dd279894342c48da5e6e8e7f1a7212003b8
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
---
Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 1cecca1..d6d337d 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
SOURCES := $(shell find . 2>&1 | grep -E '.*\.(c|h|go)$$')
PREFIX := $(DESTDIR)/usr/local
-BINDIR := $(PREFIX)/bin
+BINDIR := $(PREFIX)/sbin
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
GIT_BRANCH_CLEAN := $(shell echo $(GIT_BRANCH) | sed -e "s/[^[:alnum:]]/-/g")
RUNC_IMAGE := runc_dev$(if $(GIT_BRANCH_CLEAN),:$(GIT_BRANCH_CLEAN))
--
2.7.4.3

View File

@ -0,0 +1,57 @@
From 9d30f4580c68c7d16a94d0df04b61571b212e55f Mon Sep 17 00:00:00 2001
From: chchliang <chen.chuanliang@zte.com.cn>
Date: Wed, 12 Apr 2017 16:26:30 +0800
Subject: [PATCH 20/94] add testcase in generic_error_test.go
Change-Id: Id0e21750ea9724d48423ab16f70786a1f62ea81c
Signed-off-by: chchliang <chen.chuanliang@zte.com.cn>
---
libcontainer/generic_error_test.go | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/libcontainer/generic_error_test.go b/libcontainer/generic_error_test.go
index 292d2a3..8fbdd4d 100644
--- a/libcontainer/generic_error_test.go
+++ b/libcontainer/generic_error_test.go
@@ -12,3 +12,38 @@ func TestErrorDetail(t *testing.T) {
t.Fatal(derr)
}
}
+
+func TestErrorWithCode(t *testing.T) {
+ err := newGenericError(fmt.Errorf("test error"), SystemError)
+ if code := err.Code(); code != SystemError {
+ t.Fatalf("expected err code %q but %q", SystemError, code)
+ }
+}
+
+func TestErrorWithError(t *testing.T) {
+ cc := []struct {
+ errmsg string
+ cause string
+ }{
+ {
+ errmsg: "test error",
+ },
+ {
+ errmsg: "test error",
+ cause: "test",
+ },
+ }
+
+ for _, v := range cc {
+ err := newSystemErrorWithCause(fmt.Errorf(v.errmsg), v.cause)
+
+ msg := err.Error()
+ if v.cause == "" && msg != v.errmsg {
+ t.Fatalf("expected err(%q) equal errmsg(%q)", msg, v.errmsg)
+ }
+ if v.cause != "" && msg == v.errmsg {
+ t.Fatalf("unexpected err(%q) equal errmsg(%q)", msg, v.errmsg)
+ }
+
+ }
+}
--
2.7.4.3

View File

@ -0,0 +1,53 @@
From fe398ce943f5da085507be6a164568544fc0d1c4 Mon Sep 17 00:00:00 2001
From: Tim Potter <tpot@hpe.com>
Date: Fri, 21 Apr 2017 12:41:02 +1000
Subject: [PATCH 21/94] Fix misspelling of "properties" in various
places
Change-Id: I69229a0ba2472b52edd4c444ac7820ade837726d
Signed-off-by: Tim Potter <tpot@hpe.com>
---
checkpoint.go | 2 +-
man/runc-checkpoint.8.md | 2 +-
restore.go | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/checkpoint.go b/checkpoint.go
index 78977d7..9b5663f 100644
--- a/checkpoint.go
+++ b/checkpoint.go
@@ -33,7 +33,7 @@ checkpointed.`,
cli.BoolFlag{Name: "file-locks", Usage: "handle file locks, for safety"},
cli.BoolFlag{Name: "pre-dump", Usage: "dump container's memory information only, leave the container running after this"},
cli.StringFlag{Name: "manage-cgroups-mode", Value: "", Usage: "cgroups mode: 'soft' (default), 'full' and 'strict'"},
- cli.StringSliceFlag{Name: "empty-ns", Usage: "create a namespace, but don't restore its properies"},
+ cli.StringSliceFlag{Name: "empty-ns", Usage: "create a namespace, but don't restore its properties"},
},
Action: func(context *cli.Context) error {
if err := checkArgs(context, 1, exactArgs); err != nil {
diff --git a/man/runc-checkpoint.8.md b/man/runc-checkpoint.8.md
index b0ce2f3..4c81fd4 100644
--- a/man/runc-checkpoint.8.md
+++ b/man/runc-checkpoint.8.md
@@ -22,4 +22,4 @@ checkpointed.
--file-locks handle file locks, for safety
--pre-dump dump container's memory information only, leave the container running after this
--manage-cgroups-mode value cgroups mode: 'soft' (default), 'full' and 'strict'
- --empty-ns value create a namespace, but don't restore its properies
+ --empty-ns value create a namespace, but don't restore its properties
diff --git a/restore.go b/restore.go
index 06f635f..7ddc337 100644
--- a/restore.go
+++ b/restore.go
@@ -80,7 +80,7 @@ using the runc checkpoint command.`,
},
cli.StringSliceFlag{
Name: "empty-ns",
- Usage: "create a namespace, but don't restore its properies",
+ Usage: "create a namespace, but don't restore its properties",
},
},
Action: func(context *cli.Context) error {
--
2.7.4.3

View File

@ -0,0 +1,63 @@
From e287eae0ba5cb39df6f09b3ce8436af3810986f3 Mon Sep 17 00:00:00 2001
From: Jonh Wendell <jonh.wendell@redhat.com>
Date: Fri, 21 Apr 2017 20:43:56 -0300
Subject: [PATCH 22/94] Add a rootless containers section on README
Closes #1413.
Change-Id: I9058fea54d9f25c2fc0f07ca74a83300eed40b73
Signed-off-by: Jonh Wendell <jonh.wendell@redhat.com>
---
README.md | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index ae1ab28..a951f0d 100644
--- a/README.md
+++ b/README.md
@@ -117,8 +117,8 @@ Assuming you have an OCI bundle from the previous step you can execute the conta
The first way is to use the convenience command `run` that will handle creating, starting, and deleting the container after it exits.
```bash
+# run as root
cd /mycontainer
-
runc run mycontainerid
```
@@ -165,8 +165,8 @@ Now we can go though the lifecycle operations in your shell.
```bash
+# run as root
cd /mycontainer
-
runc create mycontainerid
# view the container is created and in the "created" state
@@ -185,6 +185,22 @@ 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.
+#### Rootless containers
+`runc` has the ability to run containers without root privileges. This is called `rootless`. You need to pass some parameters to `runc` in order to run rootless containers. See below and compare with the previous version. Run the following commands as an ordinary user:
+```bash
+# Same as the first example
+mkdir ~/mycontainer
+cd ~/mycontainer
+mkdir rootfs
+docker export $(docker create busybox) | tar -C rootfs -xvf -
+
+# The --rootless parameter instructs runc spec to generate a configuration for a rootless container, which will allow you to run the container as a non-root user.
+runc spec --rootless
+
+# The --root parameter tells runc where to store the container state. It must be writable by the user.
+runc --root /tmp/runc run mycontainerid
+```
+
#### Supervisors
`runc` can be used with process supervisors and init systems to ensure that containers are restarted when they exit.
--
2.7.4.3

View File

@ -0,0 +1,69 @@
From d6c62e91d7763bb88287a052f6f5a3dc7bee5284 Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <asarai@suse.de>
Date: Sat, 15 Apr 2017 17:31:39 +1000
Subject: [PATCH 23/94] vendor: clean up to be better written
vndr doesn't support non-top-level imports, and in addition we really
should be using tagged releases far more than we currently are
(*especially* when it come to the OCI specs).
Change-Id: Ifb997a6d9edf2d89d6b2d440ea4fa305b1b4df18
Signed-off-by: Aleksa Sarai <asarai@suse.de>
---
tests/integration/spec.bats | 2 +-
vendor.conf | 28 +++++++++++++++++-----------
2 files changed, 18 insertions(+), 12 deletions(-)
diff --git a/tests/integration/spec.bats b/tests/integration/spec.bats
index e9f28fb..6061706 100644
--- a/tests/integration/spec.bats
+++ b/tests/integration/spec.bats
@@ -72,7 +72,7 @@ function teardown() {
run git clone https://github.com/opencontainers/runtime-spec.git src/runtime-spec
[ "$status" -eq 0 ]
- SPEC_COMMIT=$(grep runtime-spec ${TESTDIR}/../../vendor.conf | cut -d ' ' -f 2)
+ SPEC_COMMIT=$(grep '^github.com/opencontainers/runtime-spec' ${TESTDIR}/../../vendor.conf | cut -d ' ' -f 2)
run git -C src/runtime-spec reset --hard "${SPEC_COMMIT}"
[ "$status" -eq 0 ]
diff --git a/vendor.conf b/vendor.conf
index 17a546e..6ab9bf8 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -1,15 +1,21 @@
-github.com/Sirupsen/logrus 26709e2714106fb8ad40b773b711ebce25b78914
-github.com/coreos/go-systemd 48702e0da86bd25e76cfef347e2adeb434a0d0a6
-github.com/coreos/pkg/dlopen 3ac0863d7acf3bc44daf49afef8919af12f704ef
-github.com/docker/docker 0f5c9d301b9b1cca66b3ea0f9dec3b5317d3686d
-github.com/docker/go-units 9b001659dd36225e356b4467c465d732e745f53d
-github.com/godbus/dbus c7fdd8b5cd55e87b4e1f4e372cdb1db61dd6c66f
-github.com/golang/protobuf/proto f7137ae6b19afbfd61a94b746fda3b3fe0491874
+# OCI runtime-spec. When updating this, make sure you use a version tag rather
+# than a commit ID so it's much more obvious what version of the spec we are
+# using.
+github.com/opencontainers/runtime-spec v1.0.0-rc5
+# Core libcontainer functionality.
github.com/mrunalp/fileutils ed869b029674c0e9ce4c0dfa781405c2d9946d08
-github.com/opencontainers/runtime-spec/specs-go 035da1dca3dfbb00d752eb58b0b158d6129f3776
-github.com/opencontainers/selinux ba1aefe8057f1d0cfb8e88d0ec1dc85925ef987d
+github.com/opencontainers/selinux v1.0.0-rc1
github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
-github.com/syndtr/gocapability/capability e7cb7fa329f456b3855136a2642b197bad7366ba
-github.com/urfave/cli d53eb991652b1d438abdd34ce4bfa3ef1539108e
+github.com/Sirupsen/logrus 26709e2714106fb8ad40b773b711ebce25b78914
+github.com/syndtr/gocapability e7cb7fa329f456b3855136a2642b197bad7366ba
github.com/vishvananda/netlink 1e2e08e8a2dcdacaae3f14ac44c5cfa31361f270
+# systemd integration.
+github.com/coreos/go-systemd v14
+github.com/coreos/pkg v3
+github.com/godbus/dbus v3
+github.com/golang/protobuf f7137ae6b19afbfd61a94b746fda3b3fe0491874
+# Command-line interface.
+github.com/docker/docker 0f5c9d301b9b1cca66b3ea0f9dec3b5317d3686d
+github.com/docker/go-units v0.2.0
+github.com/urfave/cli d53eb991652b1d438abdd34ce4bfa3ef1539108e
golang.org/x/sys 9a7256cb28ed514b4e1e5f68959914c4c28a92e0 https://github.com/golang/sys
--
2.7.4.3

View File

@ -0,0 +1,58 @@
From 6108649ff1f4f270bfeb5f2aec1de8917d9b7609 Mon Sep 17 00:00:00 2001
From: Harshal Patil <harshal.patil@in.ibm.com>
Date: Tue, 25 Apr 2017 15:56:40 +0530
Subject: [PATCH 24/94] Optimizing looping over namespaces
Change-Id: I82612d1f8161b4656011ba45b619dcd9150a3c2f
Signed-off-by: Harshal Patil <harshal.patil@in.ibm.com>
---
libcontainer/container_linux.go | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index b5563d6..aeaf583 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -1454,18 +1454,17 @@ func (c *linuxContainer) orderNamespacePaths(namespaces map[configs.NamespaceTyp
configs.NEWNS,
}
- // Remove namespaces that we don't need to join.
- var nsTypes []configs.NamespaceType
for _, ns := range order {
- if c.config.Namespaces.Contains(ns) {
- nsTypes = append(nsTypes, ns)
+
+ // Remove namespaces that we don't need to join.
+ if !c.config.Namespaces.Contains(ns) {
+ continue
}
- }
- for _, nsType := range nsTypes {
- if p, ok := namespaces[nsType]; ok && p != "" {
+
+ if p, ok := namespaces[ns]; ok && p != "" {
// check if the requested namespace is supported
- if !configs.IsNamespaceSupported(nsType) {
- return nil, newSystemError(fmt.Errorf("namespace %s is not supported", nsType))
+ if !configs.IsNamespaceSupported(ns) {
+ return nil, newSystemError(fmt.Errorf("namespace %s is not supported", ns))
}
// only set to join this namespace if it exists
if _, err := os.Lstat(p); err != nil {
@@ -1476,9 +1475,11 @@ func (c *linuxContainer) orderNamespacePaths(namespaces map[configs.NamespaceTyp
if strings.ContainsRune(p, ',') {
return nil, newSystemError(fmt.Errorf("invalid path %s", p))
}
- paths = append(paths, fmt.Sprintf("%s:%s", configs.NsName(nsType), p))
+ paths = append(paths, fmt.Sprintf("%s:%s", configs.NsName(ns), p))
}
+
}
+
return paths, nil
}
--
2.7.4.3

View File

@ -0,0 +1,54 @@
From 06f6824badbdc3a8c89d106abe5337c869a7d95f Mon Sep 17 00:00:00 2001
From: Jonh Wendell <jonh.wendell@redhat.com>
Date: Thu, 27 Apr 2017 10:52:31 -0300
Subject: [PATCH 25/94] Add a rootless section to "spec" man page and
command help
Change-Id: I6211c1adf2f6428652c75cd7cb76b86d782e7237
Signed-off-by: Jonh Wendell <jonh.wendell@redhat.com>
---
man/runc-spec.8.md | 3 +++
spec.go | 9 +++++++--
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/man/runc-spec.8.md b/man/runc-spec.8.md
index 3c69e23..4f8e9bb 100644
--- a/man/runc-spec.8.md
+++ b/man/runc-spec.8.md
@@ -45,5 +45,8 @@ already running as root, you can use sudo to give runc root privilege. For
example: "sudo runc start container1" will give runc root privilege to start the
container on your host.
+Alternatively, you can start a rootless container, which has the ability to run without root privileges. For this to work, the specification file needs to be adjusted accordingly. You can pass the parameter --rootless to this command to generate a proper rootless spec file.
+
# OPTIONS
--bundle value, -b value path to the root of the bundle directory
+ --rootless generate a configuration for a rootless container
diff --git a/spec.go b/spec.go
index 9024ad4..a15c84e 100644
--- a/spec.go
+++ b/spec.go
@@ -51,13 +51,18 @@ must be unique on your host.
An alternative for generating a customized spec config is to use "oci-runtime-tool", the
sub-command "oci-runtime-tool generate" has lots of options that can be used to do any
-customizations as you want, see [runtime-tools](https://github.com/opencontainers/runtime-tools)
+customizations as you want, see runtime-tools (https://github.com/opencontainers/runtime-tools)
to get more information.
When starting a container through runc, runc needs root privilege. If not
already running as root, you can use sudo to give runc root privilege. For
example: "sudo runc start container1" will give runc root privilege to start the
-container on your host.`,
+container on your host.
+
+Alternatively, you can start a rootless container, which has the ability to run
+without root privileges. For this to work, the specification file needs to be
+adjusted accordingly. You can pass the parameter --rootless to this command to
+generate a proper rootless spec file.`,
Flags: []cli.Flag{
cli.StringFlag{
Name: "bundle, b",
--
2.7.4.3

View File

@ -0,0 +1,150 @@
From 01218c77284209117e40350419fb60f76896a369 Mon Sep 17 00:00:00 2001
From: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
Date: Wed, 26 Apr 2017 09:53:20 -0700
Subject: [PATCH 26/94] Allow updating container pids limit
Change-Id: I5cc0d8804b1de3da943e4651806d0041eb33d7f2
Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
---
tests/integration/update.bats | 23 +++++++++++++++++++++--
update.go | 9 +++++++++
2 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/tests/integration/update.bats b/tests/integration/update.bats
index 4a6bf7f..a3f3782 100644
--- a/tests/integration/update.bats
+++ b/tests/integration/update.bats
@@ -33,6 +33,9 @@ function setup() {
"blockio": {
"blkioWeight": 1000
},
+ "pids": {
+ "limit": 20
+ },
EOF
)
DATA=$(echo ${DATA} | sed 's/\n/\\n/g')
@@ -61,7 +64,7 @@ function check_cgroup_value() {
wait_for_container 15 1 test_update
# get the cgroup paths
- for g in MEMORY CPUSET CPU BLKIO; do
+ for g in MEMORY CPUSET CPU BLKIO PIDS; do
base_path=$(grep "cgroup" /proc/self/mountinfo | gawk 'toupper($NF) ~ /\<'${g}'\>/ { print $5; exit }')
eval CGROUP_${g}="${base_path}/runc-update-integration-test"
done
@@ -78,6 +81,7 @@ function check_cgroup_value() {
check_cgroup_value $CGROUP_MEMORY "memory.kmem.tcp.limit_in_bytes" 11534336
check_cgroup_value $CGROUP_MEMORY "memory.limit_in_bytes" 33554432
check_cgroup_value $CGROUP_MEMORY "memory.soft_limit_in_bytes" 25165824
+ check_cgroup_value $CGROUP_PIDS "pids.max" 20
# update blkio-weight
runc update test_update --blkio-weight 500
@@ -160,6 +164,11 @@ function check_cgroup_value() {
[ "$status" -eq 0 ]
check_cgroup_value $CGROUP_MEMORY "memory.kmem.tcp.limit_in_bytes" 41943040
+ # update pids limit
+ runc update test_update --pids-limit 10
+ [ "$status" -eq 0 ]
+ check_cgroup_value $CGROUP_PIDS "pids.max" 10
+
# Revert to the test initial value via json on stding
runc update -r - test_update <<EOF
{
@@ -177,6 +186,9 @@ function check_cgroup_value() {
},
"blockIO": {
"blkioWeight": 1000
+ },
+ "pids": {
+ "limit": 20
}
}
EOF
@@ -190,11 +202,13 @@ EOF
check_cgroup_value $CGROUP_MEMORY "memory.kmem.tcp.limit_in_bytes" 11534336
check_cgroup_value $CGROUP_MEMORY "memory.limit_in_bytes" 33554432
check_cgroup_value $CGROUP_MEMORY "memory.soft_limit_in_bytes" 25165824
+ check_cgroup_value $CGROUP_PIDS "pids.max" 20
# redo all the changes at once
runc update test_update --blkio-weight 500 \
--cpu-period 900000 --cpu-quota 600000 --cpu-share 200 --memory 67108864 \
- --memory-reservation 33554432 --kernel-memory 50331648 --kernel-memory-tcp 41943040
+ --memory-reservation 33554432 --kernel-memory 50331648 --kernel-memory-tcp 41943040 \
+ --pids-limit 10
[ "$status" -eq 0 ]
check_cgroup_value $CGROUP_BLKIO "blkio.weight" 500
check_cgroup_value $CGROUP_CPU "cpu.cfs_period_us" 900000
@@ -204,6 +218,7 @@ EOF
check_cgroup_value $CGROUP_MEMORY "memory.kmem.tcp.limit_in_bytes" 41943040
check_cgroup_value $CGROUP_MEMORY "memory.limit_in_bytes" 67108864
check_cgroup_value $CGROUP_MEMORY "memory.soft_limit_in_bytes" 33554432
+ check_cgroup_value $CGROUP_PIDS "pids.max" 10
# reset to initial test value via json file
DATA=$(cat <<"EOF"
@@ -222,6 +237,9 @@ EOF
},
"blockIO": {
"blkioWeight": 1000
+ },
+ "pids": {
+ "limit": 20
}
}
EOF
@@ -239,6 +257,7 @@ EOF
check_cgroup_value $CGROUP_MEMORY "memory.kmem.tcp.limit_in_bytes" 11534336
check_cgroup_value $CGROUP_MEMORY "memory.limit_in_bytes" 33554432
check_cgroup_value $CGROUP_MEMORY "memory.soft_limit_in_bytes" 25165824
+ check_cgroup_value $CGROUP_PIDS "pids.max" 20
}
@test "update rt period and runtime" {
diff --git a/update.go b/update.go
index 7af3a9c..5520681 100644
--- a/update.go
+++ b/update.go
@@ -108,6 +108,10 @@ other options are ignored.
Name: "memory-swap",
Usage: "Total memory usage (memory + swap); set '-1' to enable unlimited swap",
},
+ cli.IntFlag{
+ Name: "pids-limit",
+ Usage: "Maximum number of pids allowed in the container",
+ },
},
Action: func(context *cli.Context) error {
if err := checkArgs(context, 1, exactArgs); err != nil {
@@ -138,6 +142,9 @@ other options are ignored.
BlockIO: &specs.LinuxBlockIO{
Weight: u16Ptr(0),
},
+ Pids: &specs.LinuxPids{
+ Limit: 0,
+ },
}
config := container.Config()
@@ -228,6 +235,7 @@ other options are ignored.
*pair.dest = uint64(v)
}
}
+ r.Pids.Limit = int64(context.Int("pids-limit"))
}
// Update the value
@@ -244,6 +252,7 @@ other options are ignored.
config.Cgroups.Resources.Memory = *r.Memory.Limit
config.Cgroups.Resources.MemoryReservation = *r.Memory.Reservation
config.Cgroups.Resources.MemorySwap = *r.Memory.Swap
+ config.Cgroups.Resources.PidsLimit = r.Pids.Limit
return container.Set(config)
},
--
2.7.4.3

View File

@ -0,0 +1,59 @@
From e35db3fff6d86c31ca0203ef02ffa1cf2b05bf89 Mon Sep 17 00:00:00 2001
From: Harshal Patil <harshal.patil@in.ibm.com>
Date: Fri, 28 Apr 2017 10:12:56 +0530
Subject: [PATCH 27/94] Remove redundant declaraion of namespace
slice
Change-Id: I7e7e45cec65264a91ef3dec804953a1285b23b96
Signed-off-by: Harshal Patil <harshal.patil@in.ibm.com>
---
libcontainer/configs/namespaces_unix.go | 6 +++---
libcontainer/container_linux.go | 11 +----------
2 files changed, 4 insertions(+), 13 deletions(-)
diff --git a/libcontainer/configs/namespaces_unix.go b/libcontainer/configs/namespaces_unix.go
index 8beba9d..1f0b3ee 100644
--- a/libcontainer/configs/namespaces_unix.go
+++ b/libcontainer/configs/namespaces_unix.go
@@ -64,12 +64,12 @@ func IsNamespaceSupported(ns NamespaceType) bool {
func NamespaceTypes() []NamespaceType {
return []NamespaceType{
+ NEWUSER, // Keep user NS always first, don't move it.
+ NEWIPC,
+ NEWUTS,
NEWNET,
NEWPID,
NEWNS,
- NEWUTS,
- NEWIPC,
- NEWUSER,
}
}
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index aeaf583..173a3f0 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -1444,17 +1444,8 @@ func (c *linuxContainer) currentState() (*State, error) {
// can setns in order.
func (c *linuxContainer) orderNamespacePaths(namespaces map[configs.NamespaceType]string) ([]string, error) {
paths := []string{}
- order := []configs.NamespaceType{
- // The user namespace *must* be done first.
- configs.NEWUSER,
- configs.NEWIPC,
- configs.NEWUTS,
- configs.NEWNET,
- configs.NEWPID,
- configs.NEWNS,
- }
- for _, ns := range order {
+ for _, ns := range configs.NamespaceTypes() {
// Remove namespaces that we don't need to join.
if !c.config.Namespaces.Contains(ns) {
--
2.7.4.3

View File

@ -0,0 +1,31 @@
From 34dc868ee8515be89835bc98ccbf01f22bd6b1b9 Mon Sep 17 00:00:00 2001
From: Michael Crosby <crosbymichael@gmail.com>
Date: Wed, 7 Jun 2017 10:51:42 -0700
Subject: [PATCH 28/94] Revert saneTerminal
Keep the ONCLR for the terminal created by runc for backwards compat
support of older clients.
Change-Id: Ibdf33687262f13ef98c882328d55c9c4212ce0b6
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
---
libcontainer/console_linux.go | 3 ---
1 file changed, 3 deletions(-)
diff --git a/libcontainer/console_linux.go b/libcontainer/console_linux.go
index 5e364a8..5927bdc 100644
--- a/libcontainer/console_linux.go
+++ b/libcontainer/console_linux.go
@@ -21,9 +21,6 @@ func newConsole() (Console, error) {
if err != nil {
return nil, err
}
- if err := saneTerminal(master); err != nil {
- return nil, err
- }
console, err := ptsname(master)
if err != nil {
return nil, err
--
2.7.4.3

View File

@ -0,0 +1,59 @@
From c9d66ffed85529579f4247581d0d387fc21d92fa Mon Sep 17 00:00:00 2001
From: Tibor Vass <tibor@docker.com>
Date: Thu, 6 Jul 2017 10:28:14 -0700
Subject: [PATCH 29/94] vendor runtime-spec fork
docker/runtime-spec@a45ba0989fc26c695fe166a49c45bb8b7618ab36
This vendoring brings in the change from uint64 to int64 in the Memory
structs.
Change-Id: Ic928ff9cde8055a24ad039ccff64b8ceff917142
Signed-off-by: Tibor Vass <tibor@docker.com>
---
vendor.conf | 2 +-
.../opencontainers/runtime-spec/specs-go/config.go | 12 ++++++------
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/vendor.conf b/vendor.conf
index 6ab9bf8..b961707 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -1,7 +1,7 @@
# OCI runtime-spec. When updating this, make sure you use a version tag rather
# than a commit ID so it's much more obvious what version of the spec we are
# using.
-github.com/opencontainers/runtime-spec v1.0.0-rc5
+github.com/opencontainers/runtime-spec a45ba0989fc26c695fe166a49c45bb8b7618ab36 https://github.com/docker/runtime-spec
# Core libcontainer functionality.
github.com/mrunalp/fileutils ed869b029674c0e9ce4c0dfa781405c2d9946d08
github.com/opencontainers/selinux v1.0.0-rc1
diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
index bd8e96a..6d2a026 100644
--- a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
+++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
@@ -281,16 +281,16 @@ type LinuxBlockIO struct {
// LinuxMemory for Linux cgroup 'memory' resource management
type LinuxMemory struct {
// Memory limit (in bytes).
- Limit *uint64 `json:"limit,omitempty"`
+ Limit *int64 `json:"limit,omitempty"`
// Memory reservation or soft_limit (in bytes).
- Reservation *uint64 `json:"reservation,omitempty"`
+ Reservation *int64 `json:"reservation,omitempty"`
// Total memory limit (memory + swap).
- Swap *uint64 `json:"swap,omitempty"`
+ Swap *int64 `json:"swap,omitempty"`
// Kernel memory limit (in bytes).
- Kernel *uint64 `json:"kernel,omitempty"`
+ Kernel *int64 `json:"kernel,omitempty"`
// Kernel memory limit for tcp (in bytes)
- KernelTCP *uint64 `json:"kernelTCP,omitempty"`
- // How aggressive the kernel will swap memory pages. Range from 0 to 100.
+ KernelTCP *int64 `json:"kernelTCP,omitempty"`
+ // How aggressive the kernel will swap memory pages.
Swappiness *uint64 `json:"swappiness,omitempty"`
}
--
2.7.4.3

View File

@ -0,0 +1,198 @@
From 8ffbf2a8b8ae7119ae31bb15a30cb41711b809e2 Mon Sep 17 00:00:00 2001
From: Justin Cormack <justin.cormack@docker.com>
Date: Fri, 23 Jun 2017 17:17:00 -0700
Subject: [PATCH 30/94] Update memory specs to use int64 not uint64
replace #1492 #1494
fix #1422
Since https://github.com/opencontainers/runtime-spec/pull/876 the memory
specifications are now `int64`, as that better matches the visible interface where
`-1` is a valid value. Otherwise finding the correct value was difficult as it
was kernel dependent.
Signed-off-by: Justin Cormack <justin.cormack@docker.com>
(cherry picked from commit 3d9074ead33a5c27dc20bb49457c69c6d2ae6b57)
Signed-off-by: Tibor Vass <tibor@docker.com>
Change-Id: I07ec53368c5058076d3bd35e122f32259bf69854
---
libcontainer/cgroups/fs/memory.go | 36 +++++++++++++++++-------------------
libcontainer/configs/cgroup_unix.go | 10 +++++-----
update.go | 14 +++++++-------
3 files changed, 29 insertions(+), 31 deletions(-)
diff --git a/libcontainer/cgroups/fs/memory.go b/libcontainer/cgroups/fs/memory.go
index 0981cfb..c993839 100644
--- a/libcontainer/cgroups/fs/memory.go
+++ b/libcontainer/cgroups/fs/memory.go
@@ -71,14 +71,14 @@ func EnableKernelMemoryAccounting(path string) error {
// until a limit is set on the cgroup and limit cannot be set once the
// cgroup has children, or if there are already tasks in the cgroup.
for _, i := range []int64{1, -1} {
- if err := setKernelMemory(path, uint64(i)); err != nil {
+ if err := setKernelMemory(path, i); err != nil {
return err
}
}
return nil
}
-func setKernelMemory(path string, kernelMemoryLimit uint64) error {
+func setKernelMemory(path string, kernelMemoryLimit int64) error {
if path == "" {
return fmt.Errorf("no such directory for %s", cgroupKernelMemoryLimit)
}
@@ -86,7 +86,7 @@ func setKernelMemory(path string, kernelMemoryLimit uint64) error {
// kernel memory is not enabled on the system so we should do nothing
return nil
}
- if err := ioutil.WriteFile(filepath.Join(path, cgroupKernelMemoryLimit), []byte(strconv.FormatUint(kernelMemoryLimit, 10)), 0700); err != nil {
+ if err := ioutil.WriteFile(filepath.Join(path, cgroupKernelMemoryLimit), []byte(strconv.FormatInt(kernelMemoryLimit, 10)), 0700); err != nil {
// Check if the error number returned by the syscall is "EBUSY"
// The EBUSY signal is returned on attempts to write to the
// memory.kmem.limit_in_bytes file if the cgroup has children or
@@ -104,14 +104,12 @@ func setKernelMemory(path string, kernelMemoryLimit uint64) error {
}
func setMemoryAndSwap(path string, cgroup *configs.Cgroup) error {
- ulimited := -1
-
- // If the memory update is set to uint64(-1) we should also
- // set swap to uint64(-1), it means unlimited memory.
- if cgroup.Resources.Memory == uint64(ulimited) {
- // Only set swap if it's enbled in kernel
+ // If the memory update is set to -1 we should also
+ // set swap to -1, it means unlimited memory.
+ if cgroup.Resources.Memory == -1 {
+ // Only set swap if it's enabled in kernel
if cgroups.PathExists(filepath.Join(path, cgroupMemorySwapLimit)) {
- cgroup.Resources.MemorySwap = uint64(ulimited)
+ cgroup.Resources.MemorySwap = -1
}
}
@@ -126,29 +124,29 @@ func setMemoryAndSwap(path string, cgroup *configs.Cgroup) error {
// When update memory limit, we should adapt the write sequence
// for memory and swap memory, so it won't fail because the new
// value and the old value don't fit kernel's validation.
- if cgroup.Resources.MemorySwap == uint64(ulimited) || memoryUsage.Limit < cgroup.Resources.MemorySwap {
- if err := writeFile(path, cgroupMemorySwapLimit, strconv.FormatUint(cgroup.Resources.MemorySwap, 10)); err != nil {
+ if cgroup.Resources.MemorySwap == -1 || memoryUsage.Limit < uint64(cgroup.Resources.MemorySwap) {
+ if err := writeFile(path, cgroupMemorySwapLimit, strconv.FormatInt(cgroup.Resources.MemorySwap, 10)); err != nil {
return err
}
- if err := writeFile(path, cgroupMemoryLimit, strconv.FormatUint(cgroup.Resources.Memory, 10)); err != nil {
+ if err := writeFile(path, cgroupMemoryLimit, strconv.FormatInt(cgroup.Resources.Memory, 10)); err != nil {
return err
}
} else {
- if err := writeFile(path, cgroupMemoryLimit, strconv.FormatUint(cgroup.Resources.Memory, 10)); err != nil {
+ if err := writeFile(path, cgroupMemoryLimit, strconv.FormatInt(cgroup.Resources.Memory, 10)); err != nil {
return err
}
- if err := writeFile(path, cgroupMemorySwapLimit, strconv.FormatUint(cgroup.Resources.MemorySwap, 10)); err != nil {
+ if err := writeFile(path, cgroupMemorySwapLimit, strconv.FormatInt(cgroup.Resources.MemorySwap, 10)); err != nil {
return err
}
}
} else {
if cgroup.Resources.Memory != 0 {
- if err := writeFile(path, cgroupMemoryLimit, strconv.FormatUint(cgroup.Resources.Memory, 10)); err != nil {
+ if err := writeFile(path, cgroupMemoryLimit, strconv.FormatInt(cgroup.Resources.Memory, 10)); err != nil {
return err
}
}
if cgroup.Resources.MemorySwap != 0 {
- if err := writeFile(path, cgroupMemorySwapLimit, strconv.FormatUint(cgroup.Resources.MemorySwap, 10)); err != nil {
+ if err := writeFile(path, cgroupMemorySwapLimit, strconv.FormatInt(cgroup.Resources.MemorySwap, 10)); err != nil {
return err
}
}
@@ -169,13 +167,13 @@ func (s *MemoryGroup) Set(path string, cgroup *configs.Cgroup) error {
}
if cgroup.Resources.MemoryReservation != 0 {
- if err := writeFile(path, "memory.soft_limit_in_bytes", strconv.FormatUint(cgroup.Resources.MemoryReservation, 10)); err != nil {
+ if err := writeFile(path, "memory.soft_limit_in_bytes", strconv.FormatInt(cgroup.Resources.MemoryReservation, 10)); err != nil {
return err
}
}
if cgroup.Resources.KernelMemoryTCP != 0 {
- if err := writeFile(path, "memory.kmem.tcp.limit_in_bytes", strconv.FormatUint(cgroup.Resources.KernelMemoryTCP, 10)); err != nil {
+ if err := writeFile(path, "memory.kmem.tcp.limit_in_bytes", strconv.FormatInt(cgroup.Resources.KernelMemoryTCP, 10)); err != nil {
return err
}
}
diff --git a/libcontainer/configs/cgroup_unix.go b/libcontainer/configs/cgroup_unix.go
index 7572289..e654960 100644
--- a/libcontainer/configs/cgroup_unix.go
+++ b/libcontainer/configs/cgroup_unix.go
@@ -45,19 +45,19 @@ type Resources struct {
Devices []*Device `json:"devices"`
// Memory limit (in bytes)
- Memory uint64 `json:"memory"`
+ Memory int64 `json:"memory"`
// Memory reservation or soft_limit (in bytes)
- MemoryReservation uint64 `json:"memory_reservation"`
+ MemoryReservation int64 `json:"memory_reservation"`
// Total memory usage (memory + swap); set `-1` to enable unlimited swap
- MemorySwap uint64 `json:"memory_swap"`
+ MemorySwap int64 `json:"memory_swap"`
// Kernel memory limit (in bytes)
- KernelMemory uint64 `json:"kernel_memory"`
+ KernelMemory int64 `json:"kernel_memory"`
// Kernel memory limit for TCP use (in bytes)
- KernelMemoryTCP uint64 `json:"kernel_memory_tcp"`
+ KernelMemoryTCP int64 `json:"kernel_memory_tcp"`
// CPU shares (relative weight vs. other containers)
CpuShares uint64 `json:"cpu_shares"`
diff --git a/update.go b/update.go
index 5520681..226a18a 100644
--- a/update.go
+++ b/update.go
@@ -124,11 +124,11 @@ other options are ignored.
r := specs.LinuxResources{
Memory: &specs.LinuxMemory{
- Limit: u64Ptr(0),
- Reservation: u64Ptr(0),
- Swap: u64Ptr(0),
- Kernel: u64Ptr(0),
- KernelTCP: u64Ptr(0),
+ Limit: i64Ptr(0),
+ Reservation: i64Ptr(0),
+ Swap: i64Ptr(0),
+ Kernel: i64Ptr(0),
+ KernelTCP: i64Ptr(0),
},
CPU: &specs.LinuxCPU{
Shares: u64Ptr(0),
@@ -213,7 +213,7 @@ other options are ignored.
}
for _, pair := range []struct {
opt string
- dest *uint64
+ dest *int64
}{
{"memory", r.Memory.Limit},
{"memory-swap", r.Memory.Swap},
@@ -232,7 +232,7 @@ other options are ignored.
} else {
v = -1
}
- *pair.dest = uint64(v)
+ *pair.dest = v
}
}
r.Pids.Limit = int64(context.Int("pids-limit"))
--
2.7.4.3

View File

@ -0,0 +1,70 @@
From 3a4b5e8752e2200d0b7967c0cf0fd8ab859b6d1a Mon Sep 17 00:00:00 2001
From: Lei Jitang <leijitang@huawei.com>
Date: Mon, 17 Jul 2017 02:39:37 -0400
Subject: [PATCH 31/94] Add spec for euleros
Change-Id: I74128e7ba4aa7f2a15515ac753664c933432b149
Signed-off-by: Lei Jitang <leijitang@huawei.com>
---
script/runc-euleros.spec | 49 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
create mode 100644 script/runc-euleros.spec
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
new file mode 100644
index 0000000..a925e02
--- /dev/null
+++ b/script/runc-euleros.spec
@@ -0,0 +1,49 @@
+%global _bindir /usr/local/bin
+
+Name: docker-runc
+Version: 1.0.0.rc3
+Release: 1%{?dist}
+Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
+
+License: ASL 2.0
+Source: %{name}.tar.gz
+
+URL: https://www.opencontainers.org/
+Vendor: OCI
+Packager: OCI
+
+BuildRequires: golang == 1.8.3
+BuildRequires: glibc-static
+BuildRequires: make
+BuildRequires: libseccomp-devel
+BuildRequires: libselinux-devel
+
+
+%description
+runc is a CLI tool for spawning and running containers according to the OCF specification
+
+%prep
+%setup -c -n runc
+
+%install
+
+
+mkdir -p .gopath/src/github.com/opencontainers
+export GOPATH=`pwd`/.gopath
+ln -sf `pwd` .gopath/src/github.com/opencontainers/runc
+cd .gopath/src/github.com/opencontainers/runc
+make BUILDTAGS="seccomp selinux" static
+rm -rf .gopath
+
+install -d $RPM_BUILD_ROOT/%{_bindir}
+install -p -m 755 runc $RPM_BUILD_ROOT/%{_bindir}/runc
+
+
+%clean
+%{__rm} -rf %{_bindir}/runc
+
+%files
+%{_bindir}/runc
+
+%changelog
+
--
2.7.4.3

View File

@ -0,0 +1,84 @@
From 59a5c027ef71cbad624c7547f3031dc87fc6220d Mon Sep 17 00:00:00 2001
From: Yuanhong Peng <pengyuanhong@huawei.com>
Date: Thu, 13 Jul 2017 16:57:00 +0800
Subject: [PATCH 32/94] runc-17: Always save own namespace paths
[Changelog]: Always save own namespace paths
fix https://github.com/opencontainers/runc/issues/1476
If containerA shares namespace, say ipc namespace, with containerB, then
its ipc namespace path would be the same as containerB and be stored in
`state.json`. Exec into containerA will just read the namespace paths
stored in this file and join these namespaces. So, if containerB has
already been stopped, `docker exec containerA` will fail.
To address this issue, we should always save own namespace paths no
matter if we share namespaces with other containers.
**before:**
```
# docker run -tid --name 111 ubuntu
b123d1a43786523996a52f88c0484b77f778ff59435e257b901926366ba9e046
# docker run -tid --name 222 --net container:111 ubuntu
4685ca6a5e9fd03c634a88f6a07009738729f6210b13d32ea8fc46a058b1f004
# docker restart 111
111
# docker exec -ti 222 bash
rpc error: code = 2 desc = oci runtime error: exec failed: container_linux.go:240:
creating new parent process caused "container_linux.go:1266: running lstat on namespace
path \"/proc/14575/ns/net\" caused \"lstat /proc/14575/ns/net: no such file or directory\""
```
**after:**
```
# docker run -tid --name 111 ubuntu
e00dbfe3bf56272d7bdec232135f707b4a715cb0d39cdc4d3e90b05075497175
# docker run -tid --name 222 --net container:111 ubuntu
0806efe28080392f5a3ef416c363be0d82c3bc64d069f227d57ab34170b6fb16
# docker restart 111
111
# docker exec -ti 222 bash
root@e00dbfe3bf56:/#
```
related upstream PR: https://github.com/opencontainers/runc/pull/1477
Change-Id: I4278f64704c4b0ab0c2e5b44ec9ecdd34735144d
Signed-off-by: Yuanhong Peng <pengyuanhong@huawei.com>
Signed-off-by: yangshukui <yangshukui@huawei.com>
---
libcontainer/configs/namespaces_unix.go | 3 ---
libcontainer/container_linux_test.go | 2 +-
2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/libcontainer/configs/namespaces_unix.go b/libcontainer/configs/namespaces_unix.go
index 1f0b3ee..12470a0 100644
--- a/libcontainer/configs/namespaces_unix.go
+++ b/libcontainer/configs/namespaces_unix.go
@@ -81,9 +81,6 @@ type Namespace struct {
}
func (n *Namespace) GetPath(pid int) string {
- if n.Path != "" {
- return n.Path
- }
return fmt.Sprintf("/proc/%d/ns/%s", pid, NsName(n.Type))
}
diff --git a/libcontainer/container_linux_test.go b/libcontainer/container_linux_test.go
index b7ce552..b69e344 100644
--- a/libcontainer/container_linux_test.go
+++ b/libcontainer/container_linux_test.go
@@ -134,7 +134,7 @@ func TestGetContainerState(t *testing.T) {
var (
pid = os.Getpid()
expectedMemoryPath = "/sys/fs/cgroup/memory/myid"
- expectedNetworkPath = "/networks/fd"
+ expectedNetworkPath = fmt.Sprintf("/proc/%d/ns/net", pid)
)
container := &linuxContainer{
id: "myid",
--
2.7.4.3

View File

@ -0,0 +1,52 @@
From 49ff7be84939cf93b8bf4861ddc783704fb3f50b Mon Sep 17 00:00:00 2001
From: dengguangxing <dengguangxing@huawei.com>
Date: Mon, 8 Jan 2018 10:35:34 +0800
Subject: [PATCH 33/94] runc: change runc default umask to 027
[Changelog]:change runc default umask to 027
change exec process default umask to 0027
Change-Id: Ia7ff0216adc17d61586954de83031be21ab88338
Signed-off-by: dengguangxing <dengguangxing@huawei.com>
---
libcontainer/rootfs_linux.go | 2 +-
libcontainer/setns_init_linux.go | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go
index d507373..1c93903 100644
--- a/libcontainer/rootfs_linux.go
+++ b/libcontainer/rootfs_linux.go
@@ -136,7 +136,7 @@ func finalizeRootfs(config *configs.Config) (err error) {
}
}
- syscall.Umask(0022)
+ syscall.Umask(0027)
return nil
}
diff --git a/libcontainer/setns_init_linux.go b/libcontainer/setns_init_linux.go
index 48cc0ae..e8e969a 100644
--- a/libcontainer/setns_init_linux.go
+++ b/libcontainer/setns_init_linux.go
@@ -5,6 +5,7 @@ package libcontainer
import (
"fmt"
"os"
+ "syscall"
"github.com/opencontainers/runc/libcontainer/apparmor"
"github.com/opencontainers/runc/libcontainer/keys"
@@ -40,6 +41,8 @@ func (l *linuxSetnsInit) Init() error {
return err
}
}
+ // set exec process umask to 0027 according to secure policy
+ syscall.Umask(0027)
if l.config.NoNewPrivileges {
if err := system.Prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil {
return err
--
2.7.4.3

View File

@ -0,0 +1,50 @@
From 661a5bf6a414ded19e8722e81ea20f6218d9b7de Mon Sep 17 00:00:00 2001
From: yangshukui <yangshukui@huawei.com>
Date: Fri, 20 Apr 2018 22:38:32 +0800
Subject: [PATCH 34/94] runc-17: Add some compatibility code to surport
docker's liverestore from docker-1.11.2 to docker-17.06
[Changelog]: Add some compatibility code to surport docker's liverestore from docker-1.11.2 to docker-17.06
[Author]:Shukui Yang <yangshukui@huawei.com>
Change-Id: I376cc81f781727ea8d0bc61bc0c6e72ca485d880
Signed-off-by: yangshukui <yangshukui@huawei.com>
---
libcontainer/factory_linux.go | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/libcontainer/factory_linux.go b/libcontainer/factory_linux.go
index 6a0f855..8bf448a 100644
--- a/libcontainer/factory_linux.go
+++ b/libcontainer/factory_linux.go
@@ -10,6 +10,7 @@ import (
"regexp"
"runtime/debug"
"strconv"
+ "strings"
"syscall"
"github.com/docker/docker/pkg/mount"
@@ -321,7 +322,17 @@ func (l *LinuxFactory) loadState(root, id string) (*State, error) {
defer f.Close()
var state *State
if err := json.NewDecoder(f).Decode(&state); err != nil {
- return nil, newGenericError(err, SystemError)
+ if !strings.Contains(err.Error(), "memory_swappiness") {
+ return nil, newGenericError(err, SystemError)
+ }
+
+ if state.BaseState.Config.Cgroups != nil &&
+ state.BaseState.Config.Cgroups.Resources != nil &&
+ state.BaseState.Config.Cgroups.Resources.MemorySwappiness != nil {
+ memorySwappiness := int64(-1)
+ *state.BaseState.Config.Cgroups.Resources.MemorySwappiness = uint64(memorySwappiness)
+ }
+
}
return state, nil
}
--
2.7.4.3

View File

@ -0,0 +1,141 @@
From 35c1ee336b5714b077c0007ed6c37149bd965260 Mon Sep 17 00:00:00 2001
From: yangshukui <yangshukui@huawei.com>
Date: Fri, 27 Apr 2018 20:24:42 +0800
Subject: [PATCH 35/94] runc-17: Add root to HookState for
compatibility.
[Changelog]:refactor HookState for backward compatibility.
[Author]:Shukui Yang
Change-Id: I471a748005fe5a7be69d5a857944bf8599408c3b
Signed-off-by: yangshukui <yangshukui@huawei.com>
---
libcontainer/configs/config.go | 8 +++++++-
libcontainer/container_linux.go | 22 ++++++++++++++--------
libcontainer/process_linux.go | 22 ++++++++++++++--------
libcontainer/state_linux.go | 9 ++++++---
4 files changed, 41 insertions(+), 20 deletions(-)
diff --git a/libcontainer/configs/config.go b/libcontainer/configs/config.go
index 98f4b85..af25972 100644
--- a/libcontainer/configs/config.go
+++ b/libcontainer/configs/config.go
@@ -259,8 +259,14 @@ func (hooks Hooks) MarshalJSON() ([]byte, error) {
})
}
+// Alias of specs.State
+type SpecState specs.State
+
// HookState is the payload provided to a hook on execution.
-type HookState specs.State
+type HookState struct {
+ SpecState
+ Root string `json:"root"`
+}
type Hook interface {
// Run executes the hook with the provided state.
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 173a3f0..ea6ef4c 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -275,10 +275,13 @@ func (c *linuxContainer) start(process *Process, isInit bool) error {
if c.config.Hooks != nil {
s := configs.HookState{
- Version: c.config.Version,
- ID: c.id,
- Pid: parent.pid(),
- Bundle: utils.SearchLabels(c.config.Labels, "bundle"),
+ SpecState: configs.SpecState{
+ Version: c.config.Version,
+ ID: c.id,
+ Pid: parent.pid(),
+ Bundle: utils.SearchLabels(c.config.Labels, "bundle"),
+ },
+ Root: c.config.Rootfs,
}
for i, hook := range c.config.Hooks.Poststart {
if err := hook.Run(s); err != nil {
@@ -1243,10 +1246,13 @@ func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Proc
case notify.GetScript() == "setup-namespaces":
if c.config.Hooks != nil {
s := configs.HookState{
- Version: c.config.Version,
- ID: c.id,
- Pid: int(notify.GetPid()),
- Bundle: utils.SearchLabels(c.config.Labels, "bundle"),
+ SpecState: configs.SpecState{
+ Version: c.config.Version,
+ ID: c.id,
+ Pid: int(notify.GetPid()),
+ Bundle: utils.SearchLabels(c.config.Labels, "bundle"),
+ },
+ Root: c.config.Rootfs,
}
for i, hook := range c.config.Hooks.Prestart {
if err := hook.Run(s); err != nil {
diff --git a/libcontainer/process_linux.go b/libcontainer/process_linux.go
index bfe9955..c9fb202 100644
--- a/libcontainer/process_linux.go
+++ b/libcontainer/process_linux.go
@@ -292,10 +292,13 @@ func (p *initProcess) start() error {
if !p.config.Config.Namespaces.Contains(configs.NEWNS) {
if p.config.Config.Hooks != nil {
s := configs.HookState{
- Version: p.container.config.Version,
- ID: p.container.id,
- Pid: p.pid(),
- Bundle: utils.SearchLabels(p.config.Config.Labels, "bundle"),
+ SpecState: configs.SpecState{
+ Version: p.container.config.Version,
+ ID: p.container.id,
+ Pid: p.pid(),
+ Bundle: utils.SearchLabels(p.config.Config.Labels, "bundle"),
+ },
+ Root: p.config.Config.Rootfs,
}
for i, hook := range p.config.Config.Hooks.Prestart {
if err := hook.Run(s); err != nil {
@@ -312,10 +315,13 @@ func (p *initProcess) start() error {
case procHooks:
if p.config.Config.Hooks != nil {
s := configs.HookState{
- Version: p.container.config.Version,
- ID: p.container.id,
- Pid: p.pid(),
- Bundle: utils.SearchLabels(p.config.Config.Labels, "bundle"),
+ SpecState: configs.SpecState{
+ Version: p.container.config.Version,
+ ID: p.container.id,
+ Pid: p.pid(),
+ Bundle: utils.SearchLabels(p.config.Config.Labels, "bundle"),
+ },
+ Root: p.config.Config.Rootfs,
}
for i, hook := range p.config.Config.Hooks.Prestart {
if err := hook.Run(s); err != nil {
diff --git a/libcontainer/state_linux.go b/libcontainer/state_linux.go
index 62878ac..9f8def2 100644
--- a/libcontainer/state_linux.go
+++ b/libcontainer/state_linux.go
@@ -58,9 +58,12 @@ func destroy(c *linuxContainer) error {
func runPoststopHooks(c *linuxContainer) error {
if c.config.Hooks != nil {
s := configs.HookState{
- Version: c.config.Version,
- ID: c.id,
- Bundle: utils.SearchLabels(c.config.Labels, "bundle"),
+ SpecState: configs.SpecState{
+ Version: c.config.Version,
+ ID: c.id,
+ Bundle: utils.SearchLabels(c.config.Labels, "bundle"),
+ },
+ Root: c.config.Rootfs,
}
for _, hook := range c.config.Hooks.Poststop {
if err := hook.Run(s); err != nil {
--
2.7.4.3

View File

@ -0,0 +1,208 @@
From 988554ab5c12971383bc717cda615ca672953cd5 Mon Sep 17 00:00:00 2001
From: yangshukui <yangshukui@huawei.com>
Date: Fri, 18 May 2018 11:03:48 +0800
Subject: [PATCH 36/94] runc-17: add compatibility for docker-1.11.2
[Changelog]: add compatibility for docker-1.11.2
[Author]: Shukui Yang
Change-Id: I188db47db8f4bcd744ac8218bfe966de48e97c22
Signed-off-by: yangshukui <yangshukui@huawei.com>
---
libcontainer/configs/cgroup_unix.go | 6 +++
libcontainer/configs/config.go | 11 ++++
libcontainer/container_linux.go | 6 +++
libcontainer/factory_linux.go | 102 +++++++++++++++++++++++++++++++-----
4 files changed, 113 insertions(+), 12 deletions(-)
diff --git a/libcontainer/configs/cgroup_unix.go b/libcontainer/configs/cgroup_unix.go
index e654960..75a3db0 100644
--- a/libcontainer/configs/cgroup_unix.go
+++ b/libcontainer/configs/cgroup_unix.go
@@ -33,6 +33,12 @@ type Cgroup struct {
*Resources
}
+// CompatCgroup
+type CompatCgroup struct {
+ Cgroup
+ MemorySwappiness interface{} `json:"memory_swappiness"`
+}
+
type Resources struct {
// If this is true allow access to any kind of device within the container. If false, allow access only to devices explicitly listed in the allowed_devices list.
// Deprecated
diff --git a/libcontainer/configs/config.go b/libcontainer/configs/config.go
index af25972..3a2e824 100644
--- a/libcontainer/configs/config.go
+++ b/libcontainer/configs/config.go
@@ -188,6 +188,17 @@ type Config struct {
Rootless bool `json:"rootless"`
}
+// CompatConfig is a structure inheriting from spec.Process defined
+// in runtime-spec/specs-go package. The goal is to be compatible with
+// both v1.0.0-rc4 and v1.0.0-rc5 since the latter introduced a change
+// about the type of the Capabilities field.
+// Refer to: https://github.com/opencontainers/runtime-spec/commit/37391fb
+type CompatConfig struct {
+ Config
+ Cgroups *CompatCgroup `json:"cgroups"`
+ Capabilities interface{} `json:"capabilities,omitempty" platform:"linux"`
+}
+
type Hooks struct {
// Prestart commands are executed after the container namespaces are created,
// but before the user supplied command is executed from init.
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index ea6ef4c..f4eec7e 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -66,6 +66,12 @@ type State struct {
ExternalDescriptors []string `json:"external_descriptors,omitempty"`
}
+// CompatState
+type CompatState struct{
+ State
+ Config configs.CompatConfig `json:"config"`
+}
+
// Container is a libcontainer container object.
//
// Each container is thread-safe within the same process. Since a container can
diff --git a/libcontainer/factory_linux.go b/libcontainer/factory_linux.go
index 8bf448a..b533346 100644
--- a/libcontainer/factory_linux.go
+++ b/libcontainer/factory_linux.go
@@ -10,8 +10,9 @@ import (
"regexp"
"runtime/debug"
"strconv"
- "strings"
"syscall"
+ "io/ioutil"
+ "errors"
"github.com/docker/docker/pkg/mount"
"github.com/opencontainers/runc/libcontainer/cgroups"
@@ -311,28 +312,105 @@ func (l *LinuxFactory) StartInitialization() (err error) {
return i.Init()
}
-func (l *LinuxFactory) loadState(root, id string) (*State, error) {
- f, err := os.Open(filepath.Join(root, stateFilename))
+func (l *LinuxFactory) updateStateCapabilites(compatState *CompatState, configPath string) error {
+ needUpdate := false
+
+ // In spec v1.0.0-rc4, capabilities was a list of strings. This was changed
+ // to an object with v1.0.0-rc5.
+ // Check for the interface type to support both the versions.
+ capabilities := compatState.Config.Capabilities
+ switch caps := capabilities.(type) {
+ case []interface{}:
+ var list []string
+ for _, str := range caps {
+ list = append(list, str.(string))
+ }
+
+ c := configs.Capabilities{
+ Bounding: list,
+ Effective: list,
+ Inheritable: list,
+ Ambient: list,
+ Permitted: list,
+ }
+ compatState.Config.Capabilities = c
+ needUpdate = true
+ }
+
+ //In spec v1.0.0-rc4, MemorySwappiness was a *int64. This was changed
+ // to an *uint64 with v1.0.0-rc5.
+ if compatState.Config.Cgroups != nil &&
+ compatState.Config.Cgroups.MemorySwappiness != nil {
+ memorySwappiness, ok := compatState.Config.Cgroups.MemorySwappiness.(float64)
+ if ok {
+ var memSize int64 = int64(memorySwappiness)
+ if memSize < 0 {
+ memSize = 0
+ var memUSize uint64 = uint64(memSize-1)
+ compatState.Config.Cgroups.MemorySwappiness = &memUSize
+ needUpdate = true
+ }
+ }
+ }
+
+ if needUpdate {
+ f, err := os.Create(configPath)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ if err := json.NewEncoder(f).Encode(&compatState); err != nil {
+ return err
+ }
+ return nil
+ }
+
+ return errors.New("updateStateCapabilites unexpected format for capabilities")
+}
+
+func (l *LinuxFactory) loadOriginState(configPath string) (*State, error) {
+ f, err := os.Open(configPath)
if err != nil {
if os.IsNotExist(err) {
- return nil, newGenericError(fmt.Errorf("container %q does not exist", id), ContainerNotExists)
+ return nil, newGenericError(err, ContainerNotExists)
}
return nil, newGenericError(err, SystemError)
}
defer f.Close()
var state *State
if err := json.NewDecoder(f).Decode(&state); err != nil {
- if !strings.Contains(err.Error(), "memory_swappiness") {
- return nil, newGenericError(err, SystemError)
- }
+ return nil, newGenericError(err, SystemError)
+ }
+ return state, nil
+}
- if state.BaseState.Config.Cgroups != nil &&
- state.BaseState.Config.Cgroups.Resources != nil &&
- state.BaseState.Config.Cgroups.Resources.MemorySwappiness != nil {
- memorySwappiness := int64(-1)
- *state.BaseState.Config.Cgroups.Resources.MemorySwappiness = uint64(memorySwappiness)
+func (l *LinuxFactory) loadCompatState(configPath string) (*State, error) {
+ dt, err := ioutil.ReadFile(configPath)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return nil, newGenericError(err, ContainerNotExists)
}
+ return nil, newGenericError(err, SystemError)
+ }
+ var state *CompatState
+ if err := json.Unmarshal(dt, &state); err != nil {
+ return nil, newGenericError(err, SystemError)
+ }
+
+ err = l.updateStateCapabilites(state, configPath)
+ if err != nil {
+ return nil, newGenericError(err, SystemError)
+ }
+
+ return l.loadOriginState(configPath)
+}
+
+func (l *LinuxFactory) loadState(root, id string) (*State, error) {
+ configPath := filepath.Join(root, stateFilename)
+ state, err := l.loadOriginState(configPath)
+ if err != nil {
+ return l.loadCompatState(configPath)
}
return state, nil
}
--
2.7.4.3

View File

@ -0,0 +1,61 @@
From 093594c58411b6a25844650b40463449e1af11ce Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Thu, 23 Aug 2018 15:03:50 +0800
Subject: [PATCH 37/94] docker: Don't enalbe kmem accounting by
default
reason:In kernel 3.10, kmem cgroup is unstable,
we should not enable kmem accounting by default.
Revert part of
https://github.com/hqhq/runc/commit/fe898e7862f945fa3632580139602c627dcb9be0
Change-Id: I546d1da875b1df7d525fd5c96a89c439ed6642f2
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
libcontainer/cgroups/fs/memory.go | 6 ++----
script/runc-euleros.spec | 8 ++++++--
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/libcontainer/cgroups/fs/memory.go b/libcontainer/cgroups/fs/memory.go
index c993839..118cce8 100644
--- a/libcontainer/cgroups/fs/memory.go
+++ b/libcontainer/cgroups/fs/memory.go
@@ -41,10 +41,8 @@ func (s *MemoryGroup) Apply(d *cgroupData) (err error) {
if err := os.MkdirAll(path, 0755); err != nil {
return err
}
- // Only enable kernel memory accouting when this cgroup
- // is created by libcontainer, otherwise we might get
- // error when people use `cgroupsPath` to join an existed
- // cgroup whose kernel memory is not initialized.
+ }
+ if d.config.KernelMemory != 0 {
if err := EnableKernelMemoryAccounting(path); err != nil {
return err
}
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index a925e02..c3db7c9 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 1%{?dist}
+Release: 2%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
@@ -46,4 +46,8 @@ install -p -m 755 runc $RPM_BUILD_ROOT/%{_bindir}/runc
%{_bindir}/runc
%changelog
-
+* Thu Aug 23 2018 lujingxiao<lujingxiao@huawei.com> - 1.0.0.rc3-2
+- Type:bugfix
+- ID:NA
+- SUG:NA
+- DESC:Don't enalbe kmem accounting by default
--
2.7.4.3

View File

@ -0,0 +1,64 @@
From 423ffe00c5c0cdb999bf9a193ad43ed5b6473a2d Mon Sep 17 00:00:00 2001
From: Wang Long <long.wanglong@huawei.com>
Date: Tue, 24 Jan 2017 18:51:22 +0800
Subject: [PATCH 39/94] Fix unittest and integration test error caused
by tty
Change-Id: Iae44f5a598e60b9e026ced99ca9e92aa90771fcc
Signed-off-by: Wang Long <long.wanglong@huawei.com>
---
libcontainer/integration/execin_test.go | 8 +-------
tests/integration/exec.bats | 4 ++--
2 files changed, 3 insertions(+), 9 deletions(-)
diff --git a/libcontainer/integration/execin_test.go b/libcontainer/integration/execin_test.go
index 019757f..f06075e 100644
--- a/libcontainer/integration/execin_test.go
+++ b/libcontainer/integration/execin_test.go
@@ -62,9 +62,6 @@ func TestExecIn(t *testing.T) {
if !strings.Contains(out, "cat") || !strings.Contains(out, "ps") {
t.Fatalf("unexpected running process, output %q", out)
}
- if strings.Contains(out, "\r") {
- t.Fatalf("unexpected carriage-return in output")
- }
}
func TestExecInUsernsRlimit(t *testing.T) {
@@ -327,12 +324,9 @@ func TestExecInTTY(t *testing.T) {
waitProcess(process, t)
out := stdout.String()
- if !strings.Contains(out, "cat") || !strings.Contains(out, "ps") {
+ if !strings.Contains(out, "cat") || !strings.Contains(string(out), "ps") {
t.Fatalf("unexpected running process, output %q", out)
}
- if strings.Contains(out, "\r") {
- t.Fatalf("unexpected carriage-return in output")
- }
}
func TestExecInEnvironment(t *testing.T) {
diff --git a/tests/integration/exec.bats b/tests/integration/exec.bats
index f172f9b..268a7e1 100644
--- a/tests/integration/exec.bats
+++ b/tests/integration/exec.bats
@@ -95,7 +95,7 @@ function teardown() {
runc exec --cwd /bin test_busybox pwd
[ "$status" -eq 0 ]
- [[ ${output} == "/bin" ]]
+ [[ $(echo "${output}" | tr -d '\r') == "/bin" ]]
}
@test "runc exec --env" {
@@ -124,5 +124,5 @@ function teardown() {
runc exec --user 1000:1000 test_busybox id
[ "$status" -eq 0 ]
- [[ ${output} == "uid=1000 gid=1000" ]]
+ [[ $(echo "${output}" | tr -d '\r') == "uid=1000 gid=1000" ]]
}
--
2.7.4.3

View File

@ -0,0 +1,68 @@
From a2f81f8b740b371e710b63b8c81c704842140ace Mon Sep 17 00:00:00 2001
From: yangshukui <yangshukui@huawei.com>
Date: Tue, 18 Apr 2017 19:35:30 +0800
Subject: [PATCH 41/94] Add timeout for syscall.Openat
Openat will be blocked until the fifo on the other side is opened, but in some
abnomal scenario(e.g. containerd is killed), Openat maybe be blocked all the time.
Change-Id: If1d514408b522c8bdf5f1c1cb0d3c625f0ef4a6d
Signed-off-by: yangshukui <yangshukui@huawei.com>
---
libcontainer/standard_init_linux.go | 30 ++++++++++++++++++++++++------
1 file changed, 24 insertions(+), 6 deletions(-)
diff --git a/libcontainer/standard_init_linux.go b/libcontainer/standard_init_linux.go
index ee6f19a..484ba42 100644
--- a/libcontainer/standard_init_linux.go
+++ b/libcontainer/standard_init_linux.go
@@ -7,6 +7,7 @@ import (
"os"
"os/exec"
"syscall"
+ "time"
"github.com/opencontainers/runc/libcontainer/apparmor"
"github.com/opencontainers/runc/libcontainer/configs"
@@ -166,15 +167,32 @@ func (l *linuxStandardInit) Init() error {
}
// close the pipe to signal that we have completed our init.
l.pipe.Close()
+
// wait for the fifo to be opened on the other side before
// exec'ing the users process.
- fd, err := syscall.Openat(l.stateDirFD, execFifoFilename, os.O_WRONLY|syscall.O_CLOEXEC, 0)
- if err != nil {
- return newSystemErrorWithCause(err, "openat exec fifo")
- }
- if _, err := syscall.Write(fd, []byte("0")); err != nil {
- return newSystemErrorWithCause(err, "write 0 exec fifo")
+ ch := make(chan Error, 1)
+ go func() {
+ fd, err := syscall.Openat(l.stateDirFD, execFifoFilename, os.O_WRONLY|syscall.O_CLOEXEC, 0)
+ if err != nil {
+ ch <- newSystemErrorWithCause(err, "openat exec fifo")
+ return
+ }
+ if _, err := syscall.Write(fd, []byte("0")); err != nil {
+ ch <- newSystemErrorWithCause(err, "write 0 exec fifo")
+ return
+ }
+ ch <- nil
+ }()
+
+ select {
+ case chErr := <-ch:
+ if chErr != nil {
+ return chErr
+ }
+ case <-time.After(120 * time.Second):
+ return newSystemErrorWithCause(fmt.Errorf("timeout"), "wait for the fifo to be opened on the other side ")
}
+
if l.config.Config.Seccomp != nil && l.config.NoNewPrivileges {
if err := seccomp.InitSeccomp(l.config.Config.Seccomp); err != nil {
return newSystemErrorWithCause(err, "init seccomp")
--
2.7.4.3

View File

@ -0,0 +1,46 @@
From 3b61668af89b820482b0a58f5af5316e1529116b Mon Sep 17 00:00:00 2001
From: Deng Guangxing <dengguangxing@huawei.com>
Date: Wed, 6 Sep 2017 15:04:47 +0800
Subject: [PATCH 42/94] update state earlier to avoid cgroup leak when
process failed
if process stuck in somewhere. upper caller like containerd may
have a timeout for process launching.
process will be killed after this timeout, and then call `runc
delete` to retrieve its resource like cgroup and perform poststop
hook.
if process got stuck right before updating state, and after cgroup
applied, like prestart-hook. In such case, `runc delete xxx` will
do nothing because state file is missing, runc is not aware of this
container. so process cgroup will stay and never get removed.
This patch perform state updating right after cgroup applying. so
`runc delete` will do the cleaning job
Change-Id: I7b247f501986e712a86da3958d1be573af4e84a6
Signed-off-by: Deng Guangxing <dengguangxing@huawei.com>
---
libcontainer/process_linux.go | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/libcontainer/process_linux.go b/libcontainer/process_linux.go
index c9fb202..9373595 100644
--- a/libcontainer/process_linux.go
+++ b/libcontainer/process_linux.go
@@ -260,6 +260,11 @@ func (p *initProcess) start() error {
if err := p.manager.Apply(p.pid()); err != nil {
return newSystemErrorWithCause(err, "applying cgroup configuration for process")
}
+ // update state here, so we can retrieve process resource
+ // even it get killed by accident
+ if _, err := p.container.updateState(p); err != nil {
+ return err
+ }
defer func() {
if err != nil {
// TODO: should not be the responsibility to call here
--
2.7.4.3

View File

@ -0,0 +1,43 @@
From 321679149dad13cdfd40831cc288495d4a5caf75 Mon Sep 17 00:00:00 2001
From: caihaomin <caihaomin@huawei.com>
Date: Fri, 15 Dec 2017 17:37:41 +0800
Subject: [PATCH 43/94] runc: Use rslave instead of rprivate in
chrootarchive
[Changelog]:With rprivate there exists a race where a reference to a mount has
propagated to the new namespace, when rprivate is set the parent
namespace is not able to remove the mount due to that reference.
With rslave unmounts will propagate correctly into the namespace and
prevent the sort of transient errors that are possible with rprivate.
https://github.com/moby/moby/pull/35217
[Author]git
Change-Id: I7a69a5b0c03e896b9cb1722eb676b7b84ea7dd77
Signed-off-by: caihaomin <caihaomin@huawei.com>
---
libcontainer/rootfs_linux.go | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go
index 1c93903..7cf5edd 100644
--- a/libcontainer/rootfs_linux.go
+++ b/libcontainer/rootfs_linux.go
@@ -668,9 +668,12 @@ func pivotRoot(rootfs string) error {
return err
}
- // Make oldroot rprivate to make sure our unmounts don't propagate to the
- // host (and thus bork the machine).
- if err := syscall.Mount("", ".", "", syscall.MS_PRIVATE|syscall.MS_REC, ""); err != nil {
+ // Make oldroot rslave to make sure our unmounts don't propagate to the
+ // host (and thus bork the machine). We don't use rprivate because this is
+ // known to cause issues due to races where we still have a reference to a
+ // mount while a process in the host namespace are trying to operate on
+ // something they think has no mounts (devicemapper in particular).
+ if err := syscall.Mount("", ".", "", syscall.MS_SLAVE|syscall.MS_REC, ""); err != nil {
return err
}
// Preform the unmount. MNT_DETACH allows us to unmount /proc/self/cwd.
--
2.7.4.3

View File

@ -0,0 +1,43 @@
From 06109d15b267af73d523817e6dcf501fa071a815 Mon Sep 17 00:00:00 2001
From: caihaomin <caihaomin@huawei.com>
Date: Fri, 15 Dec 2017 17:42:03 +0800
Subject: [PATCH 44/94] runc: default mount propagation correctly
[Changelog]:The code in prepareRoot
attempts to default the rootfs mount to `rslave`. However, since the spec
conversion has already defaulted it to `rprivate`, that code doesn't
actually ever do anything.
This changes the spec conversion code to accept "" and treat it as 0.
Implicitly, this makes rootfs propagation default to `rslave`, which is
a part of fixing the moby bug moby/moby#34672
Alternate implementatoins include changing this defaulting to be
`rslave` and removing the defaulting code in prepareRoot, or skipping
the mapping entirely for "", but I think this change is the cleanest of
those options.
[Author]git
Change-Id: I35954e2c8a71c1d3713753669044b5bf9d6c57fa
Signed-off-by: caihaomin <caihaomin@huawei.com>
---
libcontainer/specconv/spec_linux.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcontainer/specconv/spec_linux.go b/libcontainer/specconv/spec_linux.go
index 1575ae0..8a2947f 100644
--- a/libcontainer/specconv/spec_linux.go
+++ b/libcontainer/specconv/spec_linux.go
@@ -36,7 +36,7 @@ var mountPropagationMapping = map[string]int{
"slave": syscall.MS_SLAVE,
"rshared": syscall.MS_SHARED | syscall.MS_REC,
"shared": syscall.MS_SHARED,
- "": syscall.MS_PRIVATE | syscall.MS_REC,
+ "": 0,
}
var allowedDevices = []*configs.Device{
--
2.7.4.3

View File

@ -0,0 +1,128 @@
From eed1c5ec5166a151da33b7b9cfd6535f4556c015 Mon Sep 17 00:00:00 2001
From: dengguangxing <dengguangxing@huawei.com>
Date: Tue, 16 Jan 2018 18:00:56 +0800
Subject: [PATCH 45/94] runc: add hook specific info when error
occurred
[Changelog]: print hook path and args when hook failed to make debug
easier
[Author]:Shukui Yang
Change-Id: Idf704706b73f1cfa5f7f02b01b2ec58caadca79d
Signed-off-by: dengguangxing <dengguangxing@huawei.com>
---
libcontainer/configs/config.go | 10 ++++++++++
libcontainer/container_linux.go | 2 +-
libcontainer/factory_linux_test.go | 4 ++++
libcontainer/process_linux.go | 4 ++--
libcontainer/state_linux.go | 4 ++--
5 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/libcontainer/configs/config.go b/libcontainer/configs/config.go
index 3a2e824..49bc7a3 100644
--- a/libcontainer/configs/config.go
+++ b/libcontainer/configs/config.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"os/exec"
+ "strings"
"time"
"github.com/Sirupsen/logrus"
@@ -282,6 +283,7 @@ type HookState struct {
type Hook interface {
// Run executes the hook with the provided state.
Run(HookState) error
+ Info() string
}
// NewFunctionHook will call the provided function when the hook is run.
@@ -299,6 +301,10 @@ func (f FuncHook) Run(s HookState) error {
return f.run(s)
}
+func (f FuncHook) Info() string {
+ return "hook function"
+}
+
type Command struct {
Path string `json:"path"`
Args []string `json:"args"`
@@ -318,6 +324,10 @@ type CommandHook struct {
Command
}
+func (c Command) Info() string {
+ return c.Path + "," + strings.Join(c.Args, ",")
+}
+
func (c Command) Run(s HookState) error {
b, err := json.Marshal(s)
if err != nil {
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index f4eec7e..9fabadc 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -294,7 +294,7 @@ func (c *linuxContainer) start(process *Process, isInit bool) error {
if err := parent.terminate(); err != nil {
logrus.Warn(err)
}
- return newSystemErrorWithCausef(err, "running poststart hook %d", i)
+ return newSystemErrorWithCausef(err, "running poststart hook %d:%s", i, hook.Info())
}
}
}
diff --git a/libcontainer/factory_linux_test.go b/libcontainer/factory_linux_test.go
index ea3b513..0a84a7d 100644
--- a/libcontainer/factory_linux_test.go
+++ b/libcontainer/factory_linux_test.go
@@ -205,3 +205,7 @@ type unserializableHook struct{}
func (unserializableHook) Run(configs.HookState) error {
return nil
}
+
+func (unserializableHook) Info() string {
+ return ""
+}
diff --git a/libcontainer/process_linux.go b/libcontainer/process_linux.go
index 9373595..1b478d7 100644
--- a/libcontainer/process_linux.go
+++ b/libcontainer/process_linux.go
@@ -307,7 +307,7 @@ func (p *initProcess) start() error {
}
for i, hook := range p.config.Config.Hooks.Prestart {
if err := hook.Run(s); err != nil {
- return newSystemErrorWithCausef(err, "running prestart hook %d", i)
+ return newSystemErrorWithCausef(err, "running prestart hook %d:%s", i, hook.Info())
}
}
}
@@ -330,7 +330,7 @@ func (p *initProcess) start() error {
}
for i, hook := range p.config.Config.Hooks.Prestart {
if err := hook.Run(s); err != nil {
- return newSystemErrorWithCausef(err, "running prestart hook %d", i)
+ return newSystemErrorWithCausef(err, "running prestart hook %d:%s", i, hook.Info())
}
}
}
diff --git a/libcontainer/state_linux.go b/libcontainer/state_linux.go
index 9f8def2..c4f0dfc 100644
--- a/libcontainer/state_linux.go
+++ b/libcontainer/state_linux.go
@@ -65,9 +65,9 @@ func runPoststopHooks(c *linuxContainer) error {
},
Root: c.config.Rootfs,
}
- for _, hook := range c.config.Hooks.Poststop {
+ for i, hook := range c.config.Hooks.Poststop {
if err := hook.Run(s); err != nil {
- return err
+ return newSystemErrorWithCausef(err, "running poststop hook %d:%s", i, hook.Info())
}
}
}
--
2.7.4.3

View File

@ -0,0 +1,57 @@
From a410e6a2f9adeb46813a5016812ad334c6560b2d Mon Sep 17 00:00:00 2001
From: dengguangxing <dengguangxing@huawei.com>
Date: Thu, 18 Jan 2018 11:47:04 +0800
Subject: [PATCH 46/94] runc: print cgroup info if cpuset missing
occurs
[Changelog]: print cgroup info if cpuset missing occurs
[Author]:Shukui Yang
Change-Id: I3f8af2b57b441f5f2b4d38cb89d6826a7f24e24b
Signed-off-by: dengguangxing <dengguangxing@huawei.com>
---
libcontainer/cgroups/fs/cpuset.go | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/libcontainer/cgroups/fs/cpuset.go b/libcontainer/cgroups/fs/cpuset.go
index 918b9a3..069c491 100644
--- a/libcontainer/cgroups/fs/cpuset.go
+++ b/libcontainer/cgroups/fs/cpuset.go
@@ -9,6 +9,7 @@ import (
"os"
"path/filepath"
+ "github.com/Sirupsen/logrus"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs"
libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils"
@@ -91,6 +92,26 @@ func (s *CpusetGroup) ApplyDir(dir string, cgroup *configs.Cgroup, pid int) erro
}
func (s *CpusetGroup) getSubsystemSettings(parent string) (cpus []byte, mems []byte, err error) {
+ defer func() {
+ if err != nil {
+ minfo, err1 := ioutil.ReadFile("/proc/self/mountinfo")
+ if err1 != nil {
+ logrus.Errorf("Failed to read mountinfo when getSubsystemSettings get an error")
+ }
+
+ dirInfo := ""
+ fs, err2 := ioutil.ReadDir(parent)
+ if err2 != nil {
+ logrus.Errorf("Failed to read mountinfo when getSubsystemSettings get an error")
+ }
+ for _, f := range fs {
+ dirInfo = dirInfo + " " + f.Name()
+ }
+
+ logrus.Errorf("Read cpuset cgroup failed, print mountinfo and cgroup info here"+
+ "path: %s, mountinfo: [%s], dirinfo: [%s]", parent, string(minfo), dirInfo)
+ }
+ }()
if cpus, err = ioutil.ReadFile(filepath.Join(parent, "cpuset.cpus")); err != nil {
return
}
--
2.7.4.3

View File

@ -0,0 +1,104 @@
From f5399113b70807b57ed557bfecf932e5448016c2 Mon Sep 17 00:00:00 2001
From: dengguangxing <dengguangxing@huawei.com>
Date: Mon, 22 Jan 2018 20:27:37 +0800
Subject: [PATCH 47/94] runc: add more specific log for hooks
[Changelog]: add more specific log for hooks
[Author]:Shukui Yang
Change-Id: I317232b42a5fd6bc16773fe4aa0a376d8b9b6806
Signed-off-by: dengguangxing <dengguangxing@huawei.com>
---
libcontainer/container_linux.go | 5 +++++
libcontainer/process_linux.go | 5 +++++
libcontainer/state_linux.go | 3 +++
3 files changed, 13 insertions(+)
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 9fabadc..74b82c5 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -290,12 +290,15 @@ func (c *linuxContainer) start(process *Process, isInit bool) error {
Root: c.config.Rootfs,
}
for i, hook := range c.config.Hooks.Poststart {
+ logrus.Infof("run poststart hook %d:%s", i, hook.Info())
if err := hook.Run(s); err != nil {
+ logrus.Errorf("running poststart hook(%d:%s) failed: %s", i, hook.Info(), err)
if err := parent.terminate(); err != nil {
logrus.Warn(err)
}
return newSystemErrorWithCausef(err, "running poststart hook %d:%s", i, hook.Info())
}
+ logrus.Infof("poststart hook %d:%s done", i, hook.Info())
}
}
} else {
@@ -1261,9 +1264,11 @@ func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Proc
Root: c.config.Rootfs,
}
for i, hook := range c.config.Hooks.Prestart {
+ logrus.Infof("run prestart hook: %d:%s", i, hook.Info())
if err := hook.Run(s); err != nil {
return newSystemErrorWithCausef(err, "running prestart hook %d", i)
}
+ logrus.Infof("prestart hook: %d:%s done", i, hook.Info())
}
}
case notify.GetScript() == "post-restore":
diff --git a/libcontainer/process_linux.go b/libcontainer/process_linux.go
index 1b478d7..9064c0e 100644
--- a/libcontainer/process_linux.go
+++ b/libcontainer/process_linux.go
@@ -13,6 +13,7 @@ import (
"strconv"
"syscall"
+ "github.com/Sirupsen/logrus"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/system"
@@ -306,9 +307,11 @@ func (p *initProcess) start() error {
Root: p.config.Config.Rootfs,
}
for i, hook := range p.config.Config.Hooks.Prestart {
+ logrus.Infof("run prestart hook %d:%s", i, hook.Info())
if err := hook.Run(s); err != nil {
return newSystemErrorWithCausef(err, "running prestart hook %d:%s", i, hook.Info())
}
+ logrus.Infof("prestart hook %d:%s done", i, hook.Info())
}
}
}
@@ -329,9 +332,11 @@ func (p *initProcess) start() error {
Root: p.config.Config.Rootfs,
}
for i, hook := range p.config.Config.Hooks.Prestart {
+ logrus.Infof("run prestart hook %d:%s", i, hook.Info())
if err := hook.Run(s); err != nil {
return newSystemErrorWithCausef(err, "running prestart hook %d:%s", i, hook.Info())
}
+ logrus.Infof("prestart hook %d:%s done", i, hook.Info())
}
}
// Sync with child.
diff --git a/libcontainer/state_linux.go b/libcontainer/state_linux.go
index c4f0dfc..b8d2a87 100644
--- a/libcontainer/state_linux.go
+++ b/libcontainer/state_linux.go
@@ -66,9 +66,12 @@ func runPoststopHooks(c *linuxContainer) error {
Root: c.config.Rootfs,
}
for i, hook := range c.config.Hooks.Poststop {
+ logrus.Infof("run poststop hook %d:%s", i, hook.Info())
if err := hook.Run(s); err != nil {
+ logrus.Errorf("running poststop hook %d: %s failed: %s", i, hook.Info(), err)
return newSystemErrorWithCausef(err, "running poststop hook %d:%s", i, hook.Info())
}
+ logrus.Infof("poststop hook %d:%s done", i, hook.Info())
}
}
return nil
--
2.7.4.3

View File

@ -0,0 +1,40 @@
From caeb202a8a95863a44fa8f45e0515437239b173c Mon Sep 17 00:00:00 2001
From: dengguangxing <dengguangxing@huawei.com>
Date: Wed, 16 May 2018 15:16:51 +0800
Subject: [PATCH 48/94] runc: Only configure networking
[Changelog]: Only configure networking when creating a net ns
When joining an existing namespace, don't default to configuring a
loopback interface in that namespace.
Its creator should have done that, and we don't want to fail to create
the container when we don't have sufficient privileges to configure the
network namespace.
This is cherry-picked from runc upstream:
https://github.com/opencontainers/runc/pull/1777
[Author]:Shukui Yang
Change-Id: I1f181f18e23c621db6718a185e35b50531d27c09
Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
Signed-off-by: dengguangxing <dengguangxing@huawei.com>
---
libcontainer/specconv/spec_linux.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcontainer/specconv/spec_linux.go b/libcontainer/specconv/spec_linux.go
index 8a2947f..a968313 100644
--- a/libcontainer/specconv/spec_linux.go
+++ b/libcontainer/specconv/spec_linux.go
@@ -194,7 +194,7 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
}
config.Namespaces.Add(t, ns.Path)
}
- if config.Namespaces.Contains(configs.NEWNET) {
+ if config.Namespaces.Contains(configs.NEWNET) && config.Namespaces.PathOf(configs.NEWNET) == "" {
config.Networks = []*configs.Network{
{
Type: "loopback",
--
2.7.4.3

View File

@ -0,0 +1,37 @@
From ee3660e477b70d73812390ad96d82681f82f2e9b Mon Sep 17 00:00:00 2001
From: Denys Smirnov <denys@sourced.tech>
Date: Tue, 6 Mar 2018 23:31:31 +0100
Subject: [PATCH 49/94] cgroups/fs: fix NPE on Destroy than no
cgroups are set
[Changelog]: Currently Manager accepts nil cgroups when calling Apply, but
it will panic then trying to call Destroy with the same config.
This is cherry-picked from runc upstream:
https://github.com/opencontainers/runc/pull/1752
[Author]:Shukui Yang
Change-Id: Ie7aba1d1b7086a82a1d186038fb5e6c09b617f75
Signed-off-by: Denys Smirnov <denys@sourced.tech>
Signed-off-by: dengguangxing <dengguangxing@huawei.com>
---
libcontainer/cgroups/fs/apply_raw.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcontainer/cgroups/fs/apply_raw.go b/libcontainer/cgroups/fs/apply_raw.go
index 22d82ac..66debae 100644
--- a/libcontainer/cgroups/fs/apply_raw.go
+++ b/libcontainer/cgroups/fs/apply_raw.go
@@ -152,7 +152,7 @@ func (m *Manager) Apply(pid int) (err error) {
}
func (m *Manager) Destroy() error {
- if m.Cgroups.Paths != nil {
+ if m.Cgroups == nil || m.Cgroups.Paths != nil {
return nil
}
m.mu.Lock()
--
2.7.4.3

View File

@ -0,0 +1,214 @@
From 7e65e11136e81a834effe40a9f926416fb1eea78 Mon Sep 17 00:00:00 2001
From: Will Martin <wmartin@pivotal.io>
Date: Mon, 22 Jan 2018 17:03:02 +0000
Subject: [PATCH 50/94] runc: Avoid race when opening exec fifo
[Changelog]: Avoid race when opening exec fifo
When starting a container with `runc start` or `runc run`, the stub
process (runc[2:INIT]) opens a fifo for writing. Its parent runc process
will open the same fifo for reading. In this way, they synchronize.
If the stub process exits at the wrong time, the parent runc process
will block forever.
This can happen when racing 2 runc operations against each other: `runc
run/start`, and `runc delete`. It could also happen for other reasons,
e.g. the kernel's OOM killer may select the stub process.
This commit resolves this race by racing the opening of the exec fifo
from the runc parent process against the stub process exiting. If the
stub process exits before we open the fifo, we return an error.
Another solution is to wait on the stub process. However, it seems it
would require more refactoring to avoid calling wait multiple times on
the same process, which is an error.
This is cherry-picked from runc upstream:
https://github.com/opencontainers/runc/pull/1698
[Author]:Shukui Yang
Change-Id: Id0ba756349b59463f7ee19ad63a6f243bee4a729
Signed-off-by: Craig Furman <cfurman@pivotal.io>
Signed-off-by: dengguangxing <dengguangxing@huawei.com>
---
libcontainer/container_linux.go | 69 +++++++++++++++++++++++++++++++++++------
libcontainer/system/proc.go | 59 +++++++++++++++++++++++++++++++++++
2 files changed, 119 insertions(+), 9 deletions(-)
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 74b82c5..278f597 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -5,6 +5,7 @@ package libcontainer
import (
"bytes"
"encoding/json"
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -239,20 +240,70 @@ func (c *linuxContainer) Exec() error {
func (c *linuxContainer) exec() error {
path := filepath.Join(c.root, execFifoFilename)
- f, err := os.OpenFile(path, os.O_RDONLY, 0)
- if err != nil {
- return newSystemErrorWithCause(err, "open exec fifo for reading")
+
+ fifoOpen := make(chan struct{})
+ select {
+ case <-awaitProcessExit(c.initProcess.pid(), fifoOpen):
+ return errors.New("container process is already dead")
+ case result := <-awaitFifoOpen(path):
+ close(fifoOpen)
+ if result.err != nil {
+ return result.err
+ }
+ f := result.file
+ defer f.Close()
+ if err := readFromExecFifo(f); err != nil {
+ return err
+ }
+ return os.Remove(path)
}
- defer f.Close()
- data, err := ioutil.ReadAll(f)
+}
+
+func readFromExecFifo(execFifo io.Reader) error {
+ data, err := ioutil.ReadAll(execFifo)
if err != nil {
return err
}
- if len(data) > 0 {
- os.Remove(path)
- return nil
+ if len(data) <= 0 {
+ return fmt.Errorf("cannot start an already running container")
}
- return fmt.Errorf("cannot start an already running container")
+ return nil
+}
+
+func awaitProcessExit(pid int, exit <-chan struct{}) <-chan struct{} {
+ isDead := make(chan struct{})
+ go func() {
+ for {
+ select {
+ case <-exit:
+ return
+ case <-time.After(time.Millisecond * 100):
+ stat, err := system.GetProcessState(pid)
+ if err != nil || stat == system.Zombie {
+ close(isDead)
+ return
+ }
+ }
+ }
+ }()
+ return isDead
+}
+
+func awaitFifoOpen(path string) <-chan openResult {
+ fifoOpened := make(chan openResult)
+ go func() {
+ f, err := os.OpenFile(path, os.O_RDONLY, 0)
+ if err != nil {
+ fifoOpened <- openResult{err: newSystemErrorWithCause(err, "open exec fifo for reading")}
+ }
+ fifoOpened <- openResult{file: f}
+ }()
+ return fifoOpened
+}
+
+type openResult struct {
+ file *os.File
+ err error
}
func (c *linuxContainer) start(process *Process, isInit bool) error {
diff --git a/libcontainer/system/proc.go b/libcontainer/system/proc.go
index a0e9637..03fd940 100644
--- a/libcontainer/system/proc.go
+++ b/libcontainer/system/proc.go
@@ -1,12 +1,48 @@
package system
import (
+ "fmt"
"io/ioutil"
"path/filepath"
"strconv"
"strings"
)
+type State rune
+
+const ( // Only values for Linux 3.14 and later are listed here
+ Dead State = 'X'
+ DiskSleep State = 'D'
+ Running State = 'R'
+ Sleeping State = 'S'
+ Stopped State = 'T'
+ TracingStop State = 't'
+ Zombie State = 'Z'
+)
+
+// String forms of the state from proc(5)'s documentation for
+// /proc/[pid]/status' "State" field.
+func (s State) String() string {
+ switch s {
+ case Dead:
+ return "dead"
+ case DiskSleep:
+ return "disk sleep"
+ case Running:
+ return "running"
+ case Sleeping:
+ return "sleeping"
+ case Stopped:
+ return "stopped"
+ case TracingStop:
+ return "tracing stop"
+ case Zombie:
+ return "zombie"
+ default:
+ return fmt.Sprintf("unknown (%c)", s)
+ }
+}
+
// look in /proc to find the process start time so that we can verify
// that this pid has started after ourself
func GetProcessStartTime(pid int) (string, error) {
@@ -41,3 +77,26 @@ func parseStartTime(stat string) (string, error) {
parts := strings.Split(strings.TrimSpace(s[len(s)-1]), " ")
return parts[22-3], nil // starts at 3 (after the filename pos `2`)
}
+
+func GetProcessState(pid int) (State, error) {
+ data, err := ioutil.ReadFile(filepath.Join("/proc", strconv.Itoa(pid), "stat"))
+ if err != nil {
+ return State(0), err
+ }
+ return parseState(string(data))
+
+}
+
+func parseState(data string) (State, error) {
+ i := strings.LastIndex(data, ")")
+ if i <= 2 || i >= len(data)-3 {
+ return State(0), fmt.Errorf("invalid stat data: %q", data)
+ }
+
+ parts := strings.Split(data[i+2:], " ")
+
+ var state int
+ fmt.Sscanf(parts[3-3], "%c", &state)
+ stateStr := State(state)
+ return stateStr, nil
+}
--
2.7.4.3

View File

@ -0,0 +1,33 @@
From df24ec79d3a69e9deab962eacc8ecbd46b0aefd9 Mon Sep 17 00:00:00 2001
From: Ed King <eking@pivotal.io>
Date: Tue, 23 Jan 2018 10:46:31 +0000
Subject: [PATCH 51/94] runc: Return from goroutine when it should
terminate
[Changelog]: This is cherry-picked from runc upstream:
https://github.com/opencontainers/runc/pull/1698
[Author]:Shukui Yang
Change-Id: Ie99f80c1fb5912d99dd7426b47f93e9f5a6efb23
Signed-off-by: Craig Furman <cfurman@pivotal.io>
Signed-off-by: dengguangxing <dengguangxing@huawei.com>
---
libcontainer/container_linux.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 278f597..50fe657 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -295,6 +295,7 @@ func awaitFifoOpen(path string) <-chan openResult {
f, err := os.OpenFile(path, os.O_RDONLY, 0)
if err != nil {
fifoOpened <- openResult{err: newSystemErrorWithCause(err, "open exec fifo for reading")}
+ return
}
fifoOpened <- openResult{file: f}
}()
--
2.7.4.3

View File

@ -0,0 +1,32 @@
From c8b74f1b809d8fbf1ba2dc74c069e03d9e95be71 Mon Sep 17 00:00:00 2001
From: liruilin4 <liruilin4@huawei.com>
Date: Mon, 9 Jul 2018 12:02:33 +0800
Subject: [PATCH 52/94] runc: reduce max number of retries to 10
[Changelog]:when killing containers in D state, now runc will do
100 retries, which leads that containerd blocks for 10 seconds.
[Author]:Ruilin Li
Change-Id: I1e08ef23ad065f5e3b88506726530187d2ccc797
---
delete.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/delete.go b/delete.go
index b43dcaa..a2b14f3 100644
--- a/delete.go
+++ b/delete.go
@@ -14,8 +14,8 @@ import (
)
func killContainer(container libcontainer.Container) error {
- _ = container.Signal(syscall.SIGKILL, false)
- for i := 0; i < 100; i++ {
+ container.Signal(syscall.SIGKILL, false)
+ for i := 0; i < 10; i++ {
time.Sleep(100 * time.Millisecond)
if err := container.Signal(syscall.Signal(0), false); err != nil {
destroy(container)
--
2.7.4.3

View File

@ -0,0 +1,36 @@
From 165870fb442ca29a208a3d17f8ece6b8e74da2de Mon Sep 17 00:00:00 2001
From: panwenxiang <panwenxiang@huawei.com>
Date: Wed, 22 Aug 2018 17:04:19 +0800
Subject: [PATCH 53/94] runc: print error message during start into
container log
[Changelog]:cherry-pick from vtwrse <75eba7a697edde39e25e39c870a33f3dc5fb327a>
Change-Id: Id23f14690d77a4f79611e82f4e2ece41d9b19edf
Signed-off-by: jiangpengfei9 <jiangpengfei9@huawei.com>
---
main_unix.go | 2 ++
1 file changed, 2 insertions(+)
diff --git a/main_unix.go b/main_unix.go
index b601abc..56904e0 100644
--- a/main_unix.go
+++ b/main_unix.go
@@ -3,6 +3,7 @@
package main
import (
+ "fmt"
"os"
"runtime"
@@ -24,6 +25,7 @@ var initCommand = cli.Command{
Action: func(context *cli.Context) error {
factory, _ := libcontainer.New("")
if err := factory.StartInitialization(); err != nil {
+ fmt.Fprintf(os.Stderr, "libcontainer: container start initialization failed: %s", err)
// as the error is sent back to the parent there is no need to log
// or write it to stderr because the parent process will handle this
os.Exit(1)
--
2.7.4.3

View File

@ -0,0 +1,31 @@
From a119a29bc908bfd1385cbdcee4cc800e2b022b09 Mon Sep 17 00:00:00 2001
From: panwenxiang <panwenxiang@huawei.com>
Date: Wed, 22 Aug 2018 17:06:01 +0800
Subject: [PATCH 54/94] runc: ignore exec.fifo removing not exist error
[Changelog]:cherry-pick from vtwrse <4af7ee1635962fe3bd86ac87064fdcd7e60c1135>
Change-Id: I34a30672fb92c974965b3a53cfb8ccc75932e6d8
Signed-off-by: jiangpengfei9 <jiangpengfei9@huawei.com>
---
libcontainer/container_linux.go | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 50fe657..502a274 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -255,7 +255,10 @@ func (c *linuxContainer) exec() error {
if err := readFromExecFifo(f); err != nil {
return err
}
- return os.Remove(path)
+ if err := os.Remove(path); !os.IsNotExist(err) {
+ return err
+ }
+ return nil
}
}
--
2.7.4.3

View File

@ -0,0 +1,246 @@
From fdf82f9b9bac43cac5672226750c826e742559ce Mon Sep 17 00:00:00 2001
From: yangshukui <yangshukui@huawei.com>
Date: Mon, 18 Sep 2017 17:25:30 +0800
Subject: [PATCH 55/94] Add file fds limit
With the patch(https://lwn.net/Articles/604129/),we can limit the
num of open files in container.
Conflicts:
events.go
vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
Change-Id: I8264c0dd398227ebbd95b7dd9dae4688d76dee9b
Signed-off-by: yangshukui <yangshukui@huawei.com>
---
events.go | 9 +++
libcontainer/cgroups/fs/apply_raw.go | 1 +
libcontainer/cgroups/fs/files.go | 74 ++++++++++++++++++++++
libcontainer/cgroups/stats.go | 8 +++
libcontainer/cgroups/systemd/apply_systemd.go | 1 +
libcontainer/configs/cgroup_unix.go | 3 +
libcontainer/specconv/spec_linux.go | 3 +
.../opencontainers/runtime-spec/specs-go/config.go | 8 +++
8 files changed, 107 insertions(+)
create mode 100644 libcontainer/cgroups/fs/files.go
diff --git a/events.go b/events.go
index 6c21e52..79a72bf 100644
--- a/events.go
+++ b/events.go
@@ -27,6 +27,7 @@ type stats struct {
CPU cpu `json:"cpu"`
Memory memory `json:"memory"`
Pids pids `json:"pids"`
+ Files files `json:"files"`
Blkio blkio `json:"blkio"`
Hugetlb map[string]hugetlb `json:"hugetlb"`
}
@@ -60,6 +61,11 @@ type pids struct {
Limit uint64 `json:"limit,omitempty"`
}
+type files struct {
+ Usage uint64 `json:"usage,omitempty"`
+ Limit uint64 `json:"limit,omitempty"`
+}
+
type throttling struct {
Periods uint64 `json:"periods,omitempty"`
ThrottledPeriods uint64 `json:"throttledPeriods,omitempty"`
@@ -198,6 +204,9 @@ func convertLibcontainerStats(ls *libcontainer.Stats) *stats {
s.Pids.Current = cg.PidsStats.Current
s.Pids.Limit = cg.PidsStats.Limit
+ s.Files.Usage = cg.FilesStats.Usage
+ s.Files.Limit = cg.FilesStats.Limit
+
s.CPU.Usage.Kernel = cg.CpuStats.CpuUsage.UsageInKernelmode
s.CPU.Usage.User = cg.CpuStats.CpuUsage.UsageInUsermode
s.CPU.Usage.Total = cg.CpuStats.CpuUsage.TotalUsage
diff --git a/libcontainer/cgroups/fs/apply_raw.go b/libcontainer/cgroups/fs/apply_raw.go
index 66debae..1bf59a4 100644
--- a/libcontainer/cgroups/fs/apply_raw.go
+++ b/libcontainer/cgroups/fs/apply_raw.go
@@ -24,6 +24,7 @@ var (
&CpuGroup{},
&CpuacctGroup{},
&PidsGroup{},
+ &FilesGroup{},
&BlkioGroup{},
&HugetlbGroup{},
&NetClsGroup{},
diff --git a/libcontainer/cgroups/fs/files.go b/libcontainer/cgroups/fs/files.go
new file mode 100644
index 0000000..f2e253a
--- /dev/null
+++ b/libcontainer/cgroups/fs/files.go
@@ -0,0 +1,74 @@
+// +build linux
+
+package fs
+
+import (
+ "fmt"
+ "io/ioutil"
+ "strconv"
+
+ "github.com/opencontainers/runc/libcontainer/cgroups"
+ "github.com/opencontainers/runc/libcontainer/configs"
+)
+
+var (
+ defaultFilesMax = "8192"
+)
+
+type FilesGroup struct {
+}
+
+func init() {
+ contents, err := ioutil.ReadFile("/proc/sys/fs/file-max")
+ if err != nil {
+ return
+ }
+ defaultFilesMax = string(contents)
+}
+
+func (s *FilesGroup) Name() string {
+ return "files"
+}
+
+func (s *FilesGroup) Apply(d *cgroupData) error {
+ _, err := d.join("files")
+ if err != nil && !cgroups.IsNotFound(err) {
+ return err
+ }
+ return nil
+}
+
+func (s *FilesGroup) Set(path string, cgroup *configs.Cgroup) error {
+ if cgroup.Resources.FilesLimit != 0 {
+ limit := defaultFilesMax
+ if cgroup.Resources.FilesLimit > 0 {
+ limit = strconv.FormatInt(cgroup.Resources.FilesLimit, 10)
+ }
+
+ if err := writeFile(path, "files.limit", limit); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (s *FilesGroup) Remove(d *cgroupData) error {
+ return removePath(d.path("files"))
+}
+
+func (s *FilesGroup) GetStats(path string, stats *cgroups.Stats) error {
+ usage, err := getCgroupParamUint(path, "files.usage")
+ if err != nil {
+ return fmt.Errorf("failed to parse files.usage - %s", err)
+ }
+
+ limit, err := getCgroupParamUint(path, "files.limit")
+ if err != nil {
+ return fmt.Errorf("failed to parse files.limit - %s", err)
+ }
+
+ stats.FilesStats.Usage = usage
+ stats.FilesStats.Limit = limit
+ return nil
+}
diff --git a/libcontainer/cgroups/stats.go b/libcontainer/cgroups/stats.go
index b483f1b..5079410 100644
--- a/libcontainer/cgroups/stats.go
+++ b/libcontainer/cgroups/stats.go
@@ -62,6 +62,13 @@ type PidsStats struct {
Limit uint64 `json:"limit,omitempty"`
}
+type FilesStats struct {
+ // number of pids in the cgroup
+ Usage uint64 `json:"usage,omitempty"`
+ // active pids hard limit
+ Limit uint64 `json:"limit,omitempty"`
+}
+
type BlkioStatEntry struct {
Major uint64 `json:"major,omitempty"`
Minor uint64 `json:"minor,omitempty"`
@@ -94,6 +101,7 @@ type Stats struct {
CpuStats CpuStats `json:"cpu_stats,omitempty"`
MemoryStats MemoryStats `json:"memory_stats,omitempty"`
PidsStats PidsStats `json:"pids_stats,omitempty"`
+ FilesStats FilesStats `json:"files_stats,omitempty"`
BlkioStats BlkioStats `json:"blkio_stats,omitempty"`
// the map is in the format "size of hugepage: stats of the hugepage"
HugetlbStats map[string]HugetlbStats `json:"hugetlb_stats,omitempty"`
diff --git a/libcontainer/cgroups/systemd/apply_systemd.go b/libcontainer/cgroups/systemd/apply_systemd.go
index 456c57d..0411b72 100644
--- a/libcontainer/cgroups/systemd/apply_systemd.go
+++ b/libcontainer/cgroups/systemd/apply_systemd.go
@@ -54,6 +54,7 @@ var subsystems = subsystemSet{
&fs.CpuGroup{},
&fs.CpuacctGroup{},
&fs.PidsGroup{},
+ &fs.FilesGroup{},
&fs.BlkioGroup{},
&fs.HugetlbGroup{},
&fs.PerfEventGroup{},
diff --git a/libcontainer/configs/cgroup_unix.go b/libcontainer/configs/cgroup_unix.go
index 75a3db0..acf0562 100644
--- a/libcontainer/configs/cgroup_unix.go
+++ b/libcontainer/configs/cgroup_unix.go
@@ -89,6 +89,9 @@ type Resources struct {
// Process limit; set <= `0' to disable limit.
PidsLimit int64 `json:"pids_limit"`
+ // Process open files limit.
+ FilesLimit int64 `json:"files_limit"`
+
// Specifies per cgroup weight, range is from 10 to 1000.
BlkioWeight uint16 `json:"blkio_weight"`
diff --git a/libcontainer/specconv/spec_linux.go b/libcontainer/specconv/spec_linux.go
index a968313..b82082e 100644
--- a/libcontainer/specconv/spec_linux.go
+++ b/libcontainer/specconv/spec_linux.go
@@ -403,6 +403,9 @@ func createCgroupConfig(opts *CreateOpts) (*configs.Cgroup, error) {
if r.Pids != nil {
c.Resources.PidsLimit = r.Pids.Limit
}
+ if r.Files != nil && r.Files.Limit != nil {
+ c.Resources.FilesLimit = *r.Files.Limit
+ }
if r.BlockIO != nil {
if r.BlockIO.Weight != nil {
c.Resources.BlkioWeight = *r.BlockIO.Weight
diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
index 6d2a026..603ecf4 100644
--- a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
+++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
@@ -318,6 +318,12 @@ type LinuxPids struct {
Limit int64 `json:"limit"`
}
+// Files for Linux cgroup 'files' resource management (https://lwn.net/Articles/604129/)
+type Files struct {
+ // Maximum number of open files".
+ Limit *int64 `json:"limit,omitempty"`
+}
+
// LinuxNetwork identification and priority configuration
type LinuxNetwork struct {
// Set class identifier for container's network packets
@@ -340,6 +346,8 @@ type LinuxResources struct {
CPU *LinuxCPU `json:"cpu,omitempty"`
// Task resource restriction configuration.
Pids *LinuxPids `json:"pids,omitempty"`
+ // Files resource restriction configuration.
+ Files *Files `json:"files,omitempty"`
// BlockIO restriction configuration
BlockIO *LinuxBlockIO `json:"blockIO,omitempty"`
// Hugetlb limit (in bytes)
--
2.7.4.3

View File

@ -0,0 +1,61 @@
From 0a5b23584d79bba18429905c43774bc50a117b4b Mon Sep 17 00:00:00 2001
From: yangshukui <yangshukui@huawei.com>
Date: Sat, 4 Nov 2017 14:55:40 +0800
Subject: [PATCH 56/94] runc: Modify max files.limit to max because of
the change of kernel.
[Changelog]: Kernel has change max files.limit to max,So docker need
change too.
Change-Id: Iea6e5eb1dddf0f8d2d55ee3182ed78957cb09a75
Signed-off-by: yangshukui <yangshukui@huawei.com>
---
libcontainer/cgroups/fs/files.go | 16 ++--------------
1 file changed, 2 insertions(+), 14 deletions(-)
diff --git a/libcontainer/cgroups/fs/files.go b/libcontainer/cgroups/fs/files.go
index f2e253a..3214a82 100644
--- a/libcontainer/cgroups/fs/files.go
+++ b/libcontainer/cgroups/fs/files.go
@@ -4,28 +4,15 @@ package fs
import (
"fmt"
- "io/ioutil"
"strconv"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs"
)
-var (
- defaultFilesMax = "8192"
-)
-
type FilesGroup struct {
}
-func init() {
- contents, err := ioutil.ReadFile("/proc/sys/fs/file-max")
- if err != nil {
- return
- }
- defaultFilesMax = string(contents)
-}
-
func (s *FilesGroup) Name() string {
return "files"
}
@@ -40,7 +27,8 @@ func (s *FilesGroup) Apply(d *cgroupData) error {
func (s *FilesGroup) Set(path string, cgroup *configs.Cgroup) error {
if cgroup.Resources.FilesLimit != 0 {
- limit := defaultFilesMax
+ // "max" is the fallback value.
+ limit := "max"
if cgroup.Resources.FilesLimit > 0 {
limit = strconv.FormatInt(cgroup.Resources.FilesLimit, 10)
}
--
2.7.4.3

View File

@ -0,0 +1,55 @@
From aff98c05dbaf30fec52a0afed19ebf4a03303d63 Mon Sep 17 00:00:00 2001
From: caihaomin <caihaomin@huawei.com>
Date: Mon, 6 Nov 2017 01:43:45 +0000
Subject: [PATCH 57/94] runc: change read value of cgroup files.limit
into string
[Changelog]:change read value of cgroup files.limit from int to string.
For avoiding of value `max`
[Author]git
Change-Id: Iec6197528b1aebb13a0ea64ba919a7b4c6f31d61
Signed-off-by: caihaomin <caihaomin@huawei.com>
---
libcontainer/cgroups/fs/files.go | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/libcontainer/cgroups/fs/files.go b/libcontainer/cgroups/fs/files.go
index 3214a82..70e9524 100644
--- a/libcontainer/cgroups/fs/files.go
+++ b/libcontainer/cgroups/fs/files.go
@@ -8,6 +8,7 @@ import (
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs"
+ "path/filepath"
)
type FilesGroup struct {
@@ -51,12 +52,21 @@ func (s *FilesGroup) GetStats(path string, stats *cgroups.Stats) error {
return fmt.Errorf("failed to parse files.usage - %s", err)
}
- limit, err := getCgroupParamUint(path, "files.limit")
+ maxString, err := getCgroupParamString(path, "files.limit")
if err != nil {
return fmt.Errorf("failed to parse files.limit - %s", err)
}
+ // Default if files.limit == "max" is 0 -- which represents "no limit".
+ var max uint64
+ if maxString != "max" {
+ max, err = parseUint(maxString, 10, 64)
+ if err != nil {
+ return fmt.Errorf("failed to parse files.limit -- unable to parse %q as a uint from Cgroup file %q", maxString, filepath.Join(path, "file.limits"))
+ }
+ }
+
stats.FilesStats.Usage = usage
- stats.FilesStats.Limit = limit
+ stats.FilesStats.Limit = max
return nil
}
--
2.7.4.3

View File

@ -0,0 +1,194 @@
From 20e119ab64e02e627671957bbfa445b988cc8687 Mon Sep 17 00:00:00 2001
From: dengguangxing <dengguangxing@huawei.com>
Date: Wed, 16 May 2018 15:50:27 +0800
Subject: [PATCH 58/94] runc: fix panic when Linux is nil
[Changelog]: Linux is not always not nil.
If Linux is nil, panic will occur.
This is cherry-picked from runc upstream:
https://github.com/opencontainers/runc/pull/1551
[Author]:Shukui Yang
Conflicts:
libcontainer/specconv/spec_linux.go
Change-Id: Ib3bf9e80852dc079ab2d42a8234297397f3c56d9
Signed-off-by: Ma Shimiao <mashimiao.fnst@cn.fujitsu.com>
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
Signed-off-by: dengguangxing <dengguangxing@huawei.com>
---
libcontainer/specconv/spec_linux.go | 121 +++++++++++++++++++-----------------
1 file changed, 65 insertions(+), 56 deletions(-)
diff --git a/libcontainer/specconv/spec_linux.go b/libcontainer/specconv/spec_linux.go
index b82082e..a8cf114 100644
--- a/libcontainer/specconv/spec_linux.go
+++ b/libcontainer/specconv/spec_linux.go
@@ -180,20 +180,6 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
}
exists := false
- if config.RootPropagation, exists = mountPropagationMapping[spec.Linux.RootfsPropagation]; !exists {
- return nil, fmt.Errorf("rootfsPropagation=%v is not supported", spec.Linux.RootfsPropagation)
- }
-
- for _, ns := range spec.Linux.Namespaces {
- t, exists := namespaceMapping[ns.Type]
- if !exists {
- return nil, fmt.Errorf("namespace %q does not exist", ns)
- }
- if config.Namespaces.Contains(t) {
- return nil, fmt.Errorf("malformed spec file: duplicated ns %q", ns)
- }
- config.Namespaces.Add(t, ns.Path)
- }
if config.Namespaces.Contains(configs.NEWNET) && config.Namespaces.PathOf(configs.NEWNET) == "" {
config.Networks = []*configs.Network{
{
@@ -215,15 +201,35 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
return nil, err
}
config.Cgroups = c
- // set extra path masking for libcontainer for the various unsafe places in proc
- config.MaskPaths = spec.Linux.MaskedPaths
- config.ReadonlyPaths = spec.Linux.ReadonlyPaths
- if spec.Linux.Seccomp != nil {
- seccomp, err := setupSeccomp(spec.Linux.Seccomp)
- if err != nil {
- return nil, err
+ // set linux-specific config
+ if spec.Linux != nil {
+ if config.RootPropagation, exists = mountPropagationMapping[spec.Linux.RootfsPropagation]; !exists {
+ return nil, fmt.Errorf("rootfsPropagation=%v is not supported", spec.Linux.RootfsPropagation)
+ }
+
+ for _, ns := range spec.Linux.Namespaces {
+ t, exists := namespaceMapping[ns.Type]
+ if !exists {
+ return nil, fmt.Errorf("namespace %q does not exist", ns)
+ }
+ if config.Namespaces.Contains(t) {
+ return nil, fmt.Errorf("malformed spec file: duplicated ns %q", ns)
+ }
+ config.Namespaces.Add(t, ns.Path)
+ }
+
+ // set extra path masking for libcontainer for the various unsafe places in proc
+ config.MaskPaths = spec.Linux.MaskedPaths
+ config.ReadonlyPaths = spec.Linux.ReadonlyPaths
+ config.MountLabel = spec.Linux.MountLabel
+ config.Sysctl = spec.Linux.Sysctl
+ if spec.Linux.Seccomp != nil {
+ seccomp, err := setupSeccomp(spec.Linux.Seccomp)
+ if err != nil {
+ return nil, err
+ }
+ config.Seccomp = seccomp
}
- config.Seccomp = seccomp
}
if spec.Process.SelinuxLabel != "" {
config.ProcessLabel = spec.Process.SelinuxLabel
@@ -242,7 +248,6 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
}
}
createHooks(spec, config)
- config.MountLabel = spec.Linux.MountLabel
config.Version = specs.Version
return config, nil
}
@@ -565,41 +570,40 @@ func createDevices(spec *specs.Spec, config *configs.Config) error {
},
}
// merge in additional devices from the spec
- for _, d := range spec.Linux.Devices {
- var uid, gid uint32
- var filemode os.FileMode = 0666
+ if spec.Linux != nil {
+ for _, d := range spec.Linux.Devices {
+ var uid, gid uint32
+ var filemode os.FileMode = 0666
- if d.UID != nil {
- uid = *d.UID
- }
- if d.GID != nil {
- gid = *d.GID
- }
- dt, err := stringToDeviceRune(d.Type)
- if err != nil {
- return err
- }
- if d.FileMode != nil {
- filemode = *d.FileMode
- }
- device := &configs.Device{
- Type: dt,
- Path: d.Path,
- Major: d.Major,
- Minor: d.Minor,
- FileMode: filemode,
- Uid: uid,
- Gid: gid,
+ if d.UID != nil {
+ uid = *d.UID
+ }
+ if d.GID != nil {
+ gid = *d.GID
+ }
+ dt, err := stringToDeviceRune(d.Type)
+ if err != nil {
+ return err
+ }
+ if d.FileMode != nil {
+ filemode = *d.FileMode
+ }
+ device := &configs.Device{
+ Type: dt,
+ Path: d.Path,
+ Major: d.Major,
+ Minor: d.Minor,
+ FileMode: filemode,
+ Uid: uid,
+ Gid: gid,
+ }
+ config.Devices = append(config.Devices, device)
}
- config.Devices = append(config.Devices, device)
}
return nil
}
func setupUserNamespace(spec *specs.Spec, config *configs.Config) error {
- if len(spec.Linux.UIDMappings) == 0 {
- return nil
- }
create := func(m specs.LinuxIDMapping) configs.IDMap {
return configs.IDMap{
HostID: int(m.HostID),
@@ -607,11 +611,16 @@ func setupUserNamespace(spec *specs.Spec, config *configs.Config) error {
Size: int(m.Size),
}
}
- for _, m := range spec.Linux.UIDMappings {
- config.UidMappings = append(config.UidMappings, create(m))
- }
- for _, m := range spec.Linux.GIDMappings {
- config.GidMappings = append(config.GidMappings, create(m))
+ if spec.Linux != nil {
+ if len(spec.Linux.UIDMappings) == 0 {
+ return nil
+ }
+ for _, m := range spec.Linux.UIDMappings {
+ config.UidMappings = append(config.UidMappings, create(m))
+ }
+ for _, m := range spec.Linux.GIDMappings {
+ config.GidMappings = append(config.GidMappings, create(m))
+ }
}
rootUID, err := config.HostRootUID()
if err != nil {
--
2.7.4.3

View File

@ -0,0 +1,59 @@
From 394c8695f22731938994fdc5d7db678762119481 Mon Sep 17 00:00:00 2001
From: Wentao Zhang <zhangwentao234@huawei.com>
Date: Tue, 20 Dec 2016 06:21:10 -0500
Subject: [PATCH 59/94] Fix setup cgroup before prestart hook
* User Case:
User could use prestart hook to add block devices to container. so the
hook should have a way to set the permissions of the devices.
Just move cgroup config operation before prestart hook will work.
Conflicts:
libcontainer/process_linux.go
Change-Id: I991138f4e686c4268e0629204ce1eae6452fdecf
Signed-off-by: Wentao Zhang <zhangwentao234@huawei.com>
---
libcontainer/process_linux.go | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/libcontainer/process_linux.go b/libcontainer/process_linux.go
index 9064c0e..70e93de 100644
--- a/libcontainer/process_linux.go
+++ b/libcontainer/process_linux.go
@@ -286,9 +286,6 @@ func (p *initProcess) start() error {
ierr := parseSync(p.parentPipe, func(sync *syncT) error {
switch sync.Type {
case procReady:
- if err := p.manager.Set(p.config.Config); err != nil {
- return newSystemErrorWithCause(err, "setting cgroup config for ready process")
- }
// set rlimits, this has to be done here because we lose permissions
// to raise the limits once we enter a user-namespace
if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil {
@@ -296,6 +293,11 @@ func (p *initProcess) start() error {
}
// call prestart hooks
if !p.config.Config.Namespaces.Contains(configs.NEWNS) {
+ // Setup cgroup before prestart hook, so that the prestart hook could apply cgroup permissions.
+ if err := p.manager.Set(p.config.Config); err != nil {
+ return newSystemErrorWithCause(err, "setting cgroup config for ready process")
+ }
+
if p.config.Config.Hooks != nil {
s := configs.HookState{
SpecState: configs.SpecState{
@@ -321,6 +323,10 @@ func (p *initProcess) start() error {
}
sentRun = true
case procHooks:
+ // Setup cgroup before prestart hook, so that the prestart hook could apply cgroup permissions.
+ if err := p.manager.Set(p.config.Config); err != nil {
+ return newSystemErrorWithCause(err, "setting cgroup config for ready process")
+ }
if p.config.Config.Hooks != nil {
s := configs.HookState{
SpecState: configs.SpecState{
--
2.7.4.3

View File

@ -0,0 +1,860 @@
From c8d9a899d3425c342e83868540ca357bf9f7a661 Mon Sep 17 00:00:00 2001
From: panwenxiang <panwenxiang@huawei.com>
Date: Fri, 19 Oct 2018 15:00:34 +0800
Subject: [PATCH 60/94] runc: runc logs forwarding to syslog
reason:runc logs forwarding to syslog and using the config "--log-level" to control the number of logs
Change-Id: Ia93f6f5c56131ea8558c4b7b7e5c4bec827a1bad
Conflicts:
libcontainer/container_linux.go
libcontainer/process_linux.go
libcontainer/state_linux.go
---
create.go | 3 +-
libcontainer/configs/config.go | 55 +++++++++---
libcontainer/container_linux.go | 16 ++--
libcontainer/process_linux.go | 19 ++--
libcontainer/state_linux.go | 4 +-
main.go | 33 +++++--
script/runc-euleros.spec | 2 +-
vendor/github.com/Sirupsen/logrus/Checklist | 1 +
.../Sirupsen/logrus/hooks/airbrake/airbrake.go | 54 +++++++++++
.../Sirupsen/logrus/hooks/bugsnag/bugsnag.go | 68 ++++++++++++++
.../Sirupsen/logrus/hooks/papertrail/README.md | 28 ++++++
.../Sirupsen/logrus/hooks/papertrail/papertrail.go | 55 ++++++++++++
.../Sirupsen/logrus/hooks/sentry/README.md | 61 +++++++++++++
.../Sirupsen/logrus/hooks/sentry/sentry.go | 100 +++++++++++++++++++++
.../Sirupsen/logrus/hooks/syslog/README.md | 20 +++++
.../Sirupsen/logrus/hooks/syslog/syslog.go | 59 ++++++++++++
16 files changed, 535 insertions(+), 43 deletions(-)
create mode 100644 vendor/github.com/Sirupsen/logrus/Checklist
create mode 100644 vendor/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go
create mode 100644 vendor/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go
create mode 100644 vendor/github.com/Sirupsen/logrus/hooks/papertrail/README.md
create mode 100644 vendor/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
create mode 100644 vendor/github.com/Sirupsen/logrus/hooks/sentry/README.md
create mode 100644 vendor/github.com/Sirupsen/logrus/hooks/sentry/sentry.go
create mode 100644 vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
create mode 100644 vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
diff --git a/create.go b/create.go
index 096e8e3..d0246ad 100644
--- a/create.go
+++ b/create.go
@@ -1,9 +1,8 @@
package main
import (
- "os"
-
"github.com/urfave/cli"
+ "os"
)
var createCommand = cli.Command{
diff --git a/libcontainer/configs/config.go b/libcontainer/configs/config.go
index 49bc7a3..d6bc603 100644
--- a/libcontainer/configs/config.go
+++ b/libcontainer/configs/config.go
@@ -4,12 +4,18 @@ import (
"bytes"
"encoding/json"
"fmt"
+ "github.com/Sirupsen/logrus"
+ "github.com/opencontainers/runtime-spec/specs-go"
"os/exec"
"strings"
"time"
+)
- "github.com/Sirupsen/logrus"
- "github.com/opencontainers/runtime-spec/specs-go"
+const (
+ minHookTimeOut = 1 * time.Second
+ defaultHookTimeOut = 5 * time.Second
+ //the runc default timeout is 120s, so set the defaultWarnTime to 80% of the default timeout.
+ defaultWarnTime = 96 * time.Second
)
type Rlimit struct {
@@ -195,9 +201,9 @@ type Config struct {
// about the type of the Capabilities field.
// Refer to: https://github.com/opencontainers/runtime-spec/commit/37391fb
type CompatConfig struct {
- Config
- Cgroups *CompatCgroup `json:"cgroups"`
- Capabilities interface{} `json:"capabilities,omitempty" platform:"linux"`
+ Config
+ Cgroups *CompatCgroup `json:"cgroups"`
+ Capabilities interface{} `json:"capabilities,omitempty" platform:"linux"`
}
type Hooks struct {
@@ -342,29 +348,52 @@ func (c Command) Run(s HookState) error {
Stdout: &stdout,
Stderr: &stderr,
}
+ startTime := time.Now()
if err := cmd.Start(); err != nil {
return err
}
+ if c.Timeout != nil && *c.Timeout < minHookTimeOut {
+ *c.Timeout = defaultHookTimeOut
+ }
errC := make(chan error, 1)
+ var (
+ timerCh <-chan time.Time
+ warnTime = defaultWarnTime.Seconds()
+ )
go func() {
err := cmd.Wait()
if err != nil {
err = fmt.Errorf("error running hook: %v, stdout: %s, stderr: %s", err, stdout.String(), stderr.String())
}
+ elapsedTime := time.Since(startTime)
+ logrus.Infof("hook spends time %s, ContainerID: %s", elapsedTime, s.ID)
+ if c.Timeout != nil {
+ if elapsedTime.Seconds() >= (c.Timeout.Seconds() * 0.8) {
+ logrus.Warnf("elapsed %s, more than 80%% of the timeout %s, ContainerID: %s", elapsedTime, c.Timeout, s.ID)
+ }
+ } else {
+ if elapsedTime.Seconds() >= warnTime {
+ logrus.Warnf("elapsed %s, more than 80%% of the default timeout 120s, ContainerID: %s", elapsedTime, s.ID)
+ }
+ }
errC <- err
}()
- var timerCh <-chan time.Time
if c.Timeout != nil {
timer := time.NewTimer(*c.Timeout)
defer timer.Stop()
timerCh = timer.C
+ warnTime = float64(*c.Timeout) * 0.8
}
- select {
- case err := <-errC:
- return err
- case <-timerCh:
- cmd.Process.Kill()
- cmd.Wait()
- return fmt.Errorf("hook ran past specified timeout of %.1fs", c.Timeout.Seconds())
+ for {
+ select {
+ case err := <-errC:
+ return err
+ case <-timerCh:
+ cmd.Process.Kill()
+ cmd.Wait()
+ return fmt.Errorf("hook ran past specified timeout of %.1fs", c.Timeout.Seconds())
+ case <-time.After(time.Duration(warnTime) * time.Second):
+ logrus.Warnf("hook ran more than 80%% of the default timeout, ContainerID: %s", s.ID)
+ }
}
}
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 502a274..ba5dcd6 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -68,9 +68,9 @@ type State struct {
}
// CompatState
-type CompatState struct{
- State
- Config configs.CompatConfig `json:"config"`
+type CompatState struct {
+ State
+ Config configs.CompatConfig `json:"config"`
}
// Container is a libcontainer container object.
@@ -345,13 +345,13 @@ func (c *linuxContainer) start(process *Process, isInit bool) error {
Root: c.config.Rootfs,
}
for i, hook := range c.config.Hooks.Poststart {
- logrus.Infof("run poststart hook %d:%s", i, hook.Info())
+ logrus.Infof("run poststart hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
if err := hook.Run(s); err != nil {
logrus.Errorf("running poststart hook(%d:%s) failed: %s", i, hook.Info(), err)
if err := parent.terminate(); err != nil {
- logrus.Warn(err)
+ logrus.Warnf("run poststart hook failed: %s, ContainerID: %s", err, s.ID)
}
- return newSystemErrorWithCausef(err, "running poststart hook %d:%s", i, hook.Info())
+ return newSystemErrorWithCausef(err, "running poststart hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
}
logrus.Infof("poststart hook %d:%s done", i, hook.Info())
}
@@ -1319,9 +1319,9 @@ func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Proc
Root: c.config.Rootfs,
}
for i, hook := range c.config.Hooks.Prestart {
- logrus.Infof("run prestart hook: %d:%s", i, hook.Info())
+ logrus.Infof("run prestart hook: %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
if err := hook.Run(s); err != nil {
- return newSystemErrorWithCausef(err, "running prestart hook %d", i)
+ return newSystemErrorWithCausef(err, "running prestart hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
}
logrus.Infof("prestart hook: %d:%s done", i, hook.Info())
}
diff --git a/libcontainer/process_linux.go b/libcontainer/process_linux.go
index 70e93de..79b1c4e 100644
--- a/libcontainer/process_linux.go
+++ b/libcontainer/process_linux.go
@@ -6,18 +6,17 @@ import (
"encoding/json"
"errors"
"fmt"
+ "github.com/Sirupsen/logrus"
+ "github.com/opencontainers/runc/libcontainer/cgroups"
+ "github.com/opencontainers/runc/libcontainer/configs"
+ "github.com/opencontainers/runc/libcontainer/system"
+ "github.com/opencontainers/runc/libcontainer/utils"
"io"
"os"
"os/exec"
"path/filepath"
"strconv"
"syscall"
-
- "github.com/Sirupsen/logrus"
- "github.com/opencontainers/runc/libcontainer/cgroups"
- "github.com/opencontainers/runc/libcontainer/configs"
- "github.com/opencontainers/runc/libcontainer/system"
- "github.com/opencontainers/runc/libcontainer/utils"
)
type parentProcess interface {
@@ -309,9 +308,9 @@ func (p *initProcess) start() error {
Root: p.config.Config.Rootfs,
}
for i, hook := range p.config.Config.Hooks.Prestart {
- logrus.Infof("run prestart hook %d:%s", i, hook.Info())
+ logrus.Infof("run prestart hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
if err := hook.Run(s); err != nil {
- return newSystemErrorWithCausef(err, "running prestart hook %d:%s", i, hook.Info())
+ return newSystemErrorWithCausef(err, "running prestart hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
}
logrus.Infof("prestart hook %d:%s done", i, hook.Info())
}
@@ -338,9 +337,9 @@ func (p *initProcess) start() error {
Root: p.config.Config.Rootfs,
}
for i, hook := range p.config.Config.Hooks.Prestart {
- logrus.Infof("run prestart hook %d:%s", i, hook.Info())
+ logrus.Infof("run prestart hook %d:%s, ContainerID :%s", i, hook.Info(), s.ID)
if err := hook.Run(s); err != nil {
- return newSystemErrorWithCausef(err, "running prestart hook %d:%s", i, hook.Info())
+ return newSystemErrorWithCausef(err, "running prestart hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
}
logrus.Infof("prestart hook %d:%s done", i, hook.Info())
}
diff --git a/libcontainer/state_linux.go b/libcontainer/state_linux.go
index b8d2a87..26e091b 100644
--- a/libcontainer/state_linux.go
+++ b/libcontainer/state_linux.go
@@ -66,10 +66,10 @@ func runPoststopHooks(c *linuxContainer) error {
Root: c.config.Rootfs,
}
for i, hook := range c.config.Hooks.Poststop {
- logrus.Infof("run poststop hook %d:%s", i, hook.Info())
+ logrus.Infof("run poststop hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
if err := hook.Run(s); err != nil {
logrus.Errorf("running poststop hook %d: %s failed: %s", i, hook.Info(), err)
- return newSystemErrorWithCausef(err, "running poststop hook %d:%s", i, hook.Info())
+ return newSystemErrorWithCausef(err, "running poststop hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
}
logrus.Infof("poststop hook %d:%s done", i, hook.Info())
}
diff --git a/main.go b/main.go
index 1cb8f4d..f15a4ac 100644
--- a/main.go
+++ b/main.go
@@ -2,13 +2,14 @@ package main
import (
"fmt"
- "io"
- "os"
- "strings"
-
"github.com/Sirupsen/logrus"
+ "github.com/Sirupsen/logrus/hooks/syslog"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/urfave/cli"
+ "io"
+ "log/syslog"
+ "os"
+ "strings"
)
// version will be populated by the Makefile, read from
@@ -76,6 +77,10 @@ func main() {
Usage: "set the format used by logs ('text' (default), or 'json')",
},
cli.StringFlag{
+ Name: "log-level",
+ Usage: "Set the logging level [debug, info, warn, error, fatal, panic]",
+ },
+ cli.StringFlag{
Name: "root",
Value: "/run/runc",
Usage: "root directory for storage of container state (this should be located in tmpfs)",
@@ -110,15 +115,17 @@ func main() {
updateCommand,
}
app.Before = func(context *cli.Context) error {
- if context.GlobalBool("debug") {
- logrus.SetLevel(logrus.DebugLevel)
- }
if path := context.GlobalString("log"); path != "" {
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND|os.O_SYNC, 0666)
if err != nil {
return err
}
logrus.SetOutput(f)
+ hook, serr := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO|syslog.LOG_USER, "docker-runc")
+ if serr != nil {
+ fmt.Fprint(f, fmt.Sprintf("Leo: new syslog hook get %s", serr))
+ }
+ logrus.AddHook(hook)
}
switch context.GlobalString("log-format") {
case "text":
@@ -128,6 +135,18 @@ func main() {
default:
return fmt.Errorf("unknown log-format %q", context.GlobalString("log-format"))
}
+ if logLevel := context.GlobalString("log-level"); logLevel != "" {
+ lvl, err := logrus.ParseLevel(logLevel)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Unable to parse logging level: %s\n", logLevel)
+ os.Exit(1)
+ }
+ logrus.SetLevel(lvl)
+ }
+
+ if context.GlobalBool("debug") {
+ logrus.SetLevel(logrus.DebugLevel)
+ }
return nil
}
// If the command returns an error, cli takes upon itself to print
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index c3db7c9..5318ec2 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 2%{?dist}
+Release: 3%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
diff --git a/vendor/github.com/Sirupsen/logrus/Checklist b/vendor/github.com/Sirupsen/logrus/Checklist
new file mode 100644
index 0000000..7117b24
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/Checklist
@@ -0,0 +1 @@
+imported from runc v1.0.0-Release Candidate 2: Godeps/_workspace/src/github.com/Sirupsen/logrus/hooks
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go b/vendor/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go
new file mode 100644
index 0000000..b0502c3
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go
@@ -0,0 +1,54 @@
+package airbrake
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/Sirupsen/logrus"
+ "github.com/tobi/airbrake-go"
+)
+
+// AirbrakeHook to send exceptions to an exception-tracking service compatible
+// with the Airbrake API.
+type airbrakeHook struct {
+ APIKey string
+ Endpoint string
+ Environment string
+}
+
+func NewHook(endpoint, apiKey, env string) *airbrakeHook {
+ return &airbrakeHook{
+ APIKey: apiKey,
+ Endpoint: endpoint,
+ Environment: env,
+ }
+}
+
+func (hook *airbrakeHook) Fire(entry *logrus.Entry) error {
+ airbrake.ApiKey = hook.APIKey
+ airbrake.Endpoint = hook.Endpoint
+ airbrake.Environment = hook.Environment
+
+ var notifyErr error
+ err, ok := entry.Data["error"].(error)
+ if ok {
+ notifyErr = err
+ } else {
+ notifyErr = errors.New(entry.Message)
+ }
+
+ airErr := airbrake.Notify(notifyErr)
+ if airErr != nil {
+ return fmt.Errorf("Failed to send error to Airbrake: %s", airErr)
+ }
+
+ return nil
+}
+
+func (hook *airbrakeHook) Levels() []logrus.Level {
+ return []logrus.Level{
+ logrus.ErrorLevel,
+ logrus.FatalLevel,
+ logrus.PanicLevel,
+ }
+}
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go b/vendor/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go
new file mode 100644
index 0000000..d20a0f5
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go
@@ -0,0 +1,68 @@
+package logrus_bugsnag
+
+import (
+ "errors"
+
+ "github.com/Sirupsen/logrus"
+ "github.com/bugsnag/bugsnag-go"
+)
+
+type bugsnagHook struct{}
+
+// ErrBugsnagUnconfigured is returned if NewBugsnagHook is called before
+// bugsnag.Configure. Bugsnag must be configured before the hook.
+var ErrBugsnagUnconfigured = errors.New("bugsnag must be configured before installing this logrus hook")
+
+// ErrBugsnagSendFailed indicates that the hook failed to submit an error to
+// bugsnag. The error was successfully generated, but `bugsnag.Notify()`
+// failed.
+type ErrBugsnagSendFailed struct {
+ err error
+}
+
+func (e ErrBugsnagSendFailed) Error() string {
+ return "failed to send error to Bugsnag: " + e.err.Error()
+}
+
+// NewBugsnagHook initializes a logrus hook which sends exceptions to an
+// exception-tracking service compatible with the Bugsnag API. Before using
+// this hook, you must call bugsnag.Configure(). The returned object should be
+// registered with a log via `AddHook()`
+//
+// Entries that trigger an Error, Fatal or Panic should now include an "error"
+// field to send to Bugsnag.
+func NewBugsnagHook() (*bugsnagHook, error) {
+ if bugsnag.Config.APIKey == "" {
+ return nil, ErrBugsnagUnconfigured
+ }
+ return &bugsnagHook{}, nil
+}
+
+// Fire forwards an error to Bugsnag. Given a logrus.Entry, it extracts the
+// "error" field (or the Message if the error isn't present) and sends it off.
+func (hook *bugsnagHook) Fire(entry *logrus.Entry) error {
+ var notifyErr error
+ err, ok := entry.Data["error"].(error)
+ if ok {
+ notifyErr = err
+ } else {
+ notifyErr = errors.New(entry.Message)
+ }
+
+ bugsnagErr := bugsnag.Notify(notifyErr)
+ if bugsnagErr != nil {
+ return ErrBugsnagSendFailed{bugsnagErr}
+ }
+
+ return nil
+}
+
+// Levels enumerates the log levels on which the error should be forwarded to
+// bugsnag: everything at or above the "Error" level.
+func (hook *bugsnagHook) Levels() []logrus.Level {
+ return []logrus.Level{
+ logrus.ErrorLevel,
+ logrus.FatalLevel,
+ logrus.PanicLevel,
+ }
+}
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/papertrail/README.md b/vendor/github.com/Sirupsen/logrus/hooks/papertrail/README.md
new file mode 100644
index 0000000..ae61e92
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/papertrail/README.md
@@ -0,0 +1,28 @@
+# Papertrail Hook for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:" />
+
+[Papertrail](https://papertrailapp.com) provides hosted log management. Once stored in Papertrail, you can [group](http://help.papertrailapp.com/kb/how-it-works/groups/) your logs on various dimensions, [search](http://help.papertrailapp.com/kb/how-it-works/search-syntax) them, and trigger [alerts](http://help.papertrailapp.com/kb/how-it-works/alerts).
+
+In most deployments, you'll want to send logs to Papertrail via their [remote_syslog](http://help.papertrailapp.com/kb/configuration/configuring-centralized-logging-from-text-log-files-in-unix/) daemon, which requires no application-specific configuration. This hook is intended for relatively low-volume logging, likely in managed cloud hosting deployments where installing `remote_syslog` is not possible.
+
+## Usage
+
+You can find your Papertrail UDP port on your [Papertrail account page](https://papertrailapp.com/account/destinations). Substitute it below for `YOUR_PAPERTRAIL_UDP_PORT`.
+
+For `YOUR_APP_NAME`, substitute a short string that will readily identify your application or service in the logs.
+
+```go
+import (
+ "log/syslog"
+ "github.com/Sirupsen/logrus"
+ "github.com/Sirupsen/logrus/hooks/papertrail"
+)
+
+func main() {
+ log := logrus.New()
+ hook, err := logrus_papertrail.NewPapertrailHook("logs.papertrailapp.com", YOUR_PAPERTRAIL_UDP_PORT, YOUR_APP_NAME)
+
+ if err == nil {
+ log.Hooks.Add(hook)
+ }
+}
+```
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go b/vendor/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
new file mode 100644
index 0000000..c0f10c1
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go
@@ -0,0 +1,55 @@
+package logrus_papertrail
+
+import (
+ "fmt"
+ "net"
+ "os"
+ "time"
+
+ "github.com/Sirupsen/logrus"
+)
+
+const (
+ format = "Jan 2 15:04:05"
+)
+
+// PapertrailHook to send logs to a logging service compatible with the Papertrail API.
+type PapertrailHook struct {
+ Host string
+ Port int
+ AppName string
+ UDPConn net.Conn
+}
+
+// NewPapertrailHook creates a hook to be added to an instance of logger.
+func NewPapertrailHook(host string, port int, appName string) (*PapertrailHook, error) {
+ conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", host, port))
+ return &PapertrailHook{host, port, appName, conn}, err
+}
+
+// Fire is called when a log event is fired.
+func (hook *PapertrailHook) Fire(entry *logrus.Entry) error {
+ date := time.Now().Format(format)
+ msg, _ := entry.String()
+ payload := fmt.Sprintf("<22> %s %s: %s", date, hook.AppName, msg)
+
+ bytesWritten, err := hook.UDPConn.Write([]byte(payload))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Unable to send log line to Papertrail via UDP. Wrote %d bytes before error: %v", bytesWritten, err)
+ return err
+ }
+
+ return nil
+}
+
+// Levels returns the available logging levels.
+func (hook *PapertrailHook) Levels() []logrus.Level {
+ return []logrus.Level{
+ logrus.PanicLevel,
+ logrus.FatalLevel,
+ logrus.ErrorLevel,
+ logrus.WarnLevel,
+ logrus.InfoLevel,
+ logrus.DebugLevel,
+ }
+}
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/sentry/README.md b/vendor/github.com/Sirupsen/logrus/hooks/sentry/README.md
new file mode 100644
index 0000000..19e58bb
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/sentry/README.md
@@ -0,0 +1,61 @@
+# Sentry Hook for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:" />
+
+[Sentry](https://getsentry.com) provides both self-hosted and hosted
+solutions for exception tracking.
+Both client and server are
+[open source](https://github.com/getsentry/sentry).
+
+## Usage
+
+Every sentry application defined on the server gets a different
+[DSN](https://www.getsentry.com/docs/). In the example below replace
+`YOUR_DSN` with the one created for your application.
+
+```go
+import (
+ "github.com/Sirupsen/logrus"
+ "github.com/Sirupsen/logrus/hooks/sentry"
+)
+
+func main() {
+ log := logrus.New()
+ hook, err := logrus_sentry.NewSentryHook(YOUR_DSN, []logrus.Level{
+ logrus.PanicLevel,
+ logrus.FatalLevel,
+ logrus.ErrorLevel,
+ })
+
+ if err == nil {
+ log.Hooks.Add(hook)
+ }
+}
+```
+
+## Special fields
+
+Some logrus fields have a special meaning in this hook,
+these are server_name and logger.
+When logs are sent to sentry these fields are treated differently.
+- server_name (also known as hostname) is the name of the server which
+is logging the event (hostname.example.com)
+- logger is the part of the application which is logging the event.
+In go this usually means setting it to the name of the package.
+
+## Timeout
+
+`Timeout` is the time the sentry hook will wait for a response
+from the sentry server.
+
+If this time elapses with no response from
+the server an error will be returned.
+
+If `Timeout` is set to 0 the SentryHook will not wait for a reply
+and will assume a correct delivery.
+
+The SentryHook has a default timeout of `100 milliseconds` when created
+with a call to `NewSentryHook`. This can be changed by assigning a value to the `Timeout` field:
+
+```go
+hook, _ := logrus_sentry.NewSentryHook(...)
+hook.Timeout = 20*time.Second
+```
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/sentry/sentry.go b/vendor/github.com/Sirupsen/logrus/hooks/sentry/sentry.go
new file mode 100644
index 0000000..379f281
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/sentry/sentry.go
@@ -0,0 +1,100 @@
+package logrus_sentry
+
+import (
+ "fmt"
+ "time"
+
+ "github.com/Sirupsen/logrus"
+ "github.com/getsentry/raven-go"
+)
+
+var (
+ severityMap = map[logrus.Level]raven.Severity{
+ logrus.DebugLevel: raven.DEBUG,
+ logrus.InfoLevel: raven.INFO,
+ logrus.WarnLevel: raven.WARNING,
+ logrus.ErrorLevel: raven.ERROR,
+ logrus.FatalLevel: raven.FATAL,
+ logrus.PanicLevel: raven.FATAL,
+ }
+)
+
+func getAndDel(d logrus.Fields, key string) (string, bool) {
+ var (
+ ok bool
+ v interface{}
+ val string
+ )
+ if v, ok = d[key]; !ok {
+ return "", false
+ }
+
+ if val, ok = v.(string); !ok {
+ return "", false
+ }
+ delete(d, key)
+ return val, true
+}
+
+// SentryHook delivers logs to a sentry server.
+type SentryHook struct {
+ // Timeout sets the time to wait for a delivery error from the sentry server.
+ // If this is set to zero the server will not wait for any response and will
+ // consider the message correctly sent
+ Timeout time.Duration
+
+ client *raven.Client
+ levels []logrus.Level
+}
+
+// NewSentryHook creates a hook to be added to an instance of logger
+// and initializes the raven client.
+// This method sets the timeout to 100 milliseconds.
+func NewSentryHook(DSN string, levels []logrus.Level) (*SentryHook, error) {
+ client, err := raven.NewClient(DSN, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &SentryHook{100 * time.Millisecond, client, levels}, nil
+}
+
+// Called when an event should be sent to sentry
+// Special fields that sentry uses to give more information to the server
+// are extracted from entry.Data (if they are found)
+// These fields are: logger and server_name
+func (hook *SentryHook) Fire(entry *logrus.Entry) error {
+ packet := &raven.Packet{
+ Message: entry.Message,
+ Timestamp: raven.Timestamp(entry.Time),
+ Level: severityMap[entry.Level],
+ Platform: "go",
+ }
+
+ d := entry.Data
+
+ if logger, ok := getAndDel(d, "logger"); ok {
+ packet.Logger = logger
+ }
+ if serverName, ok := getAndDel(d, "server_name"); ok {
+ packet.ServerName = serverName
+ }
+ packet.Extra = map[string]interface{}(d)
+
+ _, errCh := hook.client.Capture(packet, nil)
+ timeout := hook.Timeout
+ if timeout != 0 {
+ timeoutCh := time.After(timeout)
+ select {
+ case err := <-errCh:
+ return err
+ case <-timeoutCh:
+ return fmt.Errorf("no response from sentry server in %s", timeout)
+ }
+ }
+ return nil
+}
+
+// Levels returns the available logging levels.
+func (hook *SentryHook) Levels() []logrus.Level {
+ return hook.levels
+}
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md b/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
new file mode 100644
index 0000000..4dbb8e7
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/syslog/README.md
@@ -0,0 +1,20 @@
+# Syslog Hooks for Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/>
+
+## Usage
+
+```go
+import (
+ "log/syslog"
+ "github.com/Sirupsen/logrus"
+ logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
+)
+
+func main() {
+ log := logrus.New()
+ hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "")
+
+ if err == nil {
+ log.Hooks.Add(hook)
+ }
+}
+```
diff --git a/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go b/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
new file mode 100644
index 0000000..b6fa374
--- /dev/null
+++ b/vendor/github.com/Sirupsen/logrus/hooks/syslog/syslog.go
@@ -0,0 +1,59 @@
+package logrus_syslog
+
+import (
+ "fmt"
+ "github.com/Sirupsen/logrus"
+ "log/syslog"
+ "os"
+)
+
+// SyslogHook to send logs via syslog.
+type SyslogHook struct {
+ Writer *syslog.Writer
+ SyslogNetwork string
+ SyslogRaddr string
+}
+
+// Creates a hook to be added to an instance of logger. This is called with
+// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")`
+// `if err == nil { log.Hooks.Add(hook) }`
+func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) {
+ w, err := syslog.Dial(network, raddr, priority, tag)
+ return &SyslogHook{w, network, raddr}, err
+}
+
+func (hook *SyslogHook) Fire(entry *logrus.Entry) error {
+ line, err := entry.String()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
+ return err
+ }
+
+ switch entry.Level {
+ case logrus.PanicLevel:
+ return hook.Writer.Crit(line)
+ case logrus.FatalLevel:
+ return hook.Writer.Crit(line)
+ case logrus.ErrorLevel:
+ return hook.Writer.Err(line)
+ case logrus.WarnLevel:
+ return hook.Writer.Warning(line)
+ case logrus.InfoLevel:
+ return hook.Writer.Info(line)
+ case logrus.DebugLevel:
+ return hook.Writer.Debug(line)
+ default:
+ return nil
+ }
+}
+
+func (hook *SyslogHook) Levels() []logrus.Level {
+ return []logrus.Level{
+ logrus.PanicLevel,
+ logrus.FatalLevel,
+ logrus.ErrorLevel,
+ logrus.WarnLevel,
+ logrus.InfoLevel,
+ logrus.DebugLevel,
+ }
+}
--
2.7.4.3

View File

@ -0,0 +1,39 @@
From 6e457e14dcf0960926109c2f89766e893f79b5da Mon Sep 17 00:00:00 2001
From: caihaomin <caihaomin@huawei.com>
Date: Wed, 24 Oct 2018 14:56:01 +0800
Subject: [PATCH 61/94] runc-17: change golang build version to make
obs happy
reason:change golang build version to make obs happy
Change-Id: Ie4b210056b34611bfb37aa6ea8510540f2c79305
Signed-off-by: caihaomin <caihaomin@huawei.com>
---
script/runc-euleros.spec | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index 5318ec2..048ea86 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 3%{?dist}
+Release: 4%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
@@ -12,7 +12,7 @@ URL: https://www.opencontainers.org/
Vendor: OCI
Packager: OCI
-BuildRequires: golang == 1.8.3
+BuildRequires: golang >= 1.8.3
BuildRequires: glibc-static
BuildRequires: make
BuildRequires: libseccomp-devel
--
2.7.4.3

View File

@ -0,0 +1,47 @@
From ccd2660d85f36695032ed075f8f669ccad17bfc3 Mon Sep 17 00:00:00 2001
From: panwenxiang <panwenxiang@huawei.com>
Date: Tue, 23 Oct 2018 16:43:20 +0800
Subject: [PATCH 62/94] runc: Check the hook timeout in case overflow
reason:the hook timeout is meaningless when more than 120s
Change-Id: Ibabf059bd9ba5e68b10189ae4e813d47dcec7ec5
---
libcontainer/configs/config.go | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/libcontainer/configs/config.go b/libcontainer/configs/config.go
index d6bc603..9049924 100644
--- a/libcontainer/configs/config.go
+++ b/libcontainer/configs/config.go
@@ -14,6 +14,7 @@ import (
const (
minHookTimeOut = 1 * time.Second
defaultHookTimeOut = 5 * time.Second
+ maxHookTimeOut = 120 * time.Second
//the runc default timeout is 120s, so set the defaultWarnTime to 80% of the default timeout.
defaultWarnTime = 96 * time.Second
)
@@ -355,6 +356,10 @@ func (c Command) Run(s HookState) error {
if c.Timeout != nil && *c.Timeout < minHookTimeOut {
*c.Timeout = defaultHookTimeOut
}
+ if c.Timeout != nil && *c.Timeout > maxHookTimeOut {
+ logrus.Warnf("hook timeout: %s is too long, ContainerID: %s", *c.Timeout, s.ID)
+ *c.Timeout = maxHookTimeOut
+ }
errC := make(chan error, 1)
var (
timerCh <-chan time.Time
@@ -382,7 +387,7 @@ func (c Command) Run(s HookState) error {
timer := time.NewTimer(*c.Timeout)
defer timer.Stop()
timerCh = timer.C
- warnTime = float64(*c.Timeout) * 0.8
+ warnTime = (*c.Timeout).Seconds() * 0.8
}
for {
select {
--
2.7.4.3

View File

@ -0,0 +1,58 @@
From 256b247e9fa9844c8e0760679411427d43b661c9 Mon Sep 17 00:00:00 2001
From: wangfengtu <wangfengtu@huawei.com>
Date: Wed, 5 Sep 2018 15:16:28 +0800
Subject: [PATCH 63/94] docker: close openchan immediately to avoid
error
reason: close openchan immediately to avoid error
Change-Id: I20664570518ea424088a4eb6a5aac3d38ac08449
Signed-off-by: wangfengtu <wangfengtu@huawei.com>
---
libcontainer/container_linux.go | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index ba5dcd6..61ffb76 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -245,8 +245,7 @@ func (c *linuxContainer) exec() error {
select {
case <-awaitProcessExit(c.initProcess.pid(), fifoOpen):
return errors.New("container process is already dead")
- case result := <-awaitFifoOpen(path):
- close(fifoOpen)
+ case result := <-awaitFifoOpen(path, fifoOpen):
if result.err != nil {
return result.err
}
@@ -283,7 +282,12 @@ func awaitProcessExit(pid int, exit <-chan struct{}) <-chan struct{} {
case <-time.After(time.Millisecond * 100):
stat, err := system.GetProcessState(pid)
if err != nil || stat == system.Zombie {
- close(isDead)
+ select {
+ case <-exit:
+ return
+ default:
+ close(isDead)
+ }
return
}
}
@@ -292,10 +296,11 @@ func awaitProcessExit(pid int, exit <-chan struct{}) <-chan struct{} {
return isDead
}
-func awaitFifoOpen(path string) <-chan openResult {
+func awaitFifoOpen(path string, fifoOpen chan struct{}) <-chan openResult {
fifoOpened := make(chan openResult)
go func() {
f, err := os.OpenFile(path, os.O_RDONLY, 0)
+ close(fifoOpen)
if err != nil {
fifoOpened <- openResult{err: newSystemErrorWithCause(err, "open exec fifo for reading")}
return
--
2.7.4.3

View File

@ -0,0 +1,30 @@
From f7c4eae61c9d532ff9ea77aba147976d05235dba Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Tue, 30 Oct 2018 15:24:47 +0800
Subject: [PATCH 64/94] runc: bump to v1.0.0.rc3.4 after normalization
reason:bump version to v1.0.0.rc3.4 after making runc and
runc-17 into one project
Change-Id: I9045945c81f9b21aff53659dac98b4461dea4199
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
script/runc-euleros.spec | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index 048ea86..0ba07be 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 4%{?dist}
+Release: 5%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
--
2.7.4.3

View File

@ -0,0 +1,94 @@
From c5f152a9dc851e0297f63a73c3e59890da135352 Mon Sep 17 00:00:00 2001
From: zhangsong34 <zhangsong34@huawei.com>
Date: Fri, 19 Oct 2018 10:53:33 +0800
Subject: [PATCH 65/94] runc: support namespaced kernel params can be
changed in system container
reason:support namespaced kernel files can be written in container,
when docker run a system container specify '--ns-change-opt' param,
net or ipc namespaced kernel params can be changed in this container.
Conflicts:
libcontainer/rootfs_linux.go
script/runc-euleros.spec
Change-Id: I051b274117abd9745a27577e14a23c906ff7cca3
Signed-off-by: jingrui <jingrui@huawei.com>
---
libcontainer/rootfs_linux.go | 26 ++++++++++++++++++++++++++
libcontainer/standard_init_linux.go | 8 ++++++++
2 files changed, 34 insertions(+)
diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go
index 7cf5edd..38bdd1b 100644
--- a/libcontainer/rootfs_linux.go
+++ b/libcontainer/rootfs_linux.go
@@ -160,6 +160,9 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string) error {
switch m.Device {
case "proc", "sysfs":
+ if strings.HasPrefix(m.Destination, "/proc/sys/") {
+ return nil
+ }
if err := os.MkdirAll(dest, 0755); err != nil {
return err
}
@@ -729,6 +732,29 @@ func readonlyPath(path string) error {
return syscall.Mount(path, path, "", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY|syscall.MS_REC, "")
}
+// remountReadWrite will bind over the top of an existing path and ensure that it is read-write.
+func remountReadWrite(path string) error {
+ for i := 0; i < 5; i++ {
+ if err := syscall.Mount("", path, "", syscall.MS_REMOUNT, ""); err != nil && !os.IsNotExist(err) {
+ switch err {
+ case syscall.EINVAL:
+ // Probably not a mountpoint, use bind-mount
+ if err := syscall.Mount(path, path, "", syscall.MS_BIND, ""); err != nil {
+ return err
+ }
+ return syscall.Mount(path, path, "", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_REC|defaultMountFlags, "")
+ case syscall.EBUSY:
+ time.Sleep(100 * time.Millisecond)
+ continue
+ default:
+ return err
+ }
+ }
+ return nil
+ }
+ return fmt.Errorf("unable to mount %s as readwrite max retries reached", path)
+}
+
// remountReadonly will remount an existing mount point and ensure that it is read-only.
func remountReadonly(m *configs.Mount) error {
var (
diff --git a/libcontainer/standard_init_linux.go b/libcontainer/standard_init_linux.go
index 484ba42..18506af 100644
--- a/libcontainer/standard_init_linux.go
+++ b/libcontainer/standard_init_linux.go
@@ -6,6 +6,7 @@ import (
"fmt"
"os"
"os/exec"
+ "strings"
"syscall"
"time"
@@ -117,6 +118,13 @@ func (l *linuxStandardInit) Init() error {
return err
}
}
+ for _, m := range l.config.Config.Mounts {
+ if m.Flags&syscall.MS_RDONLY == 0 && m.Device == "proc" && strings.HasPrefix(m.Destination, "/proc/sys/") {
+ if err := remountReadWrite(m.Destination); err != nil {
+ return err
+ }
+ }
+ }
for _, path := range l.config.Config.MaskPaths {
if err := maskPath(path); err != nil {
return err
--
2.7.4.3

View File

@ -0,0 +1,29 @@
From c8e1e988fa6509070411c7dbab50edb40092aaf9 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Sat, 23 Feb 2019 14:13:49 +0800
Subject: [PATCH 66/94] runc: bump to v1.0.0.rc3.6
reason:bump version to v1.0.0.rc3.6
Change-Id: I79890c41c7934f96ee6e1d676450d7832cc90f73
Signed-off-by: jingrui <jingrui@huawei.com>
---
script/runc-euleros.spec | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index 0ba07be..08fceee 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 5%{?dist}
+Release: 6%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
--
2.7.4.3

View File

@ -0,0 +1,137 @@
From 6bc094ef27ebb55f22c5a1b63ab40a66bf73cc35 Mon Sep 17 00:00:00 2001
From: panwenxiang <panwenxiang@huawei.com>
Date: Sat, 3 Nov 2018 12:42:49 +0800
Subject: [PATCH 67/94] runc: make the runc log more useful.
reason:changed some log infomation.
Change-Id: Ib6cda4b8a0ef3a441c45f6c435fe11430f8eada8
Signed-off-by: panwenxiang <panwenxiang@huawei.com>
---
libcontainer/configs/config.go | 13 +++++++++----
libcontainer/container_linux.go | 1 -
libcontainer/process_linux.go | 4 +---
libcontainer/state_linux.go | 1 -
main.go | 2 +-
script/runc-euleros.spec | 2 +-
6 files changed, 12 insertions(+), 11 deletions(-)
diff --git a/libcontainer/configs/config.go b/libcontainer/configs/config.go
index 9049924..f8f9d05 100644
--- a/libcontainer/configs/config.go
+++ b/libcontainer/configs/config.go
@@ -12,7 +12,7 @@ import (
)
const (
- minHookTimeOut = 1 * time.Second
+ minHookTimeOut = 0
defaultHookTimeOut = 5 * time.Second
maxHookTimeOut = 120 * time.Second
//the runc default timeout is 120s, so set the defaultWarnTime to 80% of the default timeout.
@@ -353,11 +353,12 @@ func (c Command) Run(s HookState) error {
if err := cmd.Start(); err != nil {
return err
}
- if c.Timeout != nil && *c.Timeout < minHookTimeOut {
+ if c.Timeout != nil && *c.Timeout <= minHookTimeOut {
*c.Timeout = defaultHookTimeOut
+ logrus.Warnf("hook timeout should not be negative or zero, set hook timeout as 5s")
}
if c.Timeout != nil && *c.Timeout > maxHookTimeOut {
- logrus.Warnf("hook timeout: %s is too long, ContainerID: %s", *c.Timeout, s.ID)
+ logrus.Warnf("hook timeout: %s is too long, use 120s as timeout. ContainerID: %s", *c.Timeout, s.ID)
*c.Timeout = maxHookTimeOut
}
errC := make(chan error, 1)
@@ -398,7 +399,11 @@ func (c Command) Run(s HookState) error {
cmd.Wait()
return fmt.Errorf("hook ran past specified timeout of %.1fs", c.Timeout.Seconds())
case <-time.After(time.Duration(warnTime) * time.Second):
- logrus.Warnf("hook ran more than 80%% of the default timeout, ContainerID: %s", s.ID)
+ if c.Timeout != nil {
+ logrus.Warnf("hook ran more than 80%% of the timeout %s, ContainerID: %s", *c.Timeout, s.ID)
+ } else {
+ logrus.Warnf("hook ran more than 80%% of the default timeout 120s, ContainerID: %s", s.ID)
+ }
}
}
}
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 61ffb76..8e0ad12 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -358,7 +358,6 @@ func (c *linuxContainer) start(process *Process, isInit bool) error {
}
return newSystemErrorWithCausef(err, "running poststart hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
}
- logrus.Infof("poststart hook %d:%s done", i, hook.Info())
}
}
} else {
diff --git a/libcontainer/process_linux.go b/libcontainer/process_linux.go
index 79b1c4e..4a7321c 100644
--- a/libcontainer/process_linux.go
+++ b/libcontainer/process_linux.go
@@ -312,7 +312,6 @@ func (p *initProcess) start() error {
if err := hook.Run(s); err != nil {
return newSystemErrorWithCausef(err, "running prestart hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
}
- logrus.Infof("prestart hook %d:%s done", i, hook.Info())
}
}
}
@@ -337,11 +336,10 @@ func (p *initProcess) start() error {
Root: p.config.Config.Rootfs,
}
for i, hook := range p.config.Config.Hooks.Prestart {
- logrus.Infof("run prestart hook %d:%s, ContainerID :%s", i, hook.Info(), s.ID)
+ logrus.Infof("run prestart hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
if err := hook.Run(s); err != nil {
return newSystemErrorWithCausef(err, "running prestart hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
}
- logrus.Infof("prestart hook %d:%s done", i, hook.Info())
}
}
// Sync with child.
diff --git a/libcontainer/state_linux.go b/libcontainer/state_linux.go
index 26e091b..6fa62c0 100644
--- a/libcontainer/state_linux.go
+++ b/libcontainer/state_linux.go
@@ -71,7 +71,6 @@ func runPoststopHooks(c *linuxContainer) error {
logrus.Errorf("running poststop hook %d: %s failed: %s", i, hook.Info(), err)
return newSystemErrorWithCausef(err, "running poststop hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
}
- logrus.Infof("poststop hook %d:%s done", i, hook.Info())
}
}
return nil
diff --git a/main.go b/main.go
index f15a4ac..e55ff82 100644
--- a/main.go
+++ b/main.go
@@ -78,7 +78,7 @@ func main() {
},
cli.StringFlag{
Name: "log-level",
- Usage: "Set the logging level [debug, info, warn, error, fatal, panic]",
+ Usage: "set the logging level [debug, info, warn, error, fatal, panic]",
},
cli.StringFlag{
Name: "root",
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index 08fceee..e829cb9 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 6%{?dist}
+Release: 7%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
--
2.7.4.3

View File

@ -0,0 +1,52 @@
From 940d7088701fbfe6c2d636251490a1d28f90dbdc Mon Sep 17 00:00:00 2001
From: panwenxiang <panwenxiang@huawei.com>
Date: Thu, 8 Nov 2018 10:19:23 +0800
Subject: [PATCH 68/94] runc: reduced the same log when the hook
exected long time.
reason:runc would print a lot of same logs when the hook executed long time
Change-Id: I7d0b07cca68590c560580967f8d70143764f53d9
Signed-off-by: panwenxiang <panwenxiang@huawei.com>
---
libcontainer/configs/config.go | 3 ++-
script/runc-euleros.spec | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/libcontainer/configs/config.go b/libcontainer/configs/config.go
index f8f9d05..78a7d1d 100644
--- a/libcontainer/configs/config.go
+++ b/libcontainer/configs/config.go
@@ -390,6 +390,7 @@ func (c Command) Run(s HookState) error {
timerCh = timer.C
warnTime = (*c.Timeout).Seconds() * 0.8
}
+ timeAfter := time.After(time.Duration(warnTime) * time.Second)
for {
select {
case err := <-errC:
@@ -398,7 +399,7 @@ func (c Command) Run(s HookState) error {
cmd.Process.Kill()
cmd.Wait()
return fmt.Errorf("hook ran past specified timeout of %.1fs", c.Timeout.Seconds())
- case <-time.After(time.Duration(warnTime) * time.Second):
+ case <-timeAfter:
if c.Timeout != nil {
logrus.Warnf("hook ran more than 80%% of the timeout %s, ContainerID: %s", *c.Timeout, s.ID)
} else {
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index e829cb9..025b621 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 7%{?dist}
+Release: 8%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
--
2.7.4.3

View File

@ -0,0 +1,92 @@
From 4b8a7b69792c22c1ee3abf3bee88af3590b144cb Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Thu, 8 Nov 2018 11:14:01 +0800
Subject: [PATCH 69/94] runc: Change Files to LinuxFiles for
--file-limit
reason: after runc-1.0.0.rc3, struct Files should be renamed
to LinuxFiles.
--file-limit related commits:
- 0c540de runc: change read value of cgroup files.limit into string
- fb2de87 runc: Modify max files.limit to max because of the
change of kernel.
- 5fc9474 Add file fds limit
all are already merged.
Change-Id: Ida75dd6a7ccd225f6ac851bf4a28ef77d5a3944f
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
libcontainer/specconv/spec_linux.go | 4 ++--
script/runc-euleros.spec | 2 +-
vendor/github.com/opencontainers/runtime-spec/Checklist | 1 +
.../github.com/opencontainers/runtime-spec/specs-go/config.go | 10 +++++-----
4 files changed, 9 insertions(+), 8 deletions(-)
create mode 100644 vendor/github.com/opencontainers/runtime-spec/Checklist
diff --git a/libcontainer/specconv/spec_linux.go b/libcontainer/specconv/spec_linux.go
index a8cf114..8ef9574 100644
--- a/libcontainer/specconv/spec_linux.go
+++ b/libcontainer/specconv/spec_linux.go
@@ -408,8 +408,8 @@ func createCgroupConfig(opts *CreateOpts) (*configs.Cgroup, error) {
if r.Pids != nil {
c.Resources.PidsLimit = r.Pids.Limit
}
- if r.Files != nil && r.Files.Limit != nil {
- c.Resources.FilesLimit = *r.Files.Limit
+ if r.Files != nil {
+ c.Resources.FilesLimit = r.Files.Limit
}
if r.BlockIO != nil {
if r.BlockIO.Weight != nil {
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index 025b621..19cdc42 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 8%{?dist}
+Release: 9%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
diff --git a/vendor/github.com/opencontainers/runtime-spec/Checklist b/vendor/github.com/opencontainers/runtime-spec/Checklist
new file mode 100644
index 0000000..be85bc8
--- /dev/null
+++ b/vendor/github.com/opencontainers/runtime-spec/Checklist
@@ -0,0 +1 @@
+Add struct LinuxFiles to vendor/src/github.com/opencontainers/runtime-spec/specs-go/config.go for supporting --files-limit
diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
index 603ecf4..fe3c5b6 100644
--- a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
+++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
@@ -318,10 +318,10 @@ type LinuxPids struct {
Limit int64 `json:"limit"`
}
-// Files for Linux cgroup 'files' resource management (https://lwn.net/Articles/604129/)
-type Files struct {
- // Maximum number of open files".
- Limit *int64 `json:"limit,omitempty"`
+// LinuxFiles for Linux cgroup 'files' resource management (https://lwn.net/Articles/604129/)
+type LinuxFiles struct {
+ // Maximum number of open files. Default is "no limit".
+ Limit int64 `json:"limit,omitempty"`
}
// LinuxNetwork identification and priority configuration
@@ -347,7 +347,7 @@ type LinuxResources struct {
// Task resource restriction configuration.
Pids *LinuxPids `json:"pids,omitempty"`
// Files resource restriction configuration.
- Files *Files `json:"files,omitempty"`
+ Files *LinuxFiles `json:"files,omitempty"`
// BlockIO restriction configuration
BlockIO *LinuxBlockIO `json:"blockIO,omitempty"`
// Hugetlb limit (in bytes)
--
2.7.4.3

View File

@ -0,0 +1,48 @@
From e0f78c86d05f7af62aef49c8c495f417d1bf7beb Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Fri, 9 Nov 2018 15:01:27 +0800
Subject: [PATCH 70/94] runc: not print "no such file" when cli err
reason: when container does not exists, runc will cannot find
state.json, so "state.json: no such file or directory" is expected.
but user may call runc command anytime, so we should not print such
log to syslog. Just return it with stderr is ok.
Change-Id: Ia26824d0339f69d8db3ef86c0f8344f60963a177
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
main.go | 5 ++++-
script/runc-euleros.spec | 2 +-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/main.go b/main.go
index e55ff82..be3fba6 100644
--- a/main.go
+++ b/main.go
@@ -163,6 +163,9 @@ type FatalWriter struct {
}
func (f *FatalWriter) Write(p []byte) (n int, err error) {
- logrus.Error(string(p))
+ errStr := string(p)
+ if !strings.Contains(errStr, "state.json: no such file or directory") {
+ logrus.Error(errStr)
+ }
return f.cliErrWriter.Write(p)
}
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index 19cdc42..acadd9e 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 9%{?dist}
+Release: 10%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
--
2.7.4.3

View File

@ -0,0 +1,88 @@
From a667acd5325633858ae671f27075d58345b12619 Mon Sep 17 00:00:00 2001
From: leizhongkai <leizhongkai@huawei.com>
Date: Fri, 9 Nov 2018 20:06:31 +0800
Subject: [PATCH 71/94] runc: [revert]Change Files to LinuxFiles for
--file-limit
reason:This reverts commit 1695b25310c490fe5038cf5a49e4c17ffc85af0e.
Signed-off-by: leizhongkai <leizhongkai@huawei.com>
Conflicts:
script/runc-euleros.spec
Change-Id: Iddbcc7eca095b4b8e5d062e06f2f332a2c07caf8
---
libcontainer/specconv/spec_linux.go | 4 ++--
script/runc-euleros.spec | 2 +-
vendor/github.com/opencontainers/runtime-spec/Checklist | 1 -
.../github.com/opencontainers/runtime-spec/specs-go/config.go | 10 +++++-----
4 files changed, 8 insertions(+), 9 deletions(-)
delete mode 100644 vendor/github.com/opencontainers/runtime-spec/Checklist
diff --git a/libcontainer/specconv/spec_linux.go b/libcontainer/specconv/spec_linux.go
index 8ef9574..a8cf114 100644
--- a/libcontainer/specconv/spec_linux.go
+++ b/libcontainer/specconv/spec_linux.go
@@ -408,8 +408,8 @@ func createCgroupConfig(opts *CreateOpts) (*configs.Cgroup, error) {
if r.Pids != nil {
c.Resources.PidsLimit = r.Pids.Limit
}
- if r.Files != nil {
- c.Resources.FilesLimit = r.Files.Limit
+ if r.Files != nil && r.Files.Limit != nil {
+ c.Resources.FilesLimit = *r.Files.Limit
}
if r.BlockIO != nil {
if r.BlockIO.Weight != nil {
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index acadd9e..16fb43c 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 10%{?dist}
+Release: 11%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
diff --git a/vendor/github.com/opencontainers/runtime-spec/Checklist b/vendor/github.com/opencontainers/runtime-spec/Checklist
deleted file mode 100644
index be85bc8..0000000
--- a/vendor/github.com/opencontainers/runtime-spec/Checklist
+++ /dev/null
@@ -1 +0,0 @@
-Add struct LinuxFiles to vendor/src/github.com/opencontainers/runtime-spec/specs-go/config.go for supporting --files-limit
diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
index fe3c5b6..603ecf4 100644
--- a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
+++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
@@ -318,10 +318,10 @@ type LinuxPids struct {
Limit int64 `json:"limit"`
}
-// LinuxFiles for Linux cgroup 'files' resource management (https://lwn.net/Articles/604129/)
-type LinuxFiles struct {
- // Maximum number of open files. Default is "no limit".
- Limit int64 `json:"limit,omitempty"`
+// Files for Linux cgroup 'files' resource management (https://lwn.net/Articles/604129/)
+type Files struct {
+ // Maximum number of open files".
+ Limit *int64 `json:"limit,omitempty"`
}
// LinuxNetwork identification and priority configuration
@@ -347,7 +347,7 @@ type LinuxResources struct {
// Task resource restriction configuration.
Pids *LinuxPids `json:"pids,omitempty"`
// Files resource restriction configuration.
- Files *LinuxFiles `json:"files,omitempty"`
+ Files *Files `json:"files,omitempty"`
// BlockIO restriction configuration
BlockIO *LinuxBlockIO `json:"blockIO,omitempty"`
// Hugetlb limit (in bytes)
--
2.7.4.3

View File

@ -0,0 +1,32 @@
From b736c8d450f52150db3b8f7a6a247338028b57bf Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Tue, 13 Nov 2018 17:21:19 +0800
Subject: [PATCH 72/94] Revert "runc: not print "no such file" when cli
err"
reason: This reverts commit 21c62a431c2795f59a82312dd9b8a437a1b2ca28.
Change-Id: Ice19acd48ef916a3d992d9f4d06cf056361565e5
Signed-off-by: jingrui <jingrui@huawei.com>
---
main.go | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/main.go b/main.go
index be3fba6..e55ff82 100644
--- a/main.go
+++ b/main.go
@@ -163,9 +163,6 @@ type FatalWriter struct {
}
func (f *FatalWriter) Write(p []byte) (n int, err error) {
- errStr := string(p)
- if !strings.Contains(errStr, "state.json: no such file or directory") {
- logrus.Error(errStr)
- }
+ logrus.Error(string(p))
return f.cliErrWriter.Write(p)
}
--
2.7.4.3

View File

@ -0,0 +1,80 @@
From 3c0c0adf121e44ee00b7191a2693575676eb90be Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Tue, 13 Nov 2018 15:38:05 +0800
Subject: [PATCH 73/94] runc: fix state.json: no such file or directory
reason: fix 8c14d652 * runc-17: add compatibility for docker-1.11.2
Change-Id: I8ff0b3ae90611dfb6e1f5fbd1b8170c460d9ea2d
Signed-off-by: jingrui <jingrui@huawei.com>
---
libcontainer/factory_linux.go | 14 +++++++-------
script/runc-euleros.spec | 2 +-
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/libcontainer/factory_linux.go b/libcontainer/factory_linux.go
index b533346..fe9ce24 100644
--- a/libcontainer/factory_linux.go
+++ b/libcontainer/factory_linux.go
@@ -368,11 +368,11 @@ func (l *LinuxFactory) updateStateCapabilites(compatState *CompatState, configPa
return errors.New("updateStateCapabilites unexpected format for capabilities")
}
-func (l *LinuxFactory) loadOriginState(configPath string) (*State, error) {
+func (l *LinuxFactory) loadOriginState(configPath, id string) (*State, error) {
f, err := os.Open(configPath)
if err != nil {
if os.IsNotExist(err) {
- return nil, newGenericError(err, ContainerNotExists)
+ return nil, newGenericError(fmt.Errorf("container %q does not exist", id), ContainerNotExists)
}
return nil, newGenericError(err, SystemError)
}
@@ -384,11 +384,11 @@ func (l *LinuxFactory) loadOriginState(configPath string) (*State, error) {
return state, nil
}
-func (l *LinuxFactory) loadCompatState(configPath string) (*State, error) {
+func (l *LinuxFactory) loadCompatState(configPath, id string) (*State, error) {
dt, err := ioutil.ReadFile(configPath)
if err != nil {
if os.IsNotExist(err) {
- return nil, newGenericError(err, ContainerNotExists)
+ return nil, newGenericError(fmt.Errorf("container %q does not exist", id), ContainerNotExists)
}
return nil, newGenericError(err, SystemError)
}
@@ -403,14 +403,14 @@ func (l *LinuxFactory) loadCompatState(configPath string) (*State, error) {
return nil, newGenericError(err, SystemError)
}
- return l.loadOriginState(configPath)
+ return l.loadOriginState(configPath, id)
}
func (l *LinuxFactory) loadState(root, id string) (*State, error) {
configPath := filepath.Join(root, stateFilename)
- state, err := l.loadOriginState(configPath)
+ state, err := l.loadOriginState(configPath, id)
if err != nil {
- return l.loadCompatState(configPath)
+ return l.loadCompatState(configPath, id)
}
return state, nil
}
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index 16fb43c..536678d 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 11%{?dist}
+Release: 12%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
--
2.7.4.3

View File

@ -0,0 +1,78 @@
From 0a760e4753e743a0fe874471584d378b81a02d07 Mon Sep 17 00:00:00 2001
From: zhangyuyun <zhangyuyun@huawei.com>
Date: Thu, 15 Nov 2018 01:10:44 -0500
Subject: [PATCH 74/94] runc: fix check sysctl in host network mode
reason:it's found failed in runc to check if the container is in
the host namespace,which introduced by
https://github.com/opencontainers/runc/pull/1138
https://github.com/opencontainers/runc/pull/1221
Change-Id: If1374c081cea93c700d627b40d2ca1ad58b5fb83
---
libcontainer/configs/validate/validator.go | 27 ++++++++++++++++++---------
script/runc-euleros.spec | 2 +-
2 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/libcontainer/configs/validate/validator.go b/libcontainer/configs/validate/validator.go
index 8284345..5cb50fb 100644
--- a/libcontainer/configs/validate/validator.go
+++ b/libcontainer/configs/validate/validator.go
@@ -5,6 +5,7 @@ import (
"os"
"path/filepath"
"strings"
+ "syscall"
"github.com/opencontainers/runc/libcontainer/configs"
selinux "github.com/opencontainers/selinux/go-selinux"
@@ -177,16 +178,24 @@ func checkHostNs(sysctlConfig string, path string) error {
return fmt.Errorf("could not check that %q is a symlink: %v", path, err)
}
+ var destOfContainer string
if symLink == false {
- // The provided namespace is not a symbolic link,
- // it is not the host namespace.
- return nil
- }
-
- // readlink on the path provided in the struct
- destOfContainer, err := os.Readlink(path)
- if err != nil {
- return fmt.Errorf("read soft link %q error", path)
+ // try getting inode number for comparsion
+ f, err := os.Stat(path)
+ if err != nil {
+ return err
+ }
+ stat, ok := f.Sys().(*syscall.Stat_t)
+ if !ok {
+ return fmt.Errorf("cannot convert stat value of %q to syscall.Stat_t", path)
+ }
+ destOfContainer = fmt.Sprintf("net:[%d]", stat.Ino)
+ } else {
+ // readlink on the path provided in the struct
+ destOfContainer, err = os.Readlink(path)
+ if err != nil {
+ return fmt.Errorf("read soft link %q error", path)
+ }
}
if destOfContainer == destOfCurrentProcess {
return fmt.Errorf("sysctl %q is not allowed in the hosts network namespace", sysctlConfig)
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index 536678d..0e92bf0 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 12%{?dist}
+Release: 13%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
--
2.7.4.3

View File

@ -0,0 +1,62 @@
From b35de14c25e51f98c3e61636ed79ba91e6259596 Mon Sep 17 00:00:00 2001
From: zhangsong34 <zhangsong34@huawei.com>
Date: Thu, 6 Dec 2018 19:44:58 +0800
Subject: [PATCH 75/94] runc: Fix systemd-journald service dependency
reason:runc logs forwarding to syslog only when systemd-journald service
status is active and running.
Change-Id: Ib95f0269c6905642050be1c4d195e95919245159
Signed-off-by: zhangsong34 <zhangsong34@huawei.com>
---
main.go | 12 ++++++++----
script/runc-euleros.spec | 2 +-
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/main.go b/main.go
index e55ff82..dcc2925 100644
--- a/main.go
+++ b/main.go
@@ -8,6 +8,7 @@ import (
"github.com/urfave/cli"
"io"
"log/syslog"
+ "net"
"os"
"strings"
)
@@ -121,11 +122,14 @@ func main() {
return err
}
logrus.SetOutput(f)
- hook, serr := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO|syslog.LOG_USER, "docker-runc")
- if serr != nil {
- fmt.Fprint(f, fmt.Sprintf("Leo: new syslog hook get %s", serr))
+ if conn, err := net.Dial("unixgram", "/run/systemd/journal/socket"); err == nil {
+ defer conn.Close()
+ hook, serr := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO|syslog.LOG_USER, "docker-runc")
+ if serr != nil {
+ fmt.Fprint(f, fmt.Sprintf("new syslog hook get %s", serr))
+ }
+ logrus.AddHook(hook)
}
- logrus.AddHook(hook)
}
switch context.GlobalString("log-format") {
case "text":
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index 0e92bf0..354bb24 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 13%{?dist}
+Release: 14%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
--
2.7.4.3

View File

@ -0,0 +1,60 @@
From e42b9955244945b3571aad2e2a612b827f6cafa2 Mon Sep 17 00:00:00 2001
From: zhangsong34 <zhangsong34@huawei.com>
Date: Thu, 6 Dec 2018 21:41:59 +0800
Subject: [PATCH 76/94] runc: Fix syslog hook bug
reason:If NewSyslogHook() function returns error, it indicates that
systemd-journald service is not running, do not add this hook.
Change-Id: Ifd6c9a79a4055da275a8c4c867195f220b0cdffd
Signed-off-by: zhangsong34 <zhangsong34@huawei.com>
---
main.go | 11 ++++-------
script/runc-euleros.spec | 2 +-
2 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/main.go b/main.go
index dcc2925..5f0ec91 100644
--- a/main.go
+++ b/main.go
@@ -8,7 +8,6 @@ import (
"github.com/urfave/cli"
"io"
"log/syslog"
- "net"
"os"
"strings"
)
@@ -122,12 +121,10 @@ func main() {
return err
}
logrus.SetOutput(f)
- if conn, err := net.Dial("unixgram", "/run/systemd/journal/socket"); err == nil {
- defer conn.Close()
- hook, serr := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO|syslog.LOG_USER, "docker-runc")
- if serr != nil {
- fmt.Fprint(f, fmt.Sprintf("new syslog hook get %s", serr))
- }
+ hook, serr := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO|syslog.LOG_USER, "docker-runc")
+ if serr != nil {
+ fmt.Fprint(f, fmt.Sprintf("new syslog hook get %s", serr))
+ } else {
logrus.AddHook(hook)
}
}
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index 354bb24..34f9d22 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 14%{?dist}
+Release: 15%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
--
2.7.4.3

View File

@ -0,0 +1,38 @@
From 2f064ca54d3e1fcc41bc8f97c3ac8a354de34fff Mon Sep 17 00:00:00 2001
From: zhangsong34 <zhangsong34@huawei.com>
Date: Wed, 12 Dec 2018 18:53:48 +0800
Subject: [PATCH 77/94] runc: Require libseccomp-static lib for
upgrade
reason:Require libseccomp-static lib for upgrade
Change-Id: Ie80603197c95ab36ce23c11c8b0807b43d0fb916
Signed-off-by: zhangsong34 <zhangsong34@huawei.com>
---
script/runc-euleros.spec | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index 34f9d22..f21ac08 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 15%{?dist}
+Release: 16%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
@@ -18,6 +18,7 @@ BuildRequires: make
BuildRequires: libseccomp-devel
BuildRequires: libselinux-devel
+BuildRequires: libseccomp-static
%description
runc is a CLI tool for spawning and running containers according to the OCF specification
--
2.7.4.3

View File

@ -0,0 +1,499 @@
From 7bef8ad8bbe3fed26c02b070b6ba09d484ec514b Mon Sep 17 00:00:00 2001
From: wangfengtu <wangfengtu@huawei.com>
Date: Fri, 1 Jun 2018 12:56:13 -0700
Subject: [PATCH 78/94] runc: Fix race in runc exec
reason:There is a race in runc exec when the init process stops just before
the check for the container status. It is then wrongly assumed that
we are trying to start an init process instead of an exec process.
This commit add an Init field to libcontainer Process to distinguish
between init and exec processes to prevent this race.
cherry-picked from upstream https://github.com/opencontainers/runc/pull/1812
conflicts:
exec.go
libcontainer/container_linux.go
utils_linux.go
Change-Id: I945a5f663914e652cc117aa33885d687f70a51e4
Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
Signed-off-by: wangfengtu <wangfengtu@huawei.com>
---
exec.go | 1 +
libcontainer/container_linux.go | 29 +++++++++--------------------
libcontainer/integration/checkpoint_test.go | 2 ++
libcontainer/integration/exec_test.go | 19 +++++++++++++++++++
libcontainer/integration/execin_test.go | 11 +++++++++++
libcontainer/integration/seccomp_test.go | 3 +++
libcontainer/integration/utils_test.go | 1 +
libcontainer/process.go | 3 +++
utils_linux.go | 7 +++++--
9 files changed, 54 insertions(+), 22 deletions(-)
diff --git a/exec.go b/exec.go
index 22f2689..9ed90ea 100644
--- a/exec.go
+++ b/exec.go
@@ -135,6 +135,7 @@ func execProcess(context *cli.Context) (int, error) {
consoleSocket: context.String("console-socket"),
detach: detach,
pidFile: context.String("pid-file"),
+ init: false,
}
return r.run(p)
}
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 8e0ad12..8100aca 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -197,17 +197,13 @@ func (c *linuxContainer) Set(config configs.Config) error {
func (c *linuxContainer) Start(process *Process) error {
c.m.Lock()
defer c.m.Unlock()
- status, err := c.currentStatus()
- if err != nil {
- return err
- }
- if status == Stopped {
+ if process.Init {
if err := c.createExecFifo(); err != nil {
return err
}
}
- if err := c.start(process, status == Stopped); err != nil {
- if status == Stopped {
+ if err := c.start(process); err != nil {
+ if process.Init {
c.deleteExecFifo()
}
return err
@@ -216,17 +212,10 @@ func (c *linuxContainer) Start(process *Process) error {
}
func (c *linuxContainer) Run(process *Process) error {
- c.m.Lock()
- status, err := c.currentStatus()
- if err != nil {
- c.m.Unlock()
- return err
- }
- c.m.Unlock()
if err := c.Start(process); err != nil {
return err
}
- if status == Stopped {
+ if process.Init {
return c.exec()
}
return nil
@@ -315,8 +304,8 @@ type openResult struct {
err error
}
-func (c *linuxContainer) start(process *Process, isInit bool) error {
- parent, err := c.newParentProcess(process, isInit)
+func (c *linuxContainer) start(process *Process) error {
+ parent, err := c.newParentProcess(process)
if err != nil {
return newSystemErrorWithCause(err, "creating new parent process")
}
@@ -329,7 +318,7 @@ func (c *linuxContainer) start(process *Process, isInit bool) error {
}
// generate a timestamp indicating when the container was started
c.created = time.Now().UTC()
- if isInit {
+ if process.Init {
c.state = &createdState{
c: c,
}
@@ -409,7 +398,7 @@ func (c *linuxContainer) deleteExecFifo() {
os.Remove(fifoName)
}
-func (c *linuxContainer) newParentProcess(p *Process, doInit bool) (parentProcess, error) {
+func (c *linuxContainer) newParentProcess(p *Process) (parentProcess, error) {
parentPipe, childPipe, err := utils.NewSockPair("init")
if err != nil {
return nil, newSystemErrorWithCause(err, "creating new init pipe")
@@ -418,7 +407,7 @@ func (c *linuxContainer) newParentProcess(p *Process, doInit bool) (parentProces
if err != nil {
return nil, newSystemErrorWithCause(err, "creating new command template")
}
- if !doInit {
+ if !p.Init {
return c.newSetnsProcess(p, cmd, parentPipe, childPipe)
}
diff --git a/libcontainer/integration/checkpoint_test.go b/libcontainer/integration/checkpoint_test.go
index bc5b0a3..b4d55e0 100644
--- a/libcontainer/integration/checkpoint_test.go
+++ b/libcontainer/integration/checkpoint_test.go
@@ -87,6 +87,7 @@ func TestCheckpoint(t *testing.T) {
Env: standardEnvironment,
Stdin: stdinR,
Stdout: &stdout,
+ Init: true,
}
err = container.Run(&pconfig)
@@ -182,6 +183,7 @@ func TestCheckpoint(t *testing.T) {
Cwd: "/",
Stdin: restoreStdinR,
Stdout: &stdout,
+ Init: true,
}
err = container.Restore(restoreProcessConfig, checkpointOpts)
diff --git a/libcontainer/integration/exec_test.go b/libcontainer/integration/exec_test.go
index f3dd72a..583b04a 100644
--- a/libcontainer/integration/exec_test.go
+++ b/libcontainer/integration/exec_test.go
@@ -230,6 +230,7 @@ func TestEnter(t *testing.T) {
Env: standardEnvironment,
Stdin: stdinR,
Stdout: &stdout,
+ Init: true,
}
err = container.Run(&pconfig)
stdinR.Close()
@@ -319,6 +320,7 @@ func TestProcessEnv(t *testing.T) {
},
Stdin: nil,
Stdout: &stdout,
+ Init: true,
}
err = container.Run(&pconfig)
ok(t, err)
@@ -365,6 +367,7 @@ func TestProcessEmptyCaps(t *testing.T) {
Env: standardEnvironment,
Stdin: nil,
Stdout: &stdout,
+ Init: true,
}
err = container.Run(&pconfig)
ok(t, err)
@@ -416,6 +419,7 @@ func TestProcessCaps(t *testing.T) {
Stdin: nil,
Stdout: &stdout,
Capabilities: &configs.Capabilities{},
+ Init: true,
}
pconfig.Capabilities.Bounding = append(config.Capabilities.Bounding, "CAP_NET_ADMIN")
pconfig.Capabilities.Permitted = append(config.Capabilities.Permitted, "CAP_NET_ADMIN")
@@ -490,6 +494,7 @@ func TestAdditionalGroups(t *testing.T) {
Stdin: nil,
Stdout: &stdout,
AdditionalGroups: []string{"plugdev", "audio"},
+ Init: true,
}
err = container.Run(&pconfig)
ok(t, err)
@@ -550,6 +555,7 @@ func testFreeze(t *testing.T, systemd bool) {
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR,
+ Init: true,
}
err = container.Run(pconfig)
stdinR.Close()
@@ -761,6 +767,7 @@ func TestContainerState(t *testing.T) {
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR,
+ Init: true,
}
err = container.Run(p)
if err != nil {
@@ -814,6 +821,7 @@ func TestPassExtraFiles(t *testing.T) {
ExtraFiles: []*os.File{pipein1, pipein2},
Stdin: nil,
Stdout: &stdout,
+ Init: true,
}
err = container.Run(&process)
if err != nil {
@@ -895,6 +903,7 @@ func TestMountCmds(t *testing.T) {
Cwd: "/",
Args: []string{"sh", "-c", "env"},
Env: standardEnvironment,
+ Init: true,
}
err = container.Run(&pconfig)
if err != nil {
@@ -944,6 +953,7 @@ func TestSysctl(t *testing.T) {
Env: standardEnvironment,
Stdin: nil,
Stdout: &stdout,
+ Init: true,
}
err = container.Run(&pconfig)
ok(t, err)
@@ -1084,6 +1094,7 @@ func TestOomScoreAdj(t *testing.T) {
Env: standardEnvironment,
Stdin: nil,
Stdout: &stdout,
+ Init: true,
}
err = container.Run(&pconfig)
ok(t, err)
@@ -1189,6 +1200,7 @@ func TestHook(t *testing.T) {
Env: standardEnvironment,
Stdin: nil,
Stdout: &stdout,
+ Init: true,
}
err = container.Run(&pconfig)
ok(t, err)
@@ -1305,6 +1317,7 @@ func TestRootfsPropagationSlaveMount(t *testing.T) {
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR,
+ Init: true,
}
err = container.Run(pconfig)
@@ -1422,6 +1435,7 @@ func TestRootfsPropagationSharedMount(t *testing.T) {
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR,
+ Init: true,
}
err = container.Run(pconfig)
@@ -1530,6 +1544,7 @@ func TestInitJoinPID(t *testing.T) {
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR1,
+ Init: true,
}
err = container1.Run(init1)
stdinR1.Close()
@@ -1556,6 +1571,7 @@ func TestInitJoinPID(t *testing.T) {
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR2,
+ Init: true,
}
err = container2.Run(init2)
stdinR2.Close()
@@ -1635,6 +1651,7 @@ func TestInitJoinNetworkAndUser(t *testing.T) {
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR1,
+ Init: true,
}
err = container1.Run(init1)
stdinR1.Close()
@@ -1669,6 +1686,7 @@ func TestInitJoinNetworkAndUser(t *testing.T) {
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR2,
+ Init: true,
}
err = container2.Run(init2)
stdinR2.Close()
@@ -1736,6 +1754,7 @@ func TestTmpfsCopyUp(t *testing.T) {
Env: standardEnvironment,
Stdin: nil,
Stdout: &stdout,
+ Init: true,
}
err = container.Run(&pconfig)
ok(t, err)
diff --git a/libcontainer/integration/execin_test.go b/libcontainer/integration/execin_test.go
index f06075e..988b667 100644
--- a/libcontainer/integration/execin_test.go
+++ b/libcontainer/integration/execin_test.go
@@ -36,6 +36,7 @@ func TestExecIn(t *testing.T) {
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR,
+ Init: true,
}
err = container.Run(process)
stdinR.Close()
@@ -103,6 +104,7 @@ func testExecInRlimit(t *testing.T, userns bool) {
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR,
+ Init: true,
}
err = container.Run(process)
stdinR.Close()
@@ -121,6 +123,7 @@ func testExecInRlimit(t *testing.T, userns bool) {
// increase process rlimit higher than container rlimit to test per-process limit
{Type: syscall.RLIMIT_NOFILE, Hard: 1026, Soft: 1026},
},
+ Init: true,
}
err = container.Run(ps)
ok(t, err)
@@ -157,6 +160,7 @@ func TestExecInAdditionalGroups(t *testing.T) {
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR,
+ Init: true,
}
err = container.Run(process)
stdinR.Close()
@@ -213,6 +217,7 @@ func TestExecInError(t *testing.T) {
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR,
+ Init: true,
}
err = container.Run(process)
stdinR.Close()
@@ -265,6 +270,7 @@ func TestExecInTTY(t *testing.T) {
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR,
+ Init: true,
}
err = container.Run(process)
stdinR.Close()
@@ -349,6 +355,7 @@ func TestExecInEnvironment(t *testing.T) {
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR,
+ Init: true,
}
err = container.Run(process)
stdinR.Close()
@@ -368,6 +375,7 @@ func TestExecInEnvironment(t *testing.T) {
Stdin: buffers.Stdin,
Stdout: buffers.Stdout,
Stderr: buffers.Stderr,
+ Init: true,
}
err = container.Run(process2)
ok(t, err)
@@ -413,6 +421,7 @@ func TestExecinPassExtraFiles(t *testing.T) {
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR,
+ Init: true,
}
err = container.Run(process)
stdinR.Close()
@@ -486,6 +495,7 @@ func TestExecInOomScoreAdj(t *testing.T) {
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR,
+ Init: true,
}
err = container.Run(process)
stdinR.Close()
@@ -541,6 +551,7 @@ func TestExecInUserns(t *testing.T) {
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR,
+ Init: true,
}
err = container.Run(process)
stdinR.Close()
diff --git a/libcontainer/integration/seccomp_test.go b/libcontainer/integration/seccomp_test.go
index 055f887..8e2c7cd 100644
--- a/libcontainer/integration/seccomp_test.go
+++ b/libcontainer/integration/seccomp_test.go
@@ -48,6 +48,7 @@ func TestSeccompDenyGetcwd(t *testing.T) {
Stdin: buffers.Stdin,
Stdout: buffers.Stdout,
Stderr: buffers.Stderr,
+ Init: true,
}
err = container.Run(pwd)
@@ -123,6 +124,7 @@ func TestSeccompPermitWriteConditional(t *testing.T) {
Stdin: buffers.Stdin,
Stdout: buffers.Stdout,
Stderr: buffers.Stderr,
+ Init: true,
}
err = container.Run(dmesg)
@@ -184,6 +186,7 @@ func TestSeccompDenyWriteConditional(t *testing.T) {
Stdin: buffers.Stdin,
Stdout: buffers.Stdout,
Stderr: buffers.Stderr,
+ Init: true,
}
err = container.Run(dmesg)
diff --git a/libcontainer/integration/utils_test.go b/libcontainer/integration/utils_test.go
index 74d9413..dc6a4d8 100644
--- a/libcontainer/integration/utils_test.go
+++ b/libcontainer/integration/utils_test.go
@@ -148,6 +148,7 @@ func runContainer(config *configs.Config, console string, args ...string) (buffe
Stdin: buffers.Stdin,
Stdout: buffers.Stdout,
Stderr: buffers.Stderr,
+ Init: true,
}
err = container.Run(process)
diff --git a/libcontainer/process.go b/libcontainer/process.go
index f1ad081..150510d 100644
--- a/libcontainer/process.go
+++ b/libcontainer/process.go
@@ -68,6 +68,9 @@ type Process struct {
// ConsoleSocket provides the masterfd console.
ConsoleSocket *os.File
+ // Init specifies whether the process is the first process in the container.
+ Init bool
+
ops processOperations
}
diff --git a/utils_linux.go b/utils_linux.go
index c6a8c02..df98cf9 100644
--- a/utils_linux.go
+++ b/utils_linux.go
@@ -72,7 +72,7 @@ func getDefaultImagePath(context *cli.Context) string {
// newProcess returns a new libcontainer Process with the arguments from the
// spec and stdio from the current process.
-func newProcess(p specs.Process) (*libcontainer.Process, error) {
+func newProcess(p specs.Process, init bool) (*libcontainer.Process, error) {
lp := &libcontainer.Process{
Args: p.Args,
Env: p.Env,
@@ -82,6 +82,7 @@ func newProcess(p specs.Process) (*libcontainer.Process, error) {
Label: p.SelinuxLabel,
NoNewPrivileges: &p.NoNewPrivileges,
AppArmorProfile: p.ApparmorProfile,
+ Init: init,
}
if p.Capabilities != nil {
lp.Capabilities = &configs.Capabilities{}
@@ -212,6 +213,7 @@ func createContainer(context *cli.Context, id string, spec *specs.Spec) (libcont
}
type runner struct {
+ init bool
enableSubreaper bool
shouldDestroy bool
detach bool
@@ -229,7 +231,7 @@ func (r *runner) run(config *specs.Process) (int, error) {
r.destroy()
return -1, err
}
- process, err := newProcess(*config)
+ process, err := newProcess(*config, r.init)
if err != nil {
r.destroy()
return -1, err
@@ -373,6 +375,7 @@ func startContainer(context *cli.Context, spec *specs.Spec, create bool) (int, e
pidFile: context.String("pid-file"),
preserveFDs: context.Int("preserve-fds"),
create: create,
+ init: true,
}
return r.run(&spec.Process)
}
--
2.7.4.3

View File

@ -0,0 +1,29 @@
From 912f3b9001459f118fd85f04d7614cbaaa1c351b Mon Sep 17 00:00:00 2001
From: zhangsong34 <zhangsong34@huawei.com>
Date: Tue, 25 Dec 2018 19:13:32 +0800
Subject: [PATCH 79/94] runc: modify spec file for upgrade
reason:modify spec file for upgrade
Change-Id: Ifad62b1e80bf67bb0a043bdd98e5ac03233727f5
Signed-off-by: zhangsong34 <zhangsong34@huawei.com>
---
script/runc-euleros.spec | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index f21ac08..faccbf6 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 16%{?dist}
+Release: 17%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
--
2.7.4.3

View File

@ -0,0 +1,73 @@
From 18f5c5e20e342af002b0edb2295f64ea12632cc4 Mon Sep 17 00:00:00 2001
From: wangfengtu <wangfengtu@huawei.com>
Date: Fri, 21 Dec 2018 15:02:16 +0800
Subject: [PATCH 80/94] runc: support specify umask
reason:support specify umask.
Umask can be 0022 or 0027(default) by specify umask when
start container by command `docker create/run` or start
daemon by command `dockerd`. For example:
$ dockerd --annotation native.umask=normal
$ dockerd --annotation native.umask=secure
$ docker run --exec-opt native.umask=normal
$ docker run --exec-opt native.umask=secure
`normal` reparent umask is 0022, `secure`
reparent umask is 0027.
Change-Id: I49166759ad42dca0ac1f9755f85592e93951c249
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
Signed-off-by: wangfengtu <wangfengtu@huawei.com>
---
libcontainer/rootfs_linux.go | 7 ++++++-
libcontainer/setns_init_linux.go | 10 ++++++++--
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go
index 38bdd1b..3dd5113 100644
--- a/libcontainer/rootfs_linux.go
+++ b/libcontainer/rootfs_linux.go
@@ -136,7 +136,12 @@ func finalizeRootfs(config *configs.Config) (err error) {
}
}
- syscall.Umask(0027)
+ umask := libcontainerUtils.SearchLabels(config.Labels, "native.umask")
+ if umask == "normal" {
+ syscall.Umask(0022)
+ } else {
+ syscall.Umask(0027)
+ }
return nil
}
diff --git a/libcontainer/setns_init_linux.go b/libcontainer/setns_init_linux.go
index e8e969a..b3fab21 100644
--- a/libcontainer/setns_init_linux.go
+++ b/libcontainer/setns_init_linux.go
@@ -11,6 +11,7 @@ import (
"github.com/opencontainers/runc/libcontainer/keys"
"github.com/opencontainers/runc/libcontainer/seccomp"
"github.com/opencontainers/runc/libcontainer/system"
+ "github.com/opencontainers/runc/libcontainer/utils"
"github.com/opencontainers/selinux/go-selinux/label"
)
@@ -41,8 +42,13 @@ func (l *linuxSetnsInit) Init() error {
return err
}
}
- // set exec process umask to 0027 according to secure policy
- syscall.Umask(0027)
+ // set exec process umask to 0027 or 0022 according to container's config
+ umask := utils.SearchLabels(l.config.Config.Labels, "native.umask")
+ if umask == "normal" {
+ syscall.Umask(0022)
+ } else {
+ syscall.Umask(0027)
+ }
if l.config.NoNewPrivileges {
if err := system.Prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil {
return err
--
2.7.4.3

View File

@ -0,0 +1,151 @@
From 1948bc88664ef018f87bd16c004ea2de32be3ec3 Mon Sep 17 00:00:00 2001
From: caihaomin <caihaomin@huawei.com>
Date: Mon, 21 Jan 2019 13:50:35 +0800
Subject: [PATCH 81/94] runc: fix oom-killer-disable unhandled due to
the spec
reason:fix oom-killer-disable unhandled due to the spec
Change-Id: I646b0420f8c387906afb80536352259ec1482729
Signed-off-by: caihaomin <caihaomin@huawei.com>
---
spec.go | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 83 insertions(+), 17 deletions(-)
diff --git a/spec.go b/spec.go
index a15c84e..b33e44c 100644
--- a/spec.go
+++ b/spec.go
@@ -7,7 +7,6 @@ import (
"fmt"
"io/ioutil"
"os"
- "runtime"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/specconv"
@@ -117,24 +116,101 @@ generate a proper rootless spec file.`,
func sPtr(s string) *string { return &s }
+type compatSpec struct {
+ specs.Spec
+ Linux *linux `json:"linux,omitempty" platform:"linux"`
+}
+
+type linux struct {
+ specs.Linux
+ Resources *linuxResources `json:"resources,omitempty"`
+}
+
+type linuxResources struct {
+ specs.LinuxResources
+ Memory *linuxMemory `json:"memory,omitempty"`
+}
+
+type linuxMemory struct {
+ // Memory limit (in bytes).
+ Limit *int64 `json:"limit,omitempty"`
+ // Memory reservation or soft_limit (in bytes).
+ Reservation *int64 `json:"reservation,omitempty"`
+ // Total memory limit (memory + swap).
+ Swap *int64 `json:"swap,omitempty"`
+ // Kernel memory limit (in bytes).
+ Kernel *int64 `json:"kernel,omitempty"`
+ // Kernel memory limit for tcp (in bytes)
+ KernelTCP *int64 `json:"kernelTCP,omitempty"`
+ // How aggressive the kernel will swap memory pages.
+ Swappiness *uint64 `json:"swappiness,omitempty"`
+ // DisableOOMKiller disables the OOM killer for out of memory conditions
+ DisableOOMKiller *bool `json:"disableOOMKiller,omitempty"`
+}
+
// loadSpec loads the specification from the provided path.
func loadSpec(cPath string) (spec *specs.Spec, err error) {
- cf, err := os.Open(cPath)
- if err != nil {
+ spec, err = loadOriginSpec(cPath)
+ if err != nil || spec.Linux.Resources.DisableOOMKiller == nil {
+ return loadCompactSpec(cPath)
+ }
+
+ return spec, validateProcessSpec(&spec.Process)
+}
+
+func loadOriginSpec(cPath string) (*specs.Spec, error) {
+ var spec specs.Spec
+ if _, err := os.Stat(cPath); err != nil {
if os.IsNotExist(err) {
return nil, fmt.Errorf("JSON specification file %s not found", cPath)
}
return nil, err
}
- defer cf.Close()
- if err = json.NewDecoder(cf).Decode(&spec); err != nil {
+ cData, err := ioutil.ReadFile(cPath)
+ if err != nil {
+ return nil, err
+ }
+ if err := json.Unmarshal(cData, &spec); err != nil {
+ return nil, fmt.Errorf("config.json %q error :%v", cPath, err)
+ }
+
+ return &spec, nil
+}
+
+func loadCompactSpec(cPath string) (*specs.Spec, error) {
+ var compatSpec compatSpec
+ cData, err := ioutil.ReadFile(cPath)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return nil, fmt.Errorf("JSON specification file %s not found", cPath)
+ }
return nil, err
}
- if err = validatePlatform(&spec.Platform); err != nil {
+ if err := json.Unmarshal(cData, &compatSpec); err != nil {
+ return nil, fmt.Errorf("config.json %q error :%v", cPath, err)
+ }
+
+ var spec *specs.Spec
+ if spec, err = updateCompactSpec(&compatSpec); err != nil {
return nil, err
}
- return spec, validateProcessSpec(&spec.Process)
+
+ return spec, nil
+
+}
+
+func updateCompactSpec(compatSpec *compatSpec) (*specs.Spec, error) {
+ compatjson, _ := json.Marshal(compatSpec)
+ var spec specs.Spec
+ err := json.Unmarshal(compatjson, &spec)
+ if err != nil {
+ return nil, fmt.Errorf("update config failed %v", err)
+ }
+
+ spec.Linux.Resources.DisableOOMKiller = compatSpec.Linux.Resources.Memory.DisableOOMKiller
+
+ return &spec, nil
}
func createLibContainerRlimit(rlimit specs.LinuxRlimit) (configs.Rlimit, error) {
@@ -148,13 +224,3 @@ func createLibContainerRlimit(rlimit specs.LinuxRlimit) (configs.Rlimit, error)
Soft: rlimit.Soft,
}, nil
}
-
-func validatePlatform(platform *specs.Platform) error {
- if platform.OS != runtime.GOOS {
- return fmt.Errorf("target os %s mismatch with current os %s", platform.OS, runtime.GOOS)
- }
- if platform.Arch != runtime.GOARCH {
- return fmt.Errorf("target arch %s mismatch with current arch %s", platform.Arch, runtime.GOARCH)
- }
- return nil
-}
--
2.7.4.3

View File

@ -0,0 +1,118 @@
From e8e1ec218358495648893370e19eec093681766d Mon Sep 17 00:00:00 2001
From: leizhongkai <leizhongkai@huawei.com>
Date: Thu, 24 Jan 2019 20:18:14 +0800
Subject: [PATCH 82/94] runc: make runc spec and docker-18.9
compatible
reason:make runc spec and docker-18.9 compatible
Change-Id: I794c936579a4decc1d0cd92e3483c6378dba5bfd
Signed-off-by: leizhongkai <leizhongkai@huawei.com>
---
spec.go | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 75 insertions(+), 1 deletion(-)
diff --git a/spec.go b/spec.go
index b33e44c..0bbe967 100644
--- a/spec.go
+++ b/spec.go
@@ -121,6 +121,30 @@ type compatSpec struct {
Linux *linux `json:"linux,omitempty" platform:"linux"`
}
+// linuxBlockIODevice holds major:minor format supported in blkio cgroup
+type linuxBlockIODevice struct {
+ // Major is the device's major number.
+ Major int64 `json:"major"`
+ // Minor is the device's minor number.
+ Minor int64 `json:"minor"`
+}
+
+// LinuxWeightDevice struct holds a `major:minor weight` pair for blkioWeightDevice
+type LinuxWeightDevice struct {
+ linuxBlockIODevice
+ // Weight is the bandwidth rate for the device, range is from 10 to 1000
+ Weight *uint16 `json:"weight,omitempty"`
+ // LeafWeight is the bandwidth rate for the device while competing with the cgroup's child cgroups, range is from 10 to 1000, CFQ scheduler only
+ LeafWeight *uint16 `json:"leafWeight,omitempty"`
+}
+
+// LinuxThrottleDevice struct holds a `major:minor rate_per_second` pair
+type LinuxThrottleDevice struct {
+ linuxBlockIODevice
+ // Rate is the IO rate limit per cgroup per device
+ Rate uint64 `json:"rate"`
+}
+
type linux struct {
specs.Linux
Resources *linuxResources `json:"resources,omitempty"`
@@ -128,7 +152,26 @@ type linux struct {
type linuxResources struct {
specs.LinuxResources
- Memory *linuxMemory `json:"memory,omitempty"`
+ Memory *linuxMemory `json:"memory,omitempty"`
+ BlockIO *LinuxBlockIO `json:"blockIO,omitempty"`
+}
+
+// LinuxBlockIO for Linux cgroup 'blkio' resource management
+type LinuxBlockIO struct {
+ // Specifies per cgroup weight
+ Weight *uint16 `json:"weight,omitempty"`
+ // Specifies tasks' weight in the given cgroup while competing with the cgroup's child cgroups, CFQ scheduler only
+ LeafWeight *uint16 `json:"leafWeight,omitempty"`
+ // Weight per cgroup per device, can override BlkioWeight
+ WeightDevice []LinuxWeightDevice `json:"weightDevice,omitempty"`
+ // IO read rate limit per cgroup per device, bytes per second
+ ThrottleReadBpsDevice []LinuxThrottleDevice `json:"throttleReadBpsDevice,omitempty"`
+ // IO write rate limit per cgroup per device, bytes per second
+ ThrottleWriteBpsDevice []LinuxThrottleDevice `json:"throttleWriteBpsDevice,omitempty"`
+ // IO read rate limit per cgroup per device, IO per second
+ ThrottleReadIOPSDevice []LinuxThrottleDevice `json:"throttleReadIOPSDevice,omitempty"`
+ // IO write rate limit per cgroup per device, IO per second
+ ThrottleWriteIOPSDevice []LinuxThrottleDevice `json:"throttleWriteIOPSDevice,omitempty"`
}
type linuxMemory struct {
@@ -209,6 +252,37 @@ func updateCompactSpec(compatSpec *compatSpec) (*specs.Spec, error) {
}
spec.Linux.Resources.DisableOOMKiller = compatSpec.Linux.Resources.Memory.DisableOOMKiller
+ if compatSpec.Linux.Resources.BlockIO != nil {
+ spec.Linux.Resources.BlockIO.Weight = compatSpec.Linux.Resources.BlockIO.Weight
+ spec.Linux.Resources.BlockIO.LeafWeight = compatSpec.Linux.Resources.BlockIO.LeafWeight
+ if compatSpec.Linux.Resources.BlockIO.WeightDevice != nil {
+ for _, wd := range compatSpec.Linux.Resources.BlockIO.WeightDevice {
+ wdSpec := specs.LinuxWeightDevice{
+ Weight: wd.Weight,
+ LeafWeight: wd.LeafWeight,
+ }
+ wdSpec.Major = wd.Major
+ wdSpec.Minor = wd.Minor
+ spec.Linux.Resources.BlockIO.WeightDevice = append(spec.Linux.Resources.BlockIO.WeightDevice, wdSpec)
+ }
+ }
+ procLinuxThrottleDevice := func(src []LinuxThrottleDevice, dest *[]specs.LinuxThrottleDevice) {
+ if src != nil {
+ for _, ltd := range src {
+ ltdSpec := specs.LinuxThrottleDevice{
+ Rate: ltd.Rate,
+ }
+ ltdSpec.Major = ltd.Major
+ ltdSpec.Minor = ltd.Minor
+ *dest = append(*dest, ltdSpec)
+ }
+ }
+ }
+ procLinuxThrottleDevice(compatSpec.Linux.Resources.BlockIO.ThrottleReadBpsDevice, &spec.Linux.Resources.BlockIO.ThrottleReadBpsDevice)
+ procLinuxThrottleDevice(compatSpec.Linux.Resources.BlockIO.ThrottleWriteBpsDevice, &spec.Linux.Resources.BlockIO.ThrottleWriteBpsDevice)
+ procLinuxThrottleDevice(compatSpec.Linux.Resources.BlockIO.ThrottleReadIOPSDevice, &spec.Linux.Resources.BlockIO.ThrottleReadIOPSDevice)
+ procLinuxThrottleDevice(compatSpec.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice, &spec.Linux.Resources.BlockIO.ThrottleWriteIOPSDevice)
+ }
return &spec, nil
}
--
2.7.4.3

View File

@ -0,0 +1,74 @@
From 52e08b0e3d4e44d555efde15a4ab698500d060db Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Tue, 15 Jan 2019 15:16:54 +0800
Subject: [PATCH 83/94] log: fix runc log decode failed
reason: plain logs can not parsed by containerd, using json formatted
error logs.
Change-Id: I293454c038c3b4f36a8ac9df07fc3557c51179e1
Signed-off-by: jingrui <jingrui@huawei.com>
---
main.go | 30 +++++++++++++++++++++++++-----
1 file changed, 25 insertions(+), 5 deletions(-)
diff --git a/main.go b/main.go
index 5f0ec91..0476242 100644
--- a/main.go
+++ b/main.go
@@ -1,15 +1,18 @@
package main
import (
+ "encoding/json"
"fmt"
- "github.com/Sirupsen/logrus"
- "github.com/Sirupsen/logrus/hooks/syslog"
- "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/urfave/cli"
"io"
"log/syslog"
"os"
"strings"
+ "time"
+
+ "github.com/Sirupsen/logrus"
+ "github.com/Sirupsen/logrus/hooks/syslog"
+ "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/urfave/cli"
)
// version will be populated by the Makefile, read from
@@ -123,7 +126,7 @@ func main() {
logrus.SetOutput(f)
hook, serr := logrus_syslog.NewSyslogHook("", "", syslog.LOG_INFO|syslog.LOG_USER, "docker-runc")
if serr != nil {
- fmt.Fprint(f, fmt.Sprintf("new syslog hook get %s", serr))
+ logToFile(f, "error", fmt.Sprintf("new syslog hook get %s", serr))
} else {
logrus.AddHook(hook)
}
@@ -167,3 +170,20 @@ func (f *FatalWriter) Write(p []byte) (n int, err error) {
logrus.Error(string(p))
return f.cliErrWriter.Write(p)
}
+
+func logToFile(f io.Writer, level string, msg string) {
+ var (
+ log struct {
+ Level string
+ Msg string
+ Time time.Time
+ }
+ )
+ log.Level = level
+ log.Msg = msg
+ log.Time = time.Now()
+ s, err := json.Marshal(log)
+ if err != nil {
+ fmt.Fprint(f, string(s))
+ }
+}
--
2.7.4.3

View File

@ -0,0 +1,108 @@
From 19106da5ad20c3b46888a75b08c00d0b0b12e13b Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Wed, 23 Jan 2019 22:40:51 +0800
Subject: [PATCH 84/94] oci: fix runc panic and support oom score
reason: see below.
1. docker plugin using simple spec, should add more check to avoid runc
panic.
2. add oom-score support.
Change-Id: I0999c8f61209e8127390508577034446d9ae1b4f
Signed-off-by: jingrui <jingrui@huawei.com>
---
script/runc-euleros.spec | 2 +-
spec.go | 39 ++++++++++++++++++++++++++++++++++++---
2 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index faccbf6..bcbcff1 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 17%{?dist}
+Release: 18%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
diff --git a/spec.go b/spec.go
index 0bbe967..3b90791 100644
--- a/spec.go
+++ b/spec.go
@@ -118,7 +118,8 @@ func sPtr(s string) *string { return &s }
type compatSpec struct {
specs.Spec
- Linux *linux `json:"linux,omitempty" platform:"linux"`
+ Linux *linux `json:"linux,omitempty" platform:"linux"`
+ Process processRc6 `json:"process"`
}
// linuxBlockIODevice holds major:minor format supported in blkio cgroup
@@ -150,6 +151,11 @@ type linux struct {
Resources *linuxResources `json:"resources,omitempty"`
}
+type processRc6 struct {
+ specs.Process
+ OOMScoreAdj *int `json:"oomScoreAdj,omitempty" platform:"linux"`
+}
+
type linuxResources struct {
specs.LinuxResources
Memory *linuxMemory `json:"memory,omitempty"`
@@ -191,10 +197,26 @@ type linuxMemory struct {
DisableOOMKiller *bool `json:"disableOOMKiller,omitempty"`
}
+func versionRc6Plus(ver string) bool {
+ if len(ver) < 5 { // version should be a.b.c[-rcn][x]
+ return false
+ }
+
+ // docker-18.09 1.0.1
+ if ver[:5] >= "1.0.1" {
+ return true
+ }
+
+ // TODO: add more version detect, support ab.cd.ef format.
+
+ // < 1.0.0-rc6: include 1.0.0-rc5xxx
+ return false
+}
+
// loadSpec loads the specification from the provided path.
func loadSpec(cPath string) (spec *specs.Spec, err error) {
spec, err = loadOriginSpec(cPath)
- if err != nil || spec.Linux.Resources.DisableOOMKiller == nil {
+ if err != nil || versionRc6Plus(spec.Version) {
return loadCompactSpec(cPath)
}
@@ -251,7 +273,18 @@ func updateCompactSpec(compatSpec *compatSpec) (*specs.Spec, error) {
return nil, fmt.Errorf("update config failed %v", err)
}
- spec.Linux.Resources.DisableOOMKiller = compatSpec.Linux.Resources.Memory.DisableOOMKiller
+ if compatSpec != nil && compatSpec.Linux != nil &&
+ compatSpec.Linux.Resources != nil &&
+ compatSpec.Linux.Resources.Memory != nil &&
+ compatSpec.Linux.Resources.Memory.DisableOOMKiller != nil {
+ spec.Linux.Resources.DisableOOMKiller = compatSpec.Linux.Resources.Memory.DisableOOMKiller
+ }
+
+ if compatSpec != nil && compatSpec.Process.OOMScoreAdj != nil &&
+ spec.Linux != nil && spec.Linux.Resources != nil {
+ spec.Linux.Resources.OOMScoreAdj = compatSpec.Process.OOMScoreAdj
+ }
+
if compatSpec.Linux.Resources.BlockIO != nil {
spec.Linux.Resources.BlockIO.Weight = compatSpec.Linux.Resources.BlockIO.Weight
spec.Linux.Resources.BlockIO.LeafWeight = compatSpec.Linux.Resources.BlockIO.LeafWeight
--
2.7.4.3

View File

@ -0,0 +1,40 @@
From 9421de9838d904c5eea40f0bd0cd50a00157392f Mon Sep 17 00:00:00 2001
From: zhangsong34 <zhangsong34@huawei.com>
Date: Mon, 5 Mar 2018 21:15:15 +0800
Subject: [PATCH 85/94] runc: do not setup sysctl in runc when userns
enabled
reason:when userns enabled, runc will run as normal user, it has
no rights to setup sysctl even the ipcns sysctl. let docker-hooks do this job.
Change-Id: Ia77b8c1bf4255973736f04c0962eae722ed9683e
Signed-off-by: gus.gao <gus.gao@huawei.com>
Signed-off-by: zhangsong34 <zhangsong34@huawei.com>
---
libcontainer/standard_init_linux.go | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/libcontainer/standard_init_linux.go b/libcontainer/standard_init_linux.go
index 18506af..fd836f3 100644
--- a/libcontainer/standard_init_linux.go
+++ b/libcontainer/standard_init_linux.go
@@ -107,10 +107,12 @@ func (l *linuxStandardInit) Init() error {
if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil {
return err
}
-
- for key, value := range l.config.Config.Sysctl {
- if err := writeSystemProperty(key, value); err != nil {
- return err
+ // when userns enabled, write to sysctl will fail, let docker-hooks do this job
+ if len(l.config.Config.UidMappings) == 0 && len(l.config.Config.GidMappings) == 0 {
+ for key, value := range l.config.Config.Sysctl {
+ if err := writeSystemProperty(key, value); err != nil {
+ return err
+ }
}
}
for _, path := range l.config.Config.ReadonlyPaths {
--
2.7.4.3

View File

@ -0,0 +1,68 @@
From f0cff0f9ff831b2380d6907ac1b640eb998c4d88 Mon Sep 17 00:00:00 2001
From: zhangsong34 <zhangsong34@huawei.com>
Date: Wed, 30 Jan 2019 15:33:44 +0800
Subject: [PATCH 86/94] runc: support set seccomp priority
reason:support set seccomp priority
Change-Id: I73ea0ca4ce5dc7af975c62b56edbae03f9721e76
Signed-off-by: gus.gao <gus.gao@huawei.com>
Signed-off-by: zhangsong34 <zhangsong34@huawei.com>
---
libcontainer/configs/config.go | 7 ++++---
libcontainer/seccomp/seccomp_linux.go | 2 +-
libcontainer/specconv/spec_linux.go | 7 ++++---
3 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/libcontainer/configs/config.go b/libcontainer/configs/config.go
index 78a7d1d..9074c86 100644
--- a/libcontainer/configs/config.go
+++ b/libcontainer/configs/config.go
@@ -76,9 +76,10 @@ type Arg struct {
// Syscall is a rule to match a syscall in Seccomp
type Syscall struct {
- Name string `json:"name"`
- Action Action `json:"action"`
- Args []*Arg `json:"args"`
+ Name string `json:"name"`
+ Action Action `json:"action"`
+ Priority uint8 `json:"priority,omitempty"`
+ Args []*Arg `json:"args"`
}
// TODO Windows. Many of these fields should be factored out into those parts
diff --git a/libcontainer/seccomp/seccomp_linux.go b/libcontainer/seccomp/seccomp_linux.go
index 518d2c3..db4bb4e 100644
--- a/libcontainer/seccomp/seccomp_linux.go
+++ b/libcontainer/seccomp/seccomp_linux.go
@@ -198,7 +198,7 @@ func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall) error {
}
}
- return nil
+ return filter.SetSyscallPriority(callNum, call.Priority)
}
func parseStatusFile(path string) (map[string]string, error) {
diff --git a/libcontainer/specconv/spec_linux.go b/libcontainer/specconv/spec_linux.go
index a8cf114..8c4567c 100644
--- a/libcontainer/specconv/spec_linux.go
+++ b/libcontainer/specconv/spec_linux.go
@@ -757,9 +757,10 @@ func setupSeccomp(config *specs.LinuxSeccomp) (*configs.Seccomp, error) {
for _, name := range call.Names {
newCall := configs.Syscall{
- Name: name,
- Action: newAction,
- Args: []*configs.Arg{},
+ Name: name,
+ Action: newAction,
+ Priority: call.Priority,
+ Args: []*configs.Arg{},
}
// Loop through all the arguments of the syscall and convert them
for _, arg := range call.Args {
--
2.7.4.3

View File

@ -0,0 +1,48 @@
From 23829a0c51a77222c842b0a1d277e4738ad22942 Mon Sep 17 00:00:00 2001
From: zhangsong34 <zhangsong34@huawei.com>
Date: Sun, 3 Feb 2019 09:26:44 +0800
Subject: [PATCH 87/94] runc: fix spec LinuxSyscall struct
reason:fix spec LinuxSyscall struct
Change-Id: Iab6d095b43c062ad72aad8f7f1f9206f46a4f88d
Signed-off-by: zhangsong34 <zhangsong34@huawei.com>
---
script/runc-euleros.spec | 2 +-
vendor/github.com/opencontainers/runtime-spec/specs-go/config.go | 9 +++++----
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index bcbcff1..b3db2ab 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 18%{?dist}
+Release: 19%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
index 603ecf4..8439744 100644
--- a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
+++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
@@ -554,8 +554,9 @@ type LinuxSeccompArg struct {
// LinuxSyscall is used to match a syscall in Seccomp
type LinuxSyscall struct {
- Names []string `json:"names"`
- Action LinuxSeccompAction `json:"action"`
- Args []LinuxSeccompArg `json:"args"`
- Comment string `json:"comment"`
+ Names []string `json:"names"`
+ Action LinuxSeccompAction `json:"action"`
+ Priority uint8 `json:"priority,omitempty"`
+ Args []LinuxSeccompArg `json:"args"`
+ Comment string `json:"comment"`
}
--
2.7.4.3

View File

@ -0,0 +1,306 @@
From 55dc2797a066480f836baf541a9ab858d9999421 Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Mon, 28 Jan 2019 22:12:18 +0800
Subject: [PATCH 88/94] nsenter: clone /proc/self/exe to avoid
exposing host binary to container
reason: There are quite a few circumstances where /proc/self/exe pointing to a
pretty important container binary is a _bad_ thing, so to avoid this we
have to make a copy (preferably doing self-clean-up and not being
writeable).
As a hotfix we require memfd_create(2), but we can always extend this to
use a scratch MNT_DETACH overlayfs or tmpfs. The main downside to this
approach is no page-cache sharing for the runc binary (which overlayfs
would give us) but this is far less complicated.
This is only done during nsenter so that it happens transparently to the
Go code, and any libcontainer users benefit from it. This also makes
ExtraFiles and --preserve-fds handling trivial (because we don't need to
worry about it).
Fixes: CVE-2019-5736
Signed-off-by: Aleksa Sarai <asarai@suse.de>
Change-Id: Id54b4827173affa0f2063eef4159c87343f4d672
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
libcontainer/nsenter/cloned_binary.c | 236 +++++++++++++++++++++++++++++++++++
libcontainer/nsenter/nsexec.c | 11 ++
2 files changed, 247 insertions(+)
create mode 100644 libcontainer/nsenter/cloned_binary.c
diff --git a/libcontainer/nsenter/cloned_binary.c b/libcontainer/nsenter/cloned_binary.c
new file mode 100644
index 0000000..ec383c1
--- /dev/null
+++ b/libcontainer/nsenter/cloned_binary.c
@@ -0,0 +1,236 @@
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <limits.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <sys/mman.h>
+#include <sys/sendfile.h>
+#include <sys/syscall.h>
+
+#include <linux/magic.h>
+#include <linux/memfd.h>
+
+#define MEMFD_COMMENT "runc_cloned:/proc/self/exe"
+#define MEMFD_LNKNAME "/memfd:" MEMFD_COMMENT " (deleted)"
+
+/* Use our own wrapper for memfd_create. */
+#if !defined(SYS_memfd_create) && defined(__NR_memfd_create)
+# define SYS_memfd_create __NR_memfd_create
+#endif
+#ifndef SYS_memfd_create
+# error "memfd_create(2) syscall not supported by this glibc version"
+#endif
+int memfd_create(const char *name, unsigned int flags)
+{
+ return syscall(SYS_memfd_create, name, flags);
+}
+
+/* This comes directly from <linux/fcntl.h>. */
+#ifndef F_LINUX_SPECIFIC_BASE
+# define F_LINUX_SPECIFIC_BASE 1024
+#endif
+#ifndef F_ADD_SEALS
+# define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
+# define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
+#endif
+#ifndef F_SEAL_SEAL
+# define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
+# define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
+# define F_SEAL_GROW 0x0004 /* prevent file from growing */
+# define F_SEAL_WRITE 0x0008 /* prevent writes */
+#endif
+
+/*
+ * Verify whether we are currently in a self-cloned program. It's not really
+ * possible to trivially identify a memfd compared to a regular tmpfs file, so
+ * the best we can do is to check whether the readlink(2) looks okay and that
+ * it is on a tmpfs.
+ */
+static int is_self_cloned(void)
+{
+ struct statfs statfsbuf = {0};
+ char linkname[PATH_MAX + 1] = {0};
+
+ if (statfs("/proc/self/exe", &statfsbuf) < 0)
+ return -1;
+ if (readlink("/proc/self/exe", linkname, PATH_MAX) < 0)
+ return -1;
+
+ return statfsbuf.f_type == TMPFS_MAGIC &&
+ !strncmp(linkname, MEMFD_LNKNAME, PATH_MAX);
+}
+
+/*
+ * Basic wrapper around mmap(2) that gives you the file length so you can
+ * safely treat it as an ordinary buffer. Only gives you read access.
+ */
+static char *read_file(char *path, size_t *length)
+{
+ int fd;
+ char buf[4096], *copy = NULL;
+
+ if (!length)
+ goto err;
+ *length = 0;
+
+ fd = open(path, O_RDONLY|O_CLOEXEC);
+ if (fd < 0)
+ goto err_free;
+
+ for (;;) {
+ int n;
+ char *old = copy;
+
+ n = read(fd, buf, sizeof(buf));
+ if (n < 0)
+ goto err_fd;
+ if (!n)
+ break;
+
+ do {
+ copy = realloc(old, (*length + n) * sizeof(*old));
+ } while(!copy);
+
+ memcpy(copy + *length, buf, n);
+ *length += n;
+ }
+ close(fd);
+ return copy;
+
+err_fd:
+ close(fd);
+err_free:
+ free(copy);
+err:
+ return NULL;
+}
+
+/*
+ * A poor-man's version of "xargs -0". Basically parses a given block of
+ * NUL-delimited data, within the given length and adds a pointer to each entry
+ * to the array of pointers.
+ */
+static int parse_xargs(char *data, int data_length, char ***output)
+{
+ int num = 0;
+ char *cur = data;
+
+ if (!data || *output)
+ return -1;
+
+ do {
+ *output = malloc(sizeof(**output));
+ } while (!*output);
+
+ while (cur < data + data_length) {
+ char **old = *output;
+
+ num++;
+ do {
+ *output = realloc(old, (num + 1) * sizeof(*old));
+ } while (!*output);
+
+ (*output)[num - 1] = cur;
+ cur += strlen(cur) + 1;
+ }
+ (*output)[num] = NULL;
+ return num;
+}
+
+/*
+ * "Parse" out argv and envp from /proc/self/cmdline and /proc/self/environ.
+ * This is necessary because we are running in a context where we don't have a
+ * main() that we can just get the arguments from.
+ */
+static int fetchve(char ***argv, char ***envp)
+{
+ char *cmdline, *environ;
+ size_t cmdline_size, environ_size;
+
+ cmdline = read_file("/proc/self/cmdline", &cmdline_size);
+ if (!cmdline)
+ goto err;
+ environ = read_file("/proc/self/environ", &environ_size);
+ if (!environ)
+ goto err_free;
+
+ if (parse_xargs(cmdline, cmdline_size, argv) <= 0)
+ goto err_free_both;
+ if (parse_xargs(environ, environ_size, envp) <= 0)
+ goto err_free_both;
+
+ return 0;
+
+err_free_both:
+ free(environ);
+err_free:
+ free(cmdline);
+err:
+ return -1;
+}
+
+static int clone_binary(void)
+{
+ int binfd, memfd, err;
+ ssize_t sent = 0;
+ struct stat statbuf = {0};
+
+ binfd = open("/proc/self/exe", O_RDONLY|O_CLOEXEC);
+ if (binfd < 0)
+ goto err;
+ if (fstat(binfd, &statbuf) < 0)
+ goto err_binfd;
+
+ memfd = memfd_create(MEMFD_COMMENT, MFD_CLOEXEC|MFD_ALLOW_SEALING);
+ if (memfd < 0)
+ goto err_binfd;
+
+ while (sent < statbuf.st_size) {
+ ssize_t n = sendfile(memfd, binfd, NULL, statbuf.st_size - sent);
+ if (n < 0)
+ goto err_memfd;
+ sent += n;
+ }
+
+ err = fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_SEAL);
+ if (err < 0)
+ goto err_memfd;
+
+ close(binfd);
+ return memfd;
+
+err_memfd:
+ close(memfd);
+err_binfd:
+ close(binfd);
+err:
+ return -1;
+}
+
+int ensure_cloned_binary(void)
+{
+ int execfd;
+ char **argv = NULL, **envp = NULL;
+
+ /* Check that we're not self-cloned, and if we are then bail. */
+ int cloned = is_self_cloned();
+ if (cloned != 0)
+ return cloned;
+
+ if (fetchve(&argv, &envp) < 0)
+ return -1;
+
+ execfd = clone_binary();
+ if (execfd < 0)
+ return -1;
+
+ fexecve(execfd, argv, envp);
+ return -1;
+}
diff --git a/libcontainer/nsenter/nsexec.c b/libcontainer/nsenter/nsexec.c
index 0ad6883..75211c8 100644
--- a/libcontainer/nsenter/nsexec.c
+++ b/libcontainer/nsenter/nsexec.c
@@ -432,6 +432,9 @@ void join_namespaces(char *nslist)
free(namespaces);
}
+/* Defined in cloned_binary.c. */
+int ensure_cloned_binary(void);
+
void nsexec(void)
{
int pipenum;
@@ -447,6 +450,14 @@ void nsexec(void)
if (pipenum == -1)
return;
+ /*
+ * We need to re-exec if we are not in a cloned binary. This is necessary
+ * to ensure that containers won't be able to access the host binary
+ * through /proc/self/exe. See CVE-2019-5736.
+ */
+ if (ensure_cloned_binary() < 0)
+ bail("could not ensure we are a cloned binary");
+
/* Parse all of the netlink configuration. */
nl_parse(pipenum, &config);
--
2.7.4.3

View File

@ -0,0 +1,294 @@
From eb6c73cc11d6f8da5f19ef6d0794c41374dbfae4 Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Tue, 12 Feb 2019 19:07:09 +0800
Subject: [PATCH 89/94] Revert "nsenter: clone /proc/self/exe to
avoid exposing host binary to container"
reason: This reverts commit 275c8d34e6a6fa915ea4a4e47c45ce4c246a2410.
The origin patch is from discussion email, it is the early version,
which is different with the upstream:
https://github.com/opencontainers/runc/commit/0a8e4117e7f715d5fbeef398405813ce8e88558b
So revert this patch, and recommit with newer patch
Change-Id: Idb9250ce6dc86bd1a7640015b746c7afe8b03f49
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
libcontainer/nsenter/cloned_binary.c | 236 -----------------------------------
libcontainer/nsenter/nsexec.c | 11 --
2 files changed, 247 deletions(-)
delete mode 100644 libcontainer/nsenter/cloned_binary.c
diff --git a/libcontainer/nsenter/cloned_binary.c b/libcontainer/nsenter/cloned_binary.c
deleted file mode 100644
index ec383c1..0000000
--- a/libcontainer/nsenter/cloned_binary.c
+++ /dev/null
@@ -1,236 +0,0 @@
-#define _GNU_SOURCE
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <limits.h>
-#include <fcntl.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/vfs.h>
-#include <sys/mman.h>
-#include <sys/sendfile.h>
-#include <sys/syscall.h>
-
-#include <linux/magic.h>
-#include <linux/memfd.h>
-
-#define MEMFD_COMMENT "runc_cloned:/proc/self/exe"
-#define MEMFD_LNKNAME "/memfd:" MEMFD_COMMENT " (deleted)"
-
-/* Use our own wrapper for memfd_create. */
-#if !defined(SYS_memfd_create) && defined(__NR_memfd_create)
-# define SYS_memfd_create __NR_memfd_create
-#endif
-#ifndef SYS_memfd_create
-# error "memfd_create(2) syscall not supported by this glibc version"
-#endif
-int memfd_create(const char *name, unsigned int flags)
-{
- return syscall(SYS_memfd_create, name, flags);
-}
-
-/* This comes directly from <linux/fcntl.h>. */
-#ifndef F_LINUX_SPECIFIC_BASE
-# define F_LINUX_SPECIFIC_BASE 1024
-#endif
-#ifndef F_ADD_SEALS
-# define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
-# define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
-#endif
-#ifndef F_SEAL_SEAL
-# define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
-# define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
-# define F_SEAL_GROW 0x0004 /* prevent file from growing */
-# define F_SEAL_WRITE 0x0008 /* prevent writes */
-#endif
-
-/*
- * Verify whether we are currently in a self-cloned program. It's not really
- * possible to trivially identify a memfd compared to a regular tmpfs file, so
- * the best we can do is to check whether the readlink(2) looks okay and that
- * it is on a tmpfs.
- */
-static int is_self_cloned(void)
-{
- struct statfs statfsbuf = {0};
- char linkname[PATH_MAX + 1] = {0};
-
- if (statfs("/proc/self/exe", &statfsbuf) < 0)
- return -1;
- if (readlink("/proc/self/exe", linkname, PATH_MAX) < 0)
- return -1;
-
- return statfsbuf.f_type == TMPFS_MAGIC &&
- !strncmp(linkname, MEMFD_LNKNAME, PATH_MAX);
-}
-
-/*
- * Basic wrapper around mmap(2) that gives you the file length so you can
- * safely treat it as an ordinary buffer. Only gives you read access.
- */
-static char *read_file(char *path, size_t *length)
-{
- int fd;
- char buf[4096], *copy = NULL;
-
- if (!length)
- goto err;
- *length = 0;
-
- fd = open(path, O_RDONLY|O_CLOEXEC);
- if (fd < 0)
- goto err_free;
-
- for (;;) {
- int n;
- char *old = copy;
-
- n = read(fd, buf, sizeof(buf));
- if (n < 0)
- goto err_fd;
- if (!n)
- break;
-
- do {
- copy = realloc(old, (*length + n) * sizeof(*old));
- } while(!copy);
-
- memcpy(copy + *length, buf, n);
- *length += n;
- }
- close(fd);
- return copy;
-
-err_fd:
- close(fd);
-err_free:
- free(copy);
-err:
- return NULL;
-}
-
-/*
- * A poor-man's version of "xargs -0". Basically parses a given block of
- * NUL-delimited data, within the given length and adds a pointer to each entry
- * to the array of pointers.
- */
-static int parse_xargs(char *data, int data_length, char ***output)
-{
- int num = 0;
- char *cur = data;
-
- if (!data || *output)
- return -1;
-
- do {
- *output = malloc(sizeof(**output));
- } while (!*output);
-
- while (cur < data + data_length) {
- char **old = *output;
-
- num++;
- do {
- *output = realloc(old, (num + 1) * sizeof(*old));
- } while (!*output);
-
- (*output)[num - 1] = cur;
- cur += strlen(cur) + 1;
- }
- (*output)[num] = NULL;
- return num;
-}
-
-/*
- * "Parse" out argv and envp from /proc/self/cmdline and /proc/self/environ.
- * This is necessary because we are running in a context where we don't have a
- * main() that we can just get the arguments from.
- */
-static int fetchve(char ***argv, char ***envp)
-{
- char *cmdline, *environ;
- size_t cmdline_size, environ_size;
-
- cmdline = read_file("/proc/self/cmdline", &cmdline_size);
- if (!cmdline)
- goto err;
- environ = read_file("/proc/self/environ", &environ_size);
- if (!environ)
- goto err_free;
-
- if (parse_xargs(cmdline, cmdline_size, argv) <= 0)
- goto err_free_both;
- if (parse_xargs(environ, environ_size, envp) <= 0)
- goto err_free_both;
-
- return 0;
-
-err_free_both:
- free(environ);
-err_free:
- free(cmdline);
-err:
- return -1;
-}
-
-static int clone_binary(void)
-{
- int binfd, memfd, err;
- ssize_t sent = 0;
- struct stat statbuf = {0};
-
- binfd = open("/proc/self/exe", O_RDONLY|O_CLOEXEC);
- if (binfd < 0)
- goto err;
- if (fstat(binfd, &statbuf) < 0)
- goto err_binfd;
-
- memfd = memfd_create(MEMFD_COMMENT, MFD_CLOEXEC|MFD_ALLOW_SEALING);
- if (memfd < 0)
- goto err_binfd;
-
- while (sent < statbuf.st_size) {
- ssize_t n = sendfile(memfd, binfd, NULL, statbuf.st_size - sent);
- if (n < 0)
- goto err_memfd;
- sent += n;
- }
-
- err = fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_SEAL);
- if (err < 0)
- goto err_memfd;
-
- close(binfd);
- return memfd;
-
-err_memfd:
- close(memfd);
-err_binfd:
- close(binfd);
-err:
- return -1;
-}
-
-int ensure_cloned_binary(void)
-{
- int execfd;
- char **argv = NULL, **envp = NULL;
-
- /* Check that we're not self-cloned, and if we are then bail. */
- int cloned = is_self_cloned();
- if (cloned != 0)
- return cloned;
-
- if (fetchve(&argv, &envp) < 0)
- return -1;
-
- execfd = clone_binary();
- if (execfd < 0)
- return -1;
-
- fexecve(execfd, argv, envp);
- return -1;
-}
diff --git a/libcontainer/nsenter/nsexec.c b/libcontainer/nsenter/nsexec.c
index 75211c8..0ad6883 100644
--- a/libcontainer/nsenter/nsexec.c
+++ b/libcontainer/nsenter/nsexec.c
@@ -432,9 +432,6 @@ void join_namespaces(char *nslist)
free(namespaces);
}
-/* Defined in cloned_binary.c. */
-int ensure_cloned_binary(void);
-
void nsexec(void)
{
int pipenum;
@@ -450,14 +447,6 @@ void nsexec(void)
if (pipenum == -1)
return;
- /*
- * We need to re-exec if we are not in a cloned binary. This is necessary
- * to ensure that containers won't be able to access the host binary
- * through /proc/self/exe. See CVE-2019-5736.
- */
- if (ensure_cloned_binary() < 0)
- bail("could not ensure we are a cloned binary");
-
/* Parse all of the netlink configuration. */
nl_parse(pipenum, &config);
--
2.7.4.3

View File

@ -0,0 +1,357 @@
From 2f3550fa67d6e2eb21276775e05ba145f8b5768b Mon Sep 17 00:00:00 2001
From: lujingxiao <lujingxiao@huawei.com>
Date: Tue, 12 Feb 2019 19:15:11 +0800
Subject: [PATCH 90/94] nsenter: clone /proc/self/exe to avoid
exposing host binary to container
reason: There are quite a few circumstances where /proc/self/exe pointing to a
pretty important container binary is a _bad_ thing, so to avoid this we
have to make a copy (preferably doing self-clean-up and not being
writeable).
We require memfd_create(2) -- though there is an O_TMPFILE fallback --
but we can always extend this to use a scratch MNT_DETACH overlayfs or
tmpfs. The main downside to this approach is no page-cache sharing for
the runc binary (which overlayfs would give us) but this is far less
complicated.
This is only done during nsenter so that it happens transparently to the
Go code, and any libcontainer users benefit from it. This also makes
ExtraFiles and --preserve-fds handling trivial (because we don't need to
worry about it).
Fixes: CVE-2019-5736
Co-developed-by: Christian Brauner <christian.brauner@ubuntu.com>
Signed-off-by: Aleksa Sarai <asarai@suse.de>
Recommit this patch with the upstream one:
https://github.com/opencontainers/runc/commit/0a8e4117e7f715d5fbeef398405813ce8e88558b
Change-Id: I4d4d87d480c12a7844b9ef6bd955457cb152ba51
Signed-off-by: lujingxiao <lujingxiao@huawei.com>
---
libcontainer/nsenter/cloned_binary.c | 268 +++++++++++++++++++++++++++++++++++
libcontainer/nsenter/nsexec.c | 11 ++
script/runc-euleros.spec | 2 +-
3 files changed, 280 insertions(+), 1 deletion(-)
create mode 100644 libcontainer/nsenter/cloned_binary.c
diff --git a/libcontainer/nsenter/cloned_binary.c b/libcontainer/nsenter/cloned_binary.c
new file mode 100644
index 0000000..c8a42c2
--- /dev/null
+++ b/libcontainer/nsenter/cloned_binary.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2019 Aleksa Sarai <cyphar@cyphar.com>
+ * Copyright (C) 2019 SUSE LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <sys/mman.h>
+#include <sys/sendfile.h>
+#include <sys/syscall.h>
+
+/* Use our own wrapper for memfd_create. */
+#if !defined(SYS_memfd_create) && defined(__NR_memfd_create)
+# define SYS_memfd_create __NR_memfd_create
+#endif
+#ifdef SYS_memfd_create
+# define HAVE_MEMFD_CREATE
+/* memfd_create(2) flags -- copied from <linux/memfd.h>. */
+# ifndef MFD_CLOEXEC
+# define MFD_CLOEXEC 0x0001U
+# define MFD_ALLOW_SEALING 0x0002U
+# endif
+int memfd_create(const char *name, unsigned int flags)
+{
+ return syscall(SYS_memfd_create, name, flags);
+}
+#endif
+
+/* This comes directly from <linux/fcntl.h>. */
+#ifndef F_LINUX_SPECIFIC_BASE
+# define F_LINUX_SPECIFIC_BASE 1024
+#endif
+#ifndef F_ADD_SEALS
+# define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
+# define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
+#endif
+#ifndef F_SEAL_SEAL
+# define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
+# define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
+# define F_SEAL_GROW 0x0004 /* prevent file from growing */
+# define F_SEAL_WRITE 0x0008 /* prevent writes */
+#endif
+
+#define RUNC_SENDFILE_MAX 0x7FFFF000 /* sendfile(2) is limited to 2GB. */
+#ifdef HAVE_MEMFD_CREATE
+# define RUNC_MEMFD_COMMENT "runc_cloned:/proc/self/exe"
+# define RUNC_MEMFD_SEALS \
+ (F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE)
+#endif
+
+static void *must_realloc(void *ptr, size_t size)
+{
+ void *old = ptr;
+ do {
+ ptr = realloc(old, size);
+ } while(!ptr);
+ return ptr;
+}
+
+/*
+ * Verify whether we are currently in a self-cloned program (namely, is
+ * /proc/self/exe a memfd). F_GET_SEALS will only succeed for memfds (or rather
+ * for shmem files), and we want to be sure it's actually sealed.
+ */
+static int is_self_cloned(void)
+{
+ int fd, ret, is_cloned = 0;
+
+ fd = open("/proc/self/exe", O_RDONLY|O_CLOEXEC);
+ if (fd < 0)
+ return -ENOTRECOVERABLE;
+
+#ifdef HAVE_MEMFD_CREATE
+ ret = fcntl(fd, F_GET_SEALS);
+ is_cloned = (ret == RUNC_MEMFD_SEALS);
+#else
+ struct stat statbuf = {0};
+ ret = fstat(fd, &statbuf);
+ if (ret >= 0)
+ is_cloned = (statbuf.st_nlink == 0);
+#endif
+ close(fd);
+ return is_cloned;
+}
+
+/*
+ * Basic wrapper around mmap(2) that gives you the file length so you can
+ * safely treat it as an ordinary buffer. Only gives you read access.
+ */
+static char *read_file(char *path, size_t *length)
+{
+ int fd;
+ char buf[4096], *copy = NULL;
+
+ if (!length)
+ return NULL;
+
+ fd = open(path, O_RDONLY | O_CLOEXEC);
+ if (fd < 0)
+ return NULL;
+
+ *length = 0;
+ for (;;) {
+ int n;
+
+ n = read(fd, buf, sizeof(buf));
+ if (n < 0)
+ goto error;
+ if (!n)
+ break;
+
+ copy = must_realloc(copy, (*length + n) * sizeof(*copy));
+ memcpy(copy + *length, buf, n);
+ *length += n;
+ }
+ close(fd);
+ return copy;
+
+error:
+ close(fd);
+ free(copy);
+ return NULL;
+}
+
+/*
+ * A poor-man's version of "xargs -0". Basically parses a given block of
+ * NUL-delimited data, within the given length and adds a pointer to each entry
+ * to the array of pointers.
+ */
+static int parse_xargs(char *data, int data_length, char ***output)
+{
+ int num = 0;
+ char *cur = data;
+
+ if (!data || *output != NULL)
+ return -1;
+
+ while (cur < data + data_length) {
+ num++;
+ *output = must_realloc(*output, (num + 1) * sizeof(**output));
+ (*output)[num - 1] = cur;
+ cur += strlen(cur) + 1;
+ }
+ (*output)[num] = NULL;
+ return num;
+}
+
+/*
+ * "Parse" out argv and envp from /proc/self/cmdline and /proc/self/environ.
+ * This is necessary because we are running in a context where we don't have a
+ * main() that we can just get the arguments from.
+ */
+static int fetchve(char ***argv, char ***envp)
+{
+ char *cmdline = NULL, *environ = NULL;
+ size_t cmdline_size, environ_size;
+
+ cmdline = read_file("/proc/self/cmdline", &cmdline_size);
+ if (!cmdline)
+ goto error;
+ environ = read_file("/proc/self/environ", &environ_size);
+ if (!environ)
+ goto error;
+
+ if (parse_xargs(cmdline, cmdline_size, argv) <= 0)
+ goto error;
+ if (parse_xargs(environ, environ_size, envp) <= 0)
+ goto error;
+
+ return 0;
+
+error:
+ free(environ);
+ free(cmdline);
+ return -EINVAL;
+}
+
+static int clone_binary(void)
+{
+ int binfd, memfd;
+ ssize_t sent = 0;
+
+#ifdef HAVE_MEMFD_CREATE
+ memfd = memfd_create(RUNC_MEMFD_COMMENT, MFD_CLOEXEC | MFD_ALLOW_SEALING);
+#else
+ memfd = open("/tmp", O_TMPFILE | O_EXCL | O_RDWR | O_CLOEXEC, 0711);
+#endif
+ if (memfd < 0)
+ return -ENOTRECOVERABLE;
+
+ binfd = open("/proc/self/exe", O_RDONLY | O_CLOEXEC);
+ if (binfd < 0)
+ goto error;
+
+ sent = sendfile(memfd, binfd, NULL, RUNC_SENDFILE_MAX);
+ close(binfd);
+ if (sent < 0)
+ goto error;
+
+#ifdef HAVE_MEMFD_CREATE
+ int err = fcntl(memfd, F_ADD_SEALS, RUNC_MEMFD_SEALS);
+ if (err < 0)
+ goto error;
+#else
+ /* Need to re-open "memfd" as read-only to avoid execve(2) giving -EXTBUSY. */
+ int newfd;
+ char *fdpath = NULL;
+
+ if (asprintf(&fdpath, "/proc/self/fd/%d", memfd) < 0)
+ goto error;
+ newfd = open(fdpath, O_RDONLY | O_CLOEXEC);
+ free(fdpath);
+ if (newfd < 0)
+ goto error;
+
+ close(memfd);
+ memfd = newfd;
+#endif
+ return memfd;
+
+error:
+ close(memfd);
+ return -EIO;
+}
+
+int ensure_cloned_binary(void)
+{
+ int execfd;
+ char **argv = NULL, **envp = NULL;
+
+ /* Check that we're not self-cloned, and if we are then bail. */
+ int cloned = is_self_cloned();
+ if (cloned > 0 || cloned == -ENOTRECOVERABLE)
+ return cloned;
+
+ if (fetchve(&argv, &envp) < 0)
+ return -EINVAL;
+
+ execfd = clone_binary();
+ if (execfd < 0)
+ return -EIO;
+
+ fexecve(execfd, argv, envp);
+ return -ENOEXEC;
+}
diff --git a/libcontainer/nsenter/nsexec.c b/libcontainer/nsenter/nsexec.c
index 0ad6883..64ed76f 100644
--- a/libcontainer/nsenter/nsexec.c
+++ b/libcontainer/nsenter/nsexec.c
@@ -432,6 +432,9 @@ void join_namespaces(char *nslist)
free(namespaces);
}
+/* Defined in cloned_binary.c. */
+extern int ensure_cloned_binary(void);
+
void nsexec(void)
{
int pipenum;
@@ -447,6 +450,14 @@ void nsexec(void)
if (pipenum == -1)
return;
+ /*
+ * We need to re-exec if we are not in a cloned binary. This is necessary
+ * to ensure that containers won't be able to access the host binary
+ * through /proc/self/exe. See CVE-2019-5736.
+ */
+ if (ensure_cloned_binary() < 0)
+ bail("could not ensure we are a cloned binary");
+
/* Parse all of the netlink configuration. */
nl_parse(pipenum, &config);
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index b3db2ab..2448078 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 19%{?dist}
+Release: 20%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
--
2.7.4.3

View File

@ -0,0 +1,207 @@
From 621c01059536ec167da8c9d5571e8bf860b4dadb Mon Sep 17 00:00:00 2001
From: wangfengtu <wangfengtu@huawei.com>
Date: Wed, 13 Feb 2019 05:26:38 -0500
Subject: [PATCH 91/94] runc: cve-2019-5736: workaround if
memfd_create and O_TMPFILE not work
[Changelog]: create tmpfile using mkostemp when memfd_create and
O_TMPFILE not work
[Author]: git
Change-Id: I785295b19759487ddaa5e0dcb5c11e4aa9ace838
Signed-off-by: sdu.liu <sdu.liu@huawei.com>
Signed-off-by: wangfengtu <wangfengtu@huawei.com>
---
libcontainer/nsenter/cloned_binary.c | 117 +++++++++++++++++++++++++----------
script/runc-euleros.spec | 2 +-
2 files changed, 87 insertions(+), 32 deletions(-)
diff --git a/libcontainer/nsenter/cloned_binary.c b/libcontainer/nsenter/cloned_binary.c
index c8a42c2..e59d434 100644
--- a/libcontainer/nsenter/cloned_binary.c
+++ b/libcontainer/nsenter/cloned_binary.c
@@ -71,6 +71,14 @@ int memfd_create(const char *name, unsigned int flags)
(F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE)
#endif
+enum clone_type
+{
+ USING_MEMFD = 0,
+ USING_UNAMED_FILE,
+ USING_TMPFILE,
+};
+
+
static void *must_realloc(void *ptr, size_t size)
{
void *old = ptr;
@@ -80,6 +88,23 @@ static void *must_realloc(void *ptr, size_t size)
return ptr;
}
+static int get_clone_type()
+{
+ int memfd = 0;
+#ifdef HAVE_MEMFD_CREATE
+ memfd = memfd_create(RUNC_MEMFD_COMMENT, MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ if (memfd > 0 || memfd == 0) {
+ close(memfd);
+ return USING_MEMFD;
+ }
+#else
+#ifdef O_TMPFILE
+ return USING_UNAMED_FILE;
+#endif
+#endif
+ return USING_TMPFILE;
+}
+
/*
* Verify whether we are currently in a self-cloned program (namely, is
* /proc/self/exe a memfd). F_GET_SEALS will only succeed for memfds (or rather
@@ -87,21 +112,23 @@ static void *must_realloc(void *ptr, size_t size)
*/
static int is_self_cloned(void)
{
- int fd, ret, is_cloned = 0;
+ int fd, ret, type, is_cloned = 0;
fd = open("/proc/self/exe", O_RDONLY|O_CLOEXEC);
if (fd < 0)
return -ENOTRECOVERABLE;
+ type = get_clone_type();
+
+ if (type == USING_MEMFD) {
+ ret = fcntl(fd, F_GET_SEALS);
+ is_cloned = (ret == RUNC_MEMFD_SEALS);
+ } else {
+ struct stat statbuf = {0};
+ ret = fstat(fd, &statbuf);
+ if (ret >= 0)
+ is_cloned = (statbuf.st_nlink == 0);
+ }
-#ifdef HAVE_MEMFD_CREATE
- ret = fcntl(fd, F_GET_SEALS);
- is_cloned = (ret == RUNC_MEMFD_SEALS);
-#else
- struct stat statbuf = {0};
- ret = fstat(fd, &statbuf);
- if (ret >= 0)
- is_cloned = (statbuf.st_nlink == 0);
-#endif
close(fd);
return is_cloned;
}
@@ -198,16 +225,37 @@ error:
return -EINVAL;
}
+
static int clone_binary(void)
{
int binfd, memfd;
ssize_t sent = 0;
+ char template[] = "/tmp/runc.XXXXXX";
+ int type = 0;
+ char *tmpfile = NULL;
+
+ type = get_clone_type();
+ switch (type) {
+ case USING_MEMFD:
+ memfd = memfd_create(RUNC_MEMFD_COMMENT, MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ break;
+ case USING_UNAMED_FILE:
+ memfd = open("/tmp", O_TMPFILE | O_EXCL | O_RDWR | O_CLOEXEC, 0711);
+ break;
+ case USING_TMPFILE:
+ memfd = mkostemp(template,O_EXCL | O_RDWR | O_CLOEXEC);
+ if (memfd < 0) {
+ goto error;
+ }
+ tmpfile = template;
+ if (fchmod(memfd, 0711)) {
+ goto error;
+ }
+ break;
+ default:
+ return -ENOTRECOVERABLE;
+ }
-#ifdef HAVE_MEMFD_CREATE
- memfd = memfd_create(RUNC_MEMFD_COMMENT, MFD_CLOEXEC | MFD_ALLOW_SEALING);
-#else
- memfd = open("/tmp", O_TMPFILE | O_EXCL | O_RDWR | O_CLOEXEC, 0711);
-#endif
if (memfd < 0)
return -ENOTRECOVERABLE;
@@ -220,29 +268,36 @@ static int clone_binary(void)
if (sent < 0)
goto error;
-#ifdef HAVE_MEMFD_CREATE
- int err = fcntl(memfd, F_ADD_SEALS, RUNC_MEMFD_SEALS);
- if (err < 0)
- goto error;
-#else
+ if (type == USING_MEMFD) {
+ int err = fcntl(memfd, F_ADD_SEALS, RUNC_MEMFD_SEALS);
+ if (err < 0)
+ goto error;
+ } else {
/* Need to re-open "memfd" as read-only to avoid execve(2) giving -EXTBUSY. */
- int newfd;
- char *fdpath = NULL;
+ int newfd;
+ char *fdpath = NULL;
- if (asprintf(&fdpath, "/proc/self/fd/%d", memfd) < 0)
- goto error;
- newfd = open(fdpath, O_RDONLY | O_CLOEXEC);
- free(fdpath);
- if (newfd < 0)
- goto error;
+ if (asprintf(&fdpath, "/proc/self/fd/%d", memfd) < 0)
+ goto error;
+ newfd = open(fdpath, O_RDONLY | O_CLOEXEC);
+ free(fdpath);
+ if (newfd < 0)
+ goto error;
+ close(memfd);
- close(memfd);
- memfd = newfd;
-#endif
+ memfd = newfd;
+ }
+
+ if(tmpfile) {
+ remove(tmpfile);
+ }
return memfd;
error:
close(memfd);
+ if(tmpfile) {
+ remove(tmpfile);
+ }
return -EIO;
}
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index 2448078..b577d1a 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 20%{?dist}
+Release: 21%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
--
2.7.4.3

View File

@ -0,0 +1,47 @@
From 096172d15e1d29ba177a39d8ded3ca6b5b1c0ac4 Mon Sep 17 00:00:00 2001
From: wangfengtu <wangfengtu@huawei.com>
Date: Thu, 14 Feb 2019 00:08:01 +0800
Subject: [PATCH 92/94] runc: cve-2019-5736 fix build failure
[Changelog]: fix build failure
[Author]: git
Change-Id: Ie422758618726d9e98a7f9ec9a14e34d4479251f
Signed-off-by: wangfengtu <wangfengtu@huawei.com>
---
libcontainer/nsenter/cloned_binary.c | 2 ++
script/runc-euleros.spec | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/libcontainer/nsenter/cloned_binary.c b/libcontainer/nsenter/cloned_binary.c
index e59d434..ff7ecb0 100644
--- a/libcontainer/nsenter/cloned_binary.c
+++ b/libcontainer/nsenter/cloned_binary.c
@@ -239,9 +239,11 @@ static int clone_binary(void)
case USING_MEMFD:
memfd = memfd_create(RUNC_MEMFD_COMMENT, MFD_CLOEXEC | MFD_ALLOW_SEALING);
break;
+#ifdef O_TMPFILE
case USING_UNAMED_FILE:
memfd = open("/tmp", O_TMPFILE | O_EXCL | O_RDWR | O_CLOEXEC, 0711);
break;
+#endif
case USING_TMPFILE:
memfd = mkostemp(template,O_EXCL | O_RDWR | O_CLOEXEC);
if (memfd < 0) {
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index b577d1a..6e96326 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 21%{?dist}
+Release: 22%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
--
2.7.4.3

View File

@ -0,0 +1,46 @@
From 20ce68df5145a8c56a53322fcf8c6a149d9df535 Mon Sep 17 00:00:00 2001
From: zhangyu235 <zhangyu235@huawei.com>
Date: Sun, 24 Feb 2019 17:49:09 +0800
Subject: [PATCH 93/94] runc: fix error when check the init process
reason:We shoule ensure the porcess is still the original init process
using doesInitProcessExist(). But it could happen when the process exited
just when we call function doesInitProcessExist(). Due to this reason,
we shoule not return error in this case.
Change-Id: If515af5beed73adf19b2c31eae919c5a39911a18
Signed-off-by: zhangyu235 <zhangyu235@huawei.com>
---
libcontainer/container_linux.go | 2 +-
script/runc-euleros.spec | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 8100aca..5a3705e 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -1411,7 +1411,7 @@ func (c *linuxContainer) refreshState() error {
func (c *linuxContainer) doesInitProcessExist(initPid int) (bool, error) {
startTime, err := system.GetProcessStartTime(initPid)
if err != nil {
- return false, newSystemErrorWithCausef(err, "getting init process %d start time", initPid)
+ return false, nil
}
if c.initProcessStartTime != startTime {
return false, nil
diff --git a/script/runc-euleros.spec b/script/runc-euleros.spec
index 6e96326..09be036 100644
--- a/script/runc-euleros.spec
+++ b/script/runc-euleros.spec
@@ -2,7 +2,7 @@
Name: docker-runc
Version: 1.0.0.rc3
-Release: 22%{?dist}
+Release: 23%{?dist}
Summary: runc is a CLI tool for spawning and running containers according to the OCF specification
License: ASL 2.0
--
2.7.4.3

View File

@ -0,0 +1,30 @@
From 662893f67295028a128885544d4a0ee25491da95 Mon Sep 17 00:00:00 2001
From: wangfengtu <wangfengtu@huawei.com>
Date: Sat, 2 Mar 2019 19:51:08 +0800
Subject: [PATCH 94/94] runc: If /tmp is mounted by option
noexec,docker run will fail
reason: Change /tmp to /run for storage temporary runc
Change-Id: Ia442b489dc1b57c6e4fd720b98b5061f83a88214
Signed-off-by: wangfengtu <wangfengtu@huawei.com>
---
libcontainer/nsenter/cloned_binary.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libcontainer/nsenter/cloned_binary.c b/libcontainer/nsenter/cloned_binary.c
index ff7ecb0..8e8b70e 100644
--- a/libcontainer/nsenter/cloned_binary.c
+++ b/libcontainer/nsenter/cloned_binary.c
@@ -230,7 +230,7 @@ static int clone_binary(void)
{
int binfd, memfd;
ssize_t sent = 0;
- char template[] = "/tmp/runc.XXXXXX";
+ char template[] = "/run/runc.XXXXXX";
int type = 0;
char *tmpfile = NULL;
--
2.7.4.3

View File

@ -0,0 +1,50 @@
From a854b14193b62c93bd62ccddebca29a77c8c07a2 Mon Sep 17 00:00:00 2001
From: zhangsong34 <zhangsong34@huawei.com>
Date: Fri, 8 Mar 2019 14:32:39 +0800
Subject: [PATCH] runc: just warning when poststart and poststop
failed
reason:just warning when poststart and poststop failed.
Change-Id: I65e816c344506bbf9ea2f8c5ff4dc2d47cc0a35e
Signed-off-by: mashimiao <mashimiao@huawei.com>
Signed-off-by: zhangsong34 <zhangsong34@huawei.com>
---
libcontainer/container_linux.go | 3 +--
libcontainer/state_linux.go | 3 +--
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 5a3705e..1f587c7 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -341,11 +341,10 @@ func (c *linuxContainer) start(process *Process) error {
for i, hook := range c.config.Hooks.Poststart {
logrus.Infof("run poststart hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
if err := hook.Run(s); err != nil {
- logrus.Errorf("running poststart hook(%d:%s) failed: %s", i, hook.Info(), err)
+ logrus.Warnf("running poststart hook %d:%s failed: %s, ContainerId: %s", i, hook.Info(), err, s.ID)
if err := parent.terminate(); err != nil {
logrus.Warnf("run poststart hook failed: %s, ContainerID: %s", err, s.ID)
}
- return newSystemErrorWithCausef(err, "running poststart hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
}
}
}
diff --git a/libcontainer/state_linux.go b/libcontainer/state_linux.go
index 6fa62c0..b570a24 100644
--- a/libcontainer/state_linux.go
+++ b/libcontainer/state_linux.go
@@ -68,8 +68,7 @@ func runPoststopHooks(c *linuxContainer) error {
for i, hook := range c.config.Hooks.Poststop {
logrus.Infof("run poststop hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
if err := hook.Run(s); err != nil {
- logrus.Errorf("running poststop hook %d: %s failed: %s", i, hook.Info(), err)
- return newSystemErrorWithCausef(err, "running poststop hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
+ logrus.Warnf("running poststop hook %d:%s failed: %s, ContainerID: %s", i, hook.Info(), err, s.ID)
}
}
}
--
1.8.3.1

View File

@ -0,0 +1,31 @@
From 5a4335581b0ccf28342f3e48639ba38b611a02fe Mon Sep 17 00:00:00 2001
From: zhangsong34 <zhangsong34@huawei.com>
Date: Wed, 13 Mar 2019 15:40:12 +0800
Subject: [PATCH] runc: do not kill container if poststart hooks
execute failed
reason:do not kill container if poststart hooks execute failed.
Change-Id: Ieb1e1e7eeefe4bbd3cdb38fbba5a2a003297a5b3
Signed-off-by: zhangsong34 <zhangsong34@huawei.com>
---
libcontainer/container_linux.go | 3 ---
1 file changed, 3 deletions(-)
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 1f587c7..914da7f 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -342,9 +342,6 @@ func (c *linuxContainer) start(process *Process) error {
logrus.Infof("run poststart hook %d:%s, ContainerID: %s", i, hook.Info(), s.ID)
if err := hook.Run(s); err != nil {
logrus.Warnf("running poststart hook %d:%s failed: %s, ContainerId: %s", i, hook.Info(), err, s.ID)
- if err := parent.terminate(); err != nil {
- logrus.Warnf("run poststart hook failed: %s, ContainerID: %s", err, s.ID)
- }
}
}
}
--
1.8.3.1

View File

@ -0,0 +1,120 @@
From 0b0bb50e4ecdebfb2646adb57e53972663947320 Mon Sep 17 00:00:00 2001
From: wangfengtu <wangfengtu@huawei.com>
Date: Wed, 27 Mar 2019 15:28:03 +0800
Subject: [PATCH] runc: Fix mountpoint leak and pivot_root error
reason:We have no way to get exact /proc/self/mountinfo infomation
because it can change if other process mount/umount mountpoint. So
runc sometimes cannot get container's mountpoint when runc try to
make mountpoint private. This can cause mountpoint leak and pivot_root
error, runc error out like this:
```
Handler for POST
/v1.23/containers/1d265651cb1d5475bcb7d5db21679757d5527d44a41c102c6aa4bddaa518c547/start
returned error: oci runtime error: container_linux.go:317: starting
container process caused \"process_linux.go:358: container init caused
\\\"rootfs_linux.go:105: jailing process inside rootfs caused
\\\\\\\"pivot_root invalid argument\\\\\\\"\\\"\"\n
```
Change-Id: Icde1638af6ad45c762c11fc8a2b8a969b6306ca5
Signed-off-by: wangfengtu <wangfengtu@huawei.com>
---
libcontainer/rootfs_linux.go | 32 ++++++++++++----------
.../docker/docker/pkg/mount/mountinfo_linux.go | 7 +++--
2 files changed, 21 insertions(+), 18 deletions(-)
diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go
index 3dd5113..53797e9 100644
--- a/libcontainer/rootfs_linux.go
+++ b/libcontainer/rootfs_linux.go
@@ -24,7 +24,10 @@ import (
"github.com/opencontainers/selinux/go-selinux/label"
)
-const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
+const (
+ defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
+ maxRetryTimes = 5
+)
// needsSetupDev returns true if /dev needs to be set up.
func needsSetupDev(config *configs.Config) bool {
@@ -545,23 +548,16 @@ func getMountInfo(mountinfo []*mount.Info, dir string) *mount.Info {
// Get the parent mount point of directory passed in as argument. Also return
// optional fields.
func getParentMount(rootfs string) (string, string, error) {
- var path string
-
- mountinfos, err := mount.GetMounts()
- if err != nil {
- return "", "", err
- }
-
- mountinfo := getMountInfo(mountinfos, rootfs)
- if mountinfo != nil {
- return rootfs, mountinfo.Optional, nil
- }
+ retryTimes := maxRetryTimes
+ path := rootfs
- path = rootfs
for {
- path = filepath.Dir(path)
+ mountinfos, err := mount.GetMounts()
+ if err != nil {
+ return "", "", err
+ }
- mountinfo = getMountInfo(mountinfos, path)
+ mountinfo := getMountInfo(mountinfos, path)
if mountinfo != nil {
return path, mountinfo.Optional, nil
}
@@ -569,6 +565,12 @@ func getParentMount(rootfs string) (string, string, error) {
if path == "/" {
break
}
+
+ retryTimes--
+ if retryTimes == 0 {
+ retryTimes = maxRetryTimes
+ path = filepath.Dir(path)
+ }
}
// If we are here, we did not find parent mount. Something is wrong.
diff --git a/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go b/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go
index be69fee..b74773f 100644
--- a/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go
+++ b/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go
@@ -4,8 +4,10 @@ package mount
import (
"bufio"
+ "bytes"
"fmt"
"io"
+ "io/ioutil"
"os"
"strings"
)
@@ -31,13 +33,12 @@ const (
// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
// bind mounts
func parseMountTable() ([]*Info, error) {
- f, err := os.Open("/proc/self/mountinfo")
+ content, err := ioutil.ReadFile("/proc/self/mountinfo")
if err != nil {
return nil, err
}
- defer f.Close()
- return parseInfoFile(f)
+ return parseInfoFile(bytes.NewReader(content))
}
func parseInfoFile(r io.Reader) ([]*Info, error) {
--
2.7.4

View File

@ -0,0 +1,40 @@
From 6e35f145221347264ea5d4814308ab0624725024 Mon Sep 17 00:00:00 2001
From: zhangsong34 <zhangsong34@huawei.com>
Date: Tue, 2 Apr 2019 10:00:20 +0800
Subject: [PATCH] runc: fix --read-only containers under
--userns-remap
reason:fix --read-only containers under --userns-remap
cherry-pick from:
https://github.com/opencontainers/runc/pull/1572
Change-Id: I0f823caf1e72e4d61df9abe5f97fa5605425fd2c
Signed-off-by: Tycho Andersen <tycho@docker.com>
Signed-off-by: zhangsong34 <zhangsong34@huawei.com>
---
libcontainer/rootfs_linux.go | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go
index 53797e9..18a25f2 100644
--- a/libcontainer/rootfs_linux.go
+++ b/libcontainer/rootfs_linux.go
@@ -769,7 +769,14 @@ func remountReadonly(m *configs.Mount) error {
flags = m.Flags
)
for i := 0; i < 5; i++ {
- if err := syscall.Mount("", dest, "", uintptr(flags|syscall.MS_REMOUNT|syscall.MS_RDONLY), ""); err != nil {
+ // There is a special case in the kernel for
+ // MS_REMOUNT | MS_BIND, which allows us to change only the
+ // flags even as an unprivileged user (i.e. user namespace)
+ // assuming we don't drop any security related flags (nodev,
+ // nosuid, etc.). So, let's use that case so that we can do
+ // this re-mount without failing in a userns.
+ flags |= syscall.MS_REMOUNT | syscall.MS_BIND | syscall.MS_RDONLY
+ if err := syscall.Mount("", dest, "", uintptr(flags), ""); err != nil {
switch err {
case syscall.EBUSY:
time.Sleep(100 * time.Millisecond)
--
1.8.3.1

View File

@ -0,0 +1,49 @@
From e2d3a9925386b07e15db79ceee1e5430eed13c26 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Thu, 11 Apr 2019 23:32:01 +0800
Subject: [PATCH] runc: enable bep ldflags
Change-Id: I9221cb54e470b6c511f7962294bf405de00549c7
Signed-off-by: jingrui <jingrui@huawei.com>
---
Makefile | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/Makefile b/Makefile
index f043d0bc..76423d83 100644
--- a/Makefile
+++ b/Makefile
@@ -24,21 +24,26 @@ VERSION := ${shell cat ./VERSION}
SHELL := $(shell command -v bash 2>/dev/null)
+BEP_DIR := "/tmp/runc-build-bep"
+BEP_FLAG := "-tmpdir=${BEP_DIR}"
+
.DEFAULT: runc
runc: $(SOURCES)
- go build -i -ldflags "-X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -tags "$(BUILDTAGS)" -o runc .
+ mkdir -p ${BEP_DIR}
+ go build -i -ldflags " ${BEP_FLAG} -X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -tags "$(BUILDTAGS)" -o runc .
all: runc recvtty
recvtty: contrib/cmd/recvtty/recvtty
contrib/cmd/recvtty/recvtty: $(SOURCES)
- go build -i -ldflags "-X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -tags "$(BUILDTAGS)" -o contrib/cmd/recvtty/recvtty ./contrib/cmd/recvtty
+ go build -i -ldflags " ${BEP_FLAG} -X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -tags "$(BUILDTAGS)" -o contrib/cmd/recvtty/recvtty ./contrib/cmd/recvtty
static: $(SOURCES)
- CGO_ENABLED=1 go build -i -tags "$(BUILDTAGS) cgo static_build" -ldflags "-w -extldflags -static -X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -o runc .
- CGO_ENABLED=1 go build -i -tags "$(BUILDTAGS) cgo static_build" -ldflags "-w -extldflags -static -X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -o contrib/cmd/recvtty/recvtty ./contrib/cmd/recvtty
+ mkdir -p ${BEP_DIR}
+ CGO_ENABLED=1 go build -i -tags "$(BUILDTAGS) cgo static_build" -ldflags "-w -extldflags -static ${BEP_FLAG} -X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -o runc .
+ CGO_ENABLED=1 go build -i -tags "$(BUILDTAGS) cgo static_build" -ldflags "-w -extldflags -static ${BEP_FLAG} -X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -o contrib/cmd/recvtty/recvtty ./contrib/cmd/recvtty
release:
@flag_list=(seccomp selinux apparmor static); \
--
2.17.1

View File

@ -0,0 +1,44 @@
From 0a64bd10e05937427255dada4b6e1b12f31265f0 Mon Sep 17 00:00:00 2001
From: xiadanni1 <xiadanni1@huawei.com>
Date: Tue, 23 Apr 2019 22:35:45 +0800
Subject: [PATCH] runc: set makefile buildid
reason: set makefile buildid
Change-Id: Ia547dbc383bffe6532168881a7376df1d990fd30
Signed-off-by: xiadanni1 <xiadanni1@huawei.com>
---
Makefile | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Makefile b/Makefile
index 76423d8..0352e40 100644
--- a/Makefile
+++ b/Makefile
@@ -31,19 +31,19 @@ BEP_FLAG := "-tmpdir=${BEP_DIR}"
runc: $(SOURCES)
mkdir -p ${BEP_DIR}
- go build -i -ldflags " ${BEP_FLAG} -X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -tags "$(BUILDTAGS)" -o runc .
+ go build -i -ldflags " -buildid=IdByIsula ${BEP_FLAG} -X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -tags "$(BUILDTAGS)" -o runc .
all: runc recvtty
recvtty: contrib/cmd/recvtty/recvtty
contrib/cmd/recvtty/recvtty: $(SOURCES)
- go build -i -ldflags " ${BEP_FLAG} -X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -tags "$(BUILDTAGS)" -o contrib/cmd/recvtty/recvtty ./contrib/cmd/recvtty
+ go build -i -ldflags " -buildid=IdByIsula ${BEP_FLAG} -X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -tags "$(BUILDTAGS)" -o contrib/cmd/recvtty/recvtty ./contrib/cmd/recvtty
static: $(SOURCES)
mkdir -p ${BEP_DIR}
- CGO_ENABLED=1 go build -i -tags "$(BUILDTAGS) cgo static_build" -ldflags "-w -extldflags -static ${BEP_FLAG} -X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -o runc .
- CGO_ENABLED=1 go build -i -tags "$(BUILDTAGS) cgo static_build" -ldflags "-w -extldflags -static ${BEP_FLAG} -X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -o contrib/cmd/recvtty/recvtty ./contrib/cmd/recvtty
+ CGO_ENABLED=1 go build -i -tags "$(BUILDTAGS) cgo static_build" -ldflags "-w -buildid=IdByIsula -extldflags -static ${BEP_FLAG} -X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -o runc .
+ CGO_ENABLED=1 go build -i -tags "$(BUILDTAGS) cgo static_build" -ldflags "-w -buildid=IdByIsula -extldflags -static ${BEP_FLAG} -X main.gitCommit=${COMMIT} -X main.version=${VERSION}" -o contrib/cmd/recvtty/recvtty ./contrib/cmd/recvtty
release:
@flag_list=(seccomp selinux apparmor static); \
--
1.8.3.1

View File

@ -0,0 +1,63 @@
From 574f88a1801656869b69408cf2eb0f32c6c0e4aa Mon Sep 17 00:00:00 2001
From: xiadanni1 <xiadanni1@huawei.com>
Date: Mon, 6 May 2019 02:49:36 +0800
Subject: [PATCH] runc: print memory info when syscall.Exec failed
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
reason: print system and cgroup memory info when syscall.Exec failed.
Change-Id: I4aef0ea3da16849ab82adf45db5a828c758b33ea
Signed-off-by: xiadanni1 <xiadanni1@huawei.com>
---
libcontainer/standard_init_linux.go | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/libcontainer/standard_init_linux.go b/libcontainer/standard_init_linux.go
index fd836f3..b25669f 100644
--- a/libcontainer/standard_init_linux.go
+++ b/libcontainer/standard_init_linux.go
@@ -4,12 +4,14 @@ package libcontainer
import (
"fmt"
+ "io/ioutil"
"os"
"os/exec"
"strings"
"syscall"
"time"
+ "github.com/Sirupsen/logrus"
"github.com/opencontainers/runc/libcontainer/apparmor"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/keys"
@@ -212,7 +214,24 @@ func (l *linuxStandardInit) Init() error {
// https://github.com/torvalds/linux/blob/v4.9/fs/exec.c#L1290-L1318
syscall.Close(l.stateDirFD)
if err := syscall.Exec(name, l.config.Args[0:], os.Environ()); err != nil {
+ printMemoryInfo()
return newSystemErrorWithCause(err, "exec user process")
}
return nil
}
+
+func printMemoryInfo() {
+ output, err := ioutil.ReadFile("/proc/meminfo")
+ if err != nil {
+ logrus.Errorf("Failed to read /proc/meminfo, %v", err)
+ } else {
+ logrus.Infof("print memory info (/proc/meminfo): %s", string(output))
+ }
+
+ output, err = ioutil.ReadFile("/sys/fs/cgroup/memory/memory.stat")
+ if err != nil {
+ logrus.Errorf("Failed to read /sys/fs/cgroup/memory/memory.stat, %v", err)
+ } else {
+ logrus.Infof("print memory info (cgroup memory.stat): %s", string(output))
+ }
+}
--
1.8.3.1

Some files were not shown because too many files have changed in this diff Show More