IssueReturned value of a
sensitive function not checked occurs when you call sensitive standard
functions, but you:
Polyspace® does not report a violation of this rule for these cases:
You use the return value of a function in bitwise masking operations using the
&
and ~
operators without checking the
return value but then check the masked value. For example, in this code, the return
value val
of the sensitive function bar()
is
not checked. Polyspace does not report a violation because val
is used in
a bitwise masking operation and the result of the operation
masked_val
is
checked.
void foo(){
int val = bar() // Sensitive function - Compliant
int masked_val = val & 0xff;
if(masked_val){
//...
}
}
You store the value of sensitive functions that are called in each brunch of a
conditional statement and then check the value at the end of the conditional
statement. For example, this code, the sensitive functions foo()
and foo2()
are called in two branches of the
if-else
statement. The return value for both are conditionally
stored in return_value
. Polyspace does not report a violation because return_value
is
checked after the conditional
statement.
void func(){
//...
int volatile cond;
int returned_val;
if(cond){
returned_val = foo();
}else{
returned_val = foo2();
}
if(returned_val){
do_something();
}
}
For this violation, two type of functions are
considered: sensitive and
critical sensitive.
A sensitive function is a standard function that can encounter:
Exhausted system resources (for example, when allocating resources)
Changed privileges or permissions
Tainted sources when reading, writing, or converting data from external
sources
Unsupported features despite an existing API
A critical
sensitive function is a sensitive function that performs one of
these critical or vulnerable tasks:
Set privileges (for example, setuid
)
Create a jail (for example, chroot
)
Create a process (for example, fork
)
Create a thread (for example, pthread_create
)
Lock or unlock mutex (for example, pthread_mutex_lock
)
Lock or unlock memory segments (for example, mlock
)
RiskIf you do not check the return value of
functions that perform sensitive or critical sensitive tasks, your program can behave
unexpectedly. Errors from these functions can propagate throughout the program causing
incorrect output, security vulnerabilities, and possibly system failures.
FixBefore continuing with the program, test the
return value of critical sensitive functions.
For sensitive functions,
you can explicitly ignore a return value by casting the function to
void
. Polyspace does not raise this defect for sensitive functions cast to void. This
resolution is not accepted for critical sensitive functions because
they perform more vulnerable tasks.
Extend CheckerBy default, this rule checker detects the use of some sensitive and critical sensitive
functions. Specify the sensitive and critical sensitive functions in your code by using a
datalog file. In the datalog file, include these components:
Include the definitions in the source file
models/interfaces/sensitive_function.dl
.
Specify functions as
sensitive:
sensitive_function.is_sensitive("bar").
Specify functions as
critical:
sensitive_function.is_critical("foo").
You can also configure this rule checker to ignore some functions:
sensitive_function.ignore_all()
— Configures the rule
checker to ignore the default functions.
sensitive_function.ignore_standard($sensitive_function.std
())
— Configures the rule checker to ignore the sensitive and critical
sensitive functions for a specific set, specified by
std
. Possible values of
std
include: ISO
,
POSIX
, OPENSSL
,
UNIX
, WINDOWS
.
sensitive_function.ignore_function("func
")
— Configures the rule checker to ignore the function
func
.
Specify the datalog file as the input to the option -code-behavior-specifications
.
Example — Sensitive Function Return
Ignored#include <pthread.h>
void initialize() {
pthread_attr_t attr;
pthread_attr_init(&attr); //Noncompliant
}
This example shows a call to the sensitive
function pthread_attr_init
. The return value of
pthread_attr_init
is ignored, causing a defect.
Correction — Cast Function to
(void)
One possible correction is to cast the function
to void. This fix informs Polyspace and any reviewers that you are explicitly
ignoring the return value of the sensitive function.
#include <pthread.h>
void initialize() {
pthread_attr_t attr;
(void)pthread_attr_init(&attr);
}
Correction — Test Return ValueOne possible correction is to test the return
value of pthread_attr_init
to check for errors.
#include <pthread.h>
#include <stdlib.h>
#define fatal_error() abort()
void initialize() {
pthread_attr_t attr;
int result;
result = pthread_attr_init(&attr);
if (result != 0) {
/* Handle error */
fatal_error();
}
}
Example — Critical Function Return
Ignored#include <pthread.h>
extern void *start_routine(void *);
void returnnotchecked() {
pthread_t thread_id;
pthread_attr_t attr;
void *res;
(void)pthread_attr_init(&attr);
(void)pthread_create(&thread_id, &attr, &start_routine, ((void *)0)); //Noncompliant
pthread_join(thread_id, &res); //Noncompliant
}
In this example, two critical functions are
called: pthread_create
and pthread_join
. The return
value of the pthread_create
is ignored by casting to void, but because
pthread_create
is a critical function (not just a sensitive
function), Polyspace does not ignore this Return value of a sensitive function
not checked defect. The other critical function,
pthread_join
, returns value that is ignored implicitly.
pthread_join
uses the return value of
pthread_create
, which was not checked.
Correction — Test the Return Value of Critical
FunctionsThe correction for this defect is to check the
return value of these critical functions to verify the function performed as
expected.
#include <pthread.h>
#include <stdlib.h>
#define fatal_error() abort()
extern void *start_routine(void *);
void returnnotchecked() {
pthread_t thread_id;
pthread_attr_t attr;
void *res;
int result;
(void)pthread_attr_init(&attr);
result = pthread_create(&thread_id, &attr, &start_routine, NULL);
if (result != 0) {
/* Handle error */
fatal_error();
}
result = pthread_join(thread_id, &res);
if (result != 0) {
/* Handle error */
fatal_error();
}
}
Example — Value Returned by User Specified Function IgnoredIn this example, the function foo()
is a critical sensitive
function and the function bar()
is a sensitive function.
extern int foo(void); /* Critical */
extern int bar(void); /* Senstive */
extern void do_something(void); /* Non-critical/sensitive */
void example() {
(void)foo();//Noncompliant
int ret = bar(); //Noncompliant
do_something(); // Compliant
}
Because foo()
is a critical sensitive function, explicitly
ignoring its return value by casting to void
is a violation of
this rule.
The return value of bar()
is stored in the variable
ret
but not used or checked in the code. This ignored return
value in a violation of this rule.
To specify these two functions as critical sensitive and sensitive, create
a datalog file with this
content:
.include "models/interfaces/sensitive_function.dl"
sensitive_function.is_critical("foo").
sensitive_function.is_sensitive("bar").
When running the analysis, specify
the datalog file as an input to the option
-code-behavior-specifications
.