Skip to content

Commit

Permalink
Add asmap sanity checker
Browse files Browse the repository at this point in the history
  • Loading branch information
sipa authored and xanimo committed Apr 4, 2024
1 parent 7518eb4 commit ccdfb66
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/addrman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -643,5 +643,9 @@ std::vector<bool> CAddrMan::DecodeAsmap(fs::path path)
bits.push_back((cur_byte >> bit) & 1);
}
}
if (!SanityCheckASMap(bits)) {
LogPrintf("Sanity check of asmap file %s failed\n", path);
return {};
}
return bits;
}
5 changes: 5 additions & 0 deletions src/netaddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -795,3 +795,8 @@ bool operator<(const CSubNet& a, const CSubNet& b)
{
return (a.network < b.network || (a.network == b.network && memcmp(a.netmask, b.netmask, 16) < 0));
}

bool SanityCheckASMap(const std::vector<bool>& asmap)
{
return SanityCheckASMap(asmap, 128); // For IP address lookups, the input is 128 bits
}
2 changes: 2 additions & 0 deletions src/netaddress.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,6 @@ class CService : public CNetAddr
}
};

bool SanityCheckASMap(const std::vector<bool>& asmap);

#endif // BITCOIN_NETADDRESS_H
54 changes: 54 additions & 0 deletions src/util/asmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <map>
#include <vector>
#include <assert.h>
#include <crypto/common.h>
Expand Down Expand Up @@ -118,3 +119,56 @@ uint32_t Interpret(const std::vector<bool> &asmap, const std::vector<bool> &ip)
// Reached EOF without RETURN, or aborted (see any of the breaks above).
return 0; // 0 is not a valid ASN
}

bool SanityCheckASMap(const std::vector<bool>& asmap, int bits)
{
const std::vector<bool>::const_iterator begin = asmap.begin(), endpos = asmap.end();
std::vector<bool>::const_iterator pos = begin;
std::vector<std::pair<uint32_t, int>> jumps; // All future positions we may jump to (bit offset in asmap -> bits to consume left)
jumps.reserve(bits);
while (pos != endpos) {
uint32_t offset = pos - begin;
if (!jumps.empty() && offset >= jumps.back().first) return false; // There was a jump into the middle of the previous instruction
Instruction opcode = DecodeType(pos, endpos);
if (opcode == Instruction::RETURN) {
uint32_t asn = DecodeASN(pos, endpos);
if (asn == INVALID) return false; // ASN straddles EOF
if (jumps.empty()) {
// Nothing to execute anymore
if (endpos - pos > 7) return false; // Excessive padding
while (pos != endpos) {
if (*pos) return false; // Nonzero padding bit
++pos;
}
return true; // Sanely reached EOF
} else {
// Continue by pretending we jumped to the next instruction
offset = pos - begin;
if (offset != jumps.back().first) return false; // Unreachable code
bits = jumps.back().second; // Restore the number of bits we would have had left after this jump
jumps.pop_back();
}
} else if (opcode == Instruction::JUMP) {
uint32_t jump = DecodeJump(pos, endpos);
if (jump == INVALID) return false; // Jump offset straddles EOF
if (jump > endpos - pos) return false; // Jump out of range
if (bits == 0) return false; // Consuming bits past the end of the input
--bits;
uint32_t jump_offset = pos - begin + jump;
if (!jumps.empty() && jump_offset >= jumps.back().first) return false; // Intersecting jumps
jumps.emplace_back(jump_offset, bits);
} else if (opcode == Instruction::MATCH) {
uint32_t match = DecodeMatch(pos, endpos);
if (match == INVALID) return false; // Match bits straddle EOF
int matchlen = CountBits(match) - 1;
if (bits < matchlen) return false; // Consuming bits past the end of the input
bits -= matchlen;
} else if (opcode == Instruction::DEFAULT) {
uint32_t asn = DecodeASN(pos, endpos);
if (asn == INVALID) return false; // ASN straddles EOF
} else {
return false; // Instruction straddles EOF
}
}
return false; // Reached EOF without RETURN instruction
}
5 changes: 5 additions & 0 deletions src/util/asmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
#ifndef BITCOIN_UTIL_ASMAP_H
#define BITCOIN_UTIL_ASMAP_H

#include <stdint.h>
#include <vector>

uint32_t Interpret(const std::vector<bool> &asmap, const std::vector<bool> &ip);

bool SanityCheckASMap(const std::vector<bool>& asmap, int bits);

#endif // BITCOIN_UTIL_ASMAP_H

0 comments on commit ccdfb66

Please sign in to comment.