The Apple Security Bug Could Have Been Prevented

DN Staff

March 18, 2014

3 Min Read
The Apple Security Bug Could Have Been Prevented

Have a look at the picture below, do you see the error?

image.jpg

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.

Sign up for the Design News Daily newsletter.

You May Also Like