Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to latest bpf_conformance suite #561

Merged
merged 2 commits into from
Jan 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ jobs:
steps:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt install libboost-dev libboost-filesystem-dev libboost-program-options-dev libyaml-cpp-dev valgrind

- uses: actions/checkout@v4
Expand Down
28 changes: 17 additions & 11 deletions src/asm_unmarshal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,28 +87,20 @@ struct Unmarshaller {
explicit Unmarshaller(vector<vector<string>>& notes, const program_info& info) : notes{notes}, info{info} { note_next_pc(); }

auto getAluOp(size_t pc, ebpf_inst inst) -> std::variant<Bin::Op, Un::Op> {
// First handle instructions that support a non-zero offset.
switch (inst.opcode & INST_ALU_OP_MASK) {
case INST_ALU_OP_ADD: return Bin::Op::ADD;
case INST_ALU_OP_SUB: return Bin::Op::SUB;
case INST_ALU_OP_MUL: return Bin::Op::MUL;
case INST_ALU_OP_DIV:
switch (inst.offset) {
case 0: return Bin::Op::UDIV;
case 1: return Bin::Op::SDIV;
default: throw InvalidInstruction{pc, "invalid ALU op 0x30"};
}
case INST_ALU_OP_OR: return Bin::Op::OR;
case INST_ALU_OP_AND: return Bin::Op::AND;
case INST_ALU_OP_LSH: return Bin::Op::LSH;
case INST_ALU_OP_RSH: return Bin::Op::RSH;
case INST_ALU_OP_NEG: return Un::Op::NEG;
case INST_ALU_OP_MOD:
switch (inst.offset) {
case 0: return Bin::Op::UMOD;
case 1: return Bin::Op::SMOD;
default: throw InvalidInstruction{pc, "invalid ALU op 0x90"};
}
case INST_ALU_OP_XOR: return Bin::Op::XOR;
case INST_ALU_OP_MOV:
switch (inst.offset) {
case 0: return Bin::Op::MOV;
Expand All @@ -117,6 +109,22 @@ struct Unmarshaller {
case 32: return Bin::Op::MOVSX32;
default: throw InvalidInstruction{pc, "invalid ALU op 0xb0"};
}
}

// All the rest require a zero offset.
if (inst.offset != 0)
throw InvalidInstruction{pc, "nonzero offset for register alu op"};

switch (inst.opcode & INST_ALU_OP_MASK) {
case INST_ALU_OP_ADD: return Bin::Op::ADD;
case INST_ALU_OP_SUB: return Bin::Op::SUB;
case INST_ALU_OP_MUL: return Bin::Op::MUL;
case INST_ALU_OP_OR: return Bin::Op::OR;
case INST_ALU_OP_AND: return Bin::Op::AND;
case INST_ALU_OP_LSH: return Bin::Op::LSH;
case INST_ALU_OP_RSH: return Bin::Op::RSH;
case INST_ALU_OP_NEG: return Un::Op::NEG;
case INST_ALU_OP_XOR: return Bin::Op::XOR;
case INST_ALU_OP_ARSH:
if ((inst.opcode & INST_CLS_MASK) == INST_CLS_ALU)
note("arsh32 is not allowed");
Expand Down Expand Up @@ -150,8 +158,6 @@ struct Unmarshaller {
uint64_t zero_extend(int32_t imm) { return (uint64_t)(uint32_t)imm; }

auto getBinValue(pc_t pc, ebpf_inst inst) -> Value {
if (inst.offset != 0)
throw InvalidInstruction{pc, "nonzero offset for register alu op"};
if (inst.opcode & INST_SRC_REG) {
if (inst.imm != 0)
throw InvalidInstruction{pc, "nonzero imm for register alu op"};
Expand Down
25 changes: 20 additions & 5 deletions src/test/test_conformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ void test_conformance(std::string filename, bpf_conformance_test_result_t expect
std::filesystem::path plugin_path =
test_path.remove_filename().append("conformance_check" + extension.string()).string();
std::map<std::filesystem::path, std::tuple<bpf_conformance_test_result_t, std::string>> result =
bpf_conformance(test_files, plugin_path, {}, {}, {}, bpf_conformance_test_CPU_version_t::v3,
bpf_conformance(test_files, plugin_path, {}, {}, {}, bpf_conformance_test_CPU_version_t::v4,
bpf_conformance_list_instructions_t::LIST_INSTRUCTIONS_NONE, true);
for (auto file : test_files) {
auto& [file_result, reason] = result[file];
Expand All @@ -34,21 +34,21 @@ void test_conformance(std::string filename, bpf_conformance_test_result_t expect
// legitimate programs from being usable.
#define TEST_CONFORMANCE_VERIFICATION_FAILED(filename) \
TEST_CASE("conformance_check " filename, "[conformance]") { \
test_conformance(filename, bpf_conformance_test_result_t::TEST_RESULT_FAIL, "Verification failed"); \
test_conformance(filename, bpf_conformance_test_result_t::TEST_RESULT_ERROR, "Verification failed"); \
}

// Any tests that return top are safe, but are not as precise as they
// could be and so may prevent legitimate programs from being usable.
#define TEST_CONFORMANCE_TOP(filename) \
TEST_CASE("conformance_check " filename, "[conformance]") { \
test_conformance(filename, bpf_conformance_test_result_t::TEST_RESULT_FAIL, "Couldn't determine r0 value"); \
test_conformance(filename, bpf_conformance_test_result_t::TEST_RESULT_ERROR, "Couldn't determine r0 value"); \
}

// Any tests that return a range are safe, but are not as precise as they
// could be and so may prevent legitimate programs from being usable.
#define TEST_CONFORMANCE_RANGE(filename, range) \
TEST_CASE("conformance_check " filename, "[conformance]") { \
test_conformance(filename, bpf_conformance_test_result_t::TEST_RESULT_FAIL, "r0 value is range " range); \
test_conformance(filename, bpf_conformance_test_result_t::TEST_RESULT_ERROR, "r0 value is range " range); \
}

TEST_CONFORMANCE("add.data")
Expand All @@ -74,8 +74,9 @@ TEST_CONFORMANCE("be16.data")
TEST_CONFORMANCE("be32-high.data")
TEST_CONFORMANCE("be32.data")
TEST_CONFORMANCE("be64.data")
TEST_CONFORMANCE_VERIFICATION_FAILED("call_local.data")
TEST_CONFORMANCE("call_unwind_fail.data")
TEST_CONFORMANCE("div-by-zero-reg.data")
TEST_CONFORMANCE("div32-by-zero-reg.data")
TEST_CONFORMANCE("div32-high-divisor.data")
TEST_CONFORMANCE("div32-imm.data")
TEST_CONFORMANCE("div32-reg.data")
Expand Down Expand Up @@ -149,6 +150,14 @@ TEST_CONFORMANCE_VERIFICATION_FAILED("lock_and.data")
TEST_CONFORMANCE_VERIFICATION_FAILED("lock_and32.data")
TEST_CONFORMANCE_VERIFICATION_FAILED("lock_cmpxchg.data")
TEST_CONFORMANCE_VERIFICATION_FAILED("lock_cmpxchg32.data")
TEST_CONFORMANCE_VERIFICATION_FAILED("lock_fetch_add.data")
TEST_CONFORMANCE_VERIFICATION_FAILED("lock_fetch_add32.data")
TEST_CONFORMANCE_VERIFICATION_FAILED("lock_fetch_and.data")
TEST_CONFORMANCE_VERIFICATION_FAILED("lock_fetch_and32.data")
TEST_CONFORMANCE_VERIFICATION_FAILED("lock_fetch_or.data")
TEST_CONFORMANCE_VERIFICATION_FAILED("lock_fetch_or32.data")
TEST_CONFORMANCE_VERIFICATION_FAILED("lock_fetch_xor.data")
TEST_CONFORMANCE_VERIFICATION_FAILED("lock_fetch_xor32.data")
TEST_CONFORMANCE_VERIFICATION_FAILED("lock_or.data")
TEST_CONFORMANCE_VERIFICATION_FAILED("lock_or32.data")
TEST_CONFORMANCE_VERIFICATION_FAILED("lock_xchg.data")
Expand Down Expand Up @@ -195,6 +204,12 @@ TEST_CONFORMANCE("rsh64-imm-neg.data")
TEST_CONFORMANCE("rsh64-reg.data")
TEST_CONFORMANCE("rsh64-reg-high.data")
TEST_CONFORMANCE("rsh64-reg-neg.data")
TEST_CONFORMANCE("sdiv32-by-zero-reg.data")
TEST_CONFORMANCE("sdiv32-imm.data")
TEST_CONFORMANCE("sdiv32-reg.data")
TEST_CONFORMANCE("sdiv64-by-zero-reg.data")
TEST_CONFORMANCE("sdiv64-imm.data")
TEST_CONFORMANCE("sdiv64-reg.data")
TEST_CONFORMANCE("stack.data")
TEST_CONFORMANCE("stb.data")
TEST_CONFORMANCE("stdw.data")
Expand Down
Loading