Re: Thou shalt have no other gods before the ANSI C standard

From: Trevor L. Jackson, III (tlj3_at_comcast.net)
Date: 02/27/05


Date: Sun, 27 Feb 2005 14:33:06 -0500

David Wagner wrote:
> Trevor L. Jackson, III wrote:
>
>>We need to distinguish reads from writes. I'm assuming you are
>>interested in errant writes rather than errant reads. Are you aware of
>>any exploits based upon errant buffer reads?
>
>
> Nothing really significant. I know of a few examples of exploits based
> upon errant reads, but they were were "information disclosure" or "crash
> the machine" vulnerabilities, rather than something that immediately
> leads to the ability to take control of the machine. However, if your
> application isn't handling any important secrets, errant reads seem like
> a pretty low-priority item, I would think -- it seems to be pretty rare
> to encounter a buffer overrun that leads to some kind of serious information
> disclosure vulnerability but does not allow attackers to take control of
> the application.

Even if errant reads are a real problem, focusing on errant writes is
probably not a mistake.

>
>
>>There's a similar idiom, NCHECK, that can be used to control
>>the compilation of parallel implementations, one for production (speed,
>>size, etc) and one for correctness (big & slow). The NCHECK symbol is
>>most useful when it controls not only comparison of the results, but
>>also comparison of the process.
>
>
> I take it this is another way of describing 2-version programming,
> except done at a fine granularity, and with more detailed checking of the
> results of the computation? I think I understand what you are suggesting.
> Thanks.

I failed to mention that the NCHECK code should be written by someone
other than the author of the non-NCHECK code. This technique is decades
old, and is a far more useful technique than the eXtreme Programming
paradigm of writing the tests first. Making the code evaluate itself
yields a more effective coverage metric.

[snip]

>>Of course in the impersonal sense you are correct. But I'd like to hear
>>your description of what "good enough" would be. Can you articulate a
>>criteria than can be applied at the project level to determine whether
>>hat project is good enough or not?
>
>
> I'm not sure we know what would be "good enough". How could we tell?
> The only way I know to tell is to do a controlled experiment and measure.
> Until we can articulate some process, try that process out, and measure
> its effectiveness, I don't think we will be able to tell for sure
> whether that process will be adequate -- i.e., whether we will be able to
> (justifiably) count on that process to eliminate all buffer overruns.
> I have yet to see such evidence provided for any process currently known.

There is room for further discussion here. The topic would be absolute
value versus relaive value. The phrase "good enough" suggest that there
is an absolute value or critera that should be applied. That path leads
to the hopless goal of perfect software.

The alternative or relative or incremental value, such as disciplined
methodolgy or automated error checks is easier to envision, but does not
guarantee "enough" improvement to materially reduce the icidenc the of
exploits. After all, any given progam needs only one serious
vulnerability, so finding all but the last one does not increase the
effective security of the system. Also, along this path lies hype
because we still lack a metric for (in)security.

For me this is depends on the day of the year. On even days I'm an
absolutist, and on odd days a relativist. On Feb 29ths I curse Babbage,
Turing, and Djikstra. ;-)

>
>
>>OK, but it is necessary to know that there are no memory management
>>problems in order to know that there are no security holes? How could
>>any software ever be shipped under that constraint?
>
>
> It is necessary that there be no buffer overruns, if we want to know
> that there are no security holes. How could software be shipped under
> that constraint? One way is to use a memory-safe language.

The cost of that in complexity and performance is extremely high. Would
you write any of these in a memory-safe language?
- a file system
- heap manager
- swap manager
- page fault handler
- garbage collector
- device driver (e.g., SCSI-3 or ATi Rage Pro)
- network driver
- network stack
- network firewall
- or debugger

