You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by do...@apache.org on 2026/06/15 06:10:20 UTC

(spark) branch master updated: [SPARK-57441][SQL] Disallow setting JVM system properties in `Spark Thrift Server` sessions

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

dongjoon-hyun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/master by this push:
     new a581785b7b82 [SPARK-57441][SQL] Disallow setting JVM system properties in `Spark Thrift Server` sessions
a581785b7b82 is described below

commit a581785b7b82d3b0d5a8903bf5b5b8bd9c2d0f4b
Author: Dongjoon Hyun <do...@apache.org>
AuthorDate: Sun Jun 14 23:10:09 2026 -0700

    [SPARK-57441][SQL] Disallow setting JVM system properties in `Spark Thrift Server` sessions
    
    ### What changes were proposed in this pull request?
    
    This PR aims to make Spark Thrift Server rejects setting JVM system properties via the `set:system:` session config overlay (e.g. `set:system:foo=bar` in a JDBC URL), matching how the `env:*` prefix is already handled in `HiveSessionImpl.setVariable` for Apache Spark 4.3.0.
    
    A new static config `spark.sql.legacy.hive.thriftServer.allowSettingSystemProperties` (default `false`) restores the old behavior when set to `true`. It is propagated into the session `HiveConf` in `SparkSQLSessionManager.init` so that `setVariable` can read it during session open.
    
    ### Why are the changes needed?
    
    The `set:system:` overlay lets an untrusted per-connection client mutate the shared Thrift Server's process-wide JVM state. The `env:*` prefix is already rejected for the same reason; `system:*` should be too.
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes. `set:system:` overlays (e.g. `jdbc:hive2://host:port/db?set:system:foo=bar`) are now rejected by default instead of applied. Set `spark.sql.legacy.hive.thriftServer.allowSettingSystemProperties` to `true` to restore the old behavior. Documented in `docs/sql-migration-guide.md`.
    
    ### How was this patch tested?
    
    New `HiveSessionImplSuite` tests covering both the default (rejected) and legacy-enabled (applied) cases.
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Claude Opus 4.8)
    
    Closes #56501 from dongjoon-hyun/SPARK-57441.
    
    Authored-by: Dongjoon Hyun <do...@apache.org>
    Signed-off-by: Dongjoon Hyun <do...@apache.org>
---
 docs/sql-migration-guide.md                        |  1 +
 .../apache/spark/sql/internal/StaticSQLConf.scala  | 11 ++++++
 .../hive/service/cli/session/HiveSessionImpl.java  | 18 +++++++--
 .../hive/thriftserver/SparkSQLSessionManager.scala |  8 +++-
 .../hive/thriftserver/HiveSessionImplSuite.scala   | 44 ++++++++++++++++++++++
 5 files changed, 77 insertions(+), 5 deletions(-)

diff --git a/docs/sql-migration-guide.md b/docs/sql-migration-guide.md
index f0a1ed352fdf..e39017c91884 100644
--- a/docs/sql-migration-guide.md
+++ b/docs/sql-migration-guide.md
@@ -25,6 +25,7 @@ license: |
 ## Upgrading from Spark SQL 4.2 to 4.3
 
 - Since Spark 4.3, the configuration key `spark.sql.sources.v2.bucketing.allowJoinKeysSubsetOfPartitionKeys.enabled` has been renamed to `spark.sql.sources.v2.bucketing.allowKeysSubsetOfPartitionKeys.enabled` to reflect that it now applies to storage-partitioned joins, aggregates, and windows. The old key continues to work as an alias.
+- Since Spark 4.3, the Spark Thrift Server rejects setting JVM system properties through the `set:system:` session configuration overlay (for example, in a JDBC connection string). To restore the previous behavior, set `spark.sql.legacy.hive.thriftServer.allowSettingSystemProperties` to `true`.
 
 ## Upgrading from Spark SQL 4.1 to 4.2
 
diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/internal/StaticSQLConf.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/internal/StaticSQLConf.scala
index 9a3bc9d69d43..9855244c968c 100644
--- a/sql/catalyst/src/main/scala/org/apache/spark/sql/internal/StaticSQLConf.scala
+++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/internal/StaticSQLConf.scala
@@ -125,6 +125,17 @@ object StaticSQLConf {
       .booleanConf
       .createWithDefault(false)
 
+  val LEGACY_HIVE_THRIFT_SERVER_ALLOW_SETTING_SYSTEM_PROPERTIES =
+    buildStaticConf("spark.sql.legacy.hive.thriftServer.allowSettingSystemProperties")
+      .internal()
+      .doc("When set to true, the Hive Thrift Server allows setting JVM system properties " +
+        "through the 'set:system:' session configuration overlay (for example, in a JDBC " +
+        "connection string). By default, such system property assignments are rejected.")
+      .version("4.3.0")
+      .withBindingPolicy(ConfigBindingPolicy.NOT_APPLICABLE)
+      .booleanConf
+      .createWithDefault(false)
+
   val HIVE_THRIFT_SERVER_HTTP_SNI_HOST_CHECK_ENABLED =
     buildStaticConf("spark.sql.hive.thriftServer.http.sniHostCheckEnabled")
       .internal()
diff --git a/sql/hive-thriftserver/src/main/java/org/apache/hive/service/cli/session/HiveSessionImpl.java b/sql/hive-thriftserver/src/main/java/org/apache/hive/service/cli/session/HiveSessionImpl.java
index 14404e319886..512c2716f8b7 100644
--- a/sql/hive-thriftserver/src/main/java/org/apache/hive/service/cli/session/HiveSessionImpl.java
+++ b/sql/hive-thriftserver/src/main/java/org/apache/hive/service/cli/session/HiveSessionImpl.java
@@ -234,8 +234,10 @@ public class HiveSessionImpl implements HiveSession {
     }
   }
 
