This is an automated email from the ASF dual-hosted git repository.
gerlowskija pushed a commit to branch branch_9x
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/branch_9x by this push:
new aab58730ddc SOLR-18058: Tweak "allowPath" checks to avoid NPEs
aab58730ddc is described below
commit aab58730ddcde7e8bbc3368084fe5b374a4e9520
Author: Jason Gerlowski <[email protected]>
AuthorDate: Fri Jan 9 12:22:50 2026 -0500
SOLR-18058: Tweak "allowPath" checks to avoid NPEs
---
solr/core/src/java/org/apache/solr/core/CoreContainer.java | 11 ++++++++---
.../org/apache/solr/core/FileSystemConfigSetService.java | 13 +++++++++++++
solr/core/src/java/org/apache/solr/core/SolrPaths.java | 4 ++++
.../apache/solr/response/TestPrometheusResponseWriter.java | 4 ++++
.../core/src/test/org/apache/solr/search/TestThinCache.java | 8 +++++++-
.../test/org/apache/solr/servlet/HideStackTraceTest.java | 5 +++++
.../scraper/SolrStandaloneScraperBasicAuthTest.java | 5 ++++-
.../solr/prometheus/scraper/SolrStandaloneScraperTest.java | 6 ++++--
.../solr/client/solrj/impl/Http2SolrClientProxyTest.java | 5 +++++
.../org/apache/solr/util/EmbeddedSolrServerTestRule.java | 3 +++
10 files changed, 57 insertions(+), 7 deletions(-)
diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
index 2ed0a3fb2d1..149e1c4ffc3 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -38,7 +38,6 @@ import jakarta.inject.Singleton;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collections;
@@ -447,6 +446,7 @@ public class CoreContainer {
SolrPaths.AllowPathBuilder allowPathBuilder = new
SolrPaths.AllowPathBuilder();
allowPathBuilder.addPath(cfg.getSolrHome());
allowPathBuilder.addPath(cfg.getCoreRootDirectory());
+ allowPathBuilder.addPath(cfg.getConfigSetBaseDirectory());
if (cfg.getSolrDataHome() != null) {
allowPathBuilder.addPath(cfg.getSolrDataHome());
}
@@ -1593,6 +1593,10 @@ public class CoreContainer {
log.warn(msg);
throw new SolrException(ErrorCode.CONFLICT, msg);
}
+
+ // Validate 'instancePath' prior to instantiating CoreDescriptor, as CD
construction attempts
+ // to read properties from 'instancePath'
+ assertPathAllowed(instancePath);
CoreDescriptor cd =
new CoreDescriptor(
coreName, instancePath, parameters, getContainerProperties(),
getZkController());
@@ -1607,8 +1611,7 @@ public class CoreContainer {
}
// Validate paths are relative to known locations to avoid path traversal
- assertPathAllowed(cd.getInstanceDir());
- assertPathAllowed(Paths.get(cd.getDataDir()));
+ assertPathAllowed(Path.of(cd.getDataDir()));
boolean preExistingZkEntry = false;
try {
@@ -1679,6 +1682,8 @@ public class CoreContainer {
}
}
+ public static final String ALLOW_PATHS_SYSPROP = "solr.allowPaths";
+
/**
* Checks that the given path is relative to SOLR_HOME, SOLR_DATA_HOME,
coreRootDirectory or one
* of the paths specified in solr.xml's allowPaths element. Delegates to
{@link
diff --git
a/solr/core/src/java/org/apache/solr/core/FileSystemConfigSetService.java
b/solr/core/src/java/org/apache/solr/core/FileSystemConfigSetService.java
index 56f17c395d1..72a98acd4e2 100644
--- a/solr/core/src/java/org/apache/solr/core/FileSystemConfigSetService.java
+++ b/solr/core/src/java/org/apache/solr/core/FileSystemConfigSetService.java
@@ -56,15 +56,21 @@ public class FileSystemConfigSetService extends
ConfigSetService {
public static final String METADATA_FILE = ".metadata.json";
private final Path configSetBase;
+ // TODO currently it's not really possible to check paths against allowPaths
without a
+ // CoreContainer reference, see SOLR-18059
+ private final CoreContainer cc;
public FileSystemConfigSetService(CoreContainer cc) {
super(cc.getResourceLoader(), cc.getConfig().hasSchemaCache());
+
+ this.cc = cc;
this.configSetBase = cc.getConfig().getConfigSetBaseDirectory();
}
/** Testing purpose */
protected FileSystemConfigSetService(Path configSetBase) {
super(null, false);
+ this.cc = null;
this.configSetBase = configSetBase;
}
@@ -317,6 +323,13 @@ public class FileSystemConfigSetService extends
ConfigSetService {
String configSet = cd.getConfigSet();
if (configSet == null) return cd.getInstanceDir();
Path configSetDirectory = configSetBase.resolve(configSet);
+
+ // CoreContainer only null in testing scenarios - bit of a hack, but will
go away with
+ // SOLR-18059
+ if (cc != null) {
+ cc.assertPathAllowed(configSetDirectory);
+ }
+
if (!Files.isDirectory(configSetDirectory))
throw new SolrException(
SolrException.ErrorCode.SERVER_ERROR,
diff --git a/solr/core/src/java/org/apache/solr/core/SolrPaths.java
b/solr/core/src/java/org/apache/solr/core/SolrPaths.java
index 7906c1e219f..dc7efe471aa 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrPaths.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrPaths.java
@@ -126,6 +126,10 @@ public final class SolrPaths {
* (not supported as a {@link Path} on Windows), see {@link
#addPath(String)}.
*/
public AllowPathBuilder addPath(Path path) {
+ if (path == null) {
+ return this;
+ }
+
if (paths != ALL_PATHS) {
if (path.equals(ALL_PATH)) {
paths = ALL_PATHS;
diff --git
a/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriter.java
b/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriter.java
index 7f15a6ae894..7ea3b352bf6 100644
---
a/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriter.java
+++
b/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriter.java
@@ -16,6 +16,8 @@
*/
package org.apache.solr.response;
+import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP;
+
import com.codahale.metrics.Counter;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.Meter;
@@ -33,6 +35,7 @@ import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.impl.NoOpResponseParser;
import org.apache.solr.client.solrj.request.QueryRequest;
import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.util.EnvUtils;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.util.ExternalPaths;
@@ -53,6 +56,7 @@ public class TestPrometheusResponseWriter extends
SolrTestCaseJ4 {
public static void beforeClass() throws Exception {
SharedMetricRegistries.clear();
+ EnvUtils.setProperty(ALLOW_PATHS_SYSPROP, ExternalPaths.SERVER_HOME);
solrClientTestRule.startSolr(LuceneTestCase.createTempDir());
solrClientTestRule.newCollection().withConfigSet(ExternalPaths.DEFAULT_CONFIGSET).create();
var cc = solrClientTestRule.getCoreContainer();
diff --git a/solr/core/src/test/org/apache/solr/search/TestThinCache.java
b/solr/core/src/test/org/apache/solr/search/TestThinCache.java
index c485b9fe46a..6de790500ee 100644
--- a/solr/core/src/test/org/apache/solr/search/TestThinCache.java
+++ b/solr/core/src/test/org/apache/solr/search/TestThinCache.java
@@ -16,6 +16,8 @@
*/
package org.apache.solr.search;
+import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP;
+
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
@@ -39,6 +41,9 @@ public class TestThinCache extends SolrTestCaseJ4 {
@ClassRule public static EmbeddedSolrServerTestRule solrRule = new
EmbeddedSolrServerTestRule();
public static final String SOLR_NODE_LEVEL_CACHE_XML =
"<solr>\n"
+ + " <str name=\"allowPaths\">${"
+ + ALLOW_PATHS_SYSPROP
+ + ":}</str>"
+ " <caches>\n"
+ " <cache name='myNodeLevelCache'\n"
+ " size='10'\n"
@@ -55,11 +60,12 @@ public class TestThinCache extends SolrTestCaseJ4 {
@BeforeClass
public static void setupSolrHome() throws Exception {
Path home = createTempDir("home");
+ Path configSet = createTempDir("configSet");
+ System.setProperty(ALLOW_PATHS_SYSPROP,
configSet.toAbsolutePath().toString());
Files.writeString(home.resolve("solr.xml"), SOLR_NODE_LEVEL_CACHE_XML);
solrRule.startSolr(home);
- Path configSet = createTempDir("configSet");
copyMinConf(configSet.toFile());
// insert a special filterCache configuration
Path solrConfig = configSet.resolve("conf/solrconfig.xml");
diff --git a/solr/core/src/test/org/apache/solr/servlet/HideStackTraceTest.java
b/solr/core/src/test/org/apache/solr/servlet/HideStackTraceTest.java
index 54ac3e28b5a..30c1b85d0a0 100644
--- a/solr/core/src/test/org/apache/solr/servlet/HideStackTraceTest.java
+++ b/solr/core/src/test/org/apache/solr/servlet/HideStackTraceTest.java
@@ -16,6 +16,8 @@
*/
package org.apache.solr.servlet;
+import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP;
+
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -26,6 +28,7 @@ import org.apache.lucene.tests.util.LuceneTestCase;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.SolrTestCaseJ4.SuppressSSL;
import org.apache.solr.client.solrj.impl.HttpClientUtil;
+import org.apache.solr.common.util.EnvUtils;
import org.apache.solr.handler.component.ResponseBuilder;
import org.apache.solr.handler.component.SearchComponent;
import org.apache.solr.util.SolrJettyTestRule;
@@ -47,6 +50,8 @@ public class HideStackTraceTest extends SolrTestCaseJ4 {
Path configSet = createTempDir("configSet");
copyMinConf(configSet.toFile());
+ EnvUtils.setProperty(ALLOW_PATHS_SYSPROP,
configSet.toAbsolutePath().toString());
+
// insert a special filterCache configuration
Path solrConfig = configSet.resolve("conf/solrconfig.xml");
Files.writeString(
diff --git
a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperBasicAuthTest.java
b/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperBasicAuthTest.java
index b08e771e7d3..46895894879 100644
---
a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperBasicAuthTest.java
+++
b/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperBasicAuthTest.java
@@ -71,10 +71,13 @@ public class SolrStandaloneScraperBasicAuthTest extends
SolrTestCaseJ4 {
public static void setupSolrHome() throws Exception {
Path solrHome = LuceneTestCase.createTempDir();
Files.write(solrHome.resolve("security.json"),
securityJson.getBytes(StandardCharsets.UTF_8));
- solrRule.startSolr(solrHome);
Path configSet = LuceneTestCase.createTempDir();
SolrStandaloneScraperTest.createConf(configSet);
+ System.setProperty("solr.allowPaths",
configSet.toAbsolutePath().toString());
+
+ solrRule.startSolr(solrHome);
+
solrRule
.newCollection()
.withConfigSet(configSet.toString())
diff --git
a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperTest.java
b/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperTest.java
index 7f756c0fb3e..fa088a9c12d 100644
---
a/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperTest.java
+++
b/solr/prometheus-exporter/src/test/org/apache/solr/prometheus/scraper/SolrStandaloneScraperTest.java
@@ -54,10 +54,12 @@ public class SolrStandaloneScraperTest extends
SolrTestCaseJ4 {
@BeforeClass
public static void setupBeforeClass() throws Exception {
- solrRule.startSolr(LuceneTestCase.createTempDir());
-
Path configSet = LuceneTestCase.createTempDir();
createConf(configSet);
+ System.setProperty("solr.allowPaths",
configSet.toAbsolutePath().toString());
+
+ solrRule.startSolr(LuceneTestCase.createTempDir());
+
solrRule.newCollection().withConfigSet(configSet.toString()).create();
PrometheusExporterSettings settings =
PrometheusExporterSettings.builder().build();
diff --git
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientProxyTest.java
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientProxyTest.java
index 99ea3af66c1..41dff2ec488 100644
---
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientProxyTest.java
+++
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/Http2SolrClientProxyTest.java
@@ -16,6 +16,8 @@
*/
package org.apache.solr.client.solrj.impl;
+import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP;
+
import com.carrotsearch.randomizedtesting.RandomizedTest;
import java.util.Arrays;
import java.util.Objects;
@@ -26,6 +28,7 @@ import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.cloud.SocketProxy;
import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.util.EnvUtils;
import org.apache.solr.embedded.JettyConfig;
import org.apache.solr.util.ExternalPaths;
import org.apache.solr.util.SolrJettyTestRule;
@@ -44,6 +47,8 @@ public class Http2SolrClientProxyTest extends SolrTestCaseJ4 {
public static void beforeTest() throws Exception {
RandomizedTest.assumeFalse(sslConfig.isSSLMode());
+ EnvUtils.setProperty(
+ ALLOW_PATHS_SYSPROP, ExternalPaths.SERVER_HOME); // Needed for
configset location
solrClientTestRule.enableProxy();
solrClientTestRule.startSolr(createTempDir(), new Properties(),
JettyConfig.builder().build());
// Actually only need extremely minimal configSet but just use the default
diff --git
a/solr/test-framework/src/java/org/apache/solr/util/EmbeddedSolrServerTestRule.java
b/solr/test-framework/src/java/org/apache/solr/util/EmbeddedSolrServerTestRule.java
index b7c1e3d003c..1d4cd23b9a5 100644
---
a/solr/test-framework/src/java/org/apache/solr/util/EmbeddedSolrServerTestRule.java
+++
b/solr/test-framework/src/java/org/apache/solr/util/EmbeddedSolrServerTestRule.java
@@ -19,10 +19,12 @@ package org.apache.solr.util;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Properties;
+import java.util.Set;
import org.apache.lucene.tests.util.LuceneTestCase;
import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.NodeConfig;
+import org.apache.solr.core.SolrPaths;
import org.apache.solr.core.SolrXmlConfig;
import org.apache.solr.update.UpdateShardHandlerConfig;
@@ -87,6 +89,7 @@ public class EmbeddedSolrServerTestRule extends
SolrClientTestRule {
return new NodeConfig.NodeConfigBuilder("testNode", solrHome)
.setUpdateShardHandlerConfig(UpdateShardHandlerConfig.TEST_DEFAULT)
+ .setAllowPaths(Set.of(SolrPaths.ALL_PATH))
.setCoreRootDirectory(LuceneTestCase.createTempDir("cores").toString());
}