Commit Graph

2150 Commits

Author SHA1 Message Date
Kir Kolyshkin 2bab4a56f1 libct/nsenter: fix logging race in nsexec
As reported in issue 3119, there is a race in nsexec logging
that can lead to garbled json received by log forwarder, which
complains about it with a "failed to decode" error.

This happens because dprintf (used since the very beginning of nsexec
logging introduced in commit ba3cabf932) relies on multiple write(2)
calls, and with additional logging added by 64bb59f592 a race is
possible between runc init parent and its children.

The fix is to prepare a string and write it using a single call to
write(2).

[v2: NULLify json on error from asprintf]

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-08-11 10:01:00 -07:00
Kir Kolyshkin d0c3bc44e7 libct/cg: GetAllPids: optimize for go 1.16+
filepath.WalkDir function, introduced in Go 1.16, doesn't do stat(2)
on every entry, and is therefore somewhat faster (see below).

Since we have to support Go 1.15, keep the old version for backward
compatibility.

Add a quick benchmark, which shows approximately 3x improvement:

        $ go1.15.15 test -bench AllPid -run xxx .
	BenchmarkGetAllPids-4   	      48	  23528839 ns/op

        $ go version
        go version go1.16.6 linux/amd64
        $ go test -bench AllPid -run xxx .
	BenchmarkGetAllPids-4   	     147	   7700170 ns/op

(Unrelated but worth noting -- go 1.17rc2 is pushing it even further)

        $ go1.17rc2 test -bench AllPid -run xxx .
	BenchmarkGetAllPids-4   	     164	   6820994 ns/op

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-08-05 16:22:18 -07:00
Kir Kolyshkin 363468d0e4 libct/cg: improve GetAllPids and readProcsFile
Since every cgroup directory is guaranteed to have cgroup.procs file,
we don't have to do filename comparison in GetAllPids() and just read
cgroup.procs in every directory.

