Here is some new bad news, and i mean really bad news

A memory access checker like "valgrind" would have found this, but only during it being exploited. the problem is that noone tested it with bad data.

--
umop apisdn 


--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
Reply to
Jasen Betts
Loading thread data ...

Unfortunately I have to agree with you, but it isn't strictly down either to programmers or computer scientists it is because businesses prefer to ship first and be damned later.

There has been a lot of progress in static analysis to catch at compile time the sorts of errors that humans are likely to make and options to defend at runtime against likely exploits. However, the tools needed are not easily available for teaching and are only available overpriced in the environments least likely to use them - business and enterprise!

It is possible to design languages that are fully range checked and not beyond the wit of man to make it so that a memory fetch from a location that has never previously been written to and is not declared as memory mapped IO will generate a page fault. High Integrity Ada and Modula2 lend themselves to this sort of approach when you want security.

C pointers are not *necessarily* evil but you do have to be defensive in their use and very untrusting of external data sources that may masquerade as something else or fib about their true length.

The C construct

while (*d++=*s++);

Has a lot to answer for.

Nothing compels Java to be interpreted. It could be compiled to native code with some advantage. Compilers have come a long way.

OS/2 actually did keep data and code entirely separate. The shift back to a single flat memory space containing everything came later.

On balance I think I prefer it to the flawed Intel noexecute bit bodge.

--
Regards, 
Martin Brown
Reply to
Martin Brown

In DOS it's a good way to kill trees.

Just use the mem* functions instead of the str* functions if you want known-length strings.

yeah, but doesn't it put some stupid arbitrary limit on string length?

--
umop apisdn
Reply to
Jasen Betts

CS departments have made a lot of progress in this field for high reliability code. It is *INDUSTRY* that isn't listening to them.

--
Regards, 
Martin Brown
Reply to
Martin Brown

Does you no good in a language where the default is a null terminated string. It is always possible for a malevolent external data source to send a string that will overwrite the end of any finite buffer.

The problem is that C programmers are *taught* to write in a style that is concise cryptic but dangerous when abused by malevolent source data

while (*d++=*s++);

It wouldn't matter in a world where the data sources could be trusted.

You read what you think you have written. The only way to find certain types of fault is to explain it to another person. Verbalising it uses other brain pathways and allows another viewpoint. The chances are that a second pair of eyes will not miss the same error as the author.

It isn't uncommon when style checking large ordinary documents like reports to find "the the " or "a a " occurring spontaneously. Similar unconscious repetition errors in software can be much more serious.

--
Regards, 
Martin Brown
Reply to
Martin Brown

Tinfoil hat mode:

And don't forget that spy agencies don't want people writing secure code. The obstruction I've experienced over the last several years is almost certainly partially related to this fact. My own secure application framework is now more than six years behind schedule, and that is no accident even if you discount the 'TLA sabotaging good code theory'.

Regards,

Uncle Steve

--
Always talking, lurking behind my back; surveying a place to jam the 
knife in.  Why don't you all fuck off and learn how to become 
productive humans?  Too lazy.
Reply to
Uncle Steve

That's true to a fair extent, though less so now than it used to be - people are more aware of the problem, and use safer alternative functions.

However, the bug in heartbleed has nothing to do with this - either in terms of "C culture" or programming language.

I don't disagree that C programs often have security risks that are easy to make due to C's lack of resource management and proper strings - but I strongly disagree with the implication that other languages are /safe/ or /secure/ solely because they don't have these issues.

That solves /some/ security issues - but there is nothing in C that stops you doing this if you understand how to program secure software. But it is a serious mistake to think that such issues are actually the most important factors in secure programming - or that other languages with garbage collection, no pointers, and safe arrays are actually more secure. Insecure software is just as common with Python, PHP, Perl, and other higher level languages.

You are taking one class of errors which occur more often in C (because checks have to be made manually in the code, rather than automatically in the language) and assuming this is a major security issue. But that is simply not the case. Buffer overflows and similar errors usually result in crashes - such programs are therefore susceptible to denial-of-service attacks, but they seldom (but not never, of course) lead to information leaks or privilege escalation. And the alternative

