ISO/IEC TS 17961 [taintformatio]
Using a tainted value to write to an object using a formatted input or output function
Description
Rule Definition
Using a tainted value to write to an object using a formatted input or output function.1
Polyspace Implementation
This checker checks for these issues:
Buffer overflow from incorrect string format specifier.
Destination buffer overflow in string manipulation.
Invalid use of standard library routine.
Invalid use of standard library string routine.
Tainted NULL or non-null-terminated string.
Tainted string format specifier.
Invalid use of standard library string routine.
Use of dangerous standard function.
Insufficient destination buffer size
Extend Checker
A default Bug Finder analysis might not flag a Tainted NULL or
non-null-terminated string or Tainted string format
specifier issue for certain inputs that originate outside of the current
analysis boundary. See Sources of Tainting in a Polyspace Analysis. To consider any data
that does not originate in the current scope of Polyspace analysis as tainted, use the
command line option -consider-analysis-perimeter-as-trust-boundary
.
Examples
Buffer overflow from incorrect string format specifier
Buffer overflow from incorrect string
format specifier occurs when the format specifier argument
for functions such as sscanf
leads to an overflow
or underflow in the memory buffer argument.
If the format specifier specifies a precision that is greater than the memory buffer size, an overflow occurs. Overflows can cause unexpected behavior such as memory corruption.
Use a format specifier that is compatible with the memory buffer size.
#include <stdio.h>
void func (char *str[]) {
char buf[32];
sscanf(str[1], "%33c", buf);
}
In this example, buf
can contain 32 char
elements.
Therefore, the format specifier %33c
causes a buffer
overflow.
One possible correction is to use a smaller precision in the format specifier.
#include <stdio.h> void func (char *str[]) { char buf[32]; sscanf(str[1], "%32c", buf); }
Destination buffer overflow in string manipulation
Destination buffer overflow in string manipulation occurs when certain string manipulation functions write to their destination buffer argument at an offset greater than the buffer size.
For instance, when calling the function sprintf(char*
buffer, const char* format)
, you use a constant string format
of
greater size than buffer
.
Buffer overflow can cause unexpected behavior such as memory corruption or stopping your system. Buffer overflow also introduces the risk of code injection.
One possible solution is to use alternative functions to constrain the number of characters written. For instance:
If you use
sprintf
to write formatted data to a string, usesnprintf
,_snprintf
orsprintf_s
instead to enforce length control. Alternatively, useasprintf
to automatically allocate the memory required for the destination buffer.If you use
vsprintf
to write formatted data from a variable argument list to a string, usevsnprintf
orvsprintf_s
instead to enforce length control.If you use
wcscpy
to copy a wide string, usewcsncpy
,wcslcpy
, orwcscpy_s
instead to enforce length control.
Another possible solution is to increase the buffer size.
sprintf
Use#include <stdio.h>
void func(void) {
char buffer[20];
char *fmt_string = "This is a very long string, it does not fit in the buffer";
sprintf(buffer, fmt_string);
}
In this example, buffer
can contain 20 char
elements
but fmt_string
has a greater size.
snprintf
Instead
of sprintf
One possible correction is to use the snprintf
function
to enforce length control.
#include <stdio.h> void func(void) { char buffer[20]; char *fmt_string = "This is a very long string, it does not fit in the buffer"; snprintf(buffer, 20, fmt_string); }
Invalid use of standard library routine
This issue occurs when you use invalid arguments with a function from the standard library. This defect picks up errors related to other functions not covered by float, integer, memory, or string standard library routines.
Invalid arguments to a standard library function result in undefined behavior.
The fix depends on the root cause of the defect. For instance, the argument to a
printf
function can be NULL
because a pointer was
initialized with NULL
and the initialization value was not overwritten
along a specific execution path.
See examples of fixes below.
If you do not want to fix the issue, add comments to your result or code to avoid another review. See:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
printf
Without a String#include <stdio.h>
#include <stdlib.h>
void print_null(void) {
printf(NULL);
}
The function printf
takes only string input
arguments or format specifiers. In this function, the input value is NULL, which is not a
valid string.
One possible correction is to change the input arguments to fit the requirements of the standard library routine. In this example, the input argument was changed to a character.
#include <stdio.h> void print_null(void) { char zero_val = '0'; printf((const char*)zero_val); }
Invalid use of standard library string routine
Invalid use of standard library string routine occurs when a string library function is called with invalid arguments.
The risk depends on the type of invalid arguments. For instance, using the
strcpy
function with a source argument larger than the destination
argument can result in buffer overflows.
The fix depends on the standard library function involved in the defect. In some
cases, you can constrain the function arguments before the function call. For instance, if
the strcpy
function:
char * strcpy(char * destination, const char* source);
strcpy
. In
some cases, you can use an alternative function to avoid the error. For instance, instead
of strcpy
, you can use strncpy
to control the number
of bytes copied. See also Interpret Bug Finder Results in Polyspace Desktop User Interface.See examples of fixes below.
If you do not want to fix the issue, add comments to your result or code to avoid another review. See:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
#include <string.h>
#include <stdio.h>
char* Copy_String(void)
{
char *res;
char gbuffer[5],text[20]="ABCDEFGHIJKL";
res=strcpy(gbuffer,text);
/* Error: Size of text is less than gbuffer */
return(res);
}
The string text
is larger in size than
gbuffer
. Therefore, the function strcpy
cannot
copy text
into gbuffer
.
One possible correction is to declare the destination string
gbuffer
with equal or larger size than the source string
text
.
#include <string.h> #include <stdio.h> char* Copy_String(void) { char *res; /*Fix: gbuffer has equal or larger size than text */ char gbuffer[20],text[20]="ABCDEFGHIJKL"; res=strcpy(gbuffer,text); return(res); }
Tainted NULL or non-null-terminated string
This issue occurs when strings from nonsecure sources are used in string manipulation
routines that implicitly dereference the string buffer, for instance,
strcpy
or sprintf
.
The checker raises no defect for a string returned from a call to
scanf
-family variadic functions. Similarly, no defect is raised when
you pass the string with a %s
specifier to
printf
-family variadic functions.
If a string is from an unsecure source, it is possible that an attacker manipulated the string or pointed the string pointer to a different memory location.
If the string is NULL, the string routine cannot dereference the string, causing the program to crash. If the string is not null-terminated, the string routine might not know when the string ends. This error can cause you to write out of bounds, causing a buffer overflow.
Validate the string before you use it. Check that:
The string is not NULL.
The string is null-terminated
The size of the string matches the expected size.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define SIZE128 128 #define MAX 40 extern void print_str(const char*); void warningMsg(void) { char userstr[MAX]; read(0,userstr,MAX); char str[SIZE128] = "Warning: "; strncat(str, userstr, SIZE128-(strlen(str)+1)); print_str(str); } void errorMsg(void) { char userstr[MAX]; read(0,userstr,MAX); char str[SIZE128] = "Error: "; strncat(str, userstr, SIZE128-(strlen(str)+1)); print_str(str); }
In this example, the string str
is concatenated with the argument
userstr
. The value of userstr
is unknown. If the
size of userstr
is greater than the space available, the concatenation
overflows.
One possible correction is to check the size of userstr
and make
sure that the string is null-terminated before using it in strncat
.
This example uses a helper function, sansitize_str
, to validate the
string. The defects are concentrated in this function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define SIZE128 128
#define MAX 40
extern void print_str(const char*);
int sanitize_str(char* s) {
int res = 0;
if (s && (strlen(s) > 0)) { // Defect only raised here
// - string is not null
// - string has a positive and limited size
// - TAINTED_STRING on strlen used as a firewall
res = 1;
}
return res;
}
void warningMsg(void)
{
char userstr[MAX];
read(0,userstr,MAX);
char str[SIZE128] = "Warning: ";
if (sanitize_str(userstr))
strncat(str, userstr, SIZE128-(strlen(str)+1));
print_str(str);
}
Another possible correction is to call function errorMsg
and
warningMsg
with specific strings.
#include <stdio.h> #include <string.h> #include <stdlib.h> #define SIZE128 128 extern void print_str(const char*); void warningMsg(char* userstr) { char str[SIZE128] = "Warning: "; strncat(str, userstr, SIZE128-(strlen(str)+1)); print_str(str); } void errorMsg(char* userstr) { char str[SIZE128] = "Error: "; strncat(str, userstr, SIZE128-(strlen(str)+1)); print_str(str); } int manageSensorValue(int sensorValue) { int ret = sensorValue; if ( sensorValue < 0 ) { errorMsg("sensor value should be positive"); exit(1); } else if ( sensorValue > 50 ) { warningMsg("sensor value greater than 50 (applying threshold)..."); sensorValue = 50; } return sensorValue; }
Tainted string format specifier
This issue occurs when printf
-style functions use a format
specifier constructed from nonsecure sources.
If you use externally controlled elements to format a string, you can cause buffer
overflow or data-representation problems. An attacker can use these string formatting
elements to view the contents of a stack using %x
or write to a stack
using %n
.
Pass a static string to format string functions. This fix ensures that an external actor cannot control the string.
Another possible fix is to allow only the expected number of arguments. If possible,
use functions that do not support the vulnerable %n
operator in format
strings.
#include <stdio.h>
#include <unistd.h>
#define MAX 40
void taintedstringformat(void) {
char userstr[MAX];
read(0,userstr,MAX);
printf(userstr);
}
This example prints the input argument userstr
. The string is
unknown. If it contains elements such as %
, printf
can interpret userstr
as a string format instead of a string, causing
your program to crash.
One possible correction is to print userstr
explicitly as a string
so that there is no ambiguity.
#include <stdio.h> #include <unistd.h> #define MAX 40 void taintedstringformat(void) { char userstr[MAX]; read(0,userstr,MAX); printf("%.20s", userstr);; }
Use of dangerous standard function
The Use of dangerous standard function check highlights uses of functions that are inherently dangerous or potentially dangerous given certain circumstances. The following table lists possibly dangerous functions, the risks of using each function, and what function to use instead.
Dangerous Function | Risk Level | Safer Function |
---|---|---|
gets | Inherently dangerous — You cannot control the length of input from the console. | fgets |
cin | Inherently dangerous — You cannot control the length of input from the console. | Avoid or prefaces calls to cin with
cin.width . |
strcpy | Possibly dangerous — If the source length is greater than the destination, buffer overflow can occur. | strncpy |
stpcpy | Possibly dangerous — If the source length is greater than the destination, buffer overflow can occur. | stpncpy |
lstrcpy or StrCpy | Possibly dangerous — If the source length is greater than the destination, buffer overflow can occur. | StringCbCopy , StringCchCopy ,
strncpy , strcpy_s , or
strlcpy |
strcat | Possibly dangerous — If the concatenated result is greater than the destination, buffer overflow can occur. | strncat , strlcat , or
strcat_s |
lstrcat or StrCat | Possibly dangerous — If the concatenated result is greater than the destination, buffer overflow can occur. | StringCbCat , StringCchCat ,
strncay , strcat_s , or
strlcat |
wcpcpy | Possibly dangerous — If the source length is greater than the destination, buffer overflow can occur. | wcpncpy |
wcscat | Possibly dangerous — If the concatenated result is greater than the destination, buffer overflow can occur. | wcsncat , wcslcat , or
wcncat_s |
wcscpy | Possibly dangerous — If the source length is greater than the destination, buffer overflow can occur. | wcsncpy |
sprintf | Possibly dangerous — If the output length depends on unknown lengths or values, buffer overflow can occur. | snprintf |
vsprintf | Possibly dangerous — If the output length depends on unknown lengths or values, buffer overflow can occur. | vsnprintf |
These functions can cause buffer overflow, which attackers can use to infiltrate your program.
The fix depends on the root cause of the defect. Often the result details show a sequence of events that led to the defect. You can implement the fix on any event in the sequence. If the result details do not show the event history, you can trace back using right-click options in the source code and see previous related events. See also Interpret Bug Finder Results in Polyspace Desktop User Interface.
See examples of fixes below.
If you do not want to fix the issue, add comments to your result or code to avoid another review. See:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
sprintf
#include <stdio.h>
#include <string.h>
#include <iostream>
#define BUFF_SIZE 128
int dangerous_func(char *str)
{
char dst[BUFF_SIZE];
int r = 0;
if (sprintf(dst, "%s", str) == 1)
{
r += 1;
dst[BUFF_SIZE-1] = '\0';
}
return r;
}
This example function uses sprintf
to copy the string
str
to dst
. However, if str
is
larger than the buffer, sprintf
can cause buffer overflow.
snprintf
with Buffer SizeOne possible correction is to use snprintf
instead and specify a
buffer size.
#include <stdio.h> #include <string.h> #include <iostream> #define BUFF_SIZE 128 int dangerous_func(char *str) { char dst[BUFF_SIZE]; int r = 0; if (snprintf(dst, sizeof(dst), "%s", str) == 1) { r += 1; dst[BUFF_SIZE-1] = '\0'; } return r; }
Insufficient destination buffer size
Insufficient destination buffer size occurs when the
destination buffer in a strcpy
operation cannot accommodate the source
buffer and a null terminator. This issue is reported if the size of the source buffer is
unknown. Consider this
code:
int main (int argc, char *argv[]) { const char *const input = ((argc && argv[0]) ? argv[0] : ""); char str[100]; strcpy(str, input); // Noncompliant }
input
is unknown. The size of
the destination buffer str
might be smaller than the value
(strlen(input)+1)
. Polyspace® reports a violation on the strcpy
operation.Using a destination buffer of insufficient size might allow an attacker to cause a buffer overflow. In the preceding code example, if argv[0]
contains 100 or more characters, the strcpy
operation results in a buffer overflow.
Before calling the function strcpy()
, allocate sufficient memory dynamically. For instance, use the function strlen()
to determine the size of the source buffer and then allocate the destination buffer so that its size is greater than the value strlen(source) + 1
.
Alternatively, use the function strncpy()
instead of
strcpy()
. The function strncpy()
copies a known
number of characters from the source buffer to the destination buffer. Because the
function strncpy()
copies a known number of characters, it is a safer
alternative to strcpy()
.
In this example, the size of the source
buffer is unknown, while the size of the destination
buffer is fixed at 128
. The size of the destination
buffer might not be sufficient to accommodate the characters from the source
buffer and terminate the buffer with a null. Polyspace reports a violation of the rule.
#include <string.h> int main(int argc, char *argv[]) { const char *const source = (argc && argv[0]) ? argv[0] : ""; char destination[128]; strcpy(destination,source);//Noncompliant return 0; }
strncpy
instead of
strcpy
To fix this issue, use strncpy()
to copy a known number of
characters from the source
buffer to the destination
buffer.
#include <string.h> #define MAX_ARGS 128 int main(int argc, char *argv[]) { const char *const source = (argc && argv[0]) ? argv[0] : ""; char destination[MAX_ARGS]; int num = (strlen(source)+1>MAX_ARGS)?MAX_ARGS:strlen(source)+1; strncpy(destination,source,num);//Compliant return 0; }
This violation is resolved by allocating sufficient memory for the destination
buffer. For instance, use the function strlen()
to calculate the size of the source
buffer and allocate sufficient memory for the destination
buffer so that it can accommodate all characters from the source
buffer and the null terminator ('\0'
).
#include <string.h> int main(int argc, char *argv[]) { const char *const source = (argc && argv[0]) ? argv[0] : ""; char* destination = (char *)malloc(strlen(source)+ 1); if(destination!=NULL){ strcpy(destination, source);//Compliant }else{ /*Handle Error*/ } //... free(destination); return 0; }
Check Information
Decidability: Undecidable |
Version History
Introduced in R2019a
1 Extracts from the standard "ISO/IEC TS 17961 Technical Specification - 2013-11-15" are reproduced with the agreement of AFNOR. Only the original and complete text of the standard, as published by AFNOR Editions - accessible via the website www.boutique.afnor.org - has normative value.
MATLAB Command
You clicked a link that corresponds to this MATLAB command:
Run the command by entering it in the MATLAB Command Window. Web browsers do not support MATLAB commands.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)