Commit Graph

1871 Commits

Author SHA1 Message Date
Kir Kolyshkin 1820c42547 Merge pull request #2768 from kolyshkin/unit-386
ci/gha: add i386 unit test
2021-02-25 18:23:36 -08:00
Akihiro Suda d56a9c67ac Merge pull request #2812 from kolyshkin/memory-tight 2021-02-26 10:52:17 +09:00
Akihiro Suda 8bddca5118 Merge pull request #2819 from Iceber/fix-comment
libcontainer: fix LinuxFactory comments
2021-02-25 18:08:04 +09:00
Mrunal Patel d11985a586 Merge pull request #2799 from kolyshkin/race1
Fix data races, enable testing with -race
2021-02-24 16:37:34 -08:00
Iceber Gu 916654fffa libcontainer: fix LinuxFactory comments
Signed-off-by: Iceber Gu <wei.cai-nat@daocloud.io>
2021-02-24 15:51:06 +08:00
Aleksa Sarai c153261830 merge branch 'pr-2786'
Daniel Dao (1):
  Do not convert blkio weight value using blkio->io conversion scheme

LGTMs: @kolyshkin @AkihiroSuda @cyphar
Closes #2786
2021-02-24 18:29:27 +11:00
Daniel Dao c3ffd2ef81 Do not convert blkio weight value using blkio->io conversion scheme
bfq weight controller (i.e. io.bfq.weight if present) is still using the
same bfq weight scheme (i.e 1->1000, see [1].) Unfortunately the
documentation for this was wrong, and only fixed recently [2].

Therefore, if we map blkio weight to io.bfq.weight, there's no need to
do any conversion. Otherwise, we will try to write invalid value which
results in error such as:

```
time="2021-02-03T14:55:30Z" level=error msg="container_linux.go:367: starting container process caused: process_linux.go:495: container init caused: process_linux.go:458: setting cgroup config for procHooks process caused: failed to write \"7475\": write /sys/fs/cgroup/runc-cgroups-integration-test/test-cgroup/io.bfq.weight: numerical result out of range"
```

[1] https://github.com/torvalds/linux/blob/master/Documentation/block/bfq-iosched.rst
[2] https://github.com/torvalds/linux/commit/65752aef0a407e1ef17ec78a7fc31ba4e0b360f9

Signed-off-by: Daniel Dao <dqminh89@gmail.com>
2021-02-23 19:46:16 -08:00
Kir Kolyshkin 38b2dd391d runc exec: report possible OOM kill
An exec may fail due to memory shortage (cgroup memory limits being too
tight), and an error message provided in this case is clueless:

> $ sudo ../runc/runc exec xx56 top
> ERRO[0000] exec failed: container_linux.go:367: starting container process caused: read init-p: connection reset by peer

Same as the previous commit for run/start, check the OOM kill counter
and report an OOM kill.

The differences from run are

1. The container is already running and OOM kill counter might not be
   zero.  This is why we have to read the counter before exec and after
   it failed.

2. An unrelated OOM kill event might occur in parallel with our exec
   (and I see no way to find out which process was killed, except to
   parse kernel logs which seems excessive and not very reliable).
   This is why we report _possible_ OOM kill.

With this commit, the error message looks like:

> ERRO[0000] exec failed: container_linux.go:367: starting container process caused: process_linux.go:105: possibly OOM-killed caused: read init-p: connection reset by peer

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-23 16:16:33 -08:00
Kir Kolyshkin 5d0ffbf9c8 runc start/run: report OOM
In some cases, container init fails to start because it is killed by
the kernel OOM killer. The errors returned by runc in such cases are
semi-random and rather cryptic. Below are a few examples.

On cgroup v1 + systemd cgroup driver:

> process_linux.go:348: copying bootstrap data to pipe caused: write init-p: broken pipe

> process_linux.go:352: getting the final child's pid from pipe caused: EOF

On cgroup v2:

> process_linux.go:495: container init caused: read init-p: connection reset by peer

> process_linux.go:484: writing syncT 'resume' caused: write init-p: broken pipe

This commits adds the OOM method to cgroup managers, which tells whether
the container was OOM-killed. In case that has happened, the original error
is discarded (unless --debug is set), and the new OOM error is reported
instead:

