The Apple Security Bug Could Have Been Prevented

People will fall into two groups. One group will immediately spot the problem, and the other group will say, “What error? I don’t see anything wrong.” Those in the second group can often stare at this for ages and still not see the error, while people in the first group can’t understand how anyone could miss it.

Now look at the code with the bug that caused the big hole in Apple security in a huge number (millions and millions) of devices in everyday use:

if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0)

goto fail;

if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0)

goto fail;

if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)

goto fail;

if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)

goto fail;

goto fail;

if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)

goto fail;

Do you see the error? For some people the extra goto fail will be as invisible as the extra “THE” in the Paris springtime. Others will spot it immediately. It seems as if whoever wrote that code wasn’t in the group that notices an error like this immediately. And indeed, we all, as programmers, suffer from the dread disease of seeing what we want to see, instead of what’s actually there.

So how do we prevent such problems? And what could Apple have done to avoid this situation? The answer is that it took an extraordinary chain of failures to follow best-practices for this bug to escape detection. If Apple’s software development and verification processes had followed even one of the following principles, the bug would never have made it into production code.

Best-Practice No. 1: Use an appropriate language. C is notoriously full of traps and vulnerabilities, and the excerpt above shows one of them: Although the second goto fail is indented so it looks as if it’s under control of the preceding if, in fact it’s a separate statement following the if. Using a language that avoids such vulnerabilities (such as Ada or other possibilities) would have caught this error early.

Best-Practice No. 2: Use appropriate tools to ensure proper indentation. Indenting nested code is vital in making a program easy to read and understand. If such a layout tool had been used, the second goto fail would have appeared at the same indentation level as the if statements, making it more obvious that something was amiss.

Best-Practice No. 3: Adopt coding standards that avoid traps and vulnerabilities. The C syntactic rule allowing a single statement to follow an if statement’s condition is known to cause this kind of bug, and many people writing C will use a coding standard that insists on using {} brackets to enclose even a single statement in such a context. This coding standard can then be enforced with an appropriate tool. With the brackets in place, it would have been more obvious that the second goto fail was outside the brackets (of course, if it was inside the brackets, no problem would have arisen, it would simply have been “dead code”).

Best-Practice No. 4: Make proper use of the tools you have. Virtually all C compilers, including the one Apple used at the time, have an option to detect unreachable code. In this case, the if following the second goto fail is unreachable. But you have to turn the option on! Why on Earth would critical code ever be compiled without setting all appropriate warning flags to detect possible errors?

Best-Practice No. 5: Use static analysis tools. These days we have excellent tools that inspect your code and automatically detect errors. They can’t, of course, find all bugs, but it’s hard to believe that any of the many static analysis tools available for C would miss this obvious case.

@tbh. Thanks for reply thats actually a decent post. Me likes... Still Ada is far from a best practice... i personaly would go with the more popular languages until others find/refine its problems. That now could be a best practice. :D

@ naperlou, it is an interesting case. I think there may be two reasons that can be attributed to this anomaly. First is that you were probably prepared to find the error in the code and knew the nature of the problem from going through the word exercise. Second, it might be the case of frame of reference. We can understand things better which are related to us somehow.

I agree, McConnell's books are well worth the read. His books have a lot of good pointers on writing solid code. My copy is heavily highlighted and dog-eared:) I have not read the Stroustrup pages you referenced, thanks for pointing them out. Looks interesting.

If you are interested in learning about coding practices, (and not just arguing about it) I would recommend the book "Code Complete". I think it is a Microsoft Press book. It is a fascinating book concerning what practices and habits are conducive to producing good code. It is probably a little dated by now, but it is a great read if you are really interested in quality coding. I have read it several times, and it is on my bookshelf at work. The book is not language specific, as it is mainly concerned with programming practices. The book contains a lot of actual data concerning programming practices, not just a bunch of opinions.

If you happen to be a C++ programmer, I also recommend any writings of Bjarne Stroustrup, including the stuff on his web page (http://www.stroustrup.com/). I find his writing style to be very enjoyable, and his insight into using C++ is invaluable. Because he invented the language, and has been involved with almost every detail of it, he knows what the design intent of the language is, as well as how it is most properly used. He is very good at articulating both the strengths and weaknesses of the language.

As this article points out, C/C++ does give programmers every opportunity to write disasterous code (actually most languages do). But on the other hand, it gives you control at nearly an assembly language level when you need it, and high level tools as well. When used properly, it can produce very high quality, maintainable code that executes extremely fast.

It's a matter of cost, too. In medical devices we test 100%, yes, every branch, and then a line by line peer review. It's tedious, expensive, and even minor changes trigger a complete review of the module. I'm certain that level of verification is far too costly and time consuming for a device that is largely a consumer product.

If the consumer went to WalMart and saw two computers hanging on the wall, both with the same features, but one was verified with 100% coverage at twice the price, I'm certain the consumer would pick the cheaper model. In many ways, that's already been proven.

I may not be qualified enough to raise my finger on designers and programmers working on the payroll of Apple, but these are the basics of programming. Programmers are advised to always use brackets even in case of single statements in C. It brings our attention to a problem that most of us face. We tend to turn our backs to the basics. This is a classic example of how we may suffer from doing so.

I don't think the author directly said that about Apple, but I can see how one might have seen that as implied. I'm not an analyst so I cannot comment one way or another on Apple's performance in the market, or whether or not they appear to be "off their game". That wasn't the focus of the article, and seems irrelevant to the argument put forth.

I beleive that the author was trying to be informative and provide useful information on practices that he values, and that others may benefit from knowing about. Unfortunately the article as it appeared online has major flaws that resulted, at least for me, in loss of the message.

No offense but the author has one thing right. Apple has not been getting things right for a while now... just look at their market share and stock prices... all i have to say is "SELL" for Apple. The devil is always in the details.

That table below was % of the sample population. The preferred programming language for those sampled. Obviously bias view and I have seen a different one on every major computer magazine out there. However one thing they have in common... ADA is not even listed. so correct me if I'm wrong but does not a best practice require a tried and true development environment, language and compiler? If the community does not practice this language how could it be a best practice?

Industrial workplaces are governed by OSHA rules, but this isn’t to say that rules are always followed. While injuries happen on production floors for a variety of reasons, of the top 10 OSHA rules that are most often ignored in industrial settings, two directly involve machine design: lockout/tagout procedures (LO/TO) and machine guarding.

Load dump occurs when a discharged battery is disconnected while the alternator is generating current and other loads remain on the alternator circuit. If left alone, the electrical spikes and transients will be transmitted along the power line, leading to malfunctions in individual electronics/sensors or permanent damage to the vehicle’s electronic system. Bottom line: An uncontrolled load dump threatens the overall safety and reliability of the vehicle.

While many larger companies are still reluctant to rely on wireless networks to transmit important information in industrial settings, there is an increasing acceptance rate of the newer, more robust wireless options that are now available.

To those who have not stepped into additive manufacturing, get involved as soon as possible. This is for the benefit of your company. When the new innovations come out, you want to be ready to take advantage of them immediately, and that takes knowledge.

Focus on Fundamentals consists of 45-minute on-line classes that cover a host of technologies. You learn without leaving the comfort of your desk. All classes are taught by subject-matter experts and all are archived. So if you can't attend live, attend at your convenience.