Skip to content

[SPARK-57480][SQL] Stash allowSettingSystemProperties on a static field to prevent set:hiveconf bypass#56528

Open
yadavay-amzn wants to merge 1 commit into
apache:masterfrom
yadavay-amzn:SPARK-57480-thriftserver-system-prop-bypass
Open

[SPARK-57480][SQL] Stash allowSettingSystemProperties on a static field to prevent set:hiveconf bypass#56528
yadavay-amzn wants to merge 1 commit into
apache:masterfrom
yadavay-amzn:SPARK-57480-thriftserver-system-prop-bypass

Conversation

@yadavay-amzn

@yadavay-amzn yadavay-amzn commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

This PR moves the spark.sql.legacy.hive.thriftServer.allowSettingSystemProperties toggle out of per-session HiveConf and onto a static field on HiveSessionImpl, populated once at server init by SparkSQLSessionManager.

Why are the changes needed?

SPARK-57441 added a default-deny gate on set:system:* in HiveSessionImpl.setVariable, but read its toggle from ss.getConf().getBoolean(...) -- the per-session HiveConf. The same setVariable method writes to that same HiveConf from its HIVECONF_PREFIX branch via setConf -> verifyAndSet, with no validation that rejects spark.* keys (Hive's getConfVars returns null for non-Hive keys, the key.startsWith("hive.") fallback does not fire, and verifyAndSet has no default restrictList entry for this key).

A JDBC URL of the form

jdbc:hive2://host:port/db?set:hiveconf:spark.sql.legacy.hive.thriftServer.allowSettingSystemProperties=true;set:system:foo=bar

flips the flag in the per-session HiveConf via the first directive, then the second directive's gate read sees true and proceeds with System.setProperty, bypassing the default-deny. See SPARK-57480 for the repro and impact analysis.

The fix detaches the gate read from per-session state. The static field is set once at SparkSQLSessionManager.init from the server-wide StaticSQLConf, and is no longer reachable from any per-session set: overlay. The set:hiveconf: write to the flag key still succeeds in writing into the per-session HiveConf (preserved for backward compatibility), but it is now a no-op for the gate.

Does this PR introduce any user-facing change?

No behavior change for users. The default-deny posture from SPARK-57441 is preserved, and the legacy escape-hatch (spark.sql.legacy.hive.thriftServer.allowSettingSystemProperties=true in the server's static SQLConf) still works.

How was this patch tested?

Added HiveSessionImplSuite regression test that exercises the exact bypass:

  1. Open a session with the legacy flag explicitly disabled.
  2. Call setVariable("hiveconf:" + flagKey, "true") -- this is what configureSession does for set:hiveconf: in a JDBC URL.
  3. Call setVariable("system:" + propKey, propValue).
  4. Assert that step 3 returns 1 (rejected) and System.getProperty is null.

I verified the regression test fails when the production fix is reverted (gate read goes back to ss.getConf().getBoolean(...)): test reports 0 did not equal 1 system:* should still be rejected, got rc=0.

All four HiveSessionImplSuite tests pass with the fix in place.

Was this patch authored or co-authored using generative AI tooling?

Generated-by: Claude Opus 4.7

@dongjoon-hyun dongjoon-hyun left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, @yadavay-amzn . Just one tip, you should not ping someone in the PR description because it will become a commit log. Please revise the PR description.

}

// SPARK-57480: resolved at server init time by SparkSQLSessionManager so the per-session
// JDBC `set:` overlay cannot mutate it through `set:hiveconf:`. See setAllowSettingSystemProperties.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, too long?

}
}

// SPARK-57480: resolved at server init time by SparkSQLSessionManager so the per-session

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this, SPARK-57480: .

* Configure whether `set:system:*` is permitted. Intended to be called once at server init
* from SparkSQLSessionManager. Reading and writing this value is intentionally not routed
* through any per-session HiveConf, since that would let a low-privilege client mutate it
* via `set:hiveconf:` from the same JDBC overlay this gate is meant to guard (SPARK-57480).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove (SPARK-57480).

