Improved buffer overflow checking for scanf: %c with a width (#3494)

This commit is contained in:
PKEuS 2016-05-22 14:00:26 +02:00
parent dce7128f30
commit 851c6e0ed5
3 changed files with 23 additions and 5 deletions

View File

@ -684,7 +684,7 @@ void CheckIO::checkFormatString(const Token * const tok,
if (!width.empty()) {
int numWidth = std::atoi(width.c_str());
if (numWidth != (argInfo.variableInfo->dimension(0) - 1))
invalidScanfFormatWidthError(tok, numFormat, numWidth, argInfo.variableInfo);
invalidScanfFormatWidthError(tok, numFormat, numWidth, argInfo.variableInfo, 's');
}
}
if (argListTok && argListTok->tokType() != Token::eString &&
@ -703,6 +703,13 @@ void CheckIO::checkFormatString(const Token * const tok,
done = true;
break;
case 'c':
if (argInfo.variableInfo && argInfo.isKnownType() && argInfo.variableInfo->isArray() && (argInfo.variableInfo->dimensions().size() == 1) && argInfo.variableInfo->dimensions()[0].known) {
if (!width.empty()) {
int numWidth = std::atoi(width.c_str());
if (numWidth > argInfo.variableInfo->dimension(0))
invalidScanfFormatWidthError(tok, numFormat, numWidth, argInfo.variableInfo, 'c');
}
}
if (scanf_s) {
numSecure++;
if (argListTok) {
@ -2018,7 +2025,7 @@ void CheckIO::invalidLengthModifierError(const Token* tok, unsigned int numForma
reportError(tok, Severity::warning, "invalidLengthModifierError", errmsg.str());
}
void CheckIO::invalidScanfFormatWidthError(const Token* tok, unsigned int numFormat, int width, const Variable *var)
void CheckIO::invalidScanfFormatWidthError(const Token* tok, unsigned int numFormat, int width, const Variable *var, char c)
{
MathLib::bigint arrlen = 0;
std::string varname;
@ -2037,7 +2044,7 @@ void CheckIO::invalidScanfFormatWidthError(const Token* tok, unsigned int numFor
reportError(tok, Severity::warning, "invalidScanfFormatWidth_smaller", errmsg.str(), CWE(0U), true);
} else {
errmsg << "Width " << width << " given in format string (no. " << numFormat << ") is larger than destination buffer '"
<< varname << "[" << arrlen << "]', use %" << (arrlen - 1) << "s to prevent overflowing it.";
<< varname << "[" << arrlen << "]', use %" << (c == 'c' ? arrlen : (arrlen - 1)) << c << " to prevent overflowing it.";
reportError(tok, Severity::error, "invalidScanfFormatWidth", errmsg.str(), CWE687, false);
}
}

View File

@ -126,7 +126,7 @@ private:
void invalidPrintfArgTypeError_sint(const Token* tok, unsigned int numFormat, const std::string& specifier, const ArgumentInfo* argInfo);
void invalidPrintfArgTypeError_float(const Token* tok, unsigned int numFormat, const std::string& specifier, const ArgumentInfo* argInfo);
void invalidLengthModifierError(const Token* tok, unsigned int numFormat, const std::string& modifier);
void invalidScanfFormatWidthError(const Token* tok, unsigned int numFormat, int width, const Variable *var);
void invalidScanfFormatWidthError(const Token* tok, unsigned int numFormat, int width, const Variable *var, char c);
static void argumentType(std::ostream & s, const ArgumentInfo * argInfo);
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
@ -152,7 +152,7 @@ private:
c.invalidPrintfArgTypeError_sint(nullptr, 1, "i", nullptr);
c.invalidPrintfArgTypeError_float(nullptr, 1, "f", nullptr);
c.invalidLengthModifierError(nullptr, 1, "I");
c.invalidScanfFormatWidthError(nullptr, 10, 5, nullptr);
c.invalidScanfFormatWidthError(nullptr, 10, 5, nullptr, 's');
c.wrongPrintfScanfPosixParameterPositionError(nullptr, "printf", 2, 1);
}

View File

@ -44,6 +44,7 @@ private:
TEST_CASE(testScanf1); // Scanf without field limiters
TEST_CASE(testScanf2);
TEST_CASE(testScanf3); // #3494
TEST_CASE(testScanf4); // #ticket 2553
TEST_CASE(testScanfArgument);
@ -724,6 +725,16 @@ private:
ASSERT_EQUALS("[test.cpp:4]: (warning) scanf format string requires 0 parameters but 1 is given.\n", errout.str());
}
void testScanf3() { // ticket #3494
check("void f() {\n"
" char str[8];\n"
" scanf(\"%7c\", str);\n"
" scanf(\"%8c\", str);\n"
" scanf(\"%9c\", str);\n"
"}");
ASSERT_EQUALS("[test.cpp:5]: (error) Width 9 given in format string (no. 1) is larger than destination buffer 'str[8]', use %8c to prevent overflowing it.\n", errout.str());
}
void testScanf4() { // ticket #2553
check("void f()\n"
"{\n"