Home | History | Annotate | Download | only in seccomp-bpf
      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
      3 // found in the LICENSE file.
      4 
      5 #include <string.h>
      6 
      7 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
      8 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h"
      9 #include "sandbox/linux/seccomp-bpf/syscall_iterator.h"
     10 #include "sandbox/linux/seccomp-bpf/verifier.h"
     11 
     12 
     13 namespace sandbox {
     14 
     15 namespace {
     16 
     17 struct State {
     18   State(const std::vector<struct sock_filter>& p,
     19         const struct arch_seccomp_data& d)
     20       : program(p), data(d), ip(0), accumulator(0), acc_is_valid(false) {}
     21   const std::vector<struct sock_filter>& program;
     22   const struct arch_seccomp_data& data;
     23   unsigned int ip;
     24   uint32_t accumulator;
     25   bool acc_is_valid;
     26 
     27  private:
     28   DISALLOW_IMPLICIT_CONSTRUCTORS(State);
     29 };
     30 
     31 uint32_t EvaluateErrorCode(SandboxBPF* sandbox,
     32                            const ErrorCode& code,
     33                            const struct arch_seccomp_data& data) {
     34   if (code.error_type() == ErrorCode::ET_SIMPLE ||
     35       code.error_type() == ErrorCode::ET_TRAP) {
     36     return code.err();
     37   } else if (code.error_type() == ErrorCode::ET_COND) {
     38     if (code.width() == ErrorCode::TP_32BIT &&
     39         (data.args[code.argno()] >> 32) &&
     40         (data.args[code.argno()] & 0xFFFFFFFF80000000ull) !=
     41             0xFFFFFFFF80000000ull) {
     42       return sandbox->Unexpected64bitArgument().err();
     43     }
     44     switch (code.op()) {
     45       case ErrorCode::OP_EQUAL:
     46         return EvaluateErrorCode(sandbox,
     47                                  (code.width() == ErrorCode::TP_32BIT
     48                                       ? uint32_t(data.args[code.argno()])
     49                                       : data.args[code.argno()]) == code.value()
     50                                      ? *code.passed()
     51                                      : *code.failed(),
     52                                  data);
     53       case ErrorCode::OP_HAS_ALL_BITS:
     54         return EvaluateErrorCode(sandbox,
     55                                  ((code.width() == ErrorCode::TP_32BIT
     56                                        ? uint32_t(data.args[code.argno()])
     57                                        : data.args[code.argno()]) &
     58                                   code.value()) == code.value()
     59                                      ? *code.passed()
     60                                      : *code.failed(),
     61                                  data);
     62       case ErrorCode::OP_HAS_ANY_BITS:
     63         return EvaluateErrorCode(sandbox,
     64                                  (code.width() == ErrorCode::TP_32BIT
     65                                       ? uint32_t(data.args[code.argno()])
     66                                       : data.args[code.argno()]) &
     67                                          code.value()
     68                                      ? *code.passed()
     69                                      : *code.failed(),
     70                                  data);
     71       default:
     72         return SECCOMP_RET_INVALID;
     73     }
     74   } else {
     75     return SECCOMP_RET_INVALID;
     76   }
     77 }
     78 
     79 bool VerifyErrorCode(SandboxBPF* sandbox,
     80                      const std::vector<struct sock_filter>& program,
     81                      struct arch_seccomp_data* data,
     82                      const ErrorCode& root_code,
     83                      const ErrorCode& code,
     84                      const char** err) {
     85   if (code.error_type() == ErrorCode::ET_SIMPLE ||
     86       code.error_type() == ErrorCode::ET_TRAP) {
     87     uint32_t computed_ret = Verifier::EvaluateBPF(program, *data, err);
     88     if (*err) {
     89       return false;
     90     } else if (computed_ret != EvaluateErrorCode(sandbox, root_code, *data)) {
     91       // For efficiency's sake, we'd much rather compare "computed_ret"
     92       // against "code.err()". This works most of the time, but it doesn't
     93       // always work for nested conditional expressions. The test values
     94       // that we generate on the fly to probe expressions can trigger
     95       // code flow decisions in multiple nodes of the decision tree, and the
     96       // only way to compute the correct error code in that situation is by
     97       // calling EvaluateErrorCode().
     98       *err = "Exit code from BPF program doesn't match";
     99       return false;
    100     }
    101   } else if (code.error_type() == ErrorCode::ET_COND) {
    102     if (code.argno() < 0 || code.argno() >= 6) {
    103       *err = "Invalid argument number in error code";
    104       return false;
    105     }
    106     switch (code.op()) {
    107       case ErrorCode::OP_EQUAL:
    108         // Verify that we can check a 32bit value (or the LSB of a 64bit value)
    109         // for equality.
    110         data->args[code.argno()] = code.value();
    111         if (!VerifyErrorCode(
    112                  sandbox, program, data, root_code, *code.passed(), err)) {
    113           return false;
    114         }
    115 
    116         // Change the value to no longer match and verify that this is detected
    117         // as an inequality.
    118         data->args[code.argno()] = code.value() ^ 0x55AA55AA;
    119         if (!VerifyErrorCode(
    120                  sandbox, program, data, root_code, *code.failed(), err)) {
    121           return false;
    122         }
    123 
    124         // BPF programs can only ever operate on 32bit values. So, we have
    125         // generated additional BPF instructions that inspect the MSB. Verify
    126         // that they behave as intended.
    127         if (code.width() == ErrorCode::TP_32BIT) {
    128           if (code.value() >> 32) {
    129             SANDBOX_DIE(
    130                 "Invalid comparison of a 32bit system call argument "
    131                 "against a 64bit constant; this test is always false.");
    132           }
    133 
    134           // If the system call argument was intended to be a 32bit parameter,
    135           // verify that it is a fatal error if a 64bit value is ever passed
    136           // here.
    137           data->args[code.argno()] = 0x100000000ull;
    138           if (!VerifyErrorCode(sandbox,
    139                                program,
    140                                data,
    141                                root_code,
    142                                sandbox->Unexpected64bitArgument(),
    143                                err)) {
    144             return false;
    145           }
    146         } else {
    147           // If the system call argument was intended to be a 64bit parameter,
    148           // verify that we can handle (in-)equality for the MSB. This is
    149           // essentially the same test that we did earlier for the LSB.
    150           // We only need to verify the behavior of the inequality test. We
    151           // know that the equality test already passed, as unlike the kernel
    152           // the Verifier does operate on 64bit quantities.
    153           data->args[code.argno()] = code.value() ^ 0x55AA55AA00000000ull;
    154           if (!VerifyErrorCode(
    155                    sandbox, program, data, root_code, *code.failed(), err)) {
    156             return false;
    157           }
    158         }
    159         break;
    160       case ErrorCode::OP_HAS_ALL_BITS:
    161       case ErrorCode::OP_HAS_ANY_BITS:
    162         // A comprehensive test of bit values is difficult and potentially
    163         // rather
    164         // time-expensive. We avoid doing so at run-time and instead rely on the
    165         // unittest for full testing. The test that we have here covers just the
    166         // common cases. We test against the bitmask itself, all zeros and all
    167         // ones.
    168         {
    169           // Testing "any" bits against a zero mask is always false. So, there
    170           // are some cases, where we expect tests to take the "failed()" branch
    171           // even though this is a test that normally should take "passed()".
    172           const ErrorCode& passed =
    173               (!code.value() && code.op() == ErrorCode::OP_HAS_ANY_BITS) ||
    174 
    175                       // On a 32bit system, it is impossible to pass a 64bit
    176                       // value as a
    177                       // system call argument. So, some additional tests always
    178                       // evaluate
    179                       // as false.
    180                       ((code.value() & ~uint64_t(uintptr_t(-1))) &&
    181                        code.op() == ErrorCode::OP_HAS_ALL_BITS) ||
    182                       (code.value() && !(code.value() & uintptr_t(-1)) &&
    183                        code.op() == ErrorCode::OP_HAS_ANY_BITS)
    184                   ? *code.failed()
    185                   : *code.passed();
    186 
    187           // Similary, testing for "all" bits in a zero mask is always true. So,
    188           // some cases pass despite them normally failing.
    189           const ErrorCode& failed =
    190               !code.value() && code.op() == ErrorCode::OP_HAS_ALL_BITS
    191                   ? *code.passed()
    192                   : *code.failed();
    193 
    194           data->args[code.argno()] = code.value() & uintptr_t(-1);
    195           if (!VerifyErrorCode(
    196                    sandbox, program, data, root_code, passed, err)) {
    197             return false;
    198           }
    199           data->args[code.argno()] = uintptr_t(-1);
    200           if (!VerifyErrorCode(
    201                    sandbox, program, data, root_code, passed, err)) {
    202             return false;
    203           }
    204           data->args[code.argno()] = 0;
    205           if (!VerifyErrorCode(
    206                    sandbox, program, data, root_code, failed, err)) {
    207             return false;
    208           }
    209         }
    210         break;
    211       default:  // TODO(markus): Need to add support for OP_GREATER
    212         *err = "Unsupported operation in conditional error code";
    213         return false;
    214     }
    215   } else {
    216     *err = "Attempting to return invalid error code from BPF program";
    217     return false;
    218   }
    219   return true;
    220 }
    221 
    222 void Ld(State* state, const struct sock_filter& insn, const char** err) {
    223   if (BPF_SIZE(insn.code) != BPF_W || BPF_MODE(insn.code) != BPF_ABS) {
    224     *err = "Invalid BPF_LD instruction";
    225     return;
    226   }
    227   if (insn.k < sizeof(struct arch_seccomp_data) && (insn.k & 3) == 0) {
    228     // We only allow loading of properly aligned 32bit quantities.
    229     memcpy(&state->accumulator,
    230            reinterpret_cast<const char*>(&state->data) + insn.k,
    231            4);
    232   } else {
    233     *err = "Invalid operand in BPF_LD instruction";
    234     return;
    235   }
    236   state->acc_is_valid = true;
    237   return;
    238 }
    239 
    240 void Jmp(State* state, const struct sock_filter& insn, const char** err) {
    241   if (BPF_OP(insn.code) == BPF_JA) {
    242     if (state->ip + insn.k + 1 >= state->program.size() ||
    243         state->ip + insn.k + 1 <= state->ip) {
    244     compilation_failure:
    245       *err = "Invalid BPF_JMP instruction";
    246       return;
    247     }
    248     state->ip += insn.k;
    249   } else {
    250     if (BPF_SRC(insn.code) != BPF_K || !state->acc_is_valid ||
    251         state->ip + insn.jt + 1 >= state->program.size() ||
    252         state->ip + insn.jf + 1 >= state->program.size()) {
    253       goto compilation_failure;
    254     }
    255     switch (BPF_OP(insn.code)) {
    256       case BPF_JEQ:
    257         if (state->accumulator == insn.k) {
    258           state->ip += insn.jt;
    259         } else {
    260           state->ip += insn.jf;
    261         }
    262         break;
    263       case BPF_JGT:
    264         if (state->accumulator > insn.k) {
    265           state->ip += insn.jt;
    266         } else {
    267           state->ip += insn.jf;
    268         }
    269         break;
    270       case BPF_JGE:
    271         if (state->accumulator >= insn.k) {
    272           state->ip += insn.jt;
    273         } else {
    274           state->ip += insn.jf;
    275         }
    276         break;
    277       case BPF_JSET:
    278         if (state->accumulator & insn.k) {
    279           state->ip += insn.jt;
    280         } else {
    281           state->ip += insn.jf;
    282         }
    283         break;
    284       default:
    285         goto compilation_failure;
    286     }
    287   }
    288 }
    289 
    290 uint32_t Ret(State*, const struct sock_filter& insn, const char** err) {
    291   if (BPF_SRC(insn.code) != BPF_K) {
    292     *err = "Invalid BPF_RET instruction";
    293     return 0;
    294   }
    295   return insn.k;
    296 }
    297 
    298 void Alu(State* state, const struct sock_filter& insn, const char** err) {
    299   if (BPF_OP(insn.code) == BPF_NEG) {
    300     state->accumulator = -state->accumulator;
    301     return;
    302   } else {
    303     if (BPF_SRC(insn.code) != BPF_K) {
    304       *err = "Unexpected source operand in arithmetic operation";
    305       return;
    306     }
    307     switch (BPF_OP(insn.code)) {
    308       case BPF_ADD:
    309         state->accumulator += insn.k;
    310         break;
    311       case BPF_SUB:
    312         state->accumulator -= insn.k;
    313         break;
    314       case BPF_MUL:
    315         state->accumulator *= insn.k;
    316         break;
    317       case BPF_DIV:
    318         if (!insn.k) {
    319           *err = "Illegal division by zero";
    320           break;
    321         }
    322         state->accumulator /= insn.k;
    323         break;
    324       case BPF_MOD:
    325         if (!insn.k) {
    326           *err = "Illegal division by zero";
    327           break;
    328         }
    329         state->accumulator %= insn.k;
    330         break;
    331       case BPF_OR:
    332         state->accumulator |= insn.k;
    333         break;
    334       case BPF_XOR:
    335         state->accumulator ^= insn.k;
    336         break;
    337       case BPF_AND:
    338         state->accumulator &= insn.k;
    339         break;
    340       case BPF_LSH:
    341         if (insn.k > 32) {
    342           *err = "Illegal shift operation";
    343           break;
    344         }
    345         state->accumulator <<= insn.k;
    346         break;
    347       case BPF_RSH:
    348         if (insn.k > 32) {
    349           *err = "Illegal shift operation";
    350           break;
    351         }
    352         state->accumulator >>= insn.k;
    353         break;
    354       default:
    355         *err = "Invalid operator in arithmetic operation";
    356         break;
    357     }
    358   }
    359 }
    360 
    361 }  // namespace
    362 
    363 bool Verifier::VerifyBPF(SandboxBPF* sandbox,
    364                          const std::vector<struct sock_filter>& program,
    365                          const SandboxBPFPolicy& policy,
    366                          const char** err) {
    367   *err = NULL;
    368   for (SyscallIterator iter(false); !iter.Done();) {
    369     uint32_t sysnum = iter.Next();
    370     // We ideally want to iterate over the full system call range and values
    371     // just above and just below this range. This gives us the full result set
    372     // of the "evaluators".
    373     // On Intel systems, this can fail in a surprising way, as a cleared bit 30
    374     // indicates either i386 or x86-64; and a set bit 30 indicates x32. And
    375     // unless we pay attention to setting this bit correctly, an early check in
    376     // our BPF program will make us fail with a misleading error code.
    377     struct arch_seccomp_data data = {static_cast<int>(sysnum),
    378                                      static_cast<uint32_t>(SECCOMP_ARCH)};
    379 #if defined(__i386__) || defined(__x86_64__)
    380 #if defined(__x86_64__) && defined(__ILP32__)
    381     if (!(sysnum & 0x40000000u)) {
    382       continue;
    383     }
    384 #else
    385     if (sysnum & 0x40000000u) {
    386       continue;
    387     }
    388 #endif
    389 #endif
    390     ErrorCode code = iter.IsValid(sysnum)
    391                          ? policy.EvaluateSyscall(sandbox, sysnum)
    392                          : policy.InvalidSyscall(sandbox);
    393     if (!VerifyErrorCode(sandbox, program, &data, code, code, err)) {
    394       return false;
    395     }
    396   }
    397   return true;
    398 }
    399 
    400 uint32_t Verifier::EvaluateBPF(const std::vector<struct sock_filter>& program,
    401                                const struct arch_seccomp_data& data,
    402                                const char** err) {
    403   *err = NULL;
    404   if (program.size() < 1 || program.size() >= SECCOMP_MAX_PROGRAM_SIZE) {
    405     *err = "Invalid program length";
    406     return 0;
    407   }
    408   for (State state(program, data); !*err; ++state.ip) {
    409     if (state.ip >= program.size()) {
    410       *err = "Invalid instruction pointer in BPF program";
    411       break;
    412     }
    413     const struct sock_filter& insn = program[state.ip];
    414     switch (BPF_CLASS(insn.code)) {
    415       case BPF_LD:
    416         Ld(&state, insn, err);
    417         break;
    418       case BPF_JMP:
    419         Jmp(&state, insn, err);
    420         break;
    421       case BPF_RET: {
    422         uint32_t r = Ret(&state, insn, err);
    423         switch (r & SECCOMP_RET_ACTION) {
    424           case SECCOMP_RET_TRAP:
    425           case SECCOMP_RET_ERRNO:
    426           case SECCOMP_RET_TRACE:
    427           case SECCOMP_RET_ALLOW:
    428             break;
    429           case SECCOMP_RET_KILL:     // We don't ever generate this
    430           case SECCOMP_RET_INVALID:  // Should never show up in BPF program
    431           default:
    432             *err = "Unexpected return code found in BPF program";
    433             return 0;
    434         }
    435         return r;
    436       }
    437       case BPF_ALU:
    438         Alu(&state, insn, err);
    439         break;
    440       default:
    441         *err = "Unexpected instruction in BPF program";
    442         break;
    443     }
    444   }
    445   return 0;
    446 }
    447 
    448 }  // namespace sandbox
    449