OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "sandbox/linux/bpf_dsl/bpf_dsl.h" | |
6 | |
7 #include <errno.h> | |
8 #include <netinet/in.h> | |
9 #include <sys/socket.h> | |
10 #include <sys/utsname.h> | |
11 | |
12 #include "base/macros.h" | |
13 #include "build/build_config.h" | |
14 #include "sandbox/linux/seccomp-bpf/bpf_tests.h" | |
15 #include "sandbox/linux/seccomp-bpf/errorcode.h" | |
16 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" | |
17 | |
18 using namespace sandbox::bpf_dsl; | |
19 | |
20 // Helper macro to assert that expression |expr| returns -1 and sets | |
21 // errno to |err|. | |
22 #define BPF_ASSERT_ERROR(err, expr) \ | |
23 do { \ | |
24 errno = 0; \ | |
25 BPF_ASSERT_EQ(-1, expr); \ | |
26 BPF_ASSERT_EQ(err, errno); \ | |
27 } while (0) | |
28 | |
29 namespace sandbox { | |
30 namespace { | |
31 | |
32 class BasicPolicy : public SandboxBPFDSLPolicy { | |
33 public: | |
34 BasicPolicy() {} | |
35 virtual ~BasicPolicy() {} | |
36 virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { | |
37 if (sysno == __NR_getpgid) { | |
38 const Arg<pid_t> pid(0); | |
39 return If(pid == 0, Error(EPERM)).Else(Error(EINVAL)); | |
40 } | |
41 return Allow(); | |
42 } | |
43 | |
44 private: | |
45 DISALLOW_COPY_AND_ASSIGN(BasicPolicy); | |
46 }; | |
47 | |
48 BPF_TEST_C(BPFDSL, Basic, BasicPolicy) { | |
49 BPF_ASSERT_ERROR(EPERM, getpgid(0)); | |
50 BPF_ASSERT_ERROR(EINVAL, getpgid(1)); | |
51 } | |
52 | |
53 /* On IA-32, socketpair() is implemented via socketcall(). :-( */ | |
54 #if !defined(ARCH_CPU_X86) | |
55 class BooleanLogicPolicy : public SandboxBPFDSLPolicy { | |
56 public: | |
57 BooleanLogicPolicy() {} | |
58 virtual ~BooleanLogicPolicy() {} | |
59 virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { | |
60 if (sysno == __NR_socketpair) { | |
61 const Arg<int> domain(0), type(1), protocol(2); | |
62 return If(domain == AF_UNIX && | |
63 (type == SOCK_STREAM || type == SOCK_DGRAM) && | |
64 protocol == 0, | |
65 Error(EPERM)).Else(Error(EINVAL)); | |
66 } | |
67 return Allow(); | |
68 } | |
69 | |
70 private: | |
71 DISALLOW_COPY_AND_ASSIGN(BooleanLogicPolicy); | |
72 }; | |
73 | |
74 BPF_TEST_C(BPFDSL, BooleanLogic, BooleanLogicPolicy) { | |
75 int sv[2]; | |
76 | |
77 // Acceptable combinations that should return EPERM. | |
78 BPF_ASSERT_ERROR(EPERM, socketpair(AF_UNIX, SOCK_STREAM, 0, sv)); | |
79 BPF_ASSERT_ERROR(EPERM, socketpair(AF_UNIX, SOCK_DGRAM, 0, sv)); | |
80 | |
81 // Combinations that are invalid for only one reason; should return EINVAL. | |
82 BPF_ASSERT_ERROR(EINVAL, socketpair(AF_INET, SOCK_STREAM, 0, sv)); | |
83 BPF_ASSERT_ERROR(EINVAL, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sv)); | |
84 BPF_ASSERT_ERROR(EINVAL, socketpair(AF_UNIX, SOCK_STREAM, IPPROTO_TCP, sv)); | |
85 | |
86 // Completely unacceptable combination; should also return EINVAL. | |
87 BPF_ASSERT_ERROR(EINVAL, | |
88 socketpair(AF_INET, SOCK_SEQPACKET, IPPROTO_UDP, sv)); | |
89 } | |
90 #endif // !ARCH_CPU_X86 | |
91 | |
92 class MoreBooleanLogicPolicy : public SandboxBPFDSLPolicy { | |
93 public: | |
94 MoreBooleanLogicPolicy() {} | |
95 virtual ~MoreBooleanLogicPolicy() {} | |
96 virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { | |
97 if (sysno == __NR_setresuid) { | |
98 const Arg<uid_t> ruid(0), euid(1), suid(2); | |
99 return If(ruid == 0 || euid == 0 || suid == 0, Error(EPERM)) | |
100 .ElseIf(ruid == 1 && euid == 1 && suid == 1, Error(EAGAIN)) | |
101 .Else(Error(EINVAL)); | |
102 } | |
103 return Allow(); | |
104 } | |
105 | |
106 private: | |
107 DISALLOW_COPY_AND_ASSIGN(MoreBooleanLogicPolicy); | |
108 }; | |
109 | |
110 BPF_TEST_C(BPFDSL, MoreBooleanLogic, MoreBooleanLogicPolicy) { | |
111 // Expect EPERM if any set to 0. | |
112 BPF_ASSERT_ERROR(EPERM, setresuid(0, 5, 5)); | |
113 BPF_ASSERT_ERROR(EPERM, setresuid(5, 0, 5)); | |
114 BPF_ASSERT_ERROR(EPERM, setresuid(5, 5, 0)); | |
115 | |
116 // Expect EAGAIN if all set to 1. | |
117 BPF_ASSERT_ERROR(EAGAIN, setresuid(1, 1, 1)); | |
118 | |
119 // Expect EINVAL for anything else. | |
120 BPF_ASSERT_ERROR(EINVAL, setresuid(5, 1, 1)); | |
121 BPF_ASSERT_ERROR(EINVAL, setresuid(1, 5, 1)); | |
122 BPF_ASSERT_ERROR(EINVAL, setresuid(1, 1, 5)); | |
123 BPF_ASSERT_ERROR(EINVAL, setresuid(3, 4, 5)); | |
124 } | |
125 | |
126 static const uintptr_t kDeadBeefAddr = | |
127 static_cast<uintptr_t>(0xdeadbeefdeadbeefULL); | |
128 | |
129 class ArgSizePolicy : public SandboxBPFDSLPolicy { | |
130 public: | |
131 ArgSizePolicy() {} | |
132 virtual ~ArgSizePolicy() {} | |
133 virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { | |
134 if (sysno == __NR_uname) { | |
135 const Arg<uintptr_t> addr(0); | |
136 return If(addr == kDeadBeefAddr, Error(EPERM)).Else(Allow()); | |
137 } | |
138 return Allow(); | |
139 } | |
140 | |
141 private: | |
142 DISALLOW_COPY_AND_ASSIGN(ArgSizePolicy); | |
143 }; | |
144 | |
145 BPF_TEST_C(BPFDSL, ArgSizeTest, ArgSizePolicy) { | |
146 struct utsname buf; | |
147 BPF_ASSERT_EQ(0, uname(&buf)); | |
148 | |
149 BPF_ASSERT_ERROR(EPERM, | |
150 uname(reinterpret_cast<struct utsname*>(kDeadBeefAddr))); | |
151 } | |
152 | |
153 class TrappingPolicy : public SandboxBPFDSLPolicy { | |
154 public: | |
155 TrappingPolicy() {} | |
156 virtual ~TrappingPolicy() {} | |
157 virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { | |
158 if (sysno == __NR_uname) { | |
159 return Trap(UnameTrap, &count_); | |
160 } | |
161 return Allow(); | |
162 } | |
163 | |
164 private: | |
165 static intptr_t count_; | |
166 | |
167 static intptr_t UnameTrap(const struct arch_seccomp_data& data, void* aux) { | |
168 BPF_ASSERT_EQ(&count_, aux); | |
169 return ++count_; | |
170 } | |
171 | |
172 DISALLOW_COPY_AND_ASSIGN(TrappingPolicy); | |
173 }; | |
174 | |
175 intptr_t TrappingPolicy::count_; | |
176 | |
177 BPF_TEST_C(BPFDSL, TrapTest, TrappingPolicy) { | |
178 BPF_ASSERT_EQ(1, uname(NULL)); | |
179 BPF_ASSERT_EQ(2, uname(NULL)); | |
180 BPF_ASSERT_EQ(3, uname(NULL)); | |
181 } | |
182 | |
183 class MaskingPolicy : public SandboxBPFDSLPolicy { | |
184 public: | |
185 MaskingPolicy() {} | |
186 virtual ~MaskingPolicy() {} | |
187 virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { | |
188 if (sysno == __NR_setuid) { | |
189 const Arg<uid_t> uid(0); | |
190 return If((uid & 0xf) == 0, Error(EINVAL)).Else(Error(EACCES)); | |
191 } | |
192 if (sysno == __NR_setgid) { | |
193 const Arg<gid_t> gid(0); | |
194 return If((gid & 0xf0) == 0xf0, Error(EINVAL)).Else(Error(EACCES)); | |
195 } | |
196 return Allow(); | |
197 } | |
198 | |
199 private: | |
200 DISALLOW_COPY_AND_ASSIGN(MaskingPolicy); | |
201 }; | |
202 | |
203 BPF_TEST_C(BPFDSL, MaskTest, MaskingPolicy) { | |
204 for (uid_t uid = 0; uid < 0x100; ++uid) { | |
205 const int expect_errno = (uid & 0xf) == 0 ? EINVAL : EACCES; | |
206 BPF_ASSERT_ERROR(expect_errno, setuid(uid)); | |
207 } | |
208 | |
209 for (gid_t gid = 0; gid < 0x100; ++gid) { | |
210 const int expect_errno = (gid & 0xf0) == 0xf0 ? EINVAL : EACCES; | |
211 BPF_ASSERT_ERROR(expect_errno, setgid(gid)); | |
212 } | |
213 } | |
214 | |
215 class ElseIfPolicy : public SandboxBPFDSLPolicy { | |
216 public: | |
217 ElseIfPolicy() {} | |
218 virtual ~ElseIfPolicy() {} | |
219 virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { | |
220 if (sysno == __NR_setuid) { | |
221 const Arg<uid_t> uid(0); | |
222 return If((uid & 0xfff) == 0, Error(0)) | |
223 .ElseIf((uid & 0xff0) == 0, Error(EINVAL)) | |
224 .ElseIf((uid & 0xf00) == 0, Error(EEXIST)) | |
225 .Else(Error(EACCES)); | |
226 } | |
227 return Allow(); | |
228 } | |
229 | |
230 private: | |
231 DISALLOW_COPY_AND_ASSIGN(ElseIfPolicy); | |
232 }; | |
233 | |
234 BPF_TEST_C(BPFDSL, ElseIfTest, ElseIfPolicy) { | |
235 BPF_ASSERT_EQ(0, setuid(0)); | |
236 | |
237 BPF_ASSERT_ERROR(EINVAL, setuid(0x0001)); | |
238 BPF_ASSERT_ERROR(EINVAL, setuid(0x0002)); | |
239 | |
240 BPF_ASSERT_ERROR(EEXIST, setuid(0x0011)); | |
241 BPF_ASSERT_ERROR(EEXIST, setuid(0x0022)); | |
242 | |
243 BPF_ASSERT_ERROR(EACCES, setuid(0x0111)); | |
244 BPF_ASSERT_ERROR(EACCES, setuid(0x0222)); | |
245 } | |
246 | |
247 } // namespace | |
248 } // namespace sandbox | |
OLD | NEW |