This is an automated email from the ASF dual-hosted git repository.
mymeiyi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new c5324805b53 [fix](audit) Fix SET_VAR leakage after INSERT audit
logging (#67786)
c5324805b53 is described below
commit c5324805b53f412434bcb609e0e61a6a73ca73e9
Author: meiyi <[email protected]>
AuthorDate: Wed Sep 16 15:34:21 2026 +0800
[fix](audit) Fix SET_VAR leakage after INSERT audit logging (#67786)
Problem Summary: After an INSERT containing a table-valued function
finishes, audit logging reparses its SQL for redaction. This runs after
StmtExecutor has restored session variables, but the redaction parser
applies SET_VAR again. For example, an INSERT using numbers() with
query_timeout=1 and insert_timeout=1 leaves both session values at 1,
causing the next unhinted INSERT to time out.
Pass an empty hint map to the redaction plan builder so it does not
apply execution hints. The redacted SQL still preserves the original
hint text and masks sensitive properties. This also applies to other
callers of the shared redaction parser, including FE logging and
streaming-job SQL display.
---
.../apache/doris/nereids/parser/NereidsParser.java | 5 +-
.../parser/AuditEncryptionSessionVariableTest.java | 63 ++++++++++++++++++++++
.../test_set_var_hint_restore.groovy | 44 +++++++++++++++
3 files changed, 111 insertions(+), 1 deletion(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/NereidsParser.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/NereidsParser.java
index 4184c0f421c..539a05ef867 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/NereidsParser.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/NereidsParser.java
@@ -362,11 +362,14 @@ public class NereidsParser {
return (LogicalPlan) realLogicalPlanBuilder.visit(tree);
}
+ /** Parse SQL for masking without applying execution hints to the session.
*/
public LogicalPlan parseForEncryption(String sql, Map<Pair<Integer,
Integer>, String> indexInSqlToString) {
CommonTokenStream tokenStream = parseLeanTokens(sql);
ParserRuleContext tree = toAst(tokenStream,
DorisParser::singleStatement);
+ // SQL masking must not apply SET_VAR hints to the current session.
+ // The original SQL, including its hints, is preserved by the property
replacements.
LogicalPlanBuilder realLogicalPlanBuilder = new
LogicalPlanBuilderForEncryption(
- getHintMap(sql, tokenStream, DorisParser::selectHint),
indexInSqlToString);
+ ImmutableMap.of(), indexInSqlToString);
return (LogicalPlan) realLogicalPlanBuilder.visit(tree);
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/AuditEncryptionSessionVariableTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/AuditEncryptionSessionVariableTest.java
new file mode 100644
index 00000000000..58004fa4534
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/AuditEncryptionSessionVariableTest.java
@@ -0,0 +1,63 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.parser;
+
+import org.apache.doris.common.Pair;
+import org.apache.doris.nereids.StatementContext;
+import org.apache.doris.nereids.trees.plans.commands.info.BaseViewInfo;
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.qe.SessionVariable;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.TreeMap;
+
+public class AuditEncryptionSessionVariableTest {
+ @Test
+ public void testAuditParsingDoesNotApplySetVar() {
+ ConnectContext ctx = new ConnectContext();
+ ctx.setDatabase("test");
+ ctx.setStatementContext(new StatementContext(ctx, null));
+ ctx.setThreadLocalInfo();
+ try {
+ SessionVariable session = ctx.getSessionVariable();
+ session.setQueryTimeoutS(1800);
+ session.setInsertTimeoutS(14400);
+ String hint = "/*+ SET_VAR(query_timeout=1, insert_timeout=1) */";
+ String[] sources = {
+ "numbers(\"number\"=\"1\")",
+ "S3('uri'='s3://bucket/data.parquet', 'format'='parquet',
's3.secret_key'='test-secret')"
+ };
+ for (String source : sources) {
+ String sql = "INSERT INTO t SELECT " + hint + " * FROM " +
source;
+ TreeMap<Pair<Integer, Integer>, String> replacements = new
TreeMap<>(new Pair.PairComparator<>());
+ new NereidsParser().parseForEncryption(sql, replacements);
+ Assertions.assertEquals(1800, session.getQueryTimeoutS());
+ Assertions.assertEquals(14400, session.getInsertTimeoutS());
+ Assertions.assertFalse(session.getIsSingleSetVar());
+
Assertions.assertTrue(session.getSessionOriginValue().isEmpty());
+ String masked = BaseViewInfo.rewriteSql(replacements, sql);
+ Assertions.assertTrue(masked.contains(hint));
+ Assertions.assertFalse(masked.contains("test-secret"));
+ }
+ } finally {
+ ConnectContext.remove();
+ }
+ }
+}
diff --git
a/regression-test/suites/query_p0/session_variable/test_set_var_hint_restore.groovy
b/regression-test/suites/query_p0/session_variable/test_set_var_hint_restore.groovy
new file mode 100644
index 00000000000..52fd39e99c4
--- /dev/null
+++
b/regression-test/suites/query_p0/session_variable/test_set_var_hint_restore.groovy
@@ -0,0 +1,44 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+suite("test_set_var_hint_restore") {
+ sql "DROP TABLE IF EXISTS test_set_var_hint_restore"
+ sql """
+ CREATE TABLE test_set_var_hint_restore (
+ k INT NOT NULL,
+ v BIGINT NOT NULL
+ ) ENGINE=OLAP
+ DUPLICATE KEY(k)
+ DISTRIBUTED BY HASH(k) BUCKETS 6
+ PROPERTIES ("replication_num"="1")
+ """
+
+ def timeoutsBeforeInsert = sql "SELECT @@query_timeout, @@insert_timeout"
+ test {
+ sql """
+ INSERT INTO test_set_var_hint_restore
+ SELECT /*+ SET_VAR(query_timeout=1, insert_timeout=1) */
+ 41, SUM(CRC32(CAST(number AS STRING)))
+ FROM numbers("number"="1000000000")
+ """
+ exception "timeout"
+ }
+
+ // Read immediately: another statement could restore values leaked by
audit SQL parsing.
+ def timeoutsAfterInsert = sql "SELECT @@query_timeout, @@insert_timeout"
+ assertEquals(timeoutsBeforeInsert, timeoutsAfterInsert)
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]