Getty Images

Tip

What dangling pointers are and how to avoid them

Plenty of legacy systems are vulnerable to attackers looking for dangling pointers to gain unauthorized access. Learn how to identify dangling pointers and protect your network.

Dangling pointers might not create as many security issues as they used to, but this common programming error can still crash systems and present a serious threat.

Decades ago, dangling pointers were considered quality control problems, not security issues. In 2005, for example, Microsoft was alerted to a dangling pointer in Internet Information Services 5.1, but it remained unpatched for two years.

The dangling pointer issue increased as more applications connected to the internet.

Today, however, most modern software applications are developed using programming languages that use automatic memory management to prevent dangling pointers, such as C#, Java and Ruby. Yet, a host of legacy systems written in older languages are still connected to the internet and remain at risk of attack if coding errors in the software produce dangling pointers.

Read on to learn more about dangling pointers and how to avoid them.

What is a dangling pointer and how does one occur?

A pointer is a variable in programming languages that stores the memory address of another value. It references, or points to, another memory address.

Dangling pointers occur when a programmer creates, uses and then frees an object in memory but does not change the object's pointer value accordingly -- in this case, to a null pointer. Instead, the pointer inaccurately refers to the memory location of the deallocated memory. The pointer is considered "dangling" since it points to memory that might no longer hold a valid object. Because the memory might contain completely different data, unpredictable behavior can result when a programmer mistakenly dereferences the pointer to access the object.

Below is an example of code that creates a dangling pointer:

#include <stdio.h>
#include <stdlib.h>
#include <string.h> 2: void main()
{
char* name = (char *) malloc(20);
execute some code
free(name);
}

Line 5 declares a char type pointer "name" that points to a block of memory that can store 20 characters. On Line 7, the block of memory it points to is deallocated, leaving the pointer dangling. This is because it is no longer pointing to a valid memory location, which might be used for another purpose.

Note, it's not just incorrect deallocation that can cause dangling pointers; other coding errors, such as premature deallocation and functions returning a nonstatic variable, can also create them.

In 2007, experts at online risk management company Watchfire, now part of IBM, found a way to take control of dangling pointers and point them to a specific memory location. By sending a specially crafted URL to a server, researchers Jonathan Afek and Adi Sharabani discovered they could crash a target machine and run their own shellcode on it. Using this method, an attacker could remotely control or infect any machine that has a dangling pointer in one of its applications, in much the same way that an attacker could exploit a buffer overflow vulnerability.

Buffer overflow attacks can be severely damaging and effective. When an attacker meddles with computer memory, it can result in corrupted data structures, information leaks, privilege escalation and execution of malicious code.

Dangling pointers can probably be found in most mature applications, but attackers focus on any internet-connected application to provide a potential route to sensitive data or to be recruited into a botnet.

How to avoid dangling pointers

Dangling pointers are not an inherent fault in a programming language, but they can be difficult to locate since they often corrupt unrelated data or cause system instabilities long after they are created.

The bugs are most prevalent in low-level languages, such as C and C++. In higher-level languages, like Java and C#, dangling pointers cannot occur. Here, pointers are managed automatically, and implicit garbage collection occurs when an object is eliminated. Developers using languages without some form of automatic handling of pointers need to reassess their application development processes. All pointers need to be set to a null pointer after use.

Smart pointers are popular data types that can better manage memory. A smart pointer typically uses reference counting to reclaim objects. Reference-counting mechanisms calculate the smart pointers that refer to the same object, and once the count equals zero, the object is deleted.

Some other defensive measures include the tombstones method and the locks-and-keys method. Once an object is dead, an associated tombstone can automatically nullify any pointers referencing it. In a locks-and-keys scenario, pointer access is determined by comparing the two values of a pair of ordered keys. Other available products, such as Valgrind, a suite of debugging equipment, and the Boehm-Demers-Weiser garbage collector, a tool that cleans up code, also help prevent dangling pointers.

Dangling pointers are not a benign problem. Developers must adjust their software development processes to incorporate the use of static code analysis tools and memory profilers to identify uninitialized pointers and other potentially improper memory management techniques and help prevent dangling pointers from reaching production code.

Because the problem could become too serious to leave until the quality control stage, place protective measures earlier in the development lifecycle. With high-level languages, the process is relatively straightforward. But, for those developing and maintaining programs in other languages, it's important to employ the appropriate defensive measures.

Michael Cobb, CISSP-ISSAP, is a renowned security author with more than 20 years of experience in the IT industry.

Dig Deeper on Application and platform security