Overview
If a functions return value is not checked, it could have
failed without any warning.
Ignoring a method's return value can cause the program to
overlook unexpected states and conditions.
Description
Just about every serious attack on a software system
begins with the violation of a programmer's assumptions.
After the attack, the programmer's assumptions seem flimsy
and poorly founded, but before an attack many programmers
would defend their assumptions well past the end of their
lunch break.
Two dubious assumptions that are easy to spot in code are
"this function call can never fail" and "it doesn't matter
if this function call fails". When a programmer ignores the
return value from a function, they implicitly state that
they are operating under one of these assumptions.
Consequences
- Integrity: The data which was produced as a result
of a function could be in a bad state.
Exposure period
Implementation: This flaw is a simple logic issue,
introduced entirely at implementation time.
Platform
Required resources
Any
Severity
High
Likelihood of
exploitation
Medium
Avoidance and mitigation
- Implementation: Check all functions which return a
value
- Implementation: When designing any function make
sure you return a value or throw an exception in case of
an error
Important and common functions will return some value
about the success of its actions. This will alert the
program whether or not to handle any errors caused by that
function
Examples
Example1
malloc(sizeof(int)*4);
Example2
Consider the following code:
char buf[10], cp_buf[10];
fgets(buf, 10, stdin);
strcpy(cp_buf, buf);
The programmer expects that when fgets() returns, buf
will contain a null-terminated string of length 9 or less.
But if an I/O error occurs, fgets() will not null-terminate
buf. Furthermore, if the end of the file is reached before
any characters are read, fgets() returns without writing
anything to buf. In both of these situations, fgets()
signals that something unusual has happened by returning
NULL, but in this code, the warning will not be noticed. The
lack of a null terminator in buf can result in a buffer
overflow in the subsequent call to strcpy().
Example3
The following code does not check to see if memory
allocation succeeded before attempting to use the pointer
returned by malloc().
buf = (char*) malloc(req_size);
strncpy(buf, xfer, req_size);
The traditional defense of this coding error is:
"If my program runs out of memory, it will fail. It
doesn't matter whether I handle the error or simply allow
the program to die with a segmentation fault when it tries
to dereference the null pointer."
This argument ignores three important considerations:
- Depending upon the type and size of the application,
it may be possible to free memory that is being used
elsewhere so that execution can continue.
- It is impossible for the program to perform a
graceful exit if required. If the program is performing
an atomic operation, it can leave the system in an
inconsistent state.
- The programmer has lost the opportunity to record
diagnostic information. Did the call to malloc() fail
because req_size was too large or because there were too
many requests being handled at the same time? Or was it
caused by a memory leak that has built up over time?
Without handling the error, there is no way to know.
Although some Java members may use return values to state
their status, it is preferable to use exceptions.