[Cryptography] How programming language design can help us write secure crypto code

Bertrand Mollinier Toublet crypto-metzdowd at bmt-online.org
Fri Oct 23 02:17:26 EDT 2015


> On Oct 22, 2015, at 6:28 PM, Ray Dillinger <bear at sonic.net> wrote:
> 
> 
> 
> On 10/22/2015 01:27 AM, Michael Kjörling wrote:
> 
>> In your mind, particularly in practice, what is the difference between
>> "the behavior is undefined if..." and "the result will be an undefined
>> value if..."? Do you have an example of any compiler the behavior of
>> which doesn't fall into the latter category already when faced with a
>> situation like this?
> 
>> Yes, _technically_ "the behavior of Operation X is undefined in case
>> of ABC" means the compiler is free to do absolutely whatever it
>> pleases in that situation. _In practice_, there are only a few
>> possible outcomes, largely depending on what exactly Operation X and
>> the condion ABC is.
>> 
> 
> 
> Okay, I'm going to use an illustration that has already been talked
> about on this list.  In C, the meaning of a signed integer addition
> where the sum is greater (or less) than the signed integer type can
> represent is unspecified.  And it matters whether your compiler treats
> unspecified as meaning literally "behavior doesn't matter at all" or
> unspecified as meaning literally "doesn't specify the return value
> of the expression."
> 
> If you have code that adds two positive numbers and then checks for a
> negative result intending it as a check for overflow, like this:
> 
> 
> if (y < 0 || z < 0 ) halt(1);
> z = x + y;    /* undefined in case of overflow */
> if (z < 0){
>    printf("overflow at line %d\n", __LINE__);
>    halt(1);
>    }
> printf("positive result is %d\n", z);
> 

> In the case of gcc, the compiler goes through saying "I don't
> have to care what the code DOES in case of undefined behavior.”  It

I’m not buying it. I’ve just spent over an hour poring over the C99 standard, and the best I could find is this:

"6.3.1.3 Signed and unsigned integers

• 1  When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.

• 2  Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.49)

• 3  Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.”

That, along with:

"6.5.6 Additive operators
[…]
Semantics

• 4  If both operands have arithmetic type, the usual arithmetic conversions are performed on them.

• 5  The result of the binary + operator is the sum of the operands.”

This seems to indicate that in case of overflow of signed integers, _assigned back into a signed integer_, then there is an implementation-defined result or an implementation-defined signal raised.


For that matter, I have the following program:

$ cat test.c 
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int main(void) {
    int x = INT_MAX - 1;
    int y = INT_MAX - 2;
    int z;

    if (x < 0 || y < 0 ) exit(1);
    z = x + y;    /* undefined in case of overflow */
    if (z < 0){
        printf("overflow at line %d\n", __LINE__);
        exit(1);
    }
    printf("positive result is %d\n", z);
    return 0;
}

Which is yours, but in an actually compilable form.
Compilation with pedantic warnings is silent:

$ gcc -Wall -pedantic test.c -o test
$

And behavior is as could be expected:

$ ./test 
overflow at line 13


For reference this is on current Debian with its latest gcc:

$ gcc --version
gcc (Debian 4.9.2-10) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.




All this to say: I’ve seen a lot of high claims in this thread about how gcc is bent on shooting your foot for you, with the full might of the language standard behind it, but I’m not seeing it. To those who’ve put these claims out, I would say it’s time to put up: standard says undefined behavior? Chapter and verse, please! In communist Russia, gcc shoots you in the foot? Actual output from a run, along with gcc version, please!




Let’s be clear (and on topic): I do recognize all of the potential hand-wringing around reproducible builds and how the C _language_ does not readily support secure implementations (as in secure against the local system). I’ll even readily recognize that this is largely due to its emphasis on speed.

I would like to note, however, that it is entirely conceivable that a compiler that would exhibit the proper security behaviors in compiled output, that such a compiler is entirely compatible with the requirements (and more importantly leeways) of the C language standard. In other words, your (generic your, not just you, Ray) beef is not with the language, but with the toolchains you happen to have at your disposal.
-— 
Bertrand



More information about the cryptography mailing list