diff --git a/include/audit_handler.h b/include/audit_handler.h index cd92784..97f8122 100755 --- a/include/audit_handler.h +++ b/include/audit_handler.h @@ -38,7 +38,6 @@ typedef size_t OFFSET; //mysql max identifier is 64 so 2*64 + . and null #define MAX_OBJECT_CHAR_NUMBERS 131 #define MAX_USER_CHAR_NUMBERS 20 -const char * retrieve_user (THD * thd); #define MAX_NUM_OBJECT_ELEM 256 #define MAX_NUM_USER_ELEM 256 @@ -55,6 +54,10 @@ typedef struct ThdOffsets OFFSET command; OFFSET lex; OFFSET lex_comment; + OFFSET sec_ctx_user; + OFFSET sec_ctx_host; + OFFSET sec_ctx_ip; + OFFSET sec_ctx_priv_user; } ThdOffsets; /* @@ -145,7 +148,7 @@ public: */ virtual ssize_t stop_msg_format(IWriter * writer) { return 0; } - static const char * retrive_object_type (TABLE_LIST *pObj); + 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) @@ -163,6 +166,58 @@ public: return (Security_context *) (((unsigned char *) thd) + Audit_formatter::thd_offsets.main_security_ctx); } + + 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 + { + return sctx->user; + } + return *(const char **) (((unsigned char *) sctx) + + Audit_formatter::thd_offsets.sec_ctx_user); + } + + 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 + { + return sctx->host; + } + return *(const char **) (((unsigned char *) sctx) + + Audit_formatter::thd_offsets.sec_ctx_host); + } + + 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 + { + return sctx->ip; + } + return *(const char **) (((unsigned char *) sctx) + + Audit_formatter::thd_offsets.sec_ctx_ip); + } + + 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 + { + return sctx->priv_user; + } +#if MYSQL_VERSION_ID < 50505 + //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]) + return (const char *) (((unsigned char *) sctx) + + Audit_formatter::thd_offsets.sec_ctx_priv_user); +#endif + } + static inline int thd_inst_command(THD * thd) { return *(int *) (((unsigned char *) thd) + Audit_formatter::thd_offsets.command); @@ -172,6 +227,22 @@ public: { 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) + { + return table->db; + } + + static inline const char * table_get_name(TABLE_LIST * table) + { + return table->table_name; + } + + static inline bool table_is_view(TABLE_LIST * table) + { + return table->view_tables != 0; + } }; diff --git a/offset-extract/offset-extract.sh b/offset-extract/offset-extract.sh index 5350ecb..d131997 100755 --- a/offset-extract/offset-extract.sh +++ b/offset-extract/offset-extract.sh @@ -31,7 +31,7 @@ if [ $? = 0 ]; then fi echo "set logging on" > offsets.gdb -echo 'printf "{\"'$MYVER'\",\"'$MYMD5'\", %d, %d, %d, %d, %d, %d}", ((size_t)&((THD *)log_slow_statement)->query_id) - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->thread_id) - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->main_security_ctx) - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->'$COMMAND_MEMBER') - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->lex) - (size_t)log_slow_statement, (size_t)&((LEX*)log_slow_statement)->comment - (size_t) log_slow_statement' >> offsets.gdb +echo 'printf "{\"'$MYVER'\",\"'$MYMD5'\", %d, %d, %d, %d, %d, %d, %d, %d, %d, %d}", ((size_t)&((THD *)log_slow_statement)->query_id) - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->thread_id) - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->main_security_ctx) - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->'$COMMAND_MEMBER') - (size_t)log_slow_statement, ((size_t)&((THD *)log_slow_statement)->lex) - (size_t)log_slow_statement, (size_t)&((LEX*)log_slow_statement)->comment - (size_t) log_slow_statement, ((size_t)&((Security_context *)log_slow_statement)->user) - (size_t)log_slow_statement, ((size_t)&((Security_context *)log_slow_statement)->host) - (size_t)log_slow_statement, ((size_t)&((Security_context *)log_slow_statement)->ip) - (size_t)log_slow_statement, ((size_t)&((Security_context *)log_slow_statement)->priv_user) - (size_t)log_slow_statement' >> offsets.gdb SYMPARAM="" if [ -n "$2" ]; then diff --git a/src/audit_handler.cc b/src/audit_handler.cc index 61f4977..f38debd 100755 --- a/src/audit_handler.cc +++ b/src/audit_handler.cc @@ -47,9 +47,9 @@ const char * Audit_json_formatter::DEF_MSG_DELIMITER = "\\n"; #define C_STRING_WITH_LEN(X) ((char *) (X)), ((size_t) (sizeof(X) - 1)) -const char * Audit_formatter::retrive_object_type (TABLE_LIST *pObj) +const char * Audit_formatter::retrieve_object_type (TABLE_LIST *pObj) { - if (pObj->view) + if (table_is_view(pObj)) { return "VIEW"; } @@ -327,6 +327,23 @@ static inline void yajl_add_obj( yajl_gen gen, const char *db,const char* ptype yajl_add_string_val(gen, "obj_type",ptype); } +static inline 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 + { + return user; + } + user = Audit_formatter::thd_inst_main_security_ctx_priv_user(thd); //try using priv user + if(user != NULL && *user != 0x0) //non empty + { + return user; + } + 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 #if MYSQL_VERSION_ID > 50140 @@ -375,9 +392,9 @@ static const char * thd_query_str(THD * thd, size_t * len) ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * writer) { - unsigned long thdid = thd_get_thread_id(pThdData->getTHD()); - query_id_t qid = thd_inst_query_id(pThdData->getTHD()); - Security_context * sctx = thd_inst_main_security_ctx(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 yajl_gen gen = yajl_gen_alloc(&config, NULL); @@ -390,10 +407,10 @@ ssize_t Audit_json_formatter::event_format(ThdSesData* pThdData, IWriter * write yajl_add_uint64(gen, "date", ts); yajl_add_uint64(gen, "thread-id", thdid); yajl_add_uint64(gen, "query-id", qid); - yajl_add_string_val(gen, "user", sctx->user); - yajl_add_string_val(gen, "priv_user", sctx->priv_user); - yajl_add_string_val(gen, "host", sctx->host); - yajl_add_string_val(gen, "ip", sctx->ip); + yajl_add_string_val(gen, "user", pThdData->getUserName()); + yajl_add_string_val(gen, "priv_user", Audit_formatter::thd_inst_main_security_ctx_priv_user(thd)); + yajl_add_string_val(gen, "host", Audit_formatter::thd_inst_main_security_ctx_host(thd)); + 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 @@ -554,14 +571,14 @@ bool ThdSesData::getNextObject(const char ** db_name, const char ** obj_name, co { if(m_tables) { - *db_name = m_tables->get_db_name(); - *obj_name = m_tables->get_table_name(); + *db_name = Audit_formatter::table_get_db_name(m_tables); + *obj_name = Audit_formatter::table_get_name(m_tables); 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) || - m_tables->view) + Audit_formatter::table_is_view(m_tables)) { *obj_type = "VIEW"; m_firstTable = false; diff --git a/src/audit_plugin.cc b/src/audit_plugin.cc index 29c555b..c84af8f 100755 --- a/src/audit_plugin.cc +++ b/src/audit_plugin.cc @@ -346,8 +346,28 @@ static const ThdOffsets thd_offsets_arr[] = {"5.5.32","97829c2915124a7cfa605d3f39bea354", 6064, 6112, 3816, 4240, 88, 2592}, //offsets for: /mysql/5.6.12/bin/mysqld (5.6.12) {"5.6.12","3a6bb81a7f1239eb810a06a3b0c5dc2a", 7816, 7864, 3960, 4400, 72, 2688}, - //offsets for: /mysql/5.6.13/bin/mysqld (5.6.13) - {"5.6.13","137c18e72cfe17d4fcacda209e405234", 7816, 7864, 3960, 4400, 72, 2688} + //offsets for: /mysqlrpm/5.1.71/usr/sbin/mysqld (5.1.71-community) + {"5.1.71-community","c8453ca637925c878356ca43eef8f654", 6376, 6440, 3736, 4008, 88, 2072}, + //offsets for: /mysqlrpm/5.5.33/usr/sbin/mysqld (5.5.33) + {"5.5.33","88b02a9e61f5faedcf2d64a9b0239f38", 6064, 6112, 3816, 4240, 88, 2592}, + //offsets for: /mysqlrpm/5.6.13/usr/sbin/mysqld (5.6.13) + {"5.6.13","441bbd39cf3df4847289f4cd4b2b3dc3", 7816, 7864, 3960, 4400, 72, 2688}, + //offsets for: /mysql/5.1.71/bin/mysqld (5.1.71) + {"5.1.71","f648e9c956c85fbb1fbe8250df518755", 6392, 6456, 3752, 4024, 88, 2072}, + //offsets for: /mysql/5.5.33/bin/mysqld (5.5.33) + {"5.5.33","59bf9fe80d6005e38238bc083b5aef51", 6064, 6112, 3816, 4240, 88, 2592}, + //offsets for: /mysql/5.6.13/bin/mysqld (5.6.13) + {"5.6.13","137c18e72cfe17d4fcacda209e405234", 7816, 7864, 3960, 4400, 72, 2688}, + //offsets for: /mysql-5.5.34-linux2.6-x86_64/bin/mysqld (5.5.34) + {"5.5.34","94d083ef0a7f964dedb94684eb06c7e7", 6136, 6184, 3816, 4312, 88, 2592, 96, 0, 32, 104}, + //offsets for: /mysqlrpm/5.5.34/usr/sbin/mysqld (5.5.34) + {"5.5.34","b146111cae431cbb3d20322cc0a8e3be", 6136, 6184, 3816, 4312, 88, 2592, 96, 0, 32, 104}, + //offsets for: /mysqlrpm/5.6.14/usr/sbin/mysqld (5.6.14) + {"5.6.14","42907ed406036f7d651a73547a611be0", 7888, 7936, 3960, 4472, 72, 2696, 96, 0, 32, 104}, + //offsets for: /mysqlrpm/5.1.72/usr/sbin/mysqld (5.1.72-community) + {"5.1.72-community","c53f0d8b4d400755e8c476cd512dcea3", 6384, 6448, 3736, 4008, 88, 2072, 8, 0, 24, 16}, + //offsets for: /mysql/5.1.72/bin/mysqld (5.1.72) + {"5.1.72","f560445d3c5f98a88d50878b2cd661c0", 6400, 6464, 3752, 4024, 88, 2072, 8, 0, 24, 16} }; @@ -639,7 +659,28 @@ static const ThdOffsets thd_offsets_arr[] = //offsets for: /mysql/5.5.32/bin/mysqld (5.5.32) {"5.5.32","85199d7a643bf0c336385f613b007018", 3816, 3844, 2368, 2700, 44, 1656}, //offsets for: /mysql/5.6.12/bin/mysqld (5.6.12) - {"5.6.12","469ed6bc745eea0d47a69ecf7b3e0d56", 5580, 5608, 2640, 2980, 36, 1732} + {"5.6.12","469ed6bc745eea0d47a69ecf7b3e0d56", 5580, 5608, 2640, 2980, 36, 1732}, + //offsets for: /mysqlrpm/5.1.71/usr/sbin/mysqld (5.1.71-community) + {"5.1.71-community","2039eb1fb90b85d3744e3628b3ab35fa", 4124, 4164, 2268, 2448, 44, 1188}, + //offsets for: /mysqlrpm/5.5.33/usr/sbin/mysqld (5.5.33) + {"5.5.33","403fe8f9ecd935890f7ebc73297a08bb", 3816, 3844, 2368, 2700, 44, 1656}, + //offsets for: /mysqlrpm/5.6.13/usr/sbin/mysqld (5.6.13) + {"5.6.13","8ac0185b8f8a2a066ed0f5cd45597d6b", 5580, 5608, 2640, 2980, 36, 1732}, + //offsets for: /mysql/5.1.71/bin/mysqld (5.1.71) + {"5.1.71","5e9120167eae0138de4e6f307f337383", 4140, 4180, 2284, 2464, 44, 1188}, + //offsets for: /mysql/5.5.33/bin/mysqld (5.5.33) + {"5.5.33","3172729c5bf6e81c8d87fe26fe248204", 3816, 3844, 2368, 2700, 44, 1656}, + //offsets for: /mysql/5.6.13/bin/mysqld (5.6.13) + {"5.6.13","f25a8fabbb1d205f0f2d772d7f41b9da", 5580, 5608, 2640, 2980, 36, 1732}, + //offsets for: /mysqlrpm/5.5.34/usr/sbin/mysqld (5.5.34) + {"5.5.34","fc8bc7c4edd6c115be5f941ca4618f63", 3868, 3896, 2368, 2748, 44, 1656, 60, 0, 20, 64}, + //offsets for: /mysqlrpm/5.6.14/usr/sbin/mysqld (5.6.14) + {"5.6.14","d7444b6db9d1a5aceb2162e77de762dc", 5632, 5660, 2640, 3028, 36, 1744, 60, 0, 20, 64}, + //offsets for: /mysqlrpm/5.1.72/usr/sbin/mysqld (5.1.72-community) + {"5.1.72-community","3f7221660b8c9e953f327da95d250597", 4128, 4168, 2268, 2448, 44, 1188, 4, 0, 12, 8}, + //offsets for: /mysql/5.1.72/bin/mysqld (5.1.72) + {"5.1.72","199d47e26e5a4cc29399724f47c30aca", 4144, 4184, 2284, 2464, 44, 1188, 4, 0, 12, 8} + }; @@ -880,11 +921,11 @@ static bool audit_check_table_access(THD *thd, ulong want_access,TABLE_LIST *tab { if (pQueryTableInf->num_of_elem < MAX_NUM_QUERY_TABLE_ELEM && pQueryTableInf->num_of_elem>=0) { - pQueryTableInf->db[pQueryTableInf->num_of_elem] = (char*) thd_alloc (thd, strlen (pTables->get_db_name())+1); - strcpy (pQueryTableInf->db[pQueryTableInf->num_of_elem],pTables->get_db_name()); - pQueryTableInf->table_name[pQueryTableInf->num_of_elem] = (char*) thd_alloc (thd, strlen (pTables->get_table_name()) +1); - strcpy (pQueryTableInf->table_name[pQueryTableInf->num_of_elem],pTables->get_table_name()); - pQueryTableInf->object_type[pQueryTableInf->num_of_elem] = Audit_formatter::retrive_object_type ( pTables); + pQueryTableInf->db[pQueryTableInf->num_of_elem] = (char*) thd_alloc (thd, strlen(Audit_formatter::table_get_db_name(pTables))+1); + strcpy (pQueryTableInf->db[pQueryTableInf->num_of_elem],Audit_formatter::table_get_db_name(pTables)); + pQueryTableInf->table_name[pQueryTableInf->num_of_elem] = (char*) thd_alloc (thd, strlen(Audit_formatter::table_get_name(pTables)) +1); + strcpy (pQueryTableInf->table_name[pQueryTableInf->num_of_elem],Audit_formatter::table_get_name(pTables)); + pQueryTableInf->object_type[pQueryTableInf->num_of_elem] = Audit_formatter::retrieve_object_type ( pTables); pQueryTableInf->num_of_elem ++; } pTables = pTables->next_global; @@ -1272,14 +1313,21 @@ static bool validate_offsets(const ThdOffsets * offset) return false; } //extended validation via security_context method - //can be disabled via: validate_offests_extended + //can be disabled via: audit_validate_offsets_extended=OFF if(validate_offsets_extended_enable) { const query_id_t query_id_test_val = 789; (*(query_id_t *) (((char *) thd)+ offset->query_id)) = query_id_test_val; Security_context * sctx = (Security_context *) (((unsigned char *) thd) + offset->main_security_ctx); char user_test_val[] = "aud_tusr"; - sctx->user = user_test_val; + if(!offset->sec_ctx_user) //use compiled header + { + sctx->user = user_test_val; + } + else + { + (*(const char **) (((unsigned char *) sctx) + offset->sec_ctx_user)) = user_test_val; + } char buffer[2048] = {0}; thd_security_context(thd, buffer, 2048, 1000); //verfiy our buffer contains query id @@ -1398,13 +1446,17 @@ static int setup_offsets() } if (parse_thd_offsets_string (offsets_string)) { - sql_print_information ("%s setup_offsets Audit_formatter::thd_offsets values: %zu %zu %zu %zu %zu %zu ", log_prefix, + sql_print_information ("%s setup_offsets Audit_formatter::thd_offsets values: %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu", log_prefix, Audit_formatter::thd_offsets.query_id, Audit_formatter::thd_offsets.thread_id, Audit_formatter::thd_offsets.main_security_ctx, Audit_formatter::thd_offsets.command, Audit_formatter::thd_offsets.lex, - Audit_formatter::thd_offsets.lex_comment); + Audit_formatter::thd_offsets.lex_comment, + Audit_formatter::thd_offsets.sec_ctx_user, + Audit_formatter::thd_offsets.sec_ctx_host, + Audit_formatter::thd_offsets.sec_ctx_ip, + Audit_formatter::thd_offsets.sec_ctx_priv_user); if (!validate_offsets(&Audit_formatter::thd_offsets)) { @@ -1480,14 +1532,18 @@ static int setup_offsets() if (validate_offsets(&decoffsets)) { Audit_formatter::thd_offsets = decoffsets; - sql_print_information("%s Using decrement (%zu) offsets from offset version: %s (%s) values: %zu %zu %zu %zu %zu %zu", + sql_print_information("%s Using decrement (%zu) offsets from offset version: %s (%s) values: %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu", log_prefix, dec, offset->version, offset->md5digest, Audit_formatter::thd_offsets.query_id, Audit_formatter::thd_offsets.thread_id, Audit_formatter::thd_offsets.main_security_ctx, Audit_formatter::thd_offsets.command, Audit_formatter::thd_offsets.lex, - Audit_formatter::thd_offsets.lex_comment); + Audit_formatter::thd_offsets.lex_comment, + Audit_formatter::thd_offsets.sec_ctx_user, + Audit_formatter::thd_offsets.sec_ctx_host, + Audit_formatter::thd_offsets.sec_ctx_ip, + Audit_formatter::thd_offsets.sec_ctx_priv_user); DBUG_RETURN(0); } @@ -1504,14 +1560,18 @@ static int setup_offsets() if (validate_offsets(&incoffsets)) { Audit_formatter::thd_offsets = incoffsets; - sql_print_information("%s Using increment (%zu) offsets from offset version: %s (%s) values: %zu %zu %zu %zu %zu %zu", + sql_print_information("%s Using increment (%zu) offsets from offset version: %s (%s) values: %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu", log_prefix, inc, offset->version, offset->md5digest, Audit_formatter::thd_offsets.query_id, Audit_formatter::thd_offsets.thread_id, Audit_formatter::thd_offsets.main_security_ctx, Audit_formatter::thd_offsets.command, Audit_formatter::thd_offsets.lex, - Audit_formatter::thd_offsets.lex_comment); + Audit_formatter::thd_offsets.lex_comment, + Audit_formatter::thd_offsets.sec_ctx_user, + Audit_formatter::thd_offsets.sec_ctx_host, + Audit_formatter::thd_offsets.sec_ctx_ip, + Audit_formatter::thd_offsets.sec_ctx_priv_user); DBUG_RETURN(0); } } @@ -1549,28 +1609,15 @@ const char * retrieve_command (THD * thd, bool & is_sql_cmd) { cmd = command_name[command].str; } - Security_context * sctx = Audit_formatter::thd_inst_main_security_ctx(thd); - if (strcmp (cmd, "Connect") ==0 && ((sctx->user && strcmp(sctx->user, "event_scheduler") != 0) && (sctx->priv_user == NULL || *sctx->priv_user == 0x0))) + const char * user = Audit_formatter::thd_inst_main_security_ctx_user(thd); + const char * priv_user = Audit_formatter::thd_inst_main_security_ctx_priv_user(thd); + if (strcmp (cmd, "Connect") ==0 && ((user && strcmp(user, "event_scheduler") != 0) && (priv_user == NULL || *priv_user == 0x0))) { cmd = "Failed Login"; } return cmd; } - -const char * retrieve_user (THD * thd) -{ - const char *user = NULL; - - Security_context * sctx = Audit_formatter::thd_inst_main_security_ctx(thd); - if (sctx->priv_user != NULL && *sctx->priv_user != 0x0) - { - user = sctx->priv_user; - } - return user; -} - - static int set_com_status_vars_array () { DBUG_ENTER("set_com_status_vars_array"); diff --git a/src/hot_patch.cc b/src/hot_patch.cc index d3fae61..ced7d08 100755 --- a/src/hot_patch.cc +++ b/src/hot_patch.cc @@ -1,5 +1,6 @@ #include "hot_patch.h" #include "udis86.h" +#include #define UINT unsigned int #define DWORD uint32_t @@ -65,11 +66,17 @@ static int unprotect(void *addr, size_t len) log_prefix, (void *)addr, len, errno); return res; } - char line[1024] = {0}; + char buff[1024] = {0}; const char * flags = "flags"; - bool nxchecked = false; - while(fgets(line, 1024, fp) != NULL) + bool nxchecked = false; + while(fgets(buff, 1024, fp) != NULL) { + char * line = buff; + //trim white space at start + while ((strlen(line) > 0) && (isspace(line[0]))) + { + line++; + } if(strncmp(line, flags, strlen(flags)) == 0) { nxchecked = true;