Add MariaDB 10.1.13 offsets. Format the code.
parent
051b1fd67e
commit
80646620e9
|
@ -49,12 +49,12 @@ typedef struct _THDPRINTED {
|
||||||
} THDPRINTED;
|
} THDPRINTED;
|
||||||
|
|
||||||
#define MAX_COMMAND_CHAR_NUMBERS 40
|
#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;
|
typedef size_t OFFSET;
|
||||||
|
|
||||||
#define MAX_COM_STATUS_VARS_RECORDS 512
|
#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_OBJECT_CHAR_NUMBERS 131
|
||||||
#define MAX_USER_CHAR_NUMBERS 20
|
#define MAX_USER_CHAR_NUMBERS 20
|
||||||
#define MAX_NUM_OBJECT_ELEM 256
|
#define MAX_NUM_OBJECT_ELEM 256
|
||||||
|
@ -63,22 +63,21 @@ typedef size_t OFFSET;
|
||||||
/**
|
/**
|
||||||
* The struct used to hold offsets. We should have one per version.
|
* The struct used to hold offsets. We should have one per version.
|
||||||
*/
|
*/
|
||||||
typedef struct ThdOffsets
|
typedef struct ThdOffsets {
|
||||||
{
|
const char *version;
|
||||||
const char * version;
|
const char *md5digest;
|
||||||
const char * md5digest;
|
OFFSET query_id;
|
||||||
OFFSET query_id;
|
OFFSET thread_id;
|
||||||
OFFSET thread_id;
|
OFFSET main_security_ctx;
|
||||||
OFFSET main_security_ctx;
|
OFFSET command;
|
||||||
OFFSET command;
|
|
||||||
OFFSET lex;
|
OFFSET lex;
|
||||||
OFFSET lex_comment;
|
OFFSET lex_comment;
|
||||||
OFFSET sec_ctx_user;
|
OFFSET sec_ctx_user;
|
||||||
OFFSET sec_ctx_host;
|
OFFSET sec_ctx_host;
|
||||||
OFFSET sec_ctx_ip;
|
OFFSET sec_ctx_ip;
|
||||||
OFFSET sec_ctx_priv_user;
|
OFFSET sec_ctx_priv_user;
|
||||||
OFFSET db;
|
OFFSET db;
|
||||||
OFFSET killed;
|
OFFSET killed;
|
||||||
} ThdOffsets;
|
} ThdOffsets;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -96,267 +95,263 @@ typedef ssize_t (*audit_write_func)(const char *, size_t);
|
||||||
/**
|
/**
|
||||||
* Interface for an io writer
|
* Interface for an io writer
|
||||||
*/
|
*/
|
||||||
class IWriter
|
class IWriter {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
virtual ~IWriter() {}
|
virtual ~IWriter() {}
|
||||||
//return negative on fail
|
// return negative on fail
|
||||||
virtual ssize_t write(const char * data, size_t size) = 0;
|
virtual ssize_t write(const char *data, size_t size) = 0;
|
||||||
inline ssize_t write_str(const char * str)
|
inline ssize_t write_str(const char *str)
|
||||||
{
|
{
|
||||||
return write(str, strlen(str));
|
return write(str, strlen(str));
|
||||||
}
|
}
|
||||||
//return 0 on success
|
// return 0 on success
|
||||||
virtual int open(const char * io_dest, bool log_errors) = 0;
|
virtual int open(const char *io_dest, bool log_errors) = 0;
|
||||||
virtual void close() = 0;
|
virtual void close() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ThdSesData {
|
class ThdSesData {
|
||||||
public:
|
public:
|
||||||
|
// 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; }
|
||||||
|
/**
|
||||||
|
* Start fetching objects. Return true if there are objects available.
|
||||||
|
*/
|
||||||
|
bool startGetObjects();
|
||||||
|
/**
|
||||||
|
* Get next object. Return true if populated. False if there isn't an object available.
|
||||||
|
* 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);
|
||||||
|
|
||||||
//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; }
|
|
||||||
/**
|
|
||||||
* Start fetching objects. Return true if there are objects available.
|
|
||||||
*/
|
|
||||||
bool startGetObjects();
|
|
||||||
/**
|
|
||||||
* Get next object. Return true if populated. False if there isn't an object available.
|
|
||||||
* 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);
|
|
||||||
private:
|
private:
|
||||||
THD *m_pThd;
|
THD *m_pThd;
|
||||||
const char *m_CmdName;
|
const char *m_CmdName;
|
||||||
const char *m_UserName;
|
const char *m_UserName;
|
||||||
bool m_isSqlCmd;
|
bool m_isSqlCmd;
|
||||||
enum ObjectIterType m_objIterType;
|
enum ObjectIterType m_objIterType;
|
||||||
//pointer for iterating tables
|
// pointer for iterating tables
|
||||||
TABLE_LIST * m_tables;
|
TABLE_LIST *m_tables;
|
||||||
//indicator if we are at the first table
|
// indicator if we are at the first table
|
||||||
bool m_firstTable;
|
bool m_firstTable;
|
||||||
//used for query cache iter
|
// used for query cache iter
|
||||||
QueryTableInf * m_tableInf;
|
QueryTableInf *m_tableInf;
|
||||||
int m_index;
|
int m_index;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ThdSesData (const ThdSesData& );
|
ThdSesData(const ThdSesData&);
|
||||||
ThdSesData &operator =(const ThdSesData& );
|
ThdSesData &operator =(const ThdSesData&);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base for audit formatter
|
* Base for audit formatter
|
||||||
*/
|
*/
|
||||||
class Audit_formatter
|
class Audit_formatter {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
virtual ~Audit_formatter() {}
|
||||||
|
|
||||||
virtual ~Audit_formatter() {}
|
/**
|
||||||
|
* static offsets to use for fetching THD data. Set by the audit plugin during startup.
|
||||||
|
*/
|
||||||
|
static ThdOffsets thd_offsets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* static offsets to use for fetching THD data. Set by the audit plugin during startup.
|
* Format an audit event from the passed THD. Will write out its output using the audit_write_func.
|
||||||
*/
|
*
|
||||||
static ThdOffsets thd_offsets;
|
* @return -1 on a failure
|
||||||
|
*/
|
||||||
|
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; }
|
||||||
|
/**
|
||||||
|
* format a message when handler is stopped
|
||||||
|
* @return -1 on a failure
|
||||||
|
*/
|
||||||
|
virtual ssize_t stop_msg_format(IWriter *writer) { return 0; }
|
||||||
|
|
||||||
/**
|
static const char *retrieve_object_type(TABLE_LIST *pObj);
|
||||||
* Format an audit event from the passed THD. Will write out its output using the audit_write_func.
|
static QueryTableInf *getQueryCacheTableList1(THD *thd);
|
||||||
*
|
// utility functions for fetching thd stuff
|
||||||
* @return -1 on a failure
|
static inline my_thread_id thd_inst_thread_id(THD *thd)
|
||||||
*/
|
{
|
||||||
virtual ssize_t event_format(ThdSesData *pThdData, IWriter * writer) =0;
|
return *(my_thread_id *) (((unsigned char *) thd)
|
||||||
/**
|
+ Audit_formatter::thd_offsets.thread_id);
|
||||||
* format a message when handler is started
|
}
|
||||||
* @return -1 on a failure
|
static inline query_id_t thd_inst_query_id(THD *thd)
|
||||||
*/
|
{
|
||||||
virtual ssize_t start_msg_format(IWriter * writer) { return 0; }
|
return *(query_id_t *) (((unsigned char *) thd)
|
||||||
/**
|
+ Audit_formatter::thd_offsets.query_id);
|
||||||
* format a message when handler is stopped
|
}
|
||||||
* @return -1 on a failure
|
static inline Security_context *thd_inst_main_security_ctx(THD *thd)
|
||||||
*/
|
{
|
||||||
virtual ssize_t stop_msg_format(IWriter * writer) { return 0; }
|
return (Security_context *) (((unsigned char *) thd)
|
||||||
|
+ Audit_formatter::thd_offsets.main_security_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
static const char * retrieve_object_type (TABLE_LIST *pObj);
|
static inline const char *thd_db(THD *thd)
|
||||||
static QueryTableInf* getQueryCacheTableList1 (THD *thd);
|
{
|
||||||
//utility functions for fetching thd stuff
|
if (! Audit_formatter::thd_offsets.db) // no offsets use compiled in header
|
||||||
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)
|
|
||||||
{
|
|
||||||
return *(query_id_t *) (((unsigned char *) thd)
|
|
||||||
+ Audit_formatter::thd_offsets.query_id);
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if(!Audit_formatter::thd_offsets.db) //no offsets use compiled in header
|
|
||||||
{
|
{
|
||||||
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
|
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
|
||||||
return thd->db;
|
return thd->db;
|
||||||
#else
|
#else
|
||||||
return thd->db().str;
|
return thd->db().str;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return *(const char **) (((unsigned char *) thd)
|
return *(const char **) (((unsigned char *) thd)
|
||||||
+ Audit_formatter::thd_offsets.db);
|
+ 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);
|
return ::thd_killed(thd);
|
||||||
}
|
}
|
||||||
return *(int *) (((unsigned char *) thd)
|
return *(int *) (((unsigned char *) thd)
|
||||||
+ Audit_formatter::thd_offsets.killed);
|
+ 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);
|
Security_context *sctx = thd_inst_main_security_ctx(thd);
|
||||||
if(!Audit_formatter::thd_offsets.sec_ctx_user) //no offsets use compiled in header
|
if (! Audit_formatter::thd_offsets.sec_ctx_user) // no offsets use compiled in header
|
||||||
{
|
{
|
||||||
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
|
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
|
||||||
return sctx->user;
|
return sctx->user;
|
||||||
#else
|
#else
|
||||||
return sctx->user().str;
|
return sctx->user().str;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return *(const char **) (((unsigned char *) sctx)
|
return *(const char **) (((unsigned char *) sctx)
|
||||||
+ Audit_formatter::thd_offsets.sec_ctx_user);
|
+ 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);
|
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
|
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()
|
// 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
|
// see: http://bazaar.launchpad.net/~mysql/mysql-server/5.5/revision/4407.1.1/sql/sql_class.h
|
||||||
#if defined(MARIADB_BASE_VERSION)
|
#if defined(MARIADB_BASE_VERSION)
|
||||||
return sctx->host;
|
return sctx->host;
|
||||||
#else
|
#else
|
||||||
// MySQL
|
// MySQL
|
||||||
#if MYSQL_VERSION_ID < 50534 || (MYSQL_VERSION_ID >= 50600 && MYSQL_VERSION_ID < 50614)
|
#if MYSQL_VERSION_ID < 50534 || (MYSQL_VERSION_ID >= 50600 && MYSQL_VERSION_ID < 50614)
|
||||||
return sctx->host;
|
return sctx->host;
|
||||||
#elif (MYSQL_VERSION_ID >= 50534 && MYSQL_VERSION_ID < 50600) \
|
#elif (MYSQL_VERSION_ID >= 50534 && MYSQL_VERSION_ID < 50600) \
|
||||||
|| (MYSQL_VERSION_ID >= 50614 && MYSQL_VERSION_ID < 50709)
|
|| (MYSQL_VERSION_ID >= 50614 && MYSQL_VERSION_ID < 50709)
|
||||||
return sctx->get_host()->ptr();
|
return sctx->get_host()->ptr();
|
||||||
#else
|
#else
|
||||||
// interface changed again in 5.7
|
// interface changed again in 5.7
|
||||||
return sctx->host().str;
|
return sctx->host().str;
|
||||||
#endif
|
#endif
|
||||||
#endif // ! defined(MARIADB_BASE_VERSION)
|
#endif // ! defined(MARIADB_BASE_VERSION)
|
||||||
}
|
}
|
||||||
return *(const char **) (((unsigned char *) sctx)
|
return *(const char **) (((unsigned char *) sctx)
|
||||||
+ Audit_formatter::thd_offsets.sec_ctx_host);
|
+ 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);
|
Security_context *sctx = thd_inst_main_security_ctx(thd);
|
||||||
if(!Audit_formatter::thd_offsets.sec_ctx_ip) //no offsets use compiled in header
|
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)
|
#if defined(MARIADB_BASE_VERSION)
|
||||||
return sctx->ip;
|
return sctx->ip;
|
||||||
#else
|
#else
|
||||||
// MySQL
|
// MySQL
|
||||||
#if MYSQL_VERSION_ID < 50534 || (MYSQL_VERSION_ID >= 50600 && MYSQL_VERSION_ID < 50614)
|
#if MYSQL_VERSION_ID < 50534 || (MYSQL_VERSION_ID >= 50600 && MYSQL_VERSION_ID < 50614)
|
||||||
return sctx->ip;
|
return sctx->ip;
|
||||||
#elif (MYSQL_VERSION_ID >= 50534 && MYSQL_VERSION_ID < 50600) \
|
#elif (MYSQL_VERSION_ID >= 50534 && MYSQL_VERSION_ID < 50600) \
|
||||||
|| (MYSQL_VERSION_ID >= 50614 && MYSQL_VERSION_ID < 50709)
|
|| (MYSQL_VERSION_ID >= 50614 && MYSQL_VERSION_ID < 50709)
|
||||||
return sctx->get_ip()->ptr();
|
return sctx->get_ip()->ptr();
|
||||||
#else
|
#else
|
||||||
// interface changed again in 5.7
|
// interface changed again in 5.7
|
||||||
return sctx->ip().str;
|
return sctx->ip().str;
|
||||||
#endif
|
#endif
|
||||||
#endif // ! defined(MARIADB_BASE_VERSION)
|
#endif // ! defined(MARIADB_BASE_VERSION)
|
||||||
}
|
}
|
||||||
return *(const char **) (((unsigned char *) sctx)
|
return *(const char **) (((unsigned char *) sctx)
|
||||||
+ Audit_formatter::thd_offsets.sec_ctx_ip);
|
+ 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);
|
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 (! Audit_formatter::thd_offsets.sec_ctx_priv_user) // no offsets use compiled in header
|
||||||
{
|
{
|
||||||
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
|
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
|
||||||
return sctx->priv_user;
|
return sctx->priv_user;
|
||||||
#else
|
#else
|
||||||
return sctx->priv_user().str;
|
return sctx->priv_user().str;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#if MYSQL_VERSION_ID < 50505
|
#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)
|
return *(const char **) (((unsigned char *) sctx)
|
||||||
+ Audit_formatter::thd_offsets.sec_ctx_priv_user);
|
+ Audit_formatter::thd_offsets.sec_ctx_priv_user);
|
||||||
#else
|
#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)
|
return (const char *) (((unsigned char *) sctx)
|
||||||
+ Audit_formatter::thd_offsets.sec_ctx_priv_user);
|
+ Audit_formatter::thd_offsets.sec_ctx_priv_user);
|
||||||
#endif
|
#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);
|
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
|
// 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)
|
static inline const char *table_get_db_name(TABLE_LIST *table)
|
||||||
{
|
{
|
||||||
return table->db;
|
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;
|
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;
|
return table->view_tables != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format the audit even in json format
|
* Format the audit even in json format
|
||||||
*/
|
*/
|
||||||
class Audit_json_formatter: public Audit_formatter
|
class Audit_json_formatter: public Audit_formatter {
|
||||||
{
|
|
||||||
public:
|
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),
|
||||||
|
|
||||||
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)
|
m_password_mask_regex_compiled(false), m_perform_password_masking(NULL)
|
||||||
{
|
|
||||||
config.beautify = 0;
|
|
||||||
config.indentString = NULL;
|
|
||||||
}
|
|
||||||
virtual ~Audit_json_formatter()
|
|
||||||
{
|
{
|
||||||
if(m_password_mask_regex_preg)
|
config.beautify = 0;
|
||||||
|
config.indentString = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~Audit_json_formatter()
|
||||||
|
{
|
||||||
|
if (m_password_mask_regex_preg)
|
||||||
{
|
{
|
||||||
m_password_mask_regex_compiled = false;
|
m_password_mask_regex_compiled = false;
|
||||||
pcre_free(m_password_mask_regex_preg);
|
pcre_free(m_password_mask_regex_preg);
|
||||||
|
@ -364,20 +359,20 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ssize_t event_format(ThdSesData *pThdData, IWriter * writer);
|
virtual ssize_t event_format(ThdSesData *pThdData, IWriter *writer);
|
||||||
virtual ssize_t start_msg_format(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.
|
* Utility method used to compile a regex program. Will compile and log errors if necessary.
|
||||||
* Return null if fails
|
* Return null if fails
|
||||||
*/
|
*/
|
||||||
static pcre * regex_compile(const char * str);
|
static pcre *regex_compile(const char *str);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compile password masking regex
|
* 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.
|
* Boolean indicating if to log start msg.
|
||||||
|
@ -389,20 +384,20 @@ public:
|
||||||
/**
|
/**
|
||||||
* Callback function to determine if password masking should be performed
|
* 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).
|
* Message delimiter. Should point to a valid json string (supporting the json escapping format).
|
||||||
* Will only be checked at the start. Public so can be set by sysvar.
|
* Will only be checked at the start. Public so can be set by sysvar.
|
||||||
*
|
*
|
||||||
* We only support a delimiter up to 32 chars
|
* 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.
|
* Configuration of yajl. Leave public so sysvar can update this directly.
|
||||||
*/
|
*/
|
||||||
yajl_gen_config config;
|
yajl_gen_config config;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
@ -417,83 +412,79 @@ protected:
|
||||||
/**
|
/**
|
||||||
* Regex used for password masking
|
* 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.
|
* Base class for audit handlers. Provides basic locking setup.
|
||||||
*/
|
*/
|
||||||
class Audit_handler
|
class Audit_handler {
|
||||||
{
|
|
||||||
public:
|
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[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will iterate the handler list and log using each handler
|
||||||
|
*/
|
||||||
|
static void log_audit_all(ThdSesData *pThdData);
|
||||||
|
|
||||||
static const size_t MAX_AUDIT_HANDLERS_NUM = 4;
|
/**
|
||||||
static const size_t JSON_FILE_HANDLER = 1;
|
* Will iterate the handler list and stop all handlers
|
||||||
static const size_t JSON_SOCKET_HANDLER = 3;
|
*/
|
||||||
|
static void stop_all();
|
||||||
|
|
||||||
static Audit_handler * m_audit_handler_list[];
|
Audit_handler() :
|
||||||
|
m_initialized(false), m_enabled(false), m_print_offset_err(true),
|
||||||
|
m_formatter(NULL), m_failed(false), m_log_io_errors(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
virtual ~Audit_handler()
|
||||||
* Will iterate the handler list and log using each handler
|
{
|
||||||
*/
|
if (m_initialized)
|
||||||
static void log_audit_all(ThdSesData *pThdData);
|
{
|
||||||
|
rwlock_destroy(&LOCK_audit);
|
||||||
/**
|
|
||||||
* Will iterate the handler list and stop all handlers
|
|
||||||
*/
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~Audit_handler()
|
|
||||||
{
|
|
||||||
if (m_initialized)
|
|
||||||
{
|
|
||||||
rwlock_destroy(&LOCK_audit);
|
|
||||||
pthread_mutex_destroy(&LOCK_io);
|
pthread_mutex_destroy(&LOCK_io);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should be called to initialize. We don't init in constructor in order to provide indication if
|
* Should be called to initialize. We don't init in constructor in order to provide indication if
|
||||||
* pthread stuff failed init.
|
* pthread stuff failed init.
|
||||||
*
|
*
|
||||||
* @frmt the formatter to use in this handler (does not manage distruction of this object)
|
* @frmt the formatter to use in this handler (does not manage distruction of this object)
|
||||||
* @return 0 on success
|
* @return 0 on success
|
||||||
*/
|
*/
|
||||||
int init(Audit_formatter * frmt)
|
int init(Audit_formatter *frmt)
|
||||||
{
|
{
|
||||||
m_formatter = frmt;
|
m_formatter = frmt;
|
||||||
if (m_initialized)
|
if (m_initialized)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int res = my_rwlock_init(&LOCK_audit, NULL);
|
int res = my_rwlock_init(&LOCK_audit, NULL);
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
res = pthread_mutex_init(&LOCK_io, MY_MUTEX_INIT_SLOW);;
|
res = pthread_mutex_init(&LOCK_io, MY_MUTEX_INIT_SLOW);;
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
m_initialized = true;
|
m_initialized = true;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_init()
|
bool is_init()
|
||||||
{
|
{
|
||||||
return m_initialized;
|
return m_initialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_enable(bool val);
|
void set_enable(bool val);
|
||||||
|
|
||||||
bool is_enabled()
|
bool is_enabled()
|
||||||
{
|
{
|
||||||
|
@ -505,10 +496,10 @@ public:
|
||||||
*/
|
*/
|
||||||
void flush();
|
void flush();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will get relevant shared lock and call internal method of handler
|
* Will get relevant shared lock and call internal method of handler
|
||||||
*/
|
*/
|
||||||
void log_audit(ThdSesData *pThdData);
|
void log_audit(ThdSesData *pThdData);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public so can be configured via sysvar
|
* Public so can be configured via sysvar
|
||||||
|
@ -516,16 +507,16 @@ public:
|
||||||
unsigned int m_retry_interval;
|
unsigned int m_retry_interval;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Audit_formatter * m_formatter;
|
Audit_formatter *m_formatter;
|
||||||
virtual void handler_start();
|
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();
|
bool handler_start_nolock();
|
||||||
virtual void handler_stop();
|
virtual void handler_stop();
|
||||||
virtual bool handler_start_internal() = 0;
|
virtual bool handler_start_internal() = 0;
|
||||||
virtual void handler_stop_internal() = 0;
|
virtual void handler_stop_internal() = 0;
|
||||||
virtual bool handler_log_audit(ThdSesData *pThdData) =0;
|
virtual bool handler_log_audit(ThdSesData *pThdData) =0;
|
||||||
bool m_initialized;
|
bool m_initialized;
|
||||||
bool m_enabled;
|
bool m_enabled;
|
||||||
bool m_failed;
|
bool m_failed;
|
||||||
bool m_log_io_errors;
|
bool m_log_io_errors;
|
||||||
time_t m_last_retry_sec_ts;
|
time_t m_last_retry_sec_ts;
|
||||||
|
@ -538,154 +529,147 @@ protected:
|
||||||
inline bool is_failed_now()
|
inline bool is_failed_now()
|
||||||
{
|
{
|
||||||
return m_failed && (m_retry_interval < 0 ||
|
return m_failed && (m_retry_interval < 0 ||
|
||||||
difftime(time(NULL), m_last_retry_sec_ts) > m_retry_interval);
|
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 & operator=(const Audit_handler&);
|
||||||
Audit_handler(const Audit_handler&);
|
Audit_handler(const Audit_handler&);
|
||||||
private:
|
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;
|
bool m_print_offset_err;
|
||||||
//lock io
|
// lock io
|
||||||
pthread_mutex_t LOCK_io;
|
pthread_mutex_t LOCK_io;
|
||||||
//audit (enable) lock
|
// audit (enable) lock
|
||||||
rw_lock_t LOCK_audit;
|
rw_lock_t LOCK_audit;
|
||||||
inline void lock_shared()
|
inline void lock_shared()
|
||||||
{
|
{
|
||||||
rw_rdlock(&LOCK_audit);
|
rw_rdlock(&LOCK_audit);
|
||||||
}
|
}
|
||||||
inline void lock_exclusive()
|
inline void lock_exclusive()
|
||||||
{
|
{
|
||||||
rw_wrlock(&LOCK_audit);
|
rw_wrlock(&LOCK_audit);
|
||||||
}
|
}
|
||||||
inline void unlock()
|
inline void unlock()
|
||||||
{
|
{
|
||||||
rw_unlock(&LOCK_audit);
|
rw_unlock(&LOCK_audit);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for handler which have io and need a lock
|
* 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:
|
public:
|
||||||
Audit_io_handler() : m_io_dest(NULL), m_io_type(NULL)
|
Audit_io_handler()
|
||||||
|
: m_io_dest(NULL), m_io_type(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Audit_io_handler()
|
virtual ~Audit_io_handler()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* target we write to (socket/file). Public so we update via sysvar
|
* target we write to (socket/file). Public so we update via sysvar
|
||||||
*/
|
*/
|
||||||
char * m_io_dest;
|
char *m_io_dest;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool handler_start_internal();
|
virtual bool handler_start_internal();
|
||||||
virtual void handler_stop_internal();
|
virtual void handler_stop_internal();
|
||||||
//used for logging messages
|
// used for logging messages
|
||||||
const char * m_io_type;
|
const char *m_io_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Audit_file_handler: public Audit_io_handler
|
class Audit_file_handler: public Audit_io_handler {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Audit_file_handler() :
|
Audit_file_handler() :
|
||||||
m_sync_period(0), m_log_file(NULL), m_sync_counter(0), m_bufsize(0)
|
m_sync_period(0), m_log_file(NULL), m_sync_counter(0), m_bufsize(0)
|
||||||
{
|
{
|
||||||
m_io_type = "file";
|
m_io_type = "file";
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Audit_file_handler()
|
virtual ~Audit_file_handler()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The period to use for syncing to the file system. 0 means we don't sync.
|
* The period to use for syncing to the file system. 0 means we don't sync.
|
||||||
* 1 means each write we sync. Larger than 1 means every sync_period we sync.
|
* 1 means each write we sync. Larger than 1 means every sync_period we sync.
|
||||||
*
|
*
|
||||||
* We leave this public so the mysql sysvar function can update this variable directly.
|
* We leave this public so the mysql sysvar function can update this variable directly.
|
||||||
*/
|
*/
|
||||||
unsigned int m_sync_period;
|
unsigned int m_sync_period;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The buf size used by the file stream. 0 = use default, negative or 1 = no buffering
|
* The buf size used by the file stream. 0 = use default, negative or 1 = no buffering
|
||||||
*/
|
*/
|
||||||
long m_bufsize;
|
long m_bufsize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write function we pass to formatter
|
* 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();
|
void close();
|
||||||
|
|
||||||
int open(const char * io_dest, bool m_log_errors);
|
int open(const char *io_dest, bool m_log_errors);
|
||||||
//static void print_sleep (THD *thd, int delay_ms);
|
// static void print_sleep(THD *thd, int delay_ms);
|
||||||
protected:
|
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 & operator=(const Audit_file_handler&);
|
||||||
Audit_file_handler(const Audit_file_handler&);
|
Audit_file_handler(const Audit_file_handler&);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will acquire locks and call handler_write
|
||||||
/**
|
*/
|
||||||
* Will acquire locks and call handler_write
|
virtual bool handler_log_audit(ThdSesData *pThdData);
|
||||||
*/
|
FILE *m_log_file;
|
||||||
virtual bool handler_log_audit(ThdSesData *pThdData);
|
// the period to use for syncing
|
||||||
FILE * m_log_file;
|
unsigned int m_sync_counter;
|
||||||
//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:
|
public:
|
||||||
|
|
||||||
Audit_socket_handler() :
|
Audit_socket_handler() :
|
||||||
m_vio(NULL), m_connect_timeout(1)
|
m_vio(NULL), m_connect_timeout(1)
|
||||||
{
|
{
|
||||||
m_io_type = "socket";
|
m_io_type = "socket";
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Audit_socket_handler()
|
virtual ~Audit_socket_handler()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect timeout in secconds
|
* Connect timeout in secconds
|
||||||
*/
|
*/
|
||||||
unsigned int m_connect_timeout;
|
unsigned int m_connect_timeout;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write function we pass to formatter
|
* 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();
|
void close();
|
||||||
|
|
||||||
int open(const char * io_dest, bool log_errors);
|
int open(const char *io_dest, bool log_errors);
|
||||||
protected:
|
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 & operator=(const Audit_socket_handler&);
|
||||||
Audit_socket_handler(const Audit_socket_handler&);
|
Audit_socket_handler(const Audit_socket_handler&);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will acquire locks and call handler_write
|
* Will acquire locks and call handler_write
|
||||||
*/
|
*/
|
||||||
virtual bool handler_log_audit(ThdSesData *pThdData);
|
virtual bool handler_log_audit(ThdSesData *pThdData);
|
||||||
//Vio we write to
|
// Vio we write to
|
||||||
//define as void* so we don't access members directly
|
// define as void* so we don't access members directly
|
||||||
void * m_vio;
|
void *m_vio;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* AUDIT_HANDLER_H_ */
|
#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_Update(MD5_CTX *ctx, void *data, unsigned long size);
|
||||||
extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);
|
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_MD5Context MD5_CTX
|
||||||
#define my_MD5Init MD5_Init
|
#define my_MD5Init MD5_Init
|
||||||
#define my_MD5Update MD5_Update
|
#define my_MD5Update MD5_Update
|
||||||
#define my_MD5Final MD5_Final
|
#define my_MD5Final MD5_Final
|
||||||
|
|
||||||
|
|
||||||
#endif //#if MYSQL_VERSION_ID >= 50600
|
#endif // #if MYSQL_VERSION_ID >= 50600
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
#define MYSQL_DYNAMIC_PLUGIN 1
|
#define MYSQL_DYNAMIC_PLUGIN 1
|
||||||
#define MYSQL_SERVER 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
|
// 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
|
// 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
|
#define DONT_MAP_VIO
|
||||||
|
|
||||||
#include <my_config.h>
|
#include <my_config.h>
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
#include <mysql_priv.h>
|
#include <mysql_priv.h>
|
||||||
#else
|
#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
|
#if MYSQL_VERSION_ID >= 50505
|
||||||
|
|
||||||
// These two are not present in 5.7.9
|
// These two are not present in 5.7.9
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
#include <sql/sql_table.h>
|
#include <sql/sql_table.h>
|
||||||
#include <sql/sql_view.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_lock mysql_mutex_lock
|
||||||
#define pthread_mutex_unlock mysql_mutex_unlock
|
#define pthread_mutex_unlock mysql_mutex_unlock
|
||||||
|
@ -67,8 +67,8 @@
|
||||||
#include <my_dir.h>
|
#include <my_dir.h>
|
||||||
#include <my_sys.h>
|
#include <my_sys.h>
|
||||||
|
|
||||||
//5.5 use my_free with a single param. 5.1 use with 2 params
|
// 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
|
// based on: http://bazaar.launchpad.net/~mysql/myodbc/5.1/view/head:/util/stringutil.h
|
||||||
#ifndef x_free
|
#ifndef x_free
|
||||||
# if MYSQL_VERSION_ID >= 50500
|
# if MYSQL_VERSION_ID >= 50500
|
||||||
# define x_free(A) { void *tmp= (A); if (tmp) my_free((char *) tmp); }
|
# define x_free(A) { void *tmp= (A); if (tmp) my_free((char *) tmp); }
|
||||||
|
@ -77,23 +77,19 @@
|
||||||
# endif
|
# endif
|
||||||
#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)
|
#if defined(MARIADB_BASE_VERSION)
|
||||||
|
|
||||||
#define my_getsystime() ((my_hrtime()).val * 10)
|
#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
|
#undef thd_killed
|
||||||
extern "C" int thd_killed(const MYSQL_THD thd);
|
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
|
#if MYSQL_VERSION_ID >= 100010
|
||||||
extern "C" char *thd_security_context(MYSQL_THD thd, char *buffer, unsigned int length, unsigned int max_query_len);
|
extern "C" char *thd_security_context(MYSQL_THD thd, char *buffer, unsigned int length, unsigned int max_query_len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif // MYSQL_INCL_H
|
||||||
|
|
||||||
#endif //MYSQL_INCL_H
|
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
1668
src/audit_offsets.cc
1668
src/audit_offsets.cc
File diff suppressed because it is too large
Load Diff
2071
src/audit_plugin.cc
2071
src/audit_plugin.cc
File diff suppressed because it is too large
Load Diff
280
src/hot_patch.cc
280
src/hot_patch.cc
|
@ -11,33 +11,33 @@
|
||||||
#define ULONG_PTR uint32_t
|
#define ULONG_PTR uint32_t
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const char * log_prefix = "Audit Plugin:";
|
static const char *log_prefix = "Audit Plugin:";
|
||||||
|
|
||||||
static const unsigned long PAGE_SIZE = GETPAGESIZE() ;
|
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 bool use_exec_prot = true;
|
||||||
|
|
||||||
static int protect(void *addr, size_t len)
|
static int protect(void *addr, size_t len)
|
||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
if(use_exec_prot)
|
if (use_exec_prot)
|
||||||
{
|
{
|
||||||
res = mprotect(addr,len,PROT_READ|PROT_EXEC);
|
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);
|
mprotect(addr,len,PROT_READ);
|
||||||
res = mprotect(addr,len,PROT_READ|PROT_EXEC);
|
res = mprotect(addr,len,PROT_READ|PROT_EXEC);
|
||||||
}
|
}
|
||||||
if(res)
|
if (res)
|
||||||
{
|
{
|
||||||
sql_print_information(
|
sql_print_information(
|
||||||
"%s unable to protect mode: PROT_READ|PROT_EXEC. Page: %p, Size: %zu, errno: %d, res %d.",
|
"%s unable to protect mode: PROT_READ|PROT_EXEC. Page: %p, Size: %zu, errno: %d, res %d.",
|
||||||
log_prefix, (void *)addr, len, errno, res);
|
log_prefix, (void *)addr, len, errno, res);
|
||||||
//fail only if nx bit is enabled
|
// fail only if nx bit is enabled
|
||||||
FILE * fp = fopen("/proc/cpuinfo", "r");
|
FILE *fp = fopen("/proc/cpuinfo", "r");
|
||||||
if(NULL == fp)
|
if (NULL == fp)
|
||||||
{
|
{
|
||||||
sql_print_error(
|
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.",
|
"%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;
|
return res;
|
||||||
}
|
}
|
||||||
char buff[1024] = {0};
|
char buff[1024] = {0};
|
||||||
const char * flags = "flags";
|
const char *flags = "flags";
|
||||||
bool nxchecked = false;
|
bool nxchecked = false;
|
||||||
while(fgets(buff, 1024, fp) != NULL)
|
while (fgets(buff, 1024, fp) != NULL)
|
||||||
{
|
{
|
||||||
char * line = buff;
|
char *line = buff;
|
||||||
//trim white space at start
|
// trim white space at start
|
||||||
while ((strlen(line) > 0) && (isspace(line[0])))
|
while ((strlen(line) > 0) && (isspace(line[0])))
|
||||||
{
|
{
|
||||||
line++;
|
line++;
|
||||||
}
|
}
|
||||||
if(strncmp(line, flags, strlen(flags)) == 0)
|
if (strncmp(line, flags, strlen(flags)) == 0)
|
||||||
{
|
{
|
||||||
nxchecked = true;
|
nxchecked = true;
|
||||||
sql_print_information("%s cpuinfo flags line: %s. ",log_prefix, line);
|
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(
|
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.",
|
"%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);
|
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(
|
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.",
|
"%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,66 +82,67 @@ static int protect(void *addr, size_t len)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//will try to unprotect with PROT_READ|PROT_WRITE|PROT_EXEC. If fails (might happen under SELinux)
|
// will try to unprotect with PROT_READ|PROT_WRITE|PROT_EXEC. If fails (might happen under SELinux)
|
||||||
//will use PROT_READ|PROT_WRITE
|
// will use PROT_READ|PROT_WRITE
|
||||||
static int unprotect(void *addr, size_t len)
|
static int unprotect(void *addr, size_t len)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
if(use_exec_prot)
|
if (use_exec_prot)
|
||||||
{
|
{
|
||||||
res = mprotect(addr,len,PROT_READ|PROT_WRITE|PROT_EXEC);
|
res = mprotect(addr, len, PROT_READ|PROT_WRITE|PROT_EXEC);
|
||||||
if(res)
|
if (res)
|
||||||
{
|
{
|
||||||
sql_print_information(
|
sql_print_information(
|
||||||
"%s unable to unprotect. Page: %p, Size: %zu, errno: %d. Using NO EXEC mode.",
|
"%s unable to unprotect. Page: %p, Size: %zu, errno: %d. Using NO EXEC mode.",
|
||||||
log_prefix, (void *)addr, len, errno);
|
log_prefix, (void *)addr, len, errno);
|
||||||
use_exec_prot = false;
|
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);
|
res = unprotect(addr, len);
|
||||||
if(res)
|
if (res)
|
||||||
{
|
{
|
||||||
sql_print_error(
|
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.",
|
"%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.",
|
||||||
log_prefix, (void *)addr, len, errno);
|
log_prefix, (void *)addr, len, errno);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
res = protect(addr, len);
|
res = protect(addr, len);
|
||||||
sql_print_information("%s protect res: %d", log_prefix, res);
|
sql_print_information("%s protect res: %d", log_prefix, res);
|
||||||
if(res)
|
if (res)
|
||||||
{
|
{
|
||||||
sql_print_error(
|
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.",
|
"%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.",
|
||||||
log_prefix, (void *)addr, len, errno);
|
log_prefix, (void *)addr, len, errno);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else //all is good
|
else // all is good
|
||||||
{
|
{
|
||||||
return res;
|
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(
|
sql_print_error(
|
||||||
"%s unable to unprotect. Page: %p, Size: %zu, errno: %d. Error.",
|
"%s unable to unprotect. Page: %p, Size: %zu, errno: %d. Error.",
|
||||||
log_prefix, (void *)addr, len, errno);
|
log_prefix, (void *)addr, len, errno);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
//macro to log via sql_print_information only if cond test is enabled
|
// 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)
|
#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
|
* 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 pageMask = ( ~(PAGE_SIZE - 1) ) ;
|
||||||
DATATYPE_ADDRESS longp = (unsigned long) pointer;
|
DATATYPE_ADDRESS longp = (unsigned long) pointer;
|
||||||
return (longp & pageMask);
|
return (longp & pageMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -164,112 +165,115 @@ unsigned int jump_size()
|
||||||
|
|
||||||
static void WriteJump(void *pAddress, ULONG_PTR JumpTo)
|
static void WriteJump(void *pAddress, ULONG_PTR JumpTo)
|
||||||
{
|
{
|
||||||
DATATYPE_ADDRESS AddressPage = get_page_address(pAddress);
|
DATATYPE_ADDRESS AddressPage = get_page_address(pAddress);
|
||||||
unprotect((void*)AddressPage, PAGE_SIZE);
|
unprotect((void*)AddressPage, PAGE_SIZE);
|
||||||
|
|
||||||
BYTE *pCur = (BYTE *) pAddress;
|
BYTE *pCur = (BYTE *) pAddress;
|
||||||
#ifndef __x86_64__
|
#ifndef __x86_64__
|
||||||
|
|
||||||
BYTE * pbJmpSrc = pCur + 5;
|
BYTE * pbJmpSrc = pCur + 5;
|
||||||
*pCur++ = 0xE9; // jmp +imm32
|
*pCur++ = 0xE9; // jmp +imm32
|
||||||
*((ULONG_PTR *)pCur) = JumpTo - (ULONG_PTR)pbJmpSrc;
|
*((ULONG_PTR *)pCur) = JumpTo - (ULONG_PTR)pbJmpSrc;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
*pCur = 0xff; // jmp [rip+addr]
|
*pCur = 0xff; // jmp [rip+addr]
|
||||||
*(++pCur) = 0x25;
|
*(++pCur) = 0x25;
|
||||||
*((DWORD *) ++pCur) = 0; // addr = 0
|
*((DWORD *) ++pCur) = 0; // addr = 0
|
||||||
pCur += sizeof (DWORD);
|
pCur += sizeof (DWORD);
|
||||||
*((ULONG_PTR *)pCur) = JumpTo;
|
*((ULONG_PTR *)pCur) = JumpTo;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
//}
|
// DWORD dwBuf = 0; // necessary othewrise the function fails
|
||||||
|
|
||||||
//DWORD dwBuf = 0; // nessary othewrise the function fails
|
protect((void*)AddressPage, PAGE_SIZE);
|
||||||
|
|
||||||
protect((void*)AddressPage, PAGE_SIZE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Hooks a function
|
// Hooks a function
|
||||||
//
|
//
|
||||||
static bool HookFunction(ULONG_PTR targetFunction, ULONG_PTR newFunction, ULONG_PTR trampolineFunction,
|
static bool HookFunction(ULONG_PTR targetFunction, ULONG_PTR newFunction, ULONG_PTR trampolineFunction,
|
||||||
unsigned int *trampolinesize)
|
unsigned int *trampolinesize)
|
||||||
{
|
{
|
||||||
#define MAX_INSTRUCTIONS 100
|
#define MAX_INSTRUCTIONS 100
|
||||||
uint8_t raw[MAX_INSTRUCTIONS];
|
uint8_t raw[MAX_INSTRUCTIONS];
|
||||||
unsigned int uCurrentSize =0;
|
unsigned int uCurrentSize =0;
|
||||||
|
|
||||||
#ifndef __x86_64__
|
#ifndef __x86_64__
|
||||||
#define ASM_MODE 32
|
#define ASM_MODE 32
|
||||||
#else
|
#else
|
||||||
#define ASM_MODE 64
|
#define ASM_MODE 64
|
||||||
#endif
|
#endif
|
||||||
memcpy (raw,(void*)targetFunction,MAX_INSTRUCTIONS);
|
memcpy(raw, (void*)targetFunction, MAX_INSTRUCTIONS);
|
||||||
ud_t ud_obj;
|
ud_t ud_obj;
|
||||||
ud_init(&ud_obj);
|
ud_init(&ud_obj);
|
||||||
ud_set_input_buffer(&ud_obj, raw, MAX_INSTRUCTIONS);
|
ud_set_input_buffer(&ud_obj, raw, MAX_INSTRUCTIONS);
|
||||||
ud_set_mode(&ud_obj, ASM_MODE);
|
ud_set_mode(&ud_obj, ASM_MODE);
|
||||||
ud_set_syntax(&ud_obj, UD_SYN_INTEL);
|
ud_set_syntax(&ud_obj, UD_SYN_INTEL);
|
||||||
ud_set_pc(&ud_obj, targetFunction);
|
ud_set_pc(&ud_obj, targetFunction);
|
||||||
|
|
||||||
DWORD InstrSize = 0;
|
DWORD InstrSize = 0;
|
||||||
DATATYPE_ADDRESS trampolineFunctionPage = get_page_address((void*)trampolineFunction);
|
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(
|
sql_print_error(
|
||||||
"%s unable to unprotect trampoline function page: %p. Aborting.",
|
"%s unable to unprotect trampoline function page: %p. Aborting.",
|
||||||
log_prefix, (void *)trampolineFunctionPage);
|
log_prefix, (void *)trampolineFunctionPage);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool disassemble_valid = false;
|
|
||||||
while (ud_disassemble(&ud_obj))
|
|
||||||
{
|
|
||||||
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 ||
|
|
||||||
ud_obj.operand[0].type == UD_OP_JIMM)
|
|
||||||
{
|
|
||||||
sql_print_error(
|
|
||||||
"%s unable to disassemble at address: 0x%p. Found relative addressing for instruction: [%s]. Aborting.",
|
|
||||||
log_prefix, (void *)(InstrSize + targetFunction), ud_insn_asm(&ud_obj));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
BYTE *pCurInstr = (BYTE *) (InstrSize + (ULONG_PTR) targetFunction);
|
bool disassemble_valid = false;
|
||||||
memcpy((BYTE*)trampolineFunction + uCurrentSize,
|
while (ud_disassemble(&ud_obj))
|
||||||
(void *) pCurInstr, ud_insn_len (&ud_obj));
|
{
|
||||||
|
if (ud_obj.mnemonic == UD_Iinvalid)
|
||||||
|
{
|
||||||
|
sql_print_error(
|
||||||
|
"%s unable to disassemble at address: %p. Aborting.",
|
||||||
|
log_prefix, (void *)(InstrSize + targetFunction));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
uCurrentSize += ud_insn_len (&ud_obj);
|
// make sure there isn't a jmp/call (or similar operand) as these use
|
||||||
InstrSize += ud_insn_len (&ud_obj);
|
// relative addressing and if we copy as is we will mess up the jmp/call target
|
||||||
if (InstrSize >= jump_size()) //we have enough space so break
|
if (ud_obj.mnemonic == UD_Ijmp || ud_obj.mnemonic == UD_Icall ||
|
||||||
{
|
ud_obj.operand[0].type == UD_OP_JIMM)
|
||||||
disassemble_valid = true;
|
{
|
||||||
break;
|
sql_print_error(
|
||||||
}
|
"%s unable to disassemble at address: 0x%p. Found relative addressing for instruction: [%s]. Aborting.",
|
||||||
}
|
log_prefix, (void *)(InstrSize + targetFunction), ud_insn_asm(&ud_obj));
|
||||||
if(protect((void*)trampolineFunctionPage, PAGE_SIZE)) //0 valid return
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BYTE *pCurInstr = (BYTE *) (InstrSize + (ULONG_PTR) targetFunction);
|
||||||
|
memcpy((BYTE*)trampolineFunction + uCurrentSize,
|
||||||
|
(void *) pCurInstr, ud_insn_len (&ud_obj));
|
||||||
|
|
||||||
|
uCurrentSize += ud_insn_len (&ud_obj);
|
||||||
|
InstrSize += ud_insn_len (&ud_obj);
|
||||||
|
if (InstrSize >= jump_size()) // we have enough space so break
|
||||||
|
{
|
||||||
|
disassemble_valid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (protect((void*)trampolineFunctionPage, PAGE_SIZE)) // 0 valid return
|
||||||
{
|
{
|
||||||
sql_print_error(
|
sql_print_error(
|
||||||
"%s unable to protect page. Error. Page: %p.",
|
"%s unable to protect page. Error. Page: %p.",
|
||||||
log_prefix, (void *)trampolineFunctionPage);
|
log_prefix, (void *)trampolineFunctionPage);
|
||||||
return false;
|
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;
|
{
|
||||||
}
|
return false;
|
||||||
WriteJump( (BYTE*)trampolineFunction + uCurrentSize, targetFunction + InstrSize);
|
}
|
||||||
WriteJump((void *) targetFunction, newFunction);
|
|
||||||
*trampolinesize = uCurrentSize;
|
WriteJump((BYTE*)trampolineFunction + uCurrentSize, targetFunction + InstrSize);
|
||||||
return true;
|
WriteJump((void *) targetFunction, newFunction);
|
||||||
|
*trampolinesize = uCurrentSize;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -277,18 +281,18 @@ 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);
|
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(
|
sql_print_error(
|
||||||
"%s Unhook not able to unprotect function page: %p. Aborting.",
|
"%s Unhook not able to unprotect function page: %p. Aborting.",
|
||||||
log_prefix, (void * )FunctionPage);
|
log_prefix, (void * )FunctionPage);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memcpy((void *) Function, (void*)trampolineFunction,trampolinesize);
|
memcpy((void *) Function, (void*)trampolineFunction,trampolinesize);
|
||||||
protect((void*)FunctionPage, PAGE_SIZE);
|
protect((void*)FunctionPage, PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -306,21 +310,21 @@ static void UnhookFunction(ULONG_PTR Function,ULONG_PTR trampolineFunction , uns
|
||||||
* which contains a bunch of nops.
|
* which contains a bunch of nops.
|
||||||
* @param info_print if true will print info as progressing
|
* @param info_print if true will print info as progressing
|
||||||
* @Return 0 on success otherwise failure
|
* @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);
|
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);
|
cond_info_print(info_print, "%s hot patching function: %p, trampolineFunction: %p trampolinePage: %p",log_prefix, (void *)targetFunction, (void *)trampolineFunction, (void *)trampolinePage);
|
||||||
if (HookFunction((ULONG_PTR) targetFunction, (ULONG_PTR) newFunction,
|
if (HookFunction((ULONG_PTR) targetFunction, (ULONG_PTR) newFunction,
|
||||||
(ULONG_PTR) trampolineFunction, trampolinesize))
|
(ULONG_PTR) trampolineFunction, trampolinesize))
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 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
|
* @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;
|
return;
|
||||||
}
|
}
|
||||||
DATATYPE_ADDRESS targetPage = get_page_address(targetFunction);
|
DATATYPE_ADDRESS targetPage = get_page_address(targetFunction);
|
||||||
|
|
Loading…
Reference in New Issue