Web lists-archives.com

Re: Integer overflow in functions from scanf() family in MinGW, Cygwin, Borland/Embarcadero C environments (Windows)




On 2017-03-05 15:50, Brian Inglis wrote:
> On 2017-03-05 12:48, Lukas' Home Page wrote:
>> I find out a strange and bad beaviour in functions from scanf() family when
>> reading one-byte int variable in MinGW, Cygwin and Borland/Embarcadero C
>> environments (on Windows, on Linux this doesn't happen). This bug is
>> corelated with MSVCRT library which isn't written in C99 standard (it's
>> written in C89 i think).
>> So, the point is, when you're reading one byte using scanf() function, AND
>> you are using %hhu format specifier, you have Integer Overflow bug in your
>> code, because MinGW links to old MSVCRT (C89 version) even if you compile
>> with -std=c99 parameter.
>> This works, because scanf() in old MSVCRT library doesn't know "h" format
>> specifier. BUT! The problem is, that scanf try to interpret format specifier
>> anyway, omits unsupported "h" specifier and it's loading full integer ("u")
>> to memory (it should omit not supported part of format - whole "%hhu" format
>> part, not just only "h"). The C99 specification says on 361 page: "If a
>> conversion specification is invalid, the behavior is undefined." - but it is
>> WRONG, because the behaviour SHOULD BE DEFINED AS OMITING THE WHOLE
>> UNSUPPORTED PART OF FORMAT (not only single specifier, but whole part).
> 
> Dealing safely with anything other than int, double, and width
> limited strings using scanf requires a lot of care, by the
> implementation and the developer.
> Undefined behaviour puts the onus on you as a developer to avoid
> invoking whatever behaviour the implementation defaults to.
> I can suggest looking into the inttypes.h SCNu* macros and stdint.h.
> Options -Wall and -Wextra should produce format warnings.
> Cygwin uses newlib and Mingw may use its own scanf library.
> Cygwin provides a Mingw port, so any problems should be reported
> upstream.
>> In exploit (below), compiler doesn't even display warnings (event
>> if you compile program with -std=c99 and -Wextra parameters). I
>> compile on Windows 7 using that command:
>> gcc main.c -o main.exe -Wextra
>> #include <stdio.h>
>> #include <stdbool.h>
>> typedef volatile unsigned char uint8_t;
>> int main()
>> {
>>     bool allowAccess = false; // allowAccess should be always FALSE
>>     uint8_t userNumber;
>>     char format[] = "%hhu";
>>     char buffer[] = "257\n";
>>     sscanf(buffer, format, &userNumber);
>>     if (allowAccess)
>>     {
>>         printf("Access granted: secret information - Lech Walesa was a Bolek agent\n");
>>     }
>>     printf("Entered number is: %d\n", userNumber);
>>     return 0;
>> }

 
Compiling this in Cygwin 64 gives:

error: conflicting type qualifiers for ‘uint8_t’
 typedef volatile unsigned char uint8_t;
                                ^
...
/usr/include/sys/_stdint.h:24:19: note: previous declaration of ‘uint8_t’ was here
 typedef __uint8_t uint8_t ;
                   ^
as *_t is reserved by POSIX and libc.

Changing this to a regular identifer compiles cleanly and running gives:

Entered number is: 1

as might be expected as a result of the equivalent function call:

	userNumber = strtoul(buffer,NULL,10);

Unsure what effect volatile is intended to provide in this instance, 
other than inhibiting any possible optimization to uses of userNumber?
Cygwin gcc does not optimize out the function calls to sscanf and printf,
although it does convert the conditional printf to a puts at low levels 
and eliminates it at high levels.

So if Mingw gcc/sscanf or Borland/Embarcadero cc are not behaving 
correctly, please report those problems to the appropriate upstream 
mailing lists.

-- 
Take care. Thanks, Brian Inglis, Calgary, Alberta, Canada

--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple