Name: jl125535 Date: 11/11/2003
FULL PRODUCT VERSION :
java version "1.4.2"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2-b28)
Java HotSpot(TM) Client VM (build 1.4.2-b28, mixed mode)
FULL OS VERSION :
Linux diskcheck 2.4.20-18.7 #1 Thu May 29 08:32:50 EDT 2003 i686 unknown
EXTRA RELEVANT SYSTEM CONFIGURATION :
Diskless (nfs root filesystem) server. It uses a stock kernel.
(uses initrd to mount root filesystem over NFS)
A DESCRIPTION OF THE PROBLEM :
On a diskless machine, which does no disk I/O, calls to SSLSocketFactory.getDefault() hang. It can be "unhung" by
1) Entering data from the console keyboard
a) hit the return key 3 times
b) hit the numlock key 3 times
c) combos of (a) and (b) (probably other keys...)
2) If a disk is attached, forcing I/O WRITE to the disk.
(just having a disk mounted isn't enough. I/O must occur)
Network I/O has no effect.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) Boot a diskless machine. (Just set it up so that it does no I/O writes
to the local disk. If that means using tmpfs filesystems for
/var/log and vmstat reports no I/O, it should work.)
2) Compile and run the program giving in the Source section.
Example:
javac SSLMinimal.java
java -classpath . SSLMinimal
It hangs until a disk write or sufficient I/O on the console keyboard occurs.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Expected result is immedate completion of the program. Output like
sslSocketFactory=com.sun.net.ssl.internal.ssl.SSLSocketFactoryImpl@1749757
ACTUAL -
System hangs until I/O occurs. After I/O, above expected result
happens.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
No error message. Process hangs.
From the jdb debugger, once the process is hanging
[1] java.io.FileInputStream.readBytes (native method)
[2] java.io.FileInputStream.read (FileInputStream.java:194)
[3] java.io.BufferedInputStream.read1 (BufferedInputStream.java:220)
[4] java.io.BufferedInputStream.read (BufferedInputStream.java:277)
[5] java.io.BufferedInputStream.fill (BufferedInputStream.java:183)
[6] java.io.BufferedInputStream.read1 (BufferedInputStream.java:222)
[7] java.io.BufferedInputStream.read (BufferedInputStream.java:277)
[8] sun.security.provider.SeedGenerator$URLSeedGenerator.getSeedByte (SeedGenerator.java:467)
[9] sun.security.provider.SeedGenerator.getSeedBytes (SeedGenerator.java:137)
[10] sun.security.provider.SeedGenerator.generateSeed (SeedGenerator.java:132)
[11] sun.security.provider.SecureRandom.engineGenerateSeed (SecureRandom.java:112)
[12] sun.security.provider.SecureRandom.engineNextBytes (SecureRandom.java:169)
[13] java.security.SecureRandom.nextBytes (SecureRandom.java:381)
[14] java.security.SecureRandom.next (SecureRandom.java:403)
[15] java.util.Random.nextInt (Random.java:191)
[16] com.sun.net.ssl.internal.ssl.SSLContextImpl.engineInit (null)
[17] com.sun.net.ssl.internal.ssl.SSLContextImpl.e (null)
[18] com.sun.net.ssl.internal.ssl.SSLSocketFactoryImpl.<init> (null)
[19] sun.reflect.NativeConstructorAccessorImpl.newInstance0 (native method)
[20] sun.reflect.NativeConstructorAccessorImpl.newInstance (NativeConstructorAccessorImpl.java:39)
[21] sun.reflect.DelegatingConstructorAccessorImpl.newInstance (DelegatingConstructorAccessorImpl.java:27)
[22] java.lang.reflect.Constructor.newInstance (Constructor.java:274)
[23] java.lang.Class.newInstance0 (Class.java:308)
[24] java.lang.Class.newInstance (Class.java:261)
[25] javax.net.ssl.SSLSocketFactory.getDefault (null)
(etc... )
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.security.Security;
import javax.net.ssl.SSLSocketFactory;
public class SSLMinimal
{
static public void main( String args[] ) throws Exception
{
try
{
SSLSocketFactory sslSocketFactory = (SSLSocketFactory)SSLSocketFactory.getDefault();
System.out.println( "sslSocketFactory="+sslSocketFactory );
}
catch ( Exception e )
{
System.out.println( e );
e.printStackTrace();
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
(initial workaround)
For the servers that make SSL connections, we have been forced to
install disks and mount them under /var/log. The idea being that
we write to the log file just before opening the socket. The output
is buffered, so it normally occurs after the call to
SSLSocketFactory.getDefault().
(revised workaround)
The workaround is to do something like the following:
stat -f /var/log/httpd | grep -i 'Type: EXT2' >/dev/null 2>&1
DISKLESS=$?
.
.
.
if (( DISKLESS > 0 )); then
OPTIONS="$OPTIONS -Djava.security.egd=file:/dev/urandom"
fi
java $OPTIONS myclass.class
------------------
Setting
java.security.egd=file:/dev/urandom
seems to solve the problem. Although it involves the possibility
of someone figuring out the random number generation, in our case
this isn't that much of a concern. /dev/urandom never blocks, and
that allows the jre to get the random number seed.
(Incident Review ID: 209774)
======================================================================
###@###.### 2003-11-11