- using a language with managed buffers and runtime errors - will give the same effect when the unexpected runtime error leads the program to end.

Writing secure software is about thinking securely - the language of implementation is a minor issue, partly because the coding itself should be a small part of the total workload.

The heartbleed bug did not come from an issue in the implementation language - it came from not /thinking/ enough about where information came from. Arguably it came from poor design of the heartbeat part of the protocol - it is never a good idea for the same information (the length of the test data) to be included twice in the telegram, as it can lead to confusion and mistakes.

Compilers do not and should not manipulate the MMU.

I think what you mean to say is that stacks and data segments should be marked non-executable. This is true in general, but not always - there are some types of code feature that require run-time generation of code (such as "trampolines" on the stack) to work efficiently. If you can live without such features, then stacks and data segments can be marked non-executable - and that is typically done on most systems. (It is the OS that controls the executability of memory segments, not the compiler.)

Note that most high-level languages, with the sort of run-time control and limitations that you are advocating, are byte-compiled and run by a virtual machine. In a very real sense, the data section of the VM contains the program they are executing.

Again, you are showing that you have very little idea of the issues involved, and are merely repeating the popular myths. And one of these myths is that we have so much computing horsepower that the efficiency of the programs doesn't matter. Tell that to people running farms of servers, and the people paying for the electricity.

Python, and languages like it, protect against /some/ kinds of errors that are common in C. But they are far from the sort of magic bullet you seem to believe in - they are just a tool. The ease and speed of development with Python can also lead to a quick-and-dirty attitude to development where proof-of-concept and prototype code ends up shipping - there are pros and cons to any choice of language.

It is up to programmers and program designers to understand secure programming, and to code with an appropriately paranoid mindset, regardless of the language.

Again, Ada is just an alternative tool, with its pros and cons.

For the record, I use Python for most PC programming - because it makes it easier and faster to deal with strings and with more complex data structures, and because I often find its interactivity useful in development. I use C for almost all my embedded programming - and to my knowledge, I have never written C code with a buffer overflow.

Reply to
David Brown

It was not an issue with buffer overflows, the problem was that the programmer accepted the incoming data at face value. This would have caused trouble regardless of the language used, and it would have been avoided if the programmer had followed good secure development practices.

The exact effects of the bug might have varied depending on the language

- a language with enough run-time checks could have thrown an exception (leading to a crash, as the exception would be unexpected) rather than returning other data.

MS has always had a habit of trusting too much in their coding, and not paying attention to security. The same is still true of their code today, though they are not as bad as they were. Such habits and poor development culture are independent of the language used.

No, that is a complete misunderstanding of the /real/ problem.

Language choice can prevent /some/ mistakes, but certainly not all. And good use of tools can prevent many others - if the openssl developers had tested the code using appropriate C debugging tools, they would have spotted the error as quickly as with a managed programming language. What was missing is that no one tried sending malicious packets to the code - no one thought about the possible security hole, no one noticed that the code trusted external data, no one tested it. The implementation language was irrelevant.

There is a strong correlation here. You mentioned Ada in another post - if I were hiring someone to write secure or reliable software and I had a candidate that knew Ada and a candidate that knew Python, I'd pick the Ada guy every time. If I wanted quickly developed code for use in a closed network, I'd pick the Python guy.

Ada was not responsible - it was a design error in the software, and could have occurred in any language. But this demonstrates the point that it is not the implementation language that is critical, it is the software design and the development and testing process that is vital.

Reply to
David Brown

On this point, I fully agree - the protocol was the first problem, and the implementation was the secondary problem.

malloc must be handled appropriately to be safe. But the same applies to other forms of dynamic memory allocation - in reliable systems, all forms of dynamic memory should be minimised or avoided where possible.

Reply to
David Brown

The key to secure programming - regardless of language - is to take your untrusted data and sanitise and check it. /Then/ your data is trusted, and you can take advantage of that.

Reply to
David Brown

Unfortunately we both know that that doesn't happen in the real world. (at least it fails to occur in far too many software development shops)

--
Regards, 
Martin Brown
Reply to
Martin Brown

But that happens all too often.

But it was the opposite to the usual overwrite the end and execute attack. This one wrote a tiny amount to the start and then grabbed a huge chunk back to peek into memory it was never entitled to see.

