code-423n4 / 2024-03-phala-network-findings

0 stars 0 forks source link

Unbounded Decoding In extension::get_side_effects can lead to stack overflow #25

Open c4-bot-5 opened 3 months ago

c4-bot-5 commented 3 months ago

Lines of code

https://github.com/code-423n4/2024-03-phala-network/blob/a01ffbe992560d8d0f17deadfb9b9a2bed38377e/phala-blockchain/crates/pink/runtime/src/runtime/extension.rs#L61

Vulnerability details

Impact

function get_side_effects() uses unbounded decoding of pink events within the ContractEvent::ContractEmitted match arm. Incase, Pink events are highly nested, the decoding process can recursively consume stack space until it exhausts the available stack, resulting in a stack overflow.

Proof of Concept

vulnerable part of the function :

if event.topics.len() == 1
    && event.topics[0].0 == pink::PinkEvent::event_topic()
{   
@>    match pink::PinkEvent::decode(&mut &data[..]) {
        Ok(event) => {
            pink_events.push((address.clone(), event.clone()));
            is_private_event = event.is_private();
        }
        Err(_) => {
            error!("Contract emitted an invalid pink event");
        }
    }
}

The problem is when function attempts to decode Pink events from the data, it does so without any limit on the depth of the decoding process. This means that if the Pink events within the data are structured in a highly nested manneer the decoding process will recursively traverse through each nested level.

Step by Step details how it can happen

Tools Used

Manual Review

Recommended Mitigation Steps

A recommended solutions is to set a depth limit for decoding pink events. decode_with_depth_limit method should be used instead of decode to ensure the decoding process doesn't exceed a certain depth and prevent stack overflow. Mitigationn can be done as follows :

if event.topics.len() == 1
    && event.topics[0].0 == pink::PinkEvent::event_topic()
{   
-    match pink::PinkEvent::decode(&mut &data[..]) {
+    match pink::PinkEvent::decode_with_depth_limit(&mut &data[..], MAX_DEPTH) {
        Ok(event) => {
            pink_events.push((address.clone(), event.clone()));
            is_private_event = event.is_private();
        }
        Err(_) => {
            error!("Contract emitted an invalid pink event");
        }
    }
}

would look upon judges and sponsor to Adjust the MAX_DEPTH constant based on complexity of Pink events.

Reference

Unbounded Decoding Vulnerability

Assessed type

Under/Overflow

c4-pre-sort commented 3 months ago

141345 marked the issue as insufficient quality report

141345 commented 3 months ago

PinkEvent is not that complicated

c4-judge commented 3 months ago

OpenCoreCH changed the severity to QA (Quality Assurance)

OpenCoreCH commented 3 months ago

Potential QA improvement, but no reasoning / explicit PinkEvent given how this can lead to problems in the codebase

c4-judge commented 3 months ago

OpenCoreCH marked the issue as grade-b