Chromium Code Reviews| Index: sandbox/linux/seccomp-bpf/verifier.cc |
| diff --git a/sandbox/linux/seccomp-bpf/verifier.cc b/sandbox/linux/seccomp-bpf/verifier.cc |
| index 40a1aa20be7a8fcd196a7e89e3f72128c6aeb9ee..1c996197e84bc4080b3d152df9a065ac30504b2f 100644 |
| --- a/sandbox/linux/seccomp-bpf/verifier.cc |
| +++ b/sandbox/linux/seccomp-bpf/verifier.cc |
| @@ -42,13 +42,83 @@ bool Verifier::VerifyBPF(const std::vector<struct sock_filter>& program, |
| #endif |
| #endif |
| ErrorCode code = evaluate_syscall(sysnum, aux); |
| - uint32_t computed_ret = EvaluateBPF(program, data, err); |
| + if (!VerifyErrorCode(program, &data, code, err)) { |
| + return false; |
| + } |
| + } |
| + return true; |
| +} |
| + |
| +bool Verifier::VerifyErrorCode(const std::vector<struct sock_filter>& program, |
| + struct arch_seccomp_data *data, |
| + const ErrorCode& code, const char **err) { |
| + if (code.error_type_ == ErrorCode::ET_SIMPLE || |
| + code.error_type_ == ErrorCode::ET_TRAP) { |
| + uint32_t computed_ret = EvaluateBPF(program, *data, err); |
| if (*err) { |
| return false; |
| } else if (computed_ret != code.err()) { |
| *err = "Exit code from BPF program doesn't match"; |
| return false; |
| } |
| + } else if (code.error_type_ == ErrorCode::ET_COND) { |
| + if (code.argno_ < 0 || code.argno_ >= 6) { |
| + *err = "Invalid argument number in error code"; |
| + return false; |
| + } |
| + switch (code.op_) { |
| + case ErrorCode::OP_EQUAL: |
| + // Verify that we can check a 32bit value (or the LSB of a 64bit value) |
| + // for equality. |
| + data->args[code.argno_] = code.value_; |
| + if (!VerifyErrorCode(program, data, *code.passed_, err)) { |
| + return false; |
| + } |
| + |
| + // Change the value to no longer match and verify that this is detected |
| + // as an inequality. |
| + data->args[code.argno_] = code.value_ ^ 0x55AA55AA; |
| + if (!VerifyErrorCode(program, data, *code.failed_, err)) { |
| + return false; |
| + } |
| + |
| + // BPF programs can only ever operate on 32bit values. So, we have |
| + // generated additional BPF instructions that inspect the MSB. Verify |
| + // that they behave as intended. |
| + if (code.width_ == ErrorCode::TP_32BIT) { |
| + if (code.value_ >> 32) { |
| + SANDBOX_DIE("Invalid comparison of a 32bit system call argument " |
| + "against a 64bit constant; this test is always false."); |
| + } |
| + |
| + // If the system call argument was intended to be a 32bit parameter, |
| + // verify that it is a fatal error if a 64bit value is ever passed |
| + // here. |
| + data->args[code.argno_] = 0x100000000ull; |
| + if (!VerifyErrorCode(program, data, Sandbox::Unexpected64bitArgument(), |
| + err)) { |
| + return false; |
| + } |
| + } else { |
| + // If the system call argument was intended to be a 64bit parameter, |
| + // verify that we can handle (in-)equality for the MSB. This is |
| + // essentially the same test that we did earlier for the LSB. |
| + // We only need to verify the behavior of the inequality test. We |
| + // know that the equality test already passed, as unlike the kernel |
| + // the Verifier does operate on 64bit quantities. |
| + data->args[code.argno_] = code.value_ ^ 0x55AA55AA00000000ull; |
| + if (!VerifyErrorCode(program, data, *code.failed_, err)) { |
| + return false; |
| + } |
| + } |
| + break; |
| + default: // TODO(markus): We can only check for equality so far. |
| + *err = "Unsupported operation in conditional error code"; |
| + return false; |
| + } |
| + } else { |
| + *err = "Attempting to return invalid error code from BPF program"; |
| + return false; |
| } |
| return true; |
| } |
| @@ -74,8 +144,21 @@ uint32_t Verifier::EvaluateBPF(const std::vector<struct sock_filter>& program, |
| case BPF_JMP: |
| Jmp(&state, insn, err); |
| break; |
| - case BPF_RET: |
| - return Ret(&state, insn, err); |
| + case BPF_RET: { |
| + uint32_t r = Ret(&state, insn, err); |
| + switch (r & SECCOMP_RET_ACTION) { |
| + case SECCOMP_RET_TRAP: |
|
jln (very slow on Chromium)
2012/12/14 02:28:02
nit: indent the case:
|
| + case SECCOMP_RET_ERRNO: |
| + case SECCOMP_RET_ALLOW: |
| + break; |
| + case SECCOMP_RET_KILL: // We don't ever generate this |
| + case SECCOMP_RET_TRACE: // We don't ever generate this |
| + case SECCOMP_RET_INVALID: // Should never show up in BPF program |
| + default: |
| + *err = "Unexpected return code found in BPF program"; |
| + return 0; |
| + } |
| + return r; } |
| default: |
| *err = "Unexpected instruction in BPF program"; |
| break; |