15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "sandbox/linux/seccomp-bpf/verifier.h" 61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string.h> 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <limits> 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "sandbox/linux/seccomp-bpf/linux_seccomp.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sandbox/linux/seccomp-bpf/syscall_iterator.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace sandbox { 17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace { 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst uint64_t kLower32Bits = std::numeric_limits<uint32_t>::max(); 211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst uint64_t kUpper32Bits = static_cast<uint64_t>(kLower32Bits) << 32; 221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst uint64_t kFull64Bits = std::numeric_limits<uint64_t>::max(); 231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct State { 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) State(const std::vector<struct sock_filter>& p, 26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const struct arch_seccomp_data& d) 27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : program(p), data(d), ip(0), accumulator(0), acc_is_valid(false) {} 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::vector<struct sock_filter>& program; 29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const struct arch_seccomp_data& data; 30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) unsigned int ip; 31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) uint32_t accumulator; 32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool acc_is_valid; 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_IMPLICIT_CONSTRUCTORS(State); 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)uint32_t EvaluateErrorCode(SandboxBPF* sandbox, 39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const ErrorCode& code, 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const struct arch_seccomp_data& data) { 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (code.error_type() == ErrorCode::ET_SIMPLE || 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) code.error_type() == ErrorCode::ET_TRAP) { 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return code.err(); 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (code.error_type() == ErrorCode::ET_COND) { 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (code.width() == ErrorCode::TP_32BIT && 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (data.args[code.argno()] >> 32) && 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (data.args[code.argno()] & 0xFFFFFFFF80000000ull) != 48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 0xFFFFFFFF80000000ull) { 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return sandbox->Unexpected64bitArgument().err(); 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci bool equal = (data.args[code.argno()] & code.mask()) == code.value(); 521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return EvaluateErrorCode( 531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci sandbox, equal ? *code.passed() : *code.failed(), data); 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return SECCOMP_RET_INVALID; 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool VerifyErrorCode(SandboxBPF* sandbox, 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::vector<struct sock_filter>& program, 61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) struct arch_seccomp_data* data, 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ErrorCode& root_code, 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ErrorCode& code, 64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const char** err) { 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (code.error_type() == ErrorCode::ET_SIMPLE || 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) code.error_type() == ErrorCode::ET_TRAP) { 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint32_t computed_ret = Verifier::EvaluateBPF(program, *data, err); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*err) { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (computed_ret != EvaluateErrorCode(sandbox, root_code, *data)) { 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // For efficiency's sake, we'd much rather compare "computed_ret" 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // against "code.err()". This works most of the time, but it doesn't 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // always work for nested conditional expressions. The test values 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // that we generate on the fly to probe expressions can trigger 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // code flow decisions in multiple nodes of the decision tree, and the 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // only way to compute the correct error code in that situation is by 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // calling EvaluateErrorCode(). 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *err = "Exit code from BPF program doesn't match"; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (code.error_type() == ErrorCode::ET_COND) { 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (code.argno() < 0 || code.argno() >= 6) { 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *err = "Invalid argument number in error code"; 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // TODO(mdempsky): The test values generated here try to provide good 881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // coverage for generated BPF instructions while avoiding combinatorial 891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // explosion on large policies. Ideally we would instead take a fuzzing-like 901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // approach and generate a bounded number of test cases regardless of policy 911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // size. 921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Verify that we can check a value for simple equality. 941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci data->args[code.argno()] = code.value(); 951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!VerifyErrorCode( 961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci sandbox, program, data, root_code, *code.passed(), err)) { 971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // If mask ignores any bits, verify that setting those bits is still 1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // detected as equality. 1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci uint64_t ignored_bits = ~code.mask(); 1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (code.width() == ErrorCode::TP_32BIT) { 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ignored_bits = static_cast<uint32_t>(ignored_bits); 1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if ((ignored_bits & kLower32Bits) != 0) { 1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci data->args[code.argno()] = code.value() | (ignored_bits & kLower32Bits); 1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!VerifyErrorCode( 1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci sandbox, program, data, root_code, *code.passed(), err)) { 1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if ((ignored_bits & kUpper32Bits) != 0) { 1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci data->args[code.argno()] = code.value() | (ignored_bits & kUpper32Bits); 1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!VerifyErrorCode( 1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci sandbox, program, data, root_code, *code.passed(), err)) { 1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Verify that changing bits included in the mask is detected as inequality. 1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if ((code.mask() & kLower32Bits) != 0) { 1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci data->args[code.argno()] = code.value() ^ (code.mask() & kLower32Bits); 1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!VerifyErrorCode( 1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci sandbox, program, data, root_code, *code.failed(), err)) { 1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if ((code.mask() & kUpper32Bits) != 0) { 1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci data->args[code.argno()] = code.value() ^ (code.mask() & kUpper32Bits); 1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!VerifyErrorCode( 1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci sandbox, program, data, root_code, *code.failed(), err)) { 1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (code.width() == ErrorCode::TP_32BIT) { 1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // For 32-bit system call arguments, we emit additional instructions to 1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // validate the upper 32-bits. Here we test that validation. 1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Arbitrary 64-bit values should be rejected. 1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci data->args[code.argno()] = 1ULL << 32; 1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!VerifyErrorCode(sandbox, 1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program, 1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci data, 1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci root_code, 1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci sandbox->Unexpected64bitArgument(), 1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci err)) { 1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return false; 1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Upper 32-bits set without the MSB of the lower 32-bits set should be 1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // rejected too. 1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci data->args[code.argno()] = kUpper32Bits; 1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!VerifyErrorCode(sandbox, 1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program, 1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci data, 1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci root_code, 1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci sandbox->Unexpected64bitArgument(), 1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci err)) { 161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return false; 1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *err = "Attempting to return invalid error code from BPF program"; 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void Ld(State* state, const struct sock_filter& insn, const char** err) { 172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (BPF_SIZE(insn.code) != BPF_W || BPF_MODE(insn.code) != BPF_ABS) { 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *err = "Invalid BPF_LD instruction"; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (insn.k < sizeof(struct arch_seccomp_data) && (insn.k & 3) == 0) { 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We only allow loading of properly aligned 32bit quantities. 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(&state->accumulator, 179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) reinterpret_cast<const char*>(&state->data) + insn.k, 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *err = "Invalid operand in BPF_LD instruction"; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->acc_is_valid = true; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void Jmp(State* state, const struct sock_filter& insn, const char** err) { 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (BPF_OP(insn.code) == BPF_JA) { 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (state->ip + insn.k + 1 >= state->program.size() || 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->ip + insn.k + 1 <= state->ip) { 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) compilation_failure: 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *err = "Invalid BPF_JMP instruction"; 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->ip += insn.k; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (BPF_SRC(insn.code) != BPF_K || !state->acc_is_valid || 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->ip + insn.jt + 1 >= state->program.size() || 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state->ip + insn.jf + 1 >= state->program.size()) { 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto compilation_failure; 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (BPF_OP(insn.code)) { 205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_JEQ: 206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (state->accumulator == insn.k) { 207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->ip += insn.jt; 208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else { 209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->ip += insn.jf; 210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_JGT: 213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (state->accumulator > insn.k) { 214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->ip += insn.jt; 215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else { 216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->ip += insn.jf; 217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_JGE: 220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (state->accumulator >= insn.k) { 221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->ip += insn.jt; 222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else { 223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->ip += insn.jf; 224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_JSET: 227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (state->accumulator & insn.k) { 228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->ip += insn.jt; 229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } else { 230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->ip += insn.jf; 231f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 233f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) default: 234f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) goto compilation_failure; 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)uint32_t Ret(State*, const struct sock_filter& insn, const char** err) { 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (BPF_SRC(insn.code) != BPF_K) { 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *err = "Invalid BPF_RET instruction"; 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return insn.k; 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 247f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void Alu(State* state, const struct sock_filter& insn, const char** err) { 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (BPF_OP(insn.code) == BPF_NEG) { 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) state->accumulator = -state->accumulator; 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (BPF_SRC(insn.code) != BPF_K) { 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *err = "Unexpected source operand in arithmetic operation"; 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (BPF_OP(insn.code)) { 257f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_ADD: 258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->accumulator += insn.k; 2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 260f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_SUB: 261f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->accumulator -= insn.k; 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 263f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_MUL: 264f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->accumulator *= insn.k; 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 266f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_DIV: 267f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!insn.k) { 268f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *err = "Illegal division by zero"; 269f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 270f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 271f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->accumulator /= insn.k; 272f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 273f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_MOD: 274f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!insn.k) { 275f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *err = "Illegal division by zero"; 276f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 277f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->accumulator %= insn.k; 279f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 280f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_OR: 281f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->accumulator |= insn.k; 282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 283f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_XOR: 284f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->accumulator ^= insn.k; 285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 286f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_AND: 287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->accumulator &= insn.k; 288f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 289f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_LSH: 290f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (insn.k > 32) { 291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *err = "Illegal shift operation"; 292f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 293f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 294f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->accumulator <<= insn.k; 295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 296f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_RSH: 297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (insn.k > 32) { 298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *err = "Illegal shift operation"; 299f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 300f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 301f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) state->accumulator >>= insn.k; 302f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) default: 304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *err = "Invalid operator in arithmetic operation"; 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 312a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool Verifier::VerifyBPF(SandboxBPF* sandbox, 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::vector<struct sock_filter>& program, 314a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const SandboxBPFPolicy& policy, 315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const char** err) { 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *err = NULL; 317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (SyscallIterator iter(false); !iter.Done();) { 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) uint32_t sysnum = iter.Next(); 3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We ideally want to iterate over the full system call range and values 3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // just above and just below this range. This gives us the full result set 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // of the "evaluators". 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // On Intel systems, this can fail in a surprising way, as a cleared bit 30 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // indicates either i386 or x86-64; and a set bit 30 indicates x32. And 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // unless we pay attention to setting this bit correctly, an early check in 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // our BPF program will make us fail with a misleading error code. 326f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) struct arch_seccomp_data data = {static_cast<int>(sysnum), 327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) static_cast<uint32_t>(SECCOMP_ARCH)}; 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(__i386__) || defined(__x86_64__) 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(__x86_64__) && defined(__ILP32__) 3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!(sysnum & 0x40000000u)) { 3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (sysnum & 0x40000000u) { 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) continue; 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 339cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ErrorCode code = iter.IsValid(sysnum) 340cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ? policy.EvaluateSyscall(sandbox, sysnum) 341cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) : policy.InvalidSyscall(sandbox); 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!VerifyErrorCode(sandbox, program, &data, code, code, err)) { 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)uint32_t Verifier::EvaluateBPF(const std::vector<struct sock_filter>& program, 3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const struct arch_seccomp_data& data, 351f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const char** err) { 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *err = NULL; 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (program.size() < 1 || program.size() >= SECCOMP_MAX_PROGRAM_SIZE) { 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *err = "Invalid program length"; 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0; 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (State state(program, data); !*err; ++state.ip) { 3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (state.ip >= program.size()) { 3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *err = "Invalid instruction pointer in BPF program"; 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const struct sock_filter& insn = program[state.ip]; 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (BPF_CLASS(insn.code)) { 364f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_LD: 365f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Ld(&state, insn, err); 3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 367f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_JMP: 368f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Jmp(&state, insn, err); 369f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 370f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_RET: { 371f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) uint32_t r = Ret(&state, insn, err); 372f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) switch (r & SECCOMP_RET_ACTION) { 373f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case SECCOMP_RET_TRAP: 374f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case SECCOMP_RET_ERRNO: 375f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case SECCOMP_RET_TRACE: 376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case SECCOMP_RET_ALLOW: 377f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 378f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case SECCOMP_RET_KILL: // We don't ever generate this 379f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case SECCOMP_RET_INVALID: // Should never show up in BPF program 380f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) default: 381f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *err = "Unexpected return code found in BPF program"; 382f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return 0; 383f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 384f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return r; 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 386f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) case BPF_ALU: 387f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Alu(&state, insn, err); 388f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 389f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) default: 390f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *err = "Unexpected instruction in BPF program"; 391f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) break; 3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0; 3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 397a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} // namespace sandbox 398