Commit Graph

731 Commits

Author SHA1 Message Date
Kir Kolyshkin 204c673cce [1.1] fix failed exec after systemctl daemon-reload
A regression reported for runc v1.1.3 says that "runc exec -t" fails
after doing "systemctl daemon-reload":

> exec failed: unable to start container process: open /dev/pts/0: operation not permitted: unknown

Apparently, with commit 7219387eb7 we are no longer adding
"DeviceAllow=char-pts rwm" rule (because os.Stat("char-pts") returns
ENOENT).

The bug can only be seen after "systemctl daemon-reload" because runc
also applies the same rules manually (by writing to devices.allow for
cgroup v1), and apparently reloading systemd leads to re-applying the
rules that systemd has (thus removing the char-pts access).

The fix is to do os.Stat only for "/dev" paths.

Also, emit a warning that the path was skipped. Since the original idea
was to emit less warnings, demote the level to debug.

Note this also fixes the issue of not adding "m" permission for block-*
and char-* devices.

A test case is added, which reliably fails before the fix
on both cgroup v1 and v2.

This is a backport of commit 58b1374f0a
to release-1.1 branch.

Fixes: https://github.com/opencontainers/runc/issues/3551
Fixes: 7219387eb7
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2022-08-18 15:22:40 -07:00
Aleksa Sarai 7219387eb7 cgroups: systemd: skip adding device paths that don't exist
systemd emits very loud warnings when the path specified doesn't exist
(which can be the case for some of our default rules). We don't need the
ruleset we give systemd to be completely accurate (we discard some kinds
of wildcard rules anyway) so we can safely skip adding these.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2022-06-08 09:48:24 +10:00
Kang Chen fc2a8fe13b libct/cg/sd: check dbus.ErrClosed instead of isDbusError
Signed-off-by: Kang Chen <kongchen28@gmail.com>
(cherry picked from commit 0ca0bb9fee)
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2022-05-23 16:48:12 +10:00
Kir Kolyshkin 3b7f260510 Format sources using gofumpt 0.2.1
... which adds a wee more whitespace fixes.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 89733cd055)
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2022-05-11 16:42:50 -07:00
Kir Kolyshkin 8290c4cf58 libct/cg: IsCgroup2HybridMode: don't panic
In case statfs("/sys/fs/cgroup/unified") fails with any error other
than ENOENT, current code panics. As IsCgroup2HybridMode is called from
libcontainer/cgroups/fs's init function, this means that any user of
libcontainer may panic during initialization, which is ugly.

Avoid panicking; instead, do not enable hybrid hierarchy support and
report the error (under debug level, not to confuse anyone).

Basically, replace the panic with "turn off hybrid mode support"
(which makes total sense since we were unable to statfs its root).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2022-03-28 09:13:57 -07:00
Kir Kolyshkin 96193422ea libct/cg/sd/v2: fix ENOENT on cgroup delegation
Apparently, not all files listed in /sys/kernel/cgroup/delegate must
exist in every cgroup, so we should ignore ENOENT.

Dot not ignore ENOENT on the directory itself though.

Change cgroupFilesToChown to not return ".", and refactor it to not do
any dynamic slice appending in case we're using the default built-in
list of files.

Fixes: 35d20c4e0
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 8c04b98100)
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2022-03-08 12:03:50 -08:00
Kir Kolyshkin 5c7e898186 libct/cg: rm go 1.15 compatibility
Since commit 12e99a0f8d we do require Go >= 1.16, so this file
is no longer needed.

