FULL PRODUCT VERSION :
java version "1.5.0_05"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_05-b05)
Java HotSpot(TM) Client VM (build 1.5.0_05-b05, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Linux 2.6.12-1-K7 (on Debian Sarge)
EXTRA RELEVANT SYSTEM CONFIGURATION :
(none)
A DESCRIPTION OF THE PROBLEM :
Summary:
A deleteOnFile() invocation against the java.io.File object that stores a file name that could be longer than 4096 bytes (equal to PATH_MAX ??) when it gets decoded to the filesystem's encoding, causes severe memory corruption on Java VM termination, which leads to a bus error, or a segmentation fault. You can reproduce the exact problem with the attached code.
Technical Detail:
As far as I can tell from the result of reverse-engineering (I did not ever access to the source code), deleteOnExit() internally allocates the following structure by malloc() C-library function, fills the content of "buf" field with strcpy() ing the file name, and builds a linked list to use it in "onExit" handler:
struct OnExitHandler {
struct OnExitHandler *nextHandler;
void(*callback)(void *param);
char buf[4096];
}
If this is the case, a buffer overflow that eventually induces a heap corruption can occur if the name of the file being associated to the structure is long enough to exceed the size of buf[] field. Since the structure is allocated in its exact size and the implementation of malloc() used here is publicly available, this flaw is easily exploitable to gain a shell, etc.
IMPACT:
Any program that takes an arbitrary file name from the user input to finally destroy it with deleteOnExit() is extremely vulnerable. For instance, an attacker can submit a malicious request to a web application that stores uploaded files to a temporary directory with the same file names given in the request.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile & run the attached code.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
(None happens)
ACTUAL -
(Received SIGABRT signal)
ERROR MESSAGES/STACK TRACES THAT OCCUR :
*** glibc detected *** free(): invalid next size (normal): 0x080c8038 ***
Aborted
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.io.File;
public class J2SEVulnerabilityTest
{
private static final int PATH_MAX = 4096;
private static String generateArbitraryLengthOfString(int n) {
StringBuffer buf = new StringBuffer(n);
while (--n >= 0) {
buf.append('#');
}
return buf.toString();
}
public static void main(String[] args) {
File f = new File(generateArbitraryLengthOfString(PATH_MAX + 512));
f.deleteOnExit();
}
}
---------- END SOURCE ----------

Comments

EVALUATION
DeleteOnExitTest.java can still crash JVMs on 1.4.2_11 and 1.5.0_u6, on Solaris and Linux.