snap-seccomp: add in-kernel bpf tests #3502

Merged
merged 20 commits into from Aug 31, 2017

Conversation

Projects
None yet
5 participants
Collaborator

mvo5 commented Jun 21, 2017

Based on #3431 - this adds extra tests by generating test binaries and run them against the in-kernel bpf VM.

codecov-io commented Jun 21, 2017

Codecov Report

Merging #3502 into master will increase coverage by 0.01%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #3502      +/-   ##
==========================================
+ Coverage    75.7%   75.72%   +0.01%     
==========================================
  Files         409      409              
  Lines       35227    35227              
==========================================
+ Hits        26670    26677       +7     
+ Misses       6672     6667       -5     
+ Partials     1885     1883       -2
Impacted Files Coverage Δ
overlord/snapstate/snapstate.go 80.7% <0%> (+0.25%) ⬆️
cmd/snap-seccomp/main.go 57.4% <0%> (+0.9%) ⬆️
cmd/snap/cmd_aliases.go 95% <0%> (+1.66%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 93c1d78...df89a28. Read the comment docs.

mvo5 added some commits Jun 21, 2017

mvo5 added some commits Jun 21, 2017

+1 assuming you agree with and address my comments

cmd/snap-seccomp/main_test.go
+int main(int argc, char **argv) {
+ int l[7];
+ for (int i=0; i<7;i++)
+ l[i] = atoi(argv[i+1]);
@jdstrand

jdstrand Jun 23, 2017

Contributor

strtol() is best practice, but as test code this is ok since we control all the input.

cmd/snap-seccomp/main_test.go
+ return err.Error()
+ }
+ l := strings.Split(string(output), "\n")
+ return l[len(l)-2]
@jdstrand

jdstrand Jun 23, 2017

Contributor

This is racy and trying to pick a needle out of a potential kernel logging haystack. It might be better to use lastKmsg() only when you have an unexpected error and return something like:

Showing last 10 lines of dmesg:
show
your
last
10
lines
of
dmesg
output
right
here
+ cmd.Stderr = os.Stderr
+ err = cmd.Run()
+ c.Assert(err, IsNil)
+
@jdstrand

jdstrand Jun 23, 2017

Contributor

Can you remove this newline?

+sysinfo
+exit
+# i386
+set_thread_area
@jdstrand

jdstrand Jun 23, 2017

Contributor

You might need other on other architectures. If so, these can of easily be identified in the spread tests.

@zyga

zyga Aug 16, 2017

Contributor

Yeah, I was about to write that this list is a great way to learn how linux userspace works across architectures. I don't mind having it but I bet this will bite us the first time this runs on s360 and you have to fix the tests.

@jdstrand

jdstrand Aug 30, 2017

Contributor

That's ok, it's easy to fix. Note that this list is not very different from what was in the old snap-confine unit tests.

cmd/snap-seccomp/main_test.go
+ if strings.Contains(bpfInput, "PR_SET_ENDIAN") {
+ c.Logf("cannot run PR_SET_ENDIAN in runBpfInKernel, this actually switches the endianess and the program crashes")
+ return
+ }
@jdstrand

jdstrand Jun 23, 2017

Contributor

Looking at man syscall, it seems we may also want to skip on the following syscalls: fadvise64_64, ftruncate64, posix_fadvise, pread64, pwrite64, readahead, sync_file_range, and truncate64. Please add a comment here that we just skip syscalls with architecture-specific details and in seccompSyscallRunnerContent (right above the call to syscall()) indicating that there might be architecture-specific requirements and to see man syscall for details.

- // https://github.com/golang/go/issues/20556
- // switch to x/net/bpf once we can simulate seccomp bpf there
- bpf.VmEndianness = nativeEndian()
+ s.runBpfInKernel(c, seccompWhitelist, bpfInput, expected)
@jdstrand

jdstrand Jun 23, 2017

Contributor

Now that you added this, can you adjust the comment above simulateBpf to have:

// simulateBpf first:
//  1. runs main.Compile() which will catch syntax errors and output to a file
//  2. takes the output file from main.Compile and loads it via
//     decodeBpfFromFile
//  3. parses the decoded bpf using the seccomp library and various
//     snapd functions
//  4. runs the parsed bpf through a bpf VM
//
// Then simulateBpf runs the policy through the kernel by calling
// runBpfInKernel() which:
//  1. runs main.Compile()
//  2. the program in seccompBpfLoaderContent with the output file as an
//     argument
//  3. the program in seccompBpfLoaderContent loads the output file BPF into
//     the kernel and executes the program in seccompBpfRunnerContent with the
//     syscall and arguments specified by the test
//
// In this manner, in addition to verifying policy syntax we are able to
// unit test the resulting bpf in several ways.
//
// Full testing of applied policy is done elsewhere via spread tests.

zyga and others added some commits Jul 18, 2017

Collaborator

mvo5 commented Jul 25, 2017

Thanks @jdstrand ! I addressed all comments now.

@pedronis pedronis requested a review from zyga Aug 3, 2017

A few comments, I probably missed the reason for some changes as this was done so long ago and some context is lost in my mind.

+ s.seccompSyscallRunner = filepath.Join(c.MkDir(), "seccomp_syscall_runner")
+ err = ioutil.WriteFile(s.seccompSyscallRunner+".c", seccompSyscallRunnerContent, 0644)
+ c.Assert(err, IsNil)
+ cmd = exec.Command("gcc", "-Werror", "-Wall", "-static", s.seccompSyscallRunner+".c", "-o", s.seccompSyscallRunner, "-Wl,-static", "-static-libgcc")
@zyga

zyga Aug 16, 2017

Contributor

Does the -static matter here? I'm worried about another place that does static linking across the distro landscape.

@mvo5

mvo5 Aug 22, 2017

Collaborator

Yes, it explodes with: /usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/libc.a(libc-start.o): relocation R_X86_64_32 against undefined symbol _dl_starting_up' can not be used when making a shared object; recompile with -fPIC without that.

@zyga

zyga Aug 30, 2017

Contributor

Aha, I don't know why this happens but it will be another thing that needs distro-patching as static linking to libseccomp is not a given. I'll investigate and see if I can make this nicer.

+sysinfo
+exit
+# i386
+set_thread_area
@jdstrand

jdstrand Jun 23, 2017

Contributor

You might need other on other architectures. If so, these can of easily be identified in the spread tests.

@zyga

zyga Aug 16, 2017

Contributor

Yeah, I was about to write that this list is a great way to learn how linux userspace works across architectures. I don't mind having it but I bet this will bite us the first time this runs on s360 and you have to fix the tests.

@jdstrand

jdstrand Aug 30, 2017

Contributor

That's ok, it's easy to fix. Note that this list is not very different from what was in the old snap-confine unit tests.

cmd/snap-seccomp/main_test.go
+ // Note that we will need to also skip: fadvise64_64,
+ // ftruncate64, posix_fadvise, pread64, pwrite64, readahead,
+ // sync_file_range, and truncate64.
+ // Once we start using those. See `man syscall`
@zyga

zyga Aug 16, 2017

Contributor

The comment and the next code block seem unrelated. Am I missing anything?

@mvo5

mvo5 Aug 22, 2017

Collaborator

I updated it a bit to clarify it some more. It is essentially about that we cannot test some syscalls using the in-kernel VM because when we run them things explodes.

+ args := strings.Split(l[2], ",")
+ for i := range args {
+ // init with random number argument
+ syscallArg := (uint64)(rand.Uint32())
@zyga

zyga Aug 16, 2017

Contributor

What's the point of this random value?

@mvo5

mvo5 Aug 22, 2017

Collaborator

Mostly to avoid that everything is set to "0" and we miss issues because we did not test other values.

@zyga

zyga Aug 30, 2017

Contributor

Can you adjust the comment to explain this.

@@ -233,7 +444,7 @@ func (s *snapSeccompSuite) TestCompile(c *C) {
{"read\nwrite\nexecve\n", "write", main.SeccompRetAllow},
// trivial denial
- {"read", "execve", main.SeccompRetKill},
+ {"read", "ioctl", main.SeccompRetKill},
@zyga

zyga Aug 16, 2017

Contributor

Why is this changed?

@mvo5

mvo5 Aug 22, 2017

Collaborator

Execve is now part of the common syscalls, i.e. it must be allowed so that we can actually run these tests here.

cmd/snap-seccomp/main_test.go
// bad input
- for _, bad := range []string{"quotactl;native;99999", "read;native;"} {
@zyga

zyga Aug 16, 2017

Contributor

Why is this changed?

mvo5 added some commits Aug 22, 2017

Thanks for adding the tests. I'm leaving the details for @zyga and @jdstrand. Only a trivial:

cmd/snap-seccomp/main_test.go
+#include<sys/syscall.h>
+#include<stdlib.h>
+int main(int argc, char **argv) {
+ int l[7];
@niemeyer

niemeyer Aug 29, 2017

Contributor

The indentation here is different from the one above. We have three spaces here and a tab above, apparently.

Contributor

niemeyer commented Aug 29, 2017

@zyga This is ready for another pass.

zyga and others added some commits Aug 30, 2017

cmd/snap-seccomp: format tests clang-format --style=webkit
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
cmd/snap-seccomp: fix punctuation/capitalization
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
cmd/snap-seccomp: fix another typo
Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
Contributor

jdstrand commented Aug 30, 2017

FYI, the changes since I approved this look fine (though I'm not sure we we chose 'webkit' for clang formatting, but not a blocker).

Collaborator

mvo5 commented Aug 30, 2017

@jdstrand I'm equally puzzled about the webkit formating but I agree its not a blocker.

Collaborator

mvo5 commented Aug 30, 2017

@jdstrand I'm equally puzzled about the webkit formating but I agree its not a blocker.

Contributor

niemeyer commented Aug 30, 2017

@jdstrand Can you please mark as an actual approval so it's more clear in the PR status?

@mvo5 mvo5 changed the title from snap-seccomp: add more tests to snap-seccomp: add in-kernel bpf tests Aug 30, 2017

zyga approved these changes Aug 30, 2017

:-)

mvo5 added some commits Aug 30, 2017

@mvo5 mvo5 merged commit 3748fe9 into snapcore:master Aug 31, 2017

5 of 7 checks passed

xenial-i386 autopkgtest finished (failure)
Details
yakkety-amd64 autopkgtest finished (failure)
Details
artful-amd64 autopkgtest finished (success)
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
xenial-amd64 autopkgtest finished (success)
Details
xenial-ppc64el autopkgtest finished (success)
Details
zesty-amd64 autopkgtest finished (success)
Details
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment