This is an automated email from the ASF dual-hosted git repository.
gerlowskija pushed a commit to branch branch_10_0
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/branch_10_0 by this push:
new dbb169a1a07 SOLR-18058: Tweak "allowPath" checks to avoid NPEs
dbb169a1a07 is described below
commit dbb169a1a07c9310df3eaa38c82107e721f2e330
Author: Jason Gerlowski <[email protected]>
AuthorDate: Fri Jan 9 12:22:50 2026 -0500
SOLR-18058: Tweak "allowPath" checks to avoid NPEs
---
gradle/libs.versions.toml | 1 -
solr/core/src/java/org/apache/solr/core/CoreContainer.java | 8 +++++++-
.../org/apache/solr/core/FileSystemConfigSetService.java | 13 +++++++++++++
solr/core/src/java/org/apache/solr/core/SolrPaths.java | 4 ++++
.../apache/solr/response/TestErrorResponseStackTrace.java | 5 +++++
.../apache/solr/response/TestPrometheusResponseWriter.java | 4 ++++
.../core/src/test/org/apache/solr/search/TestThinCache.java | 7 ++++++-
.../test/org/apache/solr/servlet/HideStackTraceTest.java | 5 +++++
.../client/solrj/jetty/HttpJettySolrClientProxyTest.java | 6 ++++++
.../org/apache/solr/util/EmbeddedSolrServerTestRule.java | 3 +++
10 files changed, 53 insertions(+), 3 deletions(-)
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 4a0531410bc..be018993437 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -182,7 +182,6 @@ openjdk-jmh = "1.37"
opentelemetry = "1.56.0"
opentelemetry-prometheus = "1.56.0-alpha"
opentelemetry-runtime-telemetry = "2.22.0-alpha"
-osgi-annotation = "8.1.0"
oshai-logging = "7.0.13"
# @keep for version alignment
ow2-asm = "9.8"
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 01e40d9f0fb..bb06a189b9f 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -434,6 +434,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());
}
@@ -1484,6 +1485,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());
@@ -1498,7 +1503,6 @@ public class CoreContainer {
}
// Validate paths are relative to known locations to avoid path traversal
- assertPathAllowed(cd.getInstanceDir());
assertPathAllowed(Path.of(cd.getDataDir()));
boolean preExistingZkEntry = false;
@@ -1570,6 +1574,8 @@ public class CoreContainer {
}
}
+ public static final String ALLOW_PATHS_SYSPROP = "solr.security.allow.paths";
+
/**
* 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 1b7cc819fbe..3d31349c066 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;
}
@@ -320,6 +326,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 145f3818698..1855b0fe205 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrPaths.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrPaths.java
@@ -125,6 +125,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/TestErrorResponseStackTrace.java
b/solr/core/src/test/org/apache/solr/response/TestErrorResponseStackTrace.java
index ce10d4e2d48..31abab9da58 100644
---
a/solr/core/src/test/org/apache/solr/response/TestErrorResponseStackTrace.java
+++
b/solr/core/src/test/org/apache/solr/response/TestErrorResponseStackTrace.java
@@ -16,6 +16,8 @@
*/
package org.apache.solr.response;
+import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP;
+
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -30,6 +32,7 @@ import org.apache.solr.client.solrj.apache.HttpClientUtil;
import org.apache.solr.client.solrj.request.QueryRequest;
import org.apache.solr.client.solrj.response.json.JsonMapResponseParser;
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.handler.component.ResponseBuilder;
import org.apache.solr.handler.component.SearchComponent;
@@ -47,6 +50,8 @@ public class TestErrorResponseStackTrace extends
SolrTestCaseJ4 {
public static void setupSolrHome() throws Exception {
Path configSet = createTempDir("configSet");
copyMinConf(configSet);
+ 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/core/src/test/org/apache/solr/response/TestPrometheusResponseWriter.java
b/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriter.java
index 2c86fc41bfb..34f31d47a5e 100644
---
a/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriter.java
+++
b/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriter.java
@@ -17,6 +17,7 @@
package org.apache.solr.response;
import static
org.apache.solr.client.solrj.response.InputStreamResponseParser.STREAM_KEY;
+import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP;
import java.io.InputStream;
import java.lang.invoke.MethodHandles;
@@ -34,6 +35,7 @@ import
org.apache.solr.client.solrj.SolrRequest.SolrRequestType;
import org.apache.solr.client.solrj.request.GenericSolrRequest;
import org.apache.solr.client.solrj.response.InputStreamResponseParser;
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.util.ExternalPaths;
import org.apache.solr.util.SolrJettyTestRule;
@@ -50,6 +52,8 @@ public class TestPrometheusResponseWriter extends
SolrTestCaseJ4 {
@BeforeClass
public static void beforeClass() throws Exception {
+ EnvUtils.setProperty(
+ ALLOW_PATHS_SYSPROP,
ExternalPaths.SERVER_HOME.toAbsolutePath().toString());
solrClientTestRule.startSolr(LuceneTestCase.createTempDir());
solrClientTestRule
.newCollection("core1")
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 55717b7d015..de11569c0bb 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,7 @@
*/
package org.apache.solr.search;
+import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP;
import static org.apache.solr.metrics.SolrMetricProducer.CATEGORY_ATTR;
import static org.apache.solr.metrics.SolrMetricProducer.NAME_ATTR;
@@ -44,6 +45,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"
@@ -60,11 +64,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);
// 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 db58af874c2..03a1b06a933 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.apache.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);
+ 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/solrj/src/test/org/apache/solr/client/solrj/jetty/HttpJettySolrClientProxyTest.java
b/solr/solrj/src/test/org/apache/solr/client/solrj/jetty/HttpJettySolrClientProxyTest.java
index ec887fe4f26..83864ba6d91 100644
---
a/solr/solrj/src/test/org/apache/solr/client/solrj/jetty/HttpJettySolrClientProxyTest.java
+++
b/solr/solrj/src/test/org/apache/solr/client/solrj/jetty/HttpJettySolrClientProxyTest.java
@@ -16,6 +16,8 @@
*/
package org.apache.solr.client.solrj.jetty;
+import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP;
+
import com.carrotsearch.randomizedtesting.RandomizedTest;
import java.util.Arrays;
import java.util.Objects;
@@ -27,6 +29,7 @@ import org.apache.solr.client.solrj.impl.HttpJdkSolrClient;
import org.apache.solr.client.solrj.impl.HttpSolrClientBase;
import org.apache.solr.client.solrj.request.SolrQuery;
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.SocketProxy;
@@ -46,6 +49,9 @@ public class HttpJettySolrClientProxyTest extends
SolrTestCaseJ4 {
public static void beforeTest() throws Exception {
RandomizedTest.assumeFalse(sslConfig.isSSLMode());
+ EnvUtils.setProperty(
+ ALLOW_PATHS_SYSPROP,
+ ExternalPaths.SERVER_HOME.toAbsolutePath().toString()); // 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());
}