August 28, 2012

Read-Before-Write: An Example for False Positive Detection

During the Bank Holiday weekend I was working on testing and stabilizing one of my Windbg extension commands which detects read-before-write bugs. According to the test result some detection appeared to be false positive, and in this post I discuss a case that is interesting to me.

Instead of analyzing the test result in the Windbg log file I decided to do it in IDA. I took the errors from the Windbg log and simply highlighted the instructions causing read-before-write in IDA. The highlight idea was borrowed from team ZDI (thanks).

Below is the code snippet wherein an error detected that appears to be a false positive.
There are two questions need answering:
  • Why is it a false positive detection?
  • Why the detection was mistakenly issued?
Answering why is it a false positive question is very straightforward. void* is pushed onto the stack that is a parameter for delete(). delete() uses cdecl calling convention so it doesn't clean-up void* on the stack but pop ecx in the red line does. pop ecx reads void*. The memory address void* read from has been written by push instruction. So the red line cannot be a read-before-write access.

Answering the second question: why the detection was mistakenly issued is a bit more complex and requires knowledge how my Windbg plugin extension works - read the principles here if you like. When push [ebp+var_78] is executed it does the followings. First, it reads var_78 local variable, then it writes (pushes) var_78 onto the stack. The address of the read access and the address of the write access are both stack memory addresses. In this example, the protection flags were set on stack memory region by the Windbg command extension. As mentioned above when push is executed read access occurs first. We handle this by removing the protection flags and let the push execute. Since the memory protection flags removed push didn't have a chance to cause a write access exception, therefore the address is not added to the list of written addresses. Later on the execution, pop causes a read access violation and the plugin checks if the address has been written. Since the address is not on the list of written addresses it issues a read-before-write notification, mistakenly. The answer in short is because we didn't catch the write access of push.

The current implementation wrongly assumes that an instruction could cause either read or write access. As seen above, in fact, an instruction could cause both read and write accesses. A possible fix would be to deal with the situation of multiple accesses. However, I don't think it's a priority to implement at the moment because it's possible to do a post process on the output log to mark or to remove these situations when showed in IDA.
  This blog is written and maintained by Attila Suszter. Read in Feed Reader.