Not quite. An MS implementation of JPEG had always contained a flaw that would permit a program that lied about the true length of a particular marker to overwrite code. Once you can do that it is just a case of working out how to execute the inserted hostile code.

It is a bit of an embarrassment for the open source claims of many eyes checking finding all possible bugs before they can do any harm. Wisdom of crowds is all very well but it cuts both ways and the bad guys might very well be more strongly motivated to find any vulnerabilities first.

Removing pointers entirely is probably too restrictive. Requiring that pointers to objects must check that the object they are pointing at is genuine would go a long way to preventing these problems.

Well it is sort of true. If you try juggling bean bags the worst that can happen is you drop one on the floor whereas if you try juggling with petrol driven chain saws things can get very messy indeed.

You clearly need to be a much better juggler to survive in the latter case but I would hardly recommend it!

Not true. The hardware guys had improved the external solid fuel boosters on Ariane 5 to produce an acceleration and top speed that was well beyond what the software had been specified to handle for Ariane 4. Unfortunately no one spotted that this would lead to a runtime numeric overflow on the faster takeoff with the improved SRBs.

formatting link

Is a reasonable description. It would not have mattered what language the code had been written in a floating point to 16 bit integer conversion would have generated an exception.

It added insult to injury that the data had no meaning once the vehicle had left the launch pad but *engineers* had decided to leave it running for 40s into the launch. Bad design decision to allow any unnecessary processes to run after they are no longer needed.

I like the one with the military aircraft that allowed you to retract the undercarriage when it was still on the ground and the apochryphal one that flipped over when it crossed the equator.

Gunnery table compensation for coriolis forces in artillery were still incorrect in NATO weapons as recently as the Falklands conflict. And famously the Type 42 destroyer HMS Sheffield ADACS thought that the Super Etenard launched Exocet missile was friendly (ie not Russian).

The trouble with a fence post error in a binary logic 0/1 situation is that the result is always the opposite of what you intended.

A nasty example of what happens when the wrong sort of engineers get involved in design decisions. A mechanical engineer once managed to get the handedness of a press to break emergency stop switch reversed to a press to make emergency stop switch with a relay somewhere else.

A faulty wiring harness damn near killed somebody because pressing the emergency stop which was no longer properly connected did nothing!

As a software engineer I insist on hardware interlocks on anything that poses a lethal hazard like EHT, high power RF or hazardous mechanical parts. It might be my hand that is in the way when the software fails.

Most entertaining software failure I ever saw was on an embedded TI9900 where all registers are memory mapped. Unfortunately after a system glitch the registers *including* the program counter were in ROM!

I didn't appreciate quite how good it was at context switching until later when we implemented the same sort of system on a Motorola 68k.

--
Regards, 
Martin Brown
Reply to
Martin Brown

That works fine if you put a sentinel null in the right place first. The idea of widely-used cryptographic software being put out there without a zillion unit- and regression-tests is really scary.

Cheers

Phil Hobbs

--
Dr Philip C D Hobbs 
Principal Consultant 
ElectroOptical Innovations LLC 
Optics, Electro-optics, Photonics, Analog Electronics 

160 North State Road #203 
Briarcliff Manor NY 10510 

hobbs at electrooptical dot net 
http://electrooptical.net
Reply to
Phil Hobbs

That's another part of the c culture: hack fast, don't review, and use some automated tool to find your coding errors.

--

John Larkin                  Highland Technology Inc 
www.highlandtechnology.com   jlarkin at highlandtechnology dot com    

Precision electronic instrumentation
Reply to
John Larkin

But if s is longer than d then you have corrupted one byte in the source string which may also have consequences.

Agreed. It isn't like financial institutions are naive practitioners.

Particularly odd that no-one ran any deep static analysis tools against the code base that might have spotted these sorts of vulnerablities. This was public code used unchecked in a critical security setting.

--
Regards, 
Martin Brown
Reply to
Martin Brown

Disagree. A language with indexed arrays and formal, controlled strings can have hard bounds checking. A pointer-oriented language, with null-terminated strings, can't.

Disagree again. There are languages where that sort of error couldn't happen.

