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 2021/03/05 09:17:54 UTC
[mina-sshd] 01/03: [SSHD-1125] Added reported test case for the
issue
This is an automated email from the ASF dual-hosted git repository.
lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
commit 4d2e5e3e998ddbe64ca89b0afa538d375d52d7a7
Author: Lyor Goldstein <lg...@apache.org>
AuthorDate: Thu Feb 25 21:36:21 2021 +0200
[SSHD-1125] Added reported test case for the issue
---
.../client/impl/SftpRemotePathChannelTest.java | 79 ++++++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/impl/SftpRemotePathChannelTest.java b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/impl/SftpRemotePathChannelTest.java
index f1aa19e..5d80f62 100644
--- a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/impl/SftpRemotePathChannelTest.java
+++ b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/impl/SftpRemotePathChannelTest.java
@@ -30,15 +30,28 @@ import java.nio.file.StandardOpenOption;
import java.util.Date;
import java.util.EnumSet;
+import org.apache.sshd.common.Factory;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.io.nio2.Nio2Session;
+import org.apache.sshd.common.random.Random;
+import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.mina.MinaSession;
import org.apache.sshd.sftp.SftpModuleProperties;
import org.apache.sshd.sftp.client.AbstractSftpClientTestSupport;
+import org.apache.sshd.sftp.client.RawSftpClient;
import org.apache.sshd.sftp.client.SftpClient;
+import org.apache.sshd.sftp.client.SftpClient.CloseableHandle;
+import org.apache.sshd.sftp.client.SftpClient.OpenMode;
import org.apache.sshd.sftp.common.SftpConstants;
import org.apache.sshd.util.test.CommonTestSupportUtils;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
@@ -195,4 +208,70 @@ public class SftpRemotePathChannelTest extends AbstractSftpClientTestSupport {
assertEquals("Mismatched transfered size", expected.length, actual.length);
assertArrayEquals("Mismatched transferred data", expected, actual);
}
+
+ /*
+ * Demonstrates an DoS vulnerability by opening a file and requesting data from it without actually reading
+ * any response data, the buffers in {@link org.apache.sshd.common.channel.BufferedIoOutputStream} fill up until
+ * an Out Of Memory Error occurs.
+ * To test, the available heap memory of the server must be below the value set in requested_data_volume
+ * limit the available heap memory of the junit execution by passing "-Xmx256m" to the VM.
+ */
+ @Test(timeout = 5L * 60L * 1000L) // see SSHD-1125
+ public void testReadRequestsOutOfMemory() throws Exception {
+ Path targetPath = detectTargetFolder();
+ Path parentPath = targetPath.getParent();
+ Path lclSftp = CommonTestSupportUtils.resolve(
+ targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME,
+ getClass().getSimpleName(), getCurrentTestName());
+
+ // Generate some random data file
+ Path testFile = assertHierarchyTargetFolderExists(lclSftp).resolve("file.txt");
+ byte[] expected = new byte[1024];
+ Factory<? extends Random> factory = sshd.getRandomFactory();
+ Random rnd = factory.create();
+ rnd.fill(expected);
+ Files.write(testFile, expected);
+
+ String file = CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, testFile);
+ try (SftpClient sftp = createSingleSessionClient();
+ CloseableHandle handle = sftp.open(file, OpenMode.Read)) {
+ // Prevent the client from reading any packets from the server to provoke serverside buffers to fill up
+ Session session = sftp.getSession();
+ IoSession ioSession = session.getIoSession();
+ if (ioSession instanceof MinaSession) {
+ org.apache.mina.core.session.IoSession minaSession = ((MinaSession) ioSession).getSession();
+ minaSession.suspendRead();
+ } else {
+ ((Nio2Session) ioSession).suspendRead();
+ }
+
+ // Always read from the same offset. Thereby one can work with a small file.
+ long curPos = 0L;
+ byte[] buffer = new byte[32768];
+ long readLength = buffer.length;
+ // Request about 1 GB of data
+ int requestedDataVolume = 1024 * 1024 * 1204;
+ byte[] id = handle.getIdentifier();
+ Runtime runtime = Runtime.getRuntime();
+ Logger logger = LoggerFactory.getLogger(getClass());
+ String testName = getCurrentTestName();
+ long maxRequests = requestedDataVolume / readLength;
+ for (long i = 0L; i < maxRequests; i++) {
+ if ((i & 0x03FF) == 0L) {
+ logger.info("{} - free={}, total={}, max={} after {}/{} requests",
+ testName, runtime.freeMemory(), runtime.totalMemory(), runtime.maxMemory(), i, maxRequests);
+ }
+
+ // Send a SSH_FXP_READ command to the server without reading the response
+ Buffer requestBuffer = new ByteArrayBuffer(id.length + Long.SIZE, false);
+ requestBuffer.putBytes(id);
+ requestBuffer.putLong(curPos);
+ requestBuffer.putInt(readLength);
+ ((RawSftpClient) sftp).send(SftpConstants.SSH_FXP_READ, requestBuffer);
+
+ Thread.sleep(1L);
+ }
+ Thread.sleep(1000L);
+ }
+ }
}