Attempting to dereference a null pointer results in undefined behavior, typically abnormal program termination.
Noncompliant Code Example
In this noncompliant code example, input_str
is copied into dynamically allocated memory referenced by str
. If malloc()
fails, it returns a null pointer that is assigned to str
. When str
is dereferenced in memcpy()
, the program behaves in an unpredictable manner.
Code Block |
---|
|
size_t size = strlen(input_str)+1;
str = (char *)malloc(size);
memcpy(str, input_str, size);
/* ... */
free(str);
str = NULL;
|
Compliant Solution
To correct this error, ensure the pointer returned by malloc()
is not null. This also ensures compliance with rule MEM32-C. Detect and handle memory allocation errors.
Code Block |
---|
|
size_t size = strlen(input_str)+1;
str = (char *)malloc(size);
if (str == NULL) {
/* Handle Allocation Error */
}
memcpy(str, input_str, size);
/* ... */
free(str);
str = NULL;
|
Noncompliant Code Example
Wiki Markup |
---|
This noncompliant code example can be found in {{drivers/net/tun.c}} and affects Linux kernel 2.6.30 \[[Goodin 2009|AA. Bibliography#Goodin 2009]\]. |
Code Block |
---|
|
static unsigned int tun_chr_poll(struct file *file, poll_table * wait) {
struct tun_file *tfile = file->private_data;
struct tun_struct *tun = __tun_get(tfile);
struct sock *sk = tun->sk;
unsigned int mask = 0;
if (!tun)
return POLLERR;
DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name);
poll_wait(file, &tun->socket.wait, wait);
if (!skb_queue_empty(&tun->readq))
mask |= POLLIN | POLLRDNORM;
if (sock_writeable(sk) ||
(!test_and_set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags) &&
sock_writeable(sk)))
mask |= POLLOUT | POLLWRNORM;
if (tun->dev->reg_state != NETREG_REGISTERED)
mask = POLLERR;
tun_put(tun);
return mask;
}
|
The vulnerability occurs because sk
is initialized to tun->sk
before checking if tun
is equal to NULL
. Of course, this should be done first because the GCC compiler (in this case) optimizes it and completely removes the if (!tun)
check because it is performed after the assignment. As a result, the above vulnerability can result in a null pointer dereference exploit.
Wiki Markup |
---|
Normally, null pointer dereference results in access violation and abnormal program termination. However, it is possible to permit null pointer dereferencing on several operating systems, for example, using {{mmap(2)}} with the {{MAP_FIXED}} flag on Linux and Mac OS X or using {{shmat(2)}} with the {{SHM_RND}} flag on Linux \[[Liu 2009|AA. Bibliography#Liu 2009]\]. |
Compliant Solution
This compliant solution eliminates the null pointer deference by initializing sk
to tun->sk
following the null pointer check.
Code Block |
---|
|
static unsigned int tun_chr_poll(struct file *file, poll_table * wait) {
struct tun_file *tfile = file->private_data;
struct tun_struct *tun = __tun_get(tfile);
struct sock *sk;
unsigned int mask = 0;
if (!tun)
return POLLERR;
sk = tun->sk;
DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name);
poll_wait(file, &tun->socket.wait, wait);
if (!skb_queue_empty(&tun->readq))
mask |= POLLIN | POLLRDNORM;
if (sock_writeable(sk) ||
(!test_and_set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags) &&
sock_writeable(sk)))
mask |= POLLOUT | POLLWRNORM;
if (tun->dev->reg_state != NETREG_REGISTERED)
mask = POLLERR;
tun_put(tun);
return mask;
}
|
Risk Assessment
Wiki Markup |
---|
Dereferencing a null pointer results in undefined behavior, typically abnormal program termination. In some situations, however, dereferencing a null pointer can lead to the execution of arbitrary code \[[Jack 2007|AA. Bibliography#Jack 07], [van Sprundel 2006|AA. Bibliography#van Sprundel 06]\]. The indicated severity is for this more severe case; on platforms where it is not possible to exploit a null pointer dereference to execute arbitrary code, the actual severity is low. |
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|
EXP34-C | high | likely | medium | P18 | L1 |
Automated Detection
Tool | Version | Checker | Description |
---|
| | | |
| | | |
| | | |
| | | Section |
---|
can detect violations of this rule. In particular, Rose ensures that any pointer returned by malloc() , calloc() , or realloc() is first checked for NULL before being used (otherwise it is free() -d). Rose does not handle cases where an allocation is assigned to an lvalue that is not a variable (such as a struct member or C++ function call returning a reference.) |
|
| | | Section |
---|
finds instances where a pointer is checked against NULL and then later dereferenced. |
|
| | | Section |
---|
identifies functions that can return a null pointer but are not checked. |
|
| | | Section |
---|
identifies code that dereferences a pointer and then checks the pointer against NULL . |
|
| | | Section |
---|
can find the instances where NULL is explicitly dereferenced or a pointer is checked against null but then dereferenced anyway. Coverity Prevent cannot discover all violations of this rule, so further verification is necessary. |
|
| | | |
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
CERT C++ Secure Coding Standard: EXP34-CPP. Ensure a null pointer is not dereferenced
The CERT Oracle Secure Coding Standard for Java: EXP01-J. Never dereference null pointers
ISO/IEC 9899:1999 Section 6.3.2.3, "Pointers"
ISO/IEC TR 24772 "HFC Pointer casting and pointer type changes" and "XYH Null Pointer Dereference"
MITRE CWE: CWE-476, "NULL Pointer Dereference"
Bibliography
Wiki Markup |
---|
\[[Goodin 2009|AA. Bibliography#Goodin 2009]\]
\[[Jack 2007|AA. Bibliography#Jack 07]\]
\[[Liu 2009|AA. Bibliography#Liu 2009]\]
\[[van Sprundel 2006|AA. Bibliography#van Sprundel 06]\]
\[[Viega 2005|AA. Bibliography#Viega 05]\] Section 5.2.18, "Null-pointer dereference" |
EXP33-C. Do not reference uninitialized memory 03. Expressions (EXP) EXP35-C. Do not access or modify an array in the result of a function call after a subsequent sequence point