Commit Graph

1959 Commits

Author SHA1 Message Date
Kir Kolyshkin ff692f289b Fix cgroup2 mount for rootless case
In case of rootless, cgroup2 mount is not possible (see [1] for more
details), so since commit 9c81440fb5 runc bind-mounts the whole
/sys/fs/cgroup into container.

Problem is, if cgroupns is enabled, /sys/fs/cgroup inside the container
is supposed to show the cgroup files for this cgroup, not the root one.

The fix is to pass through and use the cgroup path in case cgroup2
mount failed, cgroupns is enabled, and the path is non-empty.

Surely this requires the /sys/fs/cgroup mount in the spec, so modify
runc spec --rootless to keep it.

Before:

	$ ./runc run aaa
	# find /sys/fs/cgroup/ -type d
	/sys/fs/cgroup
	/sys/fs/cgroup/user.slice
	/sys/fs/cgroup/user.slice/user-1000.slice
	/sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service
	...
	# ls -l /sys/fs/cgroup/cgroup.controllers
	-r--r--r--    1 nobody   nogroup          0 Feb 24 02:22 /sys/fs/cgroup/cgroup.controllers
	# wc -w /sys/fs/cgroup/cgroup.procs
	142 /sys/fs/cgroup/cgroup.procs
	# cat /sys/fs/cgroup/memory.current
	cat: can't open '/sys/fs/cgroup/memory.current': No such file or directory

After:

	# find /sys/fs/cgroup/ -type d
	/sys/fs/cgroup/
	# ls -l /sys/fs/cgroup/cgroup.controllers
	-r--r--r--    1 root     root             0 Feb 24 02:43 /sys/fs/cgroup/cgroup.controllers
	# wc -w /sys/fs/cgroup/cgroup.procs
	2 /sys/fs/cgroup/cgroup.procs
	# cat /sys/fs/cgroup/memory.current
	577536

[1] https://github.com/opencontainers/runc/issues/2158

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-20 12:35:40 -07:00
Kir Kolyshkin 3826db196d libct/rootfs/mountCgroupV2: minor refactor
1. s/cgroupPath/dest/

2. don't hardcode /sys/fs/cgroup

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-20 12:30:30 -07:00
Kir Kolyshkin 1e476578b6 libct/rootfs: introduce and use mountConfig
The code is already passing three parameters around from
mountToRootfs to mountCgroupV* to mountToRootfs again.

I am about to add another parameter, so let's introduce and
use struct mountConfig to pass around.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-20 12:30:06 -07:00
Kir Kolyshkin deb8a8dd77 libct/newInitConfig: nit
Move the initialization of Console* fields as they are unconditional.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-20 12:30:02 -07:00
Sebastiaan van Stijn 73f22e7f1a libcontainer/cgroups/systemd: replace use of deprecated dbus.New()
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-04-20 14:07:23 +02:00
Akihiro Suda ba257d2de8 Merge pull request #2873 from kolyshkin/mem-root-cgroup2
libct/cg/fs2.GetStats() improvements
2021-04-19 13:59:14 +09:00
Akihiro Suda 79e097c65f Merge pull request #2912 from odinuge/cgv2-cfs
Add cfs throttle stats to cgroup v2
2021-04-19 13:10:04 +09:00
Mrunal Patel 3a20ccbe59 Merge pull request #2897 from kolyshkin/fix-ro-paths
runc run: fix readonly path error for rootless + host pidns
2021-04-18 21:07:22 -07:00
Odin Ugedal ee3b563de7 Add cfs throttle stats to cgroup v2
Signed-off-by: Odin Ugedal <odin@uged.al>
2021-04-16 13:41:22 +02:00
Kir Kolyshkin ef9922c26c libct/cg: don't return OOMKillCount error when rootless
Commit 5d0ffbf9c8 added OOM kill count checking and better container
start/run/exec error reporting in case we hit OOM.

It also introduced warnings like these:

> level=warning msg="unable to get oom kill count" error="openat2
> /sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/test_hello/memory.events:
> no such file or directory"