Also, this actually ensures that go >= 1.16 is used (otherwise
libcontainer/cgroups/getallpids.go won't compile).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-12-14 13:08:47 -08:00
Aleksa Sarai cdce249635 merge branch 'pr-3057'
Fraser Tweedale (1):
  chown cgroup to process uid in container namespace

LGTMs: kolyshkin cyphar
Closes #3057
2021-12-07 17:06:19 +11:00
Kir Kolyshkin 6c0bfcb1c8 libct/cg/fs/blkio_test: ignore unparam warning
Ignore the following warning:

> libcontainer/cgroups/fs/blkio_test.go:167:78: `appendBlkioStatEntry` - `minor` always receives `0` (unparam)
> func appendBlkioStatEntry(blkioStatEntries *[]cgroups.BlkioStatEntry, major, minor, value uint64, op string) {

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-11-29 20:10:22 -08:00
Kir Kolyshkin 06b3fd9d19 libct/cg/ebpf: drop finalize return value
It never returns any error, so let's drop it (in case it needs to be
re-added, it is easy to do so).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-11-29 20:10:22 -08:00
Kir Kolyshkin 741568ebf1 libct/cg/devices: addRule: ignore unparam warning
This function has a return value for consistency, let it stay.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-11-29 20:10:22 -08:00
Fraser Tweedale 35d20c4e0b chown cgroup to process uid in container namespace
Delegating cgroups to the container enables more complex workloads,
including systemd-based workloads.  The OCI runtime-spec was
recently updated to explicitly admit such delegation, through
specification of cgroup ownership semantics:

  https://github.com/opencontainers/runtime-spec/pull/1123

Pursuant to the updated OCI runtime-spec, change the ownership of
the container's cgroup directory and particular files therein, when
using cgroups v2 and when the cgroupfs is to be mounted read/write.

As a result of this change, systemd workloads can run in isolated
user namespaces on OpenShift when the sandbox's cgroupfs is mounted
read/write.

It might be possible to implement this feature in other cgroup
managers, but that work is deferred.

Signed-off-by: Fraser Tweedale <ftweedal@redhat.com>
2021-11-30 08:52:59 +10:00
Kir Kolyshkin 1da84d1aff libct/cg: TestGetHugePageSizeImpl: use t.Run
Move test case comments to doc strings, and use t.Run.

Suggested-by:  Sebastiaan van Stijn <github@gone.nl>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-11-19 12:03:12 -08:00
Kir Kolyshkin f13a932570 libct/cg: HugePageSizes: simplify code and test
1. Instead of distinguishing between errors and warnings, let's treat all
   errors as warnings, thus simplifying the code. This changes the
   function behaviour for input like hugepages-BadNumberKb --
   previously, the error from Atoi("BadNumber") was considered fatal,
   now it's just another warnings.

2. Move the warning logging to HugePageSizes, thus simplifying the test
   case, which no longer needs to read what logrus writes. Note that we
   do not want to log all the warnings (as chances are very low we'll
   get any, and if we do this means the code need to be updated), only
   the first one.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-11-18 18:20:49 -08:00
Kir Kolyshkin 39d4c8d5f9 libct/cg: lazy init for HugePageSizes
I have noticed that libct/cg/fs allocates 8K during init on every runc
execution:

> init github.com/opencontainers/runc/libcontainer/cgroups/fs @1.5 ms, 0.028 ms clock, 8512 bytes, 13 allocs

Apparently this is caused by global HugePageSizes variable init, which
is only used from GetStats (i.e. it is never used by runc itself).

Remove it, and use HugePageSizes() directly instead. Make it init-once,
so that GetStats (which, I guess, is periodically called by kubernetes)
does not re-read huge page sizes over and over.

This also removes 12 allocs and 8K from libct/cg/fs init section:

> $ time GODEBUG=inittrace=1 ./runc --help 2>&1 | grep cgroups/fs
> init github.com/opencontainers/runc/libcontainer/cgroups/fs @1.5 ms, 0.003 ms clock, 16 bytes, 1 allocs

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-11-18 18:20:49 -08:00
Kir Kolyshkin a4d4c4dd9f libct/cg: GetHugePageSize -> HugePageSizes
1. Since GetHugePageSize do not have any external users (checked by
   sourcegraph), and no internal user ever uses its second return value
   (the error), let's drop it.

2. Rename GetHugePageSize -> HugePageSizes (drop the Get prefix as per
   Go guidelines, add suffix since we return many sizes).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-11-18 18:20:49 -08:00
Sebastiaan van Stijn 6d35069b5e Merge pull request #3245 from kolyshkin/go116
Drop Go 1.15 support
2021-10-17 21:14:33 +02:00
Akihiro Suda d8a3446acd Merge pull request #3002 from iholder-redhat/feature/TestingSkipFinalCheckPublic
Make DevicesGroup's "TestingSkipFinalCheck" attribute public
2021-10-16 16:15:32 +09:00
Kir Kolyshkin 5516294172 Remove io/ioutil use
See https://golang.org/doc/go1.16#ioutil

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-10-14 13:46:02 -07:00
Akihiro Suda 2357eab8ca Merge pull request #3233 from kolyshkin/hugepage-fix
libct/cg/fs2: fix GetStats for unsupported hugetlb
2021-10-12 12:20:51 +09:00
Kir Kolyshkin f594edee21 Merge pull request #3059 from kolyshkin/cgroup-clean
runc exec --cgroup
2021-10-06 18:02:46 -07:00
Kir Kolyshkin 916c6a1539 libct/cg/fs2: fix GetStats for unsupported hugetlb
In case hugetlb is not supported, GetStats() should not error out,
and yet it does.

Assume that if GetHugePageSize return an error, hugetlb is
not supported (this is what cgroup v1 manager do).

Fixes: 89a87adb
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-10-05 16:48:15 -07:00
Itamar Holder f9667e633b Make DevicesGroup's "TestingSkipFinalCheck" attribute public
Users would like to have the possibility to skip checks for their
tests the same way they are skipped within the tests in runc.

Not exposing this variable makes it very hard to test components
that use this library. To avoid copying-and-pasting the code
into outside projects this variable sould be exposed to the users.

Signed-off-by: Itamar Holder <iholder@redhat.com>
2021-10-05 17:36:39 +03:00
Kang Chen 7758d3fb02 libct/cg/sd/v2: Destroy: remove cgroups recursively
Currently, we can create subcgroup in a rootless container with systemd cgroupv2 on centos8.
But after the container exited, the container cgroup and its subcgroup will not be removed.

Fix this by removing all directories recursively.

Fixes: https://github.com/opencontainers/runc/issues/3225

Signed-off-by: Kang Chen <kongchen28@gmail.com>
2021-10-01 22:07:02 +08:00
Mauricio Vásquez a8435007d9 cgroups: join cgroup v2 when using hybrid mode
Currently the parent process of the container is moved to the right
cgroup v2 tree when systemd is using a hybrid model (last line with 0::):

$ runc --systemd-cgroup run myid
/ # cat /proc/self/cgroup
12:cpuset:/system.slice/runc-myid.scope
11:blkio:/system.slice/runc-myid.scope
10:devices:/system.slice/runc-myid.scope
9:hugetlb:/system.slice/runc-myid.scope
8:memory:/system.slice/runc-myid.scope
7:rdma:/
6:perf_event:/system.slice/runc-myid.scope
5:net_cls,net_prio:/system.slice/runc-myid.scope
4:freezer:/system.slice/runc-myid.scope
3:pids:/system.slice/runc-myid.scope
2:cpu,cpuacct:/system.slice/runc-myid.scope
1:name=systemd:/system.slice/runc-myid.scope
0::/system.slice/runc-myid.scope

However, if a second process is executed in the same container, it is
not moved to the right cgroup v2 tree:

$ runc exec myid /bin/sh -c 'cat /proc/self/cgroup'
12:cpuset:/system.slice/runc-myid.scope
11:blkio:/system.slice/runc-myid.scope
10:devices:/system.slice/runc-myid.scope
9:hugetlb:/system.slice/runc-myid.scope
8:memory:/system.slice/runc-myid.scope
7:rdma:/
6:perf_event:/system.slice/runc-myid.scope
5:net_cls,net_prio:/system.slice/runc-myid.scope
4:freezer:/system.slice/runc-myid.scope
3:pids:/system.slice/runc-myid.scope
2:cpu,cpuacct:/system.slice/runc-myid.scope
1:name=systemd:/system.slice/runc-myid.scope
0::/user.slice/user-1000.slice/session-8.scope

This commit makes that processes executed with exec are placed into the
right cgroup v2 tree. The implementation checks if systemd is using a
hybrid mode (by checking if cgroups v2 is mounted in
/sys/fs/cgroup/unified), if yes, the path of the cgroup v2 slice for
this container is saved into the cgroup path list.

The fs group driver has a similar issue, in this case none of the runc
run or runc exec commands put the process in the right cgroups v2. This
commit also fixes that.

Having the processes of the container in its own cgroup v2 is useful
for any BPF programs that rely on bpf_get_current_cgroup_id(), like
https://github.com/kinvolk/inspektor-gadget/ for instance.

[@kolyshkin: rebased]

Signed-off-by: Mauricio Vásquez <mauricio@kinvolk.io>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-23 19:29:11 -07:00
Kir Kolyshkin 7d446c63d0 libct/cg.WriteCgroupProcs: improve errors
No need to add a file name to the error messages, as errors from
OpenFile and (*os.File).Write both contain the file name already.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-23 19:26:57 -07:00
Kir Kolyshkin 99ddc1be16 libct/cg/fs: rm m.config == nil checks
It is assumed that m.config is not nil, so these checks are redundant
(in case it is nil, NewManager panics and this code is unreachable).

Note that cgroups/manager.New checks that config is not nil.

Remove them.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-23 09:12:14 -07:00
Kir Kolyshkin 57edce4659 libct/cg: add Resources=nil unit test
Cgroup controllers should never panic, and yet sometimes they do.

Add a unit test to check that controllers never panic when called with
nil arguments and/or resources, and fix a few found cases.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-23 09:12:14 -07:00
Kir Kolyshkin 1af4ed1110 libct/cg/sd/v2: move fsMgr init to NewUnifiedManager
Many operations require fsMgr, so let's create it right in
NewUnifiedManager and reuse.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-23 09:12:14 -07:00
Kir Kolyshkin 9a2146fa3d libct/cg/sd/v2: move path init to NewUnifiedManager
This fixes the same issue as e.g. commit 4f8ccc5ff5
but in a more universal way.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-23 09:12:14 -07:00
Kir Kolyshkin 39be6e9768 libct/cg/fs2: minor optimization
cgName and cgParent are only used when cgPath is empty, so move
their cleaning to the body of the appropriate "if" statement.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-23 09:12:14 -07:00
Kir Kolyshkin b14a6cf9a6 libct/cg/sd/v1: move path init to NewLegacyManager
This way we
 - won't re-initialize the paths if they were provided;
 - will always have paths ready for every method.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-23 09:12:14 -07:00
Kir Kolyshkin fcc4816818 libct/cg/fs: document path removal
This is already documented but I guess more explanations (in particular,
why the path is being removed from paths) won't hurt.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-23 09:12:14 -07:00
Kir Kolyshkin 6c5441e5cb libct/cg/fs: move paths init to NewManager
1. Separate path initialization logic from Apply to initPaths,
   and call initPaths from NewManager, so:
   - we can error out early (in NewManager rather than Apply);
   - always have m.paths available (e.g. in Destroy or Exists).
   - do not unnecessarily call subsysPath from Apply in case
     the paths were already provided.

2. Add a check for non-nil cgroups.Resources to NewManager,
   since initPaths, as well as some controller's Apply methods,
   need it.

3. Move cgroups.Resources.Unified check from Apply to NewManager,
   so we can error out early (same check exists in Set).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-23 09:12:14 -07:00
Kir Kolyshkin 097c6d7425 libct/cg: simplify getting cgroup manager
1. Make Rootless and Systemd flags part of config.Cgroups.

2. Make all cgroup managers (not just fs2) return error (so it can do
   more initialization -- added by the following commits).

3. Replace complicated cgroup manager instantiation in factory_linux
   by a single (and simple) libcontainer/cgroups/manager.New() function.

4. getUnifiedPath is simplified to check that only a single path is
   supplied (rather than checking that other paths, if supplied,
   are the same).

[v2: can't -> cannot]

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-23 09:11:44 -07:00
Kir Kolyshkin 79185bc806 Merge pull request #3215 from kolyshkin/cgroupv1-opts
cgroupv1: refactor and optimize
2021-09-21 11:51:03 -07:00
Shengjing Zhu 163e2523d7 libct/cg: replace bitset with std math/big library
Cut down third party dependency.

Signed-off-by: Shengjing Zhu <zhsj@debian.org>
2021-09-19 23:38:15 +08:00
Kir Kolyshkin e692886563 libct/cg/fs: refactor
1. Dismantle and remove struct cgroupData. It contained three unrelated
   entities (cgroup paths, pid, and resources), and made the code
   harder to read. Most importantly, though, it is not needed.
   Now, subsystems' Apply methods take path, resources, and pid.

   To a reviewer -- the core of the changes is in fs.go and paths.go,
   the rest of it is adapting to the new signatures and related test
   changes.

2. Dismantle and remove struct cgroupTestUtil. This is a followup
   to the previous item -- since cgroupData is gone, there is nothing
   to hold in cgroupTestUtil. The change itself is very small (see
   util_test.go), but this patch is big because of it -- mostly
   because we had to replace helper.cgroup.Resources with
   &config.Resources{}.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-14 12:06:21 -07:00
Kir Kolyshkin 7d1cb320ad libct/cg/fs: rename join to apply
As this is called from the Apply() method, it's a natural name.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-14 12:06:02 -07:00
Kir Kolyshkin 5c7cb837c7 libct/cg/fs: micro optimization
In case c.Path is set, c.Name and c.Parent are not used, and so
calls to utils.CleanPath are entirely unnecessary. Move them to
inside of the "if" statement body.

Get rid of the intermediate cgPath variable, it is not needed.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-14 12:05:49 -07:00
Kir Kolyshkin 19b542a576 libct/cg/fs: move internal code out of fs.go
Now fs.go is not very readable as its public API functions are
intermixed with internal stuff about getting cgroup paths.

Move that out to paths.go, without changing any code.

Same for the tests -- move paths-related tests to paths_test.go.

This commit is separate to make the review easier.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-14 12:05:34 -07:00
Kir Kolyshkin eb09df749a libct/cg/sd/v1: initPaths: minor optimization
As ExpandSlice("system.slice") returns "/system.slice", there is no need
to call it for such paths (and the slash will be added by path.Join
anyway).

The same optimization was already done for v2 as part of commit
bf15cc99b1.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-14 11:58:52 -07:00
Kir Kolyshkin 63c84917f3 libct/cg/sd/v1: optimize initPaths
It does not make sense to calculate slice and unit 10+ times.
Move those out of the loop.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-14 11:58:34 -07:00
Kir Kolyshkin c7e0864d5f libct/cg/sd/v1: factor out initPaths
No functional change.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-14 11:58:20 -07:00
Kir Kolyshkin dc907e8d11 libct/cg/sd/v*.go: nit
We were checking if a unit is a slice two times. Consolidate those
checks, and improve comments while we're at it.

The code is the same in v1 and v2 but it's too complicated to factor it
out, thus we just do the same changes in v1.go and v2.go.

No functional change.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-09-14 11:57:34 -07:00
Aleksa Sarai 76c1583413 merge branch 'pr-3186'
Akihiro Suda (1):
  improve error message when dbus-user-session is not installed

LGTMs: kolyshkin cyphar
2021-09-09 14:57:03 +10:00
Sebastiaan van Stijn 7fcfb3fad6 Merge pull request #3030 from kolyshkin/openat2-improve
libct/cg/OpenFile: fix/improve openat2 handling
2021-09-03 16:54:39 +02:00
Kir Kolyshkin d8da00355e *: add go-1.17+ go:build tags
Go 1.17 introduce this new (and better) way to specify build tags.
For more info, see https://golang.org/design/draft-gobuild.

As a way to seamlessly switch from old to new build tags, gofmt (and
gopls) from go 1.17 adds the new tags along with the old ones.

Later, when go < 1.17 is no longer supported, the old build tags
can be removed.

Now, as I started to use latest gopls (v0.7.1), it adds these tags
while I edit. Rather than to randomly add new build tags, I guess
it is better to do it once for all files.

Mind that previous commits removed some tags that were useless,
so this one only touches packages that can at least be built
on non-linux.

Brought to you by

        go1.17 fmt ./...

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-08-30 20:58:22 -07:00
Kir Kolyshkin 1b17ec95af libct/cg: rm "unsupported.go" files
These are not needed as these packages (libcontainer/cgroups,
libcontainer/cgroups/fs, and libcontainer/cgroups/systemd) can
not be built under non-linux anyway (for various reasons).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-08-30 20:56:35 -07:00
Kir Kolyshkin dbb9fc03ae libct/*: remove linux build tag from some pkgs
Only some libcontainer packages can be built on non-linux platforms
(not that it make sense, but at least go build succeeds). Let's call
these "good" packages.

For all other packages (i.e. ones that fail to build with GOOS other
than linux), it does not make sense to have linux build tag (as they
are broken already, and thus are not and can not be used on anything
other than Linux).

Remove linux build tag for all non-"good" packages.

This was mostly done by the following script, with just a few manual
fixes on top.

function list_good_pkgs() {
	for pkg in $(find . -type d -print); do
		GOOS=freebsd go build $pkg 2>/dev/null \
		&& GOOS=solaris go build $pkg 2>/dev/null \
		&& echo $pkg
	done | sed -e 's|^./||' | tr '\n' '|' | sed -e 's/|$//'
}

function remove_tag() {
	sed -i -e '\|^// +build linux$|d' $1
	go fmt $1
}

SKIP="^("$(list_good_pkgs)")"
for f in $(git ls-files . | grep .go$); do
	if echo $f | grep -qE "$SKIP"; then
		echo skip $f
		continue
	fi
	echo proc $f
	remove_tag $f
done

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-08-30 20:52:07 -07:00