From 5ee092a1add7b79582f8dc7ea90a3afbb7dde2f1 Mon Sep 17 00:00:00 2001 From: Sheng Yang Date: Wed, 16 Nov 2011 18:33:47 -0800 Subject: [PATCH] bug 11904: Fix regression caused by OpenJDK 1.6.0 security fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It’s due to an security fix of OpenJDK 1.6.0 added by Redhat. Here is excerpt of [RHSA-2011:1380-01] Critical: java-1.6.0-openjdk security update( https://www.redhat.com/archives/rhsa-announce/2011-October/msg00011.html) A flaw was found in the way the SSL 3 and TLS 1.0 protocols used block ciphers in cipher-block chaining (CBC) mode. An attacker able to perform a chosen plain text attack against a connection mixing trusted and untrusted data could use this flaw to recover portions of the trusted data sent over the connection. (CVE-2011-3389) Note: This update mitigates the CVE-2011-3389 issue by splitting the first application data record byte to a separate SSL/TLS protocol record. This mitigation may cause compatibility issues with some SSL/TLS implementations and can be disabled using the jsse.enableCBCProtection boolean property. This can be done on the command line by appending the flag "-Djsse.enableCBCProtection=false" to the java command. To our knowledge, there are two condition need to be met to trigger this bug: 1. Using old keystore generated by mgmt. server 2.2.8, which is signed with SHA1withDSA. Any version later than 2.2.8 would generate keystore signed with SHA1withRSA. RSA one seems fine with us so far. 2. Use OpenJDK >=1.6.0. The reason is, due to the security fix above, the assumption that one packet would contain only one SSL record is broken. The decrypted data maybe only contained the first byte of original application data. Then result in buffer underflow when mgmt server want to read more from it. To workaround it, according to the message above, add "-Djsse.enableCBCProtection=false" to tomcat6.conf JAVA_OPTS line would work. Notice the parameter would only work with latest version of OpenJDK, so simply add it to the all setup would not work. This patch provided a fix for it. status 11904: resolved fixed --- utils/src/com/cloud/utils/nio/Link.java | 47 ++++++++++++++----------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/utils/src/com/cloud/utils/nio/Link.java b/utils/src/com/cloud/utils/nio/Link.java index 2b79808d106..1b473bfb501 100755 --- a/utils/src/com/cloud/utils/nio/Link.java +++ b/utils/src/com/cloud/utils/nio/Link.java @@ -275,31 +275,38 @@ public class Link { SSLSession sslSession = _sslEngine.getSession(); SSLEngineResult engResult; + int remaining = 0; - appBuf = ByteBuffer.allocate(sslSession.getApplicationBufferSize() + 40); - engResult = _sslEngine.unwrap(_readBuffer, appBuf); - if (engResult.getHandshakeStatus() != HandshakeStatus.FINISHED && - engResult.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING && - engResult.getStatus() != SSLEngineResult.Status.OK) { - throw new IOException("SSL: SSLEngine return bad result! " + engResult); + while (_readBuffer.hasRemaining()) { + remaining = _readBuffer.remaining(); + appBuf = ByteBuffer.allocate(sslSession.getApplicationBufferSize() + 40); + engResult = _sslEngine.unwrap(_readBuffer, appBuf); + if (engResult.getHandshakeStatus() != HandshakeStatus.FINISHED && + engResult.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING && + engResult.getStatus() != SSLEngineResult.Status.OK) { + throw new IOException("SSL: SSLEngine return bad result! " + engResult); + } + if (remaining == _readBuffer.remaining()) { + throw new IOException("SSL: Unable to unwrap received data! still remaining " + remaining + "bytes!"); + } + + appBuf.flip(); + if (_plaintextBuffer.remaining() < appBuf.limit()) { + // We need to expand _plaintextBuffer for more data + ByteBuffer newBuffer = ByteBuffer.allocate(_plaintextBuffer.capacity() + appBuf.limit() * 5); + _plaintextBuffer.flip(); + newBuffer.put(_plaintextBuffer); + _plaintextBuffer = newBuffer; + } + _plaintextBuffer.put(appBuf); + if (s_logger.isTraceEnabled()) { + s_logger.trace("Done with packet: " + appBuf.limit()); + } } - - appBuf.flip(); - if (_plaintextBuffer.remaining() < appBuf.limit()) { - // We need to expand _plaintextBuffer for more data - ByteBuffer newBuffer = ByteBuffer.allocate(_plaintextBuffer.capacity() + appBuf.limit() * 5); - _plaintextBuffer.flip(); - newBuffer.put(_plaintextBuffer); - _plaintextBuffer = newBuffer; - } - _plaintextBuffer.put(appBuf); + _readBuffer.clear(); _readHeader = true; - if (s_logger.isTraceEnabled()) { - s_logger.trace("Done with packet: " + appBuf.limit()); - } - if (!_gotFollowingPacket) { _plaintextBuffer.flip(); byte[] result = new byte[_plaintextBuffer.limit()];