用于EagleEye3.0 规则集漏报和误报测试的示例项目,项目收集于github和gitee
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

535 lines
18 KiB

/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2.0,
as published by the Free Software Foundation.
This program is also distributed with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation. The authors of MySQL hereby grant you an additional
permission to link the program and your derivative works with the
separately licensed software that they have included with MySQL.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License, version 2.0, for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/**
@addtogroup Replication
@{
@file event_reader.h
@brief Contains the class responsible for deserializing fields of an event
previously stored in a buffer.
*/
#ifndef EVENT_READER_INCLUDED
#define EVENT_READER_INCLUDED
#include <list>
#include <map>
#include <vector>
#include "byteorder.h"
#include "wrapper_functions.h"
namespace binary_log {
#define PRINT_READER_STATUS(message) \
BAPI_PRINT("debug", (message ": m_buffer= %p, " \
"m_limit= %llu, " \
"m_length= %llu, " \
"position()= %llu", \
m_buffer, m_limit, m_length, Event_reader::position()))
/**
Event_reader class purpose is to avoid out-of-buffer reads when deserializing
binary log events and increase robustness when dealing with corrupted event
buffers.
The Event_reader is composed by a pointer to the beginning of the serialized
event buffer (m_buffer), a variable containing the buffer length (m_length), a
cursor pointer that tells the current position to be read from the buffer
(m_ptr) and the buffer limit the reader shall respect (m_limit <= m_length).
All buffer reading functions shall move the cursor forward.
Before reading from the buffer, the Event_reader will check if the amount of
bytes expected to be read are less or equal to the remaining bytes to read:
remaining = m_limit - (m_ptr - m_buffer)
When there are no enough bytes to read from the buffer, Event_reader enters
in error state, so its owner can take an action.
*/
class Event_reader {
public:
/**
Event_reader constructor.
It sets the cursor to the first position of the buffer.
@param[in] buffer buffer holding a serialized event
@param[in] length known buffer length.
*/
Event_reader(const char *buffer, unsigned long long length)
: m_buffer(buffer),
m_ptr(buffer),
m_length(length),
m_limit(length),
m_error(nullptr) {}
/**
Returns if the Event_reader is in an error state or not.
@retval true if the Event_reader is in error state.
@retval false if the Event_reader is not in error state.
*/
bool has_error() {
BAPI_PRINT("debug", ("m_error= %s", m_error ? m_error : "nullptr"));
return m_error != nullptr;
}
/**
Returns the pointer to the error message.
@return the pointer to the error message when Event_reader is in error
state, or a nullptr otherwise.
*/
const char *get_error() { return m_error; }
/**
Sets Event_reader error state by setting the error message.
@param[in] error pointer to the error message.
*/
void set_error(const char *error);
/**
Returns the Event_reader buffer length.
Note: the buffer length might be larger than reader allowed buffer limit,
but the Event_reader will enter error state when trying to read above the
limit.
Example: an event buffer may contain the serialized event + checksum. The
event reader object will be configured with a buffer length that contains
both the serialized event and the checksum information, but once
Log_event_footer is instantiated, it shall adjust the event reader buffer
limit to the buffer position right before the checksum. This will avoid some
event deserialization relying on event buffer size to assume the checksum as
serialized event content.
@return the Event_reader buffer length.
*/
unsigned long long length() { return (m_length); }
/**
Sets Event_reader buffer length and limit.
The length of the buffer should only be set to values greater or equal to
the current buffer length. Trying to set the length to less than current
buffer length will make the Event_buffer to enter error state.
The length is initially set in Event_reader constructor to
LOG_EVENT_MINIMAL_HEADER_LEN by the Log_event_header when instantiating it.
This should be enough to read the event header and determine the correct
buffer length. The Log_event_header will adjust the Event_reader length by
calling this function based on the value of event data_written header field.
@param[in] length the new Event_reader buffer length.
*/
void set_length(unsigned long long length);
/**
Shrinks the Event_reader buffer limit.
This function is used by Log_event_footer to remove the checksum payload (if
necessary) from the serialized event size, as many event types rely on the
serialized event size to determine the size of some fields.
@param[in] bytes the amount of bytes to shrink the Event_reader buffer
length.
*/
void shrink_limit(unsigned long long bytes);
/**
Returns the Event_reader buffer pointer.
@return the Event_reader buffer pointer.
*/
const char *buffer() { return m_buffer; }
/**
Returns a pointer to the Event_reader cursor (next position to be read by
the Event_reader functions).
@return the pointer to the Event_reader cursor.
*/
const char *ptr() { return m_ptr; }
/**
Returns a pointer to the Event_reader cursor (next position to be read) and
moves the cursor forward.
This function is used when the buffer contains a field of a known size and
the deserialization procedure must keep the pointer to the field but moving
the cursor to after it.
@param[in] length the amount of bytes to move the cursor forward.
@return the pointer to the Event_reader cursor before forwarding it.
*/
const char *ptr(unsigned long long length);
/**
Returns the current Event_reader cursor position in bytes.
@retval m_limit if cursor position is invalid.
@retval position current Event_reader cursor position (if valid).
*/
unsigned long long position() {
return m_ptr >= m_buffer ? m_ptr - m_buffer : m_limit;
}
/**
Returns the amount of bytes still available to read from cursor position.
@return the amount of bytes still available to read.
*/
unsigned long long available_to_read() {
BAPI_ASSERT(position() <= m_limit);
return m_limit - position();
}
/**
Returns if the Event_reader can read a given amount of bytes from cursor
position.
@param bytes the amount of bytes expected to be read.
@retval true if the Event_reader can read the specified amount of bytes.
@retval false if the Event_reader cannot read the specified amount of bytes.
*/
bool can_read(unsigned long long bytes) {
return (available_to_read() >= bytes);
}
/**
Moves cursor to a given absolute buffer position and returns the pointer to
the cursor.
@param position the position to jump to.
@retval pointer a pointer to the new cursor position.
@retval nullptr if the position is out of buffer boundaries.
*/
const char *go_to(unsigned long long position);
/**
Moves the buffer position forward to a given relative position and returns
the pointer to the buffer on the specified position.
@param bytes the amount of bytes to move forward.
@retval pointer a pointer to the new buffer position.
@retval nullptr if the cursor is out of buffer boundaries.
*/
const char *forward(unsigned long long bytes) {
BAPI_PRINT("debug", ("Event_reader::forward(%llu)", bytes));
return go_to((m_ptr - m_buffer) + bytes);
}
/**
Reads a basic type - bool, char, int, long, double, etc - from the buffer,
moves the cursor forward the number of bytes returned by sizeof(T)) and
returns the read value.
@retval value the T read from the cursor position.
@retval 0 if the cursor was out of buffer boundaries.
*/
template <class T>
T read() {
PRINT_READER_STATUS("Event_reader::read");
if (!can_read(sizeof(T))) {
set_error("Cannot read from out of buffer bounds");
BAPI_PRINT("debug", ("Event_reader::tread(): "
"sizeof()= %zu",
sizeof(T)));
return 0;
}
T value = 0;
value = (T) * (m_ptr);
m_ptr = m_ptr + sizeof(T);
return value;
}
/**
Copies a basic type - bool, char, int, long, double, etc - from the buffer,
moves the cursor forward the number of bytes returned by sizeof(T)) and
returns the copied value.
@retval value the T copied from the cursor position.
@retval 0 if the cursor was out of buffer boundaries.
*/
template <class T>
T memcpy() {
PRINT_READER_STATUS("Event_reader::memcpy");
if (!can_read(sizeof(T))) {
set_error("Cannot read from out of buffer bounds");
BAPI_PRINT("debug", ("Event_reader::memcpy(): "
"sizeof()= %zu",
sizeof(T)));
return 0;
}
T value = 0;
::memcpy((char *)&value, m_ptr, sizeof(T));
m_ptr = m_ptr + sizeof(T);
return value;
}
/**
Copies a basic arithmetic type - uint8_t, [u]int16_t, [u]int32_t,
[u]int64_t - from the buffer, moves the cursor forward using specified bytes
parameter (or the number of bytes returned by sizeof(T) when not specified)
and returns the copied value transformed from little endian if necessary).
@param[in] bytes the amount of bytes to read from the buffer (and to move
forward). When not specified, will use sizeof(T).
@retval value the T copied from the cursor position.
@retval 0 if the cursor was out of buffer boundaries or there was no memory
to allocate to the new string..
*/
template <typename T>
T read_and_letoh(unsigned char bytes = sizeof(T)) {
PRINT_READER_STATUS("Event_reader::read_and_letoh");
if (!can_read(bytes)) {
set_error("Cannot read from out of buffer bounds");
BAPI_PRINT("debug", ("Event_reader::read_and_letoh(): "
"sizeof()= %zu, bytes= %u",
sizeof(T), bytes));
return 0;
}
T value = 0;
::memcpy((char *)&value, m_ptr, bytes);
m_ptr = m_ptr + bytes;
return letoh(value);
}
/**
Returns a pointer to a new string which is a duplicate of the input string.
The terminating null character is added. See: bapi_strndup().
@param[in] length the amount of bytes to read from the buffer (and to move
forward).
@retval pointer the T pointer from the cursor position.
@retval nullptr if the cursor was out of buffer boundaries.
*/
template <typename T>
T strndup(size_t length) {
PRINT_READER_STATUS("Event_reader::strndup");
if (!can_read(length)) {
BAPI_PRINT("debug", ("Event_reader::strndup(%zu)", length));
set_error("Cannot read from out of buffer bounds");
return nullptr;
}
T str;
str = reinterpret_cast<T>(bapi_strndup(m_ptr, length));
m_ptr = m_ptr + length;
return str;
}
/**
Copies from the cursor to an already existent (and allocated) buffer and
moves forward the cursor.
@param[out] destination a pointer to the destination buffer.
@param[in] length the amount of bytes to read from the buffer (and to move
forward).
*/
template <typename T>
void memcpy(T destination, size_t length) {
PRINT_READER_STATUS("Event_reader::memcpy");
if (!can_read(length)) {
BAPI_PRINT("debug", ("Event_reader::memcpy(%zu)", length));
set_error("Cannot read from out of buffer bounds");
return;
}
::memcpy(destination, m_ptr, length);
m_ptr = m_ptr + length;
}
/**
Allocates memory to a destination buffer, copies from the cursor to the
destination buffer using memcpy() and moves forward the cursor.
This function is useful for pairs of fields when a first field describes the
second field size and the deserialization procedure must allocate a buffer
for the second field and then copy the event buffer content to the new
allocated buffer.
Before implementing this function and the Event_reader, the deserialization
process did like:
memcpy(length, ptr, sizeof(length);
ptr+=sizeof(length);
field = malloc(length);
memcpy(field, ptr, length);
Allocating the memory for the field before knowing if the content can be
read from the event buffer is a mistake, as it might allocate a very large
amount of memory that will not be used.
So, alloc_and_memcpy ensures that it will only allocate memory for the field
if it can be read from the event buffer, avoiding allocating a memory that
will not be used.
@param[out] destination the destination buffer.
@param[in] length the amount of bytes to allocate and read from the buffer
(and to move forward).
@param[in] flags flags to pass to MySQL server my_malloc() function.
*/
void alloc_and_memcpy(unsigned char **destination, size_t length, int flags);
/**
Allocates memory to a destination buffer, copies from the cursor to the
destination buffer using strncpy() and moves forward the cursor.
See comments on alloc_and_memcpy() for more details.
@param[out] destination the destination buffer.
@param[in] length the amount of bytes to allocate and read from the buffer
(and to forward).
@param[in] flags flags to pass to MySQL server my_malloc() function.
*/
void alloc_and_strncpy(char **destination, size_t length, int flags);
/**
Reads string from cursor.
Reads in the following format:
1) Reads length stored on cursor first index. Moves cursor forward 1 byte.
2) Set destination pointer to the cursor. Moves cursor forward length bytes.
@param[out] destination the destination pointer.
@param[out] length the amount of bytes to allocate and read from the buffer
(and to move forward).
*/
void read_str_at_most_255_bytes(const char **destination, uint8_t *length);
/**
Reads a packed value.
This function can move the cursor forward by 1, 3, 4 or 9 bytes depending on
the value to be returned.
@return the packed value.
*/
uint64_t net_field_length_ll();
/**
Reads a transaction context data set.
@param[in] set_len length of the set object (and to move forward).
@param[out] set pointer to the set object to be filled.
*/
void read_data_set(uint32_t set_len, std::list<const char *> *set);
/**
Reads a view change certification map.
@param[in] map_len the length of the certification info map (and to move
forward).
@param[out] map the certification info map to be filled.
*/
void read_data_map(uint32_t map_len, std::map<std::string, std::string> *map);
/**
Copy a string into the destination buffer up to a max length.
@param[out] destination the destination buffer.
@param[in] max_length the max length to copy from the cursor.
@param[in] dest_length the max length supported by the destination buffer.
*/
void strncpyz(char *destination, size_t max_length, size_t dest_length);
/**
Fills a vector with a sequence of bytes from the cursor.
@param[out] destination the vector be filled.
@param[in] length the amount of bytes to read from the cursor (and to move
forward).
*/
void assign(std::vector<uint8_t> *destination, size_t length);
private:
/* The buffer with the serialized binary log event */
const char *m_buffer;
/* The cursor: a pointer to the current read position in the buffer */
const char *m_ptr;
/* The length of the buffer */
unsigned long long m_length;
/* The limit the reader shall respect when reading from the buffer */
unsigned long long m_limit;
/* The pointer to the current error message, or nullptr */
const char *m_error;
/**
Wrapper to le16toh to be used by read_and_letoh function.
@param[in] value the value to be converted.
@return the converted value.
*/
uint16_t letoh(uint16_t value) { return le16toh(value); }
/**
Wrapper to le32toh to be used by read_and_letoh function.
@param[in] value the value to be converted.
@return the converted value.
*/
int32_t letoh(int32_t value) { return le32toh(value); }
/**
Wrapper to le32toh to be used by read_and_letoh function.
@param[in] value the value to be converted.
@return the converted value.
*/
uint32_t letoh(uint32_t value) { return le32toh(value); }
/**
Wrapper to le64toh to be used by read_and_letoh function.
@param[in] value the value to be converted.
@return the converted value.
*/
int64_t letoh(int64_t value) { return le64toh(value); }
/**
Wrapper to le64toh to be used by read_and_letoh function.
@param[in] value the value to be converted.
@return the converted value.
*/
uint64_t letoh(uint64_t value) { return le64toh(value); }
};
} // end namespace binary_log
/**
@} (end of group Replication)
*/
#endif /* EVENT_READER_INCLUDED */