From 17a0f3cf5002cc853c171d6e4d18d7d425e3cff0 Mon Sep 17 00:00:00 2001 From: cgivre Date: Fri, 9 Oct 2026 11:24:20 -0400 Subject: [PATCH] [MINOR-UPDATE] Document staging-area precondition for CREATE FUNCTION / CREATE DAFFODIL SCHEMA USING JAR in threat model Both statements only register a jar already present in a staging area on the cluster filesystem, so exploiting them requires filesystem write access the model already treats as out of scope. Add a known non-finding, operator guidance to restrict the staging directories, and update the Q4 status. --- THREAT_MODEL.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/THREAT_MODEL.md b/THREAT_MODEL.md index d91288eb7b0..260dda1d32a 100644 --- a/THREAT_MODEL.md +++ b/THREAT_MODEL.md @@ -24,7 +24,7 @@ - **Version binding:** versioned with the project; a report against version *N* is triaged against the model as it stood at *N*. - **Reporting cross-reference:** §8-property violations → report privately per the ASF process (`security@apache.org` → `private@drill.apache.org`); §3/§9 findings are closed citing this document. - **Provenance legend:** *(documented)* = Drill's own docs/repo; *(maintainer)* = confirmed by a Drill PMC member through this process; *(inferred)* = reasoned from architecture/docs, not yet PMC-ratified — each has a matching §14 open question. -- **Draft confidence:** ~10 documented / 2 maintainer / ~26 inferred (cgivre's PR #3052 review folded: `contrib/` plugins in scope + the storage-enumeration non-finding). +- **Draft confidence:** ~10 documented / 3 maintainer / ~25 inferred (cgivre's PR #3052 review folded: `contrib/` plugins in scope + the storage-enumeration non-finding; 2026-10: `CREATE FUNCTION USING JAR` / `CREATE DAFFODIL SCHEMA USING JAR` staging-area precondition). **What Drill is.** Apache Drill is a **schema-free, distributed SQL query engine** for large-scale datasets. A cluster of **Drillbit** daemons (coordinated via Apache ZooKeeper) accepts ANSI-SQL queries over JDBC, ODBC, a REST API, and a Web UI (default port **8047**), and executes them directly against data in configurable **storage plugins** (local/HDFS/S3 files, Hive, HBase, Kafka, MongoDB, RDBMS via JDBC, HTTP, …) — discovering schema at query time rather than requiring a pre-defined schema. *(documented — drill.apache.org)* @@ -56,7 +56,7 @@ Intended deployment: a **clustered set of Drillbits** inside an operator-control ## §3 Out of scope (explicit non-goals) - **The security of the underlying data sources.** HDFS/S3 permissions, the RDBMS behind the JDBC plugin, Hive authorization, the Kafka cluster — each enforces its own access control. Drill assumes them; it is not responsible for their misconfiguration. *(inferred — §14 Q2)* -- **Dynamic UDFs and storage-plugin configuration as code/connectivity execution.** Uploading a UDF jar or configuring a storage plugin is an **authorized admin operation**; the code/connection runs with the Drillbit's privileges. This is a feature, not a sandbox escape — `BY-DESIGN`. A finding that requires admin rights to register a UDF or add a plugin is out of model. *(documented — admin function; §14 Q4 confirms the trust line)* +- **Dynamic UDFs and storage-plugin configuration as code/connectivity execution.** Uploading a UDF jar or configuring a storage plugin is an **authorized admin operation**; the code/connection runs with the Drillbit's privileges. This is a feature, not a sandbox escape — `BY-DESIGN`. A finding that requires admin rights to register a UDF or add a plugin is out of model. *(documented — admin function; §14 Q4 confirms the trust line)* For dynamic UDFs specifically, `CREATE FUNCTION USING JAR` only *registers* a jar that is already present in the UDF staging area (`drill.exec.udf.directory.staging`); the SQL statement cannot upload content. Placing a jar there requires write access to the Drill cluster's filesystem, which is the real trust gate (§11a). The same holds for DFDL schemas: `CREATE DAFFODIL SCHEMA USING JAR` only registers a jar already in `drill.exec.daffodil.directory.staging`, and the Daffodil format's `schemaURI`/`schemaFile` come from admin-only format config. *(maintainer — cgivre, 2026-10)* - **An operator with cluster/root access, the Drillbit service account, or direct ZooKeeper write access.** Anyone who controls the cluster processes or the coordination store has already won. `OUT-OF-MODEL: adversary-not-in-scope`. *(inferred — §14 Q5)* - **Embedded / single-user mode**, where the caller owns the JVM, the filesystem, and all input — equivalent to an in-process library call. *(inferred — §14 Q1)* - **SQL injection in an embedding application** that string-concatenates untrusted input into Drill SQL — that is the embedding app's bug, not Drill's. *(inferred — §11)* @@ -133,6 +133,7 @@ The security envelope is set primarily by runtime configuration, not compile fla - **Enable authentication and impersonation** before exposing Drill to more than one trusted user; do not run a multi-user cluster with the shipped auth-off / impersonation-off defaults. *(inferred — §14 Q9)* - **Lock down the Web UI / REST (`:8047`)** — it can configure storage plugins and upload UDFs; restrict it to admins and protect it with auth + TLS. - **Restrict who can configure storage plugins and upload dynamic UDFs** to trusted admins (these are code/connectivity-execution surfaces). +- **Restrict write access to the UDF staging area** (`drill.exec.udf.directory.staging`, on `drill.exec.udf.directory.fs`). Write access there is equivalent to code execution on every Drillbit once any user runs `CREATE FUNCTION USING JAR`. Set `exec.udf.enable_dynamic_support = false` if dynamic UDFs are not needed. Apply the same restriction to the Daffodil schema staging area (`drill.exec.daffodil.directory.staging`, on `drill.exec.daffodil.directory.fs`). - **Configure wire encryption** (SASL/SSL) on client↔Drillbit and inter-Drillbit links on untrusted networks. - **Network-isolate** the Drillbit cluster + ZooKeeper from untrusted networks; give data-source credentials least privilege. @@ -152,6 +153,7 @@ The security envelope is set primarily by runtime configuration, not compile fla - **"The REST API / Web UI accepts requests without authentication."** Only when auth is disabled — a non-default/operator-chosen posture (pending §14 Q9), not a Drill defect. `OUT-OF-MODEL: non-default-build`. - **"A query can read an arbitrary local file via the `dfs` plugin."** In-model only if it crosses the impersonated identity's authorization or the configured workspace; otherwise it is the operator's plugin-scope choice. *(inferred — §14 Q2/Q7)* - **"Drill can enumerate / read the files, schemas, or storage systems it is pointed at."** That is the **function** of a federated query engine — exposing configured storage to SQL is the point of Drill, not a vulnerability. `KNOWN-NON-FINDING` / `BY-DESIGN`. In-model **only** if the access crosses the authenticated identity's authorization (reading data an impersonated user shouldn't, or bypassing a Drill view — §8.2). *(maintainer — cgivre, PR #3052: "yes… that's the point of Drill".)* +- **"`CREATE FUNCTION USING JAR` / `CREATE DAFFODIL SCHEMA USING JAR` lets a user load a malicious jar or DFDL schema."** Recurring report. Neither statement uploads anything: each only registers a jar that already sits in its staging area on the cluster filesystem (UDF: `drill.exec.udf.directory.staging`, binary + sources; Daffodil: `drill.exec.daffodil.directory.staging`). `CreateFunctionHandler` and `CreateDaffodilSchemaHandler` fail if the file is missing. To exploit it, the attacker must already have write access to that filesystem location, i.e. filesystem/cluster access the model already treats as having won (§3, §7). `OUT-OF-MODEL: adversary-not-in-scope`. In-model **only** if a low-privilege client can get attacker-controlled bytes into the staging area through Drill itself (e.g. a `CTAS`/export or REST path that writes into either staging directory), which would be a `VALID` §8.3 break. Pointing the Daffodil format at an arbitrary `schemaURI` is format config, i.e. admin-tier (`OUT-OF-MODEL: trusted-input`). *(maintainer — cgivre, 2026-10)* - **"SQL injection in Drill"** where the untrusted string was concatenated by an *embedding app* — that app's bug (§11), not Drill's. - **Dependency-tail CVEs** (Calcite, Hadoop, Jackson, Netty, a transitive jar) from an SCA scan — triage upstream unless Drill's own code reaches the vulnerable path with untrusted input. @@ -182,7 +184,7 @@ The security envelope is set primarily by runtime configuration, not compile fla - **Q1.** Confirm the in-scope surface is "an authenticated SQL/REST client at the Drillbit front door (JDBC/ODBC/REST/Web UI), in a clustered multi-user deployment", with embedded single-user mode out of scope. Anything to add? - **Q2.** Confirm Drill is *not* responsible for the underlying data sources' own access control — that HDFS/S3/RDBMS/Hive/Kafka security is theirs, and Drill's job is to honor it (via impersonation/views), not replace it. -- **Q4.** Confirm dynamic-UDF upload and storage-plugin configuration are **admin-only, code/connectivity-execution-by-design** — i.e. a finding that requires those rights is out of model. +- **Q4.** *(Partially answered — cgivre, 2026-10: `CREATE FUNCTION USING JAR` and `CREATE DAFFODIL SCHEMA USING JAR` require the jar to be pre-placed in a staging area, so filesystem write access is the gate; folded into §3/§10/§11a.)* Confirm dynamic-UDF upload and storage-plugin configuration are **admin-only, code/connectivity-execution-by-design** — i.e. a finding that requires those rights is out of model. - **Q5.** Confirm operators with cluster-host / Drillbit-service-account / ZooKeeper-write access (and the data sources themselves) are out of model. **Wave 2 — auth, impersonation, defaults**