Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ebpf: fix device access check #2796

Merged

Conversation

vasiliy-ul
Copy link
Contributor

I was trying to expose a host character device to a container on a system with cgroup v2 enabled. Looks like there is an issue with permissions checking in the device filtering ebpf program that is loaded and attached to the container's cgroup.

This PR fixes the issue when a call to

access(dev_name, F_OK)

from a container fails with EPERM error even though the permissions for the device file are set to rw. The problem is not reproducible with rwm as in this case the check for permissions is skipped. Similar solution is used in systemd:

https://github.com/systemd/systemd/blob/8e45c72cf581a2224725469376d13ca4dcd77a74/src/core/bpf-devices.c#L145

I built and verified locally the proposed solution and also fixed the unit-tests accordingly. Hope the fix might be usefull.

Description

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

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>
@AkihiroSuda
Copy link
Member

Can we have an integration test in dev.bats ?

@cyphar
Copy link
Member

cyphar commented Feb 8, 2021

I think the wildcard behaviour is also incorrect (it ignores all entries after a wildcard). I think it would make far more sense to use the emulator to apply all of the rules and then create a program based on the minimal ruleset.

The test verifies if the device file can be queried using
'access(dev_name, F_OK)' when the permissions are set to 'rw'. The call
does not explicitly trigger read or write access but should succeed.

Signed-off-by: Vasiliy Ulyanov <vulyanov@suse.de>
@vasiliy-ul vasiliy-ul force-pushed the ebpf-fix-device-access-check branch from bc28eff to efb8552 Compare February 8, 2021 13:14
@vasiliy-ul
Copy link
Contributor Author

@AkihiroSuda , I added the test. Unfortunately I was not able to find some busybox tool that uses access syscall. Also the shell file tests (e.g. [ -e /dev/kmsg ]) are based on stat which cannot be used to reproduce the issue. Therefore I added a small C program that is built during testing.

@cyphar ,

I think the wildcard behaviour is also incorrect (it ignores all entries after a wildcard). I think it would make far more sense to use the emulator to apply all of the rules and then create a program based on the minimal ruleset.

I haven't not tried to apply a wildcard rule. In my case I have specific devices to allow. Though I think this fix should be valid also for the minimal rule set.

@cyphar
Copy link
Member

cyphar commented Feb 8, 2021

I'll work on the emulator patch myself, this patch is okay for now since it fixes a separate issue with the program generation.

Copy link
Member

@cyphar cyphar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@cyphar cyphar added this to the 1.0.0-rc94 milestone Feb 8, 2021
# test access
TEST_NAME="dev_access_test"
gcc -static -o "rootfs/bin/${TEST_NAME}" "${TESTDATA}/${TEST_NAME}.c"
runc exec test_allow_char sh -c "${TEST_NAME} /dev/kmsg"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably no need to wrap this into sh -c, iow

Suggested change
runc exec test_allow_char sh -c "${TEST_NAME} /dev/kmsg"
runc exec test_allow_char "${TEST_NAME}" /dev/kmsg

will work just fine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not important though

Copy link
Contributor Author

@vasiliy-ul vasiliy-ul Feb 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. I just followed the same approach as in other tests here. So used sh -c rather for consistency across this file. I would rather keep it just to have a common style.

Copy link
Contributor

@kolyshkin kolyshkin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kolyshkin
Copy link
Contributor

Unfortunately I was not able to find some busybox tool that uses access syscall.

You can actually use Debian Buster instead of Busybox for any test file, but I'm not sure you can find a simple binary that uses access(2) in there either.

@vasiliy-ul
Copy link
Contributor Author

Unfortunately I was not able to find some busybox tool that uses access syscall.

You can actually use Debian Buster instead of Busybox for any test file, but I'm not sure you can find a simple binary that uses access(2) in there either.

Yeah, I spent some time on strace'ing different tools trying to find such binary but eventually writing a small helper turned out to be the easiest solution.

@AkihiroSuda AkihiroSuda merged commit 9f13653 into opencontainers:master Feb 10, 2021
@vasiliy-ul vasiliy-ul deleted the ebpf-fix-device-access-check branch February 10, 2021 07:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants