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