-  // Copy from org.apache.hadoop.hive.ql.processors.SetProcessor, only change:
-  // setConf(varname, propName, varvalue, true) when varname.startsWith(HIVECONF_PREFIX)
+  // Copy from org.apache.hadoop.hive.ql.processors.SetProcessor, only changes:
+  // 1. setConf(varname, propName, varvalue, true) when varname.startsWith(HIVECONF_PREFIX)
+  // 2. system:* variables can not be set unless the legacy configuration
+  //    spark.sql.legacy.hive.thriftServer.allowSettingSystemProperties is enabled
   public static int setVariable(String varname, String varvalue) throws Exception {
     SessionState ss = SessionState.get();
     VariableSubstitution substitution = new VariableSubstitution(() -> ss.getHiveVariables());
@@ -247,8 +249,16 @@ public class HiveSessionImpl implements HiveSession {
       ss.err.println("env:* variables can not be set.");
       return 1;
     } else if (varname.startsWith(SYSTEM_PREFIX)){
-      String propName = varname.substring(SYSTEM_PREFIX.length());
-      System.getProperties().setProperty(propName, substitution.substitute(ss.getConf(),varvalue));
+      // Setting JVM system properties is allowed only when the legacy configuration
+      // spark.sql.legacy.hive.thriftServer.allowSettingSystemProperties is enabled.
+      if (ss.getConf().getBoolean(
+          "spark.sql.legacy.hive.thriftServer.allowSettingSystemProperties", false)) {
+        String propName = varname.substring(SYSTEM_PREFIX.length());
+        System.getProperties().setProperty(propName, substitution.substitute(ss.getConf(),varvalue));
+      } else {
+        ss.err.println("system:* variables can not be set.");
+        return 1;
+      }
     } else if (varname.startsWith(HIVECONF_PREFIX)){
       String propName = varname.substring(HIVECONF_PREFIX.length());
       setConf(varname, propName, varvalue, true);
diff --git a/sql/hive-thriftserver/src/main/scala/org/apache/spark/sql/hive/thriftserver/SparkSQLSessionManager.scala b/sql/hive-thriftserver/src/main/scala/org/apache/spark/sql/hive/thriftserver/SparkSQLSessionManager.scala
index ce3ece75c0ae..6a4b41b93547 100644
--- a/sql/hive-thriftserver/src/main/scala/org/apache/spark/sql/hive/thriftserver/SparkSQLSessionManager.scala
+++ b/sql/hive-thriftserver/src/main/scala/org/apache/spark/sql/hive/thriftserver/SparkSQLSessionManager.scala
@@ -29,7 +29,7 @@ import org.apache.spark.internal.Logging
 import org.apache.spark.sql.SparkSession
 import org.apache.spark.sql.hive.thriftserver.ReflectionUtils._
 import org.apache.spark.sql.hive.thriftserver.server.SparkSQLOperationManager
-import org.apache.spark.sql.internal.SQLConf
+import org.apache.spark.sql.internal.{SQLConf, StaticSQLConf}
 
 
 private[hive] class SparkSQLSessionManager(hiveServer: HiveServer2, sparkSession: SparkSession)
@@ -40,6 +40,12 @@ private[hive] class SparkSQLSessionManager(hiveServer: HiveServer2, sparkSession
 
   override def init(hiveConf: HiveConf): Unit = {
     setSuperField(this, "operationManager", sparkSqlOperationManager)
+    // Propagate the legacy toggle into HiveConf so that HiveSessionImpl.setVariable,
+    // which runs during session open before the SparkSession is attached, can read it.
+    hiveConf.setBoolean(
+      StaticSQLConf.LEGACY_HIVE_THRIFT_SERVER_ALLOW_SETTING_SYSTEM_PROPERTIES.key,
+      sparkSession.sessionState.conf.getConf(
+        StaticSQLConf.LEGACY_HIVE_THRIFT_SERVER_ALLOW_SETTING_SYSTEM_PROPERTIES))
     super.init(hiveConf)
   }
 
diff --git a/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/HiveSessionImplSuite.scala b/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/HiveSessionImplSuite.scala
index 6f89fbfb788b..89dfe2a6c492 100644
--- a/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/HiveSessionImplSuite.scala
+++ b/sql/hive-thriftserver/src/test/scala/org/apache/spark/sql/hive/thriftserver/HiveSessionImplSuite.scala
@@ -16,18 +16,21 @@
  */
 package org.apache.spark.sql.hive.thriftserver
 
+import java.io.{ByteArrayOutputStream, PrintStream}
 import java.lang.reflect.InvocationTargetException
 
 import scala.collection.mutable
 import scala.jdk.CollectionConverters._
 
 import org.apache.hadoop.hive.conf.HiveConf
+import org.apache.hadoop.hive.ql.session.SessionState
 import org.apache.hive.service.cli.OperationHandle
 import org.apache.hive.service.cli.operation.{GetCatalogsOperation, Operation, OperationManager}
 import org.apache.hive.service.cli.session.{HiveSession, HiveSessionImpl, SessionManager}
 import org.apache.hive.service.rpc.thrift.TProtocolVersion
 
 import org.apache.spark.SparkFunSuite
+import org.apache.spark.sql.internal.StaticSQLConf
 
 class HiveSessionImplSuite extends SparkFunSuite {
   private var session: HiveSessionImpl = _
@@ -61,6 +64,47 @@ class HiveSessionImplSuite extends SparkFunSuite {
     assert(operationManager.getCalledHandles.contains(operationHandle1))
     assert(operationManager.getCalledHandles.contains(operationHandle2))
   }
+
+  private def withSystemPropSession[T](allowSettingSystemProperties: Boolean)(f: => T): T = {
+    val conf = new HiveConf()
+    conf.setBoolean(
+      StaticSQLConf.LEGACY_HIVE_THRIFT_SERVER_ALLOW_SETTING_SYSTEM_PROPERTIES.key,
+      allowSettingSystemProperties)
+    val sessionImpl = new HiveSessionImpl(
+      TProtocolVersion.HIVE_CLI_SERVICE_PROTOCOL_V1, "", "", conf, "")
+    sessionImpl.setSessionManager(new SessionManager(null))
+    sessionImpl.setOperationManager(new OperationManagerMock())
+    sessionImpl.open(Map.empty[String, String].asJava)
+    // open() does not call SessionState.start(), so err is not initialized in this unit test.
+    SessionState.get().err = new PrintStream(new ByteArrayOutputStream())
+    try f finally sessionImpl.close()
+  }
+
+  test("SPARK-57441: system:* variables can not be set by default") {
+    val key = "spark.test.HiveSessionImplSuite.systemPrefixDefault"
+    try {
+      val rc = withSystemPropSession(allowSettingSystemProperties = false) {
+        HiveSessionImpl.setVariable("system:" + key, "value")
+      }
+      assert(rc == 1)
+      assert(System.getProperty(key) == null)
+    } finally {
+      System.clearProperty(key)
+    }
+  }
+
+  test("SPARK-57441: system:* variables can be set when the legacy conf is enabled") {
+    val key = "spark.test.HiveSessionImplSuite.systemPrefixLegacy"
+    try {
+      val rc = withSystemPropSession(allowSettingSystemProperties = true) {
+        HiveSessionImpl.setVariable("system:" + key, "value")
+      }
+      assert(rc == 0)
+      assert(System.getProperty(key) == "value")
+    } finally {
+      System.clearProperty(key)
+    }
+  }
 }
 
 class OperationManagerMock extends OperationManager {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org