| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 <ostream> | 5 #include <ostream> |
| 6 | 6 |
| 7 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | 7 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
| 8 #include "sandbox/linux/seccomp-bpf/verifier.h" | 8 #include "sandbox/linux/seccomp-bpf/verifier.h" |
| 9 #include "testing/gtest/include/gtest/gtest.h" | 9 #include "testing/gtest/include/gtest/gtest.h" |
| 10 | 10 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 Sandbox::STATUS_AVAILABLE) { | 71 Sandbox::STATUS_AVAILABLE) { |
| 72 ExitGroup(1); | 72 ExitGroup(1); |
| 73 } | 73 } |
| 74 Sandbox::setProcFd(proc_fd); | 74 Sandbox::setProcFd(proc_fd); |
| 75 Sandbox::setSandboxPolicy(evaluator, NULL); | 75 Sandbox::setSandboxPolicy(evaluator, NULL); |
| 76 Sandbox::startSandbox(); | 76 Sandbox::startSandbox(); |
| 77 } | 77 } |
| 78 | 78 |
| 79 void RunInSandbox(Sandbox::EvaluateSyscall evaluator, | 79 void RunInSandbox(Sandbox::EvaluateSyscall evaluator, |
| 80 void (*SandboxedCode)()) { | 80 void (*SandboxedCode)()) { |
| 81 // TODO(markus): Implement IsEqual for ErrorCode | 81 // TODO(jln): Implement IsEqual for ErrorCode |
| 82 // IsEqual(evaluator(__NR_exit_group), Sandbox::SB_ALLOWED) << | 82 // IsEqual(evaluator(__NR_exit_group), ErrorCode::ERR_ALLOWED) << |
| 83 // "You need to always allow exit_group() in your test policy"; | 83 // "You need to always allow exit_group() in your test policy"; |
| 84 StartSandboxOrDie(evaluator); | 84 StartSandboxOrDie(evaluator); |
| 85 // TODO(jln): find a way to use the testing framework inside | 85 // TODO(jln): find a way to use the testing framework inside |
| 86 // SandboxedCode() or at the very least to surface errors | 86 // SandboxedCode() or at the very least to surface errors |
| 87 SandboxedCode(); | 87 SandboxedCode(); |
| 88 // SandboxedCode() should have exited, this is a failure | 88 // SandboxedCode() should have exited, this is a failure |
| 89 ExitGroup(1); | 89 ExitGroup(1); |
| 90 } | 90 } |
| 91 | 91 |
| 92 // evaluator should always allow ExitGroup | 92 // evaluator should always allow ExitGroup |
| (...skipping 10 matching lines...) Expand all Loading... |
| 103 } else { | 103 } else { |
| 104 // The sandbox is not available. We should still try to exercise what we | 104 // The sandbox is not available. We should still try to exercise what we |
| 105 // can. | 105 // can. |
| 106 // TODO(markus): (crbug.com/141545) let us call the compiler from here. | 106 // TODO(markus): (crbug.com/141545) let us call the compiler from here. |
| 107 Sandbox::setSandboxPolicy(evaluator, NULL); | 107 Sandbox::setSandboxPolicy(evaluator, NULL); |
| 108 } | 108 } |
| 109 } | 109 } |
| 110 | 110 |
| 111 // A simple blacklist test | 111 // A simple blacklist test |
| 112 | 112 |
| 113 Sandbox::ErrorCode BlacklistNanosleepPolicy(int sysno) { | 113 ErrorCode BlacklistNanosleepPolicy(int sysno) { |
| 114 if (sysno < static_cast<int>(MIN_SYSCALL) || | 114 if (sysno < static_cast<int>(MIN_SYSCALL) || |
| 115 sysno > static_cast<int>(MAX_SYSCALL)) { | 115 sysno > static_cast<int>(MAX_SYSCALL)) { |
| 116 // FIXME: we should really not have to do that in a trivial policy | 116 // FIXME: we should really not have to do that in a trivial policy |
| 117 return ENOSYS; | 117 return ErrorCode(ENOSYS); |
| 118 } | 118 } |
| 119 switch (sysno) { | 119 switch (sysno) { |
| 120 case __NR_nanosleep: | 120 case __NR_nanosleep: |
| 121 return EACCES; | 121 return ErrorCode(EACCES); |
| 122 default: | 122 default: |
| 123 return Sandbox::SB_ALLOWED; | 123 return ErrorCode(ErrorCode::ERR_ALLOWED); |
| 124 } | 124 } |
| 125 } | 125 } |
| 126 | 126 |
| 127 void NanosleepProcess(void) { | 127 void NanosleepProcess(void) { |
| 128 const struct timespec ts = {0, 0}; | 128 const struct timespec ts = {0, 0}; |
| 129 errno = 0; | 129 errno = 0; |
| 130 if(syscall(__NR_nanosleep, &ts, NULL) != -1 || errno != EACCES) { | 130 if(syscall(__NR_nanosleep, &ts, NULL) != -1 || errno != EACCES) { |
| 131 ExitGroup(1); | 131 ExitGroup(1); |
| 132 } | 132 } |
| 133 ExitGroup(kExpectedReturnValue); | 133 ExitGroup(kExpectedReturnValue); |
| 134 } | 134 } |
| 135 | 135 |
| 136 TEST(SandboxBpf, ApplyBasicBlacklistPolicy) { | 136 TEST(SandboxBpf, ApplyBasicBlacklistPolicy) { |
| 137 TryPolicyInProcess(BlacklistNanosleepPolicy, NanosleepProcess); | 137 TryPolicyInProcess(BlacklistNanosleepPolicy, NanosleepProcess); |
| 138 } | 138 } |
| 139 | 139 |
| 140 // Now do a simple whitelist test | 140 // Now do a simple whitelist test |
| 141 | 141 |
| 142 Sandbox::ErrorCode WhitelistGetpidPolicy(int sysno) { | 142 ErrorCode WhitelistGetpidPolicy(int sysno) { |
| 143 switch (sysno) { | 143 switch (sysno) { |
| 144 case __NR_getpid: | 144 case __NR_getpid: |
| 145 case __NR_exit_group: | 145 case __NR_exit_group: |
| 146 return Sandbox::SB_ALLOWED; | 146 return ErrorCode(ErrorCode::ERR_ALLOWED); |
| 147 default: | 147 default: |
| 148 return ENOMEM; | 148 return ErrorCode(ENOMEM); |
| 149 } | 149 } |
| 150 } | 150 } |
| 151 | 151 |
| 152 void GetpidProcess(void) { | 152 void GetpidProcess(void) { |
| 153 errno = 0; | 153 errno = 0; |
| 154 // getpid() should be allowed | 154 // getpid() should be allowed |
| 155 if (syscall(__NR_getpid) < 0 || errno) | 155 if (syscall(__NR_getpid) < 0 || errno) |
| 156 ExitGroup(1); | 156 ExitGroup(1); |
| 157 // getpgid() should be denied | 157 // getpgid() should be denied |
| 158 if (getpgid(0) != -1 || errno != ENOMEM) | 158 if (getpgid(0) != -1 || errno != ENOMEM) |
| (...skipping 13 matching lines...) Expand all Loading... |
| 172 static int BlacklistNanosleepPolicySigsysAuxData; | 172 static int BlacklistNanosleepPolicySigsysAuxData; |
| 173 | 173 |
| 174 intptr_t EnomemHandler(const struct arch_seccomp_data& args, void *aux) { | 174 intptr_t EnomemHandler(const struct arch_seccomp_data& args, void *aux) { |
| 175 // We also check that the auxiliary data is correct | 175 // We also check that the auxiliary data is correct |
| 176 if (!aux) | 176 if (!aux) |
| 177 ExitGroup(1); | 177 ExitGroup(1); |
| 178 *(static_cast<int*>(aux)) = kExpectedReturnValue; | 178 *(static_cast<int*>(aux)) = kExpectedReturnValue; |
| 179 return -ENOMEM; | 179 return -ENOMEM; |
| 180 } | 180 } |
| 181 | 181 |
| 182 Sandbox::ErrorCode BlacklistNanosleepPolicySigsys(int sysno) { | 182 ErrorCode BlacklistNanosleepPolicySigsys(int sysno) { |
| 183 if (sysno < static_cast<int>(MIN_SYSCALL) || | 183 if (sysno < static_cast<int>(MIN_SYSCALL) || |
| 184 sysno > static_cast<int>(MAX_SYSCALL)) { | 184 sysno > static_cast<int>(MAX_SYSCALL)) { |
| 185 // FIXME: we should really not have to do that in a trivial policy | 185 // FIXME: we should really not have to do that in a trivial policy |
| 186 return ENOSYS; | 186 return ErrorCode(ENOSYS); |
| 187 } | 187 } |
| 188 switch (sysno) { | 188 switch (sysno) { |
| 189 case __NR_nanosleep: | 189 case __NR_nanosleep: |
| 190 return Sandbox::ErrorCode(EnomemHandler, | 190 return Sandbox::Trap(EnomemHandler, |
| 191 static_cast<void *>(&BlacklistNanosleepPolicySigsysAuxData)); | 191 static_cast<void *>(&BlacklistNanosleepPolicySigsysAuxData)); |
| 192 default: | 192 default: |
| 193 return Sandbox::SB_ALLOWED; | 193 return ErrorCode(ErrorCode::ERR_ALLOWED); |
| 194 } | 194 } |
| 195 } | 195 } |
| 196 | 196 |
| 197 void NanosleepProcessSigsys(void) { | 197 void NanosleepProcessSigsys(void) { |
| 198 const struct timespec ts = {0, 0}; | 198 const struct timespec ts = {0, 0}; |
| 199 errno = 0; | 199 errno = 0; |
| 200 // getpid() should work properly | 200 // getpid() should work properly |
| 201 if (syscall(__NR_getpid) < 0) | 201 if (syscall(__NR_getpid) < 0) |
| 202 ExitGroup(1); | 202 ExitGroup(1); |
| 203 // Our Auxiliary Data, should be reset by the signal handler | 203 // Our Auxiliary Data, should be reset by the signal handler |
| (...skipping 20 matching lines...) Expand all Loading... |
| 224 // We try to make sure we exercise optimizations in the BPF compiler. We make | 224 // We try to make sure we exercise optimizations in the BPF compiler. We make |
| 225 // sure that the compiler can have an opportunity to coalesce syscalls with | 225 // sure that the compiler can have an opportunity to coalesce syscalls with |
| 226 // contiguous numbers and we also make sure that disjoint sets can return the | 226 // contiguous numbers and we also make sure that disjoint sets can return the |
| 227 // same errno. | 227 // same errno. |
| 228 int SysnoToRandomErrno(int sysno) { | 228 int SysnoToRandomErrno(int sysno) { |
| 229 // Small contiguous sets of 3 system calls return an errno equal to the | 229 // Small contiguous sets of 3 system calls return an errno equal to the |
| 230 // index of that set + 1 (so that we never return a NUL errno). | 230 // index of that set + 1 (so that we never return a NUL errno). |
| 231 return ((sysno & ~3) >> 2) % 29 + 1; | 231 return ((sysno & ~3) >> 2) % 29 + 1; |
| 232 } | 232 } |
| 233 | 233 |
| 234 Sandbox::ErrorCode SyntheticPolicy(int sysno) { | 234 ErrorCode SyntheticPolicy(int sysno) { |
| 235 if (sysno < static_cast<int>(MIN_SYSCALL) || | 235 if (sysno < static_cast<int>(MIN_SYSCALL) || |
| 236 sysno > static_cast<int>(MAX_SYSCALL)) { | 236 sysno > static_cast<int>(MAX_SYSCALL)) { |
| 237 // FIXME: we should really not have to do that in a trivial policy. | 237 // FIXME: we should really not have to do that in a trivial policy. |
| 238 return ENOSYS; | 238 return ErrorCode(ENOSYS); |
| 239 } | 239 } |
| 240 | 240 |
| 241 // TODO(jorgelo): remove this restriction once crbug.com/141694 is fixed. | 241 // TODO(jorgelo): remove this restriction once crbug.com/141694 is fixed. |
| 242 #if defined(__arm__) | 242 #if defined(__arm__) |
| 243 if (sysno > kArmPublicSysnoCeiling) | 243 if (sysno > kArmPublicSysnoCeiling) |
| 244 return ENOSYS; | 244 return ENOSYS; |
| 245 #endif | 245 #endif |
| 246 | 246 |
| 247 if (sysno == __NR_exit_group) { | 247 if (sysno == __NR_exit_group) { |
| 248 // exit_group() is special, we really need it to work. | 248 // exit_group() is special, we really need it to work. |
| 249 return Sandbox::SB_ALLOWED; | 249 return ErrorCode(ErrorCode::ERR_ALLOWED); |
| 250 } else { | 250 } else { |
| 251 return SysnoToRandomErrno(sysno); | 251 return ErrorCode(SysnoToRandomErrno(sysno)); |
| 252 } | 252 } |
| 253 } | 253 } |
| 254 | 254 |
| 255 void SyntheticProcess(void) { | 255 void SyntheticProcess(void) { |
| 256 // Ensure that that kExpectedReturnValue + syscallnumber + 1 does not int | 256 // Ensure that that kExpectedReturnValue + syscallnumber + 1 does not int |
| 257 // overflow. | 257 // overflow. |
| 258 if (std::numeric_limits<int>::max() - kExpectedReturnValue - 1 < | 258 if (std::numeric_limits<int>::max() - kExpectedReturnValue - 1 < |
| 259 static_cast<int>(MAX_SYSCALL)) { | 259 static_cast<int>(MAX_SYSCALL)) { |
| 260 ExitGroup(1); | 260 ExitGroup(1); |
| 261 } | 261 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 284 } | 284 } |
| 285 } | 285 } |
| 286 ExitGroup(kExpectedReturnValue); | 286 ExitGroup(kExpectedReturnValue); |
| 287 } | 287 } |
| 288 | 288 |
| 289 TEST(SandboxBpf, SyntheticPolicy) { | 289 TEST(SandboxBpf, SyntheticPolicy) { |
| 290 TryPolicyInProcess(SyntheticPolicy, SyntheticProcess); | 290 TryPolicyInProcess(SyntheticPolicy, SyntheticProcess); |
| 291 } | 291 } |
| 292 | 292 |
| 293 } // namespace | 293 } // namespace |
| OLD | NEW |