2#include "seccomp-filter.h"
4namespace PosixSeccomp {
7constexpr uint32_t Reachable = 1U << 16;
9bool validInstruction(
const Instruction& instruction,
size_t remaining) {
10 switch (instruction.code) {
12 return instruction.k <
sizeof(Data) && !(instruction.k & 3);
17 return instruction.k < 16;
19 return instruction.k != 0;
22 return instruction.k < 32;
24 return instruction.k < remaining;
33 return instruction.jt < remaining && instruction.jf < remaining;
64bool validatePaths(
const Instruction* instructions,
size_t count, uint32_t* incoming) {
65 incoming[0] = Reachable;
66 const auto merge = [&](
size_t destination, uint32_t initialized) {
67 incoming[destination] =
68 incoming[destination] ? incoming[destination] & initialized : initialized;
70 for (
size_t pc = 0; pc < count; ++pc) {
71 const Instruction& instruction = instructions[pc];
72 if (!validInstruction(instruction, count - pc - 1)) {
78 uint32_t initialized = incoming[pc];
79 if (instruction.code == (LD | MEM) || instruction.code == (LDX | MEM)) {
80 if (!(initialized & (1U << instruction.k))) {
83 }
else if (instruction.code == ST || instruction.code == STX) {
84 initialized |= 1U << instruction.k;
89 if ((instruction.code & 7) == RET) {
92 if (instruction.code == (JMP | JA)) {
93 merge(pc + 1 + instruction.k, initialized);
94 }
else if ((instruction.code & 7) == JMP) {
95 merge(pc + 1 + instruction.jt, initialized);
96 merge(pc + 1 + instruction.jf, initialized);
98 if (pc + 1 == count) {
101 merge(pc + 1, initialized);
108bool validate(
const Instruction* instructions,
size_t count) {
109 if (!instructions || !count || count > MaximumInstructions) {
112 const uint16_t last = instructions[count - 1].code;
113 if (last != (RET | K) && last != (RET | A)) {
117 uint32_t* incoming =
new uint32_t[count]();
121 const bool valid = validatePaths(instructions, count, incoming);
126uint32_t evaluate(
const Instruction* instructions,
size_t count,
const Data& data) {
127 if (!instructions || !count || count > MaximumInstructions) {
130 uint32_t accumulator = 0, index = 0, initialized = 0;
131 uint32_t memory[16] = {};
132 for (
size_t pc = 0; pc < count; ++pc) {
133 const Instruction& instruction = instructions[pc];
134 if (!validInstruction(instruction, count - pc - 1)) {
137 const uint32_t operand = instruction.code & X ? index : instruction.k;
138 switch (instruction.code) {
142 const unsigned char* source =
reinterpret_cast<const unsigned char*
>(&data) + instruction.k;
143 unsigned char* destination =
reinterpret_cast<unsigned char*
>(&accumulator);
144 for (
size_t byte = 0;
byte <
sizeof(accumulator); ++byte) {
145 destination[byte] = source[byte];
150 accumulator = instruction.k;
153 index = instruction.k;
156 accumulator =
sizeof(Data);
159 index =
sizeof(Data);
163 if (!(initialized & (1U << instruction.k))) {
166 if (instruction.code == (LD | MEM)) {
167 accumulator = memory[instruction.k];
169 index = memory[instruction.k];
174 memory[instruction.k] = instruction.code == ST ? accumulator : index;
175 initialized |= 1U << instruction.k;
179 accumulator += operand;
183 accumulator -= operand;
187 accumulator *= operand;
194 accumulator /= operand;
198 accumulator |= operand;
202 accumulator &= operand;
206 accumulator ^= operand;
210 accumulator <<= operand & 31;
214 accumulator >>= operand & 31;
217 accumulator = 0U - accumulator;
224 pc += accumulator == operand ? instruction.jt : instruction.jf;
228 pc += accumulator > operand ? instruction.jt : instruction.jf;
232 pc += accumulator >= operand ? instruction.jt : instruction.jf;
236 pc += accumulator & operand ? instruction.jt : instruction.jf;
239 return instruction.k;