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