You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 5 Next »

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 do 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

If the attacker module can be introduced into the system so that the linker chooses it in preference to the "proper" class defined in Module.cpp (which can usually be achieved by putting the attacker module before the innocuous module in the list of modules to be linked, or in the shared library path) then it is possible to corrupt the virtual function table.

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

  • Quinlan 06 Quinlan, Dan; et al. "Support for Whole-Program Analysis and the Verification of the One-Definition Rule in C++"
  • No labels