From 89d364c27756dc2234da98865dea4ae67717683e Mon Sep 17 00:00:00 2001 From: "pixeebot[bot]" <104101892+pixeebot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 04:23:39 +0000 Subject: [PATCH] Protect `readLine()` against DoS --- .../conventions/info/ParallelDetector.java | 3 +- .../internal/info/GlobalBuildInfoPlugin.java | 3 +- .../test/ErrorReportingTestListener.java | 3 +- .../gradle/testclusters/RunTask.java | 3 +- .../benchmark/ops/bulk/BulkBenchmarkTask.java | 3 +- .../elasticsearch/client/RequestLogger.java | 3 +- .../plugins/cli/InstallPluginAction.java | 7 ++-- .../plugins/cli/InstallPluginActionTests.java | 11 +++--- .../plugins/cli/RemovePluginActionTests.java | 9 +++-- .../server/cli/ErrorPumpThread.java | 3 +- .../server/cli/JvmOptionsParser.java | 3 +- .../grok/GrokBuiltinPatterns.java | 3 +- .../elasticsearch/h3/CellBoundaryTests.java | 11 +++--- .../org/elasticsearch/h3/CellCenterTests.java | 5 ++- .../elasticsearch/common/ssl/PemUtils.java | 37 ++++++++++--------- .../UserAgentProcessorFactoryTests.java | 3 +- .../gcs/GoogleCloudStorageService.java | 3 +- .../Netty4SizeHeaderFrameDecoderTests.java | 3 +- .../discovery/ec2/AwsEc2Utils.java | 3 +- .../discovery/ec2/Ec2DiscoveryPlugin.java | 3 +- .../discovery/ec2/Ec2NameResolver.java | 3 +- .../hotthreads/NodesHotThreadsResponse.java | 3 +- .../bootstrap/BootstrapChecks.java | 3 +- .../org/elasticsearch/bootstrap/Spawner.java | 3 +- .../org/elasticsearch/common/io/Streams.java | 3 +- .../index/analysis/Analysis.java | 3 +- .../node/InternalSettingsPreparer.java | 3 +- .../plugins/spi/SPIClassIterator.java | 3 +- .../bootstrap/MaxMapCountCheckTests.java | 9 +++-- .../allocation/CatAllocationTestCase.java | 3 +- .../src/main/java/oldes/OldElasticsearch.java | 3 +- .../test/rest/ESRestTestCase.java | 3 +- .../test/cluster/util/ProcessUtils.java | 3 +- 33 files changed, 100 insertions(+), 67 deletions(-) diff --git a/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/info/ParallelDetector.java b/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/info/ParallelDetector.java index 688f2f858ae16..63d4627e4f788 100644 --- a/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/info/ParallelDetector.java +++ b/build-conventions/src/main/java/org/elasticsearch/gradle/internal/conventions/info/ParallelDetector.java @@ -8,6 +8,7 @@ package org.elasticsearch.gradle.internal.conventions.info; +import io.github.pixee.security.BoundedLineReader; import org.gradle.api.Action; import org.gradle.api.logging.Logger; import org.gradle.api.logging.Logging; @@ -45,7 +46,7 @@ public static int findDefaultParallel(Project project) { String currentID = ""; try (BufferedReader reader = new BufferedReader(new FileReader(cpuInfoFile))) { - for (String line = reader.readLine(); line != null; line = reader.readLine()) { + for (String line = BoundedLineReader.readLine(reader, 5_000_000); line != null; line = BoundedLineReader.readLine(reader, 5_000_000)) { if (line.contains(":")) { List parts = Arrays.stream(line.split(":", 2)).map(String::trim).collect(Collectors.toList()); String name = parts.get(0); diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/info/GlobalBuildInfoPlugin.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/info/GlobalBuildInfoPlugin.java index 115c4b0694141..e92026e716531 100644 --- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/info/GlobalBuildInfoPlugin.java +++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/info/GlobalBuildInfoPlugin.java @@ -7,6 +7,7 @@ */ package org.elasticsearch.gradle.internal.info; +import io.github.pixee.security.BoundedLineReader; import org.apache.commons.io.IOUtils; import org.elasticsearch.gradle.internal.BwcVersions; import org.elasticsearch.gradle.internal.conventions.info.GitInfo; @@ -360,7 +361,7 @@ public static String getResourceContents(String resourcePath) { BufferedReader reader = new BufferedReader(new InputStreamReader(GlobalBuildInfoPlugin.class.getResourceAsStream(resourcePath))) ) { StringBuilder b = new StringBuilder(); - for (String line = reader.readLine(); line != null; line = reader.readLine()) { + for (String line = BoundedLineReader.readLine(reader, 5_000_000); line != null; line = BoundedLineReader.readLine(reader, 5_000_000)) { if (b.length() != 0) { b.append('\n'); } diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/test/ErrorReportingTestListener.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/test/ErrorReportingTestListener.java index 15cae4868034e..c15d524c70656 100644 --- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/test/ErrorReportingTestListener.java +++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/test/ErrorReportingTestListener.java @@ -7,6 +7,7 @@ */ package org.elasticsearch.gradle.internal.test; +import io.github.pixee.security.BoundedLineReader; import org.elasticsearch.gradle.internal.ElasticsearchTestBasePlugin; import org.gradle.api.internal.tasks.testing.logging.FullExceptionFormatter; import org.gradle.api.internal.tasks.testing.logging.TestExceptionFormatter; @@ -99,7 +100,7 @@ public void afterSuite(final TestDescriptor suite, TestResult result) { try (BufferedReader reader = eventWriter.reader()) { PrintStream out = System.out; - for (String message = reader.readLine(); message != null; message = reader.readLine()) { + for (String message = BoundedLineReader.readLine(reader, 5_000_000); message != null; message = BoundedLineReader.readLine(reader, 5_000_000)) { if (message.startsWith(" 1> ")) { out = System.out; } else if (message.startsWith(" 2> ")) { diff --git a/build-tools/src/main/java/org/elasticsearch/gradle/testclusters/RunTask.java b/build-tools/src/main/java/org/elasticsearch/gradle/testclusters/RunTask.java index 86df3544ddfc6..7cec708017e4f 100644 --- a/build-tools/src/main/java/org/elasticsearch/gradle/testclusters/RunTask.java +++ b/build-tools/src/main/java/org/elasticsearch/gradle/testclusters/RunTask.java @@ -7,6 +7,7 @@ */ package org.elasticsearch.gradle.testclusters; +import io.github.pixee.security.BoundedLineReader; import org.gradle.api.GradleException; import org.gradle.api.logging.Logger; import org.gradle.api.logging.Logging; @@ -245,7 +246,7 @@ public void runAndWait() throws IOException { for (BufferedReader bufferedReader : toRead) { if (bufferedReader.ready()) { readData = true; - logger.lifecycle(bufferedReader.readLine()); + logger.lifecycle(BoundedLineReader.readLine(bufferedReader, 5_000_000)); } } diff --git a/client/benchmark/src/main/java/org/elasticsearch/client/benchmark/ops/bulk/BulkBenchmarkTask.java b/client/benchmark/src/main/java/org/elasticsearch/client/benchmark/ops/bulk/BulkBenchmarkTask.java index 69edd9c8f86ff..5c37fc7b87c09 100644 --- a/client/benchmark/src/main/java/org/elasticsearch/client/benchmark/ops/bulk/BulkBenchmarkTask.java +++ b/client/benchmark/src/main/java/org/elasticsearch/client/benchmark/ops/bulk/BulkBenchmarkTask.java @@ -7,6 +7,7 @@ */ package org.elasticsearch.client.benchmark.ops.bulk; +import io.github.pixee.security.BoundedLineReader; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.elasticsearch.ElasticsearchException; @@ -101,7 +102,7 @@ public void execute() { String line; int bulkIndex = 0; List bulkData = new ArrayList<>(bulkSize); - while ((line = reader.readLine()) != null) { + while ((line = BoundedLineReader.readLine(reader, 5_000_000)) != null) { if (bulkIndex == bulkSize) { sendBulk(bulkData); // reset data structures diff --git a/client/rest/src/main/java/org/elasticsearch/client/RequestLogger.java b/client/rest/src/main/java/org/elasticsearch/client/RequestLogger.java index 085bc5619451f..e420b1fa2d7e1 100644 --- a/client/rest/src/main/java/org/elasticsearch/client/RequestLogger.java +++ b/client/rest/src/main/java/org/elasticsearch/client/RequestLogger.java @@ -19,6 +19,7 @@ package org.elasticsearch.client; +import io.github.pixee.security.BoundedLineReader; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.Header; @@ -170,7 +171,7 @@ static String buildTraceResponse(HttpResponse httpResponse) throws IOException { } try (BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent(), charset))) { String line; - while ((line = reader.readLine()) != null) { + while ((line = BoundedLineReader.readLine(reader, 5_000_000)) != null) { responseLine.append("\n# ").append(line); } } diff --git a/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/cli/InstallPluginAction.java b/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/cli/InstallPluginAction.java index c7bee4a6c172d..fda799191dab3 100644 --- a/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/cli/InstallPluginAction.java +++ b/distribution/tools/plugin-cli/src/main/java/org/elasticsearch/plugins/cli/InstallPluginAction.java @@ -8,6 +8,7 @@ package org.elasticsearch.plugins.cli; +import io.github.pixee.security.BoundedLineReader; import org.apache.lucene.search.spell.LevenshteinDistance; import org.apache.lucene.util.CollectionUtil; import org.apache.lucene.util.Constants; @@ -579,9 +580,9 @@ private Path downloadAndValidate(final String urlString, final Path tmpDir, fina */ final BufferedReader checksumReader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); if (digestAlgo.equals("SHA-1")) { - expectedChecksum = checksumReader.readLine(); + expectedChecksum = BoundedLineReader.readLine(checksumReader, 5_000_000); } else { - final String checksumLine = checksumReader.readLine(); + final String checksumLine = BoundedLineReader.readLine(checksumReader, 5_000_000); final String[] fields = checksumLine.split(" {2}"); if (officialPlugin && fields.length != 2 || officialPlugin == false && fields.length > 2) { throw new UserException(ExitCodes.IO_ERROR, "Invalid checksum file at " + checksumUrl); @@ -603,7 +604,7 @@ private Path downloadAndValidate(final String urlString, final Path tmpDir, fina } } } - if (checksumReader.readLine() != null) { + if (BoundedLineReader.readLine(checksumReader, 5_000_000) != null) { throw new UserException(ExitCodes.IO_ERROR, "Invalid checksum file at " + checksumUrl); } } diff --git a/distribution/tools/plugin-cli/src/test/java/org/elasticsearch/plugins/cli/InstallPluginActionTests.java b/distribution/tools/plugin-cli/src/test/java/org/elasticsearch/plugins/cli/InstallPluginActionTests.java index c088e89338e74..46cd97f8e8a69 100644 --- a/distribution/tools/plugin-cli/src/test/java/org/elasticsearch/plugins/cli/InstallPluginActionTests.java +++ b/distribution/tools/plugin-cli/src/test/java/org/elasticsearch/plugins/cli/InstallPluginActionTests.java @@ -11,6 +11,7 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; +import io.github.pixee.security.BoundedLineReader; import org.apache.lucene.tests.util.LuceneTestCase; import org.bouncycastle.bcpg.ArmoredOutputStream; @@ -850,20 +851,20 @@ public void testOfficialPluginsHelpSortedAndMissingObviouslyWrongPlugins() throw MockTerminal mockTerminal = MockTerminal.create(); new MockInstallPluginCommand().main(new String[] { "--help" }, mockTerminal, new ProcessInfo(Map.of(), Map.of(), createTempDir())); try (BufferedReader reader = new BufferedReader(new StringReader(mockTerminal.getOutput()))) { - String line = reader.readLine(); + String line = BoundedLineReader.readLine(reader, 5_000_000); // first find the beginning of our list of official plugins while (line.endsWith("may be installed by name:") == false) { - line = reader.readLine(); + line = BoundedLineReader.readLine(reader, 5_000_000); } // now check each line compares greater than the last, until we reach an empty line - String prev = reader.readLine(); - line = reader.readLine(); + String prev = BoundedLineReader.readLine(reader, 5_000_000); + line = BoundedLineReader.readLine(reader, 5_000_000); while (line != null && line.trim().isEmpty() == false) { assertTrue(prev + " < " + line, prev.compareTo(line) < 0); prev = line; - line = reader.readLine(); + line = BoundedLineReader.readLine(reader, 5_000_000); // qa is not really a plugin and it shouldn't sneak in assertThat(line, not(endsWith("qa"))); assertThat(line, not(endsWith("example"))); diff --git a/distribution/tools/plugin-cli/src/test/java/org/elasticsearch/plugins/cli/RemovePluginActionTests.java b/distribution/tools/plugin-cli/src/test/java/org/elasticsearch/plugins/cli/RemovePluginActionTests.java index 73e89fc948029..a705286d1cfc4 100644 --- a/distribution/tools/plugin-cli/src/test/java/org/elasticsearch/plugins/cli/RemovePluginActionTests.java +++ b/distribution/tools/plugin-cli/src/test/java/org/elasticsearch/plugins/cli/RemovePluginActionTests.java @@ -8,6 +8,7 @@ package org.elasticsearch.plugins.cli; +import io.github.pixee.security.BoundedLineReader; import org.apache.lucene.tests.util.LuceneTestCase; import org.elasticsearch.Version; import org.elasticsearch.cli.ExitCodes; @@ -230,10 +231,10 @@ public void testRemoveUninstalledPluginErrors() throws Exception { BufferedReader reader = new BufferedReader(new StringReader(terminal.getOutput())); BufferedReader errorReader = new BufferedReader(new StringReader(terminal.getErrorOutput())) ) { - assertThat(errorReader.readLine(), equalTo("")); - assertThat(errorReader.readLine(), containsString("plugin [fake] not found")); - assertThat(reader.readLine(), nullValue()); - assertThat(errorReader.readLine(), nullValue()); + assertThat(BoundedLineReader.readLine(errorReader, 5_000_000), equalTo("")); + assertThat(BoundedLineReader.readLine(errorReader, 5_000_000), containsString("plugin [fake] not found")); + assertThat(BoundedLineReader.readLine(reader, 5_000_000), nullValue()); + assertThat(BoundedLineReader.readLine(errorReader, 5_000_000), nullValue()); } } diff --git a/distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/ErrorPumpThread.java b/distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/ErrorPumpThread.java index 8c6766b5da186..3f0c86aa8b9bf 100644 --- a/distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/ErrorPumpThread.java +++ b/distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/ErrorPumpThread.java @@ -8,6 +8,7 @@ package org.elasticsearch.server.cli; +import io.github.pixee.security.BoundedLineReader; import org.elasticsearch.bootstrap.BootstrapInfo; import java.io.BufferedReader; @@ -76,7 +77,7 @@ void drain() { public void run() { try { String line; - while ((line = reader.readLine()) != null) { + while ((line = BoundedLineReader.readLine(reader, 5_000_000)) != null) { if (line.isEmpty() == false && line.charAt(0) == SERVER_READY_MARKER) { ready = true; readyOrDead.countDown(); diff --git a/distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/JvmOptionsParser.java b/distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/JvmOptionsParser.java index 29650e4b74114..edcdf73e0f62b 100644 --- a/distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/JvmOptionsParser.java +++ b/distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/JvmOptionsParser.java @@ -8,6 +8,7 @@ package org.elasticsearch.server.cli; +import io.github.pixee.security.BoundedLineReader; import org.elasticsearch.bootstrap.ServerArgs; import org.elasticsearch.cli.ExitCodes; import org.elasticsearch.cli.UserException; @@ -289,7 +290,7 @@ static void parse( ) throws IOException { int lineNumber = 0; while (true) { - final String line = br.readLine(); + final String line = BoundedLineReader.readLine(br, 5_000_000); lineNumber++; if (line == null) { break; diff --git a/libs/grok/src/main/java/org/elasticsearch/grok/GrokBuiltinPatterns.java b/libs/grok/src/main/java/org/elasticsearch/grok/GrokBuiltinPatterns.java index 9d3813f0d0f33..19fc5a9c7f158 100644 --- a/libs/grok/src/main/java/org/elasticsearch/grok/GrokBuiltinPatterns.java +++ b/libs/grok/src/main/java/org/elasticsearch/grok/GrokBuiltinPatterns.java @@ -8,6 +8,7 @@ package org.elasticsearch.grok; +import io.github.pixee.security.BoundedLineReader; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -138,7 +139,7 @@ private static PatternBank loadPatternsFromDirectory(List patternNames, private static void loadPatternsFromFile(Map patternBank, InputStream inputStream) throws IOException { String line; BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); - while ((line = br.readLine()) != null) { + while ((line = BoundedLineReader.readLine(br, 5_000_000)) != null) { String trimmedLine = line.replaceAll("^\\s+", ""); if (trimmedLine.startsWith("#") || trimmedLine.length() == 0) { continue; diff --git a/libs/h3/src/test/java/org/elasticsearch/h3/CellBoundaryTests.java b/libs/h3/src/test/java/org/elasticsearch/h3/CellBoundaryTests.java index 903e4ed40ec16..2dfe4d714909a 100644 --- a/libs/h3/src/test/java/org/elasticsearch/h3/CellBoundaryTests.java +++ b/libs/h3/src/test/java/org/elasticsearch/h3/CellBoundaryTests.java @@ -18,6 +18,7 @@ */ package org.elasticsearch.h3; +import io.github.pixee.security.BoundedLineReader; import org.apache.lucene.geo.GeoEncodingUtils; import org.apache.lucene.tests.geo.GeoTestUtil; import org.elasticsearch.test.ESTestCase; @@ -148,22 +149,22 @@ public void testBc19r14cells() throws Exception { private void processFile(String file) throws IOException { InputStream fis = getClass().getResourceAsStream(file + ".gz"); BufferedReader reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(fis), StandardCharsets.UTF_8)); - String h3Address = reader.readLine(); + String h3Address = BoundedLineReader.readLine(reader, 5_000_000); while (h3Address != null) { assertEquals(true, H3.h3IsValid(h3Address)); long h3 = H3.stringToH3(h3Address); assertEquals(true, H3.h3IsValid(h3)); processOne(h3Address, reader); - h3Address = reader.readLine(); + h3Address = BoundedLineReader.readLine(reader, 5_000_000); } } private void processOne(String h3Address, BufferedReader reader) throws IOException { - String line = reader.readLine(); + String line = BoundedLineReader.readLine(reader, 5_000_000); if ("{".equals(line) == false) { throw new IllegalArgumentException(); } - line = reader.readLine(); + line = BoundedLineReader.readLine(reader, 5_000_000); List points = new ArrayList<>(); while ("}".equals(line) == false) { StringTokenizer tokens = new StringTokenizer(line, " "); @@ -171,7 +172,7 @@ private void processOne(String h3Address, BufferedReader reader) throws IOExcept double lat = Double.parseDouble(tokens.nextToken()); double lon = Double.parseDouble(tokens.nextToken()); points.add(new double[] { lat, lon }); - line = reader.readLine(); + line = BoundedLineReader.readLine(reader, 5_000_000); } CellBoundary boundary = H3.h3ToGeoBoundary(h3Address); assert boundary.numPoints() == points.size(); diff --git a/libs/h3/src/test/java/org/elasticsearch/h3/CellCenterTests.java b/libs/h3/src/test/java/org/elasticsearch/h3/CellCenterTests.java index af4d0a1f94b5b..525bd7234aa08 100644 --- a/libs/h3/src/test/java/org/elasticsearch/h3/CellCenterTests.java +++ b/libs/h3/src/test/java/org/elasticsearch/h3/CellCenterTests.java @@ -18,6 +18,7 @@ */ package org.elasticsearch.h3; +import io.github.pixee.security.BoundedLineReader; import org.elasticsearch.test.ESTestCase; import java.io.BufferedReader; @@ -145,7 +146,7 @@ public void testBc19r15centers() throws Exception { private void processFile(String file) throws IOException { InputStream fis = getClass().getResourceAsStream(file + ".gz"); BufferedReader reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(fis), StandardCharsets.UTF_8)); - String line = reader.readLine(); + String line = BoundedLineReader.readLine(reader, 5_000_000); while (line != null) { StringTokenizer tokenizer = new StringTokenizer(line, " "); assertEquals(3, tokenizer.countTokens()); @@ -156,7 +157,7 @@ private void processFile(String file) throws IOException { assertH3ToLatLng(h3Address, lat, lon); assertGeoToH3(h3Address, lat, lon); assertHexRing(h3Address); - line = reader.readLine(); + line = BoundedLineReader.readLine(reader, 5_000_000); } } diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java index 9bb0643907eb5..b3fbd1a350a67 100644 --- a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/PemUtils.java @@ -8,6 +8,7 @@ package org.elasticsearch.common.ssl; +import io.github.pixee.security.BoundedLineReader; import org.elasticsearch.core.CharArrays; import java.io.BufferedReader; @@ -128,9 +129,9 @@ public static PrivateKey readPrivateKey(Path path, Supplier passwordSupp */ static PrivateKey parsePrivateKey(Path keyPath, Supplier passwordSupplier) throws IOException, GeneralSecurityException { try (BufferedReader bReader = Files.newBufferedReader(keyPath, StandardCharsets.UTF_8)) { - String line = bReader.readLine(); + String line = BoundedLineReader.readLine(bReader, 5_000_000); while (null != line && line.startsWith(HEADER) == false) { - line = bReader.readLine(); + line = BoundedLineReader.readLine(bReader, 5_000_000); } if (null == line) { throw new SslConfigException("Error parsing Private Key [" + keyPath.toAbsolutePath() + "], file is empty"); @@ -170,18 +171,18 @@ static PrivateKey parsePrivateKey(Path keyPath, Supplier passwordSupplie * @throws IOException if the EC Parameter footer is missing */ private static BufferedReader removeECHeaders(BufferedReader bReader) throws IOException { - String line = bReader.readLine(); + String line = BoundedLineReader.readLine(bReader, 5_000_000); while (line != null) { if (OPENSSL_EC_PARAMS_FOOTER.equals(line.trim())) { break; } - line = bReader.readLine(); + line = BoundedLineReader.readLine(bReader, 5_000_000); } if (null == line || OPENSSL_EC_PARAMS_FOOTER.equals(line.trim()) == false) { throw new IOException("Malformed PEM file, EC Parameters footer is missing"); } // Verify that the key starts with the correct header before passing it to parseOpenSslEC - if (OPENSSL_EC_HEADER.equals(bReader.readLine()) == false) { + if (OPENSSL_EC_HEADER.equals(BoundedLineReader.readLine(bReader, 5_000_000)) == false) { throw new IOException("Malformed PEM file, EC Key header is missing"); } return bReader; @@ -194,18 +195,18 @@ private static BufferedReader removeECHeaders(BufferedReader bReader) throws IOE * @throws IOException if the EC Parameter footer is missing */ private static BufferedReader removeDsaHeaders(BufferedReader bReader) throws IOException { - String line = bReader.readLine(); + String line = BoundedLineReader.readLine(bReader, 5_000_000); while (line != null) { if (OPENSSL_DSA_PARAMS_FOOTER.equals(line.trim())) { break; } - line = bReader.readLine(); + line = BoundedLineReader.readLine(bReader, 5_000_000); } if (null == line || OPENSSL_DSA_PARAMS_FOOTER.equals(line.trim()) == false) { throw new IOException("Malformed PEM file, DSA Parameters footer is missing"); } // Verify that the key starts with the correct header before passing it to parseOpenSslDsa - if (OPENSSL_DSA_HEADER.equals(bReader.readLine()) == false) { + if (OPENSSL_DSA_HEADER.equals(BoundedLineReader.readLine(bReader, 5_000_000)) == false) { throw new IOException("Malformed PEM file, DSA Key header is missing"); } return bReader; @@ -222,13 +223,13 @@ private static BufferedReader removeDsaHeaders(BufferedReader bReader) throws IO */ private static PrivateKey parsePKCS8(BufferedReader bReader) throws IOException, GeneralSecurityException { StringBuilder sb = new StringBuilder(); - String line = bReader.readLine(); + String line = BoundedLineReader.readLine(bReader, 5_000_000); while (line != null) { if (PKCS8_FOOTER.equals(line.trim())) { break; } sb.append(line.trim()); - line = bReader.readLine(); + line = BoundedLineReader.readLine(bReader, 5_000_000); } if (null == line || PKCS8_FOOTER.equals(line.trim()) == false) { throw new IOException("Malformed PEM file, PEM footer is invalid or missing"); @@ -263,7 +264,7 @@ public static PrivateKey parsePKCS8PemString(String pemString) throws IOExceptio private static PrivateKey parseOpenSslEC(BufferedReader bReader, Supplier passwordSupplier) throws IOException, GeneralSecurityException { StringBuilder sb = new StringBuilder(); - String line = bReader.readLine(); + String line = BoundedLineReader.readLine(bReader, 5_000_000); Map pemHeaders = new HashMap<>(); while (line != null) { if (OPENSSL_EC_FOOTER.equals(line.trim())) { @@ -276,7 +277,7 @@ private static PrivateKey parseOpenSslEC(BufferedReader bReader, Supplier passwordSupplier) throws IOException, GeneralSecurityException { StringBuilder sb = new StringBuilder(); - String line = bReader.readLine(); + String line = BoundedLineReader.readLine(bReader, 5_000_000); Map pemHeaders = new HashMap<>(); while (line != null) { @@ -315,7 +316,7 @@ private static PrivateKey parsePKCS1Rsa(BufferedReader bReader, Supplier } else { sb.append(line.trim()); } - line = bReader.readLine(); + line = BoundedLineReader.readLine(bReader, 5_000_000); } if (null == line || PKCS1_FOOTER.equals(line.trim()) == false) { throw new IOException("Malformed PEM file, PEM footer is invalid or missing"); @@ -339,7 +340,7 @@ private static PrivateKey parsePKCS1Rsa(BufferedReader bReader, Supplier private static PrivateKey parseOpenSslDsa(BufferedReader bReader, Supplier passwordSupplier) throws IOException, GeneralSecurityException { StringBuilder sb = new StringBuilder(); - String line = bReader.readLine(); + String line = BoundedLineReader.readLine(bReader, 5_000_000); Map pemHeaders = new HashMap<>(); while (line != null) { @@ -354,7 +355,7 @@ private static PrivateKey parseOpenSslDsa(BufferedReader bReader, Supplier getMetadataToken(String metadataTokenUrl) { var in = urlConnection.getInputStream(); var reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)) ) { - return Optional.ofNullable(reader.readLine()).filter(s -> s.isBlank() == false); + return Optional.ofNullable(BoundedLineReader.readLine(reader, 5_000_000)).filter(s -> s.isBlank() == false); } catch (IOException e) { logger.warn("Unable to get a session token from IMDSv2 URI: " + metadataTokenUrl, e); return Optional.empty(); diff --git a/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/Ec2DiscoveryPlugin.java b/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/Ec2DiscoveryPlugin.java index 69447e800d4ac..e796e737dd990 100644 --- a/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/Ec2DiscoveryPlugin.java +++ b/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/Ec2DiscoveryPlugin.java @@ -10,6 +10,7 @@ import com.amazonaws.util.EC2MetadataUtils; import com.amazonaws.util.json.Jackson; +import io.github.pixee.security.BoundedLineReader; import org.elasticsearch.SpecialPermission; import org.elasticsearch.common.network.NetworkService; @@ -158,7 +159,7 @@ static Settings getAvailabilityZoneNodeAttributes(Settings settings, String azMe BufferedReader urlReader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)) ) { - final String metadataResult = urlReader.readLine(); + final String metadataResult = BoundedLineReader.readLine(urlReader, 5_000_000); if ((metadataResult == null) || (metadataResult.length() == 0)) { throw new IllegalStateException("no ec2 metadata returned from " + url); } else { diff --git a/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/Ec2NameResolver.java b/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/Ec2NameResolver.java index 5c8a2a8fb92f9..c85fffb04a6f7 100644 --- a/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/Ec2NameResolver.java +++ b/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/Ec2NameResolver.java @@ -9,6 +9,7 @@ package org.elasticsearch.discovery.ec2; import com.amazonaws.util.EC2MetadataUtils; +import io.github.pixee.security.BoundedLineReader; import org.elasticsearch.common.network.NetworkService.CustomNameResolver; import org.elasticsearch.core.IOUtils; @@ -95,7 +96,7 @@ public static InetAddress[] resolve(Ec2HostnameType type) throws IOException { in = SocketAccess.doPrivilegedIOException(urlConnection::getInputStream); BufferedReader urlReader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); - String metadataResult = urlReader.readLine(); + String metadataResult = BoundedLineReader.readLine(urlReader, 5_000_000); if (metadataResult == null || metadataResult.length() == 0) { throw new IOException("no gce metadata returned from [" + url + "] for [" + type.configName + "]"); } diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/node/hotthreads/NodesHotThreadsResponse.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/node/hotthreads/NodesHotThreadsResponse.java index 59307009f785b..fc2d676e1e64d 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/node/hotthreads/NodesHotThreadsResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/node/hotthreads/NodesHotThreadsResponse.java @@ -8,6 +8,7 @@ package org.elasticsearch.action.admin.cluster.node.hotthreads; +import io.github.pixee.security.BoundedLineReader; import org.elasticsearch.action.FailedNodeException; import org.elasticsearch.action.support.TransportAction; import org.elasticsearch.action.support.nodes.BaseNodesResponse; @@ -63,7 +64,7 @@ private LinesIterator(String input) { private void advance() { try { - nextLine = reader.readLine(); + nextLine = BoundedLineReader.readLine(reader, 5_000_000); } catch (IOException e) { assert false : e; // no actual IO happens here } diff --git a/server/src/main/java/org/elasticsearch/bootstrap/BootstrapChecks.java b/server/src/main/java/org/elasticsearch/bootstrap/BootstrapChecks.java index a99ed225b244b..2761264432e27 100644 --- a/server/src/main/java/org/elasticsearch/bootstrap/BootstrapChecks.java +++ b/server/src/main/java/org/elasticsearch/bootstrap/BootstrapChecks.java @@ -8,6 +8,7 @@ package org.elasticsearch.bootstrap; +import io.github.pixee.security.BoundedLineReader; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.lucene.util.Constants; @@ -501,7 +502,7 @@ BufferedReader getBufferedReader(final Path path) throws IOException { // visible for testing static String readProcSysVmMaxMapCount(final BufferedReader bufferedReader) throws IOException { - return bufferedReader.readLine(); + return BoundedLineReader.readLine(bufferedReader, 5_000_000); } // visible for testing diff --git a/server/src/main/java/org/elasticsearch/bootstrap/Spawner.java b/server/src/main/java/org/elasticsearch/bootstrap/Spawner.java index 4b09d5d143046..ae0a2b2611b54 100644 --- a/server/src/main/java/org/elasticsearch/bootstrap/Spawner.java +++ b/server/src/main/java/org/elasticsearch/bootstrap/Spawner.java @@ -8,6 +8,7 @@ package org.elasticsearch.bootstrap; +import io.github.pixee.security.BoundedLineReader; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.lucene.util.Constants; @@ -105,7 +106,7 @@ private void startPumpThread(String componentName, String streamName, InputStrea Thread t = new Thread(() -> { try (var br = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) { String line; - while ((line = br.readLine()) != null) { + while ((line = BoundedLineReader.readLine(br, 5_000_000)) != null) { // since we do not expect native controllers to ever write to stdout/stderr, we always log at warn level logger.warn(line); } diff --git a/server/src/main/java/org/elasticsearch/common/io/Streams.java b/server/src/main/java/org/elasticsearch/common/io/Streams.java index d12884de7845a..f87921733c9b3 100644 --- a/server/src/main/java/org/elasticsearch/common/io/Streams.java +++ b/server/src/main/java/org/elasticsearch/common/io/Streams.java @@ -8,6 +8,7 @@ package org.elasticsearch.common.io; +import io.github.pixee.security.BoundedLineReader; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.BytesStream; import org.elasticsearch.common.io.stream.BytesStreamOutput; @@ -152,7 +153,7 @@ public static List readAllLines(InputStream input) throws IOException { public static void readAllLines(InputStream input, Consumer consumer) throws IOException { try (BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8))) { String line; - while ((line = reader.readLine()) != null) { + while ((line = BoundedLineReader.readLine(reader, 5_000_000)) != null) { consumer.accept(line); } } diff --git a/server/src/main/java/org/elasticsearch/index/analysis/Analysis.java b/server/src/main/java/org/elasticsearch/index/analysis/Analysis.java index e19ee050c93a7..a26ac85334959 100644 --- a/server/src/main/java/org/elasticsearch/index/analysis/Analysis.java +++ b/server/src/main/java/org/elasticsearch/index/analysis/Analysis.java @@ -8,6 +8,7 @@ package org.elasticsearch.index.analysis; +import io.github.pixee.security.BoundedLineReader; import org.apache.lucene.analysis.CharArraySet; import org.apache.lucene.analysis.ar.ArabicAnalyzer; import org.apache.lucene.analysis.bg.BulgarianAnalyzer; @@ -261,7 +262,7 @@ private static List loadWordList(Path path, boolean removeComments) thro final List result = new ArrayList<>(); try (BufferedReader br = Files.newBufferedReader(path, StandardCharsets.UTF_8)) { String word; - while ((word = br.readLine()) != null) { + while ((word = BoundedLineReader.readLine(br, 5_000_000)) != null) { if (Strings.hasText(word) == false) { continue; } diff --git a/server/src/main/java/org/elasticsearch/node/InternalSettingsPreparer.java b/server/src/main/java/org/elasticsearch/node/InternalSettingsPreparer.java index 3ef69e1085cdc..084cbb8ffbee8 100644 --- a/server/src/main/java/org/elasticsearch/node/InternalSettingsPreparer.java +++ b/server/src/main/java/org/elasticsearch/node/InternalSettingsPreparer.java @@ -8,6 +8,7 @@ package org.elasticsearch.node; +import io.github.pixee.security.BoundedLineReader; import org.elasticsearch.cluster.ClusterName; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.SettingsException; @@ -92,7 +93,7 @@ static void loadConfigWithSubstitutions(Settings.Builder output, Path configFile StringBuilder builder = new StringBuilder((int) existingSize); try (BufferedReader reader = Files.newBufferedReader(configFile, StandardCharsets.UTF_8)) { String line; - while ((line = reader.readLine()) != null) { + while ((line = BoundedLineReader.readLine(reader, 5_000_000)) != null) { int dollarNdx; int nextNdx = 0; while ((dollarNdx = line.indexOf("${", nextNdx)) != -1) { diff --git a/server/src/main/java/org/elasticsearch/plugins/spi/SPIClassIterator.java b/server/src/main/java/org/elasticsearch/plugins/spi/SPIClassIterator.java index d906cf066ded2..835d729fe303e 100644 --- a/server/src/main/java/org/elasticsearch/plugins/spi/SPIClassIterator.java +++ b/server/src/main/java/org/elasticsearch/plugins/spi/SPIClassIterator.java @@ -18,6 +18,7 @@ package org.elasticsearch.plugins.spi; +import io.github.pixee.security.BoundedLineReader; import org.apache.lucene.util.IOUtils; import org.apache.lucene.util.SuppressForbidden; @@ -114,7 +115,7 @@ private boolean loadNextProfile() { try { final BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); String line; - while ((line = reader.readLine()) != null) { + while ((line = BoundedLineReader.readLine(reader, 5_000_000)) != null) { final int pos = line.indexOf('#'); if (pos >= 0) { line = line.substring(0, pos); diff --git a/server/src/test/java/org/elasticsearch/bootstrap/MaxMapCountCheckTests.java b/server/src/test/java/org/elasticsearch/bootstrap/MaxMapCountCheckTests.java index 3014d05e81036..39688c0222961 100644 --- a/server/src/test/java/org/elasticsearch/bootstrap/MaxMapCountCheckTests.java +++ b/server/src/test/java/org/elasticsearch/bootstrap/MaxMapCountCheckTests.java @@ -8,6 +8,7 @@ package org.elasticsearch.bootstrap; +import io.github.pixee.security.BoundedLineReader; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -114,7 +115,7 @@ public void testGetMaxMapCountOnLinux() { public void testGetMaxMapCount() throws IOException, IllegalAccessException { final long procSysVmMaxMapCount = randomIntBetween(1, Integer.MAX_VALUE); final BufferedReader reader = mock(BufferedReader.class); - when(reader.readLine()).thenReturn(Long.toString(procSysVmMaxMapCount)); + when(BoundedLineReader.readLine(reader, 5_000_000)).thenReturn(Long.toString(procSysVmMaxMapCount)); final Path procSysVmMaxMapCountPath = PathUtils.get("/proc/sys/vm/max_map_count"); BootstrapChecks.MaxMapCountCheck check = new BootstrapChecks.MaxMapCountCheck() { @Override @@ -130,7 +131,7 @@ BufferedReader getBufferedReader(Path path) throws IOException { { reset(reader); final IOException ioException = new IOException("fatal"); - when(reader.readLine()).thenThrow(ioException); + when(BoundedLineReader.readLine(reader, 5_000_000)).thenThrow(ioException); final Logger logger = LogManager.getLogger("testGetMaxMapCountIOException"); final MockLogAppender appender = new MockLogAppender(); appender.start(); @@ -153,7 +154,7 @@ BufferedReader getBufferedReader(Path path) throws IOException { { reset(reader); - when(reader.readLine()).thenReturn("eof"); + when(BoundedLineReader.readLine(reader, 5_000_000)).thenReturn("eof"); final Logger logger = LogManager.getLogger("testGetMaxMapCountNumberFormatException"); final MockLogAppender appender = new MockLogAppender(); appender.start(); @@ -218,7 +219,7 @@ public void assertMatched() { public void testMaxMapCountCheckRead() throws IOException { final String rawProcSysVmMaxMapCount = Long.toString(randomIntBetween(1, Integer.MAX_VALUE)); final BufferedReader reader = mock(BufferedReader.class); - when(reader.readLine()).thenReturn(rawProcSysVmMaxMapCount); + when(BoundedLineReader.readLine(reader, 5_000_000)).thenReturn(rawProcSysVmMaxMapCount); final BootstrapChecks.MaxMapCountCheck check = new BootstrapChecks.MaxMapCountCheck(); assertThat(BootstrapChecks.MaxMapCountCheck.readProcSysVmMaxMapCount(reader), equalTo(rawProcSysVmMaxMapCount)); } diff --git a/server/src/test/java/org/elasticsearch/cluster/routing/allocation/CatAllocationTestCase.java b/server/src/test/java/org/elasticsearch/cluster/routing/allocation/CatAllocationTestCase.java index ee4171f651ce4..d21b6fa600e67 100644 --- a/server/src/test/java/org/elasticsearch/cluster/routing/allocation/CatAllocationTestCase.java +++ b/server/src/test/java/org/elasticsearch/cluster/routing/allocation/CatAllocationTestCase.java @@ -8,6 +8,7 @@ package org.elasticsearch.cluster.routing.allocation; +import io.github.pixee.security.BoundedLineReader; import org.elasticsearch.action.ActionListener; import org.elasticsearch.cluster.ClusterName; import org.elasticsearch.cluster.ClusterState; @@ -63,7 +64,7 @@ public void testRun() throws IOException { "^(.+)\\s+(\\d)\\s+([rp])\\s+(STARTED|RELOCATING|INITIALIZING|UNASSIGNED)" + "\\s+\\d+\\s+[0-9.a-z]+\\s+(\\d+\\.\\d+\\.\\d+\\.\\d+).*$" ); - while ((line = reader.readLine()) != null) { + while ((line = BoundedLineReader.readLine(reader, 5_000_000)) != null) { final Matcher matcher; if ((matcher = pattern.matcher(line)).matches()) { final String index = matcher.group(1); diff --git a/test/fixtures/old-elasticsearch/src/main/java/oldes/OldElasticsearch.java b/test/fixtures/old-elasticsearch/src/main/java/oldes/OldElasticsearch.java index f3e5d72970d80..4e3a69c94a58e 100644 --- a/test/fixtures/old-elasticsearch/src/main/java/oldes/OldElasticsearch.java +++ b/test/fixtures/old-elasticsearch/src/main/java/oldes/OldElasticsearch.java @@ -8,6 +8,7 @@ package oldes; +import io.github.pixee.security.BoundedLineReader; import org.apache.lucene.util.Constants; import java.io.BufferedReader; @@ -104,7 +105,7 @@ public static void main(String[] args) throws IOException { ); try (BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { String line; - while ((line = stdout.readLine()) != null && (pid == 0 || port == 0)) { + while ((line = BoundedLineReader.readLine(stdout, 5_000_000)) != null && (pid == 0 || port == 0)) { System.out.println(line); Matcher m = pidPattern.matcher(line); if (m.find()) { diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java index 2d0abaa5cf4ca..0da878f5cb39d 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java @@ -8,6 +8,7 @@ package org.elasticsearch.test.rest; +import io.github.pixee.security.BoundedLineReader; import org.apache.http.Header; import org.apache.http.HttpHost; import org.apache.http.HttpStatus; @@ -539,7 +540,7 @@ public static void waitForPendingTasks(final RestClient restClient, final Predic int activeTasks = 0; String line; final StringBuilder tasksListString = new StringBuilder(); - while ((line = responseReader.readLine()) != null) { + while ((line = BoundedLineReader.readLine(responseReader, 5_000_000)) != null) { final String taskName = line.split("\\s+")[0]; if (taskName.startsWith(TransportListTasksAction.TYPE.name()) || taskName.startsWith(HealthNode.TASK_NAME) diff --git a/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/util/ProcessUtils.java b/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/util/ProcessUtils.java index c929f20195611..9109c24cd07ee 100644 --- a/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/util/ProcessUtils.java +++ b/test/test-clusters/src/main/java/org/elasticsearch/test/cluster/util/ProcessUtils.java @@ -8,6 +8,7 @@ package org.elasticsearch.test.cluster.util; +import io.github.pixee.security.BoundedLineReader; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -161,7 +162,7 @@ private static void startLoggingThread(InputStream is, Consumer logAppen new Thread(() -> { try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { String line; - while ((line = reader.readLine()) != null) { + while ((line = BoundedLineReader.readLine(reader, 5_000_000)) != null) { logAppender.accept(line); } } catch (IOException e) {