...
Noncompliant Code Example
This noncompliant code example can be found in {{ Wiki Markup 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.unmigrated-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
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. Wiki Markup
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
EXP34-C | high | likely | medium | P18 | L1 |
...
Tool | Version | Checker | Description | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
|
| ||||||||||||
|
|
|
| ||||||||||||
|
|
|
| ||||||||||||
|
|
|
| ||||||||||||
|
|
|
| ||||||||||||
|
|
|
| ||||||||||||
|
|
|
| ||||||||||||
|
|
|
| ||||||||||||
|
|
|
|
...
MITRE CWE: CWE-476, "NULL Pointer Dereference"
Bibliography
\[[Goodin 2009|AA. Bibliography#Goodin 2009]\]
\[ Wiki Markup
[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 ]
[Liu 2009]
[van Sprundel 2006]
[Viega 2005] 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