if (ss.getConf().getBoolean(
"spark.sql.legacy.hive.thriftServer.allowSettingSystemProperties", false)) {
// The toggle is read from a static field set once at server init time, NOT from the
// per-session HiveConf, to prevent bypass via `set:hiveconf:` (SPARK-57480).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto. Remove (SPARK-57480)

// 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,
// SPARK-57480: stash the toggle on a static field instead of writing it into HiveConf.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto. Remove SPARK-57480: .

val flagKey = StaticSQLConf.LEGACY_HIVE_THRIFT_SERVER_ALLOW_SETTING_SYSTEM_PROPERTIES.key
try {
withSystemPropSession(allowSettingSystemProperties = false) {
// Before SPARK-57480, the system: gate read its toggle from the per-session HiveConf,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove Before SPARK-57480, because this is meaningless because we add a test coverage to prevent a regression and the test prefix is supposed to mention that as you did already in line 111. This is a simple duplication without giving any new information.

…ld to prevent set:hiveconf bypass

### What changes were proposed in this pull request?

This PR moves the `spark.sql.legacy.hive.thriftServer.allowSettingSystemProperties` toggle
out of per-session `HiveConf` and onto a static field on `HiveSessionImpl`, populated once
at server init by `SparkSQLSessionManager`.

### Why are the changes needed?

SPARK-57441 added a default-deny gate on `set:system:*` in `HiveSessionImpl.setVariable`,
but read its toggle from `ss.getConf().getBoolean(...)` -- the per-session `HiveConf`. The
same `setVariable` method writes to that same `HiveConf` from its `HIVECONF_PREFIX` branch
via `setConf` -> `verifyAndSet`, with no validation that rejects `spark.*` keys (Hive's
`getConfVars` returns null for non-Hive keys, the `key.startsWith("hive.")` fallback does
not fire, and `verifyAndSet` has no default `restrictList` entry for this key).

A JDBC URL of the form

```
jdbc:hive2://host:port/db?set:hiveconf:spark.sql.legacy.hive.thriftServer.allowSettingSystemProperties=true;set:system:foo=bar
```

flips the flag in the per-session `HiveConf` via the first directive, then the second
directive's gate read sees `true` and proceeds with `System.setProperty`, bypassing the
default-deny. See SPARK-57480 for the repro and impact analysis.

The fix detaches the gate read from per-session state. The static field is set once at
`SparkSQLSessionManager.init` from the server-wide `StaticSQLConf`, and is no longer
reachable from any per-session `set:` overlay. The `set:hiveconf:<flag-key>=true` write
still succeeds in writing into the per-session `HiveConf` (preserved for backward
compatibility), but it is now a no-op for the gate.

### Does this PR introduce _any_ user-facing change?

No behavior change for users. The default-deny posture from SPARK-57441 is preserved, and
the legacy escape-hatch (`spark.sql.legacy.hive.thriftServer.allowSettingSystemProperties=true`
in the server's static SQLConf) still works.

### How was this patch tested?

Added `HiveSessionImplSuite` regression test that exercises the exact bypass:

1. Open a session with the legacy flag explicitly disabled.
2. Call `setVariable("hiveconf:<flag-key>", "true")` -- this is what `configureSession` does
   for `set:hiveconf:` in a JDBC URL.
3. Call `setVariable("system:<prop>", "<val>")`.
4. Assert that step 3 returns `1` (rejected) and `System.getProperty` is null.

I verified the regression test fails when the production fix is reverted (gate read goes
back to `ss.getConf().getBoolean(...)`): test reports
`0 did not equal 1 system:* should still be rejected, got rc=0`.

All four `HiveSessionImplSuite` tests pass with the fix in place.

### Was this patch authored or co-authored using generative AI tooling?

Generated-by: Claude Opus 4.7
@yadavay-amzn yadavay-amzn force-pushed the SPARK-57480-thriftserver-system-prop-bypass branch from 944468e to 704b6e3 Compare June 16, 2026 01:06
@yadavay-amzn

Copy link
Copy Markdown
Contributor Author

Thanks for the review @dongjoon-hyun. Addressed all comments in 704b6e3:

  • Removed SPARK-57480: prefix and (SPARK-57480) parentheticals from source comments (HiveSessionImpl.java, SparkSQLSessionManager.scala, HiveSessionImplSuite.scala) -- kept only the SPARK-57480: prefix on the regression test name per your note.
  • Tightened the field-level comment on allowSettingSystemProperties to one line.
  • Reworded the bypass-test comment to drop the Before SPARK-57480, lead-in.
  • Removed the cc @... line from the PR description.

HiveSessionImplSuite (4/4) passes locally. PTAL.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants