diff --git a/doc/bytecode.md b/doc/bytecode.md index 0730d9f0..8ef14afb 100644 --- a/doc/bytecode.md +++ b/doc/bytecode.md @@ -293,7 +293,7 @@ Verification ------------ ### all -- The bytecode must be divisible by the instruction slot size (64 bits / 8 bytes) +- The length of the bytecode must be evenly divisible by the instruction slot size (64 bits or 8 bytes) - The bytecode must contain at least one instruction - `lddw` (opcode `0x18`) is two slots long and must be followed by a slot with opcode `0x00` - Immediate values of quotient and remainder instructions must be imm ≠ 0 @@ -310,6 +310,7 @@ Verification ### until v2 - Opcodes from the product / quotient / remainder instruction class are forbiden - `le` is allowed +- `hor64` is forbidden - `callx` source register is encoded in the imm field - The targets of `call` instructions is checked at runtime not verification time - The offset of jump instructions must be limited to the range of the bytecode diff --git a/tests/verifier.rs b/tests/verifier.rs index 5fa54218..24df55d1 100644 --- a/tests/verifier.rs +++ b/tests/verifier.rs @@ -138,6 +138,7 @@ fn test_verifier_err_endian_size() { #[should_panic(expected = "IncompleteLDDW(0)")] fn test_verifier_err_incomplete_lddw() { // Note: ubpf has test-err-incomplete-lddw2, which is the same + // lddw r0, 0x55667788 let prog = &[ 0x18, 0x00, 0x00, 0x00, 0x88, 0x77, 0x66, 0x55, // 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // @@ -152,6 +153,28 @@ fn test_verifier_err_incomplete_lddw() { executable.verify::().unwrap(); } +#[test] +#[should_panic(expected = "LDDWCannotBeLast")] +fn test_verifier_err_lddw_cannot_be_last() { + for highest_sbpf_version in [SBPFVersion::V1, SBPFVersion::V2] { + let prog = &[0x18, 0x00, 0x00, 0x00, 0x88, 0x77, 0x66, 0x55]; + let executable = Executable::::from_text_bytes( + prog, + Arc::new(BuiltinProgram::new_loader( + Config { + enabled_sbpf_versions: SBPFVersion::V1..=highest_sbpf_version, + ..Config::default() + }, + FunctionRegistry::default(), + )), + highest_sbpf_version, + FunctionRegistry::default(), + ) + .unwrap(); + executable.verify::().unwrap(); + } +} + #[test] fn test_verifier_err_invalid_reg_dst() { // r11 is disabled when sbpf_version.dynamic_stack_frames()=false, and only sub and add are @@ -245,6 +268,28 @@ fn test_verifier_err_call_lddw() { executable.verify::().unwrap(); } +#[test] +#[should_panic(expected = "InvalidRegister(0)")] +fn test_verifier_err_callx_cannot_use_r10() { + for highest_sbpf_version in [SBPFVersion::V1, SBPFVersion::V2] { + let executable = assemble::( + " + callx r10 + exit + ", + Arc::new(BuiltinProgram::new_loader( + Config { + enabled_sbpf_versions: SBPFVersion::V1..=highest_sbpf_version, + ..Config::default() + }, + FunctionRegistry::default(), + )), + ) + .unwrap(); + executable.verify::().unwrap(); + } +} + #[test] #[should_panic(expected = "InvalidFunction(0)")] fn test_verifier_err_function_fallthrough() {