OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/seccomp-bpf-helpers/syscall_parameters_restrictions.h" | 5 #include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <fcntl.h> | 9 #include <fcntl.h> |
10 #include <linux/net.h> | 10 #include <linux/net.h> |
11 #include <sched.h> | 11 #include <sched.h> |
12 #include <signal.h> | 12 #include <signal.h> |
13 #include <sys/ioctl.h> | 13 #include <sys/ioctl.h> |
14 #include <sys/mman.h> | 14 #include <sys/mman.h> |
15 #include <sys/prctl.h> | 15 #include <sys/prctl.h> |
16 #include <sys/stat.h> | 16 #include <sys/stat.h> |
17 #include <sys/types.h> | 17 #include <sys/types.h> |
18 #include <unistd.h> | 18 #include <unistd.h> |
19 | 19 |
20 #include "base/basictypes.h" | 20 #include "base/basictypes.h" |
21 #include "base/logging.h" | 21 #include "base/logging.h" |
22 #include "build/build_config.h" | 22 #include "build/build_config.h" |
| 23 #include "sandbox/linux/seccomp-bpf-helpers/bpf_dsl.h" |
23 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" | 24 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" |
24 #include "sandbox/linux/seccomp-bpf/linux_seccomp.h" | 25 #include "sandbox/linux/seccomp-bpf/linux_seccomp.h" |
25 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | 26 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
26 | 27 |
27 #if defined(OS_ANDROID) | 28 #if defined(OS_ANDROID) |
28 #if !defined(F_DUPFD_CLOEXEC) | 29 #if !defined(F_DUPFD_CLOEXEC) |
29 #define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6) | 30 #define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6) |
30 #endif | 31 #endif |
31 #endif | 32 #endif |
32 | 33 |
33 #if defined(__arm__) && !defined(MAP_STACK) | 34 #if defined(__arm__) && !defined(MAP_STACK) |
34 #define MAP_STACK 0x20000 // Daisy build environment has old headers. | 35 #define MAP_STACK 0x20000 // Daisy build environment has old headers. |
35 #endif | 36 #endif |
36 | 37 |
| 38 using namespace sandbox::bpf_dsl; |
| 39 |
37 namespace { | 40 namespace { |
38 | 41 |
39 inline bool IsArchitectureX86_64() { | 42 inline bool IsArchitectureX86_64() { |
40 #if defined(__x86_64__) | 43 #if defined(__x86_64__) |
41 return true; | 44 return true; |
42 #else | 45 #else |
43 return false; | 46 return false; |
44 #endif | 47 #endif |
45 } | 48 } |
46 | 49 |
(...skipping 13 matching lines...) Expand all Loading... |
60 #endif | 63 #endif |
61 } | 64 } |
62 | 65 |
63 } // namespace. | 66 } // namespace. |
64 | 67 |
65 namespace sandbox { | 68 namespace sandbox { |
66 | 69 |
67 // Allow Glibc's and Android pthread creation flags, crash on any other | 70 // Allow Glibc's and Android pthread creation flags, crash on any other |
68 // thread creation attempts and EPERM attempts to use neither | 71 // thread creation attempts and EPERM attempts to use neither |
69 // CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations. | 72 // CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations. |
70 ErrorCode RestrictCloneToThreadsAndEPERMFork(SandboxBPF* sandbox) { | 73 ResultExpr RestrictCloneToThreadsAndEPERMFork() { |
| 74 const Arg<int> flags_arg(0); |
71 if (!IsAndroid()) { | 75 if (!IsAndroid()) { |
72 const uint64_t kGlibcPthreadFlags = | 76 const uint64_t kGlibcPthreadFlags = |
73 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | | 77 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | |
74 CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID | | 78 CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID | |
75 CLONE_CHILD_CLEARTID; | 79 CLONE_CHILD_CLEARTID; |
76 | 80 |
77 return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 81 return If(flags_arg == kGlibcPthreadFlags).Then( |
78 kGlibcPthreadFlags, | 82 Allow() |
79 ErrorCode(ErrorCode::ERR_ALLOWED), | 83 ).ElseIf((flags_arg & (CLONE_VM | CLONE_THREAD)) == 0).Then( |
80 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS, | 84 Error(EPERM) |
81 CLONE_VM | CLONE_THREAD, | 85 ).Else( |
82 sandbox->Trap(SIGSYSCloneFailure, NULL), | 86 bpf_dsl::Trap(SIGSYSCloneFailure, NULL) |
83 ErrorCode(EPERM))); | 87 ); |
84 } else { | 88 } else { |
85 const uint64_t kAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES | | 89 const uint64_t kAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES | |
86 CLONE_SIGHAND | CLONE_THREAD | | 90 CLONE_SIGHAND | CLONE_THREAD | |
87 CLONE_SYSVSEM; | 91 CLONE_SYSVSEM; |
88 const uint64_t kObsoleteAndroidCloneMask = | 92 const uint64_t kObsoleteAndroidCloneMask = |
89 kAndroidCloneMask | CLONE_DETACHED; | 93 kAndroidCloneMask | CLONE_DETACHED; |
90 | 94 |
91 return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 95 return If(flags_arg == kAndroidCloneMask || |
92 kAndroidCloneMask, | 96 flags_arg == kObsoleteAndroidCloneMask).Then( |
93 ErrorCode(ErrorCode::ERR_ALLOWED), | 97 Allow() |
94 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 98 ).ElseIf((flags_arg & (CLONE_VM | CLONE_THREAD)) == 0).Then( |
95 kObsoleteAndroidCloneMask, | 99 Error(EPERM) |
96 ErrorCode(ErrorCode::ERR_ALLOWED), | 100 ).Else( |
97 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS, | 101 bpf_dsl::Trap(SIGSYSCloneFailure, NULL) |
98 CLONE_VM | CLONE_THREAD, | 102 ); |
99 sandbox->Trap(SIGSYSCloneFailure, NULL), | |
100 ErrorCode(EPERM)))); | |
101 } | 103 } |
102 } | 104 } |
103 | 105 |
104 ErrorCode RestrictPrctl(SandboxBPF* sandbox) { | 106 ResultExpr RestrictPrctl() { |
105 // Will need to add seccomp compositing in the future. PR_SET_PTRACER is | 107 // Will need to add seccomp compositing in the future. PR_SET_PTRACER is |
106 // used by breakpad but not needed anymore. | 108 // used by breakpad but not needed anymore. |
107 return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 109 const Arg<int> option_arg(0); |
108 PR_SET_NAME, ErrorCode(ErrorCode::ERR_ALLOWED), | 110 return If(option_arg == PR_SET_NAME || |
109 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 111 option_arg == PR_SET_DUMPABLE || |
110 PR_SET_DUMPABLE, ErrorCode(ErrorCode::ERR_ALLOWED), | 112 option_arg == PR_GET_DUMPABLE).Then( |
111 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 113 Allow() |
112 PR_GET_DUMPABLE, ErrorCode(ErrorCode::ERR_ALLOWED), | 114 ).Else( |
113 sandbox->Trap(SIGSYSPrctlFailure, NULL)))); | 115 bpf_dsl::Trap(SIGSYSPrctlFailure, NULL) |
| 116 ); |
114 } | 117 } |
115 | 118 |
116 ErrorCode RestrictIoctl(SandboxBPF* sandbox) { | 119 ResultExpr RestrictIoctl() { |
117 return sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, TCGETS, | 120 const Arg<int> request_arg(1); |
118 ErrorCode(ErrorCode::ERR_ALLOWED), | 121 return If(request_arg == TCGETS || request_arg == FIONREAD).Then( |
119 sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, FIONREAD, | 122 Allow() |
120 ErrorCode(ErrorCode::ERR_ALLOWED), | 123 ).Else( |
121 sandbox->Trap(SIGSYSIoctlFailure, NULL))); | 124 bpf_dsl::Trap(SIGSYSIoctlFailure, NULL) |
| 125 ); |
122 } | 126 } |
123 | 127 |
124 ErrorCode RestrictMmapFlags(SandboxBPF* sandbox) { | 128 ResultExpr RestrictMmapFlags() { |
125 // The flags you see are actually the allowed ones, and the variable is a | 129 // The flags you see are actually the allowed ones, and the variable is a |
126 // "denied" mask because of the negation operator. | 130 // "denied" mask because of the negation operator. |
127 // Significantly, we don't permit MAP_HUGETLB, or the newer flags such as | 131 // Significantly, we don't permit MAP_HUGETLB, or the newer flags such as |
128 // MAP_POPULATE. | 132 // MAP_POPULATE. |
129 // TODO(davidung), remove MAP_DENYWRITE with updated Tegra libraries. | 133 // TODO(davidung), remove MAP_DENYWRITE with updated Tegra libraries. |
130 uint32_t denied_mask = ~(MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS | | 134 uint32_t denied_mask = ~(MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS | |
131 MAP_STACK | MAP_NORESERVE | MAP_FIXED | | 135 MAP_STACK | MAP_NORESERVE | MAP_FIXED | |
132 MAP_DENYWRITE); | 136 MAP_DENYWRITE); |
133 return sandbox->Cond(3, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS, | 137 const Arg<int> flags_arg(3); |
134 denied_mask, | 138 return If((flags_arg & denied_mask) == 0).Then( |
135 sandbox->Trap(CrashSIGSYS_Handler, NULL), | 139 Allow() |
136 ErrorCode(ErrorCode::ERR_ALLOWED)); | 140 ).Else( |
| 141 bpf_dsl::Trap(CrashSIGSYS_Handler, NULL) |
| 142 ); |
137 } | 143 } |
138 | 144 |
139 ErrorCode RestrictMprotectFlags(SandboxBPF* sandbox) { | 145 ResultExpr RestrictMprotectFlags() { |
140 // The flags you see are actually the allowed ones, and the variable is a | 146 // The flags you see are actually the allowed ones, and the variable is a |
141 // "denied" mask because of the negation operator. | 147 // "denied" mask because of the negation operator. |
142 // Significantly, we don't permit weird undocumented flags such as | 148 // Significantly, we don't permit weird undocumented flags such as |
143 // PROT_GROWSDOWN. | 149 // PROT_GROWSDOWN. |
144 uint32_t denied_mask = ~(PROT_READ | PROT_WRITE | PROT_EXEC); | 150 uint32_t denied_mask = ~(PROT_READ | PROT_WRITE | PROT_EXEC); |
145 return sandbox->Cond(2, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS, | 151 const Arg<int> prot_arg(2); |
146 denied_mask, | 152 return If((prot_arg & denied_mask) == 0).Then( |
147 sandbox->Trap(CrashSIGSYS_Handler, NULL), | 153 Allow() |
148 ErrorCode(ErrorCode::ERR_ALLOWED)); | 154 ).Else( |
| 155 bpf_dsl::Trap(CrashSIGSYS_Handler, NULL) |
| 156 ); |
149 } | 157 } |
150 | 158 |
151 ErrorCode RestrictFcntlCommands(SandboxBPF* sandbox) { | 159 ResultExpr RestrictFcntlCommands() { |
152 // We also restrict the flags in F_SETFL. We don't want to permit flags with | 160 // We also restrict the flags in F_SETFL. We don't want to permit flags with |
153 // a history of trouble such as O_DIRECT. The flags you see are actually the | 161 // a history of trouble such as O_DIRECT. The flags you see are actually the |
154 // allowed ones, and the variable is a "denied" mask because of the negation | 162 // allowed ones, and the variable is a "denied" mask because of the negation |
155 // operator. | 163 // operator. |
156 // Glibc overrides the kernel's O_LARGEFILE value. Account for this. | 164 // Glibc overrides the kernel's O_LARGEFILE value. Account for this. |
157 int kOLargeFileFlag = O_LARGEFILE; | 165 int kOLargeFileFlag = O_LARGEFILE; |
158 if (IsArchitectureX86_64() || IsArchitectureI386()) | 166 if (IsArchitectureX86_64() || IsArchitectureI386()) |
159 kOLargeFileFlag = 0100000; | 167 kOLargeFileFlag = 0100000; |
160 | 168 |
161 // TODO(jln): add TP_LONG/TP_SIZET types. | |
162 ErrorCode::ArgType mask_long_type; | |
163 if (sizeof(long) == 8) | |
164 mask_long_type = ErrorCode::TP_64BIT; | |
165 else if (sizeof(long) == 4) | |
166 mask_long_type = ErrorCode::TP_32BIT; | |
167 else | |
168 NOTREACHED(); | |
169 | |
170 unsigned long denied_mask = ~(O_ACCMODE | O_APPEND | O_NONBLOCK | O_SYNC | | 169 unsigned long denied_mask = ~(O_ACCMODE | O_APPEND | O_NONBLOCK | O_SYNC | |
171 kOLargeFileFlag | O_CLOEXEC | O_NOATIME); | 170 kOLargeFileFlag | O_CLOEXEC | O_NOATIME); |
172 return sandbox->Cond(1, ErrorCode::TP_32BIT, | 171 const Arg<int> cmd_arg(1); |
173 ErrorCode::OP_EQUAL, F_GETFL, | 172 const Arg<unsigned long> flags_arg(2); |
174 ErrorCode(ErrorCode::ERR_ALLOWED), | 173 |
175 sandbox->Cond(1, ErrorCode::TP_32BIT, | 174 return If(cmd_arg == F_GETFL || |
176 ErrorCode::OP_EQUAL, F_SETFL, | 175 (cmd_arg == F_SETFL && (flags_arg & denied_mask) == 0) || |
177 sandbox->Cond(2, mask_long_type, | 176 cmd_arg == F_GETFD || |
178 ErrorCode::OP_HAS_ANY_BITS, denied_mask, | 177 cmd_arg == F_SETFD || |
179 sandbox->Trap(CrashSIGSYS_Handler, NULL), | 178 cmd_arg == F_DUPFD || |
180 ErrorCode(ErrorCode::ERR_ALLOWED)), | 179 cmd_arg == F_SETLK || |
181 sandbox->Cond(1, ErrorCode::TP_32BIT, | 180 cmd_arg == F_SETLKW || |
182 ErrorCode::OP_EQUAL, F_GETFD, | 181 cmd_arg == F_GETLK || |
183 ErrorCode(ErrorCode::ERR_ALLOWED), | 182 cmd_arg == F_DUPFD_CLOEXEC).Then( |
184 sandbox->Cond(1, ErrorCode::TP_32BIT, | 183 Allow() |
185 ErrorCode::OP_EQUAL, F_SETFD, | 184 ).Else( |
186 ErrorCode(ErrorCode::ERR_ALLOWED), | 185 bpf_dsl::Trap(CrashSIGSYS_Handler, NULL) |
187 sandbox->Cond(1, ErrorCode::TP_32BIT, | 186 ); |
188 ErrorCode::OP_EQUAL, F_DUPFD, | |
189 ErrorCode(ErrorCode::ERR_ALLOWED), | |
190 sandbox->Cond(1, ErrorCode::TP_32BIT, | |
191 ErrorCode::OP_EQUAL, F_SETLK, | |
192 ErrorCode(ErrorCode::ERR_ALLOWED), | |
193 sandbox->Cond(1, ErrorCode::TP_32BIT, | |
194 ErrorCode::OP_EQUAL, F_SETLKW, | |
195 ErrorCode(ErrorCode::ERR_ALLOWED), | |
196 sandbox->Cond(1, ErrorCode::TP_32BIT, | |
197 ErrorCode::OP_EQUAL, F_GETLK, | |
198 ErrorCode(ErrorCode::ERR_ALLOWED), | |
199 sandbox->Cond(1, ErrorCode::TP_32BIT, | |
200 ErrorCode::OP_EQUAL, F_DUPFD_CLOEXEC, | |
201 ErrorCode(ErrorCode::ERR_ALLOWED), | |
202 sandbox->Trap(CrashSIGSYS_Handler, NULL)))))))))); | |
203 } | 187 } |
204 | 188 |
205 #if defined(__i386__) | 189 #if defined(__i386__) |
206 ErrorCode RestrictSocketcallCommand(SandboxBPF* sandbox) { | 190 ResultExpr RestrictSocketcallCommand() { |
207 // Unfortunately, we are unable to restrict the first parameter to | 191 // Unfortunately, we are unable to restrict the first parameter to |
208 // socketpair(2). Whilst initially sounding bad, it's noteworthy that very | 192 // socketpair(2). Whilst initially sounding bad, it's noteworthy that very |
209 // few protocols actually support socketpair(2). The scary call that we're | 193 // few protocols actually support socketpair(2). The scary call that we're |
210 // worried about, socket(2), remains blocked. | 194 // worried about, socket(2), remains blocked. |
211 return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 195 const Arg<int> call_arg(0); |
212 SYS_SOCKETPAIR, ErrorCode(ErrorCode::ERR_ALLOWED), | 196 return If(call_arg == SYS_SOCKETPAIR || |
213 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 197 call_arg == SYS_SEND || |
214 SYS_SEND, ErrorCode(ErrorCode::ERR_ALLOWED), | 198 call_arg == SYS_RECV || |
215 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 199 call_arg == SYS_SENDTO || |
216 SYS_RECV, ErrorCode(ErrorCode::ERR_ALLOWED), | 200 call_arg == SYS_RECVFROM || |
217 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 201 call_arg == SYS_SHUTDOWN || |
218 SYS_SENDTO, ErrorCode(ErrorCode::ERR_ALLOWED), | 202 call_arg == SYS_SENDMSG || |
219 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 203 call_arg == SYS_RECVMSG).Then( |
220 SYS_RECVFROM, ErrorCode(ErrorCode::ERR_ALLOWED), | 204 Allow() |
221 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 205 ).Else( |
222 SYS_SHUTDOWN, ErrorCode(ErrorCode::ERR_ALLOWED), | 206 Error(EPERM) |
223 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 207 ); |
224 SYS_SENDMSG, ErrorCode(ErrorCode::ERR_ALLOWED), | |
225 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | |
226 SYS_RECVMSG, ErrorCode(ErrorCode::ERR_ALLOWED), | |
227 ErrorCode(EPERM))))))))); | |
228 } | 208 } |
229 #endif | 209 #endif |
230 | 210 |
231 ErrorCode RestrictKillTarget(pid_t target_pid, SandboxBPF* sandbox, int sysno) { | 211 ResultExpr RestrictKillTarget(pid_t target_pid, int sysno) { |
232 switch (sysno) { | 212 switch (sysno) { |
233 case __NR_kill: | 213 case __NR_kill: |
234 case __NR_tgkill: | 214 case __NR_tgkill: { |
235 return sandbox->Cond(0, | 215 const Arg<pid_t> target_arg(0); |
236 ErrorCode::TP_32BIT, | 216 return If(target_arg == target_pid).Then( |
237 ErrorCode::OP_EQUAL, | 217 Allow() |
238 target_pid, | 218 ).Else( |
239 ErrorCode(ErrorCode::ERR_ALLOWED), | 219 bpf_dsl::Trap(SIGSYSKillFailure, NULL) |
240 sandbox->Trap(SIGSYSKillFailure, NULL)); | 220 ); |
| 221 } |
241 case __NR_tkill: | 222 case __NR_tkill: |
242 return sandbox->Trap(SIGSYSKillFailure, NULL); | 223 return bpf_dsl::Trap(SIGSYSKillFailure, NULL); |
243 default: | 224 default: |
244 NOTREACHED(); | 225 NOTREACHED(); |
245 return sandbox->Trap(CrashSIGSYS_Handler, NULL); | 226 return bpf_dsl::Trap(CrashSIGSYS_Handler, NULL); |
246 } | 227 } |
247 } | 228 } |
248 | 229 |
249 } // namespace sandbox. | 230 } // namespace sandbox. |
OLD | NEW |