From a security perspective, Java's s garbage-collection feature provides significant benefits over non-garbage-collected languages such as C and C++. The garbage collector (GC) is designed to automatically reclaim unreachable memory and to avoid memory leaks. Although it the GC is quite adept at performing this task, a malicious attacker can nevertheless launch a denial-of-service (DoS) attack , for example, against the GC, such as by inducing abnormal heap memory allocation or abnormally prolonged object retention. For example, some versions of the GC may could need to halt all executing threads to keep up with incoming allocation requests that trigger increased heap management activity. System throughput rapidly diminishes in this scenario.
Real-time systems, in particular, are vulnerable to a more subtle slow-heap-exhaustion DoS attack, perpetrated by stealing CPU cycles. An attacker can perform memory allocations in a way that increases resource the consumption of resources (such as CPU, battery power, and memory) without triggering an OutOfMemoryError
. Writing garbage collection friendly -collection–friendly code helps restrict many attack avenues.
Use Short-Lived Immutable Objects
Since JDK Beginning with JDK 1.2, the generational garbage collector GC has reduced memory allocation related costs to low levels, in many cases to levels lower than in C /or C++. Generational garbage collection reduces garbage -collection costs by grouping objects into generations. The _younger generation_ consists of short-lived objects. The GC performs a minor collection on the younger generation when it fills up with dead objects \ [[Oracle 2010a|AA. Bibliography#Oracle 10a]\]. Improved garbage -collection algorithms have reduced the cost of garbage collection so that it is proportional to the number of _ live _ objects in the _ younger generation _, rather than to the _total_ number of objects allocated since the last garbage collection. Wiki Markup
Note that objects in the _ younger generation _ that persist for longer durations are _tenured_ and are moved to the _tenured generation_. Few _ younger -generation _ objects continue to live through to the next garbage -collection cycle; the rest become ready to be collected in the impending collection cycle \[[Oracle 2010a|AA. Bibliography#Oracle 10a]\]. cycle. The rest become ready to be collected in the impending collection cycle [Oracle 2010a]. Wiki Markup
With generational GCs, use of short-lived immutable objects is generally more efficient than use of long-lived mutable objects, such as object pools. Avoiding object pools improves the garbage collectorGC's efficiency. Object pools bring additional costs and risks: they can create synchronization problems , and can require explicit management of deallocations, which risks possibly creating problems with dangling pointers. Further, determining the correct amount of memory to reserve for an object pool can be difficult; , especially for mission-critical code. Use of long-lived mutable objects remains appropriate in cases where when allocation of objects is particularly expensive (for example, such as when performing multiple joins across databases). Similarly, object pools are an appropriate design choice when the objects represent scarce resources, such as thread pools and database connections. The guidelines FIO00-J. Defensively copy mutable inputs and mutable internal components and OBJ09-J. Defensively copy private mutable class members before returning their references promote GC-friendly code.
Avoid Large Objects
The allocation of large objects is expensive and , in part because the cost to initialize their fields is proportional to their size. Additionally, frequent allocation of large objects of different sizes can cause fragmentation issues or non- compacting collect operations.
Do Not Use Direct Buffers for Short Lived, Infrequently Used Objects
The new IO classes (NIO) in java.nio
allow the creation and use of direct buffers. These buffers tremendously increase throughput for repeated IO activities. However, their creation and reclamation is more expensive than that for heap-based non-direct buffers, because direct buffers are managed using OS specific native code. This added management cost makes direct buffers an poor choice for single-use or infrequently used cases. Direct buffers are also not subject to Java's garbage collector which can cause memory leaks. Frequent allocation of large direct buffers can cause an OutOfMemoryError
.
Noncompliant Code Example
This noncompliant code example uses a short-lived local object buffer
, which is allocated in non-heap memory and is not garbage collected.
Code Block | ||
---|---|---|
| ||
ByteBuffer buffer = ByteBuffer.allocateDirect(8192);
// use buffer once
|
Compliant Solution
This compliant solution uses an indirect buffer to allocate the short-lived, infrequently used object.
Code Block | ||
---|---|---|
| ||
ByteBuffer buffer = ByteBuffer.allocate(8192);
// use buffer once
|
Nulling References
Reference nulling to "help the garbage collector" is unnecessary. It adds clutter to the code and can introduce subtle bugs. Assigning null
to local variables is also unnecessary; the Java Just-In-Time compiler (JIT) can perform an equivalent liveness analysis; in fact most implementations do this. A related bad practice is use of a finalizer to null
out references; see MET18-J. Avoid using finalizers for additional details.
Noncompliant Code Example
This noncompliant code example assigns null
to the buffer
array.
Code Block | ||
---|---|---|
| ||
int[] buffer = new int[100];
doSomething(buffer);
buffer = null // No need to explicitly assign null
|
Compliant Solution
This compliant solution adds a lexical block to limit the scope of the variable {{buffer}}; the garbage collector can collect the object immediately when it goes out of scope \[[Bloch 2008|AA. Bibliography#Bloch 08]\]. Wiki Markup
Code Block | ||
---|---|---|
| ||
{ // limit the scope of buffer
int[] buffer = new int[100];
doSomething(buffer);
}
|
Array based data structures such as ArrayLists
are exceptions because the programmer may be required to explicitly set individual array elements to null
to indicate their absence.
Long-Lived Objects Containing Short-Lived Objects
Always remove short-lived objects from long-lived container objects when the task is over. For example, objects attached to a java.nio.channels.SelectionKey
object must be removed when they are no longer needed. Doing so reduces the possibility of memory leaks.
Do Not Explicitly Invoke the Garbage Collector
The garbage collector GC can be explicitly invoked by calling the System.gc()
method. Even though the documentation says that it "runs the garbage collector,", there is no guarantee as to when or whether the garbage collector GC will actually run. In fact, the call only merely suggests that the GC will should subsequently execute. Other reasons to avoid explicit invocation of the GC include:; the JVM is free to ignore this suggestion.
Irresponsible use of this feature can severely degrade system performance by triggering garbage collection at inopportune moments
...
rather than waiting until ripe periods when it is safe to garbage-collect without significant interruption of the program'
...
s execution.
In the Java Hotspot VM (default since JDK 1.2), System.gc()
forces an explicit garbage collection. Such calls can be buried deep within libraries and , so they may be difficult to trace. To ignore the call in such cases, use the flag -XX:+DisableExplicitGC
. To avoid long pauses while performing a full GCgarbage collection, a less demanding concurrent cycle may be invoked by specifying the flag -XX:ExplicitGCInvokedConcurrent
.
...
Applicability
Misusing garbage-collection utilities can cause severe performance degradation resulting in a DoS attack.
OBJ13-EX0: When an application goes through several phases, such as an initialization and a ready phase, it may could require heap compaction between phases. Given an uneventful period, The System.gc()
method may be invoked in such cases, provided that there is a suitable uneventful period occurs between phases.OBJ13-EX1: System.gc() may be invoked as a last resort in a catch
block that is attempting to recover from an OutOfMemoryError
.
Risk Assessment
Misusing some garbage collection utilities can cause Denial Of Service (DoS) related issues and severe performance degradation.
Guideline | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
OBJ11-J | low | likely | high | P3 | L3 |
Related Vulnerabilities
The Apache Geronimo and Tomcat vulnerability GERONIMO-4574, reported in March 2009, resulted from PolicyContext
handler data objects being set in a thread and never released, causing these data objects to remain in memory longer than necessary.
Bibliography
Wiki Markup |
---|
\[[API 2006|AA. Bibliography#API 06]\] Class {{System}}
\[[Bloch 2008|AA. Bibliography#Bloch 08]\] Item 6: "Eliminate obsolete object references"
\[[Commes 2007|AA. Bibliography#Commes 07]\] Garbage Collection Concepts and Programming Tips
\[[Goetz 2004|AA. Bibliography#Goetz 04]\]
\[[Lo 2005|AA. Bibliography#Lo 05]\]
\[[MITRE 2009|AA. Bibliography#MITRE 09]\] [CWE ID 405|http://cwe.mitre.org/data/definitions/405.html] "Asymmetric Resource Consumption (Amplification)" |
[API 2013] | |
Item 6, "Eliminate Obsolete Object References" | |
"Garbage Collection Concepts and Programming Tips" | |
Java Theory and Practice: Garbage Collection and Performance | |
[Lo 2005] | |
[Oracle 2010a] | Java SE 6 HotSpot™ Virtual Machine Garbage Collection Tuning |
...
OBJ10-J. Do not mix generic with non-generic raw types in new code 04. Object Orientation (OBJ) OBJ12-J. Encapsulate the absence of an object by using a Null Object