offsets upto: 5.5.38 and 5.6.19 including mariadb suppoort

cleanup for global params which are set with an update function. For these params we use a static buffer instead of relying on memalloc as mem alloc works differently between versions.
SELinux: More checks to make sure that when selinux is enabled we fail installation.
pull/86/head v1.0.5
Guy Lichtman 2014-06-10 11:04:10 +03:00
parent a6d41da62e
commit a935dc105a
2 changed files with 143 additions and 174 deletions

View File

@ -39,7 +39,11 @@
//64 bit offsets //64 bit offsets
static const ThdOffsets thd_offsets_arr[] = static const ThdOffsets thd_offsets_arr[] =
{ {
//DISTRIBUTION: rpm //offsets for: /mysqlrpm/5.5.38/usr/sbin/mysqld (5.5.38)
{"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) //offsets for: mysqlrpm/5.1.30/usr/sbin/mysqld (5.1.30-community)
{"5.1.30-community","8e43bda3644a883d46a1d064304b4f1d", 6184, 6248, 3656, 3928, 88, 2048}, {"5.1.30-community","8e43bda3644a883d46a1d064304b4f1d", 6184, 6248, 3656, 3928, 88, 2048},
//offsets for: mysqlrpm/5.1.31/usr/sbin/mysqld (5.1.31-community) //offsets for: mysqlrpm/5.1.31/usr/sbin/mysqld (5.1.31-community)
@ -397,7 +401,11 @@ static const ThdOffsets thd_offsets_arr[] =
//32 bit offsets //32 bit offsets
static const ThdOffsets thd_offsets_arr[] = static const ThdOffsets thd_offsets_arr[] =
{ {
//DISTRIBUTION: rpm //offsets for: /mysqlrpm/5.5.38/usr/sbin/mysqld (5.5.38)
{"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) //offsets for: mysqlrpm/5.1.30/usr/sbin/mysqld (5.1.30-community)
{"5.1.30-community","fdfe108d05c262c185a7c28b2e493c10", 4024, 4064, 2224, 2404, 44, 1180}, {"5.1.30-community","fdfe108d05c262c185a7c28b2e493c10", 4024, 4064, 2224, 2404, 44, 1180},
//offsets for: mysqlrpm/5.1.31/usr/sbin/mysqld (5.1.31-community) //offsets for: mysqlrpm/5.1.31/usr/sbin/mysqld (5.1.31-community)
@ -735,6 +743,8 @@ static const ThdOffsets thd_offsets_arr[] =
//64 bit offsets //64 bit offsets
static const ThdOffsets thd_offsets_arr[] = static const ThdOffsets thd_offsets_arr[] =
{ {
//offsets for: /mariadb/5.5.38/bin/mysqld (5.5.38-MariaDB)
{"5.5.38-MariaDB","1ecd82e172b1bf62cab9268d48e4e070", 12016, 12080, 5800, 6896, 88, 2936, 8, 0, 16, 24},
//offsets for: /mariadb/5.5.32/bin/mysqld (5.5.32-MariaDB) //offsets for: /mariadb/5.5.32/bin/mysqld (5.5.32-MariaDB)
{"5.5.32-MariaDB","c67c5c5eaab8467ad1cc170db8e0492d", 12032, 12096, 5816, 6912, 88, 2928, 8, 0, 16, 24}, {"5.5.32-MariaDB","c67c5c5eaab8467ad1cc170db8e0492d", 12032, 12096, 5816, 6912, 88, 2928, 8, 0, 16, 24},
//offsets for: /mariadb/5.5.33/bin/mysqld (5.5.33-MariaDB) //offsets for: /mariadb/5.5.33/bin/mysqld (5.5.33-MariaDB)
@ -746,13 +756,17 @@ static const ThdOffsets thd_offsets_arr[] =
//offsets for: /mariadb/5.5.35/bin/mysqld (5.5.35-MariaDB) //offsets for: /mariadb/5.5.35/bin/mysqld (5.5.35-MariaDB)
{"5.5.35-MariaDB","18b283a98fa3659cf667446850e338eb", 12040, 12104, 5824, 6920, 88, 2936, 8, 0, 16, 24}, {"5.5.35-MariaDB","18b283a98fa3659cf667446850e338eb", 12040, 12104, 5824, 6920, 88, 2936, 8, 0, 16, 24},
//offsets for: /mariadb/5.5.36/bin/mysqld (5.5.36-MariaDB) //offsets for: /mariadb/5.5.36/bin/mysqld (5.5.36-MariaDB)
{"5.5.36-MariaDB","33180ec22cf201f6f769540538318b5b", 12040, 12104, 5824, 6920, 88, 2936, 8, 0, 16, 24} {"5.5.36-MariaDB","33180ec22cf201f6f769540538318b5b", 12040, 12104, 5824, 6920, 88, 2936, 8, 0, 16, 24},
//offsets for: /mariadb/5.5.37/bin/mysqld (5.5.37-MariaDB)
{"5.5.37-MariaDB","71b059dd674950c6007fdeb447311707", 12040, 12104, 5824, 6920, 88, 2936, 8, 0, 16, 24}
}; };
#else #else
//32 bit offsets //32 bit offsets
static const ThdOffsets thd_offsets_arr[] = static const ThdOffsets thd_offsets_arr[] =
{ {
//offsets for: /mariadb/5.5.38/bin/mysqld (5.5.38-MariaDB)
{"5.5.38-MariaDB","39d11f6145bbe9bbf140bb235398969d", 7272, 7308, 3460, 4464, 44, 1860, 4, 0, 8, 12},
//offsets for: /mariadb/5.5.32/bin/mysqld (5.5.32-MariaDB) //offsets for: /mariadb/5.5.32/bin/mysqld (5.5.32-MariaDB)
{"5.5.32-MariaDB","1c523e9b505795636319e30151eaf022", 7288, 7324, 3476, 4480, 44, 1856, 4, 0, 8, 12}, {"5.5.32-MariaDB","1c523e9b505795636319e30151eaf022", 7288, 7324, 3476, 4480, 44, 1856, 4, 0, 8, 12},
//offsets for: /mariadb/5.5.33/bin/mysqld (5.5.33-MariaDB) //offsets for: /mariadb/5.5.33/bin/mysqld (5.5.33-MariaDB)
@ -764,16 +778,15 @@ static const ThdOffsets thd_offsets_arr[] =
//offsets for: /mariadb/5.5.35/bin/mysqld (5.5.35-MariaDB) //offsets for: /mariadb/5.5.35/bin/mysqld (5.5.35-MariaDB)
{"5.5.35-MariaDB","1dc4e9caca4b9aa2440943ba3355a572", 7296, 7332, 3484, 4488, 44, 1860, 4, 0, 8, 12}, {"5.5.35-MariaDB","1dc4e9caca4b9aa2440943ba3355a572", 7296, 7332, 3484, 4488, 44, 1860, 4, 0, 8, 12},
//offsets for: /mariadb/5.5.36/bin/mysqld (5.5.36-MariaDB) //offsets for: /mariadb/5.5.36/bin/mysqld (5.5.36-MariaDB)
{"5.5.36-MariaDB","5cf95a64e10e2b53b8c85554874d034b", 7296, 7332, 3484, 4488, 44, 1860, 4, 0, 8, 12} {"5.5.36-MariaDB","5cf95a64e10e2b53b8c85554874d034b", 7296, 7332, 3484, 4488, 44, 1860, 4, 0, 8, 12},
//offsets for: /mariadb/5.5.37/bin/mysqld (5.5.37-MariaDB)
{"5.5.37-MariaDB","f4434929944d7e9c4351b51e30c0d4d6", 7296, 7332, 3484, 4488, 44, 1860, 4, 0, 8, 12}
}; };
#endif #endif
//end offsets for MariaDB //end offsets for MariaDB
#endif #endif
static my_bool need_free_memalloc_plugin_var = FALSE;
static const char * log_prefix = AUDIT_LOG_PREFIX; static const char * log_prefix = AUDIT_LOG_PREFIX;
//possible audit handlers //possible audit handlers
@ -795,9 +808,13 @@ static char * offsets_string = NULL;
static char * checksum_string = NULL; static char * checksum_string = NULL;
static int delay_ms_val =0; static int delay_ms_val =0;
static char *delay_cmds_string = NULL; static char *delay_cmds_string = NULL;
static char delay_cmds_buff[4096] = {0};
static char *record_cmds_string = NULL; static char *record_cmds_string = NULL;
static char record_cmds_buff[4096] = {0};
static char *record_objs_string = NULL; static char *record_objs_string = NULL;
static char record_objs_buff[4096] = {0};
static char *whitelist_users_string = NULL; static char *whitelist_users_string = NULL;
static char whitelist_users_buff[4096] = {0};
static char delay_cmds_array [SQLCOM_END + 2][MAX_COMMAND_CHAR_NUMBERS] = {{0}}; static char delay_cmds_array [SQLCOM_END + 2][MAX_COMMAND_CHAR_NUMBERS] = {{0}};
static char record_cmds_array [SQLCOM_END + 2][MAX_COMMAND_CHAR_NUMBERS] = {{0}}; static char record_cmds_array [SQLCOM_END + 2][MAX_COMMAND_CHAR_NUMBERS] = {{0}};
@ -1565,7 +1582,7 @@ static int setup_offsets()
//exit from function //exit from function
} }
size_t arr_size = (sizeof(thd_offsets_arr) / sizeof(thd_offsets_arr[0])); size_t arr_size = array_elements(thd_offsets_arr);// (sizeof(thd_offsets_arr) / sizeof(thd_offsets_arr[0]));
//iterate and search for the first offset which matches our checksum //iterate and search for the first offset which matches our checksum
if(validate_checksum_enable && strlen(digest_str) > 0) if(validate_checksum_enable && strlen(digest_str) > 0)
{ {
@ -1801,25 +1818,6 @@ static int string_to_array(const void *save, void *array,
return r; return r;
} }
/*
* Utility function to setup record_objs_array.
* Will use record_objs_string to setup.
*/
static void setup_record_objs_array()
{
num_record_objs = string_to_array(&record_objs_string, record_objs_array, MAX_NUM_OBJECT_ELEM + 2, MAX_OBJECT_CHAR_NUMBERS);
if(num_record_objs > 0) //check if to record also the empty set of objects
{
const char *objects[] = {"{}", NULL};
record_empty_objs_set = check_array(objects, (const char *) record_objs_array, MAX_OBJECT_CHAR_NUMBERS);
}
else
{
record_empty_objs_set = true;
}
sql_print_information("%s Set num_record_objs: %d record objs: %s", log_prefix, num_record_objs, record_objs_string);
}
__attribute__ ((noinline)) static void trampoline_dummy_func_for_mem() __attribute__ ((noinline)) static void trampoline_dummy_func_for_mem()
{ {
TRAMPOLINE_NOP_DEF TRAMPOLINE_NOP_DEF
@ -1856,6 +1854,37 @@ static int do_hot_patch(void ** trampoline_func_pp, unsigned int * trampoline_si
return 0; return 0;
} }
#define DECLARE_STRING_ARR_UPDATE_FUNC(NAME) \
static void NAME ## _string_update(THD *thd, struct st_mysql_sys_var *var, void *tgt, const void *save)\
{\
num_ ## NAME = string_to_array(save, NAME ## _array, array_elements( NAME ## _array), sizeof( NAME ## _array[0]));\
strncpy( NAME ##_buff , *static_cast<char*const*>(save), array_elements( NAME ## _buff) - 1);\
NAME ## _string = NAME ##_buff;\
sql_print_information("%s Set " #NAME " num: %d, value: %s", log_prefix, num_ ## NAME, NAME ## _string);\
}
DECLARE_STRING_ARR_UPDATE_FUNC(delay_cmds)
DECLARE_STRING_ARR_UPDATE_FUNC(record_cmds)
DECLARE_STRING_ARR_UPDATE_FUNC(whitelist_users)
DECLARE_STRING_ARR_UPDATE_FUNC(record_objs)
//extended method to set also record_empty_objs_set
static void record_objs_string_update_extended(THD *thd, struct st_mysql_sys_var *var, void *tgt, const void *save)
{
record_objs_string_update(thd, var, tgt, save);
if(num_record_objs > 0) //check if to record also the empty set of objects
{
const char *objects[] = {"{}", NULL};
record_empty_objs_set = check_array(objects, (const char *) record_objs_array, sizeof(record_objs_array[0]));
}
else
{
record_empty_objs_set = true;
}
sql_print_information("%s Set record_empty_objs: %d", log_prefix, record_empty_objs_set);
}
/* /*
Initialize the plugin installation. Initialize the plugin installation.
@ -1877,12 +1906,9 @@ static int do_hot_patch(void ** trampoline_func_pp, unsigned int * trampoline_si
const char * arch = "32bit"; const char * arch = "32bit";
#endif #endif
//See here: http://bugs.mysql.com/bug.php?id=56652
int interface_ver = audit_plugin.interface_version ; int interface_ver = audit_plugin.interface_version ;
#if MYSQL_VERSION_ID < 50600 #if MYSQL_VERSION_ID < 50600
interface_ver = interface_ver >> 8; interface_ver = interface_ver >> 8;
//we ignore || (50600 <= interface_ver && interface_ver < 50604)) as GA was with 5.6.10
need_free_memalloc_plugin_var = (interface_ver < 50519);
#endif #endif
sql_print_information( sql_print_information(
"%s starting up. Version: %s , Revision: %s (%s). AUDIT plugin interface version: %d (0x%x). MySQL Server version: %s.", "%s starting up. Version: %s , Revision: %s (%s). AUDIT plugin interface version: %d (0x%x). MySQL Server version: %s.",
@ -1896,21 +1922,16 @@ static int do_hot_patch(void ** trampoline_func_pp, unsigned int * trampoline_si
DBUG_RETURN(1); DBUG_RETURN(1);
} }
if (delay_cmds_string != NULL) { if (delay_cmds_string != NULL) {
num_delay_cmds = string_to_array(&delay_cmds_string, delay_cmds_array, SQLCOM_END + 2, MAX_COMMAND_CHAR_NUMBERS); delay_cmds_string_update(NULL, NULL, NULL, &delay_cmds_string);
sql_print_information("%s Set num_delay_cmds: %d", log_prefix, num_delay_cmds);
} }
if (record_cmds_string != NULL) { if (record_cmds_string != NULL) {
num_record_cmds = string_to_array(&record_cmds_string, record_cmds_array, SQLCOM_END + 2, MAX_COMMAND_CHAR_NUMBERS); record_cmds_string_update(NULL, NULL, NULL, &record_cmds_string);
sql_print_information("%s Set num_record_cmds: %d", log_prefix, num_record_cmds);
} }
if (whitelist_users_string != NULL) { if (whitelist_users_string != NULL) {
num_whitelist_users = string_to_array(&whitelist_users_string, whitelist_users_array, MAX_NUM_USER_ELEM + 2, MAX_USER_CHAR_NUMBERS); whitelist_users_string_update(NULL, NULL, NULL, &whitelist_users_string);
sql_print_information("%s Set num_whitelist_users: %d", log_prefix, num_whitelist_users);
} }
if (record_objs_string != NULL) { if (record_objs_string != NULL) {
setup_record_objs_array(); record_objs_string_update_extended(NULL, NULL, NULL, &record_objs_string);
} }
//setup audit handlers (initially disabled) //setup audit handlers (initially disabled)
@ -1968,6 +1989,13 @@ static int do_hot_patch(void ** trampoline_func_pp, unsigned int * trampoline_si
trampoline_mem_free = trampoline_mem; trampoline_mem_free = trampoline_mem;
//hot patch stuff //hot patch stuff
void * target_function = NULL; void * target_function = NULL;
if(do_hot_patch((void **)&trampoline_mysql_execute_command, &trampoline_mysql_execute_size,
(void *)mysql_execute_command, (void *)audit_mysql_execute_command, "mysql_execute_command"))
{
DBUG_RETURN(1);
}
#if MYSQL_VERSION_ID < 50600 #if MYSQL_VERSION_ID < 50600
if(do_hot_patch((void **)&trampoline_log_slow_statement, &trampoline_log_slow_statement_size, if(do_hot_patch((void **)&trampoline_log_slow_statement, &trampoline_log_slow_statement_size,
(void *)log_slow_statement, (void *)audit_log_slow_statement, "log_slow_statement")) (void *)log_slow_statement, (void *)audit_log_slow_statement, "log_slow_statement"))
@ -1978,12 +2006,6 @@ static int do_hot_patch(void ** trampoline_func_pp, unsigned int * trampoline_si
} }
#endif #endif
if(do_hot_patch((void **)&trampoline_mysql_execute_command, &trampoline_mysql_execute_size,
(void *)mysql_execute_command, (void *)audit_mysql_execute_command, "mysql_execute_command"))
{
DBUG_RETURN(1);
}
#if MYSQL_VERSION_ID < 50505 #if MYSQL_VERSION_ID < 50505
if(do_hot_patch((void **)&trampoline_check_user, &trampoline_check_user_size, if(do_hot_patch((void **)&trampoline_check_user, &trampoline_check_user_size,
@ -2109,78 +2131,6 @@ static void json_log_socket_enable(THD *thd, struct st_mysql_sys_var *var,
} }
} }
static void delay_cmds_string_update(THD *thd,
struct st_mysql_sys_var *var, void *tgt,
const void *save)
{
num_delay_cmds = string_to_array(save, delay_cmds_array, SQLCOM_END + 2, MAX_COMMAND_CHAR_NUMBERS);
if (need_free_memalloc_plugin_var)
{
x_free(delay_cmds_string);
delay_cmds_string = my_strdup(*static_cast<char*const*>(save), MYF(MY_WME));
}
else
{
delay_cmds_string = *static_cast<char* const *> (save);
}
sql_print_information("%s Set num_delay_cmds: %d, delay cmds: %s", log_prefix, num_delay_cmds, delay_cmds_string);
}
static void record_cmds_string_update(THD *thd,
struct st_mysql_sys_var *var, void *tgt,
const void *save)
{
num_record_cmds = string_to_array(save, record_cmds_array, SQLCOM_END + 2, MAX_COMMAND_CHAR_NUMBERS);
if (need_free_memalloc_plugin_var)
{
x_free(record_cmds_string);
record_cmds_string = my_strdup(*static_cast<char*const*>(save), MYF(MY_WME));
}
else
{
record_cmds_string = *static_cast<char* const *> (save);
}
sql_print_information("%s Set num_record_cmds: %d record cmds: %s", log_prefix, num_record_cmds, record_cmds_string);
}
static void whitelist_users_string_update(THD *thd,
struct st_mysql_sys_var *var, void *tgt,
const void *save)
{
num_whitelist_users = string_to_array(save, whitelist_users_array, MAX_NUM_USER_ELEM + 2, MAX_USER_CHAR_NUMBERS);
if (need_free_memalloc_plugin_var)
{
x_free(whitelist_users_string);
whitelist_users_string = my_strdup(*static_cast<char*const*>(save), MYF(MY_WME));
}
else
{
whitelist_users_string = *static_cast<char* const *> (save);
}
sql_print_information("%s Set num_whitelist_users: %d whitelist users: %s", log_prefix, num_whitelist_users, whitelist_users_string);
}
static void record_objs_string_update(THD *thd,
struct st_mysql_sys_var *var, void *tgt,
const void *save)
{
if (need_free_memalloc_plugin_var)
{
x_free(record_objs_string);
record_objs_string = my_strdup(*static_cast<char*const*>(save), MYF(MY_WME));
}
else
{
record_objs_string = *static_cast<char* const *> (save);
}
setup_record_objs_array();
}
//setup sysvars which update directly the relevant plugins //setup sysvars which update directly the relevant plugins
@ -2246,22 +2196,22 @@ static MYSQL_SYSVAR_INT(delay_ms, delay_ms_val,
NULL, NULL, 0, 0, INT_MAX32, 0); NULL, NULL, 0, 0, INT_MAX32, 0);
static MYSQL_SYSVAR_STR(delay_cmds, delay_cmds_string, static MYSQL_SYSVAR_STR(delay_cmds, delay_cmds_string,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC, PLUGIN_VAR_RQCMDARG,
"AUDIT plugin delay commands to match against comma separated. If empty then delay is disabled.", "AUDIT plugin delay commands to match against comma separated. If empty then delay is disabled.",
NULL, delay_cmds_string_update, NULL); NULL, delay_cmds_string_update, NULL);
static MYSQL_SYSVAR_STR(record_cmds, record_cmds_string, static MYSQL_SYSVAR_STR(record_cmds, record_cmds_string,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC, PLUGIN_VAR_RQCMDARG,
"AUDIT plugin commands to record, comma separated", "AUDIT plugin commands to record, comma separated",
NULL, record_cmds_string_update, NULL); NULL, record_cmds_string_update, NULL);
static MYSQL_SYSVAR_STR(whitelist_users, whitelist_users_string, static MYSQL_SYSVAR_STR(whitelist_users, whitelist_users_string,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC, PLUGIN_VAR_RQCMDARG,
"AUDIT plugin whitelisted users whose queries are not to recorded, comma separated", "AUDIT plugin whitelisted users whose queries are not to recorded, comma separated",
NULL, whitelist_users_string_update, NULL); NULL, whitelist_users_string_update, NULL);
static MYSQL_SYSVAR_STR(record_objs, record_objs_string, static MYSQL_SYSVAR_STR(record_objs, record_objs_string,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC, PLUGIN_VAR_RQCMDARG,
"AUDIT plugin objects to record, comma separated", "AUDIT plugin objects to record, comma separated",
NULL, record_objs_string_update, NULL); NULL, record_objs_string_update_extended, NULL);
/* /*
* Plugin system vars * Plugin system vars

83
src/hot_patch.cc Executable file → Normal file
View File

@ -20,49 +20,27 @@ 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;
if(use_exec_prot) if(use_exec_prot)
{ {
return 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);
return mprotect(addr,len,PROT_READ|PROT_EXEC); res = mprotect(addr,len,PROT_READ|PROT_EXEC);
} }
} if(res)
//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)
{
res = mprotect(addr,len,PROT_READ|PROT_WRITE|PROT_EXEC);
if(0 != res)
{ {
sql_print_information( sql_print_information(
"%s unable to unprotect. Page: %p, Size: %zu, errno: %d. Using NO EXEC mode.", "%s unable to protect mode: PROT_READ|PROT_EXEC. Page: %p, Size: %zu, errno: %d, res %d.",
log_prefix, (void *)addr, len, errno); log_prefix, (void *)addr, len, errno, res);
use_exec_prot = false;
//do a sanity test that we can actually unprotect/protect and that nx bit is off
res = unprotect(addr, len);
if(0 != 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.",
log_prefix, (void *)addr, len, errno);
return res;
}
res = protect(addr, len);
if(0 != 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. Aborting. 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.",
log_prefix, (void *)addr, len, errno); log_prefix, (void *)addr, len, errno);
return res; return res;
} }
@ -84,7 +62,7 @@ static int unprotect(void *addr, size_t len)
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. Aborting. 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.",
log_prefix, (void *)addr, len); log_prefix, (void *)addr, len);
fclose(fp); fclose(fp);
return res; return res;
@ -96,10 +74,45 @@ static int unprotect(void *addr, size_t len)
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. Aborting. 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.",
log_prefix, flags, (void *)addr, len); log_prefix, flags, (void *)addr, len);
return res; return res;
} }
}
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
static int unprotect(void *addr, size_t len)
{
int res;
if(use_exec_prot)
{
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
res = unprotect(addr, len);
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.",
log_prefix, (void *)addr, len, errno);
return res;
}
res = protect(addr, len);
sql_print_information("%s protect res: %d", log_prefix, 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.",
log_prefix, (void *)addr, len, errno);
return res;
} }
} }
else //all is good else //all is good
@ -242,7 +255,13 @@ static bool HookFunction(ULONG_PTR targetFunction, ULONG_PTR newFunction, ULONG
break; break;
} }
} }
protect((void*)trampolineFunctionPage, PAGE_SIZE); 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; return false;