From e090ec0f609f3c7d70abe16122252441e4d9a520 Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Sat, 4 Jun 2022 22:48:56 -0300 Subject: [PATCH] Add system privilege PROFILE_ANY_ATTACHMENT and permission check. Add some static_asserts. --- doc/sql.extensions/README.ddl.txt | 1 + doc/sql.extensions/README.profiler.md | 2 ++ src/jrd/ProfilerManager.cpp | 17 ++++++++++++++++- src/jrd/SystemPrivileges.h | 1 + 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/doc/sql.extensions/README.ddl.txt b/doc/sql.extensions/README.ddl.txt index 48ded29b41..bdabc22b9a 100644 --- a/doc/sql.extensions/README.ddl.txt +++ b/doc/sql.extensions/README.ddl.txt @@ -557,6 +557,7 @@ GRANT_REVOKE_ANY_DDL_RIGHT GRANT and REVOKE any DDL rights CREATE_PRIVILEGED_ROLES Use SET SYSTEM PRIVILEGES in roles MODIFY_EXT_CONN_POOL Manage properties of pool of external connections REPLICATE_INTO_DATABASE Use replication API to load changesets into database +PROFILE_ANY_ATTACHMENT Profile other users' attachments 22) New grantee type in GRANT and REVOKE operators - SYSTEM PRIVILEGE. diff --git a/doc/sql.extensions/README.profiler.md b/doc/sql.extensions/README.profiler.md index 9003cb77eb..cb999b7691 100644 --- a/doc/sql.extensions/README.profiler.md +++ b/doc/sql.extensions/README.profiler.md @@ -14,6 +14,8 @@ Remote profiling just forwards commands to the remote attachment. So it's possib Remote issued commands needs that the target attachment be in an idle state, i.e., not executing others requests. When they are not idle the call blocks waiting for that state. +If remote attachment is from a different user, the calling user must have system privilege PROFILE_ANY_ATTACHMENT. + After a session is started, PSQL and SQL statements statistics starts to be collected in memory. Note that a profile session collects data only of statements executed in the same attachment associated with the session. Data is aggregated and stored per requests (i.e. a statement execution). When querying snapshot tables, user may do extra aggregation per statements or use the auxiliary views that do that automatically. diff --git a/src/jrd/ProfilerManager.cpp b/src/jrd/ProfilerManager.cpp index 4365f02f04..34dfff879c 100644 --- a/src/jrd/ProfilerManager.cpp +++ b/src/jrd/ProfilerManager.cpp @@ -88,6 +88,7 @@ namespace event_t clientEvent; USHORT bufferSize; Tag tag; + char userName[USERNAME_LENGTH + 1]; // \0 if has PROFILE_ANY_ATTACHMENT alignas(FB_ALIGNMENT) UCHAR buffer[4096]; }; @@ -107,12 +108,14 @@ namespace template void sendAndReceive(thread_db* tdbb, Tag tag, const Input* in, Output* out) { + static_assert(sizeof(*in) <= sizeof(std::declval
().buffer), "Buffer size too small"); internalSendAndReceive(tdbb, tag, in, sizeof(*in), out, sizeof(*out)); } template void send(thread_db* tdbb, Tag tag, const Input* in) { + static_assert(sizeof(*in) <= sizeof(std::declval
().buffer), "Buffer size too small"); internalSendAndReceive(tdbb, tag, in, sizeof(*in), nullptr, 0); } @@ -757,6 +760,8 @@ void ProfilerIpc::mutexBug(int osErrorCode, const char* text) void ProfilerIpc::internalSendAndReceive(thread_db* tdbb, Tag tag, const void* in, unsigned inSize, void* out, unsigned outSize) { + const auto attachment = tdbb->getAttachment(); + { // scope ThreadStatusGuard tempStatus(tdbb); @@ -782,9 +787,15 @@ void ProfilerIpc::internalSendAndReceive(thread_db* tdbb, Tag tag, const auto header = sharedMemory->getHeader(); - header->bufferSize = inSize; header->tag = tag; + if (attachment->locksmith(tdbb, PROFILE_ANY_ATTACHMENT)) + header->userName[0] = '\0'; + else + strcpy(header->userName, attachment->getUserName().c_str()); + + header->bufferSize = inSize; + fb_assert(inSize <= sizeof(header->buffer)); memcpy(header->buffer, in, inSize); @@ -928,6 +939,9 @@ void ProfilerListener::processCommand(thread_db* tdbb) const auto header = ipc->sharedMemory->getHeader(); const auto profilerManager = attachment->getProfilerManager(tdbb); + if (header->userName[0] && attachment->getUserName() != header->userName) + status_exception::raise(Arg::Gds(isc_miss_prvlg) << "PROFILE_ANY_ATTACHMENT"); + using Tag = ProfilerIpc::Tag; switch (header->tag) @@ -983,6 +997,7 @@ void ProfilerListener::processCommand(thread_db* tdbb) in->pluginOptionsNull ? 0 : in->pluginOptions.length); const auto out = reinterpret_cast(header->buffer); + static_assert(sizeof(*out) <= sizeof(header->buffer), "Buffer size too small"); header->bufferSize = sizeof(*out); out->sessionIdNull = FB_FALSE; diff --git a/src/jrd/SystemPrivileges.h b/src/jrd/SystemPrivileges.h index 97a066c8c2..7dd08e809f 100644 --- a/src/jrd/SystemPrivileges.h +++ b/src/jrd/SystemPrivileges.h @@ -65,6 +65,7 @@ SYSTEM_PRIVILEGE(CREATE_PRIVILEGED_ROLES) SYSTEM_PRIVILEGE(GET_DBCRYPT_INFO) SYSTEM_PRIVILEGE(MODIFY_EXT_CONN_POOL) SYSTEM_PRIVILEGE(REPLICATE_INTO_DATABASE) +SYSTEM_PRIVILEGE(PROFILE_ANY_ATTACHMENT) #ifdef FB_JRD_SYSTEM_PRIVILEGES_TMP maxSystemPrivilege