OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "sandbox/linux/bpf_dsl/bpf_dsl.h" | 5 #include "sandbox/linux/bpf_dsl/bpf_dsl.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <netinet/in.h> | 9 #include <netinet/in.h> |
10 #include <sys/socket.h> | 10 #include <sys/socket.h> |
11 #include <sys/syscall.h> | 11 #include <sys/syscall.h> |
12 #include <sys/utsname.h> | 12 #include <sys/utsname.h> |
13 #include <unistd.h> | 13 #include <unistd.h> |
14 | 14 |
15 #include "base/files/scoped_file.h" | 15 #include "base/files/scoped_file.h" |
16 #include "base/macros.h" | 16 #include "base/macros.h" |
17 #include "build/build_config.h" | 17 #include "build/build_config.h" |
18 #include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h" | 18 #include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h" |
19 #include "sandbox/linux/bpf_dsl/codegen.h" | |
20 #include "sandbox/linux/bpf_dsl/policy.h" | 19 #include "sandbox/linux/bpf_dsl/policy.h" |
21 #include "sandbox/linux/bpf_dsl/policy_compiler.h" | 20 #include "sandbox/linux/seccomp-bpf/bpf_tests.h" |
22 #include "sandbox/linux/bpf_dsl/seccomp_macros.h" | |
23 #include "sandbox/linux/bpf_dsl/trap_registry.h" | |
24 #include "sandbox/linux/seccomp-bpf/errorcode.h" | 21 #include "sandbox/linux/seccomp-bpf/errorcode.h" |
25 #include "sandbox/linux/seccomp-bpf/verifier.h" | 22 #include "sandbox/linux/seccomp-bpf/syscall.h" |
26 #include "testing/gtest/include/gtest/gtest.h" | 23 #include "testing/gtest/include/gtest/gtest.h" |
27 | 24 |
28 #define CASES SANDBOX_BPF_DSL_CASES | 25 #define CASES SANDBOX_BPF_DSL_CASES |
29 | 26 |
| 27 // Helper macro to assert that invoking system call |sys| directly via |
| 28 // Syscall::Call with arguments |...| returns |res|. |
| 29 // Errors can be asserted by specifying a value like "-EINVAL". |
| 30 #define ASSERT_SYSCALL_RESULT(res, sys, ...) \ |
| 31 BPF_ASSERT_EQ(res, Stubs::sys(__VA_ARGS__)) |
| 32 |
30 namespace sandbox { | 33 namespace sandbox { |
31 namespace bpf_dsl { | 34 namespace bpf_dsl { |
32 namespace { | 35 namespace { |
33 | 36 |
34 // Helper function to construct fake arch_seccomp_data objects. | 37 // Type safe stubs for tested system calls. |
35 struct arch_seccomp_data FakeSyscall(int nr, | 38 class Stubs { |
36 uint64_t p0 = 0, | |
37 uint64_t p1 = 0, | |
38 uint64_t p2 = 0, | |
39 uint64_t p3 = 0, | |
40 uint64_t p4 = 0, | |
41 uint64_t p5 = 0) { | |
42 // Made up program counter for syscall address. | |
43 const uint64_t kFakePC = 0x543210; | |
44 | |
45 struct arch_seccomp_data data = { | |
46 nr, | |
47 SECCOMP_ARCH, | |
48 kFakePC, | |
49 { | |
50 p0, p1, p2, p3, p4, p5, | |
51 }, | |
52 }; | |
53 | |
54 return data; | |
55 } | |
56 | |
57 class FakeTrapRegistry : public TrapRegistry { | |
58 public: | 39 public: |
59 FakeTrapRegistry() : next_id_(1) {} | 40 static int getpgid(pid_t pid) { return Syscall::Call(__NR_getpgid, pid); } |
60 virtual ~FakeTrapRegistry() {} | 41 static int setuid(uid_t uid) { return Syscall::Call(__NR_setuid, uid); } |
61 | 42 static int setgid(gid_t gid) { return Syscall::Call(__NR_setgid, gid); } |
62 uint16_t Add(TrapFnc fnc, const void* aux, bool safe) override { | 43 static int setpgid(pid_t pid, pid_t pgid) { |
63 EXPECT_NE(0U, next_id_); | 44 return Syscall::Call(__NR_setpgid, pid, pgid); |
64 return next_id_++; | |
65 } | 45 } |
66 | 46 |
67 bool EnableUnsafeTraps() override { | 47 static int fcntl(int fd, int cmd, unsigned long arg = 0) { |
68 ADD_FAILURE() << "Unimplemented"; | 48 return Syscall::Call(__NR_fcntl, fd, cmd, arg); |
69 return false; | |
70 } | 49 } |
71 | 50 |
72 private: | 51 static int uname(struct utsname* buf) { |
73 uint16_t next_id_; | 52 return Syscall::Call(__NR_uname, buf); |
74 | |
75 DISALLOW_COPY_AND_ASSIGN(FakeTrapRegistry); | |
76 }; | |
77 | |
78 class PolicyEmulator { | |
79 public: | |
80 explicit PolicyEmulator(const Policy* policy) : program_(), traps_() { | |
81 program_ = *PolicyCompiler(policy, &traps_).Compile(); | |
82 } | |
83 ~PolicyEmulator() {} | |
84 | |
85 uint32_t Emulate(const struct arch_seccomp_data& data) const { | |
86 const char* err = nullptr; | |
87 uint32_t res = Verifier::EvaluateBPF(program_, data, &err); | |
88 if (err) { | |
89 ADD_FAILURE() << err; | |
90 return 0; | |
91 } | |
92 return res; | |
93 } | 53 } |
94 | 54 |
95 void ExpectAllow(const struct arch_seccomp_data& data) const { | 55 static int setresuid(uid_t ruid, uid_t euid, uid_t suid) { |
96 EXPECT_EQ(SECCOMP_RET_ALLOW, Emulate(data)); | 56 return Syscall::Call(__NR_setresuid, ruid, euid, suid); |
97 } | 57 } |
98 | 58 |
99 void ExpectErrno(uint16_t err, const struct arch_seccomp_data& data) const { | 59 #if !defined(ARCH_CPU_X86) |
100 EXPECT_EQ(SECCOMP_RET_ERRNO | err, Emulate(data)); | 60 static int socketpair(int domain, int type, int protocol, int sv[2]) { |
| 61 return Syscall::Call(__NR_socketpair, domain, type, protocol, sv); |
101 } | 62 } |
102 | 63 #endif |
103 private: | |
104 CodeGen::Program program_; | |
105 FakeTrapRegistry traps_; | |
106 | |
107 DISALLOW_COPY_AND_ASSIGN(PolicyEmulator); | |
108 }; | 64 }; |
109 | 65 |
110 class BasicPolicy : public Policy { | 66 class BasicPolicy : public Policy { |
111 public: | 67 public: |
112 BasicPolicy() {} | 68 BasicPolicy() {} |
113 ~BasicPolicy() override {} | 69 ~BasicPolicy() override {} |
114 ResultExpr EvaluateSyscall(int sysno) const override { | 70 ResultExpr EvaluateSyscall(int sysno) const override { |
115 if (sysno == __NR_getpgid) { | 71 if (sysno == __NR_getpgid) { |
116 const Arg<pid_t> pid(0); | 72 const Arg<pid_t> pid(0); |
117 return If(pid == 0, Error(EPERM)).Else(Error(EINVAL)); | 73 return If(pid == 0, Error(EPERM)).Else(Error(EINVAL)); |
118 } | 74 } |
119 if (sysno == __NR_setuid) { | 75 if (sysno == __NR_setuid) { |
120 const Arg<uid_t> uid(0); | 76 const Arg<uid_t> uid(0); |
121 return If(uid != 42, Error(ESRCH)).Else(Error(ENOMEM)); | 77 return If(uid != 42, Error(ESRCH)).Else(Error(ENOMEM)); |
122 } | 78 } |
123 return Allow(); | 79 return Allow(); |
124 } | 80 } |
125 | 81 |
126 private: | 82 private: |
127 DISALLOW_COPY_AND_ASSIGN(BasicPolicy); | 83 DISALLOW_COPY_AND_ASSIGN(BasicPolicy); |
128 }; | 84 }; |
129 | 85 |
130 TEST(BPFDSL, Basic) { | 86 BPF_TEST_C(BPFDSL, Basic, BasicPolicy) { |
131 BasicPolicy policy; | 87 ASSERT_SYSCALL_RESULT(-EPERM, getpgid, 0); |
132 PolicyEmulator emulator(&policy); | 88 ASSERT_SYSCALL_RESULT(-EINVAL, getpgid, 1); |
133 | 89 |
134 emulator.ExpectErrno(EPERM, FakeSyscall(__NR_getpgid, 0)); | 90 ASSERT_SYSCALL_RESULT(-ENOMEM, setuid, 42); |
135 emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_getpgid, 1)); | 91 ASSERT_SYSCALL_RESULT(-ESRCH, setuid, 43); |
136 | |
137 emulator.ExpectErrno(ENOMEM, FakeSyscall(__NR_setuid, 42)); | |
138 emulator.ExpectErrno(ESRCH, FakeSyscall(__NR_setuid, 43)); | |
139 } | 92 } |
140 | 93 |
141 /* On IA-32, socketpair() is implemented via socketcall(). :-( */ | 94 /* On IA-32, socketpair() is implemented via socketcall(). :-( */ |
142 #if !defined(ARCH_CPU_X86) | 95 #if !defined(ARCH_CPU_X86) |
143 class BooleanLogicPolicy : public Policy { | 96 class BooleanLogicPolicy : public Policy { |
144 public: | 97 public: |
145 BooleanLogicPolicy() {} | 98 BooleanLogicPolicy() {} |
146 ~BooleanLogicPolicy() override {} | 99 ~BooleanLogicPolicy() override {} |
147 ResultExpr EvaluateSyscall(int sysno) const override { | 100 ResultExpr EvaluateSyscall(int sysno) const override { |
148 if (sysno == __NR_socketpair) { | 101 if (sysno == __NR_socketpair) { |
149 const Arg<int> domain(0), type(1), protocol(2); | 102 const Arg<int> domain(0), type(1), protocol(2); |
150 return If(domain == AF_UNIX && | 103 return If(domain == AF_UNIX && |
151 (type == SOCK_STREAM || type == SOCK_DGRAM) && | 104 (type == SOCK_STREAM || type == SOCK_DGRAM) && |
152 protocol == 0, | 105 protocol == 0, |
153 Error(EPERM)).Else(Error(EINVAL)); | 106 Error(EPERM)).Else(Error(EINVAL)); |
154 } | 107 } |
155 return Allow(); | 108 return Allow(); |
156 } | 109 } |
157 | 110 |
158 private: | 111 private: |
159 DISALLOW_COPY_AND_ASSIGN(BooleanLogicPolicy); | 112 DISALLOW_COPY_AND_ASSIGN(BooleanLogicPolicy); |
160 }; | 113 }; |
161 | 114 |
162 TEST(BPFDSL, BooleanLogic) { | 115 BPF_TEST_C(BPFDSL, BooleanLogic, BooleanLogicPolicy) { |
163 BooleanLogicPolicy policy; | 116 int sv[2]; |
164 PolicyEmulator emulator(&policy); | |
165 | |
166 const intptr_t kFakeSV = 0x12345; | |
167 | 117 |
168 // Acceptable combinations that should return EPERM. | 118 // Acceptable combinations that should return EPERM. |
169 emulator.ExpectErrno( | 119 ASSERT_SYSCALL_RESULT(-EPERM, socketpair, AF_UNIX, SOCK_STREAM, 0, sv); |
170 EPERM, FakeSyscall(__NR_socketpair, AF_UNIX, SOCK_STREAM, 0, kFakeSV)); | 120 ASSERT_SYSCALL_RESULT(-EPERM, socketpair, AF_UNIX, SOCK_DGRAM, 0, sv); |
171 emulator.ExpectErrno( | |
172 EPERM, FakeSyscall(__NR_socketpair, AF_UNIX, SOCK_DGRAM, 0, kFakeSV)); | |
173 | 121 |
174 // Combinations that are invalid for only one reason; should return EINVAL. | 122 // Combinations that are invalid for only one reason; should return EINVAL. |
175 emulator.ExpectErrno( | 123 ASSERT_SYSCALL_RESULT(-EINVAL, socketpair, AF_INET, SOCK_STREAM, 0, sv); |
176 EINVAL, FakeSyscall(__NR_socketpair, AF_INET, SOCK_STREAM, 0, kFakeSV)); | 124 ASSERT_SYSCALL_RESULT(-EINVAL, socketpair, AF_UNIX, SOCK_SEQPACKET, 0, sv); |
177 emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_socketpair, AF_UNIX, | 125 ASSERT_SYSCALL_RESULT( |
178 SOCK_SEQPACKET, 0, kFakeSV)); | 126 -EINVAL, socketpair, AF_UNIX, SOCK_STREAM, IPPROTO_TCP, sv); |
179 emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_socketpair, AF_UNIX, | |
180 SOCK_STREAM, IPPROTO_TCP, kFakeSV)); | |
181 | 127 |
182 // Completely unacceptable combination; should also return EINVAL. | 128 // Completely unacceptable combination; should also return EINVAL. |
183 emulator.ExpectErrno( | 129 ASSERT_SYSCALL_RESULT( |
184 EINVAL, FakeSyscall(__NR_socketpair, AF_INET, SOCK_SEQPACKET, IPPROTO_UDP, | 130 -EINVAL, socketpair, AF_INET, SOCK_SEQPACKET, IPPROTO_UDP, sv); |
185 kFakeSV)); | |
186 } | 131 } |
187 #endif // !ARCH_CPU_X86 | 132 #endif // !ARCH_CPU_X86 |
188 | 133 |
189 class MoreBooleanLogicPolicy : public Policy { | 134 class MoreBooleanLogicPolicy : public Policy { |
190 public: | 135 public: |
191 MoreBooleanLogicPolicy() {} | 136 MoreBooleanLogicPolicy() {} |
192 ~MoreBooleanLogicPolicy() override {} | 137 ~MoreBooleanLogicPolicy() override {} |
193 ResultExpr EvaluateSyscall(int sysno) const override { | 138 ResultExpr EvaluateSyscall(int sysno) const override { |
194 if (sysno == __NR_setresuid) { | 139 if (sysno == __NR_setresuid) { |
195 const Arg<uid_t> ruid(0), euid(1), suid(2); | 140 const Arg<uid_t> ruid(0), euid(1), suid(2); |
196 return If(ruid == 0 || euid == 0 || suid == 0, Error(EPERM)) | 141 return If(ruid == 0 || euid == 0 || suid == 0, Error(EPERM)) |
197 .ElseIf(ruid == 1 && euid == 1 && suid == 1, Error(EAGAIN)) | 142 .ElseIf(ruid == 1 && euid == 1 && suid == 1, Error(EAGAIN)) |
198 .Else(Error(EINVAL)); | 143 .Else(Error(EINVAL)); |
199 } | 144 } |
200 return Allow(); | 145 return Allow(); |
201 } | 146 } |
202 | 147 |
203 private: | 148 private: |
204 DISALLOW_COPY_AND_ASSIGN(MoreBooleanLogicPolicy); | 149 DISALLOW_COPY_AND_ASSIGN(MoreBooleanLogicPolicy); |
205 }; | 150 }; |
206 | 151 |
207 TEST(BPFDSL, MoreBooleanLogic) { | 152 BPF_TEST_C(BPFDSL, MoreBooleanLogic, MoreBooleanLogicPolicy) { |
208 MoreBooleanLogicPolicy policy; | |
209 PolicyEmulator emulator(&policy); | |
210 | |
211 // Expect EPERM if any set to 0. | 153 // Expect EPERM if any set to 0. |
212 emulator.ExpectErrno(EPERM, FakeSyscall(__NR_setresuid, 0, 5, 5)); | 154 ASSERT_SYSCALL_RESULT(-EPERM, setresuid, 0, 5, 5); |
213 emulator.ExpectErrno(EPERM, FakeSyscall(__NR_setresuid, 5, 0, 5)); | 155 ASSERT_SYSCALL_RESULT(-EPERM, setresuid, 5, 0, 5); |
214 emulator.ExpectErrno(EPERM, FakeSyscall(__NR_setresuid, 5, 5, 0)); | 156 ASSERT_SYSCALL_RESULT(-EPERM, setresuid, 5, 5, 0); |
215 | 157 |
216 // Expect EAGAIN if all set to 1. | 158 // Expect EAGAIN if all set to 1. |
217 emulator.ExpectErrno(EAGAIN, FakeSyscall(__NR_setresuid, 1, 1, 1)); | 159 ASSERT_SYSCALL_RESULT(-EAGAIN, setresuid, 1, 1, 1); |
218 | 160 |
219 // Expect EINVAL for anything else. | 161 // Expect EINVAL for anything else. |
220 emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setresuid, 5, 1, 1)); | 162 ASSERT_SYSCALL_RESULT(-EINVAL, setresuid, 5, 1, 1); |
221 emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setresuid, 1, 5, 1)); | 163 ASSERT_SYSCALL_RESULT(-EINVAL, setresuid, 1, 5, 1); |
222 emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setresuid, 1, 1, 5)); | 164 ASSERT_SYSCALL_RESULT(-EINVAL, setresuid, 1, 1, 5); |
223 emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setresuid, 3, 4, 5)); | 165 ASSERT_SYSCALL_RESULT(-EINVAL, setresuid, 3, 4, 5); |
224 } | 166 } |
225 | 167 |
226 static const uintptr_t kDeadBeefAddr = | 168 static const uintptr_t kDeadBeefAddr = |
227 static_cast<uintptr_t>(0xdeadbeefdeadbeefULL); | 169 static_cast<uintptr_t>(0xdeadbeefdeadbeefULL); |
228 | 170 |
229 class ArgSizePolicy : public Policy { | 171 class ArgSizePolicy : public Policy { |
230 public: | 172 public: |
231 ArgSizePolicy() {} | 173 ArgSizePolicy() {} |
232 ~ArgSizePolicy() override {} | 174 ~ArgSizePolicy() override {} |
233 ResultExpr EvaluateSyscall(int sysno) const override { | 175 ResultExpr EvaluateSyscall(int sysno) const override { |
234 if (sysno == __NR_uname) { | 176 if (sysno == __NR_uname) { |
235 const Arg<uintptr_t> addr(0); | 177 const Arg<uintptr_t> addr(0); |
236 return If(addr == kDeadBeefAddr, Error(EPERM)).Else(Allow()); | 178 return If(addr == kDeadBeefAddr, Error(EPERM)).Else(Allow()); |
237 } | 179 } |
238 return Allow(); | 180 return Allow(); |
239 } | 181 } |
240 | 182 |
241 private: | 183 private: |
242 DISALLOW_COPY_AND_ASSIGN(ArgSizePolicy); | 184 DISALLOW_COPY_AND_ASSIGN(ArgSizePolicy); |
243 }; | 185 }; |
244 | 186 |
245 TEST(BPFDSL, ArgSizeTest) { | 187 BPF_TEST_C(BPFDSL, ArgSizeTest, ArgSizePolicy) { |
246 ArgSizePolicy policy; | 188 struct utsname buf; |
247 PolicyEmulator emulator(&policy); | 189 ASSERT_SYSCALL_RESULT(0, uname, &buf); |
248 | 190 ASSERT_SYSCALL_RESULT( |
249 emulator.ExpectAllow(FakeSyscall(__NR_uname, 0)); | 191 -EPERM, uname, reinterpret_cast<struct utsname*>(kDeadBeefAddr)); |
250 emulator.ExpectErrno(EPERM, FakeSyscall(__NR_uname, kDeadBeefAddr)); | |
251 } | 192 } |
252 | 193 |
253 #if 0 | |
254 // TODO(mdempsky): This is really an integration test. | |
255 | |
256 class TrappingPolicy : public Policy { | 194 class TrappingPolicy : public Policy { |
257 public: | 195 public: |
258 TrappingPolicy() {} | 196 TrappingPolicy() {} |
259 ~TrappingPolicy() override {} | 197 ~TrappingPolicy() override {} |
260 ResultExpr EvaluateSyscall(int sysno) const override { | 198 ResultExpr EvaluateSyscall(int sysno) const override { |
261 if (sysno == __NR_uname) { | 199 if (sysno == __NR_uname) { |
262 return Trap(UnameTrap, &count_); | 200 return Trap(UnameTrap, &count_); |
263 } | 201 } |
264 return Allow(); | 202 return Allow(); |
265 } | 203 } |
266 | 204 |
267 private: | 205 private: |
268 static intptr_t count_; | 206 static intptr_t count_; |
269 | 207 |
270 static intptr_t UnameTrap(const struct arch_seccomp_data& data, void* aux) { | 208 static intptr_t UnameTrap(const struct arch_seccomp_data& data, void* aux) { |
271 BPF_ASSERT_EQ(&count_, aux); | 209 BPF_ASSERT_EQ(&count_, aux); |
272 return ++count_; | 210 return ++count_; |
273 } | 211 } |
274 | 212 |
275 DISALLOW_COPY_AND_ASSIGN(TrappingPolicy); | 213 DISALLOW_COPY_AND_ASSIGN(TrappingPolicy); |
276 }; | 214 }; |
277 | 215 |
278 intptr_t TrappingPolicy::count_; | 216 intptr_t TrappingPolicy::count_; |
279 | 217 |
280 BPF_TEST_C(BPFDSL, TrapTest, TrappingPolicy) { | 218 BPF_TEST_C(BPFDSL, TrapTest, TrappingPolicy) { |
281 ASSERT_SYSCALL_RESULT(1, uname, NULL); | 219 ASSERT_SYSCALL_RESULT(1, uname, NULL); |
282 ASSERT_SYSCALL_RESULT(2, uname, NULL); | 220 ASSERT_SYSCALL_RESULT(2, uname, NULL); |
283 ASSERT_SYSCALL_RESULT(3, uname, NULL); | 221 ASSERT_SYSCALL_RESULT(3, uname, NULL); |
284 } | 222 } |
285 #endif | |
286 | 223 |
287 class MaskingPolicy : public Policy { | 224 class MaskingPolicy : public Policy { |
288 public: | 225 public: |
289 MaskingPolicy() {} | 226 MaskingPolicy() {} |
290 ~MaskingPolicy() override {} | 227 ~MaskingPolicy() override {} |
291 ResultExpr EvaluateSyscall(int sysno) const override { | 228 ResultExpr EvaluateSyscall(int sysno) const override { |
292 if (sysno == __NR_setuid) { | 229 if (sysno == __NR_setuid) { |
293 const Arg<uid_t> uid(0); | 230 const Arg<uid_t> uid(0); |
294 return If((uid & 0xf) == 0, Error(EINVAL)).Else(Error(EACCES)); | 231 return If((uid & 0xf) == 0, Error(EINVAL)).Else(Error(EACCES)); |
295 } | 232 } |
296 if (sysno == __NR_setgid) { | 233 if (sysno == __NR_setgid) { |
297 const Arg<gid_t> gid(0); | 234 const Arg<gid_t> gid(0); |
298 return If((gid & 0xf0) == 0xf0, Error(EINVAL)).Else(Error(EACCES)); | 235 return If((gid & 0xf0) == 0xf0, Error(EINVAL)).Else(Error(EACCES)); |
299 } | 236 } |
300 if (sysno == __NR_setpgid) { | 237 if (sysno == __NR_setpgid) { |
301 const Arg<pid_t> pid(0); | 238 const Arg<pid_t> pid(0); |
302 return If((pid & 0xa5) == 0xa0, Error(EINVAL)).Else(Error(EACCES)); | 239 return If((pid & 0xa5) == 0xa0, Error(EINVAL)).Else(Error(EACCES)); |
303 } | 240 } |
304 return Allow(); | 241 return Allow(); |
305 } | 242 } |
306 | 243 |
307 private: | 244 private: |
308 DISALLOW_COPY_AND_ASSIGN(MaskingPolicy); | 245 DISALLOW_COPY_AND_ASSIGN(MaskingPolicy); |
309 }; | 246 }; |
310 | 247 |
311 TEST(BPFDSL, MaskTest) { | 248 BPF_TEST_C(BPFDSL, MaskTest, MaskingPolicy) { |
312 MaskingPolicy policy; | |
313 PolicyEmulator emulator(&policy); | |
314 | |
315 for (uid_t uid = 0; uid < 0x100; ++uid) { | 249 for (uid_t uid = 0; uid < 0x100; ++uid) { |
316 const int expect_errno = (uid & 0xf) == 0 ? EINVAL : EACCES; | 250 const int expect_errno = (uid & 0xf) == 0 ? EINVAL : EACCES; |
317 emulator.ExpectErrno(expect_errno, FakeSyscall(__NR_setuid, uid)); | 251 ASSERT_SYSCALL_RESULT(-expect_errno, setuid, uid); |
318 } | 252 } |
319 | 253 |
320 for (gid_t gid = 0; gid < 0x100; ++gid) { | 254 for (gid_t gid = 0; gid < 0x100; ++gid) { |
321 const int expect_errno = (gid & 0xf0) == 0xf0 ? EINVAL : EACCES; | 255 const int expect_errno = (gid & 0xf0) == 0xf0 ? EINVAL : EACCES; |
322 emulator.ExpectErrno(expect_errno, FakeSyscall(__NR_setgid, gid)); | 256 ASSERT_SYSCALL_RESULT(-expect_errno, setgid, gid); |
323 } | 257 } |
324 | 258 |
325 for (pid_t pid = 0; pid < 0x100; ++pid) { | 259 for (pid_t pid = 0; pid < 0x100; ++pid) { |
326 const int expect_errno = (pid & 0xa5) == 0xa0 ? EINVAL : EACCES; | 260 const int expect_errno = (pid & 0xa5) == 0xa0 ? EINVAL : EACCES; |
327 emulator.ExpectErrno(expect_errno, FakeSyscall(__NR_setpgid, pid, 0)); | 261 ASSERT_SYSCALL_RESULT(-expect_errno, setpgid, pid, 0); |
328 } | 262 } |
329 } | 263 } |
330 | 264 |
331 class ElseIfPolicy : public Policy { | 265 class ElseIfPolicy : public Policy { |
332 public: | 266 public: |
333 ElseIfPolicy() {} | 267 ElseIfPolicy() {} |
334 ~ElseIfPolicy() override {} | 268 ~ElseIfPolicy() override {} |
335 ResultExpr EvaluateSyscall(int sysno) const override { | 269 ResultExpr EvaluateSyscall(int sysno) const override { |
336 if (sysno == __NR_setuid) { | 270 if (sysno == __NR_setuid) { |
337 const Arg<uid_t> uid(0); | 271 const Arg<uid_t> uid(0); |
338 return If((uid & 0xfff) == 0, Error(0)) | 272 return If((uid & 0xfff) == 0, Error(0)) |
339 .ElseIf((uid & 0xff0) == 0, Error(EINVAL)) | 273 .ElseIf((uid & 0xff0) == 0, Error(EINVAL)) |
340 .ElseIf((uid & 0xf00) == 0, Error(EEXIST)) | 274 .ElseIf((uid & 0xf00) == 0, Error(EEXIST)) |
341 .Else(Error(EACCES)); | 275 .Else(Error(EACCES)); |
342 } | 276 } |
343 return Allow(); | 277 return Allow(); |
344 } | 278 } |
345 | 279 |
346 private: | 280 private: |
347 DISALLOW_COPY_AND_ASSIGN(ElseIfPolicy); | 281 DISALLOW_COPY_AND_ASSIGN(ElseIfPolicy); |
348 }; | 282 }; |
349 | 283 |
350 TEST(BPFDSL, ElseIfTest) { | 284 BPF_TEST_C(BPFDSL, ElseIfTest, ElseIfPolicy) { |
351 ElseIfPolicy policy; | 285 ASSERT_SYSCALL_RESULT(0, setuid, 0); |
352 PolicyEmulator emulator(&policy); | |
353 | 286 |
354 emulator.ExpectErrno(0, FakeSyscall(__NR_setuid, 0)); | 287 ASSERT_SYSCALL_RESULT(-EINVAL, setuid, 0x0001); |
| 288 ASSERT_SYSCALL_RESULT(-EINVAL, setuid, 0x0002); |
355 | 289 |
356 emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setuid, 0x0001)); | 290 ASSERT_SYSCALL_RESULT(-EEXIST, setuid, 0x0011); |
357 emulator.ExpectErrno(EINVAL, FakeSyscall(__NR_setuid, 0x0002)); | 291 ASSERT_SYSCALL_RESULT(-EEXIST, setuid, 0x0022); |
358 | 292 |
359 emulator.ExpectErrno(EEXIST, FakeSyscall(__NR_setuid, 0x0011)); | 293 ASSERT_SYSCALL_RESULT(-EACCES, setuid, 0x0111); |
360 emulator.ExpectErrno(EEXIST, FakeSyscall(__NR_setuid, 0x0022)); | 294 ASSERT_SYSCALL_RESULT(-EACCES, setuid, 0x0222); |
361 | |
362 emulator.ExpectErrno(EACCES, FakeSyscall(__NR_setuid, 0x0111)); | |
363 emulator.ExpectErrno(EACCES, FakeSyscall(__NR_setuid, 0x0222)); | |
364 } | 295 } |
365 | 296 |
366 class SwitchPolicy : public Policy { | 297 class SwitchPolicy : public Policy { |
367 public: | 298 public: |
368 SwitchPolicy() {} | 299 SwitchPolicy() {} |
369 ~SwitchPolicy() override {} | 300 ~SwitchPolicy() override {} |
370 ResultExpr EvaluateSyscall(int sysno) const override { | 301 ResultExpr EvaluateSyscall(int sysno) const override { |
371 if (sysno == __NR_fcntl) { | 302 if (sysno == __NR_fcntl) { |
372 const Arg<int> cmd(1); | 303 const Arg<int> cmd(1); |
373 const Arg<unsigned long> long_arg(2); | 304 const Arg<unsigned long> long_arg(2); |
374 return Switch(cmd) | 305 return Switch(cmd) |
375 .CASES((F_GETFL, F_GETFD), Error(ENOENT)) | 306 .CASES((F_GETFL, F_GETFD), Error(ENOENT)) |
376 .Case(F_SETFD, If(long_arg == O_CLOEXEC, Allow()).Else(Error(EINVAL))) | 307 .Case(F_SETFD, If(long_arg == O_CLOEXEC, Allow()).Else(Error(EINVAL))) |
377 .Case(F_SETFL, Error(EPERM)) | 308 .Case(F_SETFL, Error(EPERM)) |
378 .Default(Error(EACCES)); | 309 .Default(Error(EACCES)); |
379 } | 310 } |
380 return Allow(); | 311 return Allow(); |
381 } | 312 } |
382 | 313 |
383 private: | 314 private: |
384 DISALLOW_COPY_AND_ASSIGN(SwitchPolicy); | 315 DISALLOW_COPY_AND_ASSIGN(SwitchPolicy); |
385 }; | 316 }; |
386 | 317 |
387 TEST(BPFDSL, SwitchTest) { | 318 BPF_TEST_C(BPFDSL, SwitchTest, SwitchPolicy) { |
388 SwitchPolicy policy; | 319 base::ScopedFD sock_fd(socket(AF_UNIX, SOCK_STREAM, 0)); |
389 PolicyEmulator emulator(&policy); | 320 BPF_ASSERT(sock_fd.is_valid()); |
390 | 321 |
391 const int kFakeSockFD = 42; | 322 ASSERT_SYSCALL_RESULT(-ENOENT, fcntl, sock_fd.get(), F_GETFD); |
| 323 ASSERT_SYSCALL_RESULT(-ENOENT, fcntl, sock_fd.get(), F_GETFL); |
392 | 324 |
393 emulator.ExpectErrno(ENOENT, FakeSyscall(__NR_fcntl, kFakeSockFD, F_GETFD)); | 325 ASSERT_SYSCALL_RESULT(0, fcntl, sock_fd.get(), F_SETFD, O_CLOEXEC); |
394 emulator.ExpectErrno(ENOENT, FakeSyscall(__NR_fcntl, kFakeSockFD, F_GETFL)); | 326 ASSERT_SYSCALL_RESULT(-EINVAL, fcntl, sock_fd.get(), F_SETFD, 0); |
395 | 327 |
396 emulator.ExpectAllow( | 328 ASSERT_SYSCALL_RESULT(-EPERM, fcntl, sock_fd.get(), F_SETFL, O_RDONLY); |
397 FakeSyscall(__NR_fcntl, kFakeSockFD, F_SETFD, O_CLOEXEC)); | |
398 emulator.ExpectErrno(EINVAL, | |
399 FakeSyscall(__NR_fcntl, kFakeSockFD, F_SETFD, 0)); | |
400 | 329 |
401 emulator.ExpectErrno(EPERM, | 330 ASSERT_SYSCALL_RESULT(-EACCES, fcntl, sock_fd.get(), F_DUPFD, 0); |
402 FakeSyscall(__NR_fcntl, kFakeSockFD, F_SETFL, O_RDONLY)); | |
403 | |
404 emulator.ExpectErrno(EACCES, | |
405 FakeSyscall(__NR_fcntl, kFakeSockFD, F_DUPFD, 0)); | |
406 } | 331 } |
407 | 332 |
408 static intptr_t DummyTrap(const struct arch_seccomp_data& data, void* aux) { | 333 static intptr_t DummyTrap(const struct arch_seccomp_data& data, void* aux) { |
409 return 0; | 334 return 0; |
410 } | 335 } |
411 | 336 |
412 TEST(BPFDSL, IsAllowDeny) { | 337 TEST(BPFDSL, IsAllowDeny) { |
413 ResultExpr allow = Allow(); | 338 ResultExpr allow = Allow(); |
414 EXPECT_TRUE(allow->IsAllow()); | 339 EXPECT_TRUE(allow->IsAllow()); |
415 EXPECT_FALSE(allow->IsDeny()); | 340 EXPECT_FALSE(allow->IsDeny()); |
(...skipping 27 matching lines...) Expand all Loading... |
443 EXPECT_TRUE(unsafe->HasUnsafeTraps()); | 368 EXPECT_TRUE(unsafe->HasUnsafeTraps()); |
444 | 369 |
445 const Arg<int> arg(0); | 370 const Arg<int> arg(0); |
446 ResultExpr maybe = If(arg == 0, allow).Else(unsafe); | 371 ResultExpr maybe = If(arg == 0, allow).Else(unsafe); |
447 EXPECT_TRUE(maybe->HasUnsafeTraps()); | 372 EXPECT_TRUE(maybe->HasUnsafeTraps()); |
448 } | 373 } |
449 | 374 |
450 } // namespace | 375 } // namespace |
451 } // namespace bpf_dsl | 376 } // namespace bpf_dsl |
452 } // namespace sandbox | 377 } // namespace sandbox |
OLD | NEW |