This is an automated email from the ASF dual-hosted git repository.

gerlowskija pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/main by this push:
     new 2d2e35259f4 SOLR-18058: Tweak "allowPath" checks to avoid NPEs
2d2e35259f4 is described below

commit 2d2e35259f48c22af5f29db6d41d6e76dfb2ff86
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  |  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 +++++
 .../test/org/apache/solr/client/solrj/TestBatchUpdate.java  |  6 ++++++
 .../apache/solr/client/solrj/TestSolrJErrorHandling.java    |  6 ++++++
 .../solr/client/solrj/impl/HttpSolrClientBadInputTest.java  |  6 ++++++
 .../client/solrj/impl/LBHttpSolrClientBadInputTest.java     |  6 ++++++
 .../client/solrj/jetty/HttpJettySolrClientProxyTest.java    |  6 ++++++
 .../org/apache/solr/util/EmbeddedSolrServerTestRule.java    |  3 +++
 13 files changed, 77 insertions(+), 2 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 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 869e3941543..cda8bbf8130 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 b38706a0108..d9d2493eb3a 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;
@@ -31,6 +32,7 @@ import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.request.MetricsRequest;
 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;
@@ -47,6 +49,8 @@ public class TestPrometheusResponseWriter extends 
SolrTestCaseJ4 {
 
   @BeforeClass
   public static void beforeClass() throws Exception {
+    EnvUtils.setProperty(
+        ALLOW_PATHS_SYSPROP, 
ExternalPaths.SERVER_HOME.toAbsolutePath().toString());
     solrTestRule.startSolr(LuceneTestCase.createTempDir());
     
solrTestRule.newCollection("core1").withConfigSet(ExternalPaths.DEFAULT_CONFIGSET).create();
     
solrTestRule.newCollection("core2").withConfigSet(ExternalPaths.DEFAULT_CONFIGSET).create();
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 02e3a529edb..8e67007d9bb 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;
 
@@ -46,6 +47,9 @@ public class TestThinCache extends SolrTestCaseJ4 {
 
   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"
@@ -62,11 +66,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);
 
     solrTestRule.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 1b589cf5687..d8bbdb094e3 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/TestBatchUpdate.java 
b/solr/solrj/src/test/org/apache/solr/client/solrj/TestBatchUpdate.java
index 32165843828..85dd1c8266d 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/TestBatchUpdate.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/TestBatchUpdate.java
@@ -16,6 +16,8 @@
  */
 package org.apache.solr.client.solrj;
 
+import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP;
+
 import java.io.IOException;
 import java.util.Iterator;
 import org.apache.solr.SolrTestCaseJ4;
@@ -27,6 +29,7 @@ import org.apache.solr.client.solrj.request.SolrQuery;
 import org.apache.solr.client.solrj.request.XMLRequestWriter;
 import org.apache.solr.client.solrj.response.QueryResponse;
 import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.util.EnvUtils;
 import org.apache.solr.util.ExternalPaths;
 import org.apache.solr.util.SolrJettyTestRule;
 import org.junit.BeforeClass;
@@ -45,6 +48,9 @@ public class TestBatchUpdate extends SolrTestCaseJ4 {
 
   @BeforeClass
   public static void beforeTest() throws Exception {
+    EnvUtils.setProperty(
+        ALLOW_PATHS_SYSPROP,
+        ExternalPaths.SERVER_HOME.toAbsolutePath().toString()); // Needed for 
configset location
     solrTestRule.startSolr(createTempDir());
     solrTestRule
         .newCollection("collection1")
diff --git 
a/solr/solrj/src/test/org/apache/solr/client/solrj/TestSolrJErrorHandling.java 
b/solr/solrj/src/test/org/apache/solr/client/solrj/TestSolrJErrorHandling.java
index 7795057a109..2a5ca071267 100644
--- 
a/solr/solrj/src/test/org/apache/solr/client/solrj/TestSolrJErrorHandling.java
+++ 
b/solr/solrj/src/test/org/apache/solr/client/solrj/TestSolrJErrorHandling.java
@@ -16,6 +16,8 @@
  */
 package org.apache.solr.client.solrj;
 
+import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP;
+
 import java.io.BufferedOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -42,6 +44,7 @@ import 
org.apache.solr.client.solrj.request.JavaBinRequestWriter;
 import org.apache.solr.client.solrj.request.XMLRequestWriter;
 import org.apache.solr.client.solrj.response.QueryResponse;
 import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.util.EnvUtils;
 import org.apache.solr.util.ExternalPaths;
 import org.apache.solr.util.SolrJettyTestRule;
 import org.junit.BeforeClass;
@@ -60,6 +63,9 @@ public class TestSolrJErrorHandling extends SolrTestCaseJ4 {
 
   @BeforeClass
   public static void beforeTest() throws Exception {
+    EnvUtils.setProperty(
+        ALLOW_PATHS_SYSPROP,
+        ExternalPaths.SERVER_HOME.toAbsolutePath().toString()); // Needed for 
configset location
     solrTestRule.startSolr(createTempDir());
     solrTestRule
         .newCollection("collection1")
diff --git 
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientBadInputTest.java
 
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientBadInputTest.java
index 37c1dc0211f..8eaa9feb82a 100644
--- 
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientBadInputTest.java
+++ 
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpSolrClientBadInputTest.java
@@ -17,11 +17,14 @@
 
 package org.apache.solr.client.solrj.impl;
 
+import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP;
+
 import java.util.ArrayList;
 import java.util.List;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.apache.HttpSolrClient;
+import org.apache.solr.common.util.EnvUtils;
 import org.apache.solr.util.ExternalPaths;
 import org.apache.solr.util.SolrJettyTestRule;
 import org.junit.BeforeClass;
@@ -39,6 +42,9 @@ public class HttpSolrClientBadInputTest extends 
SolrTestCaseJ4 {
 
   @BeforeClass
   public static void beforeTest() throws Exception {
+    EnvUtils.setProperty(
+        ALLOW_PATHS_SYSPROP,
+        ExternalPaths.SERVER_HOME.toAbsolutePath().toString()); // Needed for 
configset location
     solrTestRule.startSolr(createTempDir());
     solrTestRule
         .newCollection("collection1")
diff --git 
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/LBHttpSolrClientBadInputTest.java
 
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/LBHttpSolrClientBadInputTest.java
index df69c1938d8..647f912b11d 100644
--- 
a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/LBHttpSolrClientBadInputTest.java
+++ 
b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/LBHttpSolrClientBadInputTest.java
@@ -17,11 +17,14 @@
 
 package org.apache.solr.client.solrj.impl;
 
+import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP;
+
 import java.util.ArrayList;
 import java.util.List;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.apache.LBHttpSolrClient;
+import org.apache.solr.common.util.EnvUtils;
 import org.apache.solr.util.ExternalPaths;
 import org.apache.solr.util.SolrJettyTestRule;
 import org.junit.BeforeClass;
@@ -38,6 +41,9 @@ public class LBHttpSolrClientBadInputTest extends 
SolrTestCaseJ4 {
 
   @BeforeClass
   public static void beforeTest() throws Exception {
+    EnvUtils.setProperty(
+        ALLOW_PATHS_SYSPROP,
+        ExternalPaths.SERVER_HOME.toAbsolutePath().toString()); // Needed for 
configset location
     solrTestRule.startSolr(createTempDir());
     solrTestRule
         .newCollection("collection1")
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 8d5488ff6b1..20d44bc107d 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;
@@ -26,6 +28,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.util.ExternalPaths;
 import org.apache.solr.util.SocketProxy;
 import org.apache.solr.util.SolrJettyTestRule;
@@ -44,6 +47,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
     solrTestRule.enableProxy();
     solrTestRule.startSolr(createTempDir());
     // 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());
   }
 

Reply via email to