Apache Spark 4.2.0 - Élevé - À distance - Écriture de fichier - Session Connect SET copyFromLocalToFs.allowDestLocal
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · spark-connect-copy-local
Classe : Écriture de fichier (résidu de SPARK-58531 ; statique uniquement sur 4.3.0) Portée : Distante
Apache Spark 4.2.0 (32f72996) - Apache Software Foundation
spark.sql.artifact.copyFromLocalToFs.allowDestLocal est toujours buildConf (modifiable par session) sur ce commit. SPARK-58531 l'a déplacé vers StaticSQLConf dans la 4.3.0. Une session Connect peut définir (SET) le garde-fou de destination locale réservé aux tests, puis copyFromLocalToFs / AddArtifacts forward_to_fs/<abs> écrase un chemin local au driver en tant qu'UID Spark.
Une session Connect fait un SET puis forward_to_fs écrit des fichiers locaux au driver. La destination doit être LocalFileSystem. Pas de RCE.
| ID | pas encore de CVE (résidu de SPARK-58531) |
| Classe | Écriture de fichier (résidu de SPARK-58531 ; statique uniquement sur 4.3.0) |
| Portée | Distante (Spark Connect Config + AddArtifacts) |
| CWE | CWE-22, CWE-732 |
| CVSS | Élevé : 8.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H |
| Produit | Apache Spark (ASF) |
| Affecté | Apache Spark 4.2.0 (32f7299601108917fb01920a54e084595b7b3bf8). La 4.3.0 est statique. |
| Auth | Client Connect capable de ConfigRequest.SET et AddArtifacts. Connect par défaut n'a pas de PSK. |
| Licence | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1:18920 uniquement |
Un client Spark Connect qui peut atteindre gRPC (port d'écoute par défaut 15002, pas de PSK sauf si l'opérateur a défini spark.connect.authenticate.token) peut désactiver un garde-fou réservé aux tests avec lequel le driver a été démarré, puis écraser un chemin local choisi sur le driver en tant qu'UID Spark.
| Méthode | Cible | Privilège |
|---|---|---|
gRPC Config SET spark.sql.artifact.copyFromLocalToFs.allowDestLocal=true (ou SQL SET) | SparkConnectConfigHandler.handleSet -> RuntimeConfig.set -> SQLConf.setConfString | Intégrité (conf de session, prouvé en lab) : désactive le garde-fou de destination locale par session. N'écrit pas de fichier à lui seul. Ne modifie pas les autres sessions. Lab : SET HTTP 200, modifiable=True. |
gRPC AddArtifacts nom forward_to_fs + dest absolue, CRC ok | ArtifactManager.uploadArtifactToFs -> LocalFileSystem.copyFromLocalFile(delSrc=false, overwrite=true) | Intégrité (écrasement de fichier, prouvé en lab) : écrit/écrase un chemin local au driver en tant qu'UID Spark, hors de artifactRootDirectory/<sessionUUID>/. Lab : dest /oracle/SPARK-CONNECT-COPY-LOCAL-WITNESS, uid 185, contenu WITNESS. |
| Même AddArtifacts vers une dest HDFS/S3/ABFS | copyFromLocalToFs documenté | Intégrité (FS de cluster, par conception) : pas ce résidu. Une destination qui n'est pas LocalFileSystem ne consulte jamais le flag de test. |
Prouvé en lab vs déduit : le SET de session de la clé buildConf, puis l'écriture vers une dest LocalFileSystem en tant qu'uid 185 hors du bac à sable des artefacts, est prouvé en lab. L'écrasement par l'UID Spark d'un chemin que le processus peut écrire (répertoire de travail du driver, un dépôt accessible en écriture à tous, un script déjà exécutable que l'opérateur lance ensuite) est déduit. Aucun contrôle de RIP. Ne pas gonfler l'écriture de fichier en RCE.
Nécessite : Spark Connect en écoute. Un client capable de SET la conf SQL de session et AddArtifacts. La dest doit être Hadoop LocalFileSystem. Connect par défaut n'a pas de PSK ; si l'opérateur a défini un token, le résidu nécessite toujours ce Bearer partagé. C'est un contournement du contrôle de destination locale, pas un contournement de PSK.
| Surface | Lab |
|---|---|
| Copie sans SET | 400 _LEGACY_ERROR_TEMP_3161, dest absente |
SET de l'ancienne clé statique spark.connect.copyFromLocalToFs.allowDestLocal | 400 CANNOT_MODIFY_STATIC_CONFIG |
Nom d'artefact .. / staging absolu (ArtifactUtils.concatenatePaths) | INVALID_ARTIFACT_PATH |
Artefacts non-forward_to_fs | restent sous artifactRootDirectory/<sessionUUID>/ |
| Dest HDFS/cloud sans le flag | API documentée, pas ce résidu |
SQL non authentifié / Python UDF / Scala UdfPacket sur Connect ouvert | soumission de job selon la FAQ du fournisseur ; DROP |
| SPARK-52122 ML DefaultParamsReader | allowlist + safeMLClassLoader sur ce commit |
Pas de shell. Pas de heap dump. Pas de contournement du PSK Connect. La dest doit toujours être LocalFileSystem. L'écriture se fait en tant qu'UID Spark, pas en tant que root.
uploadArtifactToFs refuse une dest LocalFileSystem sauf si le flag de test est activé, avec un commentaire explicite indiquant qu'autrement un utilisateur écrase un fichier arbitraire sur le driver :
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)
La clé 3.5 est statique, par défaut false. Le remplacement 4.0 est buildConf optionnel :
val ARTIFACT_COPY_FROM_LOCAL_TO_FS_ALLOW_DEST_LOCAL =
buildConf("spark.sql.artifact.copyFromLocalToFs.allowDestLocal")
.internal()
...
.booleanConf
.createOptional
buildConf n'appelle pas registerStaticConfigKey. isModifiable vaut containsConfigKey && !isStaticConfigKey. RuntimeConfig.set ne rejette que les clés statiques. Internal reste modifiable. Après le SET, getConf(ARTIFACT_...) renvoie Some(true) et le repli getOrElse vers l'ancienne conf statique est ignoré.
SPARK-58531 / PR 57730 « Convert spark.sql.artifact.copyFromLocalToFs.allowDestLocal to a static conf » est résolu le 2026-08-05, Fix Version 4.3.0. JIRA : la conf « contrôle si un appelant peut écrire vers un chemin arbitraire sur le système de fichiers local du driver, elle est donc censée être définie par celui qui démarre le driver. » La 4.2.0 est listée comme Affectée. Ce commit a toujours la conf d'exécution.
Fausses pistes déjà consignées : traiter le SQL Connect comme une découverte (FAQ) ; SET de l'ancienne clé statique (CANNOT_MODIFY_STATIC_CONFIG) ; prétendre qu'une dest absolue Unix ignore le parent (elle est jointe sous la racine) ; gonfler l'écriture de fichier en RCE ; épingler la RC 4.3.0 parce que le JIRA est résolu.
cd lab
./run.sh