Apache Spark 4.2.0 - Alta - Remoto - Gravação de arquivo - Sessão Connect SET copyFromLocalToFs.allowDestLocal
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · spark-connect-copy-local
Classe: Escrita de arquivo (resquício do SPARK-58531; estático apenas no 4.3.0) Alcance: Remoto
Apache Spark 4.2.0 (32f72996) - Apache Software Foundation
spark.sql.artifact.copyFromLocalToFs.allowDestLocal ainda é buildConf (configurável por sessão) neste pin. O SPARK-58531 o moveu para StaticSQLConf no 4.3.0. Uma sessão Connect pode definir o gate de destino local apenas para testes, e então copyFromLocalToFs / AddArtifacts forward_to_fs/<abs> sobrescreve um caminho local do driver com o UID do Spark.
Sessão Connect define, então forward_to_fs grava arquivos locais do driver. O destino deve ser LocalFileSystem. Não é RCE.
| ID | sem CVE ainda (resquício do SPARK-58531) |
| Classe | Escrita de arquivo (resquício do SPARK-58531; estático apenas no 4.3.0) |
| Alcance | Remoto (Spark Connect Config + AddArtifacts) |
| CWE | CWE-22, CWE-732 |
| CVSS | Alto: 8.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H |
| Produto | Apache Spark (ASF) |
| Afetado | Apache Spark 4.2.0 (32f7299601108917fb01920a54e084595b7b3bf8). O 4.3.0 é estático. |
| Autenticação | Cliente Connect que consiga ConfigRequest.SET e AddArtifacts. O Connect padrão não tem PSK. |
| Licença | GNU Affero GPL v3.0 |
| Lab | apenas 127.0.0.1:18920 |
Um cliente Spark Connect que consiga alcançar o gRPC (porta de bind padrão 15002, sem PSK a menos que o operador tenha definido spark.connect.authenticate.token) pode desativar um gate apenas para testes com o qual o driver foi iniciado e, em seguida, sobrescrever um caminho local escolhido no driver com o UID do Spark.
| Método | Sink | Privilégio |
|---|---|---|
gRPC Config SET spark.sql.artifact.copyFromLocalToFs.allowDestLocal=true (ou SQL SET) | SparkConnectConfigHandler.handleSet -> RuntimeConfig.set -> SQLConf.setConfString | Integridade (conf de sessão, comprovado em lab): desativa o gate de destino local por sessão. Não grava um arquivo por si só. Não altera outras sessões. Lab: SET HTTP 200, modifiable=True. |
gRPC AddArtifacts nome forward_to_fs + destino absoluto, CRC ok | ArtifactManager.uploadArtifactToFs -> LocalFileSystem.copyFromLocalFile(delSrc=false, overwrite=true) | Integridade (sobrescrita de arquivo, comprovado em lab): grava/sobrescreve um caminho local do driver com o UID do Spark, fora de artifactRootDirectory/<sessionUUID>/. Lab: destino /oracle/SPARK-CONNECT-COPY-LOCAL-WITNESS, uid 185, conteúdo WITNESS. |
| Mesmo AddArtifacts para destino HDFS/S3/ABFS | copyFromLocalToFs documentado | Integridade (FS de cluster, por design): não é este resquício. Destino que não seja LocalFileSystem nunca consulta a flag de teste. |
Comprovado em lab vs inferido: o SET de sessão da chave buildConf, seguido de escrita em destino LocalFileSystem como uid 185 fora do sandbox de artefatos, é lab. A sobrescrita com UID do Spark de um caminho que o processo pode gravar (diretório de trabalho do driver, um drop gravável por todos, um script já executável que o operador executa depois) é inferido. Sem controle de RIP. Não infle Escrita de arquivo para RCE.
Requer: Spark Connect escutando. Cliente que consiga SET na conf SQL da sessão e AddArtifacts. O destino deve ser LocalFileSystem do Hadoop. O Connect padrão não tem PSK; se o operador definiu um token, o resquício ainda precisa desse Bearer compartilhado. É um bypass do controle de destino local, não um bypass de PSK.
| Superfície | Lab |
|---|---|
| Cópia sem SET | 400 _LEGACY_ERROR_TEMP_3161, destino ausente |
SET da antiga chave estática spark.connect.copyFromLocalToFs.allowDestLocal | 400 CANNOT_MODIFY_STATIC_CONFIG |
Nome de artefato .. / staging absoluto (ArtifactUtils.concatenatePaths) | INVALID_ARTIFACT_PATH |
Artefatos que não são forward_to_fs | permanecem sob artifactRootDirectory/<sessionUUID>/ |
| Destino HDFS/cloud sem a flag | API documentada, não este resquício |
SQL não autenticado / Python UDF / Scala UdfPacket em Connect aberto | submissão de job do FAQ do fornecedor; DROP |
| SPARK-52122 ML DefaultParamsReader | allowlist + safeMLClassLoader neste pin |
Sem shell. Sem heap dump. Sem pular PSK do Connect. O destino ainda precisa ser LocalFileSystem. A escrita é com o UID do Spark, não como root.
uploadArtifactToFs recusa um destino LocalFileSystem a menos que a flag de teste esteja ativada, com um comentário explícito de que, caso contrário, um usuário sobrescreve um arquivo arbitrário no 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)
A chave do 3.5 é estática, padrão false. A substituta do 4.0 é buildConf opcional:
val ARTIFACT_COPY_FROM_LOCAL_TO_FS_ALLOW_DEST_LOCAL =
buildConf("spark.sql.artifact.copyFromLocalToFs.allowDestLocal")
.internal()
...
.booleanConf
.createOptional
buildConf não chama registerStaticConfigKey. isModifiable é containsConfigKey && !isStaticConfigKey. RuntimeConfig.set só rejeita chaves estáticas. Internal ainda é configurável. Após o SET, getConf(ARTIFACT_...) retorna Some(true) e o fallback getOrElse para a antiga conf estática é ignorado.
SPARK-58531 / PR 57730 "Convert spark.sql.artifact.copyFromLocalToFs.allowDestLocal to a static conf" está resolvido em 2026-08-05, Fix Version 4.3.0. JIRA: a conf "controls whether a caller can write to an arbitrary path on the driver's local filesystem, so it is meant to be set by whoever starts the driver." O 4.2.0 está listado em Affects. Este pin ainda tem a conf de runtime.
Caminhos errados já registrados: tratar Connect SQL como um achado (FAQ); SET da antiga chave estática (CANNOT_MODIFY_STATIC_CONFIG); afirmar que um destino absoluto Unix ignora o pai (ele é unido sob a raiz); inflar Escrita de arquivo para RCE; fixar o 4.3.0 RC porque o JIRA está resolvido.
cd lab
./run.sh