> ERRO[0000] container_linux.go:367: starting container process caused: container init was OOM-killed (memory limit too low?)

Also, fix the rootless test cases that are failing because they expect
an error in the first line, and we have an additional warning now:

> unable to get oom kill count" error="no directory specified for memory.oom_control

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-23 16:15:33 -08:00
Kir Kolyshkin 7e137b9044 libct/cg/fs2/hugetlb: use fscommon.GetValueByKey
This makes the code simpler and more future-proof, in case
any more values will appear in hugetlb.*.events.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-23 16:11:55 -08:00
Kir Kolyshkin 9fa65f6607 libct/cg/fscommon: add GetValueByKey
Generalize the libct/getValueFromCgroup() as fscommon.GetValueByKey(),
and document it.

No changes other than using fscommon.ParseUint to convert the value.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-23 16:11:55 -08:00
Kir Kolyshkin c54c3f852d libcontainer/notify_linux_v2: use fscommon.ReadFile
This is to benefit from openat2() implementation, on kernels
that support it. Theoretically this also improves security.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-23 16:11:55 -08:00
Kir Kolyshkin 494f900e91 libct/cg/fscommon: rename/facelift GetCgroupParamKeyValue
1. This is the only function in the package with Get prefix
   that does not read a file (but parses a string). Rename
   accordingly, and convert the callers.

	GetCgroupParamKeyValue -> ParseKeyValue

2. Use strings.Split rather than strings.Fields. Split by a space
   is 2x faster, plus we can limit the splitting. The downside is
   we have to strip a newline in one of the callers.

3. Improve the doc and the code flow.

