|
2 | 2 | // Distributed under the MIT software license, see the accompanying
|
3 | 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
4 | 4 |
|
| 5 | +#include <map> |
5 | 6 | #include <vector>
|
6 | 7 | #include <assert.h>
|
7 | 8 | #include <crypto/common.h>
|
@@ -118,3 +119,56 @@ uint32_t Interpret(const std::vector<bool> &asmap, const std::vector<bool> &ip)
|
118 | 119 | // Reached EOF without RETURN, or aborted (see any of the breaks above).
|
119 | 120 | return 0; // 0 is not a valid ASN
|
120 | 121 | }
|
| 122 | + |
| 123 | +bool SanityCheckASMap(const std::vector<bool>& asmap, int bits) |
| 124 | +{ |
| 125 | + const std::vector<bool>::const_iterator begin = asmap.begin(), endpos = asmap.end(); |
| 126 | + std::vector<bool>::const_iterator pos = begin; |
| 127 | + std::vector<std::pair<uint32_t, int>> jumps; // All future positions we may jump to (bit offset in asmap -> bits to consume left) |
| 128 | + jumps.reserve(bits); |
| 129 | + while (pos != endpos) { |
| 130 | + uint32_t offset = pos - begin; |
| 131 | + if (!jumps.empty() && offset >= jumps.back().first) return false; // There was a jump into the middle of the previous instruction |
| 132 | + Instruction opcode = DecodeType(pos, endpos); |
| 133 | + if (opcode == Instruction::RETURN) { |
| 134 | + uint32_t asn = DecodeASN(pos, endpos); |
| 135 | + if (asn == INVALID) return false; // ASN straddles EOF |
| 136 | + if (jumps.empty()) { |
| 137 | + // Nothing to execute anymore |
| 138 | + if (endpos - pos > 7) return false; // Excessive padding |
| 139 | + while (pos != endpos) { |
| 140 | + if (*pos) return false; // Nonzero padding bit |
| 141 | + ++pos; |
| 142 | + } |
| 143 | + return true; // Sanely reached EOF |
| 144 | + } else { |
| 145 | + // Continue by pretending we jumped to the next instruction |
| 146 | + offset = pos - begin; |
| 147 | + if (offset != jumps.back().first) return false; // Unreachable code |
| 148 | + bits = jumps.back().second; // Restore the number of bits we would have had left after this jump |
| 149 | + jumps.pop_back(); |
| 150 | + } |
| 151 | + } else if (opcode == Instruction::JUMP) { |
| 152 | + uint32_t jump = DecodeJump(pos, endpos); |
| 153 | + if (jump == INVALID) return false; // Jump offset straddles EOF |
| 154 | + if (jump > endpos - pos) return false; // Jump out of range |
| 155 | + if (bits == 0) return false; // Consuming bits past the end of the input |
| 156 | + --bits; |
| 157 | + uint32_t jump_offset = pos - begin + jump; |
| 158 | + if (!jumps.empty() && jump_offset >= jumps.back().first) return false; // Intersecting jumps |
| 159 | + jumps.emplace_back(jump_offset, bits); |
| 160 | + } else if (opcode == Instruction::MATCH) { |
| 161 | + uint32_t match = DecodeMatch(pos, endpos); |
| 162 | + if (match == INVALID) return false; // Match bits straddle EOF |
| 163 | + int matchlen = CountBits(match) - 1; |
| 164 | + if (bits < matchlen) return false; // Consuming bits past the end of the input |
| 165 | + bits -= matchlen; |
| 166 | + } else if (opcode == Instruction::DEFAULT) { |
| 167 | + uint32_t asn = DecodeASN(pos, endpos); |
| 168 | + if (asn == INVALID) return false; // ASN straddles EOF |
| 169 | + } else { |
| 170 | + return false; // Instruction straddles EOF |
| 171 | + } |
| 172 | + } |
| 173 | + return false; // Reached EOF without RETURN instruction |
| 174 | +} |
0 commit comments