You've already forked mysql-audit
mirror of
https://github.com/trellix-enterprise/mysql-audit.git
synced 2025-12-17 18:24:02 +08:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd928db022 | ||
|
|
622366a459 | ||
|
|
3ec0c137c9 | ||
|
|
a875a835a4 | ||
|
|
2b130c7bd7 | ||
|
|
266447b8b7 | ||
|
|
416e6fa0aa | ||
|
|
edbed38f42 | ||
|
|
72af9c00f4 | ||
|
|
637d30a568 | ||
|
|
a52594c59c | ||
|
|
cb2cbc605c | ||
|
|
52c611cef8 | ||
|
|
6ea0b6bd15 | ||
|
|
2d0a23c73d | ||
|
|
bca3715fb5 | ||
|
|
d9786405af | ||
|
|
286197fe6d | ||
|
|
40dc1e7ff7 | ||
|
|
969d0b481a | ||
|
|
e7d07fc1fe | ||
|
|
e6fd9d8b6f | ||
|
|
8e56548468 | ||
|
|
e03dcc1cec | ||
|
|
8370847e9b | ||
|
|
4b78009cb3 | ||
|
|
f4a3411ccd | ||
|
|
cd9400da0e | ||
|
|
0ff56ddfb4 | ||
|
|
570bfb0de6 | ||
|
|
ba21262b81 | ||
|
|
4fbcae3a81 |
@@ -42,7 +42,7 @@ Source code is available at: https://github.com/mcafee/mysql-audit
|
||||
|
||||
License
|
||||
-------------------------------
|
||||
Copyright (C) 2016 McAfee, Inc.
|
||||
Copyright (C) 2011-2021 McAfee, LLC.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under the terms of the GNU
|
||||
General Public License as published by the Free Software Foundation; version 2 of the License.
|
||||
|
||||
@@ -52,6 +52,8 @@ first (see www.boost.org). In such a case, use:
|
||||
|
||||
Note: For MariaDB use: cmake . -DBUILD_CONFIG=mysql_release
|
||||
|
||||
Note: For Percona`s MySQL use: cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_CONFIG=mysql_release -DWITH_BOOST=boost_1_59_0 .
|
||||
|
||||
Note: to speed things up it is possible to build just the following directories:
|
||||
libservices
|
||||
extra
|
||||
@@ -63,6 +65,8 @@ chmod +x bootstrap.sh
|
||||
CXX='gcc -static-libgcc' CC='gcc -static-libgcc' ./configure --with-mysql=mysql-5.x.x --with-mysql-libservices=mysql-5.x.x/libservices/libmysqlservices.a
|
||||
make
|
||||
|
||||
Note: For Percona`s MySQL define also PERCONA_BUILD=true variable, like "PERCONA_BUILD=true ./configure..."
|
||||
|
||||
==== Compiling with make =====
|
||||
|
||||
Go to top source dir and run:
|
||||
@@ -77,3 +81,20 @@ Some documentation about configure command for mysql:
|
||||
|
||||
http://dev.mysql.com/doc/refman/5.1/en/source-configuration-options.html
|
||||
|
||||
|
||||
==== MariaDB 10.2.10 ======
|
||||
1. Firstly checkout the source code:-
|
||||
- svn co https://beasource3.corp.nai.org/svn/projects/DBSec-MySQL audit_plugin_mysql
|
||||
2. cd audit_plugin_mysql
|
||||
3. unzip zip-sources/mariadb-10.2.10.zip
|
||||
4. cd mariadb-10.2.10
|
||||
5. CC=gcc CXX=g++ cmake . -DBUILD_CONFIG=mysql_release -DGNUTLS_INCLUDE_DIR=./zip-sources/mariadb-10.2.10/gnutls-3.3.24/64b/include -DGNUTLS_LIBRARY=./zip-sources/mariadb-10.2.10/gnutls-3.3.24/64b/lib
|
||||
6. cd mariadb-10.2.10/libservices
|
||||
7. make
|
||||
8. cd ../extra
|
||||
9. make
|
||||
10. cd ../..
|
||||
11. chmod +x bootstrap.sh
|
||||
12. ./bootstrap.sh
|
||||
13. CXX='gcc -static-libgcc' CC='gcc -static-libgcc' MYSQL_AUDIT_PLUGIN_VERSION=1.1.7 MYSQL_AUDIT_PLUGIN_REVISION=`svn info|grep ^Revision|awk -F ": " '{print $2}'` ./configure --enable-debug=no --with-mysql=mariadb-10.2.10 --with-mysql-libservices=mariadb-10.2.10/libservices/libmysqlservices.a
|
||||
14. gmake <======== This will create the plugin "libaudit_plugin.so"
|
||||
|
||||
@@ -33,7 +33,7 @@ dnl
|
||||
dnl table_id.h included from table.h included by mysql_inc.h is
|
||||
dnl in libbinlogevents/include.
|
||||
AC_DEFINE([MYSQL_SRC], [1], [Source directory for MySQL])
|
||||
MYSQL_INC="-I$withval/sql -I$withval/libbinlogevents/export -I$withval/libbinlogevents/include -I$withval/include -I$withval/regex -I$withval"
|
||||
MYSQL_INC="-I$withval/sql -I$withval/libbinlogevents/export -I$withval/libbinlogevents/include -I$withval/include -I$withval/regex -I$withval -I$withval/extra/rapidjson/include"
|
||||
AC_MSG_RESULT(["$withval"])
|
||||
],
|
||||
[
|
||||
|
||||
@@ -96,8 +96,7 @@ AC_PATH_PROG(DIFF, diff, diff)
|
||||
#we can add the following flags for better error catching: -Werror -Wimplicit
|
||||
CPPFLAGS="$CPPFLAGS -Werror -Wall"
|
||||
CFLAGS="$CFLAGS -Wimplicit"
|
||||
# From MySQL: Disable exceptions as they seams to create problems with gcc and threads.
|
||||
CXXFLAGS="-fno-implicit-templates -fno-exceptions -fno-rtti -Wno-reorder -Wno-strict-aliasing"
|
||||
CXXFLAGS="-fno-implicit-templates -fno-strict-aliasing"
|
||||
|
||||
#add pthread libs
|
||||
LIBS="$LIBS -lpthread"
|
||||
@@ -128,6 +127,10 @@ CPPFLAGS="$CPPFLAGS -DMYSQL_AUDIT_PLUGIN_VERSION='\"$MYSQL_AUDIT_PLUGIN_VERSION\
|
||||
CPPFLAGS="$CPPFLAGS -DMYSQL_AUDIT_PLUGIN_REVISION='\"$MYSQL_AUDIT_PLUGIN_REVISION\"'"
|
||||
CPPFLAGS="$CPPFLAGS '-DMYSQL_AUDIT_PLUGIN_SYMBOL_VERSION()=extern const char audit_plugin_version_$MYSQL_AUDIT_PLUGIN_SYMBOL_VERSION'"
|
||||
|
||||
# Percona`s MySQL macro
|
||||
if [[ "$PERCONA_BUILD" = "true" ]]; then
|
||||
CPPFLAGS="$CPPFLAGS -DPERCONA_BUILD" # Percona`s build macro, used to distinguish between MySQL/MariaDB build VS Percona build
|
||||
fi
|
||||
|
||||
#subst the relevant variables
|
||||
AC_SUBST(CPPFLAGS)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
#include <pcre.h>
|
||||
|
||||
#define AUDIT_LOG_PREFIX "Audit Plugin:"
|
||||
#define AUDIT_LOG_PREFIX "McAfee Audit Plugin:"
|
||||
#define AUDIT_PROTOCOL_VERSION "1.0"
|
||||
|
||||
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709
|
||||
@@ -48,15 +48,28 @@ typedef struct _THDPRINTED {
|
||||
char is_thd_printed_queue[MAX_NUM_QUEUE_ELEM];
|
||||
} THDPRINTED;
|
||||
|
||||
#define MAX_COMMAND_CHAR_NUMBERS 40
|
||||
struct PeerInfo {
|
||||
unsigned long pid;
|
||||
enum { MAX_APP_NAME_LEN = 128, MAX_USER_NAME_LEN = 128 };
|
||||
char appName[MAX_APP_NAME_LEN + 1];
|
||||
char osUser[MAX_USER_NAME_LEN + 1]; // allow lots, in case from LDAP or some such
|
||||
PeerInfo() : pid(0) {
|
||||
memset(appName, 0, sizeof appName);
|
||||
memset(osUser, 0, sizeof osUser);
|
||||
}
|
||||
};
|
||||
|
||||
PeerInfo *retrieve_peerinfo(THD *thd);
|
||||
|
||||
const char *retrieve_command(THD *thd, bool& is_sql_cmd);
|
||||
typedef size_t OFFSET;
|
||||
|
||||
#define MAX_COMMAND_CHAR_NUMBERS 40
|
||||
#define MAX_COM_STATUS_VARS_RECORDS 512
|
||||
|
||||
// mysql max identifier is 64 so 2*64 + . and null
|
||||
#define MAX_OBJECT_CHAR_NUMBERS 131
|
||||
#define MAX_USER_CHAR_NUMBERS 20
|
||||
#define MAX_USER_CHAR_NUMBERS 32
|
||||
#define MAX_NUM_OBJECT_ELEM 256
|
||||
#define MAX_NUM_USER_ELEM 256
|
||||
|
||||
@@ -82,6 +95,16 @@ typedef struct ThdOffsets {
|
||||
OFFSET pfs_connect_attrs;
|
||||
OFFSET pfs_connect_attrs_length;
|
||||
OFFSET pfs_connect_attrs_cs;
|
||||
OFFSET net;
|
||||
OFFSET lex_m_sql_command;
|
||||
OFFSET uninstall_cmd_comment;
|
||||
OFFSET found_rows;
|
||||
OFFSET sent_row_count;
|
||||
OFFSET row_count_func;
|
||||
OFFSET stmt_da;
|
||||
OFFSET da_status;
|
||||
OFFSET da_sql_errno;
|
||||
OFFSET view_tables;
|
||||
} ThdOffsets;
|
||||
|
||||
/*
|
||||
@@ -114,11 +137,21 @@ class ThdSesData {
|
||||
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; }
|
||||
// enum indicating source of statement
|
||||
typedef enum { SOURCE_GENERAL, SOURCE_QUERY_CACHE } StatementSource;
|
||||
ThdSesData(THD *pTHD, StatementSource source = SOURCE_GENERAL);
|
||||
THD *getTHD() const { return m_pThd;}
|
||||
const char *getCmdName() const { return m_CmdName; }
|
||||
void setCmdName(const char *cmd) { m_CmdName = cmd; }
|
||||
const char *getUserName() { return m_UserName; }
|
||||
const unsigned long getPeerPid() const;
|
||||
const char *getAppName() const;
|
||||
const char *getOsUser() const;
|
||||
const int getPort() const { return m_port; }
|
||||
const StatementSource getStatementSource() const { return m_source; }
|
||||
void storeErrorCode();
|
||||
void setErrorCode(uint code) { m_errorCode = code; m_setErrorCode = true; }
|
||||
bool getErrorCode(uint & code) const { code = m_errorCode; return m_setErrorCode; }
|
||||
/**
|
||||
* Start fetching objects. Return true if there are objects available.
|
||||
*/
|
||||
@@ -145,6 +178,16 @@ private:
|
||||
QueryTableInf *m_tableInf;
|
||||
int m_index;
|
||||
|
||||
// Statement source
|
||||
StatementSource m_source;
|
||||
|
||||
PeerInfo *m_peerInfo;
|
||||
|
||||
int m_port; // TCP port of remote side
|
||||
|
||||
uint m_errorCode;
|
||||
bool m_setErrorCode;
|
||||
|
||||
protected:
|
||||
ThdSesData(const ThdSesData&);
|
||||
ThdSesData &operator =(const ThdSesData&);
|
||||
@@ -182,9 +225,13 @@ public:
|
||||
virtual ssize_t stop_msg_format(IWriter *writer) { return 0; }
|
||||
|
||||
static const char *retrieve_object_type(TABLE_LIST *pObj);
|
||||
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 80000
|
||||
static QueryTableInf *getQueryCacheTableList1(THD *thd);
|
||||
#endif
|
||||
|
||||
// utility functions for fetching thd stuff
|
||||
static int thd_client_port(THD *thd);
|
||||
|
||||
static inline my_thread_id thd_inst_thread_id(THD *thd)
|
||||
{
|
||||
return *(my_thread_id *) (((unsigned char *) thd)
|
||||
@@ -243,7 +290,9 @@ public:
|
||||
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
|
||||
// check ip to understand if set, as host is first in the struct and may actually be set to 0
|
||||
// we expect to have offsets for both ip and host or for neither of them
|
||||
if (! Audit_formatter::thd_offsets.sec_ctx_ip)
|
||||
{
|
||||
// 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
|
||||
@@ -302,15 +351,9 @@ public:
|
||||
return sctx->priv_user().str;
|
||||
#endif
|
||||
}
|
||||
#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)
|
||||
@@ -322,61 +365,61 @@ public:
|
||||
{
|
||||
return *(LEX **) (((unsigned char *) thd) + Audit_formatter::thd_offsets.lex);
|
||||
}
|
||||
|
||||
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709
|
||||
//in mysql 5.7 capabilities flag moved to protocol. We use the capabilities offset to point to m_protocol
|
||||
//and get from protocol the capabilities flag
|
||||
static inline ulong thd_client_capabilities(THD *thd)
|
||||
{
|
||||
if (! Audit_formatter::thd_offsets.client_capabilities)
|
||||
{
|
||||
//no offsets - return 0
|
||||
return 0;
|
||||
}
|
||||
Protocol * prot = *(Protocol **) (((unsigned char *) thd) + Audit_formatter::thd_offsets.client_capabilities);
|
||||
if(!prot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return prot->get_client_capabilities();
|
||||
}
|
||||
#else
|
||||
static inline ulong thd_client_capabilities(THD *thd)
|
||||
{
|
||||
if (! Audit_formatter::thd_offsets.client_capabilities)
|
||||
{
|
||||
//no offsets - return 0
|
||||
return 0;
|
||||
}
|
||||
return *(ulong *) (((unsigned char *) thd) + Audit_formatter::thd_offsets.client_capabilities);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static inline const char * pfs_connect_attrs(void * pfs)
|
||||
{
|
||||
if (! Audit_formatter::thd_offsets.pfs_connect_attrs)
|
||||
{
|
||||
//no offsets - return null
|
||||
return NULL;
|
||||
}
|
||||
return *(const char **) (((unsigned char *) pfs) + Audit_formatter::thd_offsets.pfs_connect_attrs);
|
||||
}
|
||||
|
||||
static inline uint pfs_connect_attrs_length(void * pfs)
|
||||
{
|
||||
if (! Audit_formatter::thd_offsets.pfs_connect_attrs_length)
|
||||
{
|
||||
//no offsets - return 0
|
||||
return 0;
|
||||
}
|
||||
return *(uint *) (((unsigned char *) pfs) + Audit_formatter::thd_offsets.pfs_connect_attrs_length);
|
||||
}
|
||||
|
||||
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709
|
||||
//in mysql 5.7 capabilities flag moved to protocol. We use the capabilities offset to point to m_protocol
|
||||
//and get from protocol the capabilities flag
|
||||
static inline ulong thd_client_capabilities(THD *thd)
|
||||
{
|
||||
if (! Audit_formatter::thd_offsets.client_capabilities)
|
||||
{
|
||||
//no offsets - return 0
|
||||
return 0;
|
||||
}
|
||||
Protocol * prot = *(Protocol **) (((unsigned char *) thd) + Audit_formatter::thd_offsets.client_capabilities);
|
||||
if(!prot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return prot->get_client_capabilities();
|
||||
}
|
||||
#else
|
||||
static inline ulong thd_client_capabilities(THD *thd)
|
||||
{
|
||||
if (! Audit_formatter::thd_offsets.client_capabilities)
|
||||
{
|
||||
//no offsets - return 0
|
||||
return 0;
|
||||
}
|
||||
return *(ulong *) (((unsigned char *) thd) + Audit_formatter::thd_offsets.client_capabilities);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline const char * pfs_connect_attrs(void * pfs)
|
||||
{
|
||||
if (! Audit_formatter::thd_offsets.pfs_connect_attrs || pfs == NULL)
|
||||
{
|
||||
//no offsets - return null
|
||||
return NULL;
|
||||
}
|
||||
const char **pfs_pointer = (const char **) (((unsigned char *) pfs) + Audit_formatter::thd_offsets.pfs_connect_attrs);
|
||||
|
||||
return *pfs_pointer;
|
||||
}
|
||||
|
||||
static inline uint pfs_connect_attrs_length(void * pfs)
|
||||
{
|
||||
if (! Audit_formatter::thd_offsets.pfs_connect_attrs_length || pfs == NULL)
|
||||
{
|
||||
//no offsets - return 0
|
||||
return 0;
|
||||
}
|
||||
return *(uint *) (((unsigned char *) pfs) + Audit_formatter::thd_offsets.pfs_connect_attrs_length);
|
||||
}
|
||||
|
||||
static inline const CHARSET_INFO * pfs_connect_attrs_cs(void * pfs)
|
||||
{
|
||||
if (! Audit_formatter::thd_offsets.pfs_connect_attrs_cs)
|
||||
if (! Audit_formatter::thd_offsets.pfs_connect_attrs_cs || pfs == NULL)
|
||||
{
|
||||
//no offsets - return null
|
||||
return NULL;
|
||||
@@ -398,7 +441,7 @@ static inline const CHARSET_INFO * pfs_connect_attrs_cs(void * pfs)
|
||||
// major, minor, patch);
|
||||
}
|
||||
|
||||
if ( ( major == 5 && ( (minor == 6 && patch >= 15) || minor >= 7) ) // MySQL
|
||||
if ( ( major == 5 && ( (minor == 6 && patch >= 15) || minor >= 7) ) || (major == 8) // MySQL
|
||||
|| ( major == 10 && ( (minor == 0 && patch >= 11) || minor >= 1) ) ) // MariaDB
|
||||
{
|
||||
uint cs_number = *(uint *) (((unsigned char *) pfs) + Audit_formatter::thd_offsets.pfs_connect_attrs_cs);
|
||||
@@ -415,7 +458,116 @@ static inline const CHARSET_INFO * pfs_connect_attrs_cs(void * pfs)
|
||||
return *(const CHARSET_INFO **) (((unsigned char *) pfs) + Audit_formatter::thd_offsets.pfs_connect_attrs_cs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline int thd_client_fd(THD *thd)
|
||||
{
|
||||
if (! Audit_formatter::thd_offsets.net)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
NET *net = ((NET *) (((unsigned char *) thd)
|
||||
+ Audit_formatter::thd_offsets.net));
|
||||
// get the socket for the peer
|
||||
int sock = -1;
|
||||
if (net->vio != NULL) // MySQL 5.7.17 - this can happen. :-(
|
||||
{
|
||||
#if MYSQL_VERSION_ID < 50600
|
||||
sock = net->vio->sd;
|
||||
#else
|
||||
sock = net->vio->mysql_socket.fd;
|
||||
#endif
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
static inline ulonglong thd_found_rows(THD *thd)
|
||||
{
|
||||
if (Audit_formatter::thd_offsets.found_rows == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ulonglong *rows = ((ulonglong *) (((unsigned char *) thd)
|
||||
+ Audit_formatter::thd_offsets.found_rows));
|
||||
|
||||
return *rows;
|
||||
}
|
||||
|
||||
static inline unsigned long thd_sent_row_count(THD *thd)
|
||||
{
|
||||
if (Audit_formatter::thd_offsets.sent_row_count == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ha_rows *rows = ((ha_rows *) (((unsigned char *) thd)
|
||||
+ Audit_formatter::thd_offsets.sent_row_count));
|
||||
|
||||
return (unsigned long) *rows;
|
||||
}
|
||||
|
||||
static inline longlong thd_row_count_func(THD *thd)
|
||||
{
|
||||
if (Audit_formatter::thd_offsets.row_count_func == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
longlong *rows = ((longlong *) (((unsigned char *) thd)
|
||||
+ Audit_formatter::thd_offsets.row_count_func));
|
||||
|
||||
return *rows;
|
||||
}
|
||||
|
||||
static inline bool thd_error_code(THD *thd, uint & code)
|
||||
{
|
||||
#if MYSQL_VERSION_ID >= 50534
|
||||
|
||||
if ( Audit_formatter::thd_offsets.stmt_da == 0 ||
|
||||
Audit_formatter::thd_offsets.da_status == 0 ||
|
||||
Audit_formatter::thd_offsets.da_sql_errno == 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Diagnostics_area **stmt_da = ((Diagnostics_area **) (((unsigned char *) thd)
|
||||
+ Audit_formatter::thd_offsets.stmt_da));
|
||||
|
||||
enum Diagnostics_area::enum_diagnostics_status *status =
|
||||
((enum Diagnostics_area::enum_diagnostics_status *) (((unsigned char *) (*stmt_da))
|
||||
+ Audit_formatter::thd_offsets.da_status));
|
||||
|
||||
uint *sql_errno = ((uint *) (((unsigned char *) (*stmt_da))
|
||||
+ Audit_formatter::thd_offsets.da_sql_errno));
|
||||
|
||||
if (*status == Diagnostics_area::DA_OK ||
|
||||
*status == Diagnostics_area::DA_EOF )
|
||||
{
|
||||
code = 0;
|
||||
return true;
|
||||
}
|
||||
else if (*status == Diagnostics_area::DA_ERROR)
|
||||
{
|
||||
code = *sql_errno;
|
||||
return true;
|
||||
}
|
||||
else // DA_EMPTY, DA_DISABLE
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709
|
||||
static inline Sql_cmd_uninstall_plugin* lex_sql_cmd(LEX *lex)
|
||||
{
|
||||
return *(Sql_cmd_uninstall_plugin **) (((unsigned char *) lex) + Audit_formatter::thd_offsets.lex_m_sql_command);
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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)
|
||||
@@ -430,7 +582,10 @@ static inline const CHARSET_INFO * pfs_connect_attrs_cs(void * pfs)
|
||||
|
||||
static inline bool table_is_view(TABLE_LIST *table)
|
||||
{
|
||||
return table->view_tables != 0;
|
||||
if (!Audit_formatter::thd_offsets.view_tables)
|
||||
return table->view_tables != 0;
|
||||
List<TABLE_LIST> **view_tables = (List<TABLE_LIST> **)((char*)table + Audit_formatter::thd_offsets.view_tables);
|
||||
return *view_tables;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -443,13 +598,14 @@ public:
|
||||
static const char *DEF_MSG_DELIMITER;
|
||||
|
||||
Audit_json_formatter()
|
||||
: m_msg_delimiter(NULL),
|
||||
m_write_start_msg(true),
|
||||
: m_write_start_msg(true),
|
||||
m_write_sess_connect_attrs(true),
|
||||
m_write_client_capabilities(true),
|
||||
m_password_mask_regex_preg(NULL),
|
||||
m_write_client_capabilities(false),
|
||||
m_write_socket_creds(true),
|
||||
m_perform_password_masking(NULL),
|
||||
m_msg_delimiter(NULL),
|
||||
m_password_mask_regex_compiled(false),
|
||||
m_perform_password_masking(NULL)
|
||||
m_password_mask_regex_preg(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -491,13 +647,18 @@ public:
|
||||
* Public so sysvar can update
|
||||
*/
|
||||
my_bool m_write_sess_connect_attrs;
|
||||
|
||||
/**
|
||||
* include client capabilities
|
||||
* Public for sysvar
|
||||
*/
|
||||
my_bool m_write_client_capabilities;
|
||||
|
||||
/**
|
||||
* include client capabilities
|
||||
* Public for sysvar
|
||||
*/
|
||||
my_bool m_write_client_capabilities;
|
||||
|
||||
/**
|
||||
* include socket credentials from Unix Domain Socket
|
||||
* Public for sysvar
|
||||
*/
|
||||
my_bool m_write_socket_creds;
|
||||
|
||||
/**
|
||||
* Callback function to determine if password masking should be performed
|
||||
@@ -551,8 +712,12 @@ public:
|
||||
static void stop_all();
|
||||
|
||||
Audit_handler() :
|
||||
m_initialized(false), m_enabled(false), m_print_offset_err(true),
|
||||
m_formatter(NULL), m_failed(false), m_log_io_errors(true)
|
||||
m_formatter()
|
||||
,m_initialized()
|
||||
,m_enabled()
|
||||
,m_failed()
|
||||
,m_log_io_errors(true)
|
||||
,m_print_offset_err(true)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -718,7 +883,10 @@ class Audit_file_handler: public Audit_io_handler {
|
||||
public:
|
||||
|
||||
Audit_file_handler() :
|
||||
m_sync_period(0), m_log_file(NULL), m_sync_counter(0), m_bufsize(0)
|
||||
m_sync_period(0)
|
||||
, m_bufsize(0)
|
||||
, m_log_file(NULL)
|
||||
, m_sync_counter(0)
|
||||
{
|
||||
m_io_type = "file";
|
||||
}
|
||||
@@ -765,7 +933,10 @@ class Audit_socket_handler: public Audit_io_handler {
|
||||
public:
|
||||
|
||||
Audit_socket_handler() :
|
||||
m_vio(NULL), m_connect_timeout(1)
|
||||
m_connect_timeout(1)
|
||||
, m_write_timeout()
|
||||
, m_vio()
|
||||
, m_log_with_error_severity()
|
||||
{
|
||||
m_io_type = "socket";
|
||||
}
|
||||
@@ -788,6 +959,8 @@ public:
|
||||
void close();
|
||||
|
||||
int open(const char *io_dest, bool log_errors);
|
||||
|
||||
unsigned long m_write_timeout; // write timeout in microseconds
|
||||
protected:
|
||||
// override default assignment and copy to protect against creating additional instances
|
||||
Audit_socket_handler & operator=(const Audit_socket_handler&);
|
||||
@@ -796,6 +969,9 @@ protected:
|
||||
// Vio we write to
|
||||
// define as void* so we don't access members directly
|
||||
void *m_vio;
|
||||
|
||||
// log using error severity only the second time same issue occurs
|
||||
bool m_log_with_error_severity;
|
||||
};
|
||||
|
||||
#endif /* AUDIT_HANDLER_H_ */
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
* Created on: Jan 10, 2011
|
||||
* Author: Guyl
|
||||
*/
|
||||
|
||||
#ifndef HOT_PATCH_H_
|
||||
#define HOT_PATCH_H_
|
||||
|
||||
@@ -14,9 +13,14 @@
|
||||
|
||||
#define GETPAGESIZE() sysconf (_SC_PAGE_SIZE)
|
||||
|
||||
int hot_patch_function(void* targetFunction, void* newFunction, void* trampolineFunction, unsigned int *trampolinesize, unsigned int *usedsize, bool log_info);
|
||||
struct SavedCode {
|
||||
char code [1024];
|
||||
size_t size;
|
||||
};
|
||||
|
||||
void remove_hot_patch_function(void* targetFunction, void* trampolineFunction, unsigned int trampolinesize, bool log_info);
|
||||
int hot_patch_function(void* targetFunction, void* newFunction, void* trampolineFunction, unsigned int *trampolinesize, unsigned int *usedsize, bool log_info, SavedCode* saved_code);
|
||||
|
||||
void remove_hot_patch_function(void* targetFunction, void* trampolineFunction, unsigned int trampolinesize, bool log_info, SavedCode* saved_code);
|
||||
|
||||
//8KB NOP + 16
|
||||
//can be used to define a block of memory to use for trampolines
|
||||
|
||||
@@ -17,12 +17,6 @@
|
||||
#include <my_config.h>
|
||||
#include <mysql_version.h>
|
||||
|
||||
#if MYSQL_VERSION_ID < 50505
|
||||
#include <mysql_priv.h>
|
||||
#else
|
||||
|
||||
// version 5.5.x doesn't contain mysql_priv.h . We need to add the includes provided by it.
|
||||
#if MYSQL_VERSION_ID >= 50505
|
||||
|
||||
// These two are not present in 5.7.9
|
||||
#if MYSQL_VERSION_ID < 50709
|
||||
@@ -39,11 +33,31 @@
|
||||
|
||||
#include <sql_parse.h>
|
||||
#include <sql_class.h>
|
||||
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 80019
|
||||
#include <mysql/components/services/mysql_connection_attributes_iterator.h>
|
||||
#include <mysql/components/my_service.h>
|
||||
#include <mysql/service_plugin_registry.h>
|
||||
#endif
|
||||
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 80000
|
||||
using my_bool = bool;
|
||||
#if MYSQL_VERSION_ID < 80012
|
||||
#define PLUGIN_VAR_NOSYSVAR 0x0400
|
||||
#endif
|
||||
#include <sql/item.h>
|
||||
#include <sql/log.h>
|
||||
#include <sql/log_event.h>
|
||||
#include <sql/mysqld.h>
|
||||
#include <sql/protocol.h>
|
||||
#include <sql/sql_lex.h>
|
||||
#else
|
||||
#include <my_global.h>
|
||||
typedef struct st_mysql_sys_var SYS_VAR;
|
||||
#endif
|
||||
#include <sql_connect.h>
|
||||
#include <sql/sql_base.h>
|
||||
#include <sql/sql_table.h>
|
||||
#include <sql/sql_view.h>
|
||||
#include <sql/sql_error.h>
|
||||
|
||||
// TODO: use mysql mutex instead of pthread
|
||||
/*
|
||||
@@ -53,12 +67,11 @@
|
||||
#define pthread_mutex_destroy mysql_mutex_destroy
|
||||
#define pthread_mutex_t mysql_mutex_t
|
||||
*/
|
||||
#endif /* ! if MYSQL_VERSION_ID >= 50505 */
|
||||
#endif /* ! if MYSQL_VERSION_ID < 50505 */
|
||||
|
||||
#if MYSQL_VERSION_ID >= 50709
|
||||
#include <sql/log.h>
|
||||
#if ! defined(MARIADB_BASE_VERSION)
|
||||
#include <sql/sql_plugin.h>
|
||||
#include <sql/auth/auth_common.h>
|
||||
#endif
|
||||
#endif
|
||||
@@ -79,10 +92,7 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// MariaDB doesn't have my_getsystime (returns 100 nano seconds) function. They replaced with my_hrtime_t my_hrtime() which returns microseconds
|
||||
#if defined(MARIADB_BASE_VERSION)
|
||||
|
||||
#define my_getsystime() ((my_hrtime()).val * 10)
|
||||
#if defined(MARIADB_BASE_VERSION)
|
||||
// MariaDB has a kill service that overrides thd_killed as a macro. It also has thd_killed function defined for backwards compatibility, so we redefine it.
|
||||
#undef thd_killed
|
||||
extern "C" int thd_killed(const MYSQL_THD thd);
|
||||
@@ -91,7 +101,6 @@ extern "C" int thd_killed(const MYSQL_THD thd);
|
||||
#if MYSQL_VERSION_ID >= 100010
|
||||
extern "C" char *thd_security_context(MYSQL_THD thd, char *buffer, unsigned int length, unsigned int max_query_len);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//Define HAVE_SESS_CONNECT_ATTRS. We define it for mysql 5.6 and above
|
||||
@@ -99,4 +108,80 @@ extern "C" char *thd_security_context(MYSQL_THD thd, char *buffer, unsigned int
|
||||
#define HAVE_SESS_CONNECT_ATTRS 1
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 80000
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
namespace compat {
|
||||
/*************************/
|
||||
/* my_getsystime */
|
||||
/*************************/
|
||||
#if defined(MARIADB_BASE_VERSION)
|
||||
// MariaDB doesn't have my_getsystime (returns 100 nano seconds) function. They replaced with my_hrtime_t my_hrtime() which returns microseconds
|
||||
static inline unsigned long long int my_getsystime() { return (my_hrtime()).val * 10; }
|
||||
#elif MYSQL_VERSION_ID < 80000
|
||||
static inline unsigned long long int my_getsystime() { return ::my_getsystime(); }
|
||||
#else
|
||||
static inline unsigned long long int my_getsystime() {
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
// Performance regression testing showed this to be preferable
|
||||
struct timespec tp;
|
||||
clock_gettime(CLOCK_REALTIME, &tp);
|
||||
return (static_cast<unsigned long long int>(tp.tv_sec) * 10000000 +
|
||||
static_cast<unsigned long long int>(tp.tv_nsec) / 100);
|
||||
#else
|
||||
return std::chrono::duration_cast<
|
||||
std::chrono::duration<std::int64_t, std::ratio<1, 10000000>>>(
|
||||
UTC_clock::now().time_since_epoch())
|
||||
.count();
|
||||
#endif /* HAVE_CLOCK_GETTIME */
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************/
|
||||
/* vio_socket_connect */
|
||||
/*********************************************/
|
||||
#if MYSQL_VERSION_ID >= 50600
|
||||
#ifndef MYSQL_VIO
|
||||
#define MYSQL_VIO Vio*
|
||||
#endif
|
||||
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 80000
|
||||
static inline bool vio_socket_connect(MYSQL_VIO vio, struct sockaddr *addr, socklen_t len, int timeout)
|
||||
{
|
||||
return ::vio_socket_connect(vio, addr, len, timeout);
|
||||
}
|
||||
#else
|
||||
/*********************************************/
|
||||
/* */
|
||||
/* resolve the symbols manualy to permit */
|
||||
/* loading of the plugin in their absence */
|
||||
/* */
|
||||
/*********************************************/
|
||||
extern bool (*_vio_socket_connect)(MYSQL_VIO vio, struct sockaddr *addr, socklen_t len, int timeout);
|
||||
extern bool (*_vio_socket_connect_80016)(MYSQL_VIO vio, struct sockaddr *addr, socklen_t len, bool nonblocking, int timeout);
|
||||
extern bool (*_vio_socket_connect_80020)(MYSQL_VIO vio, struct sockaddr *addr, socklen_t len, bool nonblocking, int timeout, bool *connect_done);
|
||||
|
||||
static inline bool vio_socket_connect(MYSQL_VIO vio, struct sockaddr *addr, socklen_t len, int timeout)
|
||||
{
|
||||
if (_vio_socket_connect) return _vio_socket_connect(vio, addr, len, timeout);
|
||||
if (_vio_socket_connect_80016) return _vio_socket_connect_80016(vio, addr, len, false, timeout);
|
||||
if (_vio_socket_connect_80020) return _vio_socket_connect_80020(vio, addr, len, false, timeout, nullptr);
|
||||
return true;
|
||||
}
|
||||
static inline bool init()
|
||||
{
|
||||
void* handle = dlopen(NULL, RTLD_LAZY);
|
||||
if (!handle)
|
||||
return false;
|
||||
_vio_socket_connect = (decltype(_vio_socket_connect))dlsym(handle, "_Z18vio_socket_connectP3VioP8sockaddrji");
|
||||
_vio_socket_connect_80016 = (decltype(_vio_socket_connect_80016))dlsym(handle, "_Z18vio_socket_connectP3VioP8sockaddrjbi");
|
||||
_vio_socket_connect_80020 = (decltype(_vio_socket_connect_80020))dlsym(handle, "_Z18vio_socket_connectP3VioP8sockaddrjbiPb");
|
||||
dlclose(handle);
|
||||
return _vio_socket_connect || _vio_socket_connect_80016 || _vio_socket_connect_80020;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // MYSQL_INCL_H
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ $# = 0 ]; then
|
||||
if [ $# = 0 ]
|
||||
then
|
||||
echo "Usage: $0 <mysqld executable> [optional mysqld symbols]"
|
||||
echo "Will extract offsets from mysqld. Requires gdb, md5sum and mysqld symbols."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#extract the version of mysqld
|
||||
# Extract the version of mysqld
|
||||
|
||||
FULL_MYVER=`$1 --version | grep -P -o 'Ver\s+[\w\.-]+'| awk '{print $2}'`
|
||||
FULL_MYVER=`$1 --version | grep -P -o 'Ver\s+[\w\.-]+'| awk '{ print $2 }'`
|
||||
|
||||
#extract the md5 digest
|
||||
# Extract the md5 digest
|
||||
|
||||
MYMD5=`md5sum -b $1 | awk -v Field=1 '{print $1}'`
|
||||
MYMD5=`md5sum -b $1 | awk -v Field=1 '{ print $1 }'`
|
||||
|
||||
MYVER="$FULL_MYVER"
|
||||
echo $FULL_MYVER | grep 'log' > /dev/null
|
||||
|
||||
|
||||
if [ $? = 0 ]; then
|
||||
MYVER=`echo "$MYVER" | grep -P -o '.+(?=-log)'`
|
||||
if echo $FULL_MYVER | grep 'log' > /dev/null
|
||||
then
|
||||
MYVER=`echo "$MYVER" | grep -P -o '.+(?=-log)'`
|
||||
fi
|
||||
|
||||
COMMAND_MEMBER=command
|
||||
@@ -32,43 +31,114 @@ PRIV_USER=priv_user
|
||||
DB=db
|
||||
CLIENT_CAPS="print_offset THD client_capabilities"
|
||||
|
||||
#in 5.6 command member is named m_command
|
||||
echo $MYVER | grep -P '^(5\.6|5\.7|10\.)' > /dev/null
|
||||
if [ $? = 0 ]; then
|
||||
# In 5.6 command member is named m_command
|
||||
if echo $MYVER | grep -P '^(5\.6|5\.7|8\.|10\.)' > /dev/null
|
||||
then
|
||||
COMMAND_MEMBER=m_command
|
||||
HAS_CONNECT_ATTRS=yes
|
||||
fi
|
||||
CONNECT_ATTRS_CS=m_session_connect_attrs_cs
|
||||
#in 5.7 thread_id changed to m_thread_id. main_security_ctx changed to m_main_security_ctx
|
||||
echo $MYVER | grep -P '^(5\.7)' > /dev/null
|
||||
if [ $? = 0 ]; then
|
||||
THREAD_ID=m_thread_id
|
||||
SEC_CONTEXT=m_main_security_ctx
|
||||
USER=m_user
|
||||
HOST=m_host
|
||||
IP=m_ip
|
||||
PRIV_USER=m_priv_user
|
||||
DB=m_db
|
||||
#client capabilities has moved out THD in 5.7. Set to 0
|
||||
CLIENT_CAPS='print_offset THD m_protocol'
|
||||
|
||||
HAS_CONNECT_ATTRS=yes
|
||||
fi
|
||||
|
||||
#in 5.6.15 and up, 5.7 and mariabdb 10.0.11 and up, mariadb 10.1
|
||||
#m_session_connect_attrs_cs changed to m_session_connect_attrs_cs_number
|
||||
echo $MYVER | grep -P '^(5\.7|10\.1|5\.6\.(1[5-9]|[2-9][0-9])|10.0.(1[1-9]|[2-9][0-9]))' > /dev/null
|
||||
if [ $? = 0 ]; then
|
||||
CONNECT_ATTRS_CS=m_session_connect_attrs_cs_number
|
||||
CONNECT_ATTRS_CS=m_session_connect_attrs_cs
|
||||
# In 5.7 thread_id changed to m_thread_id. main_security_ctx changed to m_main_security_ctx
|
||||
if echo $MYVER | grep -P '^(5\.7|8\.)' > /dev/null
|
||||
then
|
||||
THREAD_ID=m_thread_id
|
||||
SEC_CONTEXT=m_main_security_ctx
|
||||
USER=m_user
|
||||
HOST=m_host
|
||||
IP=m_ip
|
||||
PRIV_USER=m_priv_user
|
||||
DB=m_db
|
||||
# client capabilities has moved out THD in 5.7. Set to 0
|
||||
CLIENT_CAPS='print_offset THD m_protocol'
|
||||
|
||||
# comment which holds plugin name for uninstall moved into
|
||||
# a separate object
|
||||
HAS_LEX_SQL_CMD=yes
|
||||
fi
|
||||
|
||||
# In 5.6.15 and up, 5.7 and mariabdb 10.0.11 and up, mariadb 10.1
|
||||
# m_session_connect_attrs_cs changed to m_session_connect_attrs_cs_number
|
||||
if echo $MYVER | grep -P '^(5\.7|8\.|10\.[1-2]|5\.6\.(1[5-9]|[2-9][0-9])|10.0.(1[1-9]|[2-9][0-9]))' > /dev/null
|
||||
then
|
||||
CONNECT_ATTRS_CS=m_session_connect_attrs_cs_number
|
||||
fi
|
||||
|
||||
CONNECT_ATTRS=""
|
||||
if [ -n "$HAS_CONNECT_ATTRS" ]; then
|
||||
CONNECT_ATTRS="print_offset PFS_thread m_session_connect_attrs
|
||||
if [ -n "$HAS_CONNECT_ATTRS" ]
|
||||
then
|
||||
CONNECT_ATTRS="print_offset PFS_thread m_session_connect_attrs
|
||||
print_offset PFS_thread m_session_connect_attrs_length
|
||||
print_offset PFS_thread $CONNECT_ATTRS_CS
|
||||
"
|
||||
else
|
||||
CONNECT_ATTRS='printf ", 0, 0, 0"'
|
||||
CONNECT_ATTRS='printf ", 0, 0, 0"'
|
||||
fi
|
||||
|
||||
if echo $MYVER | grep -P '^(5\.7|8\.0)' > /dev/null
|
||||
then
|
||||
if echo $MYVER | grep -P '^5\.7\.8' > /dev/null
|
||||
then
|
||||
FOUND_ROWS="print_offset THD limit_found_rows"
|
||||
else
|
||||
FOUND_ROWS="print_offset THD previous_found_rows"
|
||||
fi
|
||||
else
|
||||
FOUND_ROWS="print_offset THD limit_found_rows"
|
||||
fi
|
||||
|
||||
if echo $MYVER | grep -P '^5\.[15]' > /dev/null
|
||||
then
|
||||
SENT_ROW_COUNT='print_offset THD sent_row_count'
|
||||
else
|
||||
SENT_ROW_COUNT="print_offset THD m_sent_row_count"
|
||||
fi
|
||||
|
||||
if echo $MYVER | grep -P '^5\.1' > /dev/null
|
||||
then
|
||||
ROW_COUNT_FUNC='print_offset THD row_count_func'
|
||||
else
|
||||
ROW_COUNT_FUNC='print_offset THD m_row_count_func'
|
||||
fi
|
||||
|
||||
LEX_SQL=""
|
||||
if [ -n "$HAS_LEX_SQL_CMD" ]
|
||||
then
|
||||
LEX_SQL="print_offset LEX m_sql_cmd
|
||||
print_offset Sql_cmd_uninstall_plugin m_comment"
|
||||
else
|
||||
LEX_SQL='printf ", 0, 0"'
|
||||
fi
|
||||
|
||||
# Exit status info 5.5, 5.6, 5.7
|
||||
DA_STATUS="print_offset Diagnostics_area m_status" # 5.5, 5.6, 5.7, mariadb 10.0, 10.1, 10.2
|
||||
DA_SQL_ERRNO="print_offset Diagnostics_area m_sql_errno" # 5.5, 5.6, mariadb 10.0, 10.1, 10.2
|
||||
STMT_DA="print_offset THD m_stmt_da" # 5.6, 5.7, mariadb 10.0, 10.1, 10.2
|
||||
|
||||
if echo $MYVER | grep -P '^(5\.7|8\.0)' > /dev/null
|
||||
then
|
||||
DA_SQL_ERRNO="print_offset Diagnostics_area m_mysql_errno"
|
||||
elif echo $MYVER | grep -P '^(5\.6|10\.)' > /dev/null
|
||||
then
|
||||
: place holder
|
||||
elif echo $MYVER | grep -P '^(5\.5)' > /dev/null
|
||||
then
|
||||
STMT_DA="print_offset THD stmt_da"
|
||||
else
|
||||
STMT_DA='printf ", 0"'
|
||||
DA_STATUS='printf ", 0"'
|
||||
DA_SQL_ERRNO='printf ", 0"'
|
||||
fi
|
||||
|
||||
LEX_COMMENT=""
|
||||
VIEW_TABLES=""
|
||||
if echo $MYVER | grep -P '^(8\.0)' > /dev/null
|
||||
then
|
||||
LEX_COMMENT='printf ", 0"'
|
||||
VIEW_TABLES="print_offset TABLE_LIST view_tables"
|
||||
else
|
||||
LEX_COMMENT="print_offset LEX comment"
|
||||
VIEW_TABLES='printf ", 0"'
|
||||
fi
|
||||
|
||||
cat <<EOF > offsets.gdb
|
||||
@@ -83,7 +153,7 @@ print_offset THD $THREAD_ID
|
||||
print_offset THD $SEC_CONTEXT
|
||||
print_offset THD $COMMAND_MEMBER
|
||||
print_offset THD lex
|
||||
print_offset LEX comment
|
||||
$LEX_COMMENT
|
||||
print_offset Security_context $USER
|
||||
print_offset Security_context $HOST
|
||||
print_offset Security_context $IP
|
||||
@@ -92,23 +162,36 @@ print_offset THD $DB
|
||||
print_offset THD killed
|
||||
$CLIENT_CAPS
|
||||
$CONNECT_ATTRS
|
||||
print_offset THD net
|
||||
$LEX_SQL
|
||||
$FOUND_ROWS
|
||||
$SENT_ROW_COUNT
|
||||
$ROW_COUNT_FUNC
|
||||
$STMT_DA
|
||||
$DA_STATUS
|
||||
$DA_SQL_ERRNO
|
||||
$VIEW_TABLES
|
||||
printf "}"
|
||||
EOF
|
||||
|
||||
SYMPARAM=""
|
||||
if [ -n "$2" ]; then
|
||||
if [ -n "$2" ]
|
||||
then
|
||||
SYMPARAM="-s $2 -e"
|
||||
fi
|
||||
|
||||
which gdb > /dev/null 2>&1
|
||||
if [ $? != 0 ]; then
|
||||
if which gdb > /dev/null 2>&1
|
||||
then
|
||||
:
|
||||
else
|
||||
echo "ERROR: gdb not found. Make sure gdb is installed and on the path."
|
||||
exit 3;
|
||||
exit 3
|
||||
fi
|
||||
|
||||
gdb -n -q -batch -x offsets.gdb $SYMPARAM $1 > /dev/null 2>&1
|
||||
|
||||
if [ $? != 0 ]; then
|
||||
if gdb -n -q -batch -x offsets.gdb $SYMPARAM $1 > /dev/null 2>&1
|
||||
then
|
||||
:
|
||||
else
|
||||
echo "GDB failed!!!" > /dev/stderr
|
||||
exit 2
|
||||
fi
|
||||
@@ -117,7 +200,6 @@ OFFSETS=`cat gdb.txt`
|
||||
echo "//offsets for: $1 ($FULL_MYVER)"
|
||||
echo "$OFFSETS,"
|
||||
|
||||
#clean up
|
||||
# clean up
|
||||
rm gdb.txt
|
||||
rm offsets.gdb
|
||||
|
||||
|
||||
54
plugin-name.txt
Normal file
54
plugin-name.txt
Normal file
@@ -0,0 +1,54 @@
|
||||
Tue, Jun 27, 2017 10:48:38 AM
|
||||
=============================
|
||||
|
||||
By default, the McAfee AUDIT plugin for MySQL* is named "AUDIT" and
|
||||
that is the name you should use when installing the plugin with the SQL
|
||||
"INSTALL PLUGIN" command.
|
||||
|
||||
It is the "AUDIT" name that provides the "audit_" prefix to the plugin's
|
||||
various configuration variables.
|
||||
|
||||
In order to avoid conflict with other vendors' auditing plugins whose
|
||||
names may start with "audit" (such as MySQL's "audit_log" plugin) it
|
||||
is possible to change the name of the McAfee plugin. The steps are
|
||||
as follows:
|
||||
|
||||
1. If you're currently using the McAfee plugin, unload it.
|
||||
|
||||
2. Edit the /usr/bin/mysqld_safe shell script (using the correct location
|
||||
for your system). For MySQL 5.7.9, look for the eval_log_error() function.
|
||||
Before the line that says:
|
||||
|
||||
eval "$cmd"
|
||||
|
||||
add a line like this:
|
||||
|
||||
export MCAFEE_AUDIT_PLUGIN_NAME=MCAFEE # use any name you want
|
||||
|
||||
You can use any name you like, "MCAFEE" is just an example.
|
||||
|
||||
For other MySQL versions, determine where the mysqld daemon is actually
|
||||
started, and set the environment variable right before that.
|
||||
|
||||
3. After restarting MySQL, you will need to load the plugin using the
|
||||
new name. From the MySQL client:
|
||||
|
||||
install plugin MCAFEE soname 'libaudit_plugin.so';
|
||||
|
||||
and/or from /etc/my.cnf:
|
||||
|
||||
[mysqld]
|
||||
plugin-load=MCAFEE=libaudit_plugin.so
|
||||
|
||||
Once you've done that, you must remember that the names of ALL the
|
||||
configuration variables will start with the lowercase version of the
|
||||
name you've chosen. For example, "mcafee_json_log_file" instead of
|
||||
"audit_json_log_file".
|
||||
|
||||
If you previously had various "audit_XXX" variables set in your
|
||||
/etc/my.cnf file, you will need to rename them! Otherwise MySQL will
|
||||
fail to start, with an error about unknown variables.
|
||||
|
||||
That's it! Good luck.
|
||||
|
||||
* Other trademarks and brands may be claimed as the property of others.
|
||||
0
src/MySQLPlugin.map
Executable file → Normal file
0
src/MySQLPlugin.map
Executable file → Normal file
@@ -23,8 +23,15 @@
|
||||
// for definition of sockaddr_un
|
||||
#include <sys/un.h>
|
||||
#include <stdio_ext.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include "static_assert.h"
|
||||
|
||||
#if MYSQL_VERSION_ID < 50600
|
||||
// for 5.5 and 5.1
|
||||
extern "C" void vio_timeout(Vio *vio,uint which, uint timeout);
|
||||
#endif
|
||||
|
||||
// utility macro to log also with a date as a prefix
|
||||
// FIXME: This is no longer used. Remove?
|
||||
#define log_with_date(f, ...) do {\
|
||||
@@ -109,6 +116,49 @@ const char *Audit_formatter::retrieve_object_type(TABLE_LIST *pObj)
|
||||
return "TABLE";
|
||||
}
|
||||
|
||||
// This routine used to pull the client port out of the thd->net->vio->remote
|
||||
// object, but on MySQL 5.7 the port is zero. So we resort to getting the
|
||||
// underlying fd and using getpeername(2) on it.
|
||||
|
||||
int Audit_formatter::thd_client_port(THD *thd)
|
||||
{
|
||||
int port = -1;
|
||||
int sock = thd_client_fd(thd);
|
||||
|
||||
if (sock < 0)
|
||||
{
|
||||
return port; // shouldn't happen
|
||||
}
|
||||
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len = sizeof(addr);
|
||||
|
||||
// get port of the guy on the other end of our connection
|
||||
if (getpeername(sock, (struct sockaddr *) & addr, & len) < 0)
|
||||
{
|
||||
return port;
|
||||
}
|
||||
|
||||
|
||||
if (addr.ss_family == AF_INET)
|
||||
{
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *) & addr;
|
||||
port = ntohs(sin->sin_port);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct sockaddr_in6 *sin = (struct sockaddr_in6 *) & addr;
|
||||
port = ntohs(sin->sin6_port);
|
||||
}
|
||||
|
||||
if (port == 0) // shouldn't happen
|
||||
{
|
||||
port = -1;
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
void Audit_handler::stop_all()
|
||||
{
|
||||
for (size_t i = 0; i < MAX_AUDIT_HANDLERS_NUM; ++i)
|
||||
@@ -458,19 +508,51 @@ int Audit_socket_handler::open(const char *io_dest, bool log_errors)
|
||||
m_connect_timeout))
|
||||
#else
|
||||
// in 5.6 timeout is in ms
|
||||
if (vio_socket_connect((Vio*)m_vio,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
|
||||
if (compat::vio_socket_connect((Vio*)m_vio,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
|
||||
m_connect_timeout * 1000))
|
||||
#endif
|
||||
{
|
||||
if (log_errors)
|
||||
{
|
||||
sql_print_warning(
|
||||
"%s unable to connect to socket: %s. err: %s.",
|
||||
AUDIT_LOG_PREFIX, m_io_dest, strerror(errno));
|
||||
|
||||
// The next time this occurs, log as an error
|
||||
m_log_with_error_severity = true;
|
||||
}
|
||||
// Only if issue persist also in second retry, report it by using 'error' severity.
|
||||
else if (m_log_with_error_severity)
|
||||
{
|
||||
sql_print_error(
|
||||
"%s unable to connect to socket: %s. err: %s.",
|
||||
AUDIT_LOG_PREFIX, m_io_dest, strerror(errno));
|
||||
|
||||
m_log_with_error_severity = false;
|
||||
}
|
||||
|
||||
close();
|
||||
return -2;
|
||||
}
|
||||
|
||||
// At this point, connected successfully.
|
||||
// Ensure same behavior in case first time failed but second retry was successful
|
||||
m_log_with_error_severity = false;
|
||||
|
||||
if (m_write_timeout > 0)
|
||||
{
|
||||
int timeout = m_write_timeout / 1000; // milliseconds to seconds, integer dvision
|
||||
if (timeout == 0)
|
||||
{
|
||||
timeout = 1; // round up to 1 second
|
||||
}
|
||||
// we don't check the result of this call since in earlier
|
||||
// versions it returns void
|
||||
//
|
||||
// 1 as the 2nd argument means write timeout
|
||||
vio_timeout((Vio*)m_vio, 1, timeout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -503,7 +585,7 @@ static void yajl_add_uint64(yajl_gen gen, const char *name, uint64 num)
|
||||
{
|
||||
const size_t max_int64_str_len = 21;
|
||||
char buf[max_int64_str_len];
|
||||
snprintf(buf, max_int64_str_len, "%llu", num);
|
||||
snprintf(buf, max_int64_str_len, "%llu", (unsigned long long)num);
|
||||
yajl_add_string_val(gen, name, buf);
|
||||
}
|
||||
|
||||
@@ -540,8 +622,11 @@ static const char *retrieve_user(THD *thd)
|
||||
// starting with MySQL version 5.1.41 thd_query_string is added
|
||||
// And at 5.7 it changed
|
||||
#if ! defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709
|
||||
|
||||
#if MYSQL_VERSION_ID >= 80000
|
||||
extern LEX_CSTRING thd_query_unsafe(MYSQL_THD thd);
|
||||
#else
|
||||
extern "C" LEX_CSTRING thd_query_unsafe(MYSQL_THD thd);
|
||||
#endif
|
||||
|
||||
static const char *thd_query_str(THD *thd, size_t *len)
|
||||
{
|
||||
@@ -558,7 +643,7 @@ static const char *thd_query_str(THD *thd, size_t *len)
|
||||
#elif defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID > 50140
|
||||
|
||||
extern "C" {
|
||||
MYSQL_LEX_STRING *thd_query_string(MYSQL_THD thd);
|
||||
MYSQL_LEX_STRING *thd_query_string(MYSQL_THD thd);
|
||||
}
|
||||
|
||||
static const char *thd_query_str(THD *thd, size_t *len)
|
||||
@@ -612,15 +697,16 @@ ssize_t Audit_json_formatter::start_msg_format(IWriter *writer)
|
||||
yajl_gen gen = yajl_gen_alloc(NULL);
|
||||
yajl_gen_map_open(gen);
|
||||
yajl_add_string_val(gen, "msg-type", "header");
|
||||
uint64 ts = my_getsystime() / (10000);
|
||||
uint64 ts = compat::my_getsystime() / (10000);
|
||||
yajl_add_uint64(gen, "date", ts);
|
||||
yajl_add_string_val(gen, "audit-version", MYSQL_AUDIT_PLUGIN_VERSION"-"MYSQL_AUDIT_PLUGIN_REVISION);
|
||||
yajl_add_string_val(gen, "audit-version", MYSQL_AUDIT_PLUGIN_VERSION "-" MYSQL_AUDIT_PLUGIN_REVISION);
|
||||
yajl_add_string_val(gen, "audit-protocol-version", AUDIT_PROTOCOL_VERSION);
|
||||
yajl_add_string_val(gen, "hostname", glob_hostname);
|
||||
yajl_add_string_val(gen, "mysql-version", server_version);
|
||||
yajl_add_string_val(gen, "mysql-program", my_progname);
|
||||
yajl_add_string_val(gen, "mysql-socket", mysqld_unix_port);
|
||||
yajl_add_uint64(gen, "mysql-port", mysqld_port);
|
||||
yajl_add_uint64(gen, "server_pid", getpid());
|
||||
ssize_t res = -2;
|
||||
|
||||
yajl_gen_status stat = yajl_gen_map_close(gen); // close the object
|
||||
@@ -675,91 +761,151 @@ static const char *replace_in_string(THD *thd,
|
||||
#ifdef HAVE_SESS_CONNECT_ATTRS
|
||||
#include <storage/perfschema/pfs_instr.h>
|
||||
|
||||
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 80000
|
||||
//declare the function: parse_length_encoded_string from: storage/perfschema/table_session_connect.cc
|
||||
bool parse_length_encoded_string(const char **ptr,
|
||||
char *dest, uint dest_size,
|
||||
uint *copied_len,
|
||||
const char *start_ptr, uint input_length,
|
||||
bool copy_data,
|
||||
const CHARSET_INFO *from_cs,
|
||||
uint nchars_max);
|
||||
char *dest, uint dest_size,
|
||||
uint *copied_len,
|
||||
const char *start_ptr, uint input_length,
|
||||
bool copy_data,
|
||||
const CHARSET_INFO *from_cs,
|
||||
uint nchars_max);
|
||||
|
||||
#else
|
||||
// the function is not exported in MySQL 8
|
||||
/**
|
||||
Take a length encoded string
|
||||
|
||||
@arg ptr inout the input string array
|
||||
@arg dest where to store the result
|
||||
@arg dest_size max size of @c dest
|
||||
@arg copied_len the actual length of the data copied
|
||||
@arg start_ptr pointer to the start of input
|
||||
@arg input_length the length of the incoming data
|
||||
@arg from_cs character set in which @c ptr is encoded
|
||||
@arg nchars_max maximum number of characters to read
|
||||
@return status
|
||||
@retval true parsing failed
|
||||
@retval false parsing succeeded
|
||||
*/
|
||||
static bool parse_length_encoded_string(
|
||||
const char **ptr
|
||||
,char *dest
|
||||
,uint dest_size
|
||||
,uint *copied_len
|
||||
,const char *start_ptr
|
||||
,uint input_length
|
||||
,bool /* unused */
|
||||
,const CHARSET_INFO *from_cs
|
||||
,uint nchars_max
|
||||
)
|
||||
{
|
||||
ulong copy_length, data_length;
|
||||
const char *well_formed_error_pos = NULL, *cannot_convert_error_pos = NULL,
|
||||
*from_end_pos = NULL;
|
||||
|
||||
copy_length = data_length = net_field_length((uchar **)ptr);
|
||||
|
||||
/* we don't tolerate NULL as a length */
|
||||
if (data_length == NULL_LENGTH) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (*ptr - start_ptr + data_length > input_length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: Migrate the data itself to UTF8MB4,
|
||||
this is still UTF8MB3 printed in a UTF8MB4 column.
|
||||
*/
|
||||
copy_length = well_formed_copy_nchars(
|
||||
&my_charset_utf8_bin
|
||||
, dest
|
||||
, dest_size
|
||||
, from_cs
|
||||
, *ptr
|
||||
, data_length
|
||||
, nchars_max
|
||||
, &well_formed_error_pos
|
||||
, &cannot_convert_error_pos
|
||||
, &from_end_pos
|
||||
);
|
||||
*copied_len = copy_length;
|
||||
(*ptr) += data_length;
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* Code based upon read_nth_attribute of storage/perfschema/table_session_connect.cc
|
||||
* Only difference we do once loop and write out the attributes
|
||||
*/
|
||||
static void log_session_connect_attrs(yajl_gen gen, THD *thd)
|
||||
{
|
||||
PFS_thread * pfs = PFS_thread::get_current_thread();
|
||||
const char * connect_attrs = Audit_formatter::pfs_connect_attrs(pfs);
|
||||
const uint connect_attrs_length = Audit_formatter::pfs_connect_attrs_length(pfs);
|
||||
const CHARSET_INFO *connect_attrs_cs = Audit_formatter::pfs_connect_attrs_cs(pfs);
|
||||
|
||||
//sanity max attributes
|
||||
const uint max_idx = 32;
|
||||
uint idx;
|
||||
const char *ptr;
|
||||
bool array_start = false;
|
||||
if(!connect_attrs || !connect_attrs_length || !connect_attrs_cs)
|
||||
{
|
||||
//either offsets are wrong or not set
|
||||
return;
|
||||
}
|
||||
for (ptr= connect_attrs, idx= 0;
|
||||
(uint)(ptr - connect_attrs) < connect_attrs_length && idx <= max_idx;
|
||||
idx++)
|
||||
{
|
||||
const uint MAX_COPY_CHARS_NAME = 32;
|
||||
const uint MAX_COPY_CHARS_VAL = 256;
|
||||
//time 6 (max udf8 char length)
|
||||
char attr_name[MAX_COPY_CHARS_NAME*6];
|
||||
char attr_value[MAX_COPY_CHARS_VAL *6];
|
||||
uint copy_length, attr_name_length, attr_value_length;
|
||||
/* always do copying */
|
||||
bool fill_in_attr_name= true;
|
||||
bool fill_in_attr_value= true;
|
||||
PFS_thread * pfs = PFS_thread::get_current_thread();
|
||||
const char * connect_attrs = Audit_formatter::pfs_connect_attrs(pfs);
|
||||
const uint connect_attrs_length = Audit_formatter::pfs_connect_attrs_length(pfs);
|
||||
const CHARSET_INFO *connect_attrs_cs = Audit_formatter::pfs_connect_attrs_cs(pfs);
|
||||
|
||||
/* read the key */
|
||||
copy_length = 0;
|
||||
if (parse_length_encoded_string(&ptr,
|
||||
attr_name, array_elements(attr_name), ©_length,
|
||||
connect_attrs,
|
||||
connect_attrs_length,
|
||||
fill_in_attr_name,
|
||||
connect_attrs_cs, MAX_COPY_CHARS_NAME) || !copy_length)
|
||||
{
|
||||
//something went wrong or we are done
|
||||
break;
|
||||
}
|
||||
|
||||
attr_name_length = copy_length;
|
||||
/* read the value */
|
||||
copy_length = 0;
|
||||
if (parse_length_encoded_string(&ptr,
|
||||
attr_value, array_elements(attr_value), ©_length,
|
||||
connect_attrs,
|
||||
connect_attrs_length,
|
||||
fill_in_attr_value,
|
||||
connect_attrs_cs, MAX_COPY_CHARS_VAL) || !copy_length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
attr_value_length= copy_length;
|
||||
if(!array_start)
|
||||
{
|
||||
yajl_add_string(gen, "connect_attrs");
|
||||
yajl_gen_map_open(gen);
|
||||
array_start = true;
|
||||
}
|
||||
yajl_gen_string(gen, (const unsigned char*)attr_name, attr_name_length);
|
||||
yajl_gen_string(gen, (const unsigned char*)attr_value, attr_value_length);
|
||||
|
||||
} //close for loop
|
||||
if(array_start)
|
||||
{
|
||||
yajl_gen_map_close(gen);
|
||||
}
|
||||
return;
|
||||
//sanity max attributes
|
||||
const uint max_idx = 32;
|
||||
uint idx;
|
||||
const char *ptr;
|
||||
// bool array_start = false;
|
||||
if(!connect_attrs || !connect_attrs_length || !connect_attrs_cs)
|
||||
{
|
||||
sql_print_information("%s Failed to compute offsets connect_attrs. pfs [%p], connect_attrs [%p], connect_attrs_length [%d], connect_attrs_cs [%p]", AUDIT_LOG_PREFIX, pfs, connect_attrs, connect_attrs_length, connect_attrs_cs);
|
||||
//either offsets are wrong or not set
|
||||
return;
|
||||
}
|
||||
for (ptr= connect_attrs, idx= 0;
|
||||
(uint)(ptr - connect_attrs) < connect_attrs_length && idx <= max_idx;
|
||||
idx++)
|
||||
{
|
||||
const uint MAX_COPY_CHARS_NAME = 32;
|
||||
const uint MAX_COPY_CHARS_VAL = 256;
|
||||
//time 6 (max udf8 char length)
|
||||
char attr_name[MAX_COPY_CHARS_NAME*6];
|
||||
char attr_value[MAX_COPY_CHARS_VAL *6];
|
||||
uint copy_length, attr_name_length, attr_value_length;
|
||||
/* always do copying */
|
||||
bool fill_in_attr_name= true;
|
||||
bool fill_in_attr_value= true;
|
||||
|
||||
/* read the key */
|
||||
copy_length = 0;
|
||||
if (parse_length_encoded_string(&ptr,
|
||||
attr_name, array_elements(attr_name), ©_length,
|
||||
connect_attrs,
|
||||
connect_attrs_length,
|
||||
fill_in_attr_name,
|
||||
connect_attrs_cs, MAX_COPY_CHARS_NAME) || !copy_length)
|
||||
{
|
||||
//something went wrong or we are done
|
||||
// sql_print_information("%s something went wrong or we are done 1", AUDIT_LOG_PREFIX);
|
||||
break;
|
||||
}
|
||||
|
||||
attr_name_length = copy_length;
|
||||
/* read the value */
|
||||
copy_length = 0;
|
||||
if (parse_length_encoded_string(&ptr,
|
||||
attr_value, array_elements(attr_value), ©_length,
|
||||
connect_attrs,
|
||||
connect_attrs_length,
|
||||
fill_in_attr_value,
|
||||
connect_attrs_cs, MAX_COPY_CHARS_VAL) || !copy_length)
|
||||
{
|
||||
// sql_print_information("%s something went wrong or we are done 2", AUDIT_LOG_PREFIX);
|
||||
break;
|
||||
}
|
||||
attr_value_length= copy_length;
|
||||
yajl_gen_string(gen, (const unsigned char*)attr_name, attr_name_length);
|
||||
yajl_gen_string(gen, (const unsigned char*)attr_value, attr_value_length);
|
||||
|
||||
} //close for loop
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -778,7 +924,7 @@ ssize_t Audit_json_formatter::event_format(ThdSesData *pThdData, IWriter *writer
|
||||
// TODO: get the start date from THD (but it is not in millis. Need to think about how we handle this)
|
||||
// for now simply use the current time.
|
||||
// my_getsystime() time since epoc in 100 nanosec units. Need to devide by 1000*(1000/100) to reach millis
|
||||
uint64 ts = my_getsystime() / (10000);
|
||||
uint64 ts = compat::my_getsystime() / (10000);
|
||||
yajl_add_uint64(gen, "date", ts);
|
||||
yajl_add_uint64(gen, "thread-id", thdid);
|
||||
yajl_add_uint64(gen, "query-id", qid);
|
||||
@@ -786,12 +932,14 @@ ssize_t Audit_json_formatter::event_format(ThdSesData *pThdData, IWriter *writer
|
||||
yajl_add_string_val(gen, "priv_user", Audit_formatter::thd_inst_main_security_ctx_priv_user(thd));
|
||||
yajl_add_string_val(gen, "ip", Audit_formatter::thd_inst_main_security_ctx_ip(thd));
|
||||
|
||||
// Don't send host unless there's a real value
|
||||
// For backwards compatibility, we always send "host".
|
||||
// If there is no value, send the IP address
|
||||
const char *host = Audit_formatter::thd_inst_main_security_ctx_host(thd);
|
||||
if (host != NULL && *host != '\0')
|
||||
if (host == NULL || *host == '\0')
|
||||
{
|
||||
yajl_add_string_val(gen, "host", host);
|
||||
host = Audit_formatter::thd_inst_main_security_ctx_ip(thd);
|
||||
}
|
||||
yajl_add_string_val(gen, "host", host);
|
||||
|
||||
if (m_write_client_capabilities)
|
||||
{
|
||||
@@ -809,7 +957,63 @@ ssize_t Audit_json_formatter::event_format(ThdSesData *pThdData, IWriter *writer
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pThdData->getPeerPid() != 0) // Unix Domain Socket
|
||||
{
|
||||
if (m_write_socket_creds)
|
||||
{
|
||||
yajl_add_uint64(gen, "pid", pThdData->getPeerPid());
|
||||
if (pThdData->getOsUser() != NULL)
|
||||
{
|
||||
yajl_add_string_val(gen, "os_user", pThdData->getOsUser());
|
||||
}
|
||||
if (pThdData->getAppName() != NULL)
|
||||
{
|
||||
yajl_add_string_val(gen, "appname", pThdData->getAppName());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pThdData->getPort() > 0) // TCP socket
|
||||
{
|
||||
yajl_add_uint64(gen, "client_port", pThdData->getPort());
|
||||
}
|
||||
|
||||
const char *cmd = pThdData->getCmdName();
|
||||
ulonglong rows = 0;
|
||||
|
||||
if (pThdData->getStatementSource() == ThdSesData::SOURCE_QUERY_CACHE)
|
||||
{
|
||||
// from the query cache
|
||||
rows = thd_found_rows(thd);
|
||||
}
|
||||
else if (strcasestr(cmd, "insert") != NULL ||
|
||||
strcasestr(cmd, "update") != NULL ||
|
||||
strcasestr(cmd, "delete") != NULL ||
|
||||
(strcasestr(cmd, "select") != NULL && thd_row_count_func(thd) > 0))
|
||||
{
|
||||
// m_row_count_func will be -1 for most selects but can be > 0, e.g. select into file
|
||||
// thd_row_count_func() returns signed valiue. Don't assign it to rows directly.
|
||||
longlong row_count = thd_row_count_func(thd);
|
||||
if (row_count > 0)
|
||||
{
|
||||
rows = row_count;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rows = thd_sent_row_count(thd);
|
||||
}
|
||||
|
||||
if (rows != 0UL)
|
||||
{
|
||||
yajl_add_uint64(gen, "rows", rows);
|
||||
}
|
||||
|
||||
uint code;
|
||||
if (pThdData->getErrorCode(code))
|
||||
{
|
||||
yajl_add_uint64(gen, "status", code); // 0 - success, otherwise reports specific errno
|
||||
}
|
||||
|
||||
yajl_add_string_val(gen, "cmd", cmd);
|
||||
|
||||
// get objects
|
||||
@@ -935,13 +1139,39 @@ ssize_t Audit_json_formatter::event_format(ThdSesData *pThdData, IWriter *writer
|
||||
return res;
|
||||
}
|
||||
|
||||
ThdSesData::ThdSesData(THD *pTHD)
|
||||
: m_pThd (pTHD), m_CmdName(NULL), m_UserName(NULL),
|
||||
m_objIterType(OBJ_NONE), m_tables(NULL), m_firstTable(true),
|
||||
m_tableInf(NULL), m_index(0), m_isSqlCmd(false)
|
||||
ThdSesData::ThdSesData(THD *pTHD, StatementSource source)
|
||||
: m_pThd (pTHD)
|
||||
, m_CmdName()
|
||||
, m_UserName()
|
||||
, m_isSqlCmd()
|
||||
, m_objIterType(OBJ_NONE)
|
||||
, m_tables()
|
||||
, m_firstTable(true)
|
||||
, m_tableInf()
|
||||
, m_index()
|
||||
, m_source(source)
|
||||
, m_port(-1)
|
||||
, m_errorCode()
|
||||
, m_setErrorCode()
|
||||
{
|
||||
m_CmdName = retrieve_command (m_pThd, m_isSqlCmd);
|
||||
m_UserName = retrieve_user (m_pThd);
|
||||
|
||||
m_peerInfo = retrieve_peerinfo(m_pThd);
|
||||
if (m_peerInfo && m_peerInfo->pid == 0)
|
||||
{
|
||||
// not UDS, get remote port
|
||||
m_port = Audit_formatter::thd_client_port(m_pThd);
|
||||
}
|
||||
}
|
||||
|
||||
void ThdSesData::storeErrorCode()
|
||||
{
|
||||
uint code = 0;
|
||||
if (Audit_formatter::thd_error_code(m_pThd, code))
|
||||
{
|
||||
setErrorCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
bool ThdSesData::startGetObjects()
|
||||
@@ -951,15 +1181,17 @@ bool ThdSesData::startGetObjects()
|
||||
m_tables = NULL;
|
||||
m_firstTable = true;
|
||||
m_index = 0;
|
||||
m_tableInf = Audit_formatter::getQueryCacheTableList1(getTHD());
|
||||
int command = Audit_formatter::thd_inst_command(getTHD());
|
||||
LEX *pLex = Audit_formatter::thd_lex(getTHD());
|
||||
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 80000
|
||||
// query cache case
|
||||
m_tableInf = Audit_formatter::getQueryCacheTableList1(getTHD());
|
||||
if (pLex && command == COM_QUERY && m_tableInf && m_tableInf->num_of_elem > 0)
|
||||
{
|
||||
m_objIterType = OBJ_QUERY_CACHE;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
const char *cmd = getCmdName();
|
||||
// commands which have single database object
|
||||
if (strcmp(cmd,"Init DB") == 0
|
||||
@@ -1055,6 +1287,21 @@ bool ThdSesData::getNextObject(const char **db_name, const char **obj_name, cons
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned long ThdSesData::getPeerPid() const
|
||||
{
|
||||
return (m_peerInfo != NULL ? m_peerInfo->pid : 0L);
|
||||
}
|
||||
|
||||
const char *ThdSesData::getAppName() const
|
||||
{
|
||||
return (m_peerInfo != NULL ? m_peerInfo->appName : NULL);
|
||||
}
|
||||
|
||||
const char *ThdSesData::getOsUser() const
|
||||
{
|
||||
return (m_peerInfo != NULL ? m_peerInfo->osUser : NULL);
|
||||
}
|
||||
|
||||
pcre *Audit_json_formatter::regex_compile(const char *str)
|
||||
{
|
||||
const char *error;
|
||||
|
||||
2401
src/audit_offsets.cc
2401
src/audit_offsets.cc
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -228,7 +228,7 @@ static void WriteJump32(void *pAddress, ULONG_PTR JumpTo)
|
||||
// Hooks a function
|
||||
//
|
||||
static bool HookFunction(ULONG_PTR targetFunction, ULONG_PTR newFunction, ULONG_PTR trampolineFunction,
|
||||
unsigned int *trampolinesize, unsigned int *usedsize)
|
||||
unsigned int *trampolinesize, unsigned int *usedsize, SavedCode* saved_code)
|
||||
{
|
||||
#define MAX_INSTRUCTIONS 100
|
||||
uint8_t raw[MAX_INSTRUCTIONS];
|
||||
@@ -293,6 +293,9 @@ static bool HookFunction(ULONG_PTR targetFunction, ULONG_PTR newFunction, ULONG_
|
||||
ud_obj.operand[0].type == UD_OP_JIMM)
|
||||
{
|
||||
bool cannot_disassemble = true;
|
||||
sql_print_information("ud_obj.mnemonic == UD_Ijmp: %d", ud_obj.mnemonic == UD_Ijmp);
|
||||
sql_print_information("ud_obj.mnemonic == UD_Icall: %d", ud_obj.mnemonic == UD_Icall);
|
||||
sql_print_information("ud_obj.operand[0].type == UD_OP_JIMM: %d", ud_obj.operand[0].type == UD_OP_JIMM);
|
||||
|
||||
#ifdef __i386__
|
||||
const BYTE *pc = (const BYTE *)targetFunction + InstrSize;
|
||||
@@ -324,7 +327,59 @@ static bool HookFunction(ULONG_PTR targetFunction, ULONG_PTR newFunction, ULONG_
|
||||
cannot_disassemble = false;
|
||||
}
|
||||
}
|
||||
sql_print_error("in __i386__");
|
||||
|
||||
#else
|
||||
// If there is a relative jump or call in the to be overwritten chunk,
|
||||
// construct an absolute jump/call in the trampoline.
|
||||
#ifdef __x86_64__
|
||||
sql_print_information("__x86_64__");
|
||||
#endif
|
||||
if (ud_obj.operand[0].type == UD_OP_JIMM && (ud_obj.mnemonic == UD_Ijmp || ud_obj.mnemonic == UD_Icall)) {
|
||||
// jump or call
|
||||
size_t rewrite_size = 0;
|
||||
switch (ud_obj.mnemonic) {
|
||||
case UD_Ijmp:
|
||||
sql_print_information("rewriting relative jump as absolute");
|
||||
memcpy((void*)(trampolineFunction + uCurrentSize), "\xff\x25\x00\x00\x00\x00", 6); // jmpq *0x0(%rip)
|
||||
rewrite_size = 6;
|
||||
break;
|
||||
case UD_Icall:
|
||||
sql_print_information("rewriting relative call as absolute");
|
||||
memcpy((void*)(trampolineFunction + uCurrentSize), "\xff\x15\x02\x00\x00\x00", 6); // callq *0x2(%rip) -- call the function via the address stored at RIP+2
|
||||
memcpy((void*)(trampolineFunction + uCurrentSize + 6), "\xeb\x08", 2); // jmp 0x08 -- jump over the function address (8 bytes forward)
|
||||
rewrite_size = 8;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// calculate the jump target from the instruction pointer and the immediate operand
|
||||
unsigned long jump_target = ud_obj.pc;
|
||||
switch (ud_obj.operand[0].size) {
|
||||
case 8:
|
||||
jump_target += ud_obj.operand[0].lval.sbyte;
|
||||
break;
|
||||
case 16:
|
||||
jump_target += ud_obj.operand[0].lval.sword;
|
||||
break;
|
||||
case 32:
|
||||
jump_target += ud_obj.operand[0].lval.sdword;
|
||||
break;
|
||||
}
|
||||
memcpy((void*)(trampolineFunction + uCurrentSize + rewrite_size), &jump_target, 8);
|
||||
rewrite_size += 8;
|
||||
|
||||
// update the indexes
|
||||
uCurrentSize += rewrite_size;
|
||||
InstrSize += ud_insn_len (&ud_obj);
|
||||
|
||||
// clear the flag
|
||||
cannot_disassemble = false;
|
||||
|
||||
sql_print_information("target address: [0x%016lx]", jump_target);
|
||||
sql_print_information("original instruction: [%s]", ud_insn_asm(&ud_obj));
|
||||
}
|
||||
#endif
|
||||
if (cannot_disassemble)
|
||||
{
|
||||
@@ -381,8 +436,17 @@ static bool HookFunction(ULONG_PTR targetFunction, ULONG_PTR newFunction, ULONG_
|
||||
return false;
|
||||
}
|
||||
|
||||
WriteJump((BYTE*)trampolineFunction + uCurrentSize, targetFunction + InstrSize);
|
||||
// Save the original code that is going to be overwitten by the jump.
|
||||
// The code in the trampoline can be larger due to rewriting of RIP
|
||||
// relative instructions and unsuitable for writting back on unhook.
|
||||
memcpy(saved_code->code, (void*)targetFunction, InstrSize);
|
||||
saved_code->size = InstrSize;
|
||||
|
||||
// jump from trampoline back to continue the original function
|
||||
WriteJump((BYTE*)trampolineFunction + uCurrentSize, targetFunction + InstrSize);
|
||||
*usedsize = uCurrentSize + JUMP_SIZE;
|
||||
|
||||
// jump from the begin of the original function to our function
|
||||
#ifndef __x86_64__
|
||||
WriteJump((void *) targetFunction, newFunction);
|
||||
#else
|
||||
@@ -411,7 +475,7 @@ 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, SavedCode* saved_code)
|
||||
{
|
||||
DATATYPE_ADDRESS FunctionPage = get_page_address((void*)Function);
|
||||
if (unprotect((void*)FunctionPage, PAGE_SIZE) != 0)
|
||||
@@ -421,7 +485,7 @@ static void UnhookFunction(ULONG_PTR Function, ULONG_PTR trampolineFunction, uns
|
||||
log_prefix, (void *) FunctionPage);
|
||||
return;
|
||||
}
|
||||
memcpy((void *) Function, (void*)trampolineFunction,trampolinesize);
|
||||
memcpy((void *) Function, saved_code->code, saved_code->size);
|
||||
protect((void*)FunctionPage, PAGE_SIZE);
|
||||
}
|
||||
|
||||
@@ -442,12 +506,12 @@ static void UnhookFunction(ULONG_PTR Function, ULONG_PTR trampolineFunction, uns
|
||||
* @Return 0 on success otherwise failure
|
||||
* @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, unsigned int *usedsize, bool info_print)
|
||||
int hot_patch_function(void *targetFunction, void *newFunction, void *trampolineFunction, unsigned int *trampolinesize, unsigned int *usedsize, bool info_print, SavedCode* saved_code)
|
||||
{
|
||||
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);
|
||||
if (HookFunction((ULONG_PTR) targetFunction, (ULONG_PTR) newFunction,
|
||||
(ULONG_PTR) trampolineFunction, trampolinesize, usedsize))
|
||||
(ULONG_PTR) trampolineFunction, trampolinesize, usedsize, saved_code))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -466,15 +530,18 @@ int hot_patch_function(void *targetFunction, void *newFunction, void *trampoline
|
||||
* @param trampolineFunction a function which contains a jump back to the targetFunction.
|
||||
* @param log_file if not null will log about progress of installing the plugin
|
||||
*/
|
||||
void remove_hot_patch_function(void *targetFunction, void *trampolineFunction, unsigned int trampolinesize, bool info_print)
|
||||
void remove_hot_patch_function(void *targetFunction, void *trampolineFunction, unsigned int trampolinesize, bool info_print, SavedCode* saved_code)
|
||||
{
|
||||
if (trampolinesize == 0)
|
||||
sql_print_information("trampolinesize: %d", trampolinesize);
|
||||
sql_print_information("saved_code->size: %zd", saved_code->size);
|
||||
if (trampolinesize == 0 || !saved_code->size)
|
||||
{
|
||||
// nothing todo. As hot patch was not set.
|
||||
return;
|
||||
cond_info_print(info_print, "%s not removing as hot patch was not set: %p",log_prefix, (void *)targetFunction);
|
||||
return;
|
||||
}
|
||||
DATATYPE_ADDRESS targetPage = get_page_address(targetFunction);
|
||||
cond_info_print(info_print, "%s removing hot patching function: %p targetPage: %p trampolineFunction: %p",log_prefix, (void *)targetFunction, (void *)targetPage, (void *)trampolineFunction);
|
||||
UnhookFunction ((ULONG_PTR) targetFunction, (ULONG_PTR)trampolineFunction,trampolinesize);
|
||||
UnhookFunction ((ULONG_PTR) targetFunction, (ULONG_PTR)trampolineFunction,trampolinesize, saved_code);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -22,3 +22,6 @@ libudis86_la_SOURCES = itab.c \
|
||||
|
||||
itab.c itab.h: ../docs/x86optable.xml opgen.py
|
||||
python ./opgen.py
|
||||
|
||||
# generate the generated sources prior to the compilation
|
||||
BUILT_SOURCES = itab.c itab.h
|
||||
|
||||
Reference in New Issue
Block a user