| 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 "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | 5 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
| 6 #include "sandbox/linux/seccomp-bpf/verifier.h" | 6 #include "sandbox/linux/seccomp-bpf/verifier.h" |
| 7 #include "testing/gtest/include/gtest/gtest.h" | 7 #include "testing/gtest/include/gtest/gtest.h" |
| 8 | 8 |
| 9 using namespace playground2; | 9 using namespace playground2; |
| 10 | 10 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 ExitGroup(1); | 59 ExitGroup(1); |
| 60 } | 60 } |
| 61 Sandbox::setProcFd(proc_fd); | 61 Sandbox::setProcFd(proc_fd); |
| 62 Sandbox::setSandboxPolicy(evaluator, NULL); | 62 Sandbox::setSandboxPolicy(evaluator, NULL); |
| 63 Sandbox::startSandbox(); | 63 Sandbox::startSandbox(); |
| 64 } | 64 } |
| 65 | 65 |
| 66 void RunInSandbox(Sandbox::EvaluateSyscall evaluator, | 66 void RunInSandbox(Sandbox::EvaluateSyscall evaluator, |
| 67 void (*SandboxedCode)()) { | 67 void (*SandboxedCode)()) { |
| 68 // TODO(jln): Implement IsEqual for ErrorCode | 68 // TODO(jln): Implement IsEqual for ErrorCode |
| 69 // IsEqual(evaluator(__NR_exit_group), Sandbox::SB_ALLOWED) << | 69 // IsEqual(evaluator(__NR_exit_group), ErrorCode::ERR_ALLOWED) << |
| 70 // "You need to always allow exit_group() in your test policy"; | 70 // "You need to always allow exit_group() in your test policy"; |
| 71 StartSandboxOrDie(evaluator); | 71 StartSandboxOrDie(evaluator); |
| 72 // TODO(jln): find a way to use the testing framework inside | 72 // TODO(jln): find a way to use the testing framework inside |
| 73 // SandboxedCode() or at the very least to surface errors | 73 // SandboxedCode() or at the very least to surface errors |
| 74 SandboxedCode(); | 74 SandboxedCode(); |
| 75 // SandboxedCode() should have exited, this is a failure | 75 // SandboxedCode() should have exited, this is a failure |
| 76 ExitGroup(1); | 76 ExitGroup(1); |
| 77 } | 77 } |
| 78 | 78 |
| 79 // evaluator should always allow ExitGroup | 79 // evaluator should always allow ExitGroup |
| 80 // SandboxedCode should ExitGroup(kExpectedReturnValue) if and only if | 80 // SandboxedCode should ExitGroup(kExpectedReturnValue) if and only if |
| 81 // things go as expected. | 81 // things go as expected. |
| 82 void TryPolicyInProcess(Sandbox::EvaluateSyscall evaluator, | 82 void TryPolicyInProcess(Sandbox::EvaluateSyscall evaluator, |
| 83 void (*SandboxedCode)()) { | 83 void (*SandboxedCode)()) { |
| 84 // TODO(jln) figure out a way to surface whether we're actually testing | 84 // TODO(jln) figure out a way to surface whether we're actually testing |
| 85 // something or not. | 85 // something or not. |
| 86 if (Sandbox::supportsSeccompSandbox(-1) == Sandbox::STATUS_AVAILABLE) { | 86 if (Sandbox::supportsSeccompSandbox(-1) == Sandbox::STATUS_AVAILABLE) { |
| 87 EXPECT_EXIT(RunInSandbox(evaluator, SandboxedCode), | 87 EXPECT_EXIT(RunInSandbox(evaluator, SandboxedCode), |
| 88 ::testing::ExitedWithCode(kExpectedReturnValue), | 88 ::testing::ExitedWithCode(kExpectedReturnValue), |
| 89 ""); | 89 ""); |
| 90 } | 90 } |
| 91 } | 91 } |
| 92 | 92 |
| 93 // A simple blacklist test | 93 // A simple blacklist test |
| 94 | 94 |
| 95 Sandbox::ErrorCode BlacklistNanosleepPolicy(int sysno) { | 95 ErrorCode BlacklistNanosleepPolicy(int sysno) { |
| 96 if (sysno < static_cast<int>(MIN_SYSCALL) || | 96 if (sysno < static_cast<int>(MIN_SYSCALL) || |
| 97 sysno > static_cast<int>(MAX_SYSCALL)) { | 97 sysno > static_cast<int>(MAX_SYSCALL)) { |
| 98 // FIXME: we should really not have to do that in a trivial policy | 98 // FIXME: we should really not have to do that in a trivial policy |
| 99 return ENOSYS; | 99 return ENOSYS; |
| 100 } | 100 } |
| 101 switch (sysno) { | 101 switch (sysno) { |
| 102 case __NR_nanosleep: | 102 case __NR_nanosleep: |
| 103 return EACCES; | 103 return EACCES; |
| 104 default: | 104 default: |
| 105 return Sandbox::SB_ALLOWED; | 105 return ErrorCode::ERR_ALLOWED; |
| 106 } | 106 } |
| 107 } | 107 } |
| 108 | 108 |
| 109 void NanosleepProcess(void) { | 109 void NanosleepProcess(void) { |
| 110 const struct timespec ts = {0, 0}; | 110 const struct timespec ts = {0, 0}; |
| 111 errno = 0; | 111 errno = 0; |
| 112 if(syscall(__NR_nanosleep, &ts, NULL) != -1 || errno != EACCES) { | 112 if(syscall(__NR_nanosleep, &ts, NULL) != -1 || errno != EACCES) { |
| 113 ExitGroup(1); | 113 ExitGroup(1); |
| 114 } | 114 } |
| 115 ExitGroup(kExpectedReturnValue); | 115 ExitGroup(kExpectedReturnValue); |
| 116 } | 116 } |
| 117 | 117 |
| 118 TEST(SandboxBpf, ApplyBasicBlacklistPolicy) { | 118 TEST(SandboxBpf, ApplyBasicBlacklistPolicy) { |
| 119 TryPolicyInProcess(BlacklistNanosleepPolicy, NanosleepProcess); | 119 TryPolicyInProcess(BlacklistNanosleepPolicy, NanosleepProcess); |
| 120 } | 120 } |
| 121 | 121 |
| 122 // Now do a simple whitelist test | 122 // Now do a simple whitelist test |
| 123 | 123 |
| 124 Sandbox::ErrorCode WhitelistGetpidPolicy(int sysno) { | 124 ErrorCode WhitelistGetpidPolicy(int sysno) { |
| 125 switch (sysno) { | 125 switch (sysno) { |
| 126 case __NR_getpid: | 126 case __NR_getpid: |
| 127 case __NR_exit_group: | 127 case __NR_exit_group: |
| 128 return Sandbox::SB_ALLOWED; | 128 return ErrorCode::ERR_ALLOWED; |
| 129 default: | 129 default: |
| 130 return ENOMEM; | 130 return ENOMEM; |
| 131 } | 131 } |
| 132 } | 132 } |
| 133 | 133 |
| 134 void GetpidProcess(void) { | 134 void GetpidProcess(void) { |
| 135 errno = 0; | 135 errno = 0; |
| 136 // getpid() should be allowed | 136 // getpid() should be allowed |
| 137 if (syscall(__NR_getpid) < 0 || errno) | 137 if (syscall(__NR_getpid) < 0 || errno) |
| 138 ExitGroup(1); | 138 ExitGroup(1); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 154 static int BlacklistNanosleepPolicySigsysAuxData; | 154 static int BlacklistNanosleepPolicySigsysAuxData; |
| 155 | 155 |
| 156 intptr_t EnomemHandler(const struct arch_seccomp_data& args, void *aux) { | 156 intptr_t EnomemHandler(const struct arch_seccomp_data& args, void *aux) { |
| 157 // We also check that the auxiliary data is correct | 157 // We also check that the auxiliary data is correct |
| 158 if (!aux) | 158 if (!aux) |
| 159 ExitGroup(1); | 159 ExitGroup(1); |
| 160 *(static_cast<int*>(aux)) = kExpectedReturnValue; | 160 *(static_cast<int*>(aux)) = kExpectedReturnValue; |
| 161 return -ENOMEM; | 161 return -ENOMEM; |
| 162 } | 162 } |
| 163 | 163 |
| 164 Sandbox::ErrorCode BlacklistNanosleepPolicySigsys(int sysno) { | 164 ErrorCode BlacklistNanosleepPolicySigsys(int sysno) { |
| 165 if (sysno < static_cast<int>(MIN_SYSCALL) || | 165 if (sysno < static_cast<int>(MIN_SYSCALL) || |
| 166 sysno > static_cast<int>(MAX_SYSCALL)) { | 166 sysno > static_cast<int>(MAX_SYSCALL)) { |
| 167 // FIXME: we should really not have to do that in a trivial policy | 167 // FIXME: we should really not have to do that in a trivial policy |
| 168 return ENOSYS; | 168 return ENOSYS; |
| 169 } | 169 } |
| 170 switch (sysno) { | 170 switch (sysno) { |
| 171 case __NR_nanosleep: | 171 case __NR_nanosleep: |
| 172 return Sandbox::ErrorCode(EnomemHandler, | 172 return Sandbox::Trap(EnomemHandler, |
| 173 static_cast<void *>(&BlacklistNanosleepPolicySigsysAuxData)); | 173 static_cast<void *>(&BlacklistNanosleepPolicySigsysAuxData)); |
| 174 default: | 174 default: |
| 175 return Sandbox::SB_ALLOWED; | 175 return ErrorCode::ERR_ALLOWED; |
| 176 } | 176 } |
| 177 } | 177 } |
| 178 | 178 |
| 179 void NanosleepProcessSigsys(void) { | 179 void NanosleepProcessSigsys(void) { |
| 180 const struct timespec ts = {0, 0}; | 180 const struct timespec ts = {0, 0}; |
| 181 errno = 0; | 181 errno = 0; |
| 182 // getpid() should work properly | 182 // getpid() should work properly |
| 183 if (syscall(__NR_getpid) < 0) | 183 if (syscall(__NR_getpid) < 0) |
| 184 ExitGroup(1); | 184 ExitGroup(1); |
| 185 // Our Auxiliary Data, should be reset by the signal handler | 185 // Our Auxiliary Data, should be reset by the signal handler |
| (...skipping 20 matching lines...) Expand all Loading... |
| 206 // We try to make sure we exercise optimizations in the BPF compiler. We make | 206 // We try to make sure we exercise optimizations in the BPF compiler. We make |
| 207 // sure that the compiler can have an opportunity to coalesce syscalls with | 207 // sure that the compiler can have an opportunity to coalesce syscalls with |
| 208 // contiguous numbers and we also make sure that disjoint sets can return the | 208 // contiguous numbers and we also make sure that disjoint sets can return the |
| 209 // same errno. | 209 // same errno. |
| 210 int SysnoToRandomErrno(int sysno) { | 210 int SysnoToRandomErrno(int sysno) { |
| 211 // Small contiguous sets of 3 system calls return an errno equal to the | 211 // Small contiguous sets of 3 system calls return an errno equal to the |
| 212 // index of that set + 1 (so that we never return a NUL errno). | 212 // index of that set + 1 (so that we never return a NUL errno). |
| 213 return ((sysno & ~3) >> 2) % 29 + 1; | 213 return ((sysno & ~3) >> 2) % 29 + 1; |
| 214 } | 214 } |
| 215 | 215 |
| 216 Sandbox::ErrorCode SyntheticPolicy(int sysno) { | 216 ErrorCode SyntheticPolicy(int sysno) { |
| 217 if (sysno < static_cast<int>(MIN_SYSCALL) || | 217 if (sysno < static_cast<int>(MIN_SYSCALL) || |
| 218 sysno > static_cast<int>(MAX_SYSCALL)) { | 218 sysno > static_cast<int>(MAX_SYSCALL)) { |
| 219 // FIXME: we should really not have to do that in a trivial policy. | 219 // FIXME: we should really not have to do that in a trivial policy. |
| 220 return ENOSYS; | 220 return ENOSYS; |
| 221 } | 221 } |
| 222 if (sysno == __NR_exit_group) { | 222 if (sysno == __NR_exit_group) { |
| 223 // exit_group() is special, we really need it to work. | 223 // exit_group() is special, we really need it to work. |
| 224 return Sandbox::SB_ALLOWED; | 224 return ErrorCode::ERR_ALLOWED; |
| 225 } else { | 225 } else { |
| 226 return SysnoToRandomErrno(sysno); | 226 return SysnoToRandomErrno(sysno); |
| 227 } | 227 } |
| 228 } | 228 } |
| 229 | 229 |
| 230 void SyntheticProcess(void) { | 230 void SyntheticProcess(void) { |
| 231 // Ensure that that kExpectedReturnValue + syscallnumber + 1 does not int | 231 // Ensure that that kExpectedReturnValue + syscallnumber + 1 does not int |
| 232 // overflow. | 232 // overflow. |
| 233 if (std::numeric_limits<int>::max() - kExpectedReturnValue - 1 < | 233 if (std::numeric_limits<int>::max() - kExpectedReturnValue - 1 < |
| 234 static_cast<int>(MAX_SYSCALL)) { | 234 static_cast<int>(MAX_SYSCALL)) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 251 } | 251 } |
| 252 } | 252 } |
| 253 ExitGroup(kExpectedReturnValue); | 253 ExitGroup(kExpectedReturnValue); |
| 254 } | 254 } |
| 255 | 255 |
| 256 TEST(SandboxBpf, SyntheticPolicy) { | 256 TEST(SandboxBpf, SyntheticPolicy) { |
| 257 TryPolicyInProcess(SyntheticPolicy, SyntheticProcess); | 257 TryPolicyInProcess(SyntheticPolicy, SyntheticProcess); |
| 258 } | 258 } |
| 259 | 259 |
| 260 } // namespace | 260 } // namespace |
| OLD | NEW |