In case of rootless containers, unless cgroup is delegated or systemd is
used, runc can not create a cgroup and thus it fails to get OOM kill
count. This is expected, and the warning should not be shown in this
case.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-14 17:57:00 -07:00
Kir Kolyshkin 5cdd9022a9 libct/cg/fs[2]: fix comments about m.rootless
For fs, commit fc620fdf81 made rootless field private,
and for fs2, it was always private, and yet comments in both
mention it as m.Rootless.

Fix it.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-14 17:44:22 -07:00
Kir Kolyshkin a2050ea471 runc run: fix start for rootless + host pidns
Currently, runc fails like this when used from rootless podman
with host PID namespace:

> $ podman --runtime=runc run --pid=host --rm -it busybox sh
> WARN[0000] additional gid=10 is not present in the user namespace, skip setting it
> Error: container_linux.go:380: starting container process caused:
> process_linux.go:545: container init caused: readonly path /proc/asound:
> operation not permitted: OCI permission denied

(Here /proc/asound is the first path from OCI spec's readonlyPaths).

The code uses MS_BIND|MS_REMOUNT flags that have a special meaning in
the kernel ("keep the flags like nodev, nosuid, noexec as is").
For some reason, this "special meaning" trick is not working for the
above use case (rootless podman + no PID namespace), and I don't know
how to reproduce this without podman.

Instead of relying on the kernel feature, let's just get the current
mount flags using fstatfs(2) and add those that needs to be preserved.

While at it, wrap errors from unix.Mount into os.PathError to make
errors a bit less cryptic.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-14 17:32:08 -07:00
Sebastiaan van Stijn f28a8cc28c ebpf: replace deprecated prog.Attach/prog.Detach
Caught by golangci-lint when enabling golint:

    libcontainer/cgroups/ebpf/ebpf.go:35:12: SA1019: prog.Attach is deprecated: use link.RawAttachProgram instead. (staticcheck)
        if err := prog.Attach(dirFD, ebpf.AttachCGroupDevice, unix.BPF_F_ALLOW_MULTI); err != nil {
                  ^
    libcontainer/cgroups/ebpf/ebpf.go:39:13: SA1019: prog.Detach is deprecated: use link.RawDetachProgram instead. (staticcheck)
            if err := prog.Detach(dirFD, ebpf.AttachCGroupDevice, unix.BPF_F_ALLOW_MULTI); err != nil {
                      ^

Worth noting that we currently call prog.Detach() with unix.BPF_F_ALLOW_MULTI;
https://github.com/golang/sys/blob/22da62e12c0cd9c1da93581e1113ca4d82a5be14/unix/zerrors_linux.go#L178

    BPF_F_ALLOW_MULTI = 0x2

Looking at the source code for prog.Detach(); https://github.com/cilium/ebpf/blob/v0.4.0/prog.go#L579-L581,
this would _always_ produce an error:

    if flags != 0 {
        return errors.New("flags must be zero")
    }

Note that the flags parameter is not used (except for that validation)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-04-13 12:27:39 +02:00
Qiang Huang 2d38476c96 Merge pull request #2840 from kolyshkin/ignore-kmem
Ignore kernel memory settings
2021-04-13 09:44:14 +08:00
Aleksa Sarai 14ce8be9b1 merge branch 'pr-2836'
Aleksa Sarai (1):
  nsenter: improve debug logging

Kir Kolyshkin (1):
  libct/nsenter: add json msg escaping

LGTMs: mrunalp cyphar
Closes #2836
2021-04-13 10:55:57 +10:00
Mrunal Patel 23f6ca80d5 Merge pull request #2900 from LiangZhou-CTY/patch-1
fix a typo
2021-04-12 17:42:51 -07:00
Kir Kolyshkin 928ef7afac libct/nsenter: add json msg escaping
Since the previous commit, some strings logged by write_log() contain a
literal newline, which leads to errors like this one:

> # time="2020-06-07T15:41:37Z" level=error msg="failed to decode \"{\\\"level\\\":\\\"debug\\\", \\\"msg\\\": \\\"nsexec-0[2265]: update /proc/2266/uid_map to '0 1000 1\\n\" to json: invalid character '\\n' in string literal"

The fix is to escape such characters.

Add a simple (as much as it can be) routine which implements JSON string
escaping as required by RFC4627, section 2.5, plus escaping of DEL (0x7f)
character (not required, but allowed by the standard, and usually done
by tools such as jq).

As much as I hate to code something like this, I was not able to find
a ready to consume and decent C implementation (not using glib).

Added a test case (and some additional asserts in C code, conditionally
enabled by the test case) to make sure the implementation is correct.
The test case have to live in a separate directory so we can use
different C flags to compile the test, and use C from go test.

[v2: try to simplify the code, add more tests]
[v3: don't do exit(1), try returning an error instead]

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-12 16:47:26 -07:00
Kir Kolyshkin 52390d6804 Ignore kernel memory settings
This is somewhat radical approach to deal with kernel memory.

Per-cgroup kernel memory limiting was always problematic. A few
examples:

 - older kernels had bugs and were even oopsing sometimes (best example
   is RHEL7 kernel);
 - kernel is unable to reclaim the kernel memory so once the limit is
   hit a cgroup is toasted;
 - some kernel memory allocations don't allow failing.

In addition to that,

 - users don't have a clue about how to set kernel memory limits
   (as the concept is much more complicated than e.g. [user] memory);
 - different kernels might have different kernel memory usage,
   which is sort of unexpected;
 - cgroup v2 do not have a [dedicated] kmem limit knob, and thus
   runc silently ignores kernel memory limits for v2;
 - kernel v5.4 made cgroup v1 kmem.limit obsoleted (see
   https://github.com/torvalds/linux/commit/0158115f702b).

In view of all this, and as the runtime-spec lists memory.kernel
and memory.kernelTCP as OPTIONAL, let's ignore kernel memory
limits (for cgroup v1, same as we're already doing for v2).

This should result in less bugs and better user experience.

The only bad side effect from it might be that stat can show kernel
memory usage as 0 (since the accounting is not enabled).

[v2: add a warning in specconv that limits are ignored]

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-12 12:18:11 -07:00
Akihiro Suda 6023d635d7 Merge pull request #2844 from kolyshkin/sd-cg-docs 2021-04-13 04:12:34 +09:00
Liang Zhou b6cdb8ae09 fix a typo
Signed-off-by: Liang Zhou <zhoul110@chinatelecom.cn>
2021-04-11 09:40:21 +08:00
Kir Kolyshkin b23315bdd9 Merge pull request #2850 from thaJeztah/userns_check
libcontainer/system: move userns utilities, remove `GetParentNSeuid`, `UIDMapInUserNS`
2021-04-08 10:12:05 -07:00
Aleksa Sarai 64bb59f592 nsenter: improve debug logging
In order to make 'runc --debug' actually useful for debugging nsexec
bugs, provide information about all the internal operations when in
debug mode.

[@kolyshkin: rebasing; fix formatting via indent for make validate to pass]

Signed-off-by: Aleksa Sarai <asarai@suse.de>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-08 09:54:43 -07:00
Peter Hunt 6ce2d63a5d libct/init_linux: retry chdir to fix EPERM
Alas, the EPERM on chdir saga continues...

Unfortunately, the there were two releases between when https://github.com/opencontainers/runc/commit/5e0e67d76cc99d76c8228d48f38f37034503f315  was released
and when the workaround https://github.com/opencontainers/runc/pull/2712 was added.

Between this, folks started relying on the ability to have a workdir that the container user doesn't have access to.

Since this case was previously valid, we should continue support for it.

Now, we retry the chdir:
Once at the top of the function (to catch cases where the runc user has access, but container user does not)
and once after we setup user (to catch cases where the container user has access, and the runc user does not)

Add a test case for this as well.

Signed-off-by: Peter Hunt <pehunt@redhat.com>
2021-04-06 14:51:43 -04:00
Akihiro Suda c453f1a523 Merge pull request #2881 from kolyshkin/test-rand-cg
tests/int: some refactoring, fix a flake
2021-04-06 13:27:19 +09:00
Akihiro Suda d8a5f6084a Merge pull request #2885 from thaJeztah/config_missing_type
libcontainer/configs: add missing type for hooknames
2021-04-06 13:24:28 +09:00
Akihiro Suda 913b9f14e8 Merge pull request #2886 from thaJeztah/check_cleanup 2021-04-06 03:28:45 +09:00
Sebastiaan van Stijn 4316df8b53 libcontainer/system: move userns utilities to separate package
Moving these utilities to a separate package, so that consumers of this
package don't have to pull in the whole "system" package.

Looking at uses of these utilities (outside of runc itself);

`RunningInUserNS()` is used by [various external consumers][1],
so adding a "Deprecated" alias for this.

[1]: https://grep.app/search?current=2&q=.RunningInUserNS

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-04-04 22:42:03 +02:00
Sebastiaan van Stijn e7fd383bce libcontainer/system: un-export UIDMapInUserNS()
`UIDMapInUserNS()` is not used anywhere, only internally. so un-export it.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-04-04 22:42:02 +02:00
Sebastiaan van Stijn 249356a1a4 libcontainer/system: remove unused GetParentNSeuid()
This function was added in f103de57ec, but no
longer used since 06f789cf26 (v1.0.0-rc6)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-04-04 22:41:59 +02:00
Kir Kolyshkin 365c6282c7 Merge pull request #2888 from thaJeztah/fixup_rm_win_carry
libcontainer: rm windows pieces (carry #2700)
2021-04-03 19:10:36 -07:00
Aleksa Sarai 0d49470392 merge branch 'pr-2855'
Kir Kolyshkin (2):
  start: don't kill runc init too early
  libct/configs/validator: add some cgroup support

LGTMs: @AkihiroSuda @cyphar
Closes #2855
2021-04-03 12:41:41 +11:00
Sebastiaan van Stijn dc52ed250a libcontainer/user: remove outdated MAINTAINERS file
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-04-02 11:56:41 +02:00
Sebastiaan van Stijn 72ecf59c88 libcontainer/user: fix windows compile error
Move the unix-specific code to a file that's not compiled on
Windows.

Some of the errors (ErrUnsupported, ErrNoPasswdEntries, ErrNoGroupEntries)
are used in other parts of the code, so are moved to a non-platform
specific file.

Most of "user" is probably not useful on Windows, although it's possible
that Windows code may have to parse a passwd file, so leaving that code
for now.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-04-02 11:56:39 +02:00
Kir Kolyshkin 2515b0c2f2 libct/user: rm windows code
Commit bf749516 added these two functions, but they are only used from
Windows code. The v1 of this patch moved these functions to _windows.go
file, but after some discussion we decided to drop windows code
altogether, so this is what this patch now does.

This fixes

> libcontainer/user/user.go:64:6: func `groupFromOS` is unused (unused)
> libcontainer/user/user.go:35:6: func `userFromOS` is unused (unused)

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-02 11:56:37 +02:00
Kir Kolyshkin 0596f6e1e7 libcontainer/devices/device_windows.go: rm
This was initially added by commit d78ee47154 but later
moved from libcontainer/configs to libcontainer/devices by
commit 677baf22.

Looks like since commit 677baf22 and also [1]
there is no use for this, thus removing.

[1] https://github.com/containers/buildah/pull/2652

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-02 11:56:21 +02:00
Kir Kolyshkin b1deba8c5a libcontainer/configs/config_windows_test.go: rm
Nothing is in there, so removing.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-02 11:55:33 +02:00
Sebastiaan van Stijn f1586dbd7a libcontainer/configs/validate: make Validate() less DRY
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-04-02 11:41:19 +02:00
Sebastiaan van Stijn 4126b807cc libcontainer/configs: add missing type for hooknames
Commit ccdd75760c introduced the HookName type
for hooks, but only set this type on the Prestart const, but not for the
other hooks.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-04-02 11:08:24 +02:00
Kir Kolyshkin 27bb1bd5ea libct/specconv/CreateCgroupConfig: don't set c.Parent default
c.Parent is only used by systemd cgroup drivers, and both v1 and v2
drivers do have code to set the default if it is empty, so setting
it here is redundant.

In addition, in case of cgroup v2 rootless container setting it here
is harmful as the default should be user.slice not system.slice.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-01 19:50:37 -07:00
Kir Kolyshkin f0dec0b4bf libct/specconv/CreateCgroupConfig: nit
Do not call libcontainerUtils.CleanPath in case its result will
not be used.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-01 19:33:01 -07:00
Kir Kolyshkin 6538f9f20a Merge pull request #2854 from thaJeztah/runc_warn_unknown_caps
capabilities: WARN, not ERROR, for unknown / unavailable capabilities
2021-04-01 18:27:57 -07:00
Mrunal Patel 8c4dca8dcb Merge pull request #2871 from masters-of-cats/pr-seccomp-pipe-hang
Ensure the seccomp pipe is being read while exporting bpf
2021-04-01 15:09:08 -07:00
Kir Kolyshkin 2dd62b3d42 libct/checkCriuFeatures: rm excessive debug
1. Remove printing criu args as now they are *always swrk 3.
2. Remove duplicated "feature check says" debug.

Before:

> DEBU[0000] Using CRIU with following args: [swrk 3]
> DEBU[0000] Using CRIU in FEATURE_CHECK mode
> DEBU[0000] Feature check says: type:FEATURE_CHECK success:true features:<mem_track:false lazy_pages:true >
> DEBU[0000] Feature check says: mem_track:false lazy_pages:true

After:

> DEBU[0000] Using CRIU in FEATURE_CHECK mode
> DEBU[0000] Feature check says: mem_track:false lazy_pages:true

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-04-01 12:57:41 -07:00
Kir Kolyshkin bed4d89f57 Merge pull request #2807 from kolyshkin/google-golang-protobuf
go.mod, libct: switch to google.golang.org/protobuf
2021-03-31 20:34:16 -07:00
Kir Kolyshkin 4ecff8d9d8 start: don't kill runc init too early
The stars can be aligned in a way that results in runc to leave a stale
bind mount in container's state directory, which manifests itself later,
while trying to remove the container, in an error like this:

> remove /run/runc/test2: unlinkat /run/runc/test2/runc.W24K2t: device or resource busy

The stale mount happens because runc start/run/exec kills runc init
while it is inside ensure_cloned_binary(). One such scenario is when
a unified cgroup resource is specified for cgroup v1, a cgroup manager's
Apply returns an error (as of commit b006f4a180), and when
(*initProcess).start() kills runc init just after it was started.

One solution is NOT to kill runc init too early. To achieve that,
amend the libcontainer/nsenter code to send a \0 byte to signal
that it is past the initial setup, and make start() (for both
run/start and exec) wait for this byte before proceeding with
kill on an error path.

While at it, improve some error messages.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-03-31 14:36:52 -07:00
Kir Kolyshkin b118430231 libct/configs/validator: add some cgroup support
Add some minimal validation for cgroups. The following checks
are implemented:

 - cgroup name and/or prefix (or path) is set;
 - for cgroup v1, unified resources are not set;
 - for cgroup v2, if memorySwap is set, memory is also set,
   and memorySwap > memory.

This makes some invalid configurations fail earlier (before runc init
is started), which is better.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-03-31 14:36:52 -07:00
Kir Kolyshkin 0f8d2b6bed libct/cg/fs2.Stat: don't look for available controllers
Some controllers might still have stats available even if they are
disabled (this is definitely so for cpu.stat -- see earlier commit).

Some stat methods might implement sensible fallbacks (see previous
commit for statPids.

In the view of all that, it makes sense to not check if a particular
controller is available, but rather ignore ENOENT from it.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-03-31 12:16:14 -07:00
Kir Kolyshkin 85416b8742 libct/cg/fs2.statPids: fall back directly
When getting pids stats, instead of checking whether the pids controller
is available, let's use a fall back function in case pids.current does
not exist. This simplifies the logic in fs2.GetStats.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-03-31 12:03:12 -07:00
Kir Kolyshkin 10f9a982ac libct/cg/fs2/getPidsWithoutController: optimize
It is inefficient to create an associative map for the whole purpose of
counting the number of elements in it, especially if the elements are
all unique. It uses more CPU than necessary and creates some work for
the garbage collector.

The file we read contains PIDs and newlines, and the easiest/fastest way
to get the number of PIDs is just to count the newlines.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-03-31 11:55:07 -07:00
Kir Kolyshkin 6121f8b69f libct/cg/fs2.Stat: always call statCpu
Giuseppe found out that cpu.stat for a cgroup is available even if
the cpu controller is not enabled for it. So, let's call statCpu
regradress, and ignore ENOENT.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-03-31 11:40:28 -07:00