Repository: mina-sshd Updated Branches: refs/heads/master 389a1ecbd -> 3b1342efc
[SSHD-701] IllegalArgumentException processing SSH_MSG_CHANNEL_OPEN_CONFIRMATION with initial window size of -1 Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/3b1342ef Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/3b1342ef Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/3b1342ef Branch: refs/heads/master Commit: 3b1342efc0c96af88968320a59606ca0b1043523 Parents: 389a1ec Author: Lyor Goldstein <[email protected]> Authored: Tue Sep 27 20:02:05 2016 +0300 Committer: Lyor Goldstein <[email protected]> Committed: Tue Sep 27 20:02:05 2016 +0300 ---------------------------------------------------------------------- .../sshd/agent/local/AgentForwardedChannel.java | 8 +- .../agent/local/ChannelAgentForwarding.java | 7 +- .../sshd/agent/unix/AgentForwardedChannel.java | 5 +- .../sshd/agent/unix/ChannelAgentForwarding.java | 7 +- .../client/channel/AbstractClientChannel.java | 20 ++-- .../sshd/client/channel/ChannelDirectTcpip.java | 7 +- .../sshd/client/channel/ChannelSession.java | 5 +- .../org/apache/sshd/common/FactoryManager.java | 16 ++- .../sshd/common/channel/AbstractChannel.java | 24 +++-- .../org/apache/sshd/common/channel/Channel.java | 12 +-- .../channel/ChannelAsyncOutputStream.java | 12 ++- .../common/channel/ChannelOutputStream.java | 36 ++++--- .../org/apache/sshd/common/channel/Window.java | 68 ++++++------ .../sshd/common/forward/TcpipClientChannel.java | 8 +- .../helpers/AbstractConnectionService.java | 8 +- .../apache/sshd/common/util/buffer/Buffer.java | 1 + .../sshd/common/util/buffer/BufferUtils.java | 51 ++++++++- .../server/channel/AbstractServerChannel.java | 4 +- .../sshd/server/channel/ChannelSession.java | 13 ++- .../sshd/server/forward/TcpipServerChannel.java | 11 +- .../sshd/server/x11/ChannelForwardedX11.java | 6 +- .../java/org/apache/sshd/client/ClientTest.java | 2 +- .../sshd/common/channel/WindowInitTest.java | 107 +++++++++++++++++++ .../apache/sshd/common/channel/WindowTest.java | 2 +- .../sshd/common/channel/WindowTimeoutTest.java | 12 +-- .../org/apache/sshd/util/test/BogusChannel.java | 10 +- 26 files changed, 336 insertions(+), 126 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentForwardedChannel.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentForwardedChannel.java b/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentForwardedChannel.java index 9a33990..18ae890 100644 --- a/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentForwardedChannel.java +++ b/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentForwardedChannel.java @@ -94,15 +94,17 @@ public class AgentForwardedChannel extends AbstractClientChannel { } @Override - protected void doWriteData(byte[] data, int off, int len) throws IOException { + protected void doWriteData(byte[] data, int off, long len) throws IOException { + ValidateUtils.checkTrue(len <= Integer.MAX_VALUE, "Data length exceeds int boundaries: %d", len); + Buffer message = null; synchronized (receiveBuffer) { - receiveBuffer.putBuffer(new ByteArrayBuffer(data, off, len)); + receiveBuffer.putBuffer(new ByteArrayBuffer(data, off, (int) len)); if (receiveBuffer.available() >= 4) { off = receiveBuffer.rpos(); len = receiveBuffer.getInt(); receiveBuffer.rpos(off); - if (receiveBuffer.available() >= 4 + len) { + if (receiveBuffer.available() >= (4 + len)) { message = new ByteArrayBuffer(receiveBuffer.getBytes()); receiveBuffer.compact(); } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java b/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java index c8e6395..66844af 100644 --- a/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java +++ b/sshd-core/src/main/java/org/apache/sshd/agent/local/ChannelAgentForwarding.java @@ -106,12 +106,13 @@ public class ChannelAgentForwarding extends AbstractServerChannel { } @Override - protected void doWriteData(byte[] data, int off, int len) throws IOException { - client.messageReceived(new ByteArrayBuffer(data, off, len)); + protected void doWriteData(byte[] data, int off, long len) throws IOException { + ValidateUtils.checkTrue(len <= Integer.MAX_VALUE, "Data length exceeds int boundaries: %d", len); + client.messageReceived(new ByteArrayBuffer(data, off, (int) len)); } @Override - protected void doWriteExtendedData(byte[] data, int off, int len) throws IOException { + protected void doWriteExtendedData(byte[] data, int off, long len) throws IOException { throw new UnsupportedOperationException("AgentForward channel does not support extended data"); } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentForwardedChannel.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentForwardedChannel.java b/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentForwardedChannel.java index f2897c2..88fae33 100644 --- a/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentForwardedChannel.java +++ b/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentForwardedChannel.java @@ -74,11 +74,12 @@ public class AgentForwardedChannel extends AbstractClientChannel implements Runn } @Override - protected synchronized void doWriteData(byte[] data, int off, int len) throws IOException { + protected synchronized void doWriteData(byte[] data, int off, long len) throws IOException { + ValidateUtils.checkTrue(len <= Integer.MAX_VALUE, "Data length exceeds int boundaries: %d", len); Window wLocal = getLocalWindow(); wLocal.consumeAndCheck(len); - int result = Socket.send(socket, data, off, len); + int result = Socket.send(socket, data, off, (int) len); if (result < Status.APR_SUCCESS) { AgentServerProxy.throwException(result); } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/agent/unix/ChannelAgentForwarding.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/unix/ChannelAgentForwarding.java b/sshd-core/src/main/java/org/apache/sshd/agent/unix/ChannelAgentForwarding.java index e87b5e0..ecafc34 100644 --- a/sshd-core/src/main/java/org/apache/sshd/agent/unix/ChannelAgentForwarding.java +++ b/sshd-core/src/main/java/org/apache/sshd/agent/unix/ChannelAgentForwarding.java @@ -174,15 +174,16 @@ public class ChannelAgentForwarding extends AbstractServerChannel { } @Override - protected void doWriteData(byte[] data, int off, int len) throws IOException { - int result = Socket.send(handle, data, off, len); + protected void doWriteData(byte[] data, int off, long len) throws IOException { + ValidateUtils.checkTrue(len <= Integer.MAX_VALUE, "Data length exceeds int boundaries: %d", len); + int result = Socket.send(handle, data, off, (int) len); if (result < Status.APR_SUCCESS) { throwException(result); } } @Override - protected void doWriteExtendedData(byte[] data, int off, int len) throws IOException { + protected void doWriteExtendedData(byte[] data, int off, long len) throws IOException { throw new UnsupportedOperationException("AgentForward channel does not support extended data"); } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java index a83dfeb..86d42d1 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java @@ -314,12 +314,12 @@ public abstract class AbstractClientChannel extends AbstractChannel implements C } @Override - public OpenFuture open(int recipient, int rwSize, int packetSize, Buffer buffer) { + public OpenFuture open(int recipient, long rwSize, long packetSize, Buffer buffer) { throw new UnsupportedOperationException("open(" + recipient + "," + rwSize + "," + packetSize + ") N/A"); } @Override - public void handleOpenSuccess(int recipient, int rwSize, int packetSize, Buffer buffer) { + public void handleOpenSuccess(int recipient, long rwSize, long packetSize, Buffer buffer) { setRecipient(recipient); Session session = getSession(); @@ -387,15 +387,17 @@ public abstract class AbstractClientChannel extends AbstractChannel implements C } @Override - protected void doWriteData(byte[] data, int off, int len) throws IOException { + protected void doWriteData(byte[] data, int off, long len) throws IOException { // If we're already closing, ignore incoming data if (isClosing()) { return; } + ValidateUtils.checkTrue(len <= Integer.MAX_VALUE, "Data length exceeds int boundaries: %d", len); + if (asyncOut != null) { - asyncOut.write(new ByteArrayBuffer(data, off, len)); + asyncOut.write(new ByteArrayBuffer(data, off, (int) len)); } else if (out != null) { - out.write(data, off, len); + out.write(data, off, (int) len); out.flush(); if (invertedOut == null) { @@ -408,15 +410,17 @@ public abstract class AbstractClientChannel extends AbstractChannel implements C } @Override - protected void doWriteExtendedData(byte[] data, int off, int len) throws IOException { + protected void doWriteExtendedData(byte[] data, int off, long len) throws IOException { // If we're already closing, ignore incoming data if (isClosing()) { return; } + ValidateUtils.checkTrue(len <= Integer.MAX_VALUE, "Extended data length exceeds int boundaries: %d", len); + if (asyncErr != null) { - asyncErr.write(new ByteArrayBuffer(data, off, len)); + asyncErr.write(new ByteArrayBuffer(data, off, (int) len)); } else if (err != null) { - err.write(data, off, len); + err.write(data, off, (int) len); err.flush(); if (invertedErr == null) { http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java index 0813142..0a077c2 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelDirectTcpip.java @@ -33,6 +33,7 @@ import org.apache.sshd.common.channel.ChannelPipedInputStream; import org.apache.sshd.common.channel.ChannelPipedOutputStream; import org.apache.sshd.common.channel.Window; import org.apache.sshd.common.session.Session; +import org.apache.sshd.common.util.ValidateUtils; import org.apache.sshd.common.util.buffer.Buffer; import org.apache.sshd.common.util.net.SshdSocketAddress; @@ -108,12 +109,12 @@ public class ChannelDirectTcpip extends AbstractClientChannel { } @Override - protected void doWriteData(byte[] data, int off, int len) throws IOException { - pipe.write(data, off, len); + protected void doWriteData(byte[] data, int off, long len) throws IOException { + ValidateUtils.checkTrue(len <= Integer.MAX_VALUE, "Data length exceeds int boundaries: %d", len); + pipe.write(data, off, (int) len); pipe.flush(); Window wLocal = getLocalWindow(); wLocal.consumeAndCheck(len); } - } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelSession.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelSession.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelSession.java index e76aab4..459a659 100644 --- a/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelSession.java +++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/ChannelSession.java @@ -33,6 +33,7 @@ import org.apache.sshd.common.channel.RequestHandler; import org.apache.sshd.common.channel.Window; import org.apache.sshd.common.future.CloseFuture; import org.apache.sshd.common.session.Session; +import org.apache.sshd.common.util.ValidateUtils; import org.apache.sshd.common.util.buffer.Buffer; import org.apache.sshd.common.util.threads.ThreadUtils; @@ -158,7 +159,9 @@ public class ChannelSession extends AbstractClientChannel { try { Session session = getSession(); Window wRemote = getRemoteWindow(); - byte[] buffer = new byte[wRemote.getPacketSize()]; + long packetSize = wRemote.getPacketSize(); + ValidateUtils.checkTrue(packetSize < Integer.MAX_VALUE, "Remote packet size exceeds int boundary: %d", packetSize); + byte[] buffer = new byte[(int) packetSize]; while (!closeFuture.isClosed()) { int len = securedRead(in, buffer, 0, buffer.length); if (len < 0) { http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java index ea3ad86..800473a 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java @@ -62,7 +62,7 @@ public interface FactoryManager /** * Default {@link #WINDOW_SIZE} if none set */ - int DEFAULT_WINDOW_SIZE = 0x200000; + long DEFAULT_WINDOW_SIZE = 0x200000L; // actually a UINT32 /** * Key used to retrieve timeout (msec.) to wait for data to @@ -87,7 +87,19 @@ public interface FactoryManager /** * Default {@link #MAX_PACKET_SIZE} if none set */ - int DEFAULT_MAX_PACKET_SIZE = 0x8000; + long DEFAULT_MAX_PACKET_SIZE = 0x8000L; // actually a UINT32 + + /** + * A safety value that is designed to avoid an attack that + * uses large channel packet sizes + * @see #DEFAULT_LIMIT_PACKET_SIZE + */ + String LIMIT_PACKET_SIZE = "max-packet-size"; + + /** + * Default {@link #LIMIT_PACKET_SIZE} if none set + */ + long DEFAULT_LIMIT_PACKET_SIZE = Integer.MAX_VALUE / 4L; /** * Number of NIO worker threads to use. http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java b/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java index d611d1d..89f84af 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java @@ -633,13 +633,13 @@ public abstract class AbstractChannel @Override public void handleData(Buffer buffer) throws IOException { - int len = validateIncomingDataSize(SshConstants.SSH_MSG_CHANNEL_DATA, buffer.getInt()); + long len = validateIncomingDataSize(SshConstants.SSH_MSG_CHANNEL_DATA, buffer.getUInt()); if (log.isDebugEnabled()) { log.debug("handleData({}) SSH_MSG_CHANNEL_DATA len={}", this, len); } if (log.isTraceEnabled()) { BufferUtils.dumpHex(getSimplifiedLogger(), BufferUtils.DEFAULT_HEXDUMP_LEVEL, "handleData(" + this + ")", - this, BufferUtils.DEFAULT_HEX_SEPARATOR, buffer.array(), buffer.rpos(), len); + this, BufferUtils.DEFAULT_HEX_SEPARATOR, buffer.array(), buffer.rpos(), (int) len); } if (isEofSignalled()) { // TODO consider throwing an exception @@ -663,13 +663,13 @@ public abstract class AbstractChannel return; } - int len = validateIncomingDataSize(SshConstants.SSH_MSG_CHANNEL_EXTENDED_DATA, buffer.getInt()); + long len = validateIncomingDataSize(SshConstants.SSH_MSG_CHANNEL_EXTENDED_DATA, buffer.getUInt()); if (log.isDebugEnabled()) { log.debug("handleExtendedData({}) SSH_MSG_CHANNEL_EXTENDED_DATA len={}", this, len); } if (log.isTraceEnabled()) { BufferUtils.dumpHex(getSimplifiedLogger(), BufferUtils.DEFAULT_HEXDUMP_LEVEL, "handleExtendedData(" + this + ")", - this, BufferUtils.DEFAULT_HEX_SEPARATOR, buffer.array(), buffer.rpos(), len); + this, BufferUtils.DEFAULT_HEX_SEPARATOR, buffer.array(), buffer.rpos(), (int) len); } if (isEofSignalled()) { // TODO consider throwing an exception @@ -678,7 +678,11 @@ public abstract class AbstractChannel doWriteExtendedData(buffer.array(), buffer.rpos(), len); } - protected int validateIncomingDataSize(int cmd, int len) { + protected long validateIncomingDataSize(int cmd, long len /* actually a uint32 */) { + if (!BufferUtils.isValidUint32Value(len)) { + throw new IllegalArgumentException("Non UINT32 length (" + len + ") for command=" + SshConstants.getCommandMessageName(cmd)); + } + /* * According to RFC 4254 section 5.1 * @@ -689,13 +693,13 @@ public abstract class AbstractChannel * should send at most */ Window wLocal = getLocalWindow(); - int maxLocalSize = wLocal.getPacketSize(); + long maxLocalSize = wLocal.getPacketSize(); /* * The reason for the +4 is that there seems to be some confusion whether * the max. packet size includes the length field or not */ - if ((len < 0) || (len > (maxLocalSize + 4))) { + if (len > (maxLocalSize + 4L)) { throw new IllegalStateException("Bad length (" + len + ") " + " for cmd=" + SshConstants.getCommandMessageName(cmd) + " - max. allowed=" + maxLocalSize); @@ -748,9 +752,9 @@ public abstract class AbstractChannel // TODO: do something to report failed requests? } - protected abstract void doWriteData(byte[] data, int off, int len) throws IOException; + protected abstract void doWriteData(byte[] data, int off, long len) throws IOException; - protected abstract void doWriteExtendedData(byte[] data, int off, int len) throws IOException; + protected abstract void doWriteExtendedData(byte[] data, int off, long len) throws IOException; protected void sendEof() throws IOException { if (eofSent.getAndSet(true)) { @@ -815,7 +819,7 @@ public abstract class AbstractChannel localWindow.init(this); } - protected void sendWindowAdjust(int len) throws IOException { + protected void sendWindowAdjust(long len) throws IOException { if (log.isDebugEnabled()) { log.debug("sendWindowAdjust({}) SSH_MSG_CHANNEL_WINDOW_ADJUST len={}", this, len); } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/common/channel/Channel.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/channel/Channel.java b/sshd-core/src/main/java/org/apache/sshd/common/channel/Channel.java index dab6f72..dae79a0 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/channel/Channel.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/channel/Channel.java @@ -154,30 +154,30 @@ public interface Channel * For a server channel, this method will actually open the channel * * @param recipient Recipient identifier - * @param rwSize Read/Write window size - * @param packetSize Preferred maximum packet size + * @param rwSize Read/Write window size ({@code uint32}) + * @param packetSize Preferred maximum packet size ({@code uint32}) * @param buffer Incoming {@link Buffer} that triggered the call. * <B>Note:</B> the buffer's read position is exactly * <U>after</U> the information that read to this call * was decoded * @return An {@link OpenFuture} for the channel open request */ - OpenFuture open(int recipient, int rwSize, int packetSize, Buffer buffer); + OpenFuture open(int recipient, long rwSize, long packetSize, Buffer buffer); /** * For a client channel, this method will be called internally by the * session when the confirmation has been received. * * @param recipient Recipient identifier - * @param rwSize Read/Write window size - * @param packetSize Preferred maximum packet size + * @param rwSize Read/Write window size ({@code uint32}) + * @param packetSize Preferred maximum packet size ({@code uint32}) * @param buffer Incoming {@link Buffer} that triggered the call. * <B>Note:</B> the buffer's read position is exactly * <U>after</U> the information that read to this call * was decoded * @throws IOException If failed to handle the success */ - void handleOpenSuccess(int recipient, int rwSize, int packetSize, Buffer buffer) throws IOException; + void handleOpenSuccess(int recipient, long rwSize, long packetSize, Buffer buffer) throws IOException; /** * For a client channel, this method will be called internally by the http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelAsyncOutputStream.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelAsyncOutputStream.java b/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelAsyncOutputStream.java index 7305937..668751b 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelAsyncOutputStream.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelAsyncOutputStream.java @@ -85,7 +85,7 @@ public class ChannelAsyncOutputStream extends AbstractCloseable implements IoOut if (total > 0) { Channel channel = getChannel(); Window remoteWindow = channel.getRemoteWindow(); - final int length = Math.min(Math.min(remoteWindow.getSize(), total), remoteWindow.getPacketSize()); + long length = Math.min(Math.min(remoteWindow.getSize(), total), remoteWindow.getPacketSize()); if (log.isTraceEnabled()) { log.trace("doWriteIfPossible({})[resume={}] attempting to write {} out of {}", this, resume, length, total); } @@ -97,15 +97,19 @@ public class ChannelAsyncOutputStream extends AbstractCloseable implements IoOut } } + if (length >= (Integer.MAX_VALUE - 12)) { + throw new IllegalArgumentException("Command " + SshConstants.getCommandMessageName(cmd) + " length (" + length + " exceeds int boundaries"); + } Session s = channel.getSession(); - Buffer buf = s.createBuffer(cmd, length + 12); + + Buffer buf = s.createBuffer(cmd, (int) length + 12); buf.putInt(channel.getRecipient()); if (cmd == SshConstants.SSH_MSG_CHANNEL_EXTENDED_DATA) { buf.putInt(SshConstants.SSH_EXTENDED_DATA_STDERR); } buf.putInt(length); - buf.putRawBytes(buffer.array(), buffer.rpos(), length); - buffer.rpos(buffer.rpos() + length); + buf.putRawBytes(buffer.array(), buffer.rpos(), (int) length); + buffer.rpos(buffer.rpos() + (int) length); remoteWindow.consume(length); try { final ChannelAsyncOutputStream stream = this; http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelOutputStream.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelOutputStream.java b/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelOutputStream.java index a8f2f7d..91e192c 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelOutputStream.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelOutputStream.java @@ -21,6 +21,7 @@ package org.apache.sshd.common.channel; import java.io.IOException; import java.io.InterruptedIOException; import java.io.OutputStream; +import java.io.StreamCorruptedException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -113,14 +114,14 @@ public class ChannelOutputStream extends OutputStream implements java.nio.channe // packet we sent to allow the producer to race ahead and fill // out the next packet before we block and wait for space to // become available again. - int l2 = Math.min(l, Math.min(remoteWindow.getSize() + lastSize, remoteWindow.getPacketSize()) - bufferLength); + long l2 = Math.min(l, Math.min(remoteWindow.getSize() + lastSize, remoteWindow.getPacketSize()) - bufferLength); if (l2 <= 0) { if (bufferLength > 0) { flush(); } else { session.resetIdleTimeout(); try { - int available = remoteWindow.waitForSpace(maxWaitTimeout); + long available = remoteWindow.waitForSpace(maxWaitTimeout); if (log.isTraceEnabled()) { log.trace("write({}) len={} - available={}", this, l, available); } @@ -144,7 +145,9 @@ public class ChannelOutputStream extends OutputStream implements java.nio.channe session.resetIdleTimeout(); continue; } - buffer.putRawBytes(buf, s, l2); + + ValidateUtils.checkTrue(l2 <= Integer.MAX_VALUE, "Accumulated bytes length exceeds int boundary: %d", l2); + buffer.putRawBytes(buf, s, (int) l2); bufferLength += l2; s += l2; l -= l2; @@ -170,8 +173,8 @@ public class ChannelOutputStream extends OutputStream implements java.nio.channe session.resetIdleTimeout(); Buffer buf = buffer; - int total = bufferLength; - int available; + long total = bufferLength; + long available; try { available = remoteWindow.waitForSpace(maxWaitTimeout); if (log.isTraceEnabled()) { @@ -186,21 +189,26 @@ public class ChannelOutputStream extends OutputStream implements java.nio.channe throw e; } - int lenToSend = Math.min(available, total); - int length = Math.min(lenToSend, remoteWindow.getPacketSize()); + long lenToSend = Math.min(available, total); + long length = Math.min(lenToSend, remoteWindow.getPacketSize()); + if (length > Integer.MAX_VALUE) { + throw new StreamCorruptedException("Accumulated " + SshConstants.getCommandMessageName(cmd) + + " command bytes size (" + length + ") exceeds int boundaries"); + } + int pos = buf.wpos(); buf.wpos((cmd == SshConstants.SSH_MSG_CHANNEL_EXTENDED_DATA) ? 14 : 10); buf.putInt(length); - buf.wpos(buf.wpos() + length); + buf.wpos(buf.wpos() + (int) length); if (total == length) { - newBuffer(length); + newBuffer((int) length); } else { - int leftover = total - length; - newBuffer(Math.max(leftover, length)); - buffer.putRawBytes(buf.array(), pos - leftover, leftover); - bufferLength = leftover; + long leftover = total - length; + newBuffer((int) Math.max(leftover, length)); + buffer.putRawBytes(buf.array(), pos - (int) leftover, (int) leftover); + bufferLength = (int) leftover; } - lastSize = length; + lastSize = (int) length; session.resetIdleTimeout(); remoteWindow.waitAndConsume(length, maxWaitTimeout); http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java b/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java index 0ca48ef..3117f40 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java @@ -25,13 +25,14 @@ import java.util.Collections; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.function.Predicate; import org.apache.sshd.common.FactoryManager; import org.apache.sshd.common.PropertyResolver; import org.apache.sshd.common.PropertyResolverUtils; import org.apache.sshd.common.util.ValidateUtils; +import org.apache.sshd.common.util.buffer.BufferUtils; import org.apache.sshd.common.util.logging.AbstractLoggingBean; /** @@ -54,13 +55,13 @@ public class Window extends AbstractLoggingBean implements java.nio.channels.Cha private final AtomicBoolean closed = new AtomicBoolean(false); private final AtomicBoolean initialized = new AtomicBoolean(false); - private final AtomicInteger sizeHolder = new AtomicInteger(0); + private final AtomicLong sizeHolder = new AtomicLong(0L); private final AbstractChannel channelInstance; private final Object lock; private final String suffix; - private int maxSize; - private int packetSize; + private long maxSize; // actually uint32 + private long packetSize; // actually uint32 private Map<String, Object> props = Collections.emptyMap(); public Window(AbstractChannel channel, Object lock, boolean client, boolean local) { @@ -84,29 +85,34 @@ public class Window extends AbstractLoggingBean implements java.nio.channels.Cha return channelInstance; } - public int getSize() { + public long getSize() { synchronized (lock) { return sizeHolder.get(); } } - public int getMaxSize() { + public long getMaxSize() { return maxSize; } - public int getPacketSize() { + public long getPacketSize() { return packetSize; } public void init(PropertyResolver resolver) { - init(PropertyResolverUtils.getIntProperty(resolver, FactoryManager.WINDOW_SIZE, FactoryManager.DEFAULT_WINDOW_SIZE), - PropertyResolverUtils.getIntProperty(resolver, FactoryManager.MAX_PACKET_SIZE, FactoryManager.DEFAULT_MAX_PACKET_SIZE), + init(PropertyResolverUtils.getLongProperty(resolver, FactoryManager.WINDOW_SIZE, FactoryManager.DEFAULT_WINDOW_SIZE), + PropertyResolverUtils.getLongProperty(resolver, FactoryManager.MAX_PACKET_SIZE, FactoryManager.DEFAULT_MAX_PACKET_SIZE), resolver.getProperties()); } - public void init(int size, int packetSize, Map<String, Object> props) { - ValidateUtils.checkTrue(size >= 0, "Illegal initial size: %d", size); - ValidateUtils.checkTrue(packetSize > 0, "Illegal packet size: %d", packetSize); + public void init(long size, long packetSize, Map<String, Object> props) { + BufferUtils.validateUint32Value(size, "Illegal initial size: %d"); + BufferUtils.validateUint32Value(packetSize, "Illegal packet size: %d"); + ValidateUtils.checkTrue(packetSize > 0L, "Packet size must be positive: %d", packetSize); + long limitPacketSize = PropertyResolverUtils.getLongProperty(props, FactoryManager.LIMIT_PACKET_SIZE, FactoryManager.DEFAULT_LIMIT_PACKET_SIZE); + if (packetSize > limitPacketSize) { + throw new IllegalArgumentException("Requested packet size (" + packetSize + ") exceeds max. allowed: " + limitPacketSize); + } synchronized (lock) { this.maxSize = size; @@ -138,10 +144,10 @@ public class Window extends AbstractLoggingBean implements java.nio.channels.Cha * 2^32 - 1 bytes. */ expandedSize = sizeHolder.get() + window; - if (expandedSize > Integer.MAX_VALUE) { - updateSize(Integer.MAX_VALUE); + if (expandedSize > BufferUtils.MAX_UINT32_VALUE) { + updateSize(BufferUtils.MAX_UINT32_VALUE); } else { - updateSize((int) expandedSize); + updateSize(expandedSize); } } @@ -152,19 +158,19 @@ public class Window extends AbstractLoggingBean implements java.nio.channels.Cha } } - public void consume(int len) { - ValidateUtils.checkTrue(len >= 0, "Negative consumption length: %d", len); + public void consume(long len) { + BufferUtils.validateUint32Value(len, "Invalid consumption length: %d"); checkInitialized("consume"); - int remainLen; + long remainLen; synchronized (lock) { remainLen = sizeHolder.get() - len; - if (remainLen >= 0) { + if (remainLen >= 0L) { updateSize(remainLen); } } - if (remainLen < 0) { + if (remainLen < 0L) { throw new IllegalStateException("consume(" + this + ") required length (" + len + ") above available: " + (remainLen + len)); } @@ -173,7 +179,7 @@ public class Window extends AbstractLoggingBean implements java.nio.channels.Cha } } - public void consumeAndCheck(int len) throws IOException { + public void consumeAndCheck(long len) throws IOException { synchronized (lock) { try { consume(len); @@ -187,15 +193,15 @@ public class Window extends AbstractLoggingBean implements java.nio.channels.Cha } } - public void check(int maxFree) throws IOException { - ValidateUtils.checkTrue(maxFree >= 0, "Negative check size: %d", maxFree); + public void check(long maxFree) throws IOException { + BufferUtils.validateUint32Value(maxFree, "Invalid check size: %d"); checkInitialized("check"); - int adjustSize = -1; + long adjustSize = -1L; AbstractChannel channel = getChannel(); synchronized (lock) { // TODO make the adjust factor configurable via FactoryManager property - int size = sizeHolder.get(); + long size = sizeHolder.get(); if (size < (maxFree / 2)) { adjustSize = maxFree - size; channel.sendWindowAdjust(adjustSize); @@ -203,7 +209,7 @@ public class Window extends AbstractLoggingBean implements java.nio.channels.Cha } } - if (adjustSize >= 0) { + if (adjustSize >= 0L) { if (log.isDebugEnabled()) { log.debug("Increase {} by {} up to {}", this, adjustSize, maxFree); } @@ -221,8 +227,8 @@ public class Window extends AbstractLoggingBean implements java.nio.channels.Cha * @see #waitForCondition(Predicate, long) * @see #consume(int) */ - public void waitAndConsume(final int len, long maxWaitTime) throws InterruptedException, WindowClosedException, SocketTimeoutException { - ValidateUtils.checkTrue(len >= 0, "Negative wait consume length: %d", len); + public void waitAndConsume(long len, long maxWaitTime) throws InterruptedException, WindowClosedException, SocketTimeoutException { + BufferUtils.validateUint32Value(len, "Invalid wait consume length: %d", len); checkInitialized("waitAndConsume"); synchronized (lock) { @@ -249,7 +255,7 @@ public class Window extends AbstractLoggingBean implements java.nio.channels.Cha * @throws SocketTimeoutException If timeout expired before space became available * @see #waitForCondition(Predicate, long) */ - public int waitForSpace(long maxWaitTime) throws InterruptedException, WindowClosedException, SocketTimeoutException { + public long waitForSpace(long maxWaitTime) throws InterruptedException, WindowClosedException, SocketTimeoutException { checkInitialized("waitForSpace"); synchronized (lock) { @@ -306,8 +312,8 @@ public class Window extends AbstractLoggingBean implements java.nio.channels.Cha throw new SocketTimeoutException("waitForCondition(" + this + ") timeout exceeded: " + maxWaitTime); } - protected void updateSize(int size) { - ValidateUtils.checkTrue(size >= 0, "Invalid size: %d", size); + protected void updateSize(long size) { + BufferUtils.validateUint32Value(size, "Invalid updated size: %d", size); this.sizeHolder.set(size); lock.notifyAll(); } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipClientChannel.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipClientChannel.java b/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipClientChannel.java index 94c75a3..98bb61e 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipClientChannel.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipClientChannel.java @@ -32,6 +32,7 @@ import org.apache.sshd.common.channel.ChannelOutputStream; import org.apache.sshd.common.channel.Window; import org.apache.sshd.common.io.IoSession; import org.apache.sshd.common.session.Session; +import org.apache.sshd.common.util.ValidateUtils; import org.apache.sshd.common.util.buffer.Buffer; import org.apache.sshd.common.util.buffer.ByteArrayBuffer; import org.apache.sshd.common.util.net.SshdSocketAddress; @@ -126,16 +127,17 @@ public class TcpipClientChannel extends AbstractClientChannel { } @Override - protected synchronized void doWriteData(byte[] data, int off, int len) throws IOException { + protected synchronized void doWriteData(byte[] data, int off, long len) throws IOException { + ValidateUtils.checkTrue(len <= Integer.MAX_VALUE, "Data length exceeds int boundaries: %d", len); // Make sure we copy the data as the incoming buffer may be reused - Buffer buf = ByteArrayBuffer.getCompactClone(data, off, len); + Buffer buf = ByteArrayBuffer.getCompactClone(data, off, (int) len); Window wLocal = getLocalWindow(); wLocal.consumeAndCheck(len); serverSession.write(buf); } @Override - protected void doWriteExtendedData(byte[] data, int off, int len) throws IOException { + protected void doWriteExtendedData(byte[] data, int off, long len) throws IOException { throw new UnsupportedOperationException(type + "Tcpip channel does not support extended data"); } } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractConnectionService.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractConnectionService.java b/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractConnectionService.java index 6878a84..05c8454 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractConnectionService.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/session/helpers/AbstractConnectionService.java @@ -367,8 +367,8 @@ public abstract class AbstractConnectionService<S extends AbstractSession> public void channelOpenConfirmation(Buffer buffer) throws IOException { Channel channel = getChannel(buffer); int sender = buffer.getInt(); - int rwsize = buffer.getInt(); - int rmpsize = buffer.getInt(); + long rwsize = buffer.getUInt(); + long rmpsize = buffer.getUInt(); if (log.isDebugEnabled()) { log.debug("channelOpenConfirmation({}) SSH_MSG_CHANNEL_OPEN_CONFIRMATION sender={}, window-size={}, packet-size={}", channel, sender, rwsize, rmpsize); @@ -514,8 +514,8 @@ public abstract class AbstractConnectionService<S extends AbstractSession> protected void channelOpen(Buffer buffer) throws Exception { String type = buffer.getString(); final int sender = buffer.getInt(); - final int rwsize = buffer.getInt(); - final int rmpsize = buffer.getInt(); + final long rwsize = buffer.getUInt(); + final long rmpsize = buffer.getUInt(); /* * NOTE: the 'sender' is the identifier assigned by the remote side - the server in this case */ http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java index 16a0368..a83abc3 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java @@ -506,6 +506,7 @@ public abstract class Buffer implements Readable { * @param i The 32-bit value */ public void putInt(long i) { + BufferUtils.validateInt32Value(i, "Invalid 32-bit value: %d"); ensureCapacity(Integer.BYTES); BufferUtils.putUInt(i, workBuf, 0, Integer.BYTES); putRawBytes(workBuf, 0, Integer.BYTES); http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/BufferUtils.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/BufferUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/BufferUtils.java index 3f8ee1e..65c37ce 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/BufferUtils.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/BufferUtils.java @@ -47,8 +47,17 @@ public final class BufferUtils { public static final int DEFAULT_HEXDUMP_CHUNK_SIZE = 64; public static final Level DEFAULT_HEXDUMP_LEVEL = Level.FINEST; - public static final Int2IntFunction DEFAULT_BUFFER_GROWTH_FACTOR = - BufferUtils::getNextPowerOf2; + public static final Int2IntFunction DEFAULT_BUFFER_GROWTH_FACTOR = BufferUtils::getNextPowerOf2; + + /** + * Maximum value of a {@code uint32} field + */ + public static final long MAX_UINT32_VALUE = 0x0FFFFFFFFL; + + /** + * Maximum value of a {@code uint8} field + */ + public static final int MAX_UINT8_VALUE = 0x0FF; /** * Private Constructor @@ -531,4 +540,42 @@ public final class BufferUtils { return buffer; } + + public static long validateInt32Value(long value, String message) { + ValidateUtils.checkTrue(isValidInt32Value(value), message, value); + return value; + } + + public static long validateInt32Value(long value, String format, Object arg) { + ValidateUtils.checkTrue(isValidInt32Value(value), format, arg); + return value; + } + + public static long validateInt32Value(long value, String format, Object ... args) { + ValidateUtils.checkTrue(isValidInt32Value(value), format, args); + return value; + } + + public static boolean isValidInt32Value(long value) { + return (value >= Integer.MIN_VALUE) && (value <= Integer.MAX_VALUE); + } + + public static long validateUint32Value(long value, String message) { + ValidateUtils.checkTrue(isValidUint32Value(value), message, value); + return value; + } + + public static long validateUint32Value(long value, String format, Object arg) { + ValidateUtils.checkTrue(isValidUint32Value(value), format, arg); + return value; + } + + public static long validateUint32Value(long value, String format, Object ... args) { + ValidateUtils.checkTrue(isValidUint32Value(value), format, args); + return value; + } + + public static boolean isValidUint32Value(long value) { + return (value >= 0L) && (value <= MAX_UINT32_VALUE); + } } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/server/channel/AbstractServerChannel.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/server/channel/AbstractServerChannel.java b/sshd-core/src/main/java/org/apache/sshd/server/channel/AbstractServerChannel.java index 835317e..dda88ed 100644 --- a/sshd-core/src/main/java/org/apache/sshd/server/channel/AbstractServerChannel.java +++ b/sshd-core/src/main/java/org/apache/sshd/server/channel/AbstractServerChannel.java @@ -65,7 +65,7 @@ public abstract class AbstractServerChannel extends AbstractChannel implements S } @Override - public OpenFuture open(int recipient, int rwSize, int packetSize, Buffer buffer) { + public OpenFuture open(int recipient, long rwSize, long packetSize, Buffer buffer) { setRecipient(recipient); Session s = getSession(); @@ -77,7 +77,7 @@ public abstract class AbstractServerChannel extends AbstractChannel implements S } @Override - public void handleOpenSuccess(int recipient, int rwSize, int packetSize, Buffer buffer) throws IOException { + public void handleOpenSuccess(int recipient, long rwSize, long packetSize, Buffer buffer) throws IOException { throw new UnsupportedOperationException("handleOpenSuccess(" + recipient + "," + rwSize + "," + packetSize + ") N/A"); } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java index 2c097c6..78d32fa 100644 --- a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java +++ b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java @@ -236,27 +236,30 @@ public class ChannelSession extends AbstractServerChannel { } @Override - protected void doWriteData(byte[] data, int off, int len) throws IOException { + protected void doWriteData(byte[] data, int off, long len) throws IOException { // If we're already closing, ignore incoming data if (isClosing()) { return; } + ValidateUtils.checkTrue(len <= Integer.MAX_VALUE, "Data length exceeds int boundaries: %d", len); + if (receiver != null) { - int r = receiver.data(this, data, off, len); + int r = receiver.data(this, data, off, (int) len); if (r > 0) { Window wLocal = getLocalWindow(); wLocal.consumeAndCheck(r); } } else { + ValidateUtils.checkTrue(len <= (Integer.MAX_VALUE - Long.SIZE), "Temporary data length exceeds int boundaries: %d", len); if (tempBuffer == null) { - tempBuffer = new ByteArrayBuffer(len + Long.SIZE, false); + tempBuffer = new ByteArrayBuffer((int) len + Long.SIZE, false); } - tempBuffer.putRawBytes(data, off, len); + tempBuffer.putRawBytes(data, off, (int) len); } } @Override - protected void doWriteExtendedData(byte[] data, int off, int len) throws IOException { + protected void doWriteExtendedData(byte[] data, int off, long len) throws IOException { throw new UnsupportedOperationException("Server channel does not support extended data"); } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpipServerChannel.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpipServerChannel.java b/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpipServerChannel.java index 00dc37b..6bb0918 100644 --- a/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpipServerChannel.java +++ b/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpipServerChannel.java @@ -328,20 +328,21 @@ public class TcpipServerChannel extends AbstractServerChannel { } @Override - protected void doWriteData(byte[] data, int off, final int len) throws IOException { + protected void doWriteData(byte[] data, int off, long len) throws IOException { + ValidateUtils.checkTrue(len <= Integer.MAX_VALUE, "Data length exceeds int boundaries: %d", len); // Make sure we copy the data as the incoming buffer may be reused - final Buffer buf = ByteArrayBuffer.getCompactClone(data, off, len); + Buffer buf = ByteArrayBuffer.getCompactClone(data, off, (int) len); ioSession.write(buf).addListener(future -> { if (future.isWritten()) { - handleWriteDataSuccess(SshConstants.SSH_MSG_CHANNEL_DATA, buf.array(), 0, len); + handleWriteDataSuccess(SshConstants.SSH_MSG_CHANNEL_DATA, buf.array(), 0, (int) len); } else { - handleWriteDataFailure(SshConstants.SSH_MSG_CHANNEL_DATA, buf.array(), 0, len, future.getException()); + handleWriteDataFailure(SshConstants.SSH_MSG_CHANNEL_DATA, buf.array(), 0, (int) len, future.getException()); } }); } @Override - protected void doWriteExtendedData(byte[] data, int off, int len) throws IOException { + protected void doWriteExtendedData(byte[] data, int off, long len) throws IOException { throw new UnsupportedOperationException(type + "Tcpip channel does not support extended data"); } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/main/java/org/apache/sshd/server/x11/ChannelForwardedX11.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/server/x11/ChannelForwardedX11.java b/sshd-core/src/main/java/org/apache/sshd/server/x11/ChannelForwardedX11.java index bcdf50b..3d95af7 100644 --- a/sshd-core/src/main/java/org/apache/sshd/server/x11/ChannelForwardedX11.java +++ b/sshd-core/src/main/java/org/apache/sshd/server/x11/ChannelForwardedX11.java @@ -32,6 +32,7 @@ import org.apache.sshd.common.channel.ChannelOutputStream; import org.apache.sshd.common.channel.Window; import org.apache.sshd.common.io.IoSession; import org.apache.sshd.common.session.Session; +import org.apache.sshd.common.util.ValidateUtils; import org.apache.sshd.common.util.buffer.Buffer; import org.apache.sshd.common.util.buffer.ByteArrayBuffer; @@ -89,11 +90,12 @@ public class ChannelForwardedX11 extends AbstractClientChannel { } @Override - protected synchronized void doWriteData(byte[] data, int off, int len) throws IOException { + protected synchronized void doWriteData(byte[] data, int off, long len) throws IOException { + ValidateUtils.checkTrue(len <= Integer.MAX_VALUE, "Data length exceeds int boundaries: %d", len); Window wLocal = getLocalWindow(); wLocal.consumeAndCheck(len); // use a clone in case data buffer is re-used - serverSession.write(ByteArrayBuffer.getCompactClone(data, off, len)); + serverSession.write(ByteArrayBuffer.getCompactClone(data, off, (int) len)); } @Override http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java b/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java index d939b11..b8046bb 100644 --- a/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java +++ b/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java @@ -196,7 +196,7 @@ public class ClientTest extends BaseTestSupport { return new ChannelSession() { @SuppressWarnings("synthetic-access") @Override - public OpenFuture open(int recipient, int rwsize, int rmpsize, Buffer buffer) { + public OpenFuture open(int recipient, long rwsize, long rmpsize, Buffer buffer) { try { channelLatch.await(); } catch (InterruptedException e) { http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowInitTest.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowInitTest.java b/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowInitTest.java new file mode 100644 index 0000000..ed6bdb4 --- /dev/null +++ b/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowInitTest.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sshd.common.channel; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.sshd.client.future.OpenFuture; +import org.apache.sshd.common.FactoryManager; +import org.apache.sshd.common.util.buffer.Buffer; +import org.apache.sshd.common.util.buffer.BufferUtils; +import org.apache.sshd.util.test.BaseTestSupport; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests +public class WindowInitTest extends BaseTestSupport { + private static final AbstractChannel MOCK_CHANNEL = new AbstractChannel(true) { + @Override + public OpenFuture open(int recipient, long rwSize, long packetSize, Buffer buffer) { + return null; + } + + @Override + public void handleOpenSuccess(int recipient, long rwSize, long packetSize, Buffer buffer) throws IOException { + // ignored + } + + @Override + public void handleOpenFailure(Buffer buffer) throws IOException { + // ignored + } + + @Override + protected void doWriteData(byte[] data, int off, long len) throws IOException { + // ignored + } + + @Override + protected void doWriteExtendedData(byte[] data, int off, long len) throws IOException { + // ignored + } + }; + + private long initialSize; + private long packetSize; + + public WindowInitTest(long initialSize, long packetSize) { + this.initialSize = initialSize; + this.packetSize = packetSize; + } + + @Parameters(name = "initial-size={0}, packet-size={1}") + public static List<Object[]> parameters() { + return Collections.unmodifiableList(new ArrayList<Object[]>() { + // Not serializing it + private static final long serialVersionUID = 1L; + + { + addTestCase(Byte.MIN_VALUE, FactoryManager.DEFAULT_MAX_PACKET_SIZE); + addTestCase(BufferUtils.MAX_UINT32_VALUE + 1L, FactoryManager.DEFAULT_MAX_PACKET_SIZE); + addTestCase(FactoryManager.DEFAULT_WINDOW_SIZE, 0L); + addTestCase(FactoryManager.DEFAULT_WINDOW_SIZE, Byte.MIN_VALUE); + addTestCase(FactoryManager.DEFAULT_WINDOW_SIZE, BufferUtils.MAX_UINT32_VALUE + 1L); + addTestCase(FactoryManager.DEFAULT_WINDOW_SIZE, FactoryManager.DEFAULT_LIMIT_PACKET_SIZE + 1L); + } + + private void addTestCase(long initialSize, long packetSize) { + add(new Object[]{initialSize, packetSize}); + } + }); + } + + @Test(expected = IllegalArgumentException.class) + public void testInitializationFailure() throws IOException { + try (Window w = new Window(MOCK_CHANNEL, null, true, true)) { + w.init(initialSize, packetSize, Collections.<String, Object>emptyMap()); + fail("Unexpected success for initialiSize=" + initialSize + ", packetSize=" + packetSize); + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowTest.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowTest.java b/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowTest.java index 5620fae..40cd588 100644 --- a/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowTest.java +++ b/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowTest.java @@ -112,7 +112,7 @@ public class WindowTest extends BaseTestSupport { return new ChannelSession() { @SuppressWarnings("synthetic-access") @Override - public OpenFuture open(int recipient, int rwsize, int rmpsize, Buffer buffer) { + public OpenFuture open(int recipient, long rwsize, long rmpsize, Buffer buffer) { try { channelLatch.await(); } catch (InterruptedException e) { http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowTimeoutTest.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowTimeoutTest.java b/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowTimeoutTest.java index d834621..83436ca 100644 --- a/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowTimeoutTest.java +++ b/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowTimeoutTest.java @@ -51,12 +51,12 @@ public class WindowTimeoutTest extends BaseTestSupport { public void setUp() throws Exception { channel = new AbstractChannel(getCurrentTestName(), true) { @Override - public OpenFuture open(int recipient, int rwSize, int packetSize, Buffer buffer) { + public OpenFuture open(int recipient, long rwSize, long packetSize, Buffer buffer) { throw new UnsupportedOperationException(); } @Override - public void handleOpenSuccess(int recipient, int rwSize, int packetSize, Buffer buffer) throws IOException { + public void handleOpenSuccess(int recipient, long rwSize, long packetSize, Buffer buffer) throws IOException { throw new UnsupportedOperationException(); } @@ -66,12 +66,12 @@ public class WindowTimeoutTest extends BaseTestSupport { } @Override - protected void doWriteExtendedData(byte[] data, int off, int len) throws IOException { + protected void doWriteExtendedData(byte[] data, int off, long len) throws IOException { throw new UnsupportedOperationException(); } @Override - protected void doWriteData(byte[] data, int off, int len) throws IOException { + protected void doWriteData(byte[] data, int off, long len) throws IOException { throw new UnsupportedOperationException(); } }; @@ -93,7 +93,7 @@ public class WindowTimeoutTest extends BaseTestSupport { long waitStart = System.nanoTime(); try { - int len = window.waitForSpace(MAX_WAIT_TIME); + long len = window.waitForSpace(MAX_WAIT_TIME); fail("Unexpected timed wait success - len=" + len); } catch (SocketTimeoutException e) { long waitEnd = System.nanoTime(); @@ -105,7 +105,7 @@ public class WindowTimeoutTest extends BaseTestSupport { window.close(); assertFalse("Window not closed", window.isOpen()); try { - int len = window.waitForSpace(MAX_WAIT_TIME); + long len = window.waitForSpace(MAX_WAIT_TIME); fail("Unexpected closed wait success - len=" + len); } catch (WindowClosedException e) { // expected http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3b1342ef/sshd-core/src/test/java/org/apache/sshd/util/test/BogusChannel.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/util/test/BogusChannel.java b/sshd-core/src/test/java/org/apache/sshd/util/test/BogusChannel.java index 3c3f89a..0ef7bed 100644 --- a/sshd-core/src/test/java/org/apache/sshd/util/test/BogusChannel.java +++ b/sshd-core/src/test/java/org/apache/sshd/util/test/BogusChannel.java @@ -31,27 +31,27 @@ public class BogusChannel extends AbstractChannel { } @Override - protected void doWriteData(byte[] data, int off, int len) throws IOException { + protected void doWriteData(byte[] data, int off, long len) throws IOException { // ignored } @Override - protected void doWriteExtendedData(byte[] data, int off, int len) throws IOException { + protected void doWriteExtendedData(byte[] data, int off, long len) throws IOException { // ignored } @Override - protected void sendWindowAdjust(int len) throws IOException { + protected void sendWindowAdjust(long len) throws IOException { // ignored } @Override - public OpenFuture open(int recipient, int rwsize, int rmpsize, Buffer buffer) { + public OpenFuture open(int recipient, long rwsize, long rmpsize, Buffer buffer) { return new DefaultOpenFuture(this.lock); } @Override - public void handleOpenSuccess(int recipient, int rwsize, int rmpsize, Buffer buffer) throws IOException { + public void handleOpenSuccess(int recipient, long rwsize, long rmpsize, Buffer buffer) throws IOException { // ignored }
