Security-aware coding in C and C++
● Generic notes
● C language related issues
● Operating system related issues
● Programming patterns
● C++ language related issues
Zoltán Porkoláb Security Aware C/C++ Coding 1 C language related issues
● Null terminated strings
● Buffer overflow
● Insecure i/o
● Tainted scalars
● Uninitialized values
● Race conditions
● Function parameters
● Syntactical considerations
Zoltán Porkoláb Security Aware C/C++ Coding 2 Buffer/Stack overflow
Zoltán Porkoláb Security Aware C/C++ Coding 3 Buffer/Stack overflow
Zoltán Porkoláb Security Aware C/C++ Coding 4 Null terminated strings char *strcpy(char *tgt, const char *src);
● Issues?
Zoltán Porkoláb Security Aware C/C++ Coding 5 Null terminated strings char *strcpy(char *tgt, const char *src);
● Undefined behavior if – the target array is not large enough – the strings overlap – target is not pointer to char array – the source is not null terminated – any of tgt or src is null pointer
Zoltán Porkoláb Security Aware C/C++ Coding 6 Null terminated strings char *strcpy(char *tgt, const char *src); char *strncpy(char *tgt, const char *src, size_t n);
● Undefined behavior if the strings overlap
● Copies at most n characters (chars after '\0' not copied)
● Fill the rest of the tgt buffer with null characters
● If there is no null character in the first n character of src, then the array tgt will not be null terminated
Zoltán Porkoláb Security Aware C/C++ Coding 7 Null terminated strings char *strcpy(char *tgt, const char *src); char *strncpy(char *tgt, const char *src, size_t n); strncpy( tgt, src, sizeof(tgt)); tgt[sizeof(tgt)-1] = '\0';
● Strncpy, strncat better to avoid
● Strncmp, … ok
Zoltán Porkoláb Security Aware C/C++ Coding 8 Null terminated strings char *strcpy(char *tgt, const char *src); size_t strlcpy(char *tgt, const char *src, size_t tsize); size_t strlcat(char *tgt, const char *src, size_t tsize);
● BSD defines strlcpy, strlcat – Truncates the source string (security risk) – Do not perform all run-time checks – Return value is not explicit about error
● The total length of the string attempted to create
Zoltán Porkoláb Security Aware C/C++ Coding 9 Null terminated strings char *strcpy(char *tgt, const char *src); size_t strlcpy(char *tgt, const char *src, size_t tsize); size_t strlcat(char *tgt, const char *src, size_t tsize);
● BSD defines strlcpy, strlcat – Truncates the source string (security risk) – Do not perform all run-time checks – Return value is not explicit about error
● The total length of the string attempted to create
Unix man page: Note, however, that if strlcat() traverses size characters without finding a NUL, the length of the string is considered to be size and the destination string will not be NUL-terminated (since there was no space for the NUL).
Zoltán Porkoláb Security Aware C/C++ Coding 10 Null terminated strings size_t strlcpy(char *tgt, const char *src, size_t tsize); size_t strlcat(char *tgt, const char *src, size_t tsize); char pname[MAXPATHLEN]; char *dir = ...; char *file = ...; if ( strlcpy( pname, dir, sizeof(pname)) >= sizeof(pname) ) { fprintf( stderr, “truncated!”); return -1; } if ( strlcat( pname, file, sizeof(pname)) >= sizeof(pname) ) { fprintf( stderr, “truncated!”); return -1; } /* ... */
Zoltán Porkoláb Security Aware C/C++ Coding 11 Do not do this! size_t strlcpy(char *tgt, const char *src, size_t tsize); size_t strlcat(char *tgt, const char *src, size_t tsize); char pname[MAXPATHLEN]; char *dir = ...; char *file = ...; size_t n = strlcpy( pname, dir, sizeof(pname)); if ( n >= sizeof(pname) ) { fprintf( stderr, “truncated!”); return -1; } if ( strlcpy( pname+n,file,sizeof(pname)-n) >= sizeof(pname)-n ) { fprintf( stderr, “truncated!”); return -1; } /* ... */
Zoltán Porkoláb Security Aware C/C++ Coding 12 Do not do this! size_t strlcpy(char *tgt, const char *src, size_t tsize); size_t strlcat(char *tgt, const char *src, size_t tsize); char pname[MAXPATHLEN]; char *dir = ...; char *file = ...; size_t n = strlcpy( pname, dir, sizeof(pname)); if ( n >= sizeof(pname) ) { fprintf( stderr, “truncated!”); return -1; } if ( strlcpy( pname+n,file,sizeof(pname)-n) >= sizeof(pname)-n ) { fprintf( stderr, “truncated!”); return -1; } However, one may question the /* ... */ validity of such optimizations, as they defeat the whole purpose of strlcpy() and strlcat(). As a matter of fact, the first version of this Zoltán Porkoláb manualSecurity Aware page C/C++ Codinggot it wrong. 13 Safe functions char *strcpy(char *tgt, const char *src); size_t strlcpy(char *tgt, const char *src, size_t tsize); errno_t strcpy_s(char *tgt, rsize_t tsize, const char *src);
● Calls the constraint handler function if – any of tgt or src is null pointer – tsize is zero or greater RSIZE_MAX – tsize <= strnlen_s(src, tsize) – tgt and src strings overlap
● Undefined if size of tgt array <= strlen_s(src,tsize) < tsize
Zoltán Porkoláb Security Aware C/C++ Coding 14 Safe functions
#define __STDC_WANT_LIB_EXT1__ 1 #include
● Safe functions are guaranteed to available if – __STDC_LIB_EXT1__ is defined by the implementation – User defines __STDC_WANT_LIB_EXT1__ before including
● Defined in
● If constraint_handler is not set, default is implementation defined
Zoltán Porkoláb Security Aware C/C++ Coding 15 Safe functions strcpy_s( char *dest, rsize_t destsz, const char *src) strncpy_s(char *dest, rsize_t destsz, const char *src, rsize_t n) strcat_s( char *dest, rsize_t destsz, const char *src) strncat_s(char *dest, rsize_t destsz, const char *src, rsize_t n) strnlen_s( char *str, rsize_t strsz) strtok_s(char *str, rsize_t *strmax, const char *delim, char **p) memset_s( void *dest, rsize_t destsz, int ch, rsize_t n) memcpy_s( void *dest, rsize_t destsz, const void *src, rsize_t n) memmove_s(void *dest, rsize_t destsz, const void *src, rsize_t n) strerrorlen_s( errno_t errnum) strerror_s( char *buf, rsize_t bufsz, errno_t errnum)
Zoltán Porkoláb Security Aware C/C++ Coding 16 Safe functions strtok_s(char *str, rsize_t *strmax, const char *delim, char **p) char str[] = "A bird came down the walk"; rsize_t strmax = sizeof(str); const char *delim = " "; char *next_token; printf("Parsing the input string '%s'\n", str); char *token = strtok_s(str, &strmax, delim, &next_token); while(token) { puts(token); token = strtok_s(NULL, &strmax, delim, &next_token); }
Zoltán Porkoláb Security Aware C/C++ Coding 17 Safe functions strerrorlen_s( errno_t errnum); strerror_s( char *buf, rsize_t bufsz, errno_t errnum); setlocale(LC_ALL, "ja_JP.utf8"); size_t errmsglen = strerrorlen_s(errno) + 1; char errmsg[errmsglen]; strerror_s(errmsg, errmsglen, errno); fprintf(stderr, “Might be truncated: %s”, errmsg);
Zoltán Porkoláb Security Aware C/C++ Coding 18 Safe functions strerrorlen_s( errno_t errnum); strerror_s( char *buf, rsize_t bufsz, errno_t errnum); setlocale(LC_ALL, "ja_JP.utf8"); size_t errmsglen = strerrorlen_s(errno) + 1; char errmsg[errmsglen]; strerror_s(errmsg, errmsglen, errno); fprintf(stderr, “Might be truncated: %s”, errmsg);
strerror_s() is the only safe function that allows truncation
Zoltán Porkoláb Security Aware C/C++ Coding 19 Buffer overflow
#include
Zoltán Porkoláb Security Aware C/C++ Coding 20 Buffer overflow
#include
Zoltán Porkoláb Security Aware C/C++ Coding 21 Buffer overflow
#include
Zoltán Porkoláb Security Aware C/C++ Coding 22 Buffer overflow
#include
Zoltán Porkoláb Security Aware C/C++ Coding 23 Buffer overflow
#include
Zoltán Porkoláb Security Aware C/C++ Coding 24 Buffer overflow
#include
Zoltán Porkoláb Security Aware C/C++ Coding 25 C++ must be better
#include
Zoltán Porkoláb Security Aware C/C++ Coding 26 C++ must be better?
#include
Zoltán Porkoláb Security Aware C/C++ Coding 27 C++ is better!
#include
#include
Zoltán Porkoláb Security Aware C/C++ Coding 29 Tainted format string
#include
Zoltán Porkoláb Security Aware C/C++ Coding 30 Tainted format string
#include
Zoltán Porkoláb Security Aware C/C++ Coding 31 Not only input can be dangerous
#include
Zoltán Porkoláb Security Aware C/C++ Coding 32 Safe i/o functions fopen_s(FILE **streamptr, const char *fname, const char *mode) freopen_s(FILE **streamptr, const char *fname, const char *mode,FILE *oldstream) gets_s( char *str, rsize_t n) scanf_s( const char *format, ...) fscanf_s(FILE *fp, const char *format, ...) sscanf_s(char *buffer, const char *format, ...) snprintf(char *buffer, size_t bufsz, const char *format ...) printf_s(const char *format ...) fprintf_s(FILE *fp, const char *format ...) sprintf_s(char *buffer, size_t bufsz, const char *format ...) snprintf_s(char *buffer, size_t bufsz, const char *format ...)
Zoltán Porkoláb Security Aware C/C++ Coding 33 Stack overflow
● Sentinels
● Address space randomization
● Stack randomization by OS
● Stack randomization by software
Similar issues with the heap
Zoltán Porkoláb Security Aware C/C++ Coding 34 String comparison
void f() { std::string s(“Hello”); if( “Hello” == s.c_str() ) { /* … */ } }
Zoltán Porkoláb Security Aware C/C++ Coding 35 String comparison
void f() { std::string s(“Hello”); if( “Hello” == s.c_str() ) { /* … */ } }
● Comparing two pointers… … likely never true
Zoltán Porkoláb Security Aware C/C++ Coding 36 strcmp
void f() { std::string s(“Hello”); if( std::strcmp(“Hello”, s.c_str()) == 0) { /* … */ } }
Zoltán Porkoláb Security Aware C/C++ Coding 37 strcmp
void f() { std::string s(“Hello”); if( std::strcmp(“Hallo”, s.c_str()) == -1 ) { /* … */ } }
Zoltán Porkoláb Security Aware C/C++ Coding 38 strcmp
void f() { std::string s(“Hello”); if( std::strcmp(“Hallo”, s.c_str()) == -1 ) { /* … */ } }
Zoltán Porkoláb Security Aware C/C++ Coding 39 strcmp
void f() { std::string s(“Hello”); if( std::strcmp(“Hallo”, s.c_str()) < 0 ) { /* … */ } }
Zoltán Porkoláb Security Aware C/C++ Coding 40 strcmp
void f() { std::string s(“Hello”); if( std::strcmp(“Hallo”, s.c_str()) < 0 ) { /* … */ } } int strcmp( const char *s1, const char *s2) { while ( *s1 == *s2 && *s1 != '\0' ) { ++s1; ++s2; } return *s1 - *s2; }
Zoltán Porkoláb Security Aware C/C++ Coding 41 Cheating strings char gpl[] = "This is a GPL license"; char fake[] = "This is a GPL license or maybe not"; std::string str1(fake); std::cerr << fake << std::endl; std::cerr << str1 << std::endl; std::cerr << str1.c_str() << std::endl; std::cerr << (str1 == gpl) << std::endl; std::cerr << (0 == strcmp(str1.c_str(),gpl)) << std::endl; This is a GPL license or maybe not This is a GPL license or maybe not This is a GPL license or maybe not 0 0
Zoltán Porkoláb Security Aware C/C++ Coding 42 Cheating strings char gpl[] = "This is a GPL license"; char fake[] = "This is a GPL license or maybe not"; str1[21] = '\0'; std::string str1(fake); std::cerr << fake << std::endl; std::cerr << str1 << std::endl; std::cerr << str1.c_str() << std::endl; std::cerr << (str1 == gpl) << std::endl; std::cerr << (0 == strcmp(str1.c_str(),gpl)) << std::endl; This is a GPL license This is a GPL licenseor maybe not This is a GPL license 0 1
Zoltán Porkoláb Security Aware C/C++ Coding 43 Cheating strings
Linuxant's HSM Modem drivers MODULE_LICENSE(“GPL\0 ...”) https://linux.slashdot.org/story/04/04/27/1435217/kernel- modules-that-lie-about-their-licenses tainted kernel issue
Mozilla/2.02 [fr] (WinNT; I) Mozilla/4.0 (compatible; MSIE 4.0; Windows 95)
Zoltán Porkoláb Security Aware C/C++ Coding 44 Safe conversions char buffer[BUFSIZE]; //... int i = atoi( buffer); long strtol( const char *str, char **str_end, int base);
// since C99 str and str_end are restrict pointers long i1 = strtol(p, &end, 10); long i2 = strtol(p, NULL, 10); // no error handling long i3 = strtol(p, &end, 0); // auto-detect base long i = strtol(p, &end, 10); if ( ERANGE == errno ) // range error
Zoltán Porkoláb Security Aware C/C++ Coding 45 C++ std::string
void f() { std::string s(“Hello”); if( std::strcmp(“Hello”, s.data()) == 0) { /* … */ } }
Zoltán Porkoláb Security Aware C/C++ Coding 46 C++ std::string
void f() { std::string s(“Hello”); if( std::strcmp(“Hello”, s.data()) == 0) { /* … */ } }
● The returned array is not required to be null-terminated. until C++11
● The returned array is null-terminated, that is, data() and c_str() perform the same function. since C++11
Zoltán Porkoláb Security Aware C/C++ Coding 47 C++ std::string
void f() { std::string s(“Hello”); if( std::strcmp(“Hello”, s.data()) == 0) { /* … */ } }
● The returned array is not required to be null-terminated. until C++11
● The returned array is null-terminated, that is, data() and c_str() perform the same function. since C++11
Zoltán Porkoláb Security Aware C/C++ Coding 48 C++ std::string
void f() { std::string s(“Hello”); if( std::strcmp(“Hello”, &s[0]) == 0) { /* … */ } }
Zoltán Porkoláb Security Aware C/C++ Coding 49 C++ std::string
void f() { std::string s(“Hello”); if( std::strcmp(“Hello”, &s[0]) == 0) { /* … */ } }
● The returned array is not required to be null-terminated. until C++11
● The returned array is null-terminated. since C++11
Zoltán Porkoláb Security Aware C/C++ Coding 50 C++ std::string
void f() { std::string s; if( std::strcmp(“Hello”, s.data()) == 0) { /* … */ } }
Zoltán Porkoláb Security Aware C/C++ Coding 51 C++ std::string
void f() { std::string s; if( std::strcmp(“Hello”, s.data()) == 0) { /* … */ } }
● If empty() returns true, the pointer is a non-null pointer that should not be dereferenced. until C++11
● If empty() returns true, the pointer points to a single null character. since C++11
Zoltán Porkoláb Security Aware C/C++ Coding 52 Practice
● Write a simple console program
● Read a secret passphrase from standard input
● Count, how many words in it
● Print the number of words to the standard output
● Be care, that the program does not store the passphrase, e.g. if the program crashes, one cannot dig it out from the core file
Zoltán Porkoláb Security Aware C/C++ Coding 53 Compiler optimization
#include
}
Zoltán Porkoláb Security Aware C/C++ Coding 54 Compiler optimization
#include
Zoltán Porkoláb Security Aware C/C++ Coding 55 https://godbolt.org/
Zoltán Porkoláb Security Aware C/C++ Coding 56 Compiler optimization
#include
}
Zoltán Porkoláb Security Aware C/C++ Coding 57 Compiler optimization
Zoltán Porkoláb Security Aware C/C++ Coding 58 -O2
Zoltán Porkoláb Security Aware C/C++ Coding 59 Compiler optimization
#include
Zoltán Porkoláb Security Aware C/C++ Coding 60 -O2
Zoltán Porkoláb Security Aware C/C++ Coding 61 Compiler optimization
#include
Zoltán Porkoláb Security Aware C/C++ Coding 62 -O2
Zoltán Porkoláb Security Aware C/C++ Coding 63 Compiler optimization
#include
Zoltán Porkoláb Security Aware C/C++ Coding 64 -O2
Zoltán Porkoláb Security Aware C/C++ Coding 65