I've read that code is formally verified by constructing a mathematical model of the code, and then a formal proof is provided to demonstrate that this model meets certain requirements. How does formal verification ensure that the resulting code is free of any vulnerability?
|
It doesn't guarantee that the code is free of vulnerability. However, if verification is used appropriately, it can increase assurance (confidence) that the application is secure. Speaking from a very broad perspective, there are two aspects of this problem:
Sometimes people focus only on verification, but both matter. In your situation, if the specification incorporates all relevant security requirements, and if the mathematical model correctly corresponds to the code, and if the verification is done appropriately and is successful, then we may have a basis for significantly increased assurance that the system will meet our security requirements. In the best case, verification can be a powerful tool to help assure security, one of the most powerful that we have. However, as with anything, it is possible to misuse the technology or get a false sense of security if it is not used appropriately. One of the most common failure modes is that the verification process does not verify all relevant security requirements (some are overlooked or omitted). To say much more might require delving into the details of the system, the security requirements, and the nature of the verification that was done, but hopefully this gives you an overview. |
||||
|
|
|
Formal verification does not guarantee a secure system. Nothing guarantees a secure system. What formal verification can do is provide a very high assurance that some parts of the system are secure. Formal verification gives a mathematical proof that under certain assumptions, a model of the system has certain properties. Thus, if part of the system has been formally verified, there still remains several conditions for the system to be secure:
The extent of the formal verification can vary a lot. For example, buffer overflows — a common kind of vulnerability — can be spotted pretty easily: most languages that are higher-level than C or C++ guarantee the absence of buffer overflows in the compiled program. It can nonetheless happen that the compiler allows broken code to get through — while compiler bugs are a lot rarer than program bugs, they are not impossible. Buffer overflows are only one kind, however; most systems' security depend on far more than knowing that there are no buffer overflows. (Related reading: Why don't computers check whether there are memory contents in some memory space?) To illustrate the limitations above, let me take a concrete example. Some smart cards run a Java Card virtual machine, and execute only bytecode that has been verified. The bytecode verifier, in principle, guarantees that the code cannot peek or poke outside its alloted memory space. This avoids some vulnerabilities but not all:
In a high-assurance system, formal verification can help in two ways:
The Common Criteria for security evaluations define several assurance levels. Only the highest assurance level (EAL7) requires formal verification. This is not the only requirement: formal verification does not preclude the evaluation of other aspects of the system, including documentation, penetration testing, etc. |
|||
|
|
|
Verification checks to see if the system has a specified property. Properties maybe expressed in various notation and logics. Specifying these properties is difficult. So if a designer can express their idea of security in a formal notation suitable for verification, and the software is proven to satisfy the property, then yes it is secure. In real life, its almost an impossible goal to verify non-trivial properties on real software running on general purpose hardware |
|||
|
|
|
Any vulnerability is too broad a term, since formal verification (in effect automated proof that an algorithm/system possesses specific properties) is geared toward specific threats: sensitive data leaking out, external information percolating through the defenses, memory leaks, allocation blunders, stack overflows etc. For some preview of current work in this regard you can e.g. visit Software Engineering Institute at Carnegie-Mellon Uni. |
|||
|
|
|
Formal verification really only works in extremely constrained cases where a system can be modeled as a series of transforms with clearly defined domains, ranges, and clearly understood rules that define the behavior of a function - in many cases this means that you're dealing with a system that is the software realization of a mathematical model, or that it's (relatively :-) ) easy to derive a model from the systems behavior (digital circuits of significantly less complexity than a general purpose CPU) I worked in some forerunners to this in the '80s, where the effort was in generating 'provably correct code' - One system I recall was named Adele, and operated on programs written in (uggh) Ada. Anecdotally, we used to joke that using Adele meant that it took 10 times as long to write, it ran 10 times more slowly, and it only crashed 10% as much - You might want to look at Bertrand Meyer's writings on Eiffel, he put significant thought and effort into how a language could provide internal verification checks via preconditions, postconditions, invariants, and a bunch of other stuff I have since forgotten..... |
|||||
|
|
Formal verification checks only conformance of coding to given specifications. If a specification itself is improper/incorrect, then an eventual verification is evidently of no value. For informations on formal verification see e.g. http://en.wikipedia.org/wiki/Formal_verification and http://en.wikipedia.org/wiki/Isabelle_%28proof_assistant%29 |
|||
|
|
|
Any model couldn't guarantee a secure, error free code. Only continuous testing can give you temporary security. Finishing a code doesn't mean that it will remain secure, so further continuous testing against new vulnerabilities required. |
|||||||||||||
|

