This is an automated email from the ASF dual-hosted git repository.
CalvinKirs 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 342fd131046 [Fix](auth) Restrict processlist visibility by user
identity (#66746)
342fd131046 is described below
commit 342fd131046b2a74a79dab22e7043e4c8ef73669
Author: linrrarity <[email protected]>
AuthorDate: Mon Aug 24 09:49:59 2026 +0800
[Fix](auth) Restrict processlist visibility by user identity (#66746)
Problem Summary:
Authenticated non-admin users could inspect sessions and active SQL
statements belonging to other users through
`information_schema.processlist`, `SHOW PROCESSLIST`
```sql
CREATE USER 'pl_victim' IDENTIFIED BY 'C123_567p';
CREATE USER 'pl_attacker' IDENTIFIED BY 'C123_567p';
GRANT SELECT_PRIV ON processlist_demo.* TO 'pl_victim';
GRANT SELECT_PRIV ON processlist_demo.* TO 'pl_attacker';
-- victim
SELECT SLEEP(120), 'victim_secret_token=demo-only-123';
-- attacker
SELECT User, Command, Info
FROM information_schema.processlist
WHERE User = 'pl_victim';
+-------------+---------+-------------------------------------------------------------------------------------------------------------------------+
| User | Command | Info
|
+-------------+---------+-------------------------------------------------------------------------------------------------------------------------+
| pl_attacker | Query | SELECT User, Command, Info
FROM information_schema.processlist
WHERE User IN ('pl_victim', 'pl_attacker')
ORDER BY User |
| pl_victim | Query | SELECT SLEEP(120),
'victim_secret_token=demo-only-123'
|
+-------------+---------+-------------------------------------------------------------------------------------------------------------------------+
```
The schema scanners did not consistently propagate the caller's user
identity to FE, and the FE metadata handlers did not always enforce
per-user visibility.
### Release note
Non-admin users can now see only their own sessions and active queries
through processlist and information_schema.active_queries. ADMIN users
retain cluster-wide visibility.
---
.../schema_processlist_scanner.cpp | 1 +
.../apache/doris/service/FrontendServiceImpl.java | 10 ++---
.../doris/service/FrontendServiceImplTest.java | 10 +++++
.../suites/show_p0/test_show_processlist.groovy | 48 +++++++++++++++++++++-
4 files changed, 63 insertions(+), 6 deletions(-)
diff --git a/be/src/information_schema/schema_processlist_scanner.cpp
b/be/src/information_schema/schema_processlist_scanner.cpp
index 9fb80e9a651..ace3081238b 100644
--- a/be/src/information_schema/schema_processlist_scanner.cpp
+++ b/be/src/information_schema/schema_processlist_scanner.cpp
@@ -58,6 +58,7 @@ Status SchemaProcessListScanner::start(RuntimeState* state) {
TShowProcessListRequest request;
request.__set_show_full_sql(true);
request.__set_time_zone(state->timezone());
+
request.__set_current_user_ident(*_param->common_param->current_user_ident);
for (const auto& fe_addr : _param->common_param->fe_addr_list) {
TShowProcessListResult tmp_ret;
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java
b/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java
index 486b27b6a43..ea4c8c18a06 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java
@@ -5626,15 +5626,15 @@ public class FrontendServiceImpl implements
FrontendService.Iface {
}
@Override
- public TShowProcessListResult showProcessList(TShowProcessListRequest
request) {
+ public TShowProcessListResult showProcessList(TShowProcessListRequest
request) throws TException {
+ if (!request.isSetCurrentUserIdent()) {
+ throw new TException("Current user identity is not set");
+ }
boolean isShowFullSql = false;
if (request.isSetShowFullSql()) {
isShowFullSql = request.isShowFullSql();
}
- UserIdentity userIdentity = UserIdentity.ROOT;
- if (request.isSetCurrentUserIdent()) {
- userIdentity =
UserIdentity.fromThrift(request.getCurrentUserIdent());
- }
+ UserIdentity userIdentity =
UserIdentity.fromThrift(request.getCurrentUserIdent());
String timeZone =
VariableMgr.getDefaultSessionVariable().getTimeZone();
if (request.isSetTimeZone()) {
timeZone = request.getTimeZone();
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/service/FrontendServiceImplTest.java
b/fe/fe-core/src/test/java/org/apache/doris/service/FrontendServiceImplTest.java
index 03fde60682b..bc5bb4d8aab 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/service/FrontendServiceImplTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/service/FrontendServiceImplTest.java
@@ -64,6 +64,7 @@ import org.apache.doris.thrift.TPrivilegeType;
import org.apache.doris.thrift.TRollbackTxnRequest;
import org.apache.doris.thrift.TSchemaTableName;
import org.apache.doris.thrift.TSchemaTableRequestParams;
+import org.apache.doris.thrift.TShowProcessListRequest;
import org.apache.doris.thrift.TShowUserRequest;
import org.apache.doris.thrift.TShowUserResult;
import org.apache.doris.thrift.TStatusCode;
@@ -76,6 +77,7 @@ import org.apache.doris.utframe.TestWithFeService;
import com.google.common.collect.Sets;
import org.apache.logging.log4j.Level;
+import org.apache.thrift.TException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
@@ -153,6 +155,14 @@ public class FrontendServiceImplTest extends
TestWithFeService {
}
}
+ public void testShowProcessListRejectsMissingUserIdentity() {
+ FrontendServiceImpl impl = new FrontendServiceImpl(exeEnv);
+ TShowProcessListRequest request = new TShowProcessListRequest();
+
+ TException exception = Assertions.assertThrows(TException.class, () ->
impl.showProcessList(request));
+ Assertions.assertEquals("Current user identity is not set",
exception.getMessage());
+ }
+
@Test
public void testGetTableNamesWithSysTablePattern() throws Exception {
FrontendServiceImpl impl = new FrontendServiceImpl(exeEnv);
diff --git a/regression-test/suites/show_p0/test_show_processlist.groovy
b/regression-test/suites/show_p0/test_show_processlist.groovy
index 8c27e2f02a2..237aed9c2a5 100644
--- a/regression-test/suites/show_p0/test_show_processlist.groovy
+++ b/regression-test/suites/show_p0/test_show_processlist.groovy
@@ -18,6 +18,20 @@
import org.apache.doris.regression.util.Http
suite("test_show_processlist") {
+ def victimUser = "test_processlist_victim"
+ def attackerUser = "test_processlist_attacker"
+ def userPassword = "C123_567p"
+ try_sql "DROP USER '${victimUser}'"
+ try_sql "DROP USER '${attackerUser}'"
+ sql "CREATE USER '${victimUser}' IDENTIFIED BY '${userPassword}'"
+ sql "CREATE USER '${attackerUser}' IDENTIFIED BY '${userPassword}'"
+ sql "GRANT SELECT_PRIV ON regression_test.* TO '${victimUser}'"
+ sql "GRANT SELECT_PRIV ON regression_test.* TO '${attackerUser}'"
+ if (isCloudMode()) {
+ sql "GRANT USAGE_PRIV ON COMPUTE GROUP '%' TO '${victimUser}'"
+ sql "GRANT USAGE_PRIV ON COMPUTE GROUP '%' TO '${attackerUser}'"
+ }
+
sql """set fetch_all_fe_for_system_table = false;"""
def result = sql """show processlist;"""
logger.info("result:${result}")
@@ -42,7 +56,39 @@ suite("test_show_processlist") {
logger.info("result:${result}")
assertTrue(result[0].size() == 15)
-
+ connect(victimUser, userPassword, context.config.jdbcUrl) {
+ sql "select 1"
+ connect(attackerUser, userPassword, context.config.jdbcUrl) {
+ def attackerRows = sql """
+ SELECT User, Info
+ FROM information_schema.processlist
+ WHERE User IN ('${victimUser}', '${attackerUser}')
+ ORDER BY User
+ """
+ assertFalse(attackerRows.isEmpty())
+ assertTrue(attackerRows.every { row -> row[0] == attackerUser })
+ assertFalse(attackerRows.any { row -> row[0] == victimUser })
+ assertTrue(attackerRows.any { row ->
+ row[1] != null &&
row[1].toString().contains("information_schema.processlist")
+ })
+
+ def showRows = sql "SHOW FULL PROCESSLIST"
+ assertFalse(showRows.isEmpty())
+ assertTrue(showRows.every { row -> row[2] == attackerUser })
+
+ connect('root', context.config.jdbcPassword,
context.config.jdbcUrl) {
+ def adminRows = sql """
+ SELECT User
+ FROM information_schema.processlist
+ WHERE User IN ('${victimUser}', '${attackerUser}')
+ ORDER BY User
+ """
+ assertTrue(adminRows.any { row -> row[0] == victimUser })
+ assertTrue(adminRows.any { row -> row[0] == attackerUser })
+ }
+ }
+ }
+
def result1 = connect('root', context.config.jdbcPassword,
context.config.jdbcUrl) {
// execute sql with admin user
sql 'select 99 + 1'
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]