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; > } -- 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