From b93f2781a8d8d0ae746b1ae3c47894c7debf52a0 Mon Sep 17 00:00:00 2001 From: Vlad Khorsun Date: Wed, 11 Feb 2026 00:04:43 +0200 Subject: [PATCH 1/3] Fixed bug #8885 : AV when lock manager settings is misconfigured. Ensure shared memory size is multiply of system page size - it guarantees mapObject() will not access area after the end of file. It could fix #5860 : operating system directive MapViewOfFile failed access denied [CORE5594] --- src/common/isc_s_proto.h | 4 ++ src/common/isc_sync.cpp | 92 ++++++++++++++++++++++------------------ src/jrd/event.cpp | 4 +- src/lock/lock.cpp | 26 +++++++++--- src/lock/lock_proto.h | 3 +- 5 files changed, 79 insertions(+), 50 deletions(-) diff --git a/src/common/isc_s_proto.h b/src/common/isc_s_proto.h index f5889159a20..4c7579a1867 100644 --- a/src/common/isc_s_proto.h +++ b/src/common/isc_s_proto.h @@ -279,6 +279,9 @@ class SharedMemoryBase int eventWait(event_t* event, const SLONG value, const SLONG micro_seconds); int eventPost(event_t* event); + // Used as memory allocation unit and mapping alignment + static ULONG getSystemPageSize(); + public: #ifdef UNIX Firebird::AutoPtr mainLock; @@ -296,6 +299,7 @@ class SharedMemoryBase #endif ULONG sh_mem_length_mapped; + const ULONG sh_mem_increment; // Suggested growth increment #ifdef WIN_NT HANDLE sh_mem_handle; // file handle HANDLE sh_mem_object; // file mapping diff --git a/src/common/isc_sync.cpp b/src/common/isc_sync.cpp index 58aad818fed..da8a109d5e5 100644 --- a/src/common/isc_sync.cpp +++ b/src/common/isc_sync.cpp @@ -1250,12 +1250,38 @@ void SharedMemoryBase::internalUnmap() } } + +ULONG SharedMemoryBase::getSystemPageSize() +{ + // Get system page size as this is the unit of mapping. + +#ifdef SOLARIS + const long ps = sysconf(_SC_PAGESIZE); + if (ps == -1) + { + error(statusVector, "sysconf", errno); + return 0; + } +#else + const int ps = getpagesize(); + if (ps == -1) + { + error(statusVector, "getpagesize", errno); + return 0; + } +#endif + return ps; +} + + SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject* callback, bool skipLock) : #ifdef HAVE_SHARED_MUTEX_SECTION sh_mem_mutex(0), #endif - sh_mem_length_mapped(0), sh_mem_header(NULL), + sh_mem_length_mapped(0), + sh_mem_increment(FB_ALIGN(length, getSystemPageSize())), + sh_mem_header(NULL), sh_mem_callback(callback) { /************************************** @@ -1286,6 +1312,9 @@ SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject TEXT init_filename[MAXPATHLEN]; iscPrefixLock(init_filename, INIT_FILE, true); + if (length && length < sh_mem_increment) + length = sh_mem_increment; + const bool trunc_flag = (length != 0); // open the init lock file @@ -1569,8 +1598,18 @@ void SharedMemoryBase::internalUnmap() unlinkFile(); } + +ULONG SharedMemoryBase::getSystemPageSize() +{ + SYSTEM_INFO sys_info; + GetSystemInfo(&sys_info); + return sys_info.dwAllocationGranularity; +} + + SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject* cb, bool /*skipLock*/) : sh_mem_mutex(0), sh_mem_length_mapped(0), + sh_mem_increment(FB_ALIGN(length, getSystemPageSize())), sh_mem_handle(INVALID_HANDLE_VALUE), sh_mem_object(0), sh_mem_interest(0), sh_mem_hdr_object(0), sh_mem_hdr_address(0), sh_mem_header(NULL), sh_mem_callback(cb), sh_mem_unlink(false) { @@ -1598,6 +1637,9 @@ SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject bool init_flag = false; DWORD err = 0; + if (length && length < sh_mem_increment) + length = sh_mem_increment; + // retry to attach to mmapped file if the process initializing dies during initialization. retry: @@ -1925,24 +1967,9 @@ UCHAR* SharedMemoryBase::mapObject(CheckStatusWrapper* statusVector, ULONG objec * **************************************/ - // Get system page size as this is the unit of mapping. - -#ifdef SOLARIS - const long ps = sysconf(_SC_PAGESIZE); - if (ps == -1) - { - error(statusVector, "sysconf", errno); + const ULONG page_size = getSystemPageSize(); + if (!page_size) return NULL; - } -#else - const int ps = getpagesize(); - if (ps == -1) - { - error(statusVector, "getpagesize", errno); - return NULL; - } -#endif - const ULONG page_size = (ULONG) ps; // Compute the start and end page-aligned offsets which contain the object being mapped. @@ -1980,24 +2007,9 @@ void SharedMemoryBase::unmapObject(CheckStatusWrapper* statusVector, UCHAR** obj * Zero the object pointer after a successful unmap. * **************************************/ - // Get system page size as this is the unit of mapping. - -#ifdef SOLARIS - const long ps = sysconf(_SC_PAGESIZE); - if (ps == -1) - { - error(statusVector, "sysconf", errno); + const size_t page_size = getSystemPageSize(); + if (!page_size) return; - } -#else - const int ps = getpagesize(); - if (ps == -1) - { - error(statusVector, "getpagesize", errno); - return; - } -#endif - const size_t page_size = (ULONG) ps; // Compute the start and end page-aligned addresses which contain the mapped object. @@ -2035,9 +2047,7 @@ UCHAR* SharedMemoryBase::mapObject(CheckStatusWrapper* statusVector, * **************************************/ - SYSTEM_INFO sys_info; - GetSystemInfo(&sys_info); - const ULONG page_size = sys_info.dwAllocationGranularity; + const ULONG page_size = getSystemPageSize(); // Compute the start and end page-aligned offsets which // contain the object being mapped. @@ -2047,6 +2057,8 @@ UCHAR* SharedMemoryBase::mapObject(CheckStatusWrapper* statusVector, const ULONG length = end - start; const HANDLE handle = sh_mem_object; + fb_assert(end <= sh_mem_length_mapped); + UCHAR* address = (UCHAR*) MapViewOfFile(handle, FILE_MAP_WRITE, 0, start, length); if (address == NULL) @@ -2075,9 +2087,7 @@ void SharedMemoryBase::unmapObject(CheckStatusWrapper* statusVector, * Zero the object pointer after a successful unmap. * **************************************/ - SYSTEM_INFO sys_info; - GetSystemInfo(&sys_info); - const size_t page_size = sys_info.dwAllocationGranularity; + const size_t page_size = getSystemPageSize(); // Compute the start and end page-aligned offsets which // contain the object being mapped. diff --git a/src/jrd/event.cpp b/src/jrd/event.cpp index ffbb4e1bb59..59b8139f9ad 100644 --- a/src/jrd/event.cpp +++ b/src/jrd/event.cpp @@ -534,8 +534,10 @@ frb* EventManager::alloc_global(UCHAR type, ULONG length, bool recurse) #ifdef HAVE_OBJECT_MAP if (!best && !recurse) { + fb_assert(length <= m_sharedMemory->sh_mem_increment); + const ULONG old_length = m_sharedMemory->sh_mem_length_mapped; - const ULONG ev_length = old_length + m_config->getEventMemSize(); + const ULONG ev_length = old_length + m_sharedMemory->sh_mem_increment; LocalStatus ls; CheckStatusWrapper localStatus(&ls); diff --git a/src/lock/lock.cpp b/src/lock/lock.cpp index 3739f3ce6af..42cc614f17b 100644 --- a/src/lock/lock.cpp +++ b/src/lock/lock.cpp @@ -177,11 +177,26 @@ LockManager::LockManager(const string& id, const Config* conf) m_config(conf), m_acquireSpins(m_config->getLockAcquireSpins()), m_memorySize(m_config->getLockMemSize()), + m_hashSlots(m_config->getLockHashSlots()), m_useBlockingThread(m_config->getServerMode() != MODE_SUPER) #ifdef USE_SHMEM_EXT , m_extents(getPool()) #endif { + if (m_hashSlots < HASH_MIN_SLOTS) + m_hashSlots = HASH_MIN_SLOTS; + if (m_hashSlots > HASH_MAX_SLOTS) + m_hashSlots = HASH_MAX_SLOTS; + + // memory size required to fit all hash slots, history blocks and header blocks + const auto minMemory = sizeof(lhb) + + FB_ALIGN(sizeof(shb), FB_ALIGNMENT) + + sizeof(lhb::lhb_hash[0]) * m_hashSlots + + FB_ALIGN(sizeof(his), FB_ALIGNMENT) * HISTORY_BLOCKS * 2; + + if (m_memorySize < minMemory) + m_memorySize = minMemory; + LocalStatus ls; CheckStatusWrapper localStatus(&ls); if (!init_shared_file(&localStatus)) @@ -304,6 +319,9 @@ bool LockManager::init_shared_file(CheckStatusWrapper* statusVector) const auto header = tmp->getHeader(); checkHeader(header); + + // Get properly aligned value + m_memorySize = m_sharedMemory->sh_mem_increment; } catch (const Exception& ex) { @@ -2330,13 +2348,7 @@ bool LockManager::initialize(SharedMemoryBase* sm, bool initializeMemory) SRQ_INIT(hdr->lhb_free_locks); SRQ_INIT(hdr->lhb_free_requests); - int hash_slots = m_config->getLockHashSlots(); - if (hash_slots < HASH_MIN_SLOTS) - hash_slots = HASH_MIN_SLOTS; - if (hash_slots > HASH_MAX_SLOTS) - hash_slots = HASH_MAX_SLOTS; - - hdr->lhb_hash_slots = (USHORT) hash_slots; + hdr->lhb_hash_slots = m_hashSlots; hdr->lhb_scan_interval = m_config->getDeadlockTimeout(); hdr->lhb_acquire_spins = m_acquireSpins; diff --git a/src/lock/lock_proto.h b/src/lock/lock_proto.h index b0b14511938..444c6c51e8b 100644 --- a/src/lock/lock_proto.h +++ b/src/lock/lock_proto.h @@ -507,7 +507,8 @@ class LockManager final : public Firebird::GlobalStorage, public Firebird::IpcOb // configurations parameters - cached values const ULONG m_acquireSpins; - const ULONG m_memorySize; + ULONG m_memorySize; + USHORT m_hashSlots; const bool m_useBlockingThread; #ifdef USE_SHMEM_EXT From 62ca546d385e57f3b56cae434b62435f52b148e0 Mon Sep 17 00:00:00 2001 From: Vlad Khorsun Date: Wed, 11 Feb 2026 01:45:41 +0200 Subject: [PATCH 2/3] Fixed non-Windows builds --- src/common/isc_s_proto.h | 4 ++-- src/common/isc_sync.cpp | 44 ++++++++++++++++++++++++++++------------ 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/common/isc_s_proto.h b/src/common/isc_s_proto.h index 4c7579a1867..72cb066de3a 100644 --- a/src/common/isc_s_proto.h +++ b/src/common/isc_s_proto.h @@ -280,7 +280,7 @@ class SharedMemoryBase int eventPost(event_t* event); // Used as memory allocation unit and mapping alignment - static ULONG getSystemPageSize(); + static ULONG getSystemPageSize(Firebird::CheckStatusWrapper* status); public: #ifdef UNIX @@ -299,7 +299,7 @@ class SharedMemoryBase #endif ULONG sh_mem_length_mapped; - const ULONG sh_mem_increment; // Suggested growth increment + ULONG sh_mem_increment; // Suggested growth increment #ifdef WIN_NT HANDLE sh_mem_handle; // file handle HANDLE sh_mem_object; // file mapping diff --git a/src/common/isc_sync.cpp b/src/common/isc_sync.cpp index da8a109d5e5..41fdc637e88 100644 --- a/src/common/isc_sync.cpp +++ b/src/common/isc_sync.cpp @@ -1251,7 +1251,7 @@ void SharedMemoryBase::internalUnmap() } -ULONG SharedMemoryBase::getSystemPageSize() +ULONG SharedMemoryBase::getSystemPageSize(CheckStatusWrapper* statusVector) { // Get system page size as this is the unit of mapping. @@ -1280,7 +1280,7 @@ SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject sh_mem_mutex(0), #endif sh_mem_length_mapped(0), - sh_mem_increment(FB_ALIGN(length, getSystemPageSize())), + sh_mem_increment(0), sh_mem_header(NULL), sh_mem_callback(callback) { @@ -1312,8 +1312,16 @@ SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject TEXT init_filename[MAXPATHLEN]; iscPrefixLock(init_filename, INIT_FILE, true); - if (length && length < sh_mem_increment) - length = sh_mem_increment; + if (length) + { + sh_mem_increment = FB_ALIGN(length, getSystemPageSize(&statusVector)); + + if (statusVector.hasData()) + status_exception::raise(&statusVector); + + if (length < sh_mem_increment) + length = sh_mem_increment; + } const bool trunc_flag = (length != 0); @@ -1599,7 +1607,7 @@ void SharedMemoryBase::internalUnmap() } -ULONG SharedMemoryBase::getSystemPageSize() +ULONG SharedMemoryBase::getSystemPageSize(CheckStatusWrapper* /*statusVector*/) { SYSTEM_INFO sys_info; GetSystemInfo(&sys_info); @@ -1608,8 +1616,7 @@ ULONG SharedMemoryBase::getSystemPageSize() SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject* cb, bool /*skipLock*/) - : sh_mem_mutex(0), sh_mem_length_mapped(0), - sh_mem_increment(FB_ALIGN(length, getSystemPageSize())), + : sh_mem_mutex(0), sh_mem_length_mapped(0), sh_mem_increment(0), sh_mem_handle(INVALID_HANDLE_VALUE), sh_mem_object(0), sh_mem_interest(0), sh_mem_hdr_object(0), sh_mem_hdr_address(0), sh_mem_header(NULL), sh_mem_callback(cb), sh_mem_unlink(false) { @@ -1637,8 +1644,19 @@ SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject bool init_flag = false; DWORD err = 0; - if (length && length < sh_mem_increment) - length = sh_mem_increment; + if (length) + { + LocalStatus ls; + CheckStatusWrapper statusVector(&ls); + + sh_mem_increment = FB_ALIGN(length, getSystemPageSize(&statusVector)); + + if (statusVector.hasData()) + status_exception::raise(&statusVector); + + if (length < sh_mem_increment) + length = sh_mem_increment; + } // retry to attach to mmapped file if the process initializing dies during initialization. @@ -1967,7 +1985,7 @@ UCHAR* SharedMemoryBase::mapObject(CheckStatusWrapper* statusVector, ULONG objec * **************************************/ - const ULONG page_size = getSystemPageSize(); + const ULONG page_size = getSystemPageSize(statusVector); if (!page_size) return NULL; @@ -2007,7 +2025,7 @@ void SharedMemoryBase::unmapObject(CheckStatusWrapper* statusVector, UCHAR** obj * Zero the object pointer after a successful unmap. * **************************************/ - const size_t page_size = getSystemPageSize(); + const size_t page_size = getSystemPageSize(statusVector); if (!page_size) return; @@ -2047,7 +2065,7 @@ UCHAR* SharedMemoryBase::mapObject(CheckStatusWrapper* statusVector, * **************************************/ - const ULONG page_size = getSystemPageSize(); + const ULONG page_size = getSystemPageSize(statusVector); // Compute the start and end page-aligned offsets which // contain the object being mapped. @@ -2087,7 +2105,7 @@ void SharedMemoryBase::unmapObject(CheckStatusWrapper* statusVector, * Zero the object pointer after a successful unmap. * **************************************/ - const size_t page_size = getSystemPageSize(); + const size_t page_size = getSystemPageSize(statusVector); // Compute the start and end page-aligned offsets which // contain the object being mapped. From dfd3d099f54bc3020c5f1120447ef0bd78552da3 Mon Sep 17 00:00:00 2001 From: Vlad Khorsun Date: Wed, 11 Feb 2026 14:43:11 +0200 Subject: [PATCH 3/3] Simplify code in SharedMemoryBase() ctor. Add missed alignment in remapFile(). --- src/common/isc_sync.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/common/isc_sync.cpp b/src/common/isc_sync.cpp index 41fdc637e88..9998406e93f 100644 --- a/src/common/isc_sync.cpp +++ b/src/common/isc_sync.cpp @@ -1314,13 +1314,10 @@ SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject if (length) { - sh_mem_increment = FB_ALIGN(length, getSystemPageSize(&statusVector)); + sh_mem_increment = length = FB_ALIGN(length, getSystemPageSize(&statusVector)); if (statusVector.hasData()) status_exception::raise(&statusVector); - - if (length < sh_mem_increment) - length = sh_mem_increment; } const bool trunc_flag = (length != 0); @@ -1649,13 +1646,10 @@ SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject LocalStatus ls; CheckStatusWrapper statusVector(&ls); - sh_mem_increment = FB_ALIGN(length, getSystemPageSize(&statusVector)); + sh_mem_increment = length = FB_ALIGN(length, getSystemPageSize(&statusVector)); if (statusVector.hasData()) status_exception::raise(&statusVector); - - if (length < sh_mem_increment) - length = sh_mem_increment; } // retry to attach to mmapped file if the process initializing dies during initialization. @@ -2525,6 +2519,8 @@ bool SharedMemoryBase::remapFile(CheckStatusWrapper* statusVector, ULONG new_len if (flag) { + new_length = FB_ALIGN(new_length, getSystemPageSize(statusVector)); + FB_UNUSED(os_utils::ftruncate(mainLock->getFd(), new_length)); if (new_length > sh_mem_length_mapped) @@ -2581,6 +2577,8 @@ bool SharedMemoryBase::remapFile(CheckStatusWrapper* statusVector, if (flag) { + new_length = FB_ALIGN(new_length, getSystemPageSize(statusVector)); + LARGE_INTEGER offset; offset.QuadPart = new_length;