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

Unhandled Bailout During AbstractInstructi #6810

Closed
IGI-111 opened this issue Jan 6, 2025 · 0 comments · Fixed by #6834
Closed

Unhandled Bailout During AbstractInstructi #6810

IGI-111 opened this issue Jan 6, 2025 · 0 comments · Fixed by #6834
Assignees
Labels
bug Something isn't working compiler: codegen Everything to do with IR->ASM, register allocation, etc. P: high Should be looked at if there are no critical issues left team:compiler Compiler Team

Comments

@IGI-111
Copy link
Contributor

IGI-111 commented Jan 6, 2025

From https://reports.immunefi.com/fuel-network-or-attackathon/attackathon-_-fuel-network-32438-smart-contract-low-unhandled-bailout-during-abstractinstructionset

const_indexing_aggregates_function() process VirtualOp::LW without handling the case if the offset in addr_reg is not aligned to 8, resulting in the old constant being used and leading to incorrect program behavior.

Vulnerability Details

While processing a VirtualOp::LW with non-aligned address offset, const_indexing_aggregates_function() does not clear register information in reg_contents and setup a new definition with record_new_def(). This means the old state of the register stored in reg_contents will still be used, causing incorrect value tracking after the LW instruction. The incorrect tracking may then cause incorrect immediate replacement in other instructions.

VirtualOp::LW(dest, addr_reg, imm) => match reg_contents.get(addr_reg) {
    Some(RegContents::BaseOffset(base_reg, offset))
        if get_def_version(&latest_version, &base_reg.reg) == base_reg.ver
            && ((offset / 8) + imm.value as u64)
                < compiler_constants::TWELVE_BITS =>
    {
        // bail if LW cannot read where this memory is
        if offset % 8 == 0 {
            let new_imm = VirtualImmediate12::new_unchecked(
                (offset / 8) + imm.value as u64,
                "Immediate offset too big for LW",
            );
            let new_lw =
                VirtualOp::LW(dest.clone(), base_reg.reg.clone(), new_imm);
            // The register defined is no more useful for us. Forget anything from its past.
            reg_contents.remove(dest);
            record_new_def(&mut latest_version, dest);
            // Replace the LW with a new one in-place.
            *op = new_lw;
        }
    }
    _ => {
        reg_contents.remove(dest);
        record_new_def(&mut latest_version, dest);
    }
},

Impact Details

As usual, it is hard to come up with a precise impact estimation of incorrect code generation because it depends on what code the user writes. The best case scenario would be contracts that run into those bugs getting bricked, and the worst case scenario would be that incorrect program behaviors lead to loss of funds.

References

Proof of concept

This test would fail because addi a a i15 incorrectly uses the reg values before lw a a i0

#[test]
fn incorrect_bailout() -> u64 {
    let a = asm(a, b) {
        movi a i32;		// a = 32
        aloc a;			// hp = buf[0;32]

        movi a i1;		// a = 1
        addi b hp i23;	// b = &buf[23]
        sb b a i0;		// buf[23] = a = 1
        addi a hp i9;	// a = &buf[9]
        addi b hp i1;	// b = &buf[1]
        sb b a i7;		// buf[1:9] = a = &buf[9] avoid using sw, which is buggy itself
        srli a a i8;
        sb b a i6;
        srli a a i8;
        sb b a i5;
        srli a a i8;
        sb b a i4;
        srli a a i8;
        sb b a i3;
        srli a a i8;
        sb b a i2;
        srli a a i8;
        sb b a i1;
        srli a a i8;
        sb b a i0;

        addi a hp i1;	// a = &buf[1]
        lw a a i0;		// a = buf[1:9] = &buf[9]
        addi a a i15;	// expected : a = &buf[24]              real : a = &buf[16]
        lw a a i0;		// expected : a = buf[24:32] = 0        real : a = bug[16:24] = 1
        a: u64
    };
    assert(a == 0);
    a
}
@IGI-111 IGI-111 added bug Something isn't working compiler: codegen Everything to do with IR->ASM, register allocation, etc. P: high Should be looked at if there are no critical issues left labels Jan 6, 2025
@IGI-111 IGI-111 added the team:compiler Compiler Team label Feb 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working compiler: codegen Everything to do with IR->ASM, register allocation, etc. P: high Should be looked at if there are no critical issues left team:compiler Compiler Team
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants