Does it make sense to have DFI and CFI?
Does DFI imply CFI?
Yes, because hijacking the control flow means modifying a control-data and DFI ensures the integrity of data whether it is used for control or not.
Can I still use exploits that alter the control flow graph (CFG) if I have only DFI?
No, it will be detected.
DFI enforces a policy on the data-flow observed at runtime. It ensures that a program must follow a data-flow graph generated via a static analysis at compile time. An instrumentation pass on the program adds checks before each read instruction to ensure that they do not read a corrupted data.
The static analysis uses a reaching definition analysis. It is a data-flow analysis that gives us for each read instruction reading a variable, a set of instructions that could have last defined this variable.
For each read instruction the analysis is performed, and each write instruction that defines a variable is assigned an unique identifier.
Then, an instrumentation pass adds checks before each write instruction to update a table mapping an address being written to and the last identifier having written a value at that address.
In addition, the instrumentation adds checks before each read instruction. It fetches the identifier mapped with the address it is reading the value from, and it ensures that the identifier is in the set of reaching definitions found thanks to the static analysis.
For instance, if an attacker manages to corrupt the return address on the stack, the write instruction used to corrupt it updated the table with its identifier. Hence, the instrumentation just before the
ret instruction will notice the corruption, because the last identifier used to modify the return address is not in the set of allowed identifiers.
That's why DFI prevents both non-control data attacks and control-data attacks. It also explains why it does not make sense to use both, because it would be redundant.