You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2016/09/27 17:00:05 UTC
mina-sshd git commit: [SSHD-701] IllegalArgumentException processing
SSH_MSG_CHANNEL_OPEN_CONFIRMATION with initial window size of -1
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 <ly...@gmail.com>
Authored: Tue Sep 27 20:02:05 2016 +0300
Committer: Lyor Goldstein <ly...@gmail.com>
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:dev@mina.apache.org">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
}