
Apache Spark 4.2.0 - 高 - リモート - ファイル書き込み - Connect セッション SET copyFromLocalToFs.allowDestLocal
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · spark-connect-copy-local
クラス: ファイル書き込み (SPARK-58531 の残存; 4.3.0 のみで static) 到達性: リモート
Apache Spark 4.2.0 (32f72996) - Apache Software Foundation
spark.sql.artifact.copyFromLocalToFs.allowDestLocal はこのピンでは依然として buildConf (セッションで設定可能) である。SPARK-58531 は 4.3.0 でこれを StaticSQLConf に移動した。Connect セッションはテスト専用の local-dest ゲートを SET でき、その後 copyFromLocalToFs / AddArtifacts の forward_to_fs/<abs> が Spark UID としてドライバーローカルのパスを上書きする。
Connect セッションで SET してから forward_to_fs がドライバーローカルのファイルを書き込む。宛先は LocalFileSystem でなければならない。RCE ではない。
| ID | CVE 未割当 (SPARK-58531 の残存) |
| クラス | ファイル書き込み (SPARK-58531 の残存; 4.3.0 のみで static) |
| 到達性 | リモート (Spark Connect Config + AddArtifacts) |
| CWE | CWE-22, CWE-732 |
| CVSS | High: 8.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H |
| 製品 | Apache Spark (ASF) |
| 影響を受けるバージョン | Apache Spark 4.2.0 (32f7299601108917fb01920a54e084595b7b3bf8)。4.3.0 は static。 |
| 認証 | ConfigRequest.SET と AddArtifacts を実行できる Connect クライアント。デフォルトの Connect には PSK がない。 |
| ライセンス | GNU Affero GPL v3.0 |
| ラボ | 127.0.0.1:18920 のみ |
gRPC に到達できる Spark Connect クライアント (デフォルトのバインドポート 15002、オペレーターが spark.connect.authenticate.token を設定していない限り PSK なし) は、ドライバー起動時に設定されたテスト専用ゲートをオフに切り替え、その後 Spark UID としてドライバー上の任意のローカルパスを上書きできる。
| 手法 | シンク | 権限 |
|---|---|---|
gRPC Config SET spark.sql.artifact.copyFromLocalToFs.allowDestLocal=true (または SQL SET) | SparkConnectConfigHandler.handleSet -> RuntimeConfig.set -> SQLConf.setConfString | 整合性 (セッション設定、ラボ実証済み): セッション単位の local-dest ゲートを切り替える。それ自体ではファイルを書き込まない。他のセッションには影響しない。ラボ: SET HTTP 200、modifiable=True。 |
gRPC AddArtifacts の名前 forward_to_fs + 絶対宛先、CRC 正常 | ArtifactManager.uploadArtifactToFs -> LocalFileSystem.copyFromLocalFile(delSrc=false, overwrite=true) | 整合性 (ファイル上書き、ラボ実証済み): artifactRootDirectory/<sessionUUID>/ の外にあるドライバーローカルのパスを Spark UID として書き込み/上書きする。ラボ: 宛先 /oracle/SPARK-CONNECT-COPY-LOCAL-WITNESS、uid 185、内容 WITNESS。 |
| 同じ AddArtifacts を HDFS/S3/ABFS の宛先に対して実行 | ドキュメント化された copyFromLocalToFs | 整合性 (クラスタ FS、設計通り): この残存ではない。LocalFileSystem でない宛先はテストフラグを参照しない。 |
ラボ実証済み vs 推測: buildConf キーのセッション SET、その後 uid 185 としてアーティファクトサンドボックス外の LocalFileSystem 宛先への書き込みはラボ実証済み。プロセスが書き込めるパス (ドライバーの作業ディレクトリ、誰でも書き込み可能なドロップ先、オペレーターが後で実行する既存の実行可能スクリプト) の Spark UID による上書きは推測。RIP 制御はない。ファイル書き込みを RCE に誇張しないこと。
必要条件: Spark Connect がリッスンしていること。セッション SQL conf を SET し、AddArtifacts を実行できるクライアント。宛先は Hadoop LocalFileSystem でなければならない。デフォルトの Connect には PSK がない。オペレーターがトークンを設定している場合、この残存には依然としてその共有 Bearer が必要。これは local-dest 制御のバイパスであり、PSK バイパスではない。
| 攻撃面 | ラボ |
|---|---|
| SET なしのコピー | 400 _LEGACY_ERROR_TEMP_3161、宛先なし |
古い static な spark.connect.copyFromLocalToFs.allowDestLocal の SET | 400 CANNOT_MODIFY_STATIC_CONFIG |
アーティファクト名 .. / 絶対ステージング (ArtifactUtils.concatenatePaths) | INVALID_ARTIFACT_PATH |
forward_to_fs 以外のアーティファクト | artifactRootDirectory/<sessionUUID>/ 配下に留まる |
| フラグなしの HDFS/クラウド宛先 | ドキュメント化された API、この残存ではない |
オープンな Connect に対する未認証 SQL / Python UDF / Scala UdfPacket | ベンダー FAQ のジョブ投入; DROP |
| SPARK-52122 ML DefaultParamsReader | このピンでは allowlist + safeMLClassLoader |
シェルなし。ヒープダンプなし。Connect PSK スキップなし。宛先は依然として LocalFileSystem でなければならない。書き込みは root としてではなく Spark UID として行われる。
uploadArtifactToFs はテストフラグがオンでない限り LocalFileSystem 宛先を拒否し、そうでなければユーザーがドライバー上の任意のファイルを上書きすることになるという明示的なコメントを添えている:
if (fs.isInstanceOf[LocalFileSystem]) {
val allowDestLocalConf =
session.sessionState.conf.getConf(SQLConf.ARTIFACT_COPY_FROM_LOCAL_TO_FS_ALLOW_DEST_LOCAL)
.getOrElse(
session.conf.get("spark.connect.copyFromLocalToFs.allowDestLocal").contains("true"))
if (!allowDestLocalConf) {
throw new SparkUnsupportedOperationException("_LEGACY_ERROR_TEMP_3161")
}
}
fs.copyFromLocalFile(false, true, new FSPath(localPath.toString), destFSPath)
3.5 のキーは static で、デフォルトは false。4.0 の置き換えは buildConf の optional:
val ARTIFACT_COPY_FROM_LOCAL_TO_FS_ALLOW_DEST_LOCAL =
buildConf("spark.sql.artifact.copyFromLocalToFs.allowDestLocal")
.internal()
...
.booleanConf
.createOptional
buildConf は registerStaticConfigKey を呼び出さない。isModifiable は containsConfigKey && !isStaticConfigKey。RuntimeConfig.set は static キーのみを拒否する。internal は依然として設定可能。SET 後、getConf(ARTIFACT_...) は Some(true) を返し、static な古い conf への getOrElse フォールバックはスキップされる。
SPARK-58531 / PR 57730「Convert spark.sql.artifact.copyFromLocalToFs.allowDestLocal to a static conf」は 2026-08-05 に解決済み、Fix Version 4.3.0。JIRA: この conf は「呼び出し元がドライバーのローカルファイルシステム上の任意のパスに書き込めるかどうかを制御するため、ドライバーを起動する者が設定することを意図している」。4.2.0 が Affects に記載されている。このピンには依然としてランタイム conf がある。
すでに記録済みの誤った道: Connect SQL を所見として扱うこと (FAQ); 古い static キーの SET (CANNOT_MODIFY_STATIC_CONFIG); Unix の絶対宛先が親を無視すると主張すること (root 配下に結合される); ファイル書き込みを RCE に誇張すること; JIRA が解決済みだからという理由で 4.3.0 RC をピン留めすること。
cd lab
./run.sh
ループバック 127.0.0.1:18920。セッション conf ゲートと LocalFileSystem 宛先コピーのガジェット (ピン v4.2.0 32f72996)。サーバー UID 185。SET なしの対照: 400 _LEGACY_ERROR_TEMP_3161、宛先なし。古い static キーの SET の対照: CANNOT_MODIFY_STATIC_CONFIG。buildConf キーのセッション SET 後のコピー: 宛先 /oracle/SPARK-CONNECT-COPY-LOCAL-WITNESS は /opt/spark/work/artifacts/<sessionUUID>/ の外、uid 185、内容 WITNESS。
health pin=v4.2.0 commit=32f7299601108917fb01920a54e084595b7b3bf8
server uid=185 artifact_root=/opt/spark/work/artifacts/<sessionUUID>
control-no-set status=400 condition=_LEGACY_ERROR_TEMP_3161
control-no-set dest-absent=yes
control-static-set status=400 error_class=CANNOT_MODIFY_STATIC_CONFIG
session-set status=200 modifiable=True
copy-after-set status=200 dest=/oracle/SPARK-CONNECT-COPY-LOCAL-WITNESS
oracle dest=/oracle/SPARK-CONNECT-COPY-LOCAL-WITNESS uid=185 outside-sandbox=yes content=SPARK-CONNECT-COPY-LOCAL-WITNESS
SUCCESS SPARK-CONNECT-COPY-LOCAL SPARK-CONNECT-COPY-LOCAL-WITNESS
spark.sql.artifact.copyFromLocalToFs.allowDestLocal を StaticSQLConf に移動し、セッションが SET できないようにする。これが 4.3.0 の SPARK-58531 / PR 57730 である。オペレーターが 4.3.0 を実行できるようになるまでは: トークンとネットワーク ACL なしで Connect を公開しないこと、そしてドライバーが未設定で起動されたという理由だけでテストフラグがオフであるとみなさないこと。