Chromium Code Reviews| Index: sandbox/linux/seccomp-bpf-helpers/bpf_dsl_unittest.cc |
| diff --git a/sandbox/linux/seccomp-bpf-helpers/bpf_dsl_unittest.cc b/sandbox/linux/seccomp-bpf-helpers/bpf_dsl_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..f0ef259f73bec7e21d529d9f925c3fcb655b447a |
| --- /dev/null |
| +++ b/sandbox/linux/seccomp-bpf-helpers/bpf_dsl_unittest.cc |
| @@ -0,0 +1,210 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "sandbox/linux/seccomp-bpf-helpers/bpf_dsl.h" |
| + |
| +#include <errno.h> |
| +#include <netinet/in.h> |
| +#include <sys/socket.h> |
| +#include <sys/utsname.h> |
| + |
| +#include "base/macros.h" |
| +#include "sandbox/linux/seccomp-bpf/bpf_tests.h" |
| +#include "sandbox/linux/seccomp-bpf/errorcode.h" |
| +#include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" |
| + |
| +using namespace sandbox::bpf_dsl; |
| + |
| +namespace sandbox { |
| + |
| +namespace { |
| + |
| +class BasicPolicy : public SandboxBPFDSLPolicy { |
| + public: |
| + BasicPolicy() {} |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
| + if (sysno == __NR_getpgid) { |
| + const Arg<pid_t> pid(0); |
| + return If(pid == 0, Error(EPERM)).Else(Error(EINVAL)); |
| + } |
| + return Allow(); |
| + } |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(BasicPolicy); |
| +}; |
| + |
| +BPF_TEST_C(BPFDSL, Basic, BasicPolicy) { |
|
jln (very slow on Chromium)
2014/06/25 00:14:53
Let's set errno to 0 first.
mdempsky
2014/06/25 23:50:22
Done. I added a helper macro that clears errno an
|
| + BPF_ASSERT_EQ(-1, getpgid(0)); |
| + BPF_ASSERT_EQ(EPERM, errno); |
| + |
| + BPF_ASSERT_EQ(-1, getpgid(1)); |
| + BPF_ASSERT_EQ(EINVAL, errno); |
| +} |
| + |
| +class BooleanLogicPolicy : public SandboxBPFDSLPolicy { |
| + public: |
| + BooleanLogicPolicy() {} |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
| + if (sysno == __NR_socketpair) { |
| + const Arg<int> domain(0), type(1), protocol(2); |
| + return If(domain == AF_UNIX && |
| + (type == SOCK_STREAM || type == SOCK_DGRAM) && |
| + protocol == 0, |
| + Error(EPERM)).Else(Error(EINVAL)); |
| + } |
| + return Allow(); |
| + } |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(BooleanLogicPolicy); |
| +}; |
| + |
| +void AssertSocketPairError(int expected_errno, |
| + int domain, |
| + int type, |
| + int protocol) { |
| + int sv[2]; |
| + BPF_ASSERT_EQ(-1, socketpair(domain, type, protocol, sv)); |
| + BPF_ASSERT_EQ(expected_errno, errno); |
| +} |
| + |
| +BPF_TEST_C(BPFDSL, BooleanLogic, BooleanLogicPolicy) { |
|
jln (very slow on Chromium)
2014/06/25 00:14:54
errno = 0;
mdempsky
2014/06/25 23:50:22
Done.
|
| + // Acceptable combinations that should return EPERM. |
| + AssertSocketPairError(EPERM, AF_UNIX, SOCK_STREAM, 0); |
| + AssertSocketPairError(EPERM, AF_UNIX, SOCK_DGRAM, 0); |
| + |
| + // Combinations that are invalid for only one reason; should return EINVAL. |
| + AssertSocketPairError(EINVAL, AF_INET, SOCK_STREAM, 0); |
| + AssertSocketPairError(EINVAL, AF_UNIX, SOCK_SEQPACKET, 0); |
| + AssertSocketPairError(EINVAL, AF_UNIX, SOCK_STREAM, IPPROTO_TCP); |
| + |
| + // Completely unacceptable combination; should also return EINVAL. |
| + AssertSocketPairError(EINVAL, AF_INET, SOCK_SEQPACKET, IPPROTO_UDP); |
| +} |
| + |
| +static const uintptr_t kDeadBeefAddr = |
| + static_cast<uintptr_t>(0xdeadbeefdeadbeefULL); |
| + |
| +class ArgSizePolicy : public SandboxBPFDSLPolicy { |
| + public: |
| + ArgSizePolicy() {} |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
| + if (sysno == __NR_uname) { |
| + const Arg<uintptr_t> addr(0); |
| + return If(addr == kDeadBeefAddr, Error(EPERM)).Else(Allow()); |
| + } |
| + return Allow(); |
| + } |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(ArgSizePolicy); |
| +}; |
| + |
| +BPF_TEST_C(BPFDSL, ArgSizeTest, ArgSizePolicy) { |
| + struct utsname buf; |
| + BPF_ASSERT_EQ(0, uname(&buf)); |
| + |
| + BPF_ASSERT_EQ(-1, uname(reinterpret_cast<struct utsname*>(kDeadBeefAddr))); |
| + BPF_ASSERT_EQ(EPERM, errno); |
| +} |
| + |
|
jln (very slow on Chromium)
2014/06/25 00:14:53
Let's add a Size test for a 32 bits argument like
|
| +class TrappingPolicy : public SandboxBPFDSLPolicy { |
| + public: |
| + TrappingPolicy() {} |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
| + if (sysno == __NR_uname) { |
| + return Trap(UnameTrap, &count_); |
| + } |
| + return Allow(); |
| + } |
| + |
| + private: |
| + static intptr_t count_; |
| + |
| + static intptr_t UnameTrap(const struct arch_seccomp_data& data, void* aux) { |
| + BPF_ASSERT_EQ(&count_, aux); |
| + return ++count_; |
| + } |
| + |
| + DISALLOW_COPY_AND_ASSIGN(TrappingPolicy); |
| +}; |
| + |
| +intptr_t TrappingPolicy::count_; |
| + |
| +BPF_TEST_C(BPFDSL, TrapTest, TrappingPolicy) { |
| + BPF_ASSERT_EQ(1, uname(NULL)); |
| + BPF_ASSERT_EQ(2, uname(NULL)); |
| + BPF_ASSERT_EQ(3, uname(NULL)); |
| +} |
| + |
| +class MaskingPolicy : public SandboxBPFDSLPolicy { |
| + public: |
| + MaskingPolicy() {} |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
| + if (sysno == __NR_setuid) { |
| + const Arg<uid_t> uid(0); |
| + return If((uid & 0xf) == 0, Error(EINVAL)).Else(Error(EACCES)); |
| + } |
| + if (sysno == __NR_setgid) { |
| + const Arg<gid_t> gid(0); |
| + return If((gid & 0xf0) == 0xf0, Error(EINVAL)).Else(Error(EACCES)); |
| + } |
| + return Allow(); |
| + } |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(MaskingPolicy); |
| +}; |
| + |
| +BPF_TEST_C(BPFDSL, MaskTest, MaskingPolicy) { |
| + for (uid_t uid = 0; uid < 0x100; ++uid) { |
| + BPF_ASSERT_EQ(-1, setuid(uid)); |
| + BPF_ASSERT_EQ((uid & 0xf) == 0 ? EINVAL : EACCES, errno); |
| + } |
| + |
| + for (gid_t gid = 0; gid < 0x100; ++gid) { |
| + BPF_ASSERT_EQ(-1, setgid(gid)); |
| + BPF_ASSERT_EQ((gid & 0xf0) == 0xf0 ? EINVAL : EACCES, errno); |
| + } |
| +} |
| + |
| +class ElseIfPolicy : public SandboxBPFDSLPolicy { |
| + public: |
| + ElseIfPolicy() {} |
| + virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { |
| + if (sysno == __NR_setuid) { |
| + const Arg<uid_t> uid(0); |
| + return If(uid == 0, Error(0)) |
| + .ElseIf((uid & 0xf0f0) == 0, Error(EINVAL)) |
| + .ElseIf((uid & 0x00ff) == 0, Error(EEXIST)) |
| + .Else(Error(EACCES)); |
| + } |
| + return Allow(); |
| + } |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(ElseIfPolicy); |
| +}; |
| + |
| +BPF_TEST_C(BPFDSL, ElseIfTest, ElseIfPolicy) { |
| + BPF_ASSERT_EQ(0, setuid(0)); |
| + |
| + BPF_ASSERT_EQ(-1, setuid(0x0001)); |
| + BPF_ASSERT_EQ(EINVAL, errno); |
| + BPF_ASSERT_EQ(-1, setuid(0x0100)); |
| + BPF_ASSERT_EQ(EINVAL, errno); |
| + |
|
jln (very slow on Chromium)
2014/06/25 00:14:53
Currently this doesn't test the order if the two "
mdempsky
2014/06/25 23:50:22
I believe the 0x100 test case covered this, but th
|
| + BPF_ASSERT_EQ(-1, setuid(0x1000)); |
| + BPF_ASSERT_EQ(EEXIST, errno); |
| + BPF_ASSERT_EQ(-1, setuid(0x2000)); |
| + BPF_ASSERT_EQ(EEXIST, errno); |
| + |
| + BPF_ASSERT_EQ(-1, setuid(0x1234)); |
| + BPF_ASSERT_EQ(EACCES, errno); |
| +} |
| + |
| +} // namespace |
| + |
| +} // namespace sandbox |