While at it, switch readProcsFile to use our own OpenFile.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-08-05 16:22:11 -07:00
Kir Kolyshkin 504271a374 libct/cg: move GetAllPids out of utils.go
This is just moving the code around to ease the code review, no other
changes.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-08-05 16:00:03 -07:00
Mrunal Patel 8772c4dd2f Merge pull request #3109 from kolyshkin/seccomp
seccomp: skip redundant rules
2021-08-03 23:09:00 -04:00
Kir Kolyshkin 2aabb29741 Merge pull request #3113 from kolyshkin/init-rm-code
runc init: remove some code
2021-07-29 16:54:47 -07:00
Kir Kolyshkin 5110bd2fc0 nsenter: remove cgroupns sync mechanism
As pointed out in TODO item added by commit 64bb59f59, it is not
necessary to have a special sync mechanism for cgroupns, as the parent
adds runc init to cgroup way earlier (before sending nl bootstrap data.

This sync was added by commit df3fa115f9, which was also added a
second cgroup manager.Apply() call, later removed in commit
d1ba8e39f8. It seems the original author had the idea to wait for
that second Apply().

Fixes: df3fa115f9
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-27 12:17:47 -07:00
Kir Kolyshkin a91ce3062f libct/*_test.go: use t.TempDir
Replace ioutil.TempDir (mostly) with t.TempDir, which require no
explicit cleanup.

While at it, fix incorrect usage of os.ModePerm in libcontainer/intelrdt
test. This is supposed to be a mask, not mode bits.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-27 01:41:47 -07:00
Kir Kolyshkin 3bc606e9d3 libct/int: adapt to Go 1.15
1. Use t.TempDir instead of ioutil.TempDir. This means no need for an
   explicit cleanup, which removes some code, including newTestBundle
   and newTestRoot.

2. Move newRootfs invocation down to newTemplateConfig, removing a need
   for explicit rootfs creation. Also, remove rootfs from tParam as it
   is no longer needed (there was a since test case in which two
   containers shared the same rootfs, but it does not look like it's
   required for the test).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-27 01:41:47 -07:00
Kir Kolyshkin 1eeaf11301 libct/intelrdt/*_test.go: use t.TempDir
This simplifies the code as no explicit cleanup is required.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-27 01:41:47 -07:00
Kir Kolyshkin f6a56f603c libct/cg/fs/*_test.go: use t.TempDir
This simplifies the code as no explicit cleanup is required.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-27 01:41:47 -07:00
Kir Kolyshkin 2d1645d2e5 libct/cg/fscommon: drop go 1.13 compatibility
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-27 01:41:47 -07:00
Kir Kolyshkin 12a1dccb9c Revert "libcontainer: avoid using t.Cleanup"
This reverts commit 45f49e8fca.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-27 01:41:47 -07:00
Kir Kolyshkin 5dd92fd9b4 libct/seccomp: skip redundant rules
This fixes using runc with podman on my system (Fedora 34).

> $ podman --runtime `pwd`/runc run --rm --memory 4M fedora echo it works
> Error: unable to start container process: error adding seccomp filter rule for syscall bdflush: permission denied: OCI permission denied

The problem is, libseccomp returns EPERM when a redundant rule (i.e. the
rule with the same action as the default one) is added, and podman (on
my machine) sets the following rules in config.json:

    <....>
    "seccomp": {
      "defaultAction": "SCMP_ACT_ERRNO",
      "architectures": [
        "SCMP_ARCH_X86_64",
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
      ],
      "syscalls": [
        {
          "names": [
            "bdflush",
            "io_pgetevents",
            <....>
          ],
          "action": "SCMP_ACT_ERRNO",
          "errnoRet": 1
        },
        <....>

(Note that defaultErrnoRet is not set, but it defaults to 1).

With this commit, it works:

> $ podman --runtime `pwd`/runc run --memory 4M fedora echo it works
> it works

Add an integration test (that fails without the fix).

Similar crun commit:
 * https://github.com/containers/crun/commit/08229f3fb904c5ea19a7d9

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-27 00:04:59 -07:00
Kir Kolyshkin e44bee1026 libct/seccomp: warn about unknown syscalls
Rather than silently ignoring unknown syscalls, print a warning.

While at it, fix imports ordering (stdlib, others, ours).

[v2: demote Warn to Debug]

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-27 00:04:59 -07:00
Kir Kolyshkin 073e085ca4 libct/seccomp: ConvertStringToAction: fix doc
As of commit caca840972 (Nov 12 2015) SCMP_ACT_TRACE
is supported.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-27 00:04:59 -07:00
Kir Kolyshkin a71102624d libct/cg/sd: add TestPodSkipDevicesUpdate
TestPodSkipDevicesUpdate checks that updating a pod having SkipDevices: true
does not result in spurious "permission denied" errors in a container
running under the pod. The test is somewhat similar in nature to the
@test "update devices [minimal transition rules]" in tests/integration,
but uses a pod.

This tests the validity of freezeBeforeSet in v1.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-15 00:07:22 -07:00
Kir Kolyshkin 52dd96db6b libct/cg/sd: TestFreezePodCgroup: rm explicit freeze
This was initially added by commit 3e5c199708 because Set (with
r.Freezer = Frozen) was not able to freeze a container.

Now (see a few previous commits) Set can do the freeze, so the explicit
Freeze is no longer needed.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-15 00:07:19 -07:00
Kir Kolyshkin f2db87986c libct/cg/sd/v1: Set: avoid unnecessary freeze/thaw
Introduce freezeBeforeSet, which contains the logic of figuring out
whether we need to freeze/thaw around setting systemd unit properties.

In particular, if SkipDevices is set, and the current unit properties
allow all devices, there is no need to freeze and thaw, as systemd
won't write any device rules in this case.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-15 00:07:10 -07:00
Kir Kolyshkin 5dc3260431 libct/int/TestFreeze: test freeze/thaw via Set
In addition to freezing and thawing a container via Pause/Resume,
there is a way to also do so via Set.

This way was broken though and is being fixed by a few preceding
commits. The test is added to make sure this is fixed and won't regress.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-14 23:42:35 -07:00
Kir Kolyshkin af1688a544 libct/int: allow subtests
The t.Name() usage in libcontainer/integration prevented subtests
to be used, since in such case it returns a string containing "/",
and thus it can't be used to name a container.

Fix this by replacing slashes with underscores where appropriate.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-14 23:42:35 -07:00
Kir Kolyshkin 67cfd3d400 libct/cg/sd/v1: Set: don't overwrite r.Freezer
m.Freeze method changes m.cgroups.Resources.Freezer field, which should
not be done while we're temporarily freezing the cgroup in Set. If this
field is changed, and r == m.cgroups.Resources (as it often happens),
this results in inability to freeze the container using Set().

To fix, add and use a method which does not change r.Freezer field.

A test case for the bug will be added separately.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-14 23:42:35 -07:00
Aleksa Sarai 57e3c54182 cgroupv2: ebpf: ignore inaccessible existing programs
This is necessary in order for runc to be able to configure device
cgroups with --systemd-cgroup on distributions that have very strict
SELinux policies such as openSUSE MicroOS[1].

The core issue here is that systemd is adding its own BPF policy that
has an SELinux label such that runc cannot interact with it. In order to
work around this, we can just ignore the policy -- in theory this
behaviour is not correct but given that the most obvious case
(--systemd-cgroup) will still handle updates correctly, this logic is
reasonable.

[1]: https://bugzilla.suse.com/show_bug.cgi?id=1182428

Fixes: d0f2c25f52 ("cgroup2: devices: replace all existing filters when attaching")
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2021-07-14 11:17:19 +10:00
Aleksa Sarai 2c01cec8ac merge branch 'pr-3067'
Odin Ugedal (2):
  libct/cg/sd: Don't freeze cgroup on cgroup v2 Set
  Update device update tests

LGTMs: kolyshkin mrunalp cyphar
Closes #3067
2021-07-13 12:59:29 +10:00
Mrunal Patel dc3236f957 Merge pull request #3070 from kolyshkin/unconvert
ci: enable unconvert linter, fix its warnings
2021-07-12 16:47:14 -04:00
Akihiro Suda 3a041e9654 Merge pull request #3081 from kolyshkin/carry-3065
Make cgroup freezer only care about current control group (carry #3065)
2021-07-12 13:09:40 +09:00
Qiang Huang 9493bb8268 Merge pull request #3041 from kolyshkin/rtd-cleanups
libcontainer/intelrdt: cleanups
2021-07-10 11:54:43 +08:00
Kir Kolyshkin 497e4032bd Merge pull request #3058 from kinvolk/rata/nsexec-close-bug
libcontainer: Don't close already closed fds and bail on close(2) failures
2021-07-09 11:35:36 -07:00
Odin Ugedal 3e5c199708 libct/cg/sd: Add freezer tests
This test the issues fixed by the two preceding commits.

Co-Authored-By: Kir Kolyshkin <kolyshkin@gmail.com>
Signed-off-by: Odin Ugedal <odin@uged.al>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-08 19:32:39 -07:00
Odin Ugedal 294c4866ea libct/cg/fs/freezer.GetState: report current cgroup state
If a control group is frozen, all its descendants will report FROZEN
in freezer.state cgroup file.

OTOH cgroup v2 cgroup.freeze is not reporting the cgroup as frozen
unless it is frozen directly (i.e. not via an ancestor).

Fix the discrepancy between v1 and v2 drivers behavior by
looking into freezer.self_freezing cgroup file, which, according
to kernel documentation, will show 1 iff the cgroup was frozen directly.

Co-authored-by: Kir Kolyshkin <kolyshkin@gmail.com>
Signed-off-by: Odin Ugedal <odin@uged.al>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-08 19:32:08 -07:00
Aleksa Sarai 262f294a2a merge branch 'pr-3062'
Kir Kolyshkin (3):
  libct/user: use []byte more, avoid allocations
  libct/user: ParseGroupFilter: use TrimSpace
  libct/user: fix parsing long /etc/group lines

LGTMs: AkihiroSuda cyphar
Closes #3062
2021-07-08 17:10:26 +10:00
Odin Ugedal f33be7cc98 libct/cg/sd: Don't freeze cgroup on cgroup v2 Set
Since device updates in cgroup v2 are atomic for systemd, there is no
need to freeze the processes before running the updates.

Signed-off-by: Odin Ugedal <odin@uged.al>
2021-07-07 22:44:08 +02:00
Kir Kolyshkin be1d5f83c0 ci: enable unconvert linter, fix its warnings
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-07 10:42:48 -07:00
Kir Kolyshkin 24d5daf54d libct/user: fix parsing long /etc/group lines
Lines in /etc/group longer than 64 characters breaks the current
implementation of group parser. This is caused by bufio.Scanner
buffer limit.

Fix by re-using the fix for a similar problem in golang os/user,
namely https://go-review.googlesource.com/c/go/+/283601.

Add some tests.

Co-authored-by: Andrey Bokhanko <andreybokhanko@gmail.com>
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-02 13:19:42 -07:00
Kir Kolyshkin 226dfab0bc libct/user: ParseGroupFilter: use TrimSpace
Same as in other places (other parsers here, as well as golang os/user
parser and glibc parser all tolerate extra space at BOL and EOL).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-02 12:25:51 -07:00
Kir Kolyshkin 120e3a77d8 libct/user: use []byte more, avoid allocations
Every []byte to string conversion results in a new allocation.
Avoid some by using []byte more.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-02 12:25:45 -07:00
Rodrigo Campos 83776dd8b3 libcontainer: Bail on close(2) failures
Don't ignore close(2) return code, rather bail if there is any
unexpected failures. By checking the close return code we make sure we
don't introduce the same bug (closing an already closed fd) I've fixed
in the previous patch.

As a side note, we are not handling in this patch when close(2) returns
EINTR and the go runtime, since go 1.14, sends SIGURG to preempt
goroutines. This should not happen here though, as nsenter is guaranteed
to be executed before the go runtime starts.

Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io>
2021-07-02 16:43:25 +02:00
Rodrigo Campos 7d479e6beb libcontainer: Don't close fds already closed
This was closed in the child[1], before calling clone_parent (so runc
INIT will have this fd closed too), there is no point closing it again.

This was not causing issues because we ignore the return code of
close(2) and no one was opening a new fd between both calls to close.
However, with the new patches that I'm working on (PR #2576), this
problem is no longer inocuos: we do open a new fd in that PR, sometimes
that fd is allocated between the two close(2) calls and, as the lowest
fd is allocated to the new fd, sometimes the second close ends up
incorrectly closing this new fd.

Before it was not a problem in practice, but it was incorrect
nevertheless.

This seems to be long standing bug, present since at least 2018
(a54316bae), when SYNC_GRANDCHILD was introduced.

[1]: https://github.com/opencontainers/runc/blob/5547b5774f71f75a088e7432fa961778750a0fbd/libcontainer/nsenter/nsexec.c#L888

Co-authored-by: Alban Crequy <alban@kinvolk.io>
Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io>
2021-07-02 15:55:11 +02:00
Maksim An e39ad65059 retry unix.EINTR for container init process
When running a script from an azure file share interrupted syscall
occurs quite frequently, to remedy this add retries around execve
syscall, when EINTR is returned.

Signed-off-by: Maksim An <maksiman@microsoft.com>
2021-06-30 22:22:31 -07:00
Akihiro Suda 5547b5774f Merge pull request #3033 from kolyshkin/rm-own-errors
libcontainer: rm own error system
2021-07-01 13:47:27 +09:00
Kailun Qin c508a7bc0a libct/rootfs: consolidate utils imports
Signed-off-by: Kailun Qin <kailun.qin@intel.com>
2021-06-30 06:49:38 -04:00
Kir Kolyshkin 0229a77a80 libcontainer/intelrdt: privatize some ids
These are not used anywhere outside of the package
(I have also checked the only external user of the package
(github.com/google/cadvisor).

No changes other than changing the case. The following
identifiers are now private:

 * IntelRdtTasks
 * NewLastCmdError
 * NewStats

Brought to you by gorename.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-06-28 12:45:28 -07:00
Kir Kolyshkin 8f8dfc498a libcontainer/intelrdt: move NewLastCmdError down
... the stack, so every caller will automatically benefit from it.

The only change that it causes is the user in
libcontainer/process_linux.go will get a better error message.

[v2: typo fix]

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-06-28 12:45:28 -07:00
Kir Kolyshkin 00d1562967 libct/intelrdt: simplify NewLastCmdError
For errors that only have a string and an underlying error, using
fmt.Errorf with %w to wrap an error is sufficient.

In this particular case, the code is simplified, and now we have
unwrappable errors as a bonus (same could be achieved by adding
(*LastCmdError).Unwrap() method, but that's adding more code).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-06-28 12:45:28 -07:00
Kir Kolyshkin e0ce428bce libct/intelrdt: remove NotFoundError type
Initially, this was copied over from libcontainer/cgroups, where it made
sense as for cgroup v1 we have multiple controllers and mount points.

Here, we only have a single mount, so there's no need for the whole
type.

Replace all that with a simple error (which is currently internal since
the only user is our own test case).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-06-28 12:45:28 -07:00
Kir Kolyshkin feff2c451e libct/intelrdt: fix potential nil dereference
In case getIntelRdtData() returns an error, d is set to nil.

In case the error returned is of NotFoundError type (which happens
if resctlr mount is not found in /proc/self/mountinfo), the function
proceeds to call d.join(), resulting in a nil deref and a panic.

In practice, this never happens in runc because of the checks in
intelrdt() function in libcontainer/configs/validate, which raises
an error in case any of the parameters are set in config but
the IntelRTD itself is not available (that includes checking
that the mount point is there).

Nevertheless, the code is wrong, and can result in nil dereference
if some external users uses Apply on a system without resctrl mount.

Fix this by removing the exclusion.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-06-28 12:45:28 -07:00
Kir Kolyshkin 82498e3d77 libct/specconf: remove unneeded checks
In cases we have something like

	if y != "" {
		x = y
	}

where both x and y are strings, and x was not set before,
it makes no sense to have a condition, as such code is
equivalent to mere

	x = y

Simplify such cases by removing "if".

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-06-28 12:45:28 -07:00
Kir Kolyshkin 70fdc0573d Revert "checkpoint: resolve symlink for external bind mount"
This reverts commit da22625f69
(PR 2902).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-06-24 20:52:43 -07:00
Mrunal Patel 1079288bef Merge pull request #2902 from liusdu/checkpoint
checkpoint: resolve symlink for external bind mount
2021-06-24 22:52:02 -04:00
Mrunal Patel 245fe2b678 Merge pull request #3029 from liusdu/work
checkpoint: set default work-dir to image-path
2021-06-24 22:44:48 -04:00