The C++ Standard [ISO/IEC 14882-2003] Section 3.2 "One definition rule" says, in paragraph 3: "Every program shall contain exactly one definition of every non-inline function or object that is used in that program; no diagnostic required." Although it is possible to check that the ODR is complied with (see [[Quinlan 06]]) compilers to not, at present, enforce the rule or even issue a diagnostic. As the paper by Quinlan, et al. shows, failing to enforce the ODR enables a virtual function pointer attack, known as the VPTR exploit.
Non-Compliant Code Example
This example is taken from the paper by Quinlan, et al. referenced above.
Base abstract class (Base.h
)
class Base { public: virtual ~Base () {} virtual void run () = 0;
Innocuous module (Module.cpp
)
# include "Base.h" class Derived: public Base { public: Derived () {buf_[0] = 'a';} void run () {buf_[0] = 'z';} char buf_[1]; }; void runModule () { Derived a,b; Base *pa = &a, *pb = &b; pb->run (); // Expect b.buf_[0] == 'z' pa->run (); // Expect a.buf_[0] == 'z' }
Malicious module (Attacker.cpp
)
# include "Base.h" class Attacker: public Base { public: void run () { // vtable is overwritten // do malicious things here ... } } class Derived: public Base { // Class violating ODR public: void run () { buf_[0] = 'z'; // Looks normal, but ... Attacker x; // Instantiate to get a vtable to inject *((unsigned *)(buf_ = 12)) = *((const unsigned *)(&x)): } char buf_[16]; // Buffer used to overwrite vtable }; Derived d; // Instantiate to get malicious Derived
Compliant Solution
The solution is to not allow more than one definition of a non-inline function or object to be admitted into a system.
Priority: P3 Level: L3
Failing to obey the ODR allows the VPTR exploit, which could lead to an attacker being able to execute arbitrary code.
Component |
Value |
---|---|
Severity |
3 (high) |
Likelihood |
1 (unlikely) |
Remediation cost |
1 (high) |
References
- ISO/IEC 14882-2003 Section 3.2 One definition rule
- Quinlan 06 Quinlan, Dan; et al. "Support for Whole-Program Analysis and the Verification of the One-Definition Rule in C++"