And languages that don't oblige days of testing to stress a few lines of code.

Buffer overruns have been a major source of security lapses. A language that prevented them would, well, prevent them.

--

John Larkin                  Highland Technology Inc 
www.highlandtechnology.com   jlarkin at highlandtechnology dot com    

Precision electronic instrumentation
Reply to
John Larkin

There is a method that works quite well in order to keep trusted and untrusted data separate - the Hungarian notation. Simonyi (the Hungarian in question, working for MS) first used it to make distinctions about data that could not easily be checked and enforced by the compiler - in particular, incoming data strings would have a "us" prefix for "unsafe string" and sanitised versions would get the prefix "ss" for "safe string". If you stick rigidly to this convention, you will not mix up your safe and unsafe data. This "Apps Hungarian" notation is independent of programming language.

Unfortunately, some halfwit (also at MS) thought "Hungarian notation" meant prefixing names in C with letters indicating the type - so-called "Systems Hungarian" which just makes code a mess, makes it easy to be inconsistent, adds little information that is not already easily available to the compiler and IDE, and means you can't use "Apps Hungarian" to improve code safety. It's a fine example of snatching defeat from the jaws of victory - and of MS having a strong group of theoretical computer scientists with no communication with or influence over the mass of numpties doing their real coding.

There are, of course, many other ways to ensure that your untrusted data does not mix with the trusted data, and there are ways that can be enforced by a C compiler (or at least by additional checking tools). But it has to be part of the design process, and has to be implemented consistently.

Reply to
David Brown

You take the sentinel back out when you're done. I'm not defending that as a universal practice, especially when things like memcpy exist that are more efficient still, but it does save a loop counter increment and test, at the cost of a single local variable to store the previous value of the sentinel.

The main issue is in multithreaded code, where some other thread may be wanting to read s during the time you've got the sentinel in there. It also isn't async-safe and all that.

But the larger issue IMO is the lack of unit testing, and the unwarranted confidence in the "all bugs are shallow in the bazaar" mantra, which has repeatedly been shown to be ludicrously false.

Yup. What I'd be very interested to hear from anyone knowledgeable about the process is whether that's SOP or an outlier. And of course money may have changed hands, as with those schlemiels at RSA.

Cheers

Phil Hobbs

--
Dr Philip C D Hobbs 
Principal Consultant 
ElectroOptical Innovations LLC 
Optics, Electro-optics, Photonics, Analog Electronics 

160 North State Road #203 
Briarcliff Manor NY 10510 

hobbs at electrooptical dot net 
http://electrooptical.net
Reply to
Phil Hobbs

The alternative, which is used for most non-C coding, is even worse - hack fast, don't review, and don't use automated tools to find coding errors because there are no such tools, and because your run-time typing and dynamic behaviour means such tools won't work anyway.

What you seem to think of as "C culture" is general programming culture. Apart from a few niche areas where there are stronger rules and more control over the development process, it applies to /all/ programming regardless of the language.

Ironically, openssl development is an example of a normally solid development process - this is the first security bug in openssl since

2003, which is an impressive record for such widely used software. Human error in the development process was at fault here (unless you believe it was the NSA all along...)
Reply to
David Brown

Actually it isn't. I wish it was. People always look hurt when I run aggressive static analysis against a C codebase and ask if they want the bugs it finds fixed as well as the ones I am supposed to look at.

Once I found a whole chunk of modules where every variable had been altered to a soap opera character name. That took a while to undo.

I always do a before and after scan to demonstrate what is there and avoid any unpleasant surprises later on. Another metric I consider very reliable at finding code likely to contain bugs is McCabes CCI which is a measure of the minimum number of test cases to exercise every path through the code. If this number is too high then the code will almost certainly be buggy and may still contain paths that have never executed.

CPU cycles are cheap and getting cheaper where as people cycles are expensive and getting more so. It makes sense to offload as much of the automateable grunt work onto the compiler and toolset as you can.

One compiler I know with a sense of humour will compile access to an uninitialised variable as a hard trap with a warning message by default. I have it promoted to a hard error (language is Modula 2).

--
Regards, 
Martin Brown
Reply to
Martin Brown

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.