>
> Another way is to ship the software without knowing whether it is secure.
> This latter method seems to be very widely used. :-(
>
>
>>I disagree. While many people have underestimated or even deprecated
>>the attackers, I suspect that most people just didn't care. That's why
>>point #2 above is the second most important point. If you want securiry
>>and reliability you have to say so. And you have to say so early. And
>>you have to not flinch when you get the estimate of the time and money
>>it will really cost.
>
>
> That could well be. Sounds like a very credible hypothesis to me.
>
>
>>>Any? No, not all buffer overruns can be exploited to take control of
>>>the machine.
>>
>>OK, I lack the experience to be able to tell the difference. From your
>>endorsement of the total elimination policy I infer that you, with
>>substantially more experience, may not be able to describe the
>>difference either. Is that inference accurate?
>
>
> I don't trust myself to be able to reliably distinguish a non-exploitable
> buffer overrun from an exploitable buffer overrun. Often I can make
> a pretty good guess, but I've also been wrong too many times. I don't
> like taking that kind of risk. Given that, I think we're pretty much
> forced to say that any time you find a buffer overrun, you should treat
> it as a defect and fix it, even if you can't immediately identify any
> way to exploit it.

OK I accept your opinion. Are there any other kinds of defects that
have that property?

>
> A buffer overrun is an example where the program is doing something wrong
> and something that "violates the model". Putting an upper bound on exactly
> how much harm can be caused by that wrong is often hard to do, particularly
> since you cannot reason within the model (you can't assume, for instance,
> that "int x = 0; f(); return x;" returns 0).
>
>
>>If not, please elaborate on the characteristics that make bugs
>>exploitable. I ask because those characteristics may make exploitable
>>bugs easier to catch than all bugs in general.
>
>
> One of the characteristics that tends to make a buffer overrun exploitable
> is the ability to overwrite key portions of the address space: data
> structures that were only supposed to be maintained by the compiler
> (e.g., the return address or frame pointer on the stack, vtables in C++)
> or linker (e.g., the GOT) or libraries (e.g., private data structures
> maintained by malloc, such as the free list), data that the program relies
> upon for correct execution (e.g., function pointers, the place where
> the OS stores your uid, data that will later be used as an argument to
> a system call), and so on. It is hard to come up with an exhaustive list.

Your list is sufficient to trigger something like an "Aha!". Consider
that in any executable the examples you gave are examples of
non-application-accesible addresses. We can color them red. The set of
program-declared and system-supplied variables are the blue adresses.
In theory programs have access only to blue addresses. But proving that
a program stays within the blue zone is very difficult. Part of the
difficulty lies in the intermediate grey addresses which might or might
not be appropriate based on context.

The set of red locations can be increase by adding to your list. But
the key observation is that there is a set of addresses that no
application code should ever touch. That makes the analysis
conxext-free (in some sense). Ihe individual subsets of those red
addresses can be built on a system-by system or program-by-program
basis, mostly automatically (using the linker and a .map post processor).

Add to the above a form of automated analysis similar to interval
arithmetic as applied to program variables and you have the possibility
of a tool that could warn of constructs that have the potential of
interacting with red addresses.

I'd be interested in working on such a tool. It would be terribly slow,
but _you only have to run it once per module, component, or subsystem_.
  So it it takes an hour or a day to run who cares?

I think such a tool is within the current state of the art. If it
existed, would it be useful enough to spend the time to run it and
interpret the results (a list of software that has the capacity to write
to red addresses)?

/tj3



Relevant Pages

  • Re: Thou shalt have no other gods before the ANSI C standard
    ... >interested in errant writes rather than errant reads. ... leads to the ability to take control of the machine. ... buffer overrun from an exploitable buffer overrun. ... that processes a secret and that had a format string vulnerability. ...
    (sci.crypt)
  • Re: Language Features Id Like To See
    ... > '\0' to control the while loop. ... prior to the end of the buffer*. ... Can you say "buffer overrun"? ...
    (borland.public.delphi.non-technical)
  • Re: VFP8 Intellisense issue
    ... I would suspect that VFP crashes when evaluating the properties and methods ... and this list is control specific. ... > noticed a problem when testing this ActiveX control in Visual FoxPro 8 and ... > A buffer overrun has been detected which has corrupted the programs' ...
    (microsoft.public.fox.programmer.exchange)
  • Re: Baud Rate In Serial Comm, Buffer overrun
    ... We are having software flow control in our protocol. ... > cause buffer overrun? ... No. That's the whole point of flow control - to prevent overruns. ...
    (microsoft.public.dotnet.framework.compactframework)