Skip to content

MDEV-40498 KEY_OP_CHANGE copies length without checking header_end - #5568

Open
KhaledR57 wants to merge 1 commit into
10.11from
10.11-MDEV-40498
Open

MDEV-40498 KEY_OP_CHANGE copies length without checking header_end#5568
KhaledR57 wants to merge 1 commit into
10.11from
10.11-MDEV-40498

Conversation

@KhaledR57

Copy link
Copy Markdown
Contributor

The KEY_OP_CHANGE branch of _ma_apply_redo_index() passed the length from the redo record to memcpy() without checking it against the end of that record, and bounded the destination with a DBUG_ASSERT, which is compiled out when DBUG_OFF is set. A record claiming more data than it carries could therefore copy bytes of earlier records into the page, and an unchecked page offset could put that copy outside the page.

Turn the assert into a runtime check. The logged length and its two operand bytes must fit in what is left of the record, the page offset must be set, and offset plus length must stay inside the used page. The page bound matters on its own: page_offset comes from KEY_OP_OFFSET, which is still guarded only by a DBUG_ASSERT, and records carrying no KEY_OP_SHIFT reach the copy with no bound on it at all.

The test forges the logged length with corrupt_change_length and the logged offset with corrupt_change_offset, then crashes the server so recovery has to replay the records. Each keyword uses the largest value the earlier checks accept, so the two cases trip different halves of the new check.

The KEY_OP_CHANGE branch of _ma_apply_redo_index() passed the length from
the redo record to memcpy() without checking it against the end of that
record, and bounded the destination with a DBUG_ASSERT, which is compiled
out when DBUG_OFF is set. A record claiming more data than it carries
could therefore copy bytes of earlier records into the page, and an
unchecked page offset could put that copy outside the page.

Turn the assert into a runtime check. The logged length and its two
operand bytes must fit in what is left of the record, the page offset
must be set, and offset plus length must stay inside the used page. The
page bound matters on its own: page_offset comes from KEY_OP_OFFSET,
which is still guarded only by a DBUG_ASSERT, and records carrying no
KEY_OP_SHIFT reach the copy with no bound on it at all.

The test forges the logged length with corrupt_change_length and the
logged offset with corrupt_change_offset, then crashes the server so
recovery has to replay the records. Each keyword uses the largest value
the earlier checks accept, so the two cases trip different halves of the
new check.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

1 participant