Add MariaDB 10.1.13 offsets. Format the code.
parent
051b1fd67e
commit
80646620e9
|
@ -49,12 +49,12 @@ typedef struct _THDPRINTED {
|
|||
} THDPRINTED;
|
||||
|
||||
#define MAX_COMMAND_CHAR_NUMBERS 40
|
||||
const char * retrieve_command (THD * thd, bool & is_sql_cmd);
|
||||
const char *retrieve_command(THD *thd, bool & is_sql_cmd);
|
||||
typedef size_t OFFSET;
|
||||
|
||||
#define MAX_COM_STATUS_VARS_RECORDS 512
|
||||
|
||||
//mysql max identifier is 64 so 2*64 + . and null
|
||||
// mysql max identifier is 64 so 2*64 + . and null
|
||||
#define MAX_OBJECT_CHAR_NUMBERS 131
|
||||
#define MAX_USER_CHAR_NUMBERS 20
|
||||
#define MAX_NUM_OBJECT_ELEM 256
|
||||
|
@ -63,10 +63,9 @@ typedef size_t OFFSET;
|
|||
/**
|
||||
* The struct used to hold offsets. We should have one per version.
|
||||
*/
|
||||
typedef struct ThdOffsets
|
||||
{
|
||||
const char * version;
|
||||
const char * md5digest;
|
||||
typedef struct ThdOffsets {
|
||||
const char *version;
|
||||
const char *md5digest;
|
||||
OFFSET query_id;
|
||||
OFFSET thread_id;
|
||||
OFFSET main_security_ctx;
|
||||
|
@ -96,30 +95,28 @@ typedef ssize_t (*audit_write_func)(const char *, size_t);
|
|||
/**
|
||||
* Interface for an io writer
|
||||
*/
|
||||
class IWriter
|
||||
{
|
||||
class IWriter {
|
||||
public:
|
||||
virtual ~IWriter() {}
|
||||
//return negative on fail
|
||||
virtual ssize_t write(const char * data, size_t size) = 0;
|
||||
inline ssize_t write_str(const char * str)
|
||||
// return negative on fail
|
||||
virtual ssize_t write(const char *data, size_t size) = 0;
|
||||
inline ssize_t write_str(const char *str)
|
||||
{
|
||||
return write(str, strlen(str));
|
||||
}
|
||||
//return 0 on success
|
||||
virtual int open(const char * io_dest, bool log_errors) = 0;
|
||||
// return 0 on success
|
||||
virtual int open(const char *io_dest, bool log_errors) = 0;
|
||||
virtual void close() = 0;
|
||||
};
|
||||
|
||||
class ThdSesData {
|
||||
public:
|
||||
|
||||
//enum indicating from where the object list came from
|
||||
// enum indicating from where the object list came from
|
||||
enum ObjectIterType {OBJ_NONE, OBJ_DB, OBJ_QUERY_CACHE, OBJ_TABLE_LIST};
|
||||
ThdSesData(THD *pTHD);
|
||||
THD* getTHD () { return m_pThd;}
|
||||
const char * getCmdName () { return m_CmdName; }
|
||||
const char * getUserName () { return m_UserName; }
|
||||
THD *getTHD() { return m_pThd;}
|
||||
const char *getCmdName() { return m_CmdName; }
|
||||
const char *getUserName() { return m_UserName; }
|
||||
/**
|
||||
* Start fetching objects. Return true if there are objects available.
|
||||
*/
|
||||
|
@ -129,32 +126,32 @@ public:
|
|||
* Will point the passed pointers to point to db, name and type.
|
||||
* obj_type is optional and may be null.
|
||||
*/
|
||||
bool getNextObject(const char ** db_name, const char ** obj_name, const char ** obj_type);
|
||||
bool getNextObject(const char **db_name, const char **obj_name, const char **obj_type);
|
||||
|
||||
private:
|
||||
THD *m_pThd;
|
||||
const char *m_CmdName;
|
||||
const char *m_UserName;
|
||||
bool m_isSqlCmd;
|
||||
enum ObjectIterType m_objIterType;
|
||||
//pointer for iterating tables
|
||||
TABLE_LIST * m_tables;
|
||||
//indicator if we are at the first table
|
||||
// pointer for iterating tables
|
||||
TABLE_LIST *m_tables;
|
||||
// indicator if we are at the first table
|
||||
bool m_firstTable;
|
||||
//used for query cache iter
|
||||
QueryTableInf * m_tableInf;
|
||||
// used for query cache iter
|
||||
QueryTableInf *m_tableInf;
|
||||
int m_index;
|
||||
|
||||
protected:
|
||||
ThdSesData (const ThdSesData& );
|
||||
ThdSesData &operator =(const ThdSesData& );
|
||||
ThdSesData(const ThdSesData&);
|
||||
ThdSesData &operator =(const ThdSesData&);
|
||||
};
|
||||
|
||||
/**
|
||||
* Base for audit formatter
|
||||
*/
|
||||
class Audit_formatter
|
||||
{
|
||||
class Audit_formatter {
|
||||
public:
|
||||
|
||||
virtual ~Audit_formatter() {}
|
||||
|
||||
/**
|
||||
|
@ -167,40 +164,40 @@ public:
|
|||
*
|
||||
* @return -1 on a failure
|
||||
*/
|
||||
virtual ssize_t event_format(ThdSesData *pThdData, IWriter * writer) =0;
|
||||
virtual ssize_t event_format(ThdSesData *pThdData, IWriter *writer) =0;
|
||||
/**
|
||||
* format a message when handler is started
|
||||
* @return -1 on a failure
|
||||
*/
|
||||
virtual ssize_t start_msg_format(IWriter * writer) { return 0; }
|
||||
virtual ssize_t start_msg_format(IWriter *writer) { return 0; }
|
||||
/**
|
||||
* format a message when handler is stopped
|
||||
* @return -1 on a failure
|
||||
*/
|
||||
virtual ssize_t stop_msg_format(IWriter * writer) { return 0; }
|
||||
virtual ssize_t stop_msg_format(IWriter *writer) { return 0; }
|
||||
|
||||
static const char * retrieve_object_type (TABLE_LIST *pObj);
|
||||
static QueryTableInf* getQueryCacheTableList1 (THD *thd);
|
||||
//utility functions for fetching thd stuff
|
||||
static inline my_thread_id thd_inst_thread_id(THD * thd)
|
||||
static const char *retrieve_object_type(TABLE_LIST *pObj);
|
||||
static QueryTableInf *getQueryCacheTableList1(THD *thd);
|
||||
// utility functions for fetching thd stuff
|
||||
static inline my_thread_id thd_inst_thread_id(THD *thd)
|
||||
{
|
||||
return *(my_thread_id *) (((unsigned char *) thd)
|
||||
+ Audit_formatter::thd_offsets.thread_id);
|
||||
}
|
||||
static inline query_id_t thd_inst_query_id(THD * thd)
|
||||
static inline query_id_t thd_inst_query_id(THD *thd)
|
||||
{
|
||||
return *(query_id_t *) (((unsigned char *) thd)
|
||||
+ Audit_formatter::thd_offsets.query_id);
|
||||
}
|
||||
static inline Security_context * thd_inst_main_security_ctx(THD * thd)
|
||||
static inline Security_context *thd_inst_main_security_ctx(THD *thd)
|
||||
{
|
||||
return (Security_context *) (((unsigned char *) thd)
|
||||
+ Audit_formatter::thd_offsets.main_security_ctx);
|
||||
}
|
||||
|
||||
static inline const char * thd_db(THD * thd)
|
||||
static inline const char *thd_db(THD *thd)
|
||||
{
|
||||
if(!Audit_formatter::thd_offsets.db) //no offsets use compiled in header
|
||||
if (! Audit_formatter::thd_offsets.db) // no offsets use compiled in header
|
||||
{
|
||||
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
|
||||
return thd->db;
|
||||
|
@ -212,9 +209,9 @@ public:
|
|||
+ Audit_formatter::thd_offsets.db);
|
||||
}
|
||||
|
||||
static inline int thd_killed(THD * thd)
|
||||
static inline int thd_killed(THD *thd)
|
||||
{
|
||||
if(!Audit_formatter::thd_offsets.killed) //no offsets use thd_killed function
|
||||
if (! Audit_formatter::thd_offsets.killed) // no offsets use thd_killed function
|
||||
{
|
||||
return ::thd_killed(thd);
|
||||
}
|
||||
|
@ -222,10 +219,10 @@ public:
|
|||
+ Audit_formatter::thd_offsets.killed);
|
||||
}
|
||||
|
||||
static inline const char * thd_inst_main_security_ctx_user(THD * thd)
|
||||
static inline const char *thd_inst_main_security_ctx_user(THD *thd)
|
||||
{
|
||||
Security_context * sctx = thd_inst_main_security_ctx(thd);
|
||||
if(!Audit_formatter::thd_offsets.sec_ctx_user) //no offsets use compiled in header
|
||||
Security_context *sctx = thd_inst_main_security_ctx(thd);
|
||||
if (! Audit_formatter::thd_offsets.sec_ctx_user) // no offsets use compiled in header
|
||||
{
|
||||
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
|
||||
return sctx->user;
|
||||
|
@ -237,13 +234,13 @@ public:
|
|||
+ Audit_formatter::thd_offsets.sec_ctx_user);
|
||||
}
|
||||
|
||||
static inline const char * thd_inst_main_security_ctx_host(THD * thd)
|
||||
static inline const char *thd_inst_main_security_ctx_host(THD *thd)
|
||||
{
|
||||
Security_context * sctx = thd_inst_main_security_ctx(thd);
|
||||
if(!Audit_formatter::thd_offsets.sec_ctx_ip) //check ip to understand if set as host is first and may actually be set to 0
|
||||
Security_context *sctx = thd_inst_main_security_ctx(thd);
|
||||
if (! Audit_formatter::thd_offsets.sec_ctx_ip) // check ip to understand if set as host is first and may actually be set to 0
|
||||
{
|
||||
//interface changed in 5.5.34 and 5.6.14 and up host changed to get_host()
|
||||
//see: http://bazaar.launchpad.net/~mysql/mysql-server/5.5/revision/4407.1.1/sql/sql_class.h
|
||||
// interface changed in 5.5.34 and 5.6.14 and up host changed to get_host()
|
||||
// see: http://bazaar.launchpad.net/~mysql/mysql-server/5.5/revision/4407.1.1/sql/sql_class.h
|
||||
#if defined(MARIADB_BASE_VERSION)
|
||||
return sctx->host;
|
||||
#else
|
||||
|
@ -263,12 +260,12 @@ public:
|
|||
+ Audit_formatter::thd_offsets.sec_ctx_host);
|
||||
}
|
||||
|
||||
static inline const char * thd_inst_main_security_ctx_ip(THD * thd)
|
||||
static inline const char *thd_inst_main_security_ctx_ip(THD *thd)
|
||||
{
|
||||
Security_context * sctx = thd_inst_main_security_ctx(thd);
|
||||
if(!Audit_formatter::thd_offsets.sec_ctx_ip) //no offsets use compiled in header
|
||||
Security_context *sctx = thd_inst_main_security_ctx(thd);
|
||||
if (! Audit_formatter::thd_offsets.sec_ctx_ip) // no offsets use compiled in header
|
||||
{
|
||||
//interface changed in 5.5.34 and 5.6.14 and up host changed to get_ip()
|
||||
// interface changed in 5.5.34 and 5.6.14 and up host changed to get_ip()
|
||||
#if defined(MARIADB_BASE_VERSION)
|
||||
return sctx->ip;
|
||||
#else
|
||||
|
@ -288,10 +285,10 @@ public:
|
|||
+ Audit_formatter::thd_offsets.sec_ctx_ip);
|
||||
}
|
||||
|
||||
static inline const char * thd_inst_main_security_ctx_priv_user(THD * thd)
|
||||
static inline const char *thd_inst_main_security_ctx_priv_user(THD *thd)
|
||||
{
|
||||
Security_context * sctx = thd_inst_main_security_ctx(thd);
|
||||
if(!Audit_formatter::thd_offsets.sec_ctx_priv_user) //no offsets use compiled in header
|
||||
Security_context *sctx = thd_inst_main_security_ctx(thd);
|
||||
if (! Audit_formatter::thd_offsets.sec_ctx_priv_user) // no offsets use compiled in header
|
||||
{
|
||||
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
|
||||
return sctx->priv_user;
|
||||
|
@ -300,53 +297,50 @@ public:
|
|||
#endif
|
||||
}
|
||||
#if MYSQL_VERSION_ID < 50505
|
||||
//in 5.1.x priv_user is a pointer
|
||||
// in 5.1.x priv_user is a pointer
|
||||
return *(const char **) (((unsigned char *) sctx)
|
||||
+ Audit_formatter::thd_offsets.sec_ctx_priv_user);
|
||||
#else
|
||||
//in 5.5 and up priv_user is an array (char priv_user[USERNAME_LENGTH])
|
||||
// in 5.5 and up priv_user is an array (char priv_user[USERNAME_LENGTH])
|
||||
return (const char *) (((unsigned char *) sctx)
|
||||
+ Audit_formatter::thd_offsets.sec_ctx_priv_user);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int thd_inst_command(THD * thd)
|
||||
static inline int thd_inst_command(THD *thd)
|
||||
{
|
||||
return *(int *) (((unsigned char *) thd) + Audit_formatter::thd_offsets.command);
|
||||
}
|
||||
|
||||
static inline LEX* thd_lex(THD * thd)
|
||||
static inline LEX *thd_lex(THD *thd)
|
||||
{
|
||||
return *(LEX**) (((unsigned char *) thd) + Audit_formatter::thd_offsets.lex);
|
||||
return *(LEX **) (((unsigned char *) thd) + Audit_formatter::thd_offsets.lex);
|
||||
}
|
||||
|
||||
//we don't use get_db_name() as when we call it view may be not null and it may return an invalid value for view_db
|
||||
static inline const char * table_get_db_name(TABLE_LIST * table)
|
||||
// we don't use get_db_name() as when we call it view may be not null and it may return an invalid value for view_db
|
||||
static inline const char *table_get_db_name(TABLE_LIST *table)
|
||||
{
|
||||
return table->db;
|
||||
}
|
||||
|
||||
static inline const char * table_get_name(TABLE_LIST * table)
|
||||
static inline const char *table_get_name(TABLE_LIST *table)
|
||||
{
|
||||
return table->table_name;
|
||||
}
|
||||
|
||||
static inline bool table_is_view(TABLE_LIST * table)
|
||||
static inline bool table_is_view(TABLE_LIST *table)
|
||||
{
|
||||
return table->view_tables != 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Format the audit even in json format
|
||||
*/
|
||||
class Audit_json_formatter: public Audit_formatter
|
||||
{
|
||||
class Audit_json_formatter: public Audit_formatter {
|
||||
public:
|
||||
|
||||
static const char * DEF_MSG_DELIMITER;
|
||||
static const char *DEF_MSG_DELIMITER;
|
||||
|
||||
Audit_json_formatter(): m_msg_delimiter(NULL), m_write_start_msg(true), m_password_mask_regex_preg(NULL),
|
||||
m_password_mask_regex_compiled(false), m_perform_password_masking(NULL)
|
||||
|
@ -354,9 +348,10 @@ public:
|
|||
config.beautify = 0;
|
||||
config.indentString = NULL;
|
||||
}
|
||||
|
||||
virtual ~Audit_json_formatter()
|
||||
{
|
||||
if(m_password_mask_regex_preg)
|
||||
if (m_password_mask_regex_preg)
|
||||
{
|
||||
m_password_mask_regex_compiled = false;
|
||||
pcre_free(m_password_mask_regex_preg);
|
||||
|
@ -364,20 +359,20 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
virtual ssize_t event_format(ThdSesData *pThdData, IWriter * writer);
|
||||
virtual ssize_t start_msg_format(IWriter * writer);
|
||||
virtual ssize_t event_format(ThdSesData *pThdData, IWriter *writer);
|
||||
virtual ssize_t start_msg_format(IWriter *writer);
|
||||
|
||||
/**
|
||||
* Utility method used to compile a regex program. Will compile and log errors if necessary.
|
||||
* Return null if fails
|
||||
*/
|
||||
static pcre * regex_compile(const char * str);
|
||||
static pcre *regex_compile(const char *str);
|
||||
|
||||
/**
|
||||
* Compile password masking regex
|
||||
* Return 0 on success
|
||||
* Return true on success
|
||||
*/
|
||||
int compile_password_masking_regex(const char * str);
|
||||
bool compile_password_masking_regex(const char *str);
|
||||
|
||||
/**
|
||||
* Boolean indicating if to log start msg.
|
||||
|
@ -389,7 +384,7 @@ public:
|
|||
/**
|
||||
* Callback function to determine if password masking should be performed
|
||||
*/
|
||||
my_bool (* m_perform_password_masking)(const char *cmd);
|
||||
my_bool (*m_perform_password_masking)(const char *cmd);
|
||||
|
||||
/**
|
||||
* Message delimiter. Should point to a valid json string (supporting the json escapping format).
|
||||
|
@ -397,7 +392,7 @@ public:
|
|||
*
|
||||
* We only support a delimiter up to 32 chars
|
||||
*/
|
||||
char * m_msg_delimiter;
|
||||
char *m_msg_delimiter;
|
||||
|
||||
/**
|
||||
* Configuration of yajl. Leave public so sysvar can update this directly.
|
||||
|
@ -417,24 +412,19 @@ protected:
|
|||
/**
|
||||
* Regex used for password masking
|
||||
*/
|
||||
pcre * m_password_mask_regex_preg;
|
||||
|
||||
pcre *m_password_mask_regex_preg;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for audit handlers. Provides basic locking setup.
|
||||
*/
|
||||
class Audit_handler
|
||||
{
|
||||
class Audit_handler {
|
||||
public:
|
||||
|
||||
|
||||
|
||||
static const size_t MAX_AUDIT_HANDLERS_NUM = 4;
|
||||
static const size_t JSON_FILE_HANDLER = 1;
|
||||
static const size_t JSON_SOCKET_HANDLER = 3;
|
||||
|
||||
static Audit_handler * m_audit_handler_list[];
|
||||
static Audit_handler *m_audit_handler_list[];
|
||||
|
||||
/**
|
||||
* Will iterate the handler list and log using each handler
|
||||
|
@ -447,7 +437,8 @@ public:
|
|||
static void stop_all();
|
||||
|
||||
Audit_handler() :
|
||||
m_initialized(false), m_enabled(false), m_print_offset_err(true), m_formatter(NULL), m_failed(false), m_log_io_errors(true)
|
||||
m_initialized(false), m_enabled(false), m_print_offset_err(true),
|
||||
m_formatter(NULL), m_failed(false), m_log_io_errors(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -467,7 +458,7 @@ public:
|
|||
* @frmt the formatter to use in this handler (does not manage distruction of this object)
|
||||
* @return 0 on success
|
||||
*/
|
||||
int init(Audit_formatter * frmt)
|
||||
int init(Audit_formatter *frmt)
|
||||
{
|
||||
m_formatter = frmt;
|
||||
if (m_initialized)
|
||||
|
@ -516,9 +507,9 @@ public:
|
|||
unsigned int m_retry_interval;
|
||||
|
||||
protected:
|
||||
Audit_formatter * m_formatter;
|
||||
Audit_formatter *m_formatter;
|
||||
virtual void handler_start();
|
||||
//wiil call internal method and set failed as needed
|
||||
// wiil call internal method and set failed as needed
|
||||
bool handler_start_nolock();
|
||||
virtual void handler_stop();
|
||||
virtual bool handler_start_internal() = 0;
|
||||
|
@ -540,15 +531,15 @@ protected:
|
|||
return m_failed && (m_retry_interval < 0 ||
|
||||
difftime(time(NULL), m_last_retry_sec_ts) > m_retry_interval);
|
||||
}
|
||||
//override default assignment and copy to protect against creating additional instances
|
||||
// override default assignment and copy to protect against creating additional instances
|
||||
Audit_handler & operator=(const Audit_handler&);
|
||||
Audit_handler(const Audit_handler&);
|
||||
private:
|
||||
//bool indicating if to print offset errors to log or not
|
||||
// bool indicating if to print offset errors to log or not
|
||||
bool m_print_offset_err;
|
||||
//lock io
|
||||
// lock io
|
||||
pthread_mutex_t LOCK_io;
|
||||
//audit (enable) lock
|
||||
// audit (enable) lock
|
||||
rw_lock_t LOCK_audit;
|
||||
inline void lock_shared()
|
||||
{
|
||||
|
@ -567,10 +558,10 @@ private:
|
|||
/**
|
||||
* Base class for handler which have io and need a lock
|
||||
*/
|
||||
class Audit_io_handler: public Audit_handler, public IWriter
|
||||
{
|
||||
class Audit_io_handler: public Audit_handler, public IWriter {
|
||||
public:
|
||||
Audit_io_handler() : m_io_dest(NULL), m_io_type(NULL)
|
||||
Audit_io_handler()
|
||||
: m_io_dest(NULL), m_io_type(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -582,17 +573,16 @@ public:
|
|||
/**
|
||||
* target we write to (socket/file). Public so we update via sysvar
|
||||
*/
|
||||
char * m_io_dest;
|
||||
char *m_io_dest;
|
||||
|
||||
protected:
|
||||
virtual bool handler_start_internal();
|
||||
virtual void handler_stop_internal();
|
||||
//used for logging messages
|
||||
const char * m_io_type;
|
||||
// used for logging messages
|
||||
const char *m_io_type;
|
||||
};
|
||||
|
||||
class Audit_file_handler: public Audit_io_handler
|
||||
{
|
||||
class Audit_file_handler: public Audit_io_handler {
|
||||
public:
|
||||
|
||||
Audit_file_handler() :
|
||||
|
@ -621,32 +611,27 @@ public:
|
|||
/**
|
||||
* Write function we pass to formatter
|
||||
*/
|
||||
ssize_t write(const char * data, size_t size);
|
||||
ssize_t write(const char *data, size_t size);
|
||||
|
||||
void close();
|
||||
|
||||
int open(const char * io_dest, bool m_log_errors);
|
||||
//static void print_sleep (THD *thd, int delay_ms);
|
||||
int open(const char *io_dest, bool m_log_errors);
|
||||
// static void print_sleep(THD *thd, int delay_ms);
|
||||
protected:
|
||||
//override default assignment and copy to protect against creating additional instances
|
||||
// override default assignment and copy to protect against creating additional instances
|
||||
Audit_file_handler & operator=(const Audit_file_handler&);
|
||||
Audit_file_handler(const Audit_file_handler&);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Will acquire locks and call handler_write
|
||||
*/
|
||||
virtual bool handler_log_audit(ThdSesData *pThdData);
|
||||
FILE * m_log_file;
|
||||
//the period to use for syncing
|
||||
FILE *m_log_file;
|
||||
// the period to use for syncing
|
||||
unsigned int m_sync_counter;
|
||||
|
||||
|
||||
};
|
||||
|
||||
class Audit_socket_handler: public Audit_io_handler
|
||||
{
|
||||
class Audit_socket_handler: public Audit_io_handler {
|
||||
public:
|
||||
|
||||
Audit_socket_handler() :
|
||||
|
@ -668,13 +653,13 @@ public:
|
|||
/**
|
||||
* Write function we pass to formatter
|
||||
*/
|
||||
ssize_t write(const char * data, size_t size);
|
||||
ssize_t write(const char *data, size_t size);
|
||||
|
||||
void close();
|
||||
|
||||
int open(const char * io_dest, bool log_errors);
|
||||
int open(const char *io_dest, bool log_errors);
|
||||
protected:
|
||||
//override default assignment and copy to protect against creating additional instances
|
||||
// override default assignment and copy to protect against creating additional instances
|
||||
Audit_socket_handler & operator=(const Audit_socket_handler&);
|
||||
Audit_socket_handler(const Audit_socket_handler&);
|
||||
|
||||
|
@ -682,10 +667,9 @@ protected:
|
|||
* Will acquire locks and call handler_write
|
||||
*/
|
||||
virtual bool handler_log_audit(ThdSesData *pThdData);
|
||||
//Vio we write to
|
||||
//define as void* so we don't access members directly
|
||||
void * m_vio;
|
||||
// Vio we write to
|
||||
// define as void* so we don't access members directly
|
||||
void *m_vio;
|
||||
};
|
||||
|
||||
#endif /* AUDIT_HANDLER_H_ */
|
||||
|
||||
|
|
|
@ -43,13 +43,13 @@ extern void MD5_Init(MD5_CTX *ctx);
|
|||
extern void MD5_Update(MD5_CTX *ctx, void *data, unsigned long size);
|
||||
extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);
|
||||
|
||||
//define the my_MD5* functions
|
||||
// define the my_MD5* functions
|
||||
#define my_MD5Context MD5_CTX
|
||||
#define my_MD5Init MD5_Init
|
||||
#define my_MD5Update MD5_Update
|
||||
#define my_MD5Final MD5_Final
|
||||
|
||||
|
||||
#endif //#if MYSQL_VERSION_ID >= 50600
|
||||
#endif // #if MYSQL_VERSION_ID >= 50600
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
#define MYSQL_DYNAMIC_PLUGIN 1
|
||||
#define MYSQL_SERVER 1
|
||||
|
||||
//Fix for VIO. We don't want to using method mapping as then a change in the struct will cause the offsets compiled with to
|
||||
//be wrong. As is the case with ndb which uses a version of Vio with support for ipv6 similar to 5.5 but different from 5.1
|
||||
// Fix for VIO. We don't want to using method mapping as then a change in the struct will cause the offsets compiled with to
|
||||
// be wrong. As is the case with ndb which uses a version of Vio with support for ipv6 similar to 5.5 but different from 5.1
|
||||
#define DONT_MAP_VIO
|
||||
|
||||
#include <my_config.h>
|
||||
|
@ -19,7 +19,7 @@
|
|||
#include <mysql_priv.h>
|
||||
#else
|
||||
|
||||
//version 5.5.x doesn't contain mysql_priv.h . We need to add the includes provided by it.
|
||||
// version 5.5.x doesn't contain mysql_priv.h . We need to add the includes provided by it.
|
||||
#if MYSQL_VERSION_ID >= 50505
|
||||
|
||||
// These two are not present in 5.7.9
|
||||
|
@ -43,7 +43,7 @@
|
|||
#include <sql/sql_table.h>
|
||||
#include <sql/sql_view.h>
|
||||
|
||||
//TODO: use mysql mutex instead of pthread
|
||||
// TODO: use mysql mutex instead of pthread
|
||||
/*
|
||||
#define pthread_mutex_lock mysql_mutex_lock
|
||||
#define pthread_mutex_unlock mysql_mutex_unlock
|
||||
|
@ -67,8 +67,8 @@
|
|||
#include <my_dir.h>
|
||||
#include <my_sys.h>
|
||||
|
||||
//5.5 use my_free with a single param. 5.1 use with 2 params
|
||||
//based on: http://bazaar.launchpad.net/~mysql/myodbc/5.1/view/head:/util/stringutil.h
|
||||
// 5.5 use my_free with a single param. 5.1 use with 2 params
|
||||
// based on: http://bazaar.launchpad.net/~mysql/myodbc/5.1/view/head:/util/stringutil.h
|
||||
#ifndef x_free
|
||||
# if MYSQL_VERSION_ID >= 50500
|
||||
# define x_free(A) { void *tmp= (A); if (tmp) my_free((char *) tmp); }
|
||||
|
@ -77,23 +77,19 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
//MariaDB doesn't have my_getsystime (returns 100 nano seconds) function. They replaced with my_hrtime_t my_hrtime() which returns microseconds
|
||||
// MariaDB doesn't have my_getsystime (returns 100 nano seconds) function. They replaced with my_hrtime_t my_hrtime() which returns microseconds
|
||||
#if defined(MARIADB_BASE_VERSION)
|
||||
|
||||
#define my_getsystime() ((my_hrtime()).val * 10)
|
||||
//MariaDB has a kill service that overrides thd_killed as a macro. It also has thd_killed function defined for backwards compatibility, so we redefine it.
|
||||
// MariaDB has a kill service that overrides thd_killed as a macro. It also has thd_killed function defined for backwards compatibility, so we redefine it.
|
||||
#undef thd_killed
|
||||
extern "C" int thd_killed(const MYSQL_THD thd);
|
||||
|
||||
//MariadDB 10.0.10 removed the include for thd_security_context
|
||||
// MariadDB 10.0.10 removed the include for thd_security_context
|
||||
#if MYSQL_VERSION_ID >= 100010
|
||||
extern "C" char *thd_security_context(MYSQL_THD thd, char *buffer, unsigned int length, unsigned int max_query_len);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif //MYSQL_INCL_H
|
||||
|
||||
|
||||
#endif // MYSQL_INCL_H
|
||||
|
|
|
@ -18,16 +18,17 @@
|
|||
* Created on: Feb 6, 2011
|
||||
* Author: guyl
|
||||
*/
|
||||
|
||||
#include "audit_handler.h"
|
||||
//for definition of sockaddr_un
|
||||
// for definition of sockaddr_un
|
||||
#include <sys/un.h>
|
||||
#include <stdio_ext.h>
|
||||
#include "static_assert.h"
|
||||
|
||||
//utility macro to log also with a date as a prefix
|
||||
#define log_with_date(f, ...) do{\
|
||||
// utility macro to log also with a date as a prefix
|
||||
#define log_with_date(f, ...) do {\
|
||||
struct tm tm_tmp;\
|
||||
time_t result= time(NULL);\
|
||||
time_t result = time(NULL);\
|
||||
localtime_r(&result, &tm_tmp);\
|
||||
fprintf(f, "%02d%02d%02d %2d:%02d:%02d: ",\
|
||||
tm_tmp.tm_year % 100,\
|
||||
|
@ -37,23 +38,21 @@
|
|||
tm_tmp.tm_min,\
|
||||
tm_tmp.tm_sec);\
|
||||
fprintf(f, __VA_ARGS__);\
|
||||
}while(0)
|
||||
} while (0)
|
||||
|
||||
//regex flags used in compilation
|
||||
// regex flags used in compilation
|
||||
static const int regex_flags = PCRE_DOTALL | PCRE_UTF8 | PCRE_CASELESS | PCRE_DUPNAMES;
|
||||
|
||||
|
||||
//initialize static stuff
|
||||
// initialize static stuff
|
||||
ThdOffsets Audit_formatter::thd_offsets = { 0 };
|
||||
Audit_handler * Audit_handler::m_audit_handler_list[Audit_handler::MAX_AUDIT_HANDLERS_NUM];
|
||||
Audit_handler *Audit_handler::m_audit_handler_list[Audit_handler::MAX_AUDIT_HANDLERS_NUM];
|
||||
const char * Audit_json_formatter::DEF_MSG_DELIMITER = "\\n";
|
||||
|
||||
#if MYSQL_VERSION_ID < 50709
|
||||
#define C_STRING_WITH_LEN(X) ((char *) (X)), ((size_t) (sizeof(X) - 1))
|
||||
#endif
|
||||
|
||||
|
||||
const char * Audit_formatter::retrieve_object_type (TABLE_LIST *pObj)
|
||||
const char *Audit_formatter::retrieve_object_type(TABLE_LIST *pObj)
|
||||
{
|
||||
if (table_is_view(pObj))
|
||||
{
|
||||
|
@ -62,7 +61,6 @@ const char * Audit_formatter::retrieve_object_type (TABLE_LIST *pObj)
|
|||
return "TABLE";
|
||||
}
|
||||
|
||||
|
||||
void Audit_handler::stop_all()
|
||||
{
|
||||
for (size_t i = 0; i < MAX_AUDIT_HANDLERS_NUM; ++i)
|
||||
|
@ -88,7 +86,7 @@ void Audit_handler::log_audit_all(ThdSesData *pThdData)
|
|||
void Audit_handler::set_enable(bool val)
|
||||
{
|
||||
lock_exclusive();
|
||||
if (m_enabled == val) //we are already enabled simply return
|
||||
if (m_enabled == val) // we are already enabled simply return
|
||||
{
|
||||
unlock();
|
||||
return;
|
||||
|
@ -96,12 +94,12 @@ void Audit_handler::set_enable(bool val)
|
|||
m_enabled = val;
|
||||
if (m_enabled)
|
||||
{
|
||||
//call the startup of the handler
|
||||
// call the startup of the handler
|
||||
handler_start();
|
||||
}
|
||||
else
|
||||
{
|
||||
//call the cleanup of the handler
|
||||
// call the cleanup of the handler
|
||||
handler_stop();
|
||||
}
|
||||
unlock();
|
||||
|
@ -110,14 +108,14 @@ void Audit_handler::set_enable(bool val)
|
|||
void Audit_handler::flush()
|
||||
{
|
||||
lock_exclusive();
|
||||
if (!m_enabled) //if not running we don't flush
|
||||
if (! m_enabled) // if not running we don't flush
|
||||
{
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
//call the cleanup of the handler
|
||||
// call the cleanup of the handler
|
||||
handler_stop();
|
||||
//call the startup of the handler
|
||||
// call the startup of the handler
|
||||
handler_start();
|
||||
sql_print_information("%s Log flush complete.", AUDIT_LOG_PREFIX);
|
||||
unlock();
|
||||
|
@ -126,13 +124,13 @@ void Audit_handler::flush()
|
|||
void Audit_handler::log_audit(ThdSesData *pThdData)
|
||||
{
|
||||
lock_shared();
|
||||
if (!m_enabled)
|
||||
if (! m_enabled)
|
||||
{
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
//sanity check that offsets match
|
||||
//we can also consider using secutiry context function to do some sanity checks
|
||||
// sanity check that offsets match
|
||||
// we can also consider using secutiry context function to do some sanity checks
|
||||
// char buffer[2048];
|
||||
// thd_security_context(thd, buffer, 2048, 2000);
|
||||
// fprintf(log_file, "info from security context: %s\n", buffer);
|
||||
|
@ -149,24 +147,25 @@ void Audit_handler::log_audit(ThdSesData *pThdData)
|
|||
}
|
||||
}
|
||||
else
|
||||
{//offsets are good
|
||||
m_print_offset_err = true; //mark to print offset err to log incase we encounter in the future
|
||||
{
|
||||
// offsets are good
|
||||
m_print_offset_err = true; // mark to print offset err to log in case we encounter in the future
|
||||
pthread_mutex_lock(&LOCK_io);
|
||||
//check if failed
|
||||
// check if failed
|
||||
bool do_log = true;
|
||||
if (m_failed)
|
||||
{
|
||||
do_log = false;
|
||||
bool retry = m_retry_interval > 0 &&
|
||||
difftime(time(NULL), m_last_retry_sec_ts) > m_retry_interval;
|
||||
if(retry)
|
||||
if (retry)
|
||||
{
|
||||
do_log = handler_start_nolock();
|
||||
}
|
||||
}
|
||||
if(do_log)
|
||||
if (do_log)
|
||||
{
|
||||
if(!handler_log_audit(pThdData))
|
||||
if (! handler_log_audit(pThdData))
|
||||
{
|
||||
set_failed();
|
||||
handler_stop_internal();
|
||||
|
@ -186,10 +185,10 @@ void Audit_file_handler::close()
|
|||
m_log_file = NULL;
|
||||
}
|
||||
|
||||
ssize_t Audit_file_handler::write(const char * data, size_t size)
|
||||
ssize_t Audit_file_handler::write(const char *data, size_t size)
|
||||
{
|
||||
ssize_t res = my_fwrite(m_log_file, (uchar *) data, size, MYF(0));
|
||||
if(res < 0) // log the error
|
||||
if (res < 0) // log the error
|
||||
{
|
||||
sql_print_error("%s failed writing to file: %s. Err: %s",
|
||||
AUDIT_LOG_PREFIX, m_io_dest, strerror(errno));
|
||||
|
@ -197,14 +196,15 @@ ssize_t Audit_file_handler::write(const char * data, size_t size)
|
|||
return res;
|
||||
}
|
||||
|
||||
int Audit_file_handler::open(const char * io_dest, bool log_errors)
|
||||
int Audit_file_handler::open(const char *io_dest, bool log_errors)
|
||||
{
|
||||
char format_name[FN_REFLEN];
|
||||
|
||||
fn_format(format_name, io_dest, "", "", MY_UNPACK_FILENAME);
|
||||
m_log_file = my_fopen(format_name, O_WRONLY | O_APPEND| O_CREAT, MYF(0));
|
||||
if (!m_log_file)
|
||||
if (! m_log_file)
|
||||
{
|
||||
if(log_errors)
|
||||
if (log_errors)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s unable to open file %s: %s. audit file handler disabled!!",
|
||||
|
@ -212,16 +212,18 @@ int Audit_file_handler::open(const char * io_dest, bool log_errors)
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t bufsize = BUFSIZ;
|
||||
int res =0;
|
||||
//0 -> use default, 1 or negative -> disabled
|
||||
if(m_bufsize > 1)
|
||||
int res = 0;
|
||||
// 0 -> use default, 1 or negative -> disabled
|
||||
if (m_bufsize > 1)
|
||||
{
|
||||
bufsize = m_bufsize;
|
||||
}
|
||||
if(1 == m_bufsize || m_bufsize < 0)
|
||||
|
||||
if (1 == m_bufsize || m_bufsize < 0)
|
||||
{
|
||||
//disabled
|
||||
// disabled
|
||||
res = setvbuf(m_log_file, NULL, _IONBF, 0);
|
||||
}
|
||||
else
|
||||
|
@ -229,7 +231,8 @@ int Audit_file_handler::open(const char * io_dest, bool log_errors)
|
|||
res = setvbuf(m_log_file, NULL, _IOFBF, bufsize);
|
||||
|
||||
}
|
||||
if(res)
|
||||
|
||||
if (res)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s unable to set bufzie [%zd (%ld)] for file %s: %s.",
|
||||
|
@ -240,12 +243,12 @@ int Audit_file_handler::open(const char * io_dest, bool log_errors)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//no locks. called by handler_start and when it is time to retry
|
||||
// no locks. called by handler_start and when it is time to retry
|
||||
bool Audit_io_handler::handler_start_internal()
|
||||
{
|
||||
if(!m_io_dest || strlen(m_io_dest) == 0)
|
||||
if (! m_io_dest || strlen(m_io_dest) == 0)
|
||||
{
|
||||
if(m_log_io_errors)
|
||||
if (m_log_io_errors)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s %s: io destination not set. Not connecting.",
|
||||
|
@ -255,16 +258,16 @@ bool Audit_io_handler::handler_start_internal()
|
|||
}
|
||||
if (open(m_io_dest, m_log_io_errors) != 0)
|
||||
{
|
||||
//open failed
|
||||
// open failed
|
||||
return false;
|
||||
}
|
||||
ssize_t res = m_formatter->start_msg_format(this);
|
||||
/*
|
||||
sanity check of writing to the log. If we fail. We will print an erorr and disable this handler.
|
||||
* Sanity check of writing to the log. If we fail, we print an erorr and disable this handler.
|
||||
*/
|
||||
if (res < 0)
|
||||
{
|
||||
if(m_log_io_errors)
|
||||
if (m_log_io_errors)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s unable to write header msg to %s: %s.",
|
||||
|
@ -279,7 +282,7 @@ bool Audit_io_handler::handler_start_internal()
|
|||
|
||||
void Audit_io_handler::handler_stop_internal()
|
||||
{
|
||||
if(!m_failed)
|
||||
if (! m_failed)
|
||||
{
|
||||
m_formatter->stop_msg_format(this);
|
||||
}
|
||||
|
@ -289,7 +292,7 @@ void Audit_io_handler::handler_stop_internal()
|
|||
bool Audit_handler::handler_start_nolock()
|
||||
{
|
||||
bool res = handler_start_internal();
|
||||
if(res)
|
||||
if (res)
|
||||
{
|
||||
m_failed = false;
|
||||
}
|
||||
|
@ -307,6 +310,7 @@ void Audit_handler::handler_start()
|
|||
handler_start_nolock();
|
||||
pthread_mutex_unlock(&LOCK_io);
|
||||
}
|
||||
|
||||
void Audit_handler::handler_stop()
|
||||
{
|
||||
pthread_mutex_lock(&LOCK_io);
|
||||
|
@ -320,11 +324,11 @@ bool Audit_file_handler::handler_log_audit(ThdSesData *pThdData)
|
|||
if (res && m_sync_period && ++m_sync_counter >= m_sync_period)
|
||||
{
|
||||
m_sync_counter = 0;
|
||||
//Note fflush() only flushes the user space buffers provided by the C library.
|
||||
//To ensure that the data is physically stored on disk the kernel buffers must be flushed too,
|
||||
//e.g. with sync(2) or fsync(2).
|
||||
// Note fflush() only flushes the user space buffers provided by the C library.
|
||||
// To ensure that the data is physically stored on disk the kernel buffers must be flushed too,
|
||||
// e.g. with sync(2) or fsync(2).
|
||||
res = (fflush(m_log_file) == 0);
|
||||
if(res)
|
||||
if (res)
|
||||
{
|
||||
int fd = fileno(m_log_file);
|
||||
res = (my_sync(fd, MYF(MY_WME)) == 0);
|
||||
|
@ -339,16 +343,16 @@ void Audit_socket_handler::close()
|
|||
{
|
||||
if (m_vio)
|
||||
{
|
||||
//no need for vio_close as is called by delete (additionally close changed its name to vio_shutdown in 5.6.11)
|
||||
// no need for vio_close as is called by delete (additionally close changed its name to vio_shutdown in 5.6.11)
|
||||
vio_delete((Vio*)m_vio);
|
||||
}
|
||||
m_vio = NULL;
|
||||
}
|
||||
|
||||
ssize_t Audit_socket_handler::write(const char * data, size_t size)
|
||||
ssize_t Audit_socket_handler::write(const char *data, size_t size)
|
||||
{
|
||||
ssize_t res = vio_write((Vio*)m_vio, (const uchar *) data, size);
|
||||
if(res < 0) // log the error
|
||||
if (res < 0) // log the error
|
||||
{
|
||||
sql_print_error("%s failed writing to socket: %s. Err: %s",
|
||||
AUDIT_LOG_PREFIX, m_io_dest, strerror(vio_errno((Vio*)m_vio)));
|
||||
|
@ -356,13 +360,13 @@ ssize_t Audit_socket_handler::write(const char * data, size_t size)
|
|||
return res;
|
||||
}
|
||||
|
||||
int Audit_socket_handler::open(const char * io_dest, bool log_errors)
|
||||
int Audit_socket_handler::open(const char *io_dest, bool log_errors)
|
||||
{
|
||||
//open the socket
|
||||
int sock = socket(AF_UNIX,SOCK_STREAM,0);
|
||||
// open the socket
|
||||
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock < 0)
|
||||
{
|
||||
if(log_errors)
|
||||
if (log_errors)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s unable to create unix socket: %s.",
|
||||
|
@ -371,8 +375,8 @@ int Audit_socket_handler::open(const char * io_dest, bool log_errors)
|
|||
return -1;
|
||||
}
|
||||
|
||||
//connect the socket
|
||||
m_vio= vio_new(sock, VIO_TYPE_SOCKET, VIO_LOCALHOST);
|
||||
// connect the socket
|
||||
m_vio = vio_new(sock, VIO_TYPE_SOCKET, VIO_LOCALHOST);
|
||||
struct sockaddr_un UNIXaddr;
|
||||
UNIXaddr.sun_family = AF_UNIX;
|
||||
strmake(UNIXaddr.sun_path, io_dest, sizeof(UNIXaddr.sun_path)-1);
|
||||
|
@ -380,12 +384,12 @@ int Audit_socket_handler::open(const char * io_dest, bool log_errors)
|
|||
if (my_connect(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
|
||||
m_connect_timeout))
|
||||
#else
|
||||
//in 5.6 timeout is in ms
|
||||
// in 5.6 timeout is in ms
|
||||
if (vio_socket_connect((Vio*)m_vio,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
|
||||
m_connect_timeout * 1000))
|
||||
#endif
|
||||
{
|
||||
if(log_errors)
|
||||
if (log_errors)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s unable to connect to socket: %s. err: %s.",
|
||||
|
@ -406,38 +410,38 @@ bool Audit_socket_handler::handler_log_audit(ThdSesData *pThdData)
|
|||
|
||||
|
||||
|
||||
|
||||
static yajl_gen_status yajl_add_string(yajl_gen hand, const char * str)
|
||||
static yajl_gen_status yajl_add_string(yajl_gen hand, const char *str)
|
||||
{
|
||||
return yajl_gen_string(hand, (const unsigned char*)str, strlen(str));
|
||||
return yajl_gen_string(hand, (const unsigned char *) str, strlen(str));
|
||||
}
|
||||
|
||||
static void yajl_add_string_val(yajl_gen hand, const char * name, const char* val)
|
||||
static void yajl_add_string_val(yajl_gen hand, const char *name, const char *val)
|
||||
{
|
||||
if(0 == val)
|
||||
if (0 == val)
|
||||
{
|
||||
return; //we don't add NULL values to json
|
||||
return; // we don't add NULL values to json
|
||||
}
|
||||
yajl_add_string(hand, name);
|
||||
yajl_add_string(hand, val);
|
||||
}
|
||||
|
||||
static void yajl_add_string_val(yajl_gen hand, const char * name, const char* val, size_t val_len)
|
||||
static void yajl_add_string_val(yajl_gen hand, const char *name, const char *val, size_t val_len)
|
||||
{
|
||||
yajl_add_string(hand, name);
|
||||
yajl_gen_string(hand, (const unsigned char*)val, val_len);
|
||||
}
|
||||
|
||||
static void yajl_add_uint64(yajl_gen gen, const char * name, uint64 num)
|
||||
static void yajl_add_uint64(yajl_gen gen, const char *name, uint64 num)
|
||||
{
|
||||
const size_t max_int64_str_len = 21;
|
||||
char buf[max_int64_str_len];
|
||||
snprintf(buf, max_int64_str_len, "%llu", num);
|
||||
yajl_add_string_val(gen, name, buf);
|
||||
}
|
||||
static void yajl_add_obj( yajl_gen gen, const char *db,const char* ptype,const char * name =NULL)
|
||||
|
||||
static void yajl_add_obj(yajl_gen gen, const char *db, const char *ptype, const char *name = NULL)
|
||||
{
|
||||
if(db)
|
||||
if (db)
|
||||
{
|
||||
yajl_add_string_val(gen, "db", db);
|
||||
}
|
||||
|
@ -445,37 +449,36 @@ static void yajl_add_obj( yajl_gen gen, const char *db,const char* ptype,const
|
|||
{
|
||||
yajl_add_string_val(gen, "name", name);
|
||||
}
|
||||
yajl_add_string_val(gen, "obj_type",ptype);
|
||||
yajl_add_string_val(gen, "obj_type", ptype);
|
||||
}
|
||||
|
||||
static const char * retrieve_user (THD * thd)
|
||||
static const char *retrieve_user(THD *thd)
|
||||
{
|
||||
|
||||
const char * user = Audit_formatter::thd_inst_main_security_ctx_user(thd);
|
||||
if(user != NULL && *user != 0x0) //non empty
|
||||
const char *user = Audit_formatter::thd_inst_main_security_ctx_user(thd);
|
||||
if (user != NULL && *user != '\0') // non empty
|
||||
{
|
||||
return user;
|
||||
}
|
||||
user = Audit_formatter::thd_inst_main_security_ctx_priv_user(thd); //try using priv user
|
||||
if(user != NULL && *user != 0x0) //non empty
|
||||
user = Audit_formatter::thd_inst_main_security_ctx_priv_user(thd); // try using priv user
|
||||
if (user != NULL && *user != '\0') // non empty
|
||||
{
|
||||
return user;
|
||||
}
|
||||
return ""; //always use at least the empty string
|
||||
return ""; // always use at least the empty string
|
||||
}
|
||||
|
||||
|
||||
//will return a pointer to the query and set len with the length of the query
|
||||
//starting with MySQL version 5.1.41 thd_query_string is added
|
||||
//And at 5.7 it changed
|
||||
// will return a pointer to the query and set len with the length of the query
|
||||
// starting with MySQL version 5.1.41 thd_query_string is added
|
||||
// And at 5.7 it changed
|
||||
#if ! defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709
|
||||
|
||||
extern "C" LEX_CSTRING thd_query_unsafe(MYSQL_THD thd);
|
||||
|
||||
static const char * thd_query_str(THD * thd, size_t * len)
|
||||
static const char *thd_query_str(THD *thd, size_t *len)
|
||||
{
|
||||
const LEX_CSTRING str = thd_query_unsafe(thd);
|
||||
if(str.length > 0)
|
||||
if (str.length > 0)
|
||||
{
|
||||
*len = str.length;
|
||||
return str.str;
|
||||
|
@ -489,10 +492,11 @@ static const char * thd_query_str(THD * thd, size_t * len)
|
|||
extern "C" {
|
||||
MYSQL_LEX_STRING *thd_query_string(MYSQL_THD thd);
|
||||
}
|
||||
static const char * thd_query_str(THD * thd, size_t * len)
|
||||
|
||||
static const char *thd_query_str(THD *thd, size_t *len)
|
||||
{
|
||||
MYSQL_LEX_STRING * str = thd_query_string(thd);
|
||||
if(str)
|
||||
if (str)
|
||||
{
|
||||
*len = str->length;
|
||||
return str->str;
|
||||
|
@ -501,21 +505,22 @@ static const char * thd_query_str(THD * thd, size_t * len)
|
|||
return NULL;
|
||||
}
|
||||
#else
|
||||
//we are being compiled against mysql version 5.1.40 or lower (our default compilation env)
|
||||
//we still want to support thd_query_string if we are run on a version higher than 5.1.40, so we try to lookup the symbol
|
||||
// we are being compiled against mysql version 5.1.40 or lower (our default compilation env)
|
||||
// we still want to support thd_query_string if we are run on a version higher than 5.1.40, so we try to lookup the symbol
|
||||
static LEX_STRING * (*thd_query_string_func)(THD *thd) = (LEX_STRING*(*)(THD*))dlsym(RTLD_DEFAULT, "thd_query_string");
|
||||
static bool print_thd_query_string_func = true; //debug info print only once
|
||||
static const char * thd_query_str(THD * thd, size_t * len)
|
||||
static bool print_thd_query_string_func = true; // debug info print only once
|
||||
|
||||
static const char *thd_query_str(THD *thd, size_t *len)
|
||||
{
|
||||
if(print_thd_query_string_func)
|
||||
if (print_thd_query_string_func)
|
||||
{
|
||||
sql_print_information("%s thd_query_string_func: 0x%lx", AUDIT_LOG_PREFIX, (unsigned long)thd_query_string_func);
|
||||
print_thd_query_string_func = false;
|
||||
}
|
||||
if(thd_query_string_func)
|
||||
if (thd_query_string_func)
|
||||
{
|
||||
MYSQL_LEX_STRING * str = thd_query_string_func(thd);
|
||||
if(str)
|
||||
MYSQL_LEX_STRING *str = thd_query_string_func(thd);
|
||||
if (str)
|
||||
{
|
||||
*len = str->length;
|
||||
return str->str;
|
||||
|
@ -528,13 +533,14 @@ static const char * thd_query_str(THD * thd, size_t * len)
|
|||
}
|
||||
#endif
|
||||
|
||||
ssize_t Audit_json_formatter::start_msg_format(IWriter * writer)
|
||||
ssize_t Audit_json_formatter::start_msg_format(IWriter *writer)
|
||||
{
|
||||
if(!m_write_start_msg) //disabled
|
||||
if (! m_write_start_msg) // disabled
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
//initialize yajl
|
||||
|
||||
// initialize yajl
|
||||
yajl_gen gen = yajl_gen_alloc(&config, NULL);
|
||||
yajl_gen_map_open(gen);
|
||||
yajl_add_string_val(gen, "msg-type", "header");
|
||||
|
@ -548,24 +554,24 @@ ssize_t Audit_json_formatter::start_msg_format(IWriter * writer)
|
|||
yajl_add_string_val(gen, "mysql-socket", mysqld_unix_port);
|
||||
yajl_add_uint64(gen, "mysql-port", mysqld_port);
|
||||
ssize_t res = -2;
|
||||
yajl_gen_status stat = yajl_gen_map_close(gen); //close the object
|
||||
if(stat == yajl_gen_status_ok) //all is good write the buffer out
|
||||
|
||||
yajl_gen_status stat = yajl_gen_map_close(gen); // close the object
|
||||
if (stat == yajl_gen_status_ok) // all is good write the buffer out
|
||||
{
|
||||
const unsigned char * text = NULL;
|
||||
const unsigned char *text = NULL;
|
||||
unsigned int len = 0;
|
||||
yajl_gen_get_buf(gen, &text, &len);
|
||||
//print the json
|
||||
// print the json
|
||||
res = writer->write((const char *)text, len);
|
||||
if(res >= 0)
|
||||
if (res >= 0)
|
||||
{
|
||||
//TODO: use the msg_delimiter
|
||||
// TODO: use the msg_delimiter
|
||||
res = writer->write("\n", 1);
|
||||
}
|
||||
//my_fwrite(log_file, (uchar *) b.data, json_size(&b), MYF(0));
|
||||
// my_fwrite(log_file, (uchar *) b.data, json_size(&b), MYF(0));
|
||||
}
|
||||
yajl_gen_free(gen); //free the generator
|
||||
yajl_gen_free(gen); // free the generator
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
// This routine replaces clear text with the string in `replace', leaving the rest of the string intact.
|
||||
|
@ -602,19 +608,19 @@ static const char *replace_in_string(THD *thd,
|
|||
return new_str;
|
||||
}
|
||||
|
||||
ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * writer)
|
||||
ssize_t Audit_json_formatter::event_format(ThdSesData *pThdData, IWriter *writer)
|
||||
{
|
||||
THD * thd = pThdData->getTHD();
|
||||
THD *thd = pThdData->getTHD();
|
||||
unsigned long thdid = thd_get_thread_id(thd);
|
||||
query_id_t qid = thd_inst_query_id(thd);
|
||||
|
||||
//initialize yajl
|
||||
// initialize yajl
|
||||
yajl_gen gen = yajl_gen_alloc(&config, NULL);
|
||||
yajl_gen_map_open(gen);
|
||||
yajl_add_string_val(gen, "msg-type", "activity");
|
||||
//TODO: get the start date from THD (but it is not in millis. Need to think about how we handle this)
|
||||
//for now simply use the current time.
|
||||
//my_getsystime() time since epoc in 100 nanosec units. Need to devide by 1000*(1000/100) to reach millis
|
||||
// TODO: get the start date from THD (but it is not in millis. Need to think about how we handle this)
|
||||
// for now simply use the current time.
|
||||
// my_getsystime() time since epoc in 100 nanosec units. Need to devide by 1000*(1000/100) to reach millis
|
||||
uint64 ts = my_getsystime() / (10000);
|
||||
yajl_add_uint64(gen, "date", ts);
|
||||
yajl_add_uint64(gen, "thread-id", thdid);
|
||||
|
@ -625,15 +631,16 @@ ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * write
|
|||
yajl_add_string_val(gen, "ip", Audit_formatter::thd_inst_main_security_ctx_ip(thd));
|
||||
const char *cmd = pThdData->getCmdName();
|
||||
yajl_add_string_val(gen, "cmd", cmd);
|
||||
//get objects
|
||||
if(pThdData->startGetObjects())
|
||||
|
||||
// get objects
|
||||
if (pThdData->startGetObjects())
|
||||
{
|
||||
yajl_add_string(gen, "objects");
|
||||
yajl_gen_array_open(gen);
|
||||
const char * db_name = NULL;
|
||||
const char * obj_name = NULL;
|
||||
const char * obj_type = NULL;
|
||||
while(pThdData->getNextObject(&db_name, &obj_name, &obj_type))
|
||||
const char *db_name = NULL;
|
||||
const char *obj_name = NULL;
|
||||
const char *obj_type = NULL;
|
||||
while (pThdData->getNextObject(&db_name, &obj_name, &obj_type))
|
||||
{
|
||||
yajl_gen_map_open(gen);
|
||||
yajl_add_obj (gen, db_name, obj_type, obj_name );
|
||||
|
@ -643,7 +650,7 @@ ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * write
|
|||
}
|
||||
|
||||
size_t qlen = 0;
|
||||
const char * query = thd_query_str(pThdData->getTHD(), &qlen);
|
||||
const char *query = thd_query_str(pThdData->getTHD(), &qlen);
|
||||
if (query && qlen > 0)
|
||||
{
|
||||
#if MYSQL_VERSION_ID < 50600
|
||||
|
@ -658,7 +665,8 @@ ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * write
|
|||
const char *query_text = query;
|
||||
size_t query_len = qlen;
|
||||
|
||||
if (strcmp(col_connection->csname, "utf8") != 0) {
|
||||
if (strcmp(col_connection->csname, "utf8") != 0)
|
||||
{
|
||||
// max UTF-8 bytes per char is 4.
|
||||
size_t to_amount = (qlen * 4) + 1;
|
||||
char* to = (char *) thd_alloc(thd, to_amount);
|
||||
|
@ -676,20 +684,23 @@ ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * write
|
|||
qlen = len;
|
||||
}
|
||||
|
||||
if(m_perform_password_masking && m_password_mask_regex_compiled && m_password_mask_regex_preg && m_perform_password_masking(cmd))
|
||||
if (m_perform_password_masking
|
||||
&& m_password_mask_regex_compiled
|
||||
&& m_password_mask_regex_preg
|
||||
&& m_perform_password_masking(cmd))
|
||||
{
|
||||
//do password masking
|
||||
int matches[90] = {0};
|
||||
if(pcre_exec(m_password_mask_regex_preg, NULL, query_text, query_len, 0, 0, matches, array_elements(matches)) >= 0)
|
||||
// do password masking
|
||||
int matches[90] = { 0 };
|
||||
if (pcre_exec(m_password_mask_regex_preg, NULL, query_text, query_len, 0, 0, matches, array_elements(matches)) >= 0)
|
||||
{
|
||||
//search for the first substring that matches with the name psw
|
||||
// search for the first substring that matches with the name psw
|
||||
char *first = NULL, *last = NULL;
|
||||
int entrysize = pcre_get_stringtable_entries(m_password_mask_regex_preg, "psw", &first, &last);
|
||||
if(entrysize > 0)
|
||||
if (entrysize > 0)
|
||||
{
|
||||
for (unsigned char * entry = (unsigned char *)first; entry <= (unsigned char *)last; entry += entrysize)
|
||||
for (unsigned char *entry = (unsigned char *)first; entry <= (unsigned char *)last; entry += entrysize)
|
||||
{
|
||||
//first 2 bytes give us the number
|
||||
// first 2 bytes give us the number
|
||||
int n = (((int)(entry)[0]) << 8) | (entry)[1];
|
||||
if (n > 0 && n < (int)array_elements(matches) && matches[n*2] >= 0)
|
||||
{
|
||||
|
@ -700,7 +711,12 @@ ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * write
|
|||
// interfaces in MySQL have changed fairly drastically. So we just do the
|
||||
// replacement ourselves.
|
||||
const char *pass_replace = "***";
|
||||
const char *updated = replace_in_string(thd, query_text, query_len, matches[n*2], matches[(n*2) + 1] - matches[n*2], pass_replace);
|
||||
const char *updated = replace_in_string(thd,
|
||||
query_text,
|
||||
query_len,
|
||||
matches[n*2],
|
||||
matches[(n*2) + 1] - matches[n*2],
|
||||
pass_replace);
|
||||
query_text = updated;
|
||||
query_len = strlen(query_text);
|
||||
break;
|
||||
|
@ -713,39 +729,38 @@ ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * write
|
|||
}
|
||||
else
|
||||
{
|
||||
if (cmd!=NULL && strlen (cmd)!=0)
|
||||
if (cmd != NULL && strlen(cmd) != 0)
|
||||
{
|
||||
yajl_add_string_val(gen, "query",cmd, strlen (cmd));
|
||||
yajl_add_string_val(gen, "query", cmd, strlen(cmd));
|
||||
}
|
||||
else
|
||||
{
|
||||
yajl_add_string_val(gen, "query","n/a", strlen ("n/a" ));
|
||||
yajl_add_string_val(gen, "query", "n/a", strlen("n/a"));
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t res = -2;
|
||||
yajl_gen_status stat = yajl_gen_map_close(gen); //close the object
|
||||
if(stat == yajl_gen_status_ok) //all is good write the buffer out
|
||||
yajl_gen_status stat = yajl_gen_map_close(gen); // close the object
|
||||
if (stat == yajl_gen_status_ok) // all is good write the buffer out
|
||||
{
|
||||
const unsigned char * text = NULL;
|
||||
const unsigned char *text = NULL;
|
||||
unsigned int len = 0;
|
||||
yajl_gen_get_buf(gen, &text, &len);
|
||||
//print the json
|
||||
// print the json
|
||||
res = writer->write((const char *)text, len);
|
||||
if(res >= 0)
|
||||
if (res >= 0)
|
||||
{
|
||||
//TODO: use the msg_delimiter
|
||||
// TODO: use the msg_delimiter
|
||||
res = writer->write("\n", 1);
|
||||
}
|
||||
//my_fwrite(log_file, (uchar *) b.data, json_size(&b), MYF(0));
|
||||
// my_fwrite(log_file, (uchar *) b.data, json_size(&b), MYF(0));
|
||||
}
|
||||
yajl_gen_free(gen); //free the generator
|
||||
yajl_gen_free(gen); // free the generator
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ThdSesData::ThdSesData (THD *pTHD) :
|
||||
m_pThd (pTHD), m_CmdName(NULL), m_UserName(NULL),
|
||||
ThdSesData::ThdSesData(THD *pTHD)
|
||||
: m_pThd (pTHD), m_CmdName(NULL), m_UserName(NULL),
|
||||
m_objIterType(OBJ_NONE), m_tables(NULL), m_firstTable(true),
|
||||
m_tableInf(NULL), m_index(0), m_isSqlCmd(false)
|
||||
{
|
||||
|
@ -755,56 +770,56 @@ ThdSesData::ThdSesData (THD *pTHD) :
|
|||
|
||||
bool ThdSesData::startGetObjects()
|
||||
{
|
||||
//reset vars as this may be called multiple times
|
||||
// reset vars as this may be called multiple times
|
||||
m_objIterType = OBJ_NONE;
|
||||
m_tables = NULL;
|
||||
m_firstTable = true;
|
||||
m_index = 0;
|
||||
m_tableInf = Audit_formatter::getQueryCacheTableList1(getTHD());
|
||||
int command = Audit_formatter::thd_inst_command(getTHD());
|
||||
LEX * pLex = Audit_formatter::thd_lex(getTHD());
|
||||
//query cache case
|
||||
if(pLex && command == COM_QUERY && m_tableInf && m_tableInf->num_of_elem > 0)
|
||||
LEX *pLex = Audit_formatter::thd_lex(getTHD());
|
||||
// query cache case
|
||||
if (pLex && command == COM_QUERY && m_tableInf && m_tableInf->num_of_elem > 0)
|
||||
{
|
||||
m_objIterType = OBJ_QUERY_CACHE;
|
||||
return true;
|
||||
}
|
||||
const char *cmd = getCmdName();
|
||||
//commands which have single database object
|
||||
if (strcmp (cmd,"Init DB") ==0
|
||||
|| strcmp (cmd, "SHOW TABLES")== 0
|
||||
|| strcmp (cmd, "SHOW TABLE")==0)
|
||||
// commands which have single database object
|
||||
if (strcmp(cmd,"Init DB") == 0
|
||||
|| strcmp(cmd, "SHOW TABLES") == 0
|
||||
|| strcmp(cmd, "SHOW TABLE") == 0)
|
||||
{
|
||||
if(Audit_formatter::thd_db(getTHD()))
|
||||
if (Audit_formatter::thd_db(getTHD()))
|
||||
{
|
||||
m_objIterType = OBJ_DB;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//only return query tabls if command is COM_QUERY
|
||||
//TODO: check if other commands can also generate query tables such as "show fields"
|
||||
// only return query tables if command is COM_QUERY
|
||||
// TODO: check if other commands can also generate query tables such as "show fields"
|
||||
if (pLex && command == COM_QUERY && pLex->query_tables)
|
||||
{
|
||||
m_tables = pLex->query_tables;
|
||||
m_objIterType = OBJ_TABLE_LIST;
|
||||
return true;
|
||||
}
|
||||
//no objects
|
||||
// no objects
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ThdSesData::getNextObject(const char ** db_name, const char ** obj_name, const char ** obj_type)
|
||||
bool ThdSesData::getNextObject(const char **db_name, const char **obj_name, const char **obj_type)
|
||||
{
|
||||
switch(m_objIterType)
|
||||
{
|
||||
case OBJ_DB:
|
||||
{
|
||||
if(m_firstTable)
|
||||
if (m_firstTable)
|
||||
{
|
||||
*db_name = Audit_formatter::thd_db(getTHD());
|
||||
*obj_name = NULL;
|
||||
if(obj_type)
|
||||
if (obj_type)
|
||||
{
|
||||
*obj_type = "DATABASE";
|
||||
}
|
||||
|
@ -815,12 +830,12 @@ bool ThdSesData::getNextObject(const char ** db_name, const char ** obj_name, co
|
|||
}
|
||||
case OBJ_QUERY_CACHE:
|
||||
{
|
||||
if(m_index < m_tableInf->num_of_elem &&
|
||||
if (m_index < m_tableInf->num_of_elem &&
|
||||
m_index< MAX_NUM_QUERY_TABLE_ELEM)
|
||||
{
|
||||
*db_name = m_tableInf->db[m_index];
|
||||
*obj_name = m_tableInf->table_name[m_index];
|
||||
if(obj_type)
|
||||
if (obj_type)
|
||||
{
|
||||
*obj_type = m_tableInf->object_type[m_index];
|
||||
}
|
||||
|
@ -831,15 +846,15 @@ bool ThdSesData::getNextObject(const char ** db_name, const char ** obj_name, co
|
|||
}
|
||||
case OBJ_TABLE_LIST:
|
||||
{
|
||||
if(m_tables)
|
||||
if (m_tables)
|
||||
{
|
||||
*db_name = Audit_formatter::table_get_db_name(m_tables);
|
||||
*obj_name = Audit_formatter::table_get_name(m_tables);
|
||||
if(obj_type)
|
||||
if (obj_type)
|
||||
{
|
||||
//object is a view if it view command (alter_view, drop_view ..)
|
||||
//and first object or view field is populated
|
||||
if((m_firstTable && strstr(getCmdName(), "_view") != NULL) ||
|
||||
// object is a view if it view command (alter_view, drop_view ..)
|
||||
// and first object or view field is populated
|
||||
if ((m_firstTable && strstr(getCmdName(), "_view") != NULL) ||
|
||||
Audit_formatter::table_is_view(m_tables))
|
||||
{
|
||||
*obj_type = "VIEW";
|
||||
|
@ -855,16 +870,16 @@ bool ThdSesData::getNextObject(const char ** db_name, const char ** obj_name, co
|
|||
}
|
||||
return false;
|
||||
}
|
||||
default :
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pcre * Audit_json_formatter::regex_compile(const char * str)
|
||||
pcre *Audit_json_formatter::regex_compile(const char *str)
|
||||
{
|
||||
const char *error;
|
||||
int erroffset;
|
||||
pcre * re = pcre_compile(str, regex_flags, &error, &erroffset, NULL);
|
||||
pcre *re = pcre_compile(str, regex_flags, &error, &erroffset, NULL);
|
||||
if (!re)
|
||||
{
|
||||
sql_print_error("%s unable to compile regex [%s]. offset: %d message: [%s].",
|
||||
|
@ -873,25 +888,26 @@ pcre * Audit_json_formatter::regex_compile(const char * str)
|
|||
return re;
|
||||
}
|
||||
|
||||
int Audit_json_formatter::compile_password_masking_regex(const char * str)
|
||||
bool Audit_json_formatter::compile_password_masking_regex(const char *str)
|
||||
{
|
||||
//first free existing
|
||||
if(m_password_mask_regex_compiled)
|
||||
// first free existing
|
||||
if (m_password_mask_regex_compiled)
|
||||
{
|
||||
m_password_mask_regex_compiled = false;
|
||||
//small sleep to let threads oomplete regexc
|
||||
// small sleep to let threads complete regexec
|
||||
my_sleep(10 * 1000);
|
||||
pcre_free(m_password_mask_regex_preg);
|
||||
}
|
||||
int error = 1; //default is error (case of empty string)
|
||||
if(NULL != str && str[0] != '\0')
|
||||
|
||||
bool success = false; // default is error (case of empty string)
|
||||
if (NULL != str && str[0] != '\0')
|
||||
{
|
||||
m_password_mask_regex_preg = regex_compile(str);
|
||||
if(m_password_mask_regex_preg)
|
||||
if (m_password_mask_regex_preg)
|
||||
{
|
||||
m_password_mask_regex_compiled = true;
|
||||
error = 0;
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
return success;
|
||||
}
|
||||
|
|
|
@ -72,7 +72,6 @@ const ThdOffsets thd_offsets_arr[] =
|
|||
{"5.5.38","ae5937fbe5856b36b1ac7b0cb400abdd", 6136, 6184, 3816, 4312, 88, 2592, 96, 0, 32, 104},
|
||||
//offsets for: /mysqlrpm/5.6.19/usr/sbin/mysqld (5.6.19)
|
||||
{"5.6.19","2a01471dc6b6b59ae25a7efe675d1af4", 7928, 7976, 3992, 4512, 72, 2704, 96, 0, 32, 104},
|
||||
|
||||
//offsets for: mysqlrpm/5.1.30/usr/sbin/mysqld (5.1.30-community)
|
||||
{"5.1.30-community","8e43bda3644a883d46a1d064304b4f1d", 6184, 6248, 3656, 3928, 88, 2048},
|
||||
//offsets for: mysqlrpm/5.1.31/usr/sbin/mysqld (5.1.31-community)
|
||||
|
@ -157,7 +156,6 @@ const ThdOffsets thd_offsets_arr[] =
|
|||
{"5.1.68-community","4042e9a2778090df6fd8481e03ed6737", 6376, 6440, 3736, 4008, 88, 2056},
|
||||
//offsets for: /mysqlrpm/5.1.69/usr/sbin/mysqld (5.1.69-community)
|
||||
{"5.1.69-community","e9cb524b604419964f4dd55a8c87d618", 6376, 6440, 3736, 4008, 88, 2056},
|
||||
|
||||
//offsets for: mysqlrpm/5.5.8/usr/sbin/mysqld (5.5.8)
|
||||
{"5.5.8","70a882693d54df8ab7c7d9f256e317bb", 6032, 6080, 3776, 4200, 88, 2560},
|
||||
//offsets for: mysqlrpm/5.5.9/usr/sbin/mysqld (5.5.9)
|
||||
|
@ -216,7 +214,6 @@ const ThdOffsets thd_offsets_arr[] =
|
|||
{"5.5.30-ndb-7.2.12-cluster-commercial-advanced","9f96bc38bf06a9b18a945227ff9e5c42", 6096, 6144, 3816, 4240, 88, 2568},
|
||||
//offsets for: /mysqlrpm/5.5.31/usr/sbin/mysqld (5.5.31)
|
||||
{"5.5.31","f6604e70b9592f484a7a04a0173f0b25", 6064, 6112, 3816, 4240, 88, 2568},
|
||||
|
||||
//offsets for: MySQL-server-5.6.10-1.el6.x86_64/usr/sbin/mysqld (5.6.10)
|
||||
{"5.6.10","7016428728fe057d6825682d30e37b3d", 7808, 7856, 3960, 4400, 72, 2664},
|
||||
//offsets for: /mysqlrpm/5.6.10/usr/sbin/mysqld (5.6.10)
|
||||
|
@ -308,7 +305,6 @@ const ThdOffsets thd_offsets_arr[] =
|
|||
{"5.1.68","673dd031ea4ad3493b47d74662a49079", 6392, 6456, 3752, 4024, 88, 2056},
|
||||
//offsets for: /mysql/5.1.69/bin/mysqld (5.1.69)
|
||||
{"5.1.69","af2936f85db019bfd44c7e12a2138707", 6392, 6456, 3752, 4024, 88, 2056},
|
||||
|
||||
//offsets for: mysql/5.5.8/bin/mysqld (5.5.8)
|
||||
{"5.5.8","a32b163f08ca8bfd7486cd77200d9df3", 6032, 6080, 3776, 4200, 88, 2560},
|
||||
//offsets for: mysql/5.5.9/bin/mysqld (5.5.9)
|
||||
|
@ -362,12 +358,10 @@ const ThdOffsets thd_offsets_arr[] =
|
|||
{"5.5.31","858dc19ffc5d34e669ab85d32a8a0623", 6064, 6112, 3816, 4240, 88, 2568},
|
||||
//offsets for: /mysql/5.5.31/bin/mysqld (5.5.31)
|
||||
{"5.5.31","61e65a4cc9360e03f3810ef2928c916d", 6064, 6112, 3816, 4240, 88, 2568},
|
||||
|
||||
//offsets for: /mysql/5.6.10/bin/mysqld (5.6.10)
|
||||
{"5.6.10","37f9c31dd092bb2d0da7eb6e2098732f", 7808, 7856, 3960, 4400, 72, 2664},
|
||||
//offsets for: /mysql/5.6.11/bin/mysqld (5.6.11)
|
||||
{"5.6.11","85fd884192cc5cd12fba52b7b140c819", 7808, 7856, 3960, 4400, 72, 2672},
|
||||
|
||||
//offsets for: /mysqlrpm/5.1.70/usr/sbin/mysqld (5.1.70-community)
|
||||
{"5.1.70-community","e70f9d48dad2a30b24e6c2744bed94d2", 6376, 6440, 3736, 4008, 88, 2072},
|
||||
//offsets for: /mysqlrpm/5.5.32/usr/sbin/mysqld (5.5.32)
|
||||
|
@ -481,7 +475,6 @@ const ThdOffsets thd_offsets_arr[] =
|
|||
{"5.5.38","89e8b85dd5731e15df3d5597020c0ec8", 3868, 3896, 2368, 2748, 44, 1656, 60, 0, 20, 64},
|
||||
//offsets for: /mysqlrpm/5.6.19/usr/sbin/mysqld (5.6.19)
|
||||
{"5.6.19","3f94430e20b564951159aa78627df97f", 5652, 5680, 2656, 3048, 36, 1748, 60, 0, 20, 64},
|
||||
|
||||
//offsets for: mysqlrpm/5.1.30/usr/sbin/mysqld (5.1.30-community)
|
||||
{"5.1.30-community","fdfe108d05c262c185a7c28b2e493c10", 4024, 4064, 2224, 2404, 44, 1180},
|
||||
//offsets for: mysqlrpm/5.1.31/usr/sbin/mysqld (5.1.31-community)
|
||||
|
@ -563,7 +556,6 @@ const ThdOffsets thd_offsets_arr[] =
|
|||
{"5.1.68-community","df5dc268b36dbe853ed37d91fd4b6b3f", 4124, 4164, 2268, 2448, 44, 1180},
|
||||
//offsets for: /mysqlrpm/5.1.69/usr/sbin/mysqld (5.1.69-community)
|
||||
{"5.1.69-community","4c8acbca31f3f4ba44d35db9f5c65bc0", 4124, 4164, 2268, 2448, 44, 1180},
|
||||
|
||||
//offsets for: mysqlrpm/5.5.8/usr/sbin/mysqld (5.5.8)
|
||||
{"5.5.8","3132e8c883f72caf4c8eddb24fd005b4", 3792, 3820, 2336, 2668, 44, 1640},
|
||||
//offsets for: mysqlrpm/5.5.9/usr/sbin/mysqld (5.5.9)
|
||||
|
@ -610,7 +602,6 @@ const ThdOffsets thd_offsets_arr[] =
|
|||
{"5.5.30","0186d1ef4725814924bfe968e3455138", 3816, 3844, 2368, 2700, 44, 1644},
|
||||
//offsets for: /mysqlrpm/5.5.31/usr/sbin/mysqld (5.5.31)
|
||||
{"5.5.31","190e7556e226f8690ba8672869178e4c", 3816, 3844, 2368, 2700, 44, 1644},
|
||||
|
||||
//offsets for: /mysqlrpm/5.6.10/usr/sbin/mysqld (5.6.10)
|
||||
{"5.6.10","dd3abddcfd0015de81b6a26b6190cefb", 5572, 5600, 2640, 2980, 36, 1712},
|
||||
//offsets for: /mysqlrpm/5.6.11/usr/sbin/mysqld (5.6.11)
|
||||
|
@ -696,7 +687,6 @@ const ThdOffsets thd_offsets_arr[] =
|
|||
{"5.1.68","d03c42d8a8946f11ace86a5e1189114d", 4140, 4180, 2284, 2464, 44, 1180},
|
||||
//offsets for: /mysql/5.1.69/bin/mysqld (5.1.69)
|
||||
{"5.1.69","5abf5a9f9f9c01be997595b066a40986", 4140, 4180, 2284, 2464, 44, 1180},
|
||||
|
||||
//offsets for: /mysqlrpm/5.5.8/usr/sbin/mysqld (5.5.8)
|
||||
{"5.5.8","3132e8c883f72caf4c8eddb24fd005b4", 3792, 3820, 2336, 2668, 44, 1640},
|
||||
{"5.5.8","ad8a16d9bbfb783dab53f38cef757900", 3792, 3820, 2336, 2668, 44, 1640},
|
||||
|
@ -748,12 +738,10 @@ const ThdOffsets thd_offsets_arr[] =
|
|||
{"5.5.30","c7b98be45d35b77da6679c354c23d1fa", 3816, 3844, 2368, 2700, 44, 1644},
|
||||
//offsets for: /mysql/5.5.31/bin/mysqld (5.5.31)
|
||||
{"5.5.31","36631a7c748358598ba21cd4157545d9", 3816, 3844, 2368, 2700, 44, 1644},
|
||||
|
||||
//offsets for: /mysql/5.6.10/bin/mysqld (5.6.10)
|
||||
{"5.6.10","84600f18354f519e38302c04fe55ed9c", 5572, 5600, 2640, 2980, 36, 1712},
|
||||
//offsets for: /mysql/5.6.11/bin/mysqld (5.6.11)
|
||||
{"5.6.11","72e67111f3c1d1c1d4e7095e3a004fcf", 5572, 5600, 2640, 2980, 36, 1724},
|
||||
|
||||
//offsets for: /mysqlrpm/5.1.70/usr/sbin/mysqld (5.1.70-community)
|
||||
{"5.1.70-community","605c76c9d37a890cea85c075aeaaa2e6", 4124, 4164, 2268, 2448, 44, 1188},
|
||||
//offsets for: /mysqlrpm/5.5.32/usr/sbin/mysqld (5.5.32)
|
||||
|
@ -812,7 +800,6 @@ const ThdOffsets thd_offsets_arr[] =
|
|||
|
||||
#endif
|
||||
|
||||
|
||||
#else
|
||||
//start offsets for MariaDB
|
||||
#ifdef __x86_64__
|
||||
|
@ -820,6 +807,8 @@ const ThdOffsets thd_offsets_arr[] =
|
|||
const ThdOffsets thd_offsets_arr[] =
|
||||
{
|
||||
/* +++ MARIADB 64 OFFSETS GO HERE +++ */
|
||||
//offsets for: /mariadb/10.1.13/bin/mysqld (10.1.13-MariaDB)
|
||||
{"10.1.13-MariaDB","cd322698dcd46dd82770dc091f1eec51", 13592, 13656, 6368, 7976, 88, 2976, 8, 0, 16, 24, 152, 13748},
|
||||
//offsets for: /mariadb/10.1.12/bin/mysqld (10.1.12-MariaDB)
|
||||
{"10.1.12-MariaDB","e2ba726e2e6f56976518581da0a2c443", 13592, 13656, 6368, 7976, 88, 2976, 8, 0, 16, 24, 152, 13748},
|
||||
//offsets for: /mariadb/10.0.24/bin/mysqld (10.0.24-MariaDB)
|
||||
|
@ -911,6 +900,8 @@ const ThdOffsets thd_offsets_arr[] =
|
|||
const ThdOffsets thd_offsets_arr[] =
|
||||
{
|
||||
/* +++ MARIADB 32 OFFSETS GO HERE +++ */
|
||||
//offsets for: /mariadb/10.1.13/bin/mysqld (10.1.13-MariaDB)
|
||||
{"10.1.13-MariaDB","546cb7233e8567aea304fda3d9812a7b", 8472, 8508, 3816, 5276, 44, 1892, 4, 0, 8, 12, 84, 8584},
|
||||
//offsets for: /mariadb/10.1.12/bin/mysqld (10.1.12-MariaDB)
|
||||
{"10.1.12-MariaDB","590bb2be8fb17c7b3599539d4a69ab44", 8472, 8508, 3816, 5276, 44, 1892, 4, 0, 8, 12, 84, 8584},
|
||||
//offsets for: /mariadb/10.0.24/bin/mysqld (10.0.24-MariaDB)
|
||||
|
@ -1003,4 +994,3 @@ const ThdOffsets thd_offsets_arr[] =
|
|||
|
||||
//the size of the offsets arr
|
||||
const size_t thd_offsets_arr_size = array_elements(thd_offsets_arr);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
108
src/hot_patch.cc
108
src/hot_patch.cc
|
@ -11,33 +11,33 @@
|
|||
#define ULONG_PTR uint32_t
|
||||
#endif
|
||||
|
||||
static const char * log_prefix = "Audit Plugin:";
|
||||
static const char *log_prefix = "Audit Plugin:";
|
||||
|
||||
static const unsigned long PAGE_SIZE = GETPAGESIZE() ;
|
||||
|
||||
//used to indicate how to do the protect/unprotect
|
||||
// used to indicate how to do the protect/unprotect
|
||||
static bool use_exec_prot = true;
|
||||
|
||||
static int protect(void *addr, size_t len)
|
||||
{
|
||||
int res = 0;
|
||||
if(use_exec_prot)
|
||||
if (use_exec_prot)
|
||||
{
|
||||
res = mprotect(addr,len,PROT_READ|PROT_EXEC);
|
||||
}
|
||||
else //try doing in a 2 step fashion
|
||||
else // try doing in a 2 step fashion
|
||||
{
|
||||
mprotect(addr,len,PROT_READ);
|
||||
res = mprotect(addr,len,PROT_READ|PROT_EXEC);
|
||||
}
|
||||
if(res)
|
||||
if (res)
|
||||
{
|
||||
sql_print_information(
|
||||
"%s unable to protect mode: PROT_READ|PROT_EXEC. Page: %p, Size: %zu, errno: %d, res %d.",
|
||||
log_prefix, (void *)addr, len, errno, res);
|
||||
//fail only if nx bit is enabled
|
||||
FILE * fp = fopen("/proc/cpuinfo", "r");
|
||||
if(NULL == fp)
|
||||
// fail only if nx bit is enabled
|
||||
FILE *fp = fopen("/proc/cpuinfo", "r");
|
||||
if (NULL == fp)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s unable to verify nx bit. Failed checking /proc/cpuinfo. This may happen if you have SELinux enabled. Disable SELinux execmod protection for mysqld. Page: %p, Size: %zu, errno: %d.",
|
||||
|
@ -45,21 +45,21 @@ static int protect(void *addr, size_t len)
|
|||
return res;
|
||||
}
|
||||
char buff[1024] = {0};
|
||||
const char * flags = "flags";
|
||||
const char *flags = "flags";
|
||||
bool nxchecked = false;
|
||||
while(fgets(buff, 1024, fp) != NULL)
|
||||
while (fgets(buff, 1024, fp) != NULL)
|
||||
{
|
||||
char * line = buff;
|
||||
//trim white space at start
|
||||
char *line = buff;
|
||||
// trim white space at start
|
||||
while ((strlen(line) > 0) && (isspace(line[0])))
|
||||
{
|
||||
line++;
|
||||
}
|
||||
if(strncmp(line, flags, strlen(flags)) == 0)
|
||||
if (strncmp(line, flags, strlen(flags)) == 0)
|
||||
{
|
||||
nxchecked = true;
|
||||
sql_print_information("%s cpuinfo flags line: %s. ",log_prefix, line);
|
||||
if(strstr(line, " nx")) //nx enabled so fail
|
||||
if (strstr(line, " nx")) // nx enabled so fail
|
||||
{
|
||||
sql_print_error(
|
||||
"%s unable to protect page and nx bit enabled. This may happen if you have SELinux enabled. Disable SELinux execmod protection for mysqld. Page: %p, Size: %zu.",
|
||||
|
@ -71,7 +71,7 @@ static int protect(void *addr, size_t len)
|
|||
}
|
||||
}
|
||||
fclose(fp);
|
||||
if(!nxchecked) //we didn't find flags string for some reason
|
||||
if (! nxchecked) // we didn't find flags string for some reason
|
||||
{
|
||||
sql_print_error(
|
||||
"%s unable to verify nx bit. Failed finding: %s in /proc/cpuinfo. This may happen if you have SELinux enabled. Disable SELinux execmod protection for mysqld. Page: %p, Size: %zu.",
|
||||
|
@ -82,23 +82,23 @@ static int protect(void *addr, size_t len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//will try to unprotect with PROT_READ|PROT_WRITE|PROT_EXEC. If fails (might happen under SELinux)
|
||||
//will use PROT_READ|PROT_WRITE
|
||||
// will try to unprotect with PROT_READ|PROT_WRITE|PROT_EXEC. If fails (might happen under SELinux)
|
||||
// will use PROT_READ|PROT_WRITE
|
||||
static int unprotect(void *addr, size_t len)
|
||||
{
|
||||
int res;
|
||||
if(use_exec_prot)
|
||||
if (use_exec_prot)
|
||||
{
|
||||
res = mprotect(addr,len,PROT_READ|PROT_WRITE|PROT_EXEC);
|
||||
if(res)
|
||||
res = mprotect(addr, len, PROT_READ|PROT_WRITE|PROT_EXEC);
|
||||
if (res)
|
||||
{
|
||||
sql_print_information(
|
||||
"%s unable to unprotect. Page: %p, Size: %zu, errno: %d. Using NO EXEC mode.",
|
||||
log_prefix, (void *)addr, len, errno);
|
||||
use_exec_prot = false;
|
||||
//do a sanity test that we can actually unprotect/protect and that nx bit is off
|
||||
// do a sanity test that we can actually unprotect/protect and that nx bit is off
|
||||
res = unprotect(addr, len);
|
||||
if(res)
|
||||
if (res)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s unable to unprotect page. This may happen if you have SELinux enabled. Disable SELinux execmod protection for mysqld. Aborting. Page: %p, Size: %zu, errno: %d.",
|
||||
|
@ -107,7 +107,7 @@ static int unprotect(void *addr, size_t len)
|
|||
}
|
||||
res = protect(addr, len);
|
||||
sql_print_information("%s protect res: %d", log_prefix, res);
|
||||
if(res)
|
||||
if (res)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s unable to protect page. This may happen if you have SELinux enabled. Disable SELinux execmod protection for mysqld. Aborting. Page: %p, Size: %zu, errno: %d.",
|
||||
|
@ -115,13 +115,14 @@ static int unprotect(void *addr, size_t len)
|
|||
return res;
|
||||
}
|
||||
}
|
||||
else //all is good
|
||||
else // all is good
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}
|
||||
res = mprotect(addr,len,PROT_READ|PROT_WRITE);
|
||||
if(0 != res) //log the failure
|
||||
|
||||
res = mprotect(addr, len, PROT_READ|PROT_WRITE);
|
||||
if (0 != res) // log the failure
|
||||
{
|
||||
sql_print_error(
|
||||
"%s unable to unprotect. Page: %p, Size: %zu, errno: %d. Error.",
|
||||
|
@ -130,14 +131,14 @@ static int unprotect(void *addr, size_t len)
|
|||
return res;
|
||||
}
|
||||
|
||||
//macro to log via sql_print_information only if cond test is enabled
|
||||
#define cond_info_print(cond_test, ...) do{if(cond_test) sql_print_information(__VA_ARGS__);}while(0)
|
||||
// macro to log via sql_print_information only if cond test is enabled
|
||||
#define cond_info_print(cond_test, ...) do { if (cond_test) sql_print_information(__VA_ARGS__);} while (0)
|
||||
|
||||
|
||||
/*
|
||||
* Get the page address of a given pointer
|
||||
*/
|
||||
static DATATYPE_ADDRESS get_page_address(void * pointer)
|
||||
static DATATYPE_ADDRESS get_page_address(void *pointer)
|
||||
{
|
||||
DATATYPE_ADDRESS pageMask = ( ~(PAGE_SIZE - 1) ) ;
|
||||
DATATYPE_ADDRESS longp = (unsigned long) pointer;
|
||||
|
@ -183,9 +184,7 @@ static void WriteJump(void *pAddress, ULONG_PTR JumpTo)
|
|||
*((ULONG_PTR *)pCur) = JumpTo;
|
||||
|
||||
#endif
|
||||
//}
|
||||
|
||||
//DWORD dwBuf = 0; // nessary othewrise the function fails
|
||||
// DWORD dwBuf = 0; // necessary othewrise the function fails
|
||||
|
||||
protect((void*)AddressPage, PAGE_SIZE);
|
||||
}
|
||||
|
@ -196,16 +195,16 @@ static void WriteJump(void *pAddress, ULONG_PTR JumpTo)
|
|||
static bool HookFunction(ULONG_PTR targetFunction, ULONG_PTR newFunction, ULONG_PTR trampolineFunction,
|
||||
unsigned int *trampolinesize)
|
||||
{
|
||||
#define MAX_INSTRUCTIONS 100
|
||||
#define MAX_INSTRUCTIONS 100
|
||||
uint8_t raw[MAX_INSTRUCTIONS];
|
||||
unsigned int uCurrentSize =0;
|
||||
|
||||
#ifndef __x86_64__
|
||||
#define ASM_MODE 32
|
||||
#define ASM_MODE 32
|
||||
#else
|
||||
#define ASM_MODE 64
|
||||
#define ASM_MODE 64
|
||||
#endif
|
||||
memcpy (raw,(void*)targetFunction,MAX_INSTRUCTIONS);
|
||||
memcpy(raw, (void*)targetFunction, MAX_INSTRUCTIONS);
|
||||
ud_t ud_obj;
|
||||
ud_init(&ud_obj);
|
||||
ud_set_input_buffer(&ud_obj, raw, MAX_INSTRUCTIONS);
|
||||
|
@ -215,26 +214,28 @@ static bool HookFunction(ULONG_PTR targetFunction, ULONG_PTR newFunction, ULONG
|
|||
|
||||
DWORD InstrSize = 0;
|
||||
DATATYPE_ADDRESS trampolineFunctionPage = get_page_address((void*)trampolineFunction);
|
||||
if(unprotect((void*)trampolineFunctionPage, PAGE_SIZE) != 0)
|
||||
if (unprotect((void*)trampolineFunctionPage, PAGE_SIZE) != 0)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s unable to unprotect trampoline function page: %p. Aborting.",
|
||||
log_prefix, (void *)trampolineFunctionPage);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool disassemble_valid = false;
|
||||
while (ud_disassemble(&ud_obj))
|
||||
{
|
||||
if(ud_obj.mnemonic == UD_Iinvalid)
|
||||
if (ud_obj.mnemonic == UD_Iinvalid)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s unable to disassemble at address: %p. Aborting.",
|
||||
log_prefix, (void *)(InstrSize + targetFunction));
|
||||
break;
|
||||
}
|
||||
//make sure there isn't a jmp/call (or similar operand) as these use
|
||||
//relative addressing and if we copy as is we will mess up the jmp/call target
|
||||
if(ud_obj.mnemonic == UD_Ijmp || ud_obj.mnemonic == UD_Icall ||
|
||||
|
||||
// make sure there isn't a jmp/call (or similar operand) as these use
|
||||
// relative addressing and if we copy as is we will mess up the jmp/call target
|
||||
if (ud_obj.mnemonic == UD_Ijmp || ud_obj.mnemonic == UD_Icall ||
|
||||
ud_obj.operand[0].type == UD_OP_JIMM)
|
||||
{
|
||||
sql_print_error(
|
||||
|
@ -249,24 +250,27 @@ static bool HookFunction(ULONG_PTR targetFunction, ULONG_PTR newFunction, ULONG
|
|||
|
||||
uCurrentSize += ud_insn_len (&ud_obj);
|
||||
InstrSize += ud_insn_len (&ud_obj);
|
||||
if (InstrSize >= jump_size()) //we have enough space so break
|
||||
if (InstrSize >= jump_size()) // we have enough space so break
|
||||
{
|
||||
disassemble_valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(protect((void*)trampolineFunctionPage, PAGE_SIZE)) //0 valid return
|
||||
|
||||
if (protect((void*)trampolineFunctionPage, PAGE_SIZE)) // 0 valid return
|
||||
{
|
||||
sql_print_error(
|
||||
"%s unable to protect page. Error. Page: %p.",
|
||||
log_prefix, (void *)trampolineFunctionPage);
|
||||
return false;
|
||||
}
|
||||
if(!disassemble_valid) //something went wrong. log was written before so return false
|
||||
|
||||
if (! disassemble_valid) // something went wrong. log was written before so return false
|
||||
{
|
||||
return false;
|
||||
}
|
||||
WriteJump( (BYTE*)trampolineFunction + uCurrentSize, targetFunction + InstrSize);
|
||||
|
||||
WriteJump((BYTE*)trampolineFunction + uCurrentSize, targetFunction + InstrSize);
|
||||
WriteJump((void *) targetFunction, newFunction);
|
||||
*trampolinesize = uCurrentSize;
|
||||
return true;
|
||||
|
@ -277,10 +281,10 @@ static bool HookFunction(ULONG_PTR targetFunction, ULONG_PTR newFunction, ULONG
|
|||
//
|
||||
|
||||
|
||||
static void UnhookFunction(ULONG_PTR Function,ULONG_PTR trampolineFunction , unsigned int trampolinesize)
|
||||
static void UnhookFunction(ULONG_PTR Function, ULONG_PTR trampolineFunction, unsigned int trampolinesize)
|
||||
{
|
||||
DATATYPE_ADDRESS FunctionPage = get_page_address((void*)Function);
|
||||
if(unprotect((void*)FunctionPage, PAGE_SIZE) != 0)
|
||||
if (unprotect((void*)FunctionPage, PAGE_SIZE) != 0)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s Unhook not able to unprotect function page: %p. Aborting.",
|
||||
|
@ -306,9 +310,9 @@ static void UnhookFunction(ULONG_PTR Function,ULONG_PTR trampolineFunction , uns
|
|||
* which contains a bunch of nops.
|
||||
* @param info_print if true will print info as progressing
|
||||
* @Return 0 on success otherwise failure
|
||||
* @See MS Detours paper: http://research.microsoft.com/pubs/68568/huntusenixnt99.pdf for some background info.
|
||||
* @See MS Detours paper: http:// research.microsoft.com/pubs/68568/huntusenixnt99.pdf for some background info.
|
||||
*/
|
||||
int hot_patch_function (void* targetFunction, void* newFunction, void * trampolineFunction, unsigned int *trampolinesize, bool info_print)
|
||||
int hot_patch_function(void *targetFunction, void *newFunction, void *trampolineFunction, unsigned int *trampolinesize, bool info_print)
|
||||
{
|
||||
DATATYPE_ADDRESS trampolinePage = get_page_address(trampolineFunction);
|
||||
cond_info_print(info_print, "%s hot patching function: %p, trampolineFunction: %p trampolinePage: %p",log_prefix, (void *)targetFunction, (void *)trampolineFunction, (void *)trampolinePage);
|
||||
|
@ -332,11 +336,11 @@ int hot_patch_function (void* targetFunction, void* newFunction, void * trampoli
|
|||
* @param trampolineFunction a function which contains a jump back to the targetFunction.
|
||||
* @param log_file if not null will log about progress of installing the plugin
|
||||
*/
|
||||
void remove_hot_patch_function (void* targetFunction, void * trampolineFunction, unsigned int trampolinesize, bool info_print)
|
||||
void remove_hot_patch_function(void *targetFunction, void *trampolineFunction, unsigned int trampolinesize, bool info_print)
|
||||
{
|
||||
if(trampolinesize == 0)
|
||||
if (trampolinesize == 0)
|
||||
{
|
||||
//nothing todo. As hot patch was not set.
|
||||
// nothing todo. As hot patch was not set.
|
||||
return;
|
||||
}
|
||||
DATATYPE_ADDRESS targetPage = get_page_address(targetFunction);
|
||||
|
|
Loading…
Reference in New Issue