4. Fix a test case with invalid data (spaces at BOL).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-23 16:11:55 -08:00
Kir Kolyshkin 1880d2fc05 libct/cg/fs/memory: handle EBUSY
EBUSY when trying to set memory limit may mean the new limit is too low
(lower than the current usage, and the kernel can't do anything).
Provide a more specific error for such case.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-23 16:11:55 -08:00
Kir Kolyshkin 27fd3fc3ce libct/cg/fs: setMemoryAndSwap: refactor
1. Factor out setMemory and setSwap
2. Pass cgroup.Resources (rather than cgroup) to setMemoryAndSwap().
3. Merge the duplicated "set memory, set swap" case.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-23 16:11:55 -08:00
Kir Kolyshkin 3cced523a5 libct/cg/fs/memory: optimize Set
Currently, we read and parse 5 different files while we only need 1.

Use GetCgroupParamUint() directly to get current limit.

While at it, remove the workaround previously needed for the unit test,
and make it a bit more verbose.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-23 16:11:55 -08:00
Mrunal Patel f36d64d683 Merge pull request #2814 from kolyshkin/systemd-apply
libct/cgroups/systemd: don't set limits in Apply
2021-02-23 15:16:43 -08:00
Mrunal Patel e00273e09d Merge pull request #2816 from odinuge/cgroup-v2-cache
Fix memory stats for cache in fs2
2021-02-23 14:59:42 -08:00
Akihiro Suda f245b8c207 Merge pull request #2815 from hnts/update_readme 2021-02-23 22:12:42 +09:00
Ryosuke Hanatsuka 53d3b5524a Update README.md for libcontainer
Signed-off-by: Ryosuke Hanatsuka <hanatsuu@gmail.com>
2021-02-23 11:21:34 +09:00
Odin Ugedal 6c5ed0db3a Fix memory stats for cache in fs2
In cgroup v2, the "cache" value from cgroup v1 is called "file" in v2.
There are no values called "cache" in v2.

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/mm/memcontrol.c?id=31caf8b2a847214be856f843e251fc2ed2cd1075#n1521
Signed-off-by: Odin Ugedal <odin@uged.al>
2021-02-22 12:27:12 +01:00
Kir Kolyshkin af521ed580 libct/cgroups/systemd: don't set limits in Apply
All cgroup managers has Apply() and Set() methods:

 - Apply is used to create a cgroup (and, in case of systemd,
   a systemd unit) and/or put a PID into the cgroup (and unit);

 - Set is used to set various cgroup resources and limits.

The fs/fs2 cgroup manager implements the functionality as described above.

The systemd v1/v2 manager deviate -- it sets *most* of cgroup limits
(those that can be projected to systemd unit properties) in Apply(),
and then again *all* cgroup limits in Set (first indirectly via systemd
properties -- same as in Apply, then via cgroupfs).

This commit removes setting the cgroup limits from Apply,
so now the systemd manager behaves the same way as the fs manager.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-19 18:53:24 -08:00
Iceber Gu fa52df9493 libcontainer: fix the file mode of the device
Signed-off-by: Iceber Gu <wei.cai-nat@daocloud.io>
2021-02-17 15:08:22 +08:00
Mrunal Patel 824e4ad3b8 Merge pull request #2803 from AkihiroSuda/fix-arch-apparmor
apparmor: try attr/apparmor/exec before attr/exec
2021-02-10 10:29:13 -08:00
Akihiro Suda 9f1365373d Merge pull request #2796 from vasiliy-ul/ebpf-fix-device-access-check
ebpf: fix device access check
2021-02-10 16:37:01 +09:00
Akihiro Suda f3f563bc0f apparmor: try attr/apparmor/exec before attr/exec
Fix issue 2801

Tested on Arch Linux with the following configuration
```
[root@archlinux ~]# pacman -Q runc containerd docker linux
runc 1.0.0rc93-1
containerd 1.4.3-1
docker 1:20.10.3-1
linux 5.10.14.arch1-1

[root@archlinux ~]# cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-linux root=UUID=bd8aaf58-8735-4fd5-a0c1-804a998f8d57 rw net.ifnames=0 rootflags=compress-force=zstd apparmor=1 lsm=capability,lockdown,yama,bpf,apparmor

[root@archlinux ~]# cat /etc/docker/daemon.json
{
  "runtimes": {
    "runc-tmp": {
      "path": "/tmp/runc"
    }
  }
}

[root@archlinux ~]# docker run -it --rm alpine
docker: Error response from daemon: OCI runtime create failed: container_linux.go:367: starting container process caused: process_linux.go:495: container init caused: apply apparmor profile: apparmor failed to apply profile: write /proc/self/attr/exec: invalid argument: unknown.

[root@archlinux ~]# docker run -it --rm --runtime=runc-tmp alpine
/ # cat /proc/self/attr/apparmor/current
docker-default (enforce)
/ # cat /proc/self/attr/current
cat: read error: Invalid argument
``

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
2021-02-10 16:27:13 +09:00
Mrunal Patel 2dbfa87477 Merge pull request #2793 from cyphar/cgroup2-ebpf-userns
cgroup2: devices: handle eBPF skipping more correctly
2021-02-09 15:12:12 -08:00
Kir Kolyshkin b774454736 libct/int: fix a data race
Fix for the following:

$ sudo go test -race -v ./libcontainer/integration/
=== RUN   TestUsernsCheckpoint
==================
WARNING: DATA RACE
Write at 0x00c00019e650 by goroutine 15:
  bytes.(*Buffer).ReadFrom()
      /usr/lib/golang/src/bytes/buffer.go:200 +0x48
  io.copyBuffer()
      /usr/lib/golang/src/io/io.go:395 +0x3fe
  io.Copy()
      /usr/lib/golang/src/io/io.go:368 +0x7a
  os/exec.(*Cmd).writerDescriptor.func1()
      /usr/lib/golang/src/os/exec/exec.go:311 +0x4a
  os/exec.(*Cmd).Start.func1()
      /usr/lib/golang/src/os/exec/exec.go:441 +0x38

Previous write at 0x00c00019e650 by goroutine 12:
  bytes.(*Buffer).ReadFrom()
      /usr/lib/golang/src/bytes/buffer.go:200 +0x48
  io.copyBuffer()
      /usr/lib/golang/src/io/io.go:395 +0x3fe
  io.Copy()
      /usr/lib/golang/src/io/io.go:368 +0x7a
  os/exec.(*Cmd).writerDescriptor.func1()
      /usr/lib/golang/src/os/exec/exec.go:311 +0x4a
  os/exec.(*Cmd).Start.func1()
      /usr/lib/golang/src/os/exec/exec.go:441 +0x38

Goroutine 15 (running) created at:
  os/exec.(*Cmd).Start()
      /usr/lib/golang/src/os/exec/exec.go:440 +0xaaa
  github.com/opencontainers/runc/libcontainer.(*linuxContainer).criuSwrk()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/container_linux.go:1490 +0x5f7
  github.com/opencontainers/runc/libcontainer.(*linuxContainer).Restore()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/container_linux.go:1398 +0x29ef
  github.com/opencontainers/runc/libcontainer/integration.testCheckpoint()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go:204 +0x1898
  github.com/opencontainers/runc/libcontainer/integration.TestUsernsCheckpoint()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go:48 +0x177
  testing.tRunner()
      /usr/lib/golang/src/testing/testing.go:1123 +0x202

Goroutine 12 (finished) created at:
  os/exec.(*Cmd).Start()
      /usr/lib/golang/src/os/exec/exec.go:440 +0xaaa
  github.com/opencontainers/runc/libcontainer.(*initProcess).start()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/process_linux.go:313 +0xda
  github.com/opencontainers/runc/libcontainer.(*linuxContainer).start()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/container_linux.go:366 +0xb0
  github.com/opencontainers/runc/libcontainer.(*linuxContainer).Start()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/container_linux.go:263 +0x27b
  github.com/opencontainers/runc/libcontainer.(*linuxContainer).Run()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/container_linux.go:273 +0x46
  github.com/opencontainers/runc/libcontainer/integration.testCheckpoint()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go:108 +0x941
  github.com/opencontainers/runc/libcontainer/integration.TestUsernsCheckpoint()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go:48 +0x177
  testing.tRunner()
      /usr/lib/golang/src/testing/testing.go:1123 +0x202
==================
==================
WARNING: DATA RACE
Read at 0x00c00019e630 by goroutine 15:
  bytes.(*Buffer).Len()
      /usr/lib/golang/src/bytes/buffer.go:73 +0x58
  bytes.(*Buffer).grow()
      /usr/lib/golang/src/bytes/buffer.go:118 +0x4f
  bytes.(*Buffer).ReadFrom()
      /usr/lib/golang/src/bytes/buffer.go:202 +0x7c
  io.copyBuffer()
      /usr/lib/golang/src/io/io.go:395 +0x3fe
  io.Copy()
      /usr/lib/golang/src/io/io.go:368 +0x7a
  os/exec.(*Cmd).writerDescriptor.func1()
      /usr/lib/golang/src/os/exec/exec.go:311 +0x4a
  os/exec.(*Cmd).Start.func1()
      /usr/lib/golang/src/os/exec/exec.go:441 +0x38

Previous write at 0x00c00019e630 by goroutine 12:
  bytes.(*Buffer).ReadFrom()
      /usr/lib/golang/src/bytes/buffer.go:209 +0x1c4
  io.copyBuffer()
      /usr/lib/golang/src/io/io.go:395 +0x3fe
  io.Copy()
      /usr/lib/golang/src/io/io.go:368 +0x7a
  os/exec.(*Cmd).writerDescriptor.func1()
      /usr/lib/golang/src/os/exec/exec.go:311 +0x4a
  os/exec.(*Cmd).Start.func1()
      /usr/lib/golang/src/os/exec/exec.go:441 +0x38

Goroutine 15 (running) created at:
  os/exec.(*Cmd).Start()
      /usr/lib/golang/src/os/exec/exec.go:440 +0xaaa
  github.com/opencontainers/runc/libcontainer.(*linuxContainer).criuSwrk()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/container_linux.go:1490 +0x5f7
  github.com/opencontainers/runc/libcontainer.(*linuxContainer).Restore()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/container_linux.go:1398 +0x29ef
  github.com/opencontainers/runc/libcontainer/integration.testCheckpoint()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go:204 +0x1898
  github.com/opencontainers/runc/libcontainer/integration.TestUsernsCheckpoint()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go:48 +0x177
  testing.tRunner()
      /usr/lib/golang/src/testing/testing.go:1123 +0x202

Goroutine 12 (finished) created at:
  os/exec.(*Cmd).Start()
      /usr/lib/golang/src/os/exec/exec.go:440 +0xaaa
  github.com/opencontainers/runc/libcontainer.(*initProcess).start()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/process_linux.go:313 +0xda
  github.com/opencontainers/runc/libcontainer.(*linuxContainer).start()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/container_linux.go:366 +0xb0
  github.com/opencontainers/runc/libcontainer.(*linuxContainer).Start()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/container_linux.go:263 +0x27b
  github.com/opencontainers/runc/libcontainer.(*linuxContainer).Run()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/container_linux.go:273 +0x46
  github.com/opencontainers/runc/libcontainer/integration.testCheckpoint()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go:108 +0x941
  github.com/opencontainers/runc/libcontainer/integration.TestUsernsCheckpoint()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go:48 +0x177
  testing.tRunner()
      /usr/lib/golang/src/testing/testing.go:1123 +0x202
==================
==================
WARNING: DATA RACE
Read at 0x00c00019e648 by goroutine 15:
  bytes.(*Buffer).Len()
      /usr/lib/golang/src/bytes/buffer.go:73 +0x7e
  bytes.(*Buffer).grow()
      /usr/lib/golang/src/bytes/buffer.go:118 +0x4f
  bytes.(*Buffer).ReadFrom()
      /usr/lib/golang/src/bytes/buffer.go:202 +0x7c
  io.copyBuffer()
      /usr/lib/golang/src/io/io.go:395 +0x3fe
  io.Copy()
      /usr/lib/golang/src/io/io.go:368 +0x7a
  os/exec.(*Cmd).writerDescriptor.func1()
      /usr/lib/golang/src/os/exec/exec.go:311 +0x4a
  os/exec.(*Cmd).Start.func1()
      /usr/lib/golang/src/os/exec/exec.go:441 +0x38

Previous write at 0x00c00019e648 by goroutine 12:
  bytes.(*Buffer).grow()
      /usr/lib/golang/src/bytes/buffer.go:147 +0x2d7
  bytes.(*Buffer).ReadFrom()
      /usr/lib/golang/src/bytes/buffer.go:202 +0x7c
  io.copyBuffer()
      /usr/lib/golang/src/io/io.go:395 +0x3fe
  io.Copy()
      /usr/lib/golang/src/io/io.go:368 +0x7a
  os/exec.(*Cmd).writerDescriptor.func1()
      /usr/lib/golang/src/os/exec/exec.go:311 +0x4a
  os/exec.(*Cmd).Start.func1()
      /usr/lib/golang/src/os/exec/exec.go:441 +0x38

Goroutine 15 (running) created at:
  os/exec.(*Cmd).Start()
      /usr/lib/golang/src/os/exec/exec.go:440 +0xaaa
  github.com/opencontainers/runc/libcontainer.(*linuxContainer).criuSwrk()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/container_linux.go:1490 +0x5f7
  github.com/opencontainers/runc/libcontainer.(*linuxContainer).Restore()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/container_linux.go:1398 +0x29ef
  github.com/opencontainers/runc/libcontainer/integration.testCheckpoint()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go:204 +0x1898
  github.com/opencontainers/runc/libcontainer/integration.TestUsernsCheckpoint()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go:48 +0x177
  testing.tRunner()
      /usr/lib/golang/src/testing/testing.go:1123 +0x202

Goroutine 12 (finished) created at:
  os/exec.(*Cmd).Start()
      /usr/lib/golang/src/os/exec/exec.go:440 +0xaaa
  github.com/opencontainers/runc/libcontainer.(*initProcess).start()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/process_linux.go:313 +0xda
  github.com/opencontainers/runc/libcontainer.(*linuxContainer).start()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/container_linux.go:366 +0xb0
  github.com/opencontainers/runc/libcontainer.(*linuxContainer).Start()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/container_linux.go:263 +0x27b
  github.com/opencontainers/runc/libcontainer.(*linuxContainer).Run()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/container_linux.go:273 +0x46
  github.com/opencontainers/runc/libcontainer/integration.testCheckpoint()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go:108 +0x941
  github.com/opencontainers/runc/libcontainer/integration.TestUsernsCheckpoint()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/integration/checkpoint_test.go:48 +0x177
  testing.tRunner()
      /usr/lib/golang/src/testing/testing.go:1123 +0x202
==================
    testing.go:1038: race detected during execution of test
--- FAIL: TestUsernsCheckpoint (0.62s)

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-08 15:33:24 -08:00
Vasiliy Ulyanov 81707abd33 ebpf: fix device access check
Checking the access mode as bellow

    if (R3 & bpfAccess == 0 /* use R1 as a temp var */) goto next

does not handle correctly device file probing with:

    access(dev_name, F_OK)

F_OK does not trigger read or write access. Instead the access type in
R3 in that case will be zero and the check will not pass even if "rw" is
allowed for the device file. Comparing the 'masked' access type with the
requested one solves the issue:

    if (R3 & bpfAccess != R3 /* use R1 as a temp var */) goto next

Signed-off-by: Vasiliy Ulyanov <vulyanov@suse.de>
2021-02-07 19:33:10 +01:00
Aleksa Sarai 94ae7afa36 merge branch 'pr-2791'
Kir Kolyshkin (1):
  cgroupv1 freezer: thaw to increase freeze chances

LGTMs: @cyphar @dqminh
Closes #2791
2021-02-07 19:04:04 +11:00
Kir Kolyshkin c342872276 libct/config: fix a data race
As reported by go test -race ./libcontainer/configs:

=== RUN   TestCommandHookRunTimeout
==================
WARNING: DATA RACE
Read at 0x00c000202230 by goroutine 23:
  os/exec.(*Cmd).Wait()
      /usr/lib/golang/src/os/exec/exec.go:502 +0x91
  github.com/opencontainers/runc/libcontainer/configs.Command.Run()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/configs/config.go:390 +0x58c
  github.com/opencontainers/runc/libcontainer/configs_test.TestCommandHookRunTimeout()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/configs/config_test.go:223 +0x3ed
  testing.tRunner()
      /usr/lib/golang/src/testing/testing.go:1123 +0x202

Previous write at 0x00c000202230 by goroutine 27:
  os/exec.(*Cmd).Wait()
      /usr/lib/golang/src/os/exec/exec.go:505 +0xb4
  github.com/opencontainers/runc/libcontainer/configs.Command.Run.func1()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/configs/config.go:373 +0x55

Goroutine 23 (running) created at:
  testing.(*T).Run()
      /usr/lib/golang/src/testing/testing.go:1168 +0x5bb
  testing.runTests.func1()
      /usr/lib/golang/src/testing/testing.go:1439 +0xa6
  testing.tRunner()
      /usr/lib/golang/src/testing/testing.go:1123 +0x202
  testing.runTests()
      /usr/lib/golang/src/testing/testing.go:1437 +0x612
  testing.(*M).Run()
      /usr/lib/golang/src/testing/testing.go:1345 +0x3b3
  main.main()
      _testmain.go:69 +0x236

Goroutine 27 (running) created at:
  github.com/opencontainers/runc/libcontainer/configs.Command.Run()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/configs/config.go:372 +0x415
  github.com/opencontainers/runc/libcontainer/configs_test.TestCommandHookRunTimeout()
      /home/kir/go/src/github.com/opencontainers/runc/libcontainer/configs/config_test.go:223 +0x3ed
  testing.tRunner()
      /usr/lib/golang/src/testing/testing.go:1123 +0x202
==================
    testing.go:1038: race detected during execution of test
--- FAIL: TestCommandHookRunTimeout (0.10s)

Apparently, the issue is we call two Wait()s for the same command
which can race internally.

Fix is easy -- since we already have a waiting goroutine,
wait for it to return instead of calling a second Wait().

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-05 13:02:47 -08:00
Aleksa Sarai b142a70ece libct/seccomp/patchpbf/test: fix for 32-bit
This test fails to compile on i386:

> libcontainer/seccomp/patchbpf/enosys_linux_test.go:180:20: constant 3735928559 overflows int
> libcontainer/seccomp/patchbpf/enosys_linux_test.go:204:19: constant 3735928559 overflows int
> libcontainer/seccomp/patchbpf/enosys_linux_test.go:227:25: constant 3735928559 overflows int

This is because golang.org/x/net/bpf returns an int from their emulated
BPF VM implementation when they should really be returning uint32.

Fix by switching to uint32 in the test code.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-05 11:49:43 -08:00
Aleksa Sarai 2831fb5595 cgroup2: devices: handle eBPF skipping more correctly
In the past we incorrectly handled eBPF errors in two ways:

 1. We would only ignore errors if there was an allow rule in the list
    (this doesn't make sense because for security purposes we only care
    if a *deny* rule is being ignored). Arguably this is a security flaw
    but you would only get an error from bpf(2) in rare cases, and thus
    is not a big enough deal to go through security review.

 2. If we were in a rootless container we would still return an error
    even though bpf(2) is blocked for rootless containers.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2021-02-05 18:13:06 +11:00
Akihiro Suda 9f1e43ea69 Merge pull request #2741 from kolyshkin/test-images 2021-02-05 15:30:43 +09:00
Kir Kolyshkin d1007b08a3 cgroupv1 freezer: thaw to increase freeze chances
It appears that briefly thawing the cgroup while freezing
greatly increases its chances to freeze successfully.

The test case I used is doing runc exec in a look parallel with runc
pause/resume in another loop, and the failure to freeze rate reduced
from 40 to 0 per minute (tested inside a VM using a busybox container
running sleep 1h, doing about 1500 pause/resumes and 650 execs per
minute), with max retries being 150 (of 1000).

This is still a game of chances, so failures are possible.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-04 15:06:11 -08:00
Mauricio Vásquez 5c0342ba2c libcontainer: fix bad conversion from syscall.Errno to error
The correct way to do that conversion according to
https://pkg.go.dev/syscall#Errno is:

```
err = nil
if errno != 0 {
	err = errno
}
```

In this case the error check will always report a false positive in
unix.RawSyscall(unix.SYS_SECCOMP, ...), probably nobody has faced this
problem because the code takes the other path in most of the cases.

Fixes: 7a8d7162f9 ("seccomp: prepend -ENOSYS stub to all filters")

Signed-off-by: Mauricio Vásquez <mauricio@kinvolk.io>
2021-02-03 16:12:33 -05:00
Kir Kolyshkin 5ab0588432 ci: untangle getting test images
This simplifies and optimizes getting container images used for tests.

Currently, we have three different ways of getting images:

1. (for hello-world) the image is in this repo under tests/integration/testdata.

2. (for busybox) download it from github (the repo that is used for
   preparing official Docker image) using curl.

3. (for debian) download from Docker hub, using skopeo and umoci.

To further complicate things, we have to do this downloading in multiple
scenarios (at least 4): locally, in github CI, from Dockefile, inside a
Vagrant VM. For each scenario, we have to install skopeo and umoci, and
those two are not yet universally available for all the distros that we
use.

Yet another complication is those images are used for tests/integration
(bats-driven tests) as well as for libcontainer/integration (go tests).
The tests in libcontainer/integration rely on busybox being available
from /busybox, and the bats tests just download the images to a
temporary location during every run.

It is also hard to support CI for other architectures, because all
the machinery for preparing images is so complicated.

This commit is an attempt to simplify and optimize getting images,
mostly by getting rid of skopeo and umoci dependencies, but also
by moving the download logic into one small shell script, which
is used from all the places.

Benefits:

 - images (if not present) are only downloaded once;
 - same images are used for both kind of tests (go and bats);
 - same images are used for local and inside-docker tests
   (because source directory is mounted into container);
 - the download logic is located within 1 simple shell script.

[v2: fix eval; more doc to get-images; print URL if curl failed]
[v3: use "slim" debian, twice as small]
[v4: fix not using $image in setup_bundle]
[v5: don't remove TESTDATA from helpers.bash]
[v6: add i386 support]

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-02 16:03:29 -08:00
Aleksa Sarai 7e3c3e8c22 merge branch 'pr-2780'
Sebastiaan van Stijn (1):
  Remove "PatchAndLoad" stub as it's not used without seccomp enabled

LGTMs: @kolyshkin @cyphar
Closes #2780
2021-02-03 00:45:32 +11:00
Kir Kolyshkin 76ae1f5c31 libct/cg/fs/freezer: fix freezing race
Before this commit, Set() used GetState() to check the freezer state
and retry the operation if the actual state still differs from requested.
This should help with the situation when a new process (such as one
added by runc exec) is added to the container's cgroup while it's being
freezed by the kernel, but it's not working as it should.

The problem is, GetState() never returns FREEZING state, looping until
the state is either FROZEN or THAWED, so Set() does not have a chance
to repeate the freeze attempt.

As a result, the container might end up stuck in a FREEZING state,
with GetState() never returning (which in turn blocks some other
operations).

One way to fix this would be to have GetState returning FREEZING state
instead of retrying ad infinitum. It would result in changing the public
API, and no callers of GetState expects it to return this.

To fix, let's not use GetState() from Set(). Instead, read the
freezer.state file directly and act accordingly -- return success
on FROZEN, retry on FREEZING, and error out on any other (unexpected)
value.

While at it, further improve the code:
 - limit the number of retries;
 - if retries are exceeded, thaw and return an error;
 - don't retry (or read the state back) on THAW.

I played a lot with various reproducers for this bug, including

 - parallel runc execs and runc pause/resumes
 - parallel runc execs and runc --systemd-cgroup update
   (the latter performs freeze/unfreeze);
 - continuously running /bin/printf inside container
   in parallel with runc pause/resume;
 - running pthread bomb (from criu test suite) in parallel
   with runc pause/resume;

and I was not able to make freeze work 100%, meaning sometimes
runc pause fails, or runc --systemd-cgroup update produces a warning.

With that said, it's still a big improvement over the previous
state of affairs where container is stuck in FREEZING state,
and GetState() (and all its users) are also stuck.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-02-01 13:54:00 -08:00
Sebastiaan van Stijn c4bc3b080e Remove "PatchAndLoad" stub as it's not used without seccomp enabled
This function is called by `InitSeccomp`, but only when compiled
with seccomp (and cgo) enabled, so should not be needed for other
situations.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2021-02-01 22:01:59 +01:00
Kir Kolyshkin 6c85f6389e Merge pull request #2775 from cyphar/fix-build
cgroupfs: cpuset: fix broken build
2021-02-01 09:02:21 -08:00
Aleksa Sarai 4074b47975 merge branch 'pr-2636'
Kenta Tada (1):
  libcontainer/intelrdt: adjust the file mode

LGTMs: @AkihiroSuda @cyphar
Closes #2636
2021-02-01 20:50:25 +11:00
Akihiro Suda 2046f264ca Merge pull request #2755 from kolyshkin/numa-stat
libct/cg/fs: getPageUsageByNUMA: rewrite/optimize, fix panic, add more tests
2021-02-01 13:49:53 +09:00
Aleksa Sarai 6ddfaa5e95 cgroupfs: cpuset: fix broken build
The merge 6eed6e5795 broke the build because ab27e12ceb ("Implement
GetStat for cpuset cgroup.") dropped the errors import which was used by
c85cd2b325 ("libct/cg/fs/cpuset: don't parse mountinfo") and the CI
wasn't retriggered.

Fix this by just importing "github.com/pkg/errors" again.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2021-02-01 14:31:47 +11:00
Aleksa Sarai 091dd32dd1 merge branch 'pr-2607'
Sebastiaan van Stijn (1):
  libcontainer: move capabilities to separate package

LGTMs: @AkihiroSuda @cyphar
Closes #2607
2021-02-01 14:26:17 +11:00
Aleksa Sarai 6eed6e5795 merge branch 'pr-2599'
Kir Kolyshkin (4):
  libct/cgroups/fs/cpuset: don't use MkdirAll
  libct/cg/fs/cpuset: don't parse mountinfo
  libct/cg/fs.getCgroupRoot: reuse (cached) cgroup mountinfo
  libct/cgroups/v1_utils: implement mountinfo cache

LGTMs: @AkihiroSuda @cyphar
Closes #2599
2021-02-01 11:04:11 +11:00
Kir Kolyshkin c531a6f26a Merge pull request #2750 from cyphar/seccomp-patched-bpf
seccomp: prepend -ENOSYS stub to all filters
2021-01-31 11:54:41 -08:00
Akihiro Suda e7bd1fb10a Merge pull request #2717 from kolyshkin/check-proc-opt
libct/checkProcMounts: optimize
2021-01-29 17:32:45 +09:00
Mrunal Patel b8c2093338 Merge pull request #2738 from kolyshkin/unit-verbose
ci/unit tests: decrease verbosity
2021-01-28 15:34:06 -08:00
Aleksa Sarai 4160d74338 seccomp: add enosys unit tests
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2021-01-28 23:11:28 +11:00