diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 200c49e0f24..b5d6f1c67cf 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -749,6 +749,33 @@ namespace } } + USHORT validatePageSize(SLONG pageSize) + { + USHORT actualPageSize = DEFAULT_PAGE_SIZE; + + if (pageSize > 0) + { + for (SLONG size = MIN_PAGE_SIZE; size <= MAX_PAGE_SIZE; size <<= 1) + { + if (pageSize <= size) + { + pageSize = size; + break; + } + } + + if (pageSize > MAX_PAGE_SIZE) + pageSize = MAX_PAGE_SIZE; + + fb_assert(pageSize <= MAX_USHORT); + actualPageSize = (USHORT) pageSize; + } + + fb_assert(actualPageSize % PAGE_SIZE_BASE == 0); + fb_assert(actualPageSize >= MIN_PAGE_SIZE && actualPageSize <= MAX_PAGE_SIZE); + + return actualPageSize; + } class DefaultCallback : public AutoIface > { @@ -3005,18 +3032,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch attachment->att_client_charset = attachment->att_charset = options.dpb_interp; - if (options.dpb_page_size <= 0) { - options.dpb_page_size = DEFAULT_PAGE_SIZE; - } - - SLONG page_size = MIN_PAGE_SIZE; - for (; page_size < MAX_PAGE_SIZE; page_size <<= 1) - { - if (options.dpb_page_size < page_size << 1) - break; - } - - dbb->dbb_page_size = (page_size > MAX_PAGE_SIZE) ? MAX_PAGE_SIZE : page_size; + dbb->dbb_page_size = validatePageSize(options.dpb_page_size); TRA_init(attachment); @@ -7634,20 +7650,22 @@ static JAttachment* create_attachment(const PathName& alias_name, static void check_single_maintenance(thread_db* tdbb) { - Database* const dbb = tdbb->getDatabase(); + const auto dbb = tdbb->getDatabase(); + const auto attachment = tdbb->getAttachment(); const ULONG ioBlockSize = dbb->getIOBlockSize(); const ULONG headerSize = MAX(RAW_HEADER_SIZE, ioBlockSize); HalfStaticArray temp; - UCHAR* header_page_buffer = temp.getAlignedBuffer(headerSize, ioBlockSize); + UCHAR* const header_page_buffer = temp.getAlignedBuffer(headerSize, ioBlockSize); - Ods::header_page* const header_page = reinterpret_cast(header_page_buffer); + if (!PIO_header(tdbb, header_page_buffer, headerSize)) + ERR_post(Arg::Gds(isc_bad_db_format) << Arg::Str(attachment->att_filename)); - PIO_header(tdbb, header_page_buffer, headerSize); + const auto header_page = reinterpret_cast(header_page_buffer); if (header_page->hdr_shutdown_mode == Ods::hdr_shutdown_single) - ERR_post(Arg::Gds(isc_shutdown) << Arg::Str(tdbb->getAttachment()->att_filename)); + ERR_post(Arg::Gds(isc_shutdown) << Arg::Str(attachment->att_filename)); } diff --git a/src/jrd/ods.h b/src/jrd/ods.h index dfed99612eb..eeec2987ba7 100644 --- a/src/jrd/ods.h +++ b/src/jrd/ods.h @@ -214,6 +214,9 @@ inline constexpr ULONG FIRST_SCN_PAGE = 2; // Page size limits +inline constexpr USHORT PAGE_SIZE_BASE = 1024; // Minimal page size ever supported, + // common divisor for valid page sizes + inline constexpr USHORT MIN_PAGE_SIZE = 4096; inline constexpr USHORT MAX_PAGE_SIZE = 32768; diff --git a/src/jrd/os/pio_proto.h b/src/jrd/os/pio_proto.h index 8ec0ec3cde0..b1deba54342 100644 --- a/src/jrd/os/pio_proto.h +++ b/src/jrd/os/pio_proto.h @@ -44,7 +44,7 @@ void PIO_extend(Jrd::thread_db*, Jrd::jrd_file*, const ULONG, const USHORT); void PIO_flush(Jrd::thread_db*, Jrd::jrd_file*); void PIO_force_write(Jrd::jrd_file*, const bool); ULONG PIO_get_number_of_pages(const Jrd::jrd_file*, const USHORT); -void PIO_header(Jrd::thread_db*, UCHAR*, int); +bool PIO_header(Jrd::thread_db*, UCHAR*, unsigned); USHORT PIO_init_data(Jrd::thread_db*, Jrd::jrd_file*, Jrd::FbStatusVector*, ULONG, USHORT); Jrd::jrd_file* PIO_open(Jrd::thread_db*, const Firebird::PathName&, const Firebird::PathName&); diff --git a/src/jrd/os/posix/unix.cpp b/src/jrd/os/posix/unix.cpp index 5d41325a480..f92600461e5 100644 --- a/src/jrd/os/posix/unix.cpp +++ b/src/jrd/os/posix/unix.cpp @@ -507,7 +507,7 @@ error: Raw device support for your OS is missing. Fix it or turn off raw device } -void PIO_header(thread_db* tdbb, UCHAR* address, int length) +bool PIO_header(thread_db* tdbb, UCHAR* address, unsigned length) { /************************************** * @@ -519,13 +519,13 @@ void PIO_header(thread_db* tdbb, UCHAR* address, int length) * Read the page header. * **************************************/ - Database* const dbb = tdbb->getDatabase(); + const auto dbb = tdbb->getDatabase(); - int i; + unsigned i; SINT64 bytes; - PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); - jrd_file* file = pageSpace->file; + PageSpace* const pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); + jrd_file* const file = pageSpace->file; if (file->fil_desc == -1) unix_error("PIO_header", file, isc_io_read_err); @@ -537,7 +537,11 @@ void PIO_header(thread_db* tdbb, UCHAR* address, int length) if (bytes < 0 && !SYSCALL_INTERRUPTED(errno)) unix_error("read", file, isc_io_read_err); if (bytes >= 0) - block_size_error(file, bytes); + { + FbLocalStatus tempStatus; + if (!block_size_error(file, bytes, &tempStatus)) + return false; + } } if (i == IO_RETRY) @@ -558,6 +562,8 @@ void PIO_header(thread_db* tdbb, UCHAR* address, int length) unix_error("read_retry", file, isc_io_read_err); } } + + return true; } // we need a class here only to return memory on shutdown and avoid diff --git a/src/jrd/os/win32/winnt.cpp b/src/jrd/os/win32/winnt.cpp index fa9ea5bb1ea..6feb7bd66b0 100644 --- a/src/jrd/os/win32/winnt.cpp +++ b/src/jrd/os/win32/winnt.cpp @@ -329,7 +329,7 @@ void PIO_force_write(jrd_file* file, const bool forceWrite) } -void PIO_header(thread_db* tdbb, UCHAR* address, int length) +bool PIO_header(thread_db* tdbb, UCHAR* address, unsigned length) { /************************************** * @@ -345,11 +345,11 @@ void PIO_header(thread_db* tdbb, UCHAR* address, int length) * callers should not rely on this behavior * **************************************/ - Database* const dbb = tdbb->getDatabase(); + const auto dbb = tdbb->getDatabase(); - PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); - jrd_file* file = pageSpace->file; - HANDLE desc = file->fil_desc; + PageSpace* const pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); + jrd_file* const file = pageSpace->file; + const HANDLE desc = file->fil_desc; OVERLAPPED overlapped; memset(&overlapped, 0, sizeof(OVERLAPPED)); @@ -361,10 +361,12 @@ void PIO_header(thread_db* tdbb, UCHAR* address, int length) { if (GetLastError() == ERROR_IO_PENDING) ret = GetOverlappedResult(desc, &overlapped, &actual_length, TRUE); + + if (!ret) + nt_error("ReadFile", file, isc_io_read_err, NULL); } - if (!ret || (length != actual_length)) - nt_error("ReadFile", file, isc_io_read_err, NULL); + return (length == actual_length); } // we need a class here only to return memory on shutdown and avoid diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index 17e150184a7..b7e3d65d198 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -1115,10 +1115,15 @@ void PAG_header_init(thread_db* tdbb) HalfStaticArray temp; UCHAR* const temp_page = temp.getAlignedBuffer(headerSize, ioBlockSize); - PIO_header(tdbb, temp_page, headerSize); - const header_page* header = (header_page*) temp_page; + if (!PIO_header(tdbb, temp_page, headerSize)) + ERR_post(Arg::Gds(isc_bad_db_format) << Arg::Str(attachment->att_filename)); + + const auto header = (header_page*) temp_page; + + if (header->hdr_header.pag_type != pag_header || header->hdr_header.pag_pageno != HEADER_PAGE) + ERR_post(Arg::Gds(isc_bad_db_format) << Arg::Str(attachment->att_filename)); - if (header->hdr_header.pag_type != pag_header) + if (header->hdr_page_size < PAGE_SIZE_BASE || header->hdr_page_size % PAGE_SIZE_BASE != 0) ERR_post(Arg::Gds(isc_bad_db_format) << Arg::Str(attachment->att_filename)); const USHORT ods_version = header->hdr_ods_version & ~ODS_FIREBIRD_FLAG;