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/seccomp-bpf-helpers/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 "sandbox/linux/seccomp-bpf/bpf_tests.h" | |
14 #include "sandbox/linux/seccomp-bpf/errorcode.h" | |
15 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" | |
16 | |
17 using namespace sandbox::bpf_dsl; | |
18 | |
19 // Helper macro to assert that expression |expr| returns -1 and sets | |
20 // errno to |err|. | |
21 #define BPF_ASSERT_ERROR(err, expr) \ | |
22 do { \ | |
23 errno = 0; \ | |
24 BPF_ASSERT_EQ(-1, expr); \ | |
25 BPF_ASSERT_EQ(err, errno); \ | |
26 } while (0) | |
27 | |
28 namespace sandbox { | |
29 | |
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 class BooleanLogicPolicy : public SandboxBPFDSLPolicy { | |
54 public: | |
55 BooleanLogicPolicy() {} | |
56 virtual ~BooleanLogicPolicy() {} | |
57 virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { | |
58 if (sysno == __NR_socketpair) { | |
jln (very slow on Chromium)
2014/06/27 01:45:50
x86 32 bits is unhappy with this since it's multip
mdempsky
2014/06/28 00:36:42
Ah, right.
| |
59 const Arg<int> domain(0), type(1), protocol(2); | |
60 return If(domain == AF_UNIX && | |
61 (type == SOCK_STREAM || type == SOCK_DGRAM) && | |
62 protocol == 0, | |
63 Error(EPERM)).Else(Error(EINVAL)); | |
64 } | |
65 return Allow(); | |
66 } | |
67 | |
68 private: | |
69 DISALLOW_COPY_AND_ASSIGN(BooleanLogicPolicy); | |
70 }; | |
71 | |
72 BPF_TEST_C(BPFDSL, BooleanLogic, BooleanLogicPolicy) { | |
73 int sv[2]; | |
74 | |
75 // Acceptable combinations that should return EPERM. | |
76 BPF_ASSERT_ERROR(EPERM, socketpair(AF_UNIX, SOCK_STREAM, 0, sv)); | |
77 BPF_ASSERT_ERROR(EPERM, socketpair(AF_UNIX, SOCK_DGRAM, 0, sv)); | |
78 | |
79 // Combinations that are invalid for only one reason; should return EINVAL. | |
80 BPF_ASSERT_ERROR(EINVAL, socketpair(AF_INET, SOCK_STREAM, 0, sv)); | |
81 BPF_ASSERT_ERROR(EINVAL, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sv)); | |
82 BPF_ASSERT_ERROR(EINVAL, socketpair(AF_UNIX, SOCK_STREAM, IPPROTO_TCP, sv)); | |
83 | |
84 // Completely unacceptable combination; should also return EINVAL. | |
85 BPF_ASSERT_ERROR(EINVAL, | |
86 socketpair(AF_INET, SOCK_SEQPACKET, IPPROTO_UDP, sv)); | |
87 } | |
88 | |
89 static const uintptr_t kDeadBeefAddr = | |
90 static_cast<uintptr_t>(0xdeadbeefdeadbeefULL); | |
91 | |
92 class ArgSizePolicy : public SandboxBPFDSLPolicy { | |
93 public: | |
94 ArgSizePolicy() {} | |
95 virtual ~ArgSizePolicy() {} | |
96 virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { | |
97 if (sysno == __NR_uname) { | |
98 const Arg<uintptr_t> addr(0); | |
99 return If(addr == kDeadBeefAddr, Error(EPERM)).Else(Allow()); | |
100 } | |
101 return Allow(); | |
102 } | |
103 | |
104 private: | |
105 DISALLOW_COPY_AND_ASSIGN(ArgSizePolicy); | |
106 }; | |
107 | |
108 BPF_TEST_C(BPFDSL, ArgSizeTest, ArgSizePolicy) { | |
109 struct utsname buf; | |
110 BPF_ASSERT_EQ(0, uname(&buf)); | |
111 | |
112 BPF_ASSERT_ERROR(EPERM, | |
113 uname(reinterpret_cast<struct utsname*>(kDeadBeefAddr))); | |
114 } | |
115 | |
116 class TrappingPolicy : public SandboxBPFDSLPolicy { | |
117 public: | |
118 TrappingPolicy() {} | |
119 virtual ~TrappingPolicy() {} | |
120 virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { | |
121 if (sysno == __NR_uname) { | |
122 return Trap(UnameTrap, &count_); | |
123 } | |
124 return Allow(); | |
125 } | |
126 | |
127 private: | |
128 static intptr_t count_; | |
129 | |
130 static intptr_t UnameTrap(const struct arch_seccomp_data& data, void* aux) { | |
131 BPF_ASSERT_EQ(&count_, aux); | |
132 return ++count_; | |
133 } | |
134 | |
135 DISALLOW_COPY_AND_ASSIGN(TrappingPolicy); | |
136 }; | |
137 | |
138 intptr_t TrappingPolicy::count_; | |
139 | |
140 BPF_TEST_C(BPFDSL, TrapTest, TrappingPolicy) { | |
141 BPF_ASSERT_EQ(1, uname(NULL)); | |
142 BPF_ASSERT_EQ(2, uname(NULL)); | |
143 BPF_ASSERT_EQ(3, uname(NULL)); | |
144 } | |
145 | |
146 class MaskingPolicy : public SandboxBPFDSLPolicy { | |
147 public: | |
148 MaskingPolicy() {} | |
149 virtual ~MaskingPolicy() {} | |
150 virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { | |
151 if (sysno == __NR_setuid) { | |
152 const Arg<uid_t> uid(0); | |
153 return If((uid & 0xf) == 0, Error(EINVAL)).Else(Error(EACCES)); | |
154 } | |
155 if (sysno == __NR_setgid) { | |
156 const Arg<gid_t> gid(0); | |
157 return If((gid & 0xf0) == 0xf0, Error(EINVAL)).Else(Error(EACCES)); | |
158 } | |
159 return Allow(); | |
160 } | |
161 | |
162 private: | |
163 DISALLOW_COPY_AND_ASSIGN(MaskingPolicy); | |
164 }; | |
165 | |
166 BPF_TEST_C(BPFDSL, MaskTest, MaskingPolicy) { | |
167 for (uid_t uid = 0; uid < 0x100; ++uid) { | |
168 const int expect_errno = (uid & 0xf) == 0 ? EINVAL : EACCES; | |
169 BPF_ASSERT_ERROR(expect_errno, setuid(uid)); | |
170 } | |
171 | |
172 for (gid_t gid = 0; gid < 0x100; ++gid) { | |
173 const int expect_errno = (gid & 0xf0) == 0xf0 ? EINVAL : EACCES; | |
174 BPF_ASSERT_ERROR(expect_errno, setgid(gid)); | |
175 } | |
176 } | |
177 | |
178 class ElseIfPolicy : public SandboxBPFDSLPolicy { | |
179 public: | |
180 ElseIfPolicy() {} | |
181 virtual ~ElseIfPolicy() {} | |
182 virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE { | |
183 if (sysno == __NR_setuid) { | |
184 const Arg<uid_t> uid(0); | |
185 return If((uid & 0xfff) == 0, Error(0)) | |
186 .ElseIf((uid & 0xff0) == 0, Error(EINVAL)) | |
187 .ElseIf((uid & 0xf00) == 0, Error(EEXIST)) | |
188 .Else(Error(EACCES)); | |
189 } | |
190 return Allow(); | |
191 } | |
192 | |
193 private: | |
194 DISALLOW_COPY_AND_ASSIGN(ElseIfPolicy); | |
195 }; | |
196 | |
197 BPF_TEST_C(BPFDSL, ElseIfTest, ElseIfPolicy) { | |
198 BPF_ASSERT_EQ(0, setuid(0)); | |
199 | |
200 BPF_ASSERT_ERROR(EINVAL, setuid(0x0001)); | |
201 BPF_ASSERT_ERROR(EINVAL, setuid(0x0002)); | |
202 | |
203 BPF_ASSERT_ERROR(EEXIST, setuid(0x0011)); | |
204 BPF_ASSERT_ERROR(EEXIST, setuid(0x0022)); | |
205 | |
206 BPF_ASSERT_ERROR(EACCES, setuid(0x0111)); | |
207 BPF_ASSERT_ERROR(EACCES, setuid(0x0222)); | |
208 } | |
209 | |
210 } // namespace | |
211 | |
212 } // namespace sandbox | |
OLD | NEW |