36 Commits

Author SHA1 Message Date
Patrick Wade
4c91fb3692 * Added support for:
MySQL 64-bit   8.0.28, 8.0.27, 8.0.26

MySQL 64-bit   5.7.37
MySQL 32-bit   5.7.37

MariaDB 64-bit  10.6.7, 10.6.5, 10.6.4, 10.6.3

MariaDB 64-bit  10.5.15, 10.4.24, 10.2.43
MariaDB 32-bit  10.2.43
2022-07-26 17:34:24 +01:00
pwrpw
1f19442b6e access check 2022-06-16 12:35:04 +01:00
Patrick Wade
bcde7e83e6 Added support for:
Percona 64-bit  5.7.36-39

MySQL 64-bit   5.7.36
MySQL 32-bit   5.7.36

MariaDB 64-bit  10.5.13, 10.4.22, 10.2.41
MariaDB 32-bit  10.2.41
2022-03-15 16:05:37 +00:00
Barrett, William
29a12f3441 Adding support for:
MySQL      64-bit    5.7.35
MariaDB   64-bit    10.5.12, 10.4.21, 10.2.40
Percona    64-bit    5.7.35-38
MySQL      32-bit    5.7.35
MariaDB   32-bit    10.2.40

Updating THIRDPARTY.txt
2021-12-07 13:30:09 +00:00
Patrick Wade
10c4255ebe Added support for:
Percona 64-bit  5.7.34-37
MySQL 64-bit   8.0.25, 8.0.24, 5.7.34
MariaDB 64-bit  10.2.39, 10.2.38, 10.5.11, 10.5.10, 10.4.20, 10.4.19, 10.4.18, 10.4.17, 10.4.16, 10.4.15, 10.4.14, 10.4.13, 10.4.12, 10.4.11, 10.4.10, 10.4.8, 10.4.7, 10.4.6

MySQL 32-bit   5.7.34
MariaDB 32-bit  10.2.39, 10.2.38
2021-09-14 15:47:30 +01:00
William Barrett
e2b3d52fc7 Update CODEOWNERS 2021-08-20 15:15:48 +01:00
William Barrett
0bf751633a Create CODEOWNERS 2021-08-20 10:25:27 +01:00
William Barrett
85557b0f03 Updating README to point to LICENSE 2021-08-03 12:37:45 +01:00
William Barrett
974a169127 Create LICENSE.md 2021-08-03 12:36:30 +01:00
William Barrett
e87e8ec29d Update README.md
Updating README.md to point to CONTRIBUTING.md
2021-07-20 18:28:23 +01:00
William Barrett
a48d47210d Create CONTRIBUTING.md 2021-07-20 18:27:11 +01:00
William Barrett
9514cd999b Update README.md
Minor changes to README
2021-06-25 11:06:21 +01:00
Patrick Wade
b02c4b443c Added support for:
Percona  64-bit  5.7.32-35, 5.7.33-36
MySQL  64-bit   8.0.23, 5.7.33, 5.6.51
MariaDB 64-bit  10.2.37, 10.5.4, 10.5.5, 10.5.6, 10.5.7, 10.5.8, 10.5.9
MySQL  32-bit   5.7.33, 5.6.51
Plugin now provides OS User and Application details in events for MariaDB, where available.
2021-06-01 16:01:22 +01:00
William Barrett
a45cbf78fd Update README.md
No Longer publishing releases to Bintray
2021-04-29 17:42:39 +01:00
Patrick Wade
7057e313ff Adding McAfee code of conduct 2021-04-28 15:23:54 +01:00
Patrick Wade
cd928db022 Updating with the latest offsets for
Percona64 	5.7.31-34
MySQL64 	5.6.50, 5.7.32
MariaDB64	10.2.36, 10.2.35, 10.1.48
MySQL32		5.6.50, 5.7.32
MariaDB32	10.2.36, 10.2.35, 10.1.48
2021-02-23 16:47:11 +00:00
pwrpw
622366a459 Update README.md 2021-02-21 13:33:43 +00:00
wbarrettmcafee
3ec0c137c9 Updating with the latest offsets for
Percona64 	5.7.30-33, 5.7.29-32, 5.7.28-31, 5.7.27-30, 5.7.26-29

MySQL64 	8.0.22, 9.0.21, 8.0.20, 8.0.19, 8.0.18, 8.0.17, 8.0.16, 8.0.15, 8.0.14, 8.0.13, 8.0.12, 8.0.11,
		5.6.49, 5.7.31, 5.6.46, 5.6.47, 5.6.48, 5.7.30, 5.7.29, 5.7.28, 5.6.45, 5.7.27, 5.6.44, 5.7.26

MariaDB64	10.1.43, 10.2.27, 10.2.29, 5.5.66, 10.1.47, 10.2.34, 10.2.30, 10.2.33, 10.1.46, 10.2.31, 10.1.44,
		10.1.45, 10.2.32, 5.5.67, 5.5.68, 10.1.41, 10.2.26, 5.5.65, 10.2.25, 10.1.40, 10.1.39, 10.2.24,
		10.2.23, 5.5.64

MySQL32		5.6.49, 5.7.31, 5.6.46, 5.6.47, 5.6.48, 5.7.28, 5.7.29, 5.7.30, 5.6.45, 5.7.27, 5.6.44, 5.7.26

MariaDB32	10.1.43, 10.2.27, 10.2.29, 5.5.66, 10.1.47, 10.2.34, 10.2.30, 10.2.33, 10.1.46, 10.2.32, 10.1.44,
		10.1.45, 10.2.31, 5.5.67, 5.5.68, 10.1.41, 10.2.26, 5.5.65, 10.2.25, 10.1.40, 10.1.39, 10.2.24,
		10.2.23, 5.5.64
2020-12-03 15:15:07 +00:00
Twomey, Sean
a875a835a4 Update with the latest offsets for
MySQL 5.6.43, 5.7.25, 5.5.62, 5.6.42, 5.7.24
MariaDB 10.2.21, 10.2.20, 10.2.19, 10.1.37, 10.0.37, 5.5.62
Percona 5.7.24-27,  5.7.24-26,  5.7.23-25, 5.7.23-24
2019-03-12 16:56:15 +00:00
Twomey, Sean
2b130c7bd7 Remove file falsely added 2018-11-21 10:41:44 +00:00
Twomey, Sean
266447b8b7 update API Key 2018-11-14 15:24:56 +00:00
Twomey, Sean
416e6fa0aa Add offsets for the follow versions
MySQL 	5.5.60
MySQL 	5.5.61
MySQL 	5.6.40
MySQL 	5.6.41
MySQL 	5.7.22
MySQL 	5.7.23

MariaDB 	5.5.59
MariaDB 	5.5.60
MariaDB 	5.5.61

MariaDB 	10.0.35-36
MariaDB 	10.1.32-36
MariaDB 	10.2.14-18
Percona 	5.7.22-23
2018-11-12 16:41:44 +00:00
Aharon Robbins
edbed38f42 Update copyright year in README.md. 2018-03-25 14:19:12 +03:00
Aharon Robbins
72af9c00f4 Add offsets for Percona 5.7.21-20. 2018-02-21 09:19:48 +02:00
Aharon Robbins
637d30a568 Add offsets for MariaDB 10.2.13. 2018-02-15 11:43:35 +02:00
Aharon Robbins
a52594c59c Add offsets for MariaDB 10.1.31. 2018-02-08 10:52:38 +02:00
Aharon Robbins
cb2cbc605c Add offsets for MariaDB 10.0.34. 2018-01-31 13:21:41 +02:00
Aharon Robbins
52c611cef8 MySQL 5.5.59, 5.6.39, 5.7.21
MariaDB 5.5.59, 10.2.12
Percona 5.7.20-19
2018-01-22 14:23:28 +02:00
Tomer Hadri
6ea0b6bd15 Merge branch 'master' of https://github.com/mcafee/mysql-audit
Conflicts:
	src/audit_offsets.cc
2017-12-28 14:49:00 +02:00
Tomer Hadri
2d0a23c73d - Add support for Percona`s MySQL 5.7.19-17, 5.7.20-18
- MySQL 5.1 support EOL
2017-12-28 14:34:46 +02:00
Aharon Robbins
bca3715fb5 Add support for Percona 5.7.19-17 64-bit.
Add support for MySQL 5.5.58, 5.6.38, 5.7.20.
Add support for MariaDB 5.5.58, 10.0.33, 10.1.27-29, 10.2.8-11.
2017-12-05 12:27:22 +02:00
Tomer Hadri
d9786405af Add support for 5.5.58, 5.6.38, 5.7.20.
Include code from https://github.com/mcafee/mysql-audit/pull/179.
2017-10-22 11:48:27 +03:00
Aharon Robbins
286197fe6d Add offsets for MySQL 5.5.57, 5.6.37 and 5.7.19. 2017-09-13 12:42:55 +03:00
Aharon Robbins
40dc1e7ff7 Add offsets for MariaDB 10.0.32 and 10.1.26.
Fix Community Issues 171, 172, 173.
Add support for sending exit status of a command.
2017-08-31 11:16:19 +03:00
Aharon Robbins
969d0b481a Add offsets for MariaDB 5.5.57. 2017-07-20 17:46:45 +03:00
Aharon Robbins
e7d07fc1fe Add offsets for MariaDB 10.2.7. 2017-07-13 15:35:14 +03:00
22 changed files with 3728 additions and 1462 deletions

1
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1 @@
@awalicka @pwrpw @wpdbarrett

77
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,77 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team via **Github Issues**
All complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

63
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,63 @@
# Contributing to mysql-audit
Welcome, and thank you for your interest in contributing to mysql-audit!
## Asking Questions
Have a question? </br>
We accept questions as issues on GitHub.</br>
https://github.com/mcafee/mysql-audit/issues
## Providing Feedback
Have some feedback? We would love to hear it!</br>
Open an issue and let us know what you think.</br>
https://github.com/mcafee/mysql-audit/issues
## Reporting Issues
Found a bug?
Please feel free to report to: https://github.com/mcafee/mysql-audit/issues
### Look For an Existing Issue
Before you create a new issue, please do a search in [open issues](https://github.com/mcafee/mysql-audit/issues) to see if the issue or feature request has already been filed.
If you find your issue already exists, make relevant comments and add your [reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Use a reaction in place of a "+1" comment:
* 👍 - upvote
* 👎 - downvote
If you cannot find an existing issue that describes your bug or feature, create a new issue using the guidelines below.
### Writing Good Bug Reports and Feature Requests
Be sure to include a **title and clear description** with as much information as possible.
If reporting a bug, please describe the problem verbosely. Try to see if it reproduces and
include a detailed description on how to reproduce.
Make sure to include your MySQL Server version and Audit Plugin version.
To print MySQL Server version: log into MySQL and execute the command:
status
Please include with the bug the MySQL error log.
Log file location can be queried by running the following command:
show global variables like 'log_error'
## Contributing
* Open a new GitHub pull request with a patch - name the patch something along the lines of `{contributor-name}-short-description`
* Ensure the pull request description clearly describes the problem/fix and solution. Include the relevant issue number if applicable.
* Follow the coding and documentation conventions in the existing project. Pull requests that simply reformat or restructure the content will not be accepted.
# Thank You!
Your contributions to open source, large or small, make great projects like this possible. Thank you for taking the time to contribute.

13
LICENSE.md Normal file
View File

@@ -0,0 +1,13 @@
# License
Copyright (C) 2021 Musarubra US 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.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
See COPYING file for a copy of the GPL Version 2 license.
<sup>*</sup> Other trademarks and brands may be claimed as the property of others.

View File

@@ -1,56 +1,31 @@
AUDIT Plugin for MySQL<sup>*</sup>
===================
# AUDIT Plugin for MySQL<sup>*</sup>
A MySQL plugin from McAfee providing audit capabilities for MySQL,
## Overview
A MySQL plugin from Trellix providing audit capabilities for MySQL,
designed with an emphasis on security and audit requirements. The plugin may be used
as a standalone audit solution or configured to feed data to external monitoring tools.
Installation and Configuration
------------------------------
Please check out our wiki on github for detailed installation and configuration instructions:
## Documentation
Please check out our wiki on GitHub. <br/>
https://github.com/mcafee/mysql-audit/wiki
Issues
------------------------------
## Installation / Configuration
Official Trellix plugin binary releases can be downloaded from the Releases page on GitHub: <br/>
https://github.com/mcafee/mysql-audit/releases
Please check out our wiki on GitHub for detailed installation and configuration instructions: <br/>
https://github.com/mcafee/mysql-audit/wiki
## Feedback / Bug Reporting
Found a bug? Got a feature request or question?
Please feel free to report to: https://github.com/mcafee/mysql-audit/issues
If reporting a bug, please describe the problem verbosely. Try to see if it reproduces and
include a detailed description on how to reproduce.
Make sure to include your MySQL Server version and Audit Plugin version.
To print MySQL Server version: log into MySQL and execute the command:
status
Please include with the bug the MySQL error log.
Log file location can be queried by running the following command:
show global variables like 'log_error'
Check out the [CONTRIBUTING.md](https://github.com/mcafee/mysql-audit/blob/master/CONTRIBUTING.md) to see how you can get involved.
Source Code
-------------------------------
## Source Code
Source code is available at: https://github.com/mcafee/mysql-audit
License
-------------------------------
Copyright (C) 2011-2017 McAfee, Inc.
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.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
See COPYING file for a copy of the GPL Version 2 license.
<sup>*</sup> Other trademarks and brands may be claimed as the property of others.

File diff suppressed because it is too large Load Diff

View File

@@ -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.12 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"

View File

@@ -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 -I$withval/wsrep-lib/include -I$withval/wsrep-lib/wsrep-API/v26"
AC_MSG_RESULT(["$withval"])
],
[

View File

@@ -16,10 +16,19 @@ AC_DEFUN([CHECK_DEBUG], [
AC_MSG_CHECKING(whether to enable debugging)
if test "x$enable_debug" = "xyes"; then
CPPFLAGS="$CPPFLAGS -g -D_DEBUG"
# Note that SAFE_MUTEX is needed in debug plugin compilation, in order that
# it aligns with MySQL at debug level. Specifically, in the MySQL source file
# "include/thr_mutex.h", we need both the my_mutex_init() function and the
# my_mutex_lock() function to use the same paradigm (i.e. both using
# "safe_mutex_*" calls ... or both using "native_mutex_*" calls ... but
# definitely NOT a mix of 'safe' and 'native').
CPPFLAGS="$CPPFLAGS -g -D_DEBUG -DSAFE_MUTEX"
AC_MSG_RESULT(yes)
else
CPPFLAGS="$CPPFLAGS -g -O2 -DDBUG_OFF"
# We need to specify -DDBUG_OFF and -DNDEBUG in order to compile the plugin
# without MySQL debug components. Later versions of MySQL ignore the DBUG_OFF
# flag, but continue to respect the NDEBUG flag.
CPPFLAGS="$CPPFLAGS -g -O2 -DDBUG_OFF -DNDEBUG"
AC_MSG_RESULT(no)
fi
@@ -96,8 +105,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,12 +136,29 @@ 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)
AC_SUBST(CXXLAGS)
AC_SUBST(CLAGS)
#mariadb-visibility section start
AC_ARG_ENABLE(mariadb-visibility,
[ --enable-mariadb-visibility, Enable symbol visibility for Mariadb, default:no ],
[case "${enableval}" in
yes) mariadb_visibility=yes ;;
no) mariadb_visibility=no ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-mariadb-visibility]) ;;
esac],
[ mariadb_visibility=no ]
)
AC_MSG_RESULT($mariadb_visibility)
AM_CONDITIONAL([ENABLE_MARIADB_SYMBOLS], [test "x$mariadb_visibility" = "xyes"])
#mariadb-visibility section end
AC_CONFIG_FILES([Makefile
src/Makefile

View File

@@ -17,7 +17,7 @@
#include <pcre.h>
#define AUDIT_LOG_PREFIX "McAfee Audit Plugin:"
#define AUDIT_LOG_PREFIX "Trellix Audit Plugin:"
#define AUDIT_PROTOCOL_VERSION "1.0"
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 50709
@@ -69,7 +69,7 @@ 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
#define MAX_USER_CHAR_NUMBERS 32
#define MAX_NUM_OBJECT_ELEM 256
#define MAX_NUM_USER_ELEM 256
@@ -101,6 +101,10 @@ typedef struct ThdOffsets {
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;
/*
@@ -145,6 +149,9 @@ public:
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.
*/
@@ -178,6 +185,9 @@ private:
int m_port; // TCP port of remote side
uint m_errorCode;
bool m_setErrorCode;
protected:
ThdSesData(const ThdSesData&);
ThdSesData &operator =(const ThdSesData&);
@@ -215,7 +225,9 @@ 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);
@@ -240,8 +252,14 @@ public:
{
if (! Audit_formatter::thd_offsets.db) // no offsets use compiled in header
{
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID < 50709
return thd->db;
#elif defined(MARIADB_BASE_VERSION)
#if MYSQL_VERSION_ID >= 100307
return thd->db.str;
#else
return thd->db;
#endif
#else
return thd->db().str;
#endif
@@ -278,7 +296,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
@@ -337,15 +357,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)
@@ -387,25 +401,21 @@ public:
}
#endif
static inline const char * pfs_connect_attrs(void * pfs)
static inline const char * pfs_connect_attrs(const void * pfs)
{
if (! Audit_formatter::thd_offsets.pfs_connect_attrs)
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);
if (pfs_pointer == NULL)
{
return NULL;
}
return *pfs_pointer;
}
static inline uint pfs_connect_attrs_length(void * pfs)
static inline uint pfs_connect_attrs_length(const void * pfs)
{
if (! Audit_formatter::thd_offsets.pfs_connect_attrs_length)
if (! Audit_formatter::thd_offsets.pfs_connect_attrs_length || pfs == NULL)
{
//no offsets - return 0
return 0;
@@ -413,9 +423,9 @@ public:
return *(uint *) (((unsigned char *) pfs) + Audit_formatter::thd_offsets.pfs_connect_attrs_length);
}
static inline const CHARSET_INFO * pfs_connect_attrs_cs(void * pfs)
static inline const CHARSET_INFO * pfs_connect_attrs_cs(const 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;
@@ -437,7 +447,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);
@@ -516,6 +526,47 @@ static inline const CHARSET_INFO * pfs_connect_attrs_cs(void * pfs)
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)
{
@@ -527,17 +578,28 @@ static inline const CHARSET_INFO * pfs_connect_attrs_cs(void * pfs)
// and it may return an invalid value for view_db
static inline const char *table_get_db_name(TABLE_LIST *table)
{
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100307
return table->db.str;
#else
return table->db;
#endif
}
static inline const char *table_get_name(TABLE_LIST *table)
{
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100307
return table->table_name.str;
#else
return table->table_name;
#endif
}
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;
}
};
@@ -550,14 +612,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(false),
m_write_socket_creds(true),
m_password_mask_regex_preg(NULL),
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)
{
}
@@ -664,8 +726,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)
{
}
@@ -831,7 +897,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";
}
@@ -878,8 +947,10 @@ class Audit_socket_handler: public Audit_io_handler {
public:
Audit_socket_handler() :
m_vio(NULL), m_connect_timeout(1), m_write_timeout(0),
m_log_with_error_severity(false)
m_connect_timeout(1)
, m_write_timeout()
, m_vio()
, m_log_with_error_severity()
{
m_io_type = "socket";
}

View File

@@ -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

View File

@@ -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
@@ -37,13 +31,44 @@
#include <mysql/plugin_audit.h>
#endif
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100307
// From MariaDB 10.3 we include macro definitions for items like MY_GNUC_PREREQ
#include <my_compiler.h>
#include <my_global.h>
#endif
#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
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID < 100504
#include <my_global.h>
#endif
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,8 +78,6 @@
#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>
@@ -80,10 +103,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);
@@ -92,12 +112,161 @@ 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
#if (!defined(MARIADB_BASE_VERSION)) && MYSQL_VERSION_ID >= 50600
//Define HAVE_SESS_CONNECT_ATTRS. We define it for mysql 5.6 and above and MariaDB 10.0 and above
#if MYSQL_VERSION_ID >= 50600
#define HAVE_SESS_CONNECT_ATTRS 1
#endif
#include <storage/perfschema/pfs_instr.h>
#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 manually 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_vio_socket_connect()
{
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;
}
extern const std::string & (*_str_session_80026)(int cmd);
extern const LEX_STRING *_command_name;
static inline const char* str_session(int cmd)
{
if (_str_session_80026) return _str_session_80026(cmd).c_str();
if (_command_name) return _command_name[cmd].str;
return "";
}
static inline bool init_str_session()
{
void* handle = dlopen(NULL, RTLD_LAZY);
if (!handle)
return false;
_command_name = (decltype(_command_name))dlsym(handle, "command_name");
_str_session_80026 = (decltype(_str_session_80026))dlsym(handle, "_ZN13Command_names11str_sessionE19enum_server_command");
dlclose(handle);
return _command_name || _str_session_80026;
}
#endif
#endif
/*********************************************/
/* PFS_thread::get_current_thread */
/*********************************************/
#if defined(HAVE_SESS_CONNECT_ATTRS) && defined(MARIADB_BASE_VERSION)
typedef const ::PFS_thread* (*pfs_thread_t)();
extern pfs_thread_t _pfs_thread_get_current_thread;
extern PSI_v1* _psi_interface;
namespace PFS_thread {
static inline const ::PFS_thread* get_current_thread()
{
// Try PFS_thread and PSI_hook when MariaDB
if (_pfs_thread_get_current_thread) return _pfs_thread_get_current_thread();
if (_psi_interface) return (::PFS_thread*)_psi_interface->get_thread();
return NULL;
}
}
static inline bool init_PFS_thread_get_current_thread()
{
// obtain the PFS_thread::get_current_thread() address if it is exported
void* handle = dlopen(NULL, RTLD_LAZY);
if (handle) {
_pfs_thread_get_current_thread = (pfs_thread_t)dlsym(handle, "_ZN10PFS_thread18get_current_threadEv");
dlclose(handle);
}
// obtain the PSI interface address
if (PSI_hook)
_psi_interface = (PSI_v1*)PSI_hook->get_interface(PSI_VERSION_1);
if (!_pfs_thread_get_current_thread && !_psi_interface)
sql_print_information("Failed to initialize Performance Schema. 'osuser' and 'appname' will not be avalilable.");
return true;
}
#elif defined(HAVE_SESS_CONNECT_ATTRS)
namespace PFS_thread {
static inline const ::PFS_thread* get_current_thread()
{
// Use PFS_thread when MySQL
return ::PFS_thread::get_current_thread();
}
}
#endif
static inline bool init()
{
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 80000
return init_vio_socket_connect() && init_str_session();
#elif defined(HAVE_SESS_CONNECT_ATTRS) && defined(MARIADB_BASE_VERSION)
return init_PFS_thread_get_current_thread();
#else
return true;
#endif
}
}
#endif // MYSQL_INCL_H

View File

@@ -32,7 +32,7 @@ DB=db
CLIENT_CAPS="print_offset THD client_capabilities"
# In 5.6 command member is named m_command
if echo $MYVER | grep -P '^(5\.6|5\.7|10\.)' > /dev/null
if echo $MYVER | grep -P '^(5\.6|5\.7|8\.|10\.)' > /dev/null
then
COMMAND_MEMBER=m_command
HAS_CONNECT_ATTRS=yes
@@ -40,7 +40,7 @@ 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
if echo $MYVER | grep -P '^(5\.7)' > /dev/null
if echo $MYVER | grep -P '^(5\.7|8\.)' > /dev/null
then
THREAD_ID=m_thread_id
SEC_CONTEXT=m_main_security_ctx
@@ -59,7 +59,7 @@ 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|10\.[1-2]|5\.6\.(1[5-9]|[2-9][0-9])|10.0.(1[1-9]|[2-9][0-9]))' > /dev/null
if echo $MYVER | grep -P '^(5\.7|8\.|10\.[1-5]|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
@@ -75,7 +75,7 @@ else
CONNECT_ATTRS='printf ", 0, 0, 0"'
fi
if echo $MYVER | grep -P '^5\.7' > /dev/null
if echo $MYVER | grep -P '^(5\.7|8\.0)' > /dev/null
then
if echo $MYVER | grep -P '^5\.7\.8' > /dev/null
then
@@ -110,6 +110,37 @@ 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 to 10.5
DA_SQL_ERRNO="print_offset Diagnostics_area m_sql_errno" # 5.5, 5.6, mariadb 10.0 to 10.5
STMT_DA="print_offset THD m_stmt_da" # 5.6, 5.7, mariadb 10.0 to 10.5
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
set logging on
set width 0
@@ -122,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
@@ -136,6 +167,10 @@ $LEX_SQL
$FOUND_ROWS
$SENT_ROW_COUNT
$ROW_COUNT_FUNC
$STMT_DA
$DA_STATUS
$DA_SQL_ERRNO
$VIEW_TABLES
printf "}"
EOF

View File

@@ -1,7 +1,7 @@
Tue, Jun 27, 2017 10:48:38 AM
Mon, Apr 11, 2022 10:48:38 AM
=============================
By default, the McAfee AUDIT plugin for MySQL* is named "AUDIT" and
By default, the Trellix 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.
@@ -10,10 +10,10 @@ 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
is possible to change the name of the Trellix plugin. The steps are
as follows:
1. If you're currently using the McAfee plugin, unload it.
1. If you're currently using the Trellix 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.
@@ -23,9 +23,9 @@ Before the line that says:
add a line like this:
export MCAFEE_AUDIT_PLUGIN_NAME=MCAFEE # use any name you want
export MCAFEE_AUDIT_PLUGIN_NAME=TRELLIX # use any name you want
You can use any name you like, "MCAFEE" is just an example.
You can use any name you like, "TRELLIX" is just an example.
For other MySQL versions, determine where the mysqld daemon is actually
started, and set the environment variable right before that.
@@ -33,16 +33,16 @@ 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';
install plugin TRELLIX soname 'libaudit_plugin.so';
and/or from /etc/my.cnf:
[mysqld]
plugin-load=MCAFEE=libaudit_plugin.so
plugin-load=TRELLIX=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
name you've chosen. For example, "trellix_json_log_file" instead of
"audit_json_log_file".
If you previously had various "audit_XXX" variables set in your

View File

@@ -24,7 +24,11 @@ pkgplugin_LTLIBRARIES = libaudit_plugin.la
libaudit_plugin_la_DEPENDENCIESADD = pcre
libaudit_plugin_la_LDFLAGS = -module -Wl,--version-script=MySQLPlugin.map
if ENABLE_MARIADB_SYMBOLS
libaudit_plugin_la_LDFLAGS = -module -Wl,--version-script=MariadbPlugin.map
else
libaudit_plugin_la_LDFLAGS = -module -Wl,--version-script=MySQLPlugin.map
endif
libaudit_plugin_la_SOURCES = hot_patch.cc audit_offsets.cc audit_plugin.cc audit_handler.cc md5.cc

13
src/MariadbPlugin.map Normal file
View File

@@ -0,0 +1,13 @@
{
global:
_mysql_plugin_declarations_;
_mysql_plugin_interface_version_;
_mysql_sizeof_struct_st_plugin_;
_maria_plugin_declarations_;
_maria_plugin_interface_version_;
_maria_sizeof_struct_st_plugin_;
audit_plugin_so_init;
thd_alloc_service;
local: *;
};

0
src/MySQLPlugin.map Executable file → Normal file
View File

View File

@@ -508,7 +508,7 @@ 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
{
@@ -585,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);
}
@@ -622,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)
{
@@ -694,9 +697,9 @@ 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);
@@ -756,8 +759,7 @@ static const char *replace_in_string(THD *thd,
}
#ifdef HAVE_SESS_CONNECT_ATTRS
#include <storage/perfschema/pfs_instr.h>
#if 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,
@@ -767,13 +769,105 @@ bool parse_length_encoded_string(const char **ptr,
const CHARSET_INFO *from_cs,
uint nchars_max);
#else
// the function is not exported in MySQL 8 and neither in MariaDB
/**
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;
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;
}
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100504
String_copier copier;
copy_length = copier.well_formed_copy(
&my_charset_utf8mb3_bin
, dest
, dest_size
, from_cs
, *ptr
, data_length
, nchars_max
);
#elif defined(MARIADB_BASE_VERSION) && ( MYSQL_VERSION_ID >= 100104 && MYSQL_VERSION_ID < 100504 )
String_copier copier;
copy_length = copier.well_formed_copy(
&my_charset_utf8_bin
, dest
, dest_size
, from_cs
, *ptr
, data_length
, nchars_max
);
#else
/*
TODO: Migrate the data itself to UTF8MB4,
this is still UTF8MB3 printed in a UTF8MB4 column.
*/
const char *well_formed_error_pos = NULL, *cannot_convert_error_pos = NULL,
*from_end_pos = NULL;
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
);
#endif
*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 PFS_thread * pfs = compat::PFS_thread::get_current_thread();
if (!pfs)
return;
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);
@@ -782,9 +876,10 @@ static void log_session_connect_attrs(yajl_gen gen, THD *thd)
const uint max_idx = 32;
uint idx;
const char *ptr;
bool array_start = false;
// 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;
}
@@ -812,6 +907,7 @@ static void log_session_connect_attrs(yajl_gen gen, THD *thd)
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;
}
@@ -825,23 +921,14 @@ static void log_session_connect_attrs(yajl_gen gen, THD *thd)
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;
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;
}
#endif
@@ -861,7 +948,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);
@@ -945,6 +1032,12 @@ ssize_t Audit_json_formatter::event_format(ThdSesData *pThdData, IWriter *writer
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
@@ -980,7 +1073,11 @@ ssize_t Audit_json_formatter::event_format(ThdSesData *pThdData, IWriter *writer
const char *query_text = query;
size_t query_len = qlen;
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100603
if (strcmp(col_connection->cs_name.str, "utf8") != 0)
#else
if (strcmp(col_connection->csname, "utf8") != 0)
#endif
{
// max UTF-8 bytes per char is 4.
size_t to_amount = (qlen * 4) + 1;
@@ -989,7 +1086,11 @@ ssize_t Audit_json_formatter::event_format(ThdSesData *pThdData, IWriter *writer
uint errors = 0;
size_t len = copy_and_convert(to, to_amount,
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100504
&my_charset_utf8mb3_general_ci,
#else
&my_charset_utf8_general_ci,
#endif
query, qlen,
col_connection, & errors);
@@ -1071,10 +1172,19 @@ ssize_t Audit_json_formatter::event_format(ThdSesData *pThdData, IWriter *writer
}
ThdSesData::ThdSesData(THD *pTHD, StatementSource source)
: 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),
m_port(-1), m_source(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);
@@ -1087,6 +1197,15 @@ ThdSesData::ThdSesData(THD *pTHD, StatementSource source)
}
}
void ThdSesData::storeErrorCode()
{
uint code = 0;
if (Audit_formatter::thd_error_code(m_pThd, code))
{
setErrorCode(code);
}
}
bool ThdSesData::startGetObjects()
{
// reset vars as this may be called multiple times
@@ -1094,15 +1213,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

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,6 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "mysql_inc.h"
#include "hot_patch.h"
#include <stdlib.h>
@@ -47,14 +46,14 @@ static Audit_socket_handler json_socket_handler;
static Audit_json_formatter json_formatter;
// flags to hold if audit handlers are enabled
static my_bool json_file_handler_enable = FALSE;
static my_bool force_record_logins_enable = FALSE;
static my_bool json_file_handler_flush = FALSE;
static my_bool json_socket_handler_enable = FALSE;
static my_bool uninstall_plugin_enable = FALSE;
static my_bool validate_checksum_enable = FALSE;
static my_bool offsets_by_version_enable = FALSE;
static my_bool validate_offsets_extended_enable = FALSE;
static my_bool json_file_handler_enable;
static my_bool force_record_logins_enable;
static my_bool json_file_handler_flush;
static my_bool json_socket_handler_enable;
static my_bool uninstall_plugin_enable;
static my_bool validate_checksum_enable;
static my_bool offsets_by_version_enable;
static my_bool validate_offsets_extended_enable;
static char *offsets_string = NULL;
static char *checksum_string = NULL;
static int delay_ms_val = 0;
@@ -104,12 +103,12 @@ static char password_masking_regex_buff[4096] = {0};
static const char default_pw_masking_regex[] =
// identified by [password] '***'
"identified"_COMMENT_SPACE_"by"_COMMENT_SPACE_"(?:password)?"_COMMENT_SPACE_ _QUOTED_PSW_
"identified" _COMMENT_SPACE_ "by" _COMMENT_SPACE_ "(?:password)?" _COMMENT_SPACE_ _QUOTED_PSW_
// password function
"|password"_COMMENT_SPACE_"\\("_COMMENT_SPACE_ _QUOTED_PSW_ _COMMENT_SPACE_"\\)"
"|password" _COMMENT_SPACE_ "\\(" _COMMENT_SPACE_ _QUOTED_PSW_ _COMMENT_SPACE_ "\\)"
// Used at: CHANGE MASTER TO MASTER_PASSWORD='new3cret', SET PASSWORD [FOR user] = 'hash', password 'user_pass';
"|password"_COMMENT_SPACE_"(?:for"_COMMENT_SPACE_"\\S+?)?"_COMMENT_SPACE_"="_COMMENT_SPACE_ _QUOTED_PSW_
"|password"_COMMENT_SPACE_ _QUOTED_PSW_
"|password" _COMMENT_SPACE_ "(?:for" _COMMENT_SPACE_ "\\S+?)?" _COMMENT_SPACE_ "=" _COMMENT_SPACE_ _QUOTED_PSW_
"|password" _COMMENT_SPACE_ _QUOTED_PSW_
// federated engine create table with connection. See: http://dev.mysql.com/doc/refman/5.5/en/federated-create-connection.html
// commented out as federated engine is disabled by default
// "|ENGINE"_COMMENT_SPACE_"="_COMMENT_SPACE_"FEDERATED"_COMMENT_SPACE_".*CONNECTION"_COMMENT_SPACE_"="_COMMENT_SPACE_"[\'|\"]\\S+?://\\S+?:(?<psw>.*)@\\S+[\'|\"]"
@@ -129,18 +128,15 @@ static char json_socket_name_buff[1024] = {0};
*/
static int (*trampoline_mysql_execute_command)(THD *thd) = NULL;
static unsigned int trampoline_mysql_execute_size = 0;
SavedCode trampoline_mysql_execute_saved_code;
#if MYSQL_VERSION_ID < 50600
static void (*trampoline_log_slow_statement)(THD *thd) = NULL;
static unsigned int trampoline_log_slow_statement_size = 0;
#endif
#if MYSQL_VERSION_ID < 50505
static int (*trampoline_check_user)(THD *thd, enum enum_server_command command, const char *passwd, uint passwd_len, const char *db, bool check_count) = NULL;
static unsigned int trampoline_check_user_size = 0;
#elif MYSQL_VERSION_ID < 50600
SavedCode trampoline_log_slow_statement_saved_code;
static bool (*trampoline_acl_authenticate)(THD *thd, uint connect_errors, uint com_change_user_pkt_len) = NULL;
static unsigned int trampoline_acl_authenticate_size = 0;
SavedCode trampoline_acl_authenticate_saved_code;
#endif
static MYSQL_THDVAR_ULONG(is_thd_printed_list,
@@ -251,7 +247,7 @@ static void initializePeerCredentials(THD *pThd)
peer = (PeerInfo *) THDVAR(pThd, peer_info);
if (peer != NULL)
{
memset(peer, 0, sizeof(PeerInfo));
*peer = PeerInfo();
}
#endif
@@ -371,10 +367,10 @@ static void initializePeerCredentials(THD *pThd)
}
// set that we have a UDS, so that THD vars will be used
THDVAR(pThd, peer_is_uds) = TRUE;
THDVAR(pThd, peer_is_uds) = true;
done:
THDVAR(pThd, set_peer_cred) = TRUE;
THDVAR(pThd, set_peer_cred) = true;
}
PeerInfo *retrieve_peerinfo(THD *thd)
@@ -388,7 +384,7 @@ PeerInfo *retrieve_peerinfo(THD *thd)
{
PeerInfo *peer = (PeerInfo *) THDVAR(thd, peer_info);
if (THDVAR(thd, peer_is_uds) && peer != NULL);
if (THDVAR(thd, peer_is_uds) && peer != NULL)
{
return peer;
}
@@ -397,20 +393,25 @@ PeerInfo *retrieve_peerinfo(THD *thd)
return NULL;
}
static int check_array(const char *cmds[],const char *array, int length)
// cmds[] is a list of "commands" (names, commands, whatever) to
// check against the list stored in `array'. Although declared
// here as simple `char *', the `array' is actually a two-dimensional
// array where each element is `length' bytes long. (An array of
// strings.)
//
// We loop over the array and for each element see if it's also
// in `cmds'. If so, we return 1, otherwise we return 0.
//
// This should really be of type bool and return true/false.
static int check_array(const char *cmds[], const char *array, int length)
{
for (int k = 0; array[k * length] !='\0';k++)
{
const char *elem = array + (k * length);
for (int q = 0; cmds[q] != NULL; q++)
{
const char *cmd = cmds[q];
int j = 0;
while (array[k * length + j] != '\0' && cmd[j] != '\0'
&& array[k * length + j] == tolower(cmd[j]))
{
j++;
}
if (array[k * length + j] == '\0' && j != 0)
if (strcasecmp(cmd, elem) == 0)
{
return 1;
}
@@ -576,11 +577,15 @@ static void audit(ThdSesData *pThdData)
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
static int (*trampoline_send_result_to_client)(Query_cache *pthis, THD *thd, char *sql, uint query_length) = NULL;
#else
#elif MYSQL_VERSION_ID < 80000
static int (*trampoline_send_result_to_client)(Query_cache *pthis, THD *thd, const LEX_CSTRING& sql_query) = NULL;
#endif
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100108
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID == 100224
static bool (*trampoline_open_tables)(THD *thd, const DDL_options_st &options, TABLE_LIST **start, uint *counter,
Sroutine_hash_entry **sroutine_to_open, uint flags, Prelocking_strategy *prelocking_strategy) = NULL;
#elif defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100108
static bool (*trampoline_open_tables)(THD *thd, const DDL_options_st &options, TABLE_LIST **start, uint *counter, uint flags,
Prelocking_strategy *prelocking_strategy) = NULL;
#elif MYSQL_VERSION_ID > 50505
@@ -591,28 +596,24 @@ static int (*trampoline_open_tables)(THD *thd, TABLE_LIST **start, uint *counter
#endif
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 80000
QueryTableInf *Audit_formatter::getQueryCacheTableList1(THD *thd)
{
return (QueryTableInf*) THDVAR(thd, query_cache_table_list);
}
#endif
static bool (*trampoline_check_table_access)(THD *thd, ulong want_access,TABLE_LIST *tables,
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID >= 50505
bool any_combination_of_privileges_will_do,
#endif
uint number, bool no_errors) = NULL;
static bool audit_check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID >= 50505
bool any_combination_of_privileges_will_do,
#endif
uint number, bool no_errors)
{
TABLE_LIST *pTables;
bool res = trampoline_check_table_access(thd, want_access, tables,
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID >= 50505
any_combination_of_privileges_will_do,
#endif
number, no_errors);
if (!res && tables)
{
@@ -642,7 +643,9 @@ static bool audit_check_table_access(THD *thd, ulong want_access,TABLE_LIST *tab
}
static unsigned int trampoline_check_table_access_size = 0;
SavedCode trampoline_check_table_access_saved_code;
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 80000
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
static int audit_send_result_to_client(Query_cache *pthis, THD *thd, char *sql, uint query_length)
#else
@@ -665,16 +668,25 @@ static int audit_send_result_to_client(Query_cache *pthis, THD *thd, const LEX_
#endif
if (res)
{
ThdSesData thd_data(thd, ThdSesData::SOURCE_QUERY_CACHE);
audit(&thd_data);
ThdSesData thdData(thd, ThdSesData::SOURCE_QUERY_CACHE);
thdData.storeErrorCode();
audit(&thdData);
}
THDVAR(thd, query_cache_table_list) = 0;
return res;
}
static unsigned int trampoline_send_result_to_client_size = 0;
SavedCode trampoline_send_result_to_client_saved_code;
#endif // defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 80000
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100108
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID == 100224
static bool audit_open_tables(THD *thd, const DDL_options_st &options, TABLE_LIST **start, uint *counter,
Sroutine_hash_entry **sroutine_to_open, uint flags, Prelocking_strategy *prelocking_strategy)
{
bool res;
res = trampoline_open_tables (thd, options, start, counter, sroutine_to_open, flags, prelocking_strategy);
#elif defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100108
static bool audit_open_tables(THD *thd, const DDL_options_st &options, TABLE_LIST **start, uint *counter, uint flags,
Prelocking_strategy *prelocking_strategy)
{
@@ -697,13 +709,15 @@ static int audit_open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint f
&& (Audit_formatter::thd_inst_thread_id(thd)
|| Audit_formatter::thd_inst_query_id(thd)))
{
ThdSesData thd_data (thd);
ThdSesData thd_data(thd);
// This is before something is run, so no need to set exit status
audit(&thd_data);
}
return res;
}
static unsigned int trampoline_open_tables_size = 0;
SavedCode trampoline_open_tables_saved_code;
// called by log_slow_statement and general audit event caught by audit interface
static void audit_post_execute(THD * thd)
@@ -712,10 +726,11 @@ static void audit_post_execute(THD * thd)
// query events are audited by mysql execute command
if (Audit_formatter::thd_inst_command(thd) != COM_QUERY)
{
ThdSesData ThdData(thd);
if (strcasestr(ThdData.getCmdName(), "show_fields") == NULL)
ThdSesData thdData(thd);
if (strcasestr(thdData.getCmdName(), "show_fields") == NULL)
{
audit(&ThdData);
thdData.storeErrorCode();
audit(&thdData);
}
}
}
@@ -779,6 +794,7 @@ static int audit_notify(THD *thd, mysql_event_class_t event_class,
case ER_ACCOUNT_HAS_BEEN_LOCKED:
#endif
ThdData.setCmdName("Failed Login");
ThdData.setErrorCode(event_general->general_error_code);
audit(&ThdData);
break;
default:
@@ -836,21 +852,23 @@ static struct st_mysql_audit audit_plugin =
#endif
// some extern definitions which are not in include files
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 80000
extern void log_slow_statement(THD *thd);
#endif
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100603
extern int mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt);
#else
extern int mysql_execute_command(THD *thd);
#endif
#if defined(MARIADB_BASE_VERSION)
extern void end_connection(THD *thd);
static int (*trampoline_end_connection)(THD *thd) = NULL;
static unsigned int trampoline_end_connection_size = 0;
SavedCode trampoline_end_connection_saved_code;
#endif
#if MYSQL_VERSION_ID >= 50505
// in 5.5 builtins is named differently
#define mysqld_builtins mysql_mandatory_plugins
#endif
extern struct st_mysql_plugin *mysqld_builtins[];
void remove_hot_functions()
{
void * target_function = NULL;
@@ -858,23 +876,21 @@ void remove_hot_functions()
#if MYSQL_VERSION_ID < 50600
target_function = (void *) log_slow_statement;
remove_hot_patch_function(target_function,
(void*) trampoline_log_slow_statement, trampoline_log_slow_statement_size, true);
(void*) trampoline_log_slow_statement, trampoline_log_slow_statement_size, true, &trampoline_log_slow_statement_saved_code);
trampoline_log_slow_statement_size = 0;
#endif
#if MYSQL_VERSION_ID < 50505
target_function = (void *) check_user;
remove_hot_patch_function(target_function,
(void*) trampoline_check_user, trampoline_check_user_size, true);
trampoline_check_user_size = 0;
#elif MYSQL_VERSION_ID < 50600
trampoline_log_slow_statement_saved_code.size = 0;
target_function = (void *) acl_authenticate;
remove_hot_patch_function(target_function,
(void*) trampoline_acl_authenticate, trampoline_acl_authenticate_size, true);
(void*) trampoline_acl_authenticate, trampoline_acl_authenticate_size, true, &trampoline_acl_authenticate_saved_code);
trampoline_acl_authenticate_size = 0;
trampoline_acl_authenticate_saved_code.size = 0;
#endif
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100108
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID == 100224
target_function = (void *)*(bool (*)(THD *thd, const DDL_options_st &options, TABLE_LIST **start, uint *counter,
Sroutine_hash_entry **sroutine_to_open, uint flags, Prelocking_strategy *prelocking_strategy)) &open_tables;
#elif defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100108
target_function = (void *)*(bool (*)(THD *thd, const DDL_options_st &options, TABLE_LIST **start, uint *counter, uint flags,
Prelocking_strategy *prelocking_strategy)) &open_tables;
#elif MYSQL_VERSION_ID > 50505
@@ -884,9 +900,11 @@ void remove_hot_functions()
target_function = (void *)*(int (*)(THD *thd, TABLE_LIST **start, uint *counter, uint flags)) &open_tables;
#endif
remove_hot_patch_function(target_function,
(void*) trampoline_open_tables, trampoline_open_tables_size, true);
(void*) trampoline_open_tables, trampoline_open_tables_size, true, &trampoline_open_tables_saved_code);
trampoline_open_tables_size = 0;
trampoline_open_tables_saved_code.size = 0;
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 80000
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
int (Query_cache::*pf_send_result_to_client)(THD *,char *, uint) = &Query_cache::send_result_to_client;
#else
@@ -894,15 +912,23 @@ void remove_hot_functions()
#endif
target_function = *(void **) &pf_send_result_to_client;
remove_hot_patch_function(target_function,
(void*) trampoline_send_result_to_client, trampoline_send_result_to_client_size, true);
(void*) trampoline_send_result_to_client, trampoline_send_result_to_client_size, true, &trampoline_send_result_to_client_saved_code);
trampoline_send_result_to_client_size = 0;
trampoline_send_result_to_client_saved_code.size = 0;
#endif
remove_hot_patch_function((void*) check_table_access,
(void*) trampoline_check_table_access,
trampoline_check_table_access_size, true);
trampoline_check_table_access_size, true, &trampoline_check_table_access_saved_code);
trampoline_check_table_access_size=0;
trampoline_check_table_access_saved_code.size = 0;
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100603
target_function = (void*)
(int (*)(THD *thd, bool is_called_from_prepared_stmt)) &mysql_execute_command;
#elif defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID < 100603
target_function = (void*) mysql_execute_command;
#elif MYSQL_VERSION_ID < 50709
target_function = (void*) mysql_execute_command;
#else
target_function = (void*)
@@ -913,14 +939,16 @@ void remove_hot_functions()
target_function = (void*) end_connection;
remove_hot_patch_function(target_function,
(void*) trampoline_end_connection,
trampoline_end_connection_size, true);
trampoline_end_connection_size, true, &trampoline_end_connection_saved_code);
trampoline_end_connection_size = 0;
trampoline_end_connection_saved_code.size = 0;
#endif
remove_hot_patch_function(target_function,
(void*) trampoline_mysql_execute_command,
trampoline_mysql_execute_size, true);
trampoline_mysql_execute_size, true, &trampoline_mysql_execute_saved_code);
trampoline_mysql_execute_size = 0;
trampoline_mysql_execute_saved_code.size = 0;
}
int is_remove_patches(ThdSesData *pThdData)
@@ -939,9 +967,11 @@ int is_remove_patches(ThdSesData *pThdData)
#endif
if (strncasecmp(Lex_comment.str, PLUGIN_NAME, strlen(PLUGIN_NAME)) == 0)
{
char msgBuffer[200];
if (! uninstall_plugin_enable)
{
my_message(ER_NOT_ALLOWED_COMMAND, "Uninstall AUDIT plugin disabled", MYF(0));
sprintf(msgBuffer, "Uninstall %s plugin disabled", PLUGIN_NAME);
my_message(ER_NOT_ALLOWED_COMMAND, msgBuffer, MYF(0));
return 2;
}
@@ -951,7 +981,8 @@ int is_remove_patches(ThdSesData *pThdData)
if (! called_once)
{
called_once = true;
my_message(WARN_PLUGIN_BUSY, "Uninstall AUDIT plugin must be called again to complete", MYF(0));
sprintf(msgBuffer, "Uninstall %s plugin must be called again to complete", PLUGIN_NAME);
my_message(WARN_PLUGIN_BUSY, msgBuffer, MYF(0));
return 2;
}
return 1;
@@ -989,10 +1020,10 @@ static int audit_mysql_execute_command(THD *thd)
}
}
ThdSesData thd_data(thd);
const char *cmd = thd_data.getCmdName();
ThdSesData thdData(thd);
const char *cmd = thdData.getCmdName();
do_delay(& thd_data);
do_delay(& thdData);
if (before_after_mode == AUDIT_BEFORE || before_after_mode == AUDIT_BOTH)
{
@@ -1002,7 +1033,7 @@ static int audit_mysql_execute_command(THD *thd)
strcasestr(cmd, "truncate") != NULL ||
strcasestr(cmd, "rename") != NULL)
{
audit(&thd_data);
audit(&thdData);
}
}
@@ -1017,7 +1048,7 @@ static int audit_mysql_execute_command(THD *thd)
}
else
{
switch (is_remove_patches(&thd_data))
switch (is_remove_patches(&thdData))
{
case 1:
// hot patch function were removed and we call the real execute (restored)
@@ -1037,10 +1068,11 @@ static int audit_mysql_execute_command(THD *thd)
}
}
thdData.storeErrorCode();
if (before_after_mode == AUDIT_AFTER || before_after_mode == AUDIT_BOTH)
{
audit(&thd_data);
audit(&thdData);
}
if (pThdPrintedList && pThdPrintedList->cur_index > 0)
@@ -1062,29 +1094,15 @@ static void audit_log_slow_statement(THD *thd)
trampoline_log_slow_statement(thd);
audit_post_execute(thd);
}
#endif
#if MYSQL_VERSION_ID < 50505
static int audit_check_user(THD *thd, enum enum_server_command command,
const char *passwd, uint passwd_len, const char *db,
bool check_count)
{
int res = trampoline_check_user(thd, command, passwd, passwd_len, db, check_count);
ThdSesData ThdData(thd);
audit(&ThdData);
return (res);
}
#elif MYSQL_VERSION_ID < 50600
// only for 5.5
// in 5.6: we use audit plugin event to get the login event
static bool audit_acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
{
bool res = trampoline_acl_authenticate(thd, connect_errors, com_change_user_pkt_len);
ThdSesData ThdData(thd);
audit(&ThdData);
ThdSesData thdData(thd);
thdData.storeErrorCode();
audit(&thdData);
return (res);
}
@@ -1110,10 +1128,10 @@ static void audit_end_connection(THD *thd)
static bool parse_thd_offsets_string (char *poffsets_string)
{
char offset_str[2048] = {0};
char offset_str[2049] = {0};
char *poffset_str = offset_str;
strncpy(poffset_str,poffsets_string,array_elements(offset_str));
strncpy(poffset_str,poffsets_string,array_elements(offset_str)-1);
char *comma_delimiter = strchr(poffset_str, ',');
size_t i = 0;
@@ -1167,6 +1185,7 @@ static bool parse_thd_offsets_string (char *poffsets_string)
if ((size_t)pOffset- (size_t)&Audit_formatter::thd_offsets < sizeof (Audit_formatter::thd_offsets))
{
sql_print_error("%s Failed parsing audit_offsets: not all offsets specified. This may happen if you used an old version of offset-extract.sh script.", log_prefix);
sql_print_error("%s Got %zu quantity of offsets, but expected more", log_prefix, i);
return false;
}
return true;
@@ -1224,9 +1243,35 @@ static bool validate_offsets(const ThdOffsets *offset)
(*(const char **) (((unsigned char *) sctx) + offset->sec_ctx_user)) = user_test_val;
}
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 80000
PSI_mutex_key key_LOCK_thd_query_validate=99999;
mysql_mutex_init(key_LOCK_thd_query_validate, &thd->LOCK_thd_query, MY_MUTEX_INIT_FAST);
#ifdef _DEBUG
my_mutex_t *mp = &thd->LOCK_thd_query.m_mutex;
if (mp == nullptr)
{
sql_print_information(
"%s validate offsets - mutex for query string is null", log_prefix);
}
else if (mp->m_u.m_safe_ptr != nullptr)
{
sql_print_information(
"%s validate offsets - mutex for query string is safe pointer", log_prefix);
}
else if (mp->m_u.m_safe_ptr == nullptr)
{
sql_print_information(
"%s validate offsets - mutex for query string is native pointer", log_prefix);
}
#endif
#endif
char buffer[2048] = {0};
thd_security_context(thd, buffer, 2048, 1000);
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 80000
mysql_mutex_destroy(&thd->LOCK_thd_query);
#endif
// verfiy our buffer contains query id
if (strstr(buffer, " 789") == NULL || strstr(buffer, user_test_val) == NULL)
{
@@ -1257,9 +1302,17 @@ static bool calc_file_md5(const char *file_name, char *digest_str)
if ((fd = my_open(file_name, O_RDONLY, MYF(MY_WME))) < 0)
{
sql_print_error("%s Failed file open: [%s], errno: %d.",
log_prefix, file_name, errno);
return false;
sql_print_error("%s Failed file open: [%s], errno: %d. Retrying with /proc/%d/exe.",
log_prefix, file_name, errno, getpid());
char pidFilename[100];
sprintf(pidFilename, "/proc/%d/exe", getpid());
if ((fd = my_open(pidFilename, O_RDONLY, MYF(MY_WME))) < 0)
{
sql_print_error("%s Failed file open: [%s], errno: %d.",
log_prefix, pidFilename, errno);
return false;
}
}
my_MD5Context context;
@@ -1348,7 +1401,7 @@ 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 %zu %zu %zu %zu %zu %zu %zu %zu %zu %zu %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 %zu %zu %zu %zu %zu %zu %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,
@@ -1370,7 +1423,11 @@ static int setup_offsets()
Audit_formatter::thd_offsets.uninstall_cmd_comment,
Audit_formatter::thd_offsets.found_rows,
Audit_formatter::thd_offsets.sent_row_count,
Audit_formatter::thd_offsets.row_count_func
Audit_formatter::thd_offsets.row_count_func,
Audit_formatter::thd_offsets.stmt_da,
Audit_formatter::thd_offsets.da_status,
Audit_formatter::thd_offsets.da_sql_errno,
Audit_formatter::thd_offsets.view_tables
);
if (! validate_offsets(&Audit_formatter::thd_offsets))
@@ -1485,11 +1542,23 @@ static int setup_offsets()
{
decoffsets.row_count_func -= dec;
}
if (decoffsets.stmt_da)
{
decoffsets.stmt_da -= dec;
}
if (decoffsets.da_status)
{
decoffsets.da_status -= dec;
}
if (decoffsets.da_sql_errno)
{
decoffsets.da_sql_errno -= dec;
}
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 %zu %zu %zu %zu %zu %zu %zu %zu %zu %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 %zu %zu %zu %zu %zu %zu %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,
@@ -1501,6 +1570,7 @@ static int setup_offsets()
Audit_formatter::thd_offsets.sec_ctx_host,
Audit_formatter::thd_offsets.sec_ctx_ip,
Audit_formatter::thd_offsets.sec_ctx_priv_user,
Audit_formatter::thd_offsets.db,
Audit_formatter::thd_offsets.killed,
Audit_formatter::thd_offsets.client_capabilities,
Audit_formatter::thd_offsets.pfs_connect_attrs,
@@ -1511,7 +1581,11 @@ static int setup_offsets()
Audit_formatter::thd_offsets.uninstall_cmd_comment,
Audit_formatter::thd_offsets.found_rows,
Audit_formatter::thd_offsets.sent_row_count,
Audit_formatter::thd_offsets.row_count_func
Audit_formatter::thd_offsets.row_count_func,
Audit_formatter::thd_offsets.stmt_da,
Audit_formatter::thd_offsets.da_status,
Audit_formatter::thd_offsets.da_sql_errno,
Audit_formatter::thd_offsets.view_tables
);
DBUG_RETURN(0);
@@ -1529,7 +1603,7 @@ 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 %zu %zu %zu %zu %zu %zu %zu %zu %zu %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 %zu %zu %zu %zu %zu %zu %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,
@@ -1541,6 +1615,7 @@ static int setup_offsets()
Audit_formatter::thd_offsets.sec_ctx_host,
Audit_formatter::thd_offsets.sec_ctx_ip,
Audit_formatter::thd_offsets.sec_ctx_priv_user,
Audit_formatter::thd_offsets.db,
Audit_formatter::thd_offsets.killed,
Audit_formatter::thd_offsets.client_capabilities,
Audit_formatter::thd_offsets.pfs_connect_attrs,
@@ -1551,7 +1626,11 @@ static int setup_offsets()
Audit_formatter::thd_offsets.uninstall_cmd_comment,
Audit_formatter::thd_offsets.found_rows,
Audit_formatter::thd_offsets.sent_row_count,
Audit_formatter::thd_offsets.row_count_func
Audit_formatter::thd_offsets.row_count_func,
Audit_formatter::thd_offsets.stmt_da,
Audit_formatter::thd_offsets.da_status,
Audit_formatter::thd_offsets.da_sql_errno,
Audit_formatter::thd_offsets.view_tables
);
DBUG_RETURN(0);
}
@@ -1598,7 +1677,11 @@ const char *retrieve_command(THD *thd, bool &is_sql_cmd)
if (! cmd)
{
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 80000
cmd = command_name[command].str;
#else
cmd = compat::str_session(command);
#endif
}
#if MYSQL_VERSION_ID < 50600
@@ -1737,7 +1820,7 @@ static void *trampoline_mem_free = NULL;
* Utility method for hot patching
*/
static int do_hot_patch(void ** trampoline_func_pp, unsigned int * trampoline_size,
void* target_function, void* audit_function, const char * func_name)
void* target_function, void* audit_function, const char * func_name, SavedCode* saved_code)
{
// 16 byte align the pointer
DATATYPE_ADDRESS addrs = (DATATYPE_ADDRESS)trampoline_mem_free + 15;
@@ -1746,7 +1829,7 @@ static int do_hot_patch(void ** trampoline_func_pp, unsigned int * trampoline_si
// hot patch functions
unsigned int used_size;
int res = hot_patch_function(target_function, audit_function,
*trampoline_func_pp, trampoline_size, &used_size, true);
*trampoline_func_pp, trampoline_size, &used_size, true, saved_code);
if (res != 0)
{
// hot patch failed.
@@ -1762,7 +1845,7 @@ static int do_hot_patch(void ** trampoline_func_pp, unsigned int * trampoline_si
}
#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)\
static void NAME ## _string_update(THD *thd, SYS_VAR *var, void *tgt, const void *save)\
{\
num_ ## NAME = string_to_array(save, NAME ## _array, array_elements( NAME ## _array), sizeof( NAME ## _array[0]));\
/* handle "set global audit_xxx = null;" */ \
@@ -1786,7 +1869,7 @@ DECLARE_STRING_ARR_UPDATE_FUNC(password_masking_cmds)
DECLARE_STRING_ARR_UPDATE_FUNC(whitelist_users)
DECLARE_STRING_ARR_UPDATE_FUNC(record_objs)
static void password_masking_regex_string_update(THD *thd, struct st_mysql_sys_var *var, void *tgt, const void *save)
static void password_masking_regex_string_update(THD *thd, SYS_VAR *var, void *tgt, const void *save)
{
const char *str_val = "";
char *const* save_p = static_cast<char*const*>(save);
@@ -1844,7 +1927,7 @@ static void replace_char(char *str, const char tofind, const char rplc)
}
}
static void json_socket_name_update(THD *thd, struct st_mysql_sys_var *var, void *tgt, const void *save)
static void json_socket_name_update(THD *thd, SYS_VAR *var, void *tgt, const void *save)
{
const char *str_val = NULL;
char *const* save_p = static_cast<char*const*>(save);
@@ -1915,7 +1998,7 @@ static void json_socket_name_update(THD *thd, struct st_mysql_sys_var *var, void
}
// check that the regex compiles. Return 0 on success.
static int password_masking_regex_check(THD *thd, struct st_mysql_sys_var *var, void *save, st_mysql_value *value)
static int password_masking_regex_check(THD *thd, SYS_VAR *var, void *save, st_mysql_value *value)
{
int length = array_elements(password_masking_regex_check_buff);
const char *str = value->val_str(value, password_masking_regex_check_buff, &length);
@@ -1935,7 +2018,7 @@ static int password_masking_regex_check(THD *thd, struct st_mysql_sys_var *var,
}
// 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)
static void record_objs_string_update_extended(THD *thd, 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
@@ -1960,10 +2043,27 @@ static void record_objs_string_update_extended(THD *thd, struct st_mysql_sys_var
* 0 success
* 1 failure
*/
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID > 80000
bool (*compat::_vio_socket_connect)(MYSQL_VIO vio, struct sockaddr *addr, socklen_t len, int timeout);
bool (*compat::_vio_socket_connect_80016)(MYSQL_VIO vio, struct sockaddr *addr, socklen_t len, bool nonblocking, int timeout);
bool (*compat::_vio_socket_connect_80020)(MYSQL_VIO vio, struct sockaddr *addr, socklen_t len, bool nonblocking, int timeout, bool *connect_done);
const std::string & (*compat::_str_session_80026)(int cmd);
const LEX_STRING *compat::_command_name;
#elif defined(HAVE_SESS_CONNECT_ATTRS) && defined(MARIADB_BASE_VERSION)
compat::pfs_thread_t compat::_pfs_thread_get_current_thread;
PSI_v1* compat::_psi_interface;
#endif
static int audit_plugin_init(void *p)
{
DBUG_ENTER("audit_plugin_init");
const bool compat_init_ok = compat::init();
if (!compat_init_ok)
{
sql_print_error("%s unable to init compatibility layer. Aborting.", log_prefix);
DBUG_RETURN(1);
}
#ifdef __x86_64__
const char * arch = "64bit";
@@ -1976,7 +2076,7 @@ static int audit_plugin_init(void *p)
interface_ver = interface_ver >> 8;
#endif
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). MySQL AUDIT plugin interface version: %d (0x%x). MySQL Server version: %s.",
log_prefix, MYSQL_AUDIT_PLUGIN_VERSION,
MYSQL_AUDIT_PLUGIN_REVISION, arch, interface_ver, interface_ver,
server_version);
@@ -2078,7 +2178,7 @@ static int audit_plugin_init(void *p)
trampoline_mem = NULL;
#ifdef __x86_64__
size_t func_in_mysqld = (size_t)log_slow_statement;
size_t func_in_mysqld = (size_t)check_table_access;
size_t func_in_plugin = (size_t)trampoline_dummy_func_for_mem;
if (func_in_mysqld < INT_MAX && func_in_plugin > INT_MAX)
{
@@ -2131,7 +2231,12 @@ static int audit_plugin_init(void *p)
// hot patch stuff
void * target_function = NULL;
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100603
target_function = (void*)
(int (*)(THD *thd, bool is_called_from_prepared_stmt)) &mysql_execute_command;
#elif defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID < 100603
target_function = (void*) mysql_execute_command;
#elif MYSQL_VERSION_ID < 50709
target_function = (void*) mysql_execute_command;
#else
target_function = (void*)
@@ -2139,36 +2244,29 @@ static int audit_plugin_init(void *p)
#endif
if (do_hot_patch((void **)&trampoline_mysql_execute_command, &trampoline_mysql_execute_size,
target_function, (void *)audit_mysql_execute_command, "mysql_execute_command"))
target_function, (void *)audit_mysql_execute_command, "mysql_execute_command", &trampoline_mysql_execute_saved_code))
{
DBUG_RETURN(1);
}
#if MYSQL_VERSION_ID < 50600
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", &trampoline_log_slow_statement_saved_code))
{
sql_print_error("%s Failed hot patch. Continuing as non-critical.",
log_prefix);
}
#endif
#if MYSQL_VERSION_ID < 50505
if (do_hot_patch((void **)&trampoline_check_user, &trampoline_check_user_size,
(void *)check_user, (void *)audit_check_user, "check_user"))
{
DBUG_RETURN(1);
}
#elif MYSQL_VERSION_ID < 50600
if (do_hot_patch((void **)&trampoline_acl_authenticate, &trampoline_acl_authenticate_size,
(void *)acl_authenticate, (void *)audit_acl_authenticate, "acl_authenticate"))
(void *)acl_authenticate, (void *)audit_acl_authenticate, "acl_authenticate", &trampoline_acl_authenticate_saved_code))
{
DBUG_RETURN(1);
}
#endif
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 80000
#if defined(MARIADB_BASE_VERSION) || MYSQL_VERSION_ID < 50709
int (Query_cache::*pf_send_result_to_client)(THD *,char *, uint) = &Query_cache::send_result_to_client;
#else
@@ -2176,18 +2274,22 @@ static int audit_plugin_init(void *p)
#endif
target_function = *(void **) &pf_send_result_to_client;
if (do_hot_patch((void **)&trampoline_send_result_to_client, &trampoline_send_result_to_client_size,
(void *)target_function, (void *)audit_send_result_to_client, "send_result_to_client"))
(void *)target_function, (void *)audit_send_result_to_client, "send_result_to_client", &trampoline_send_result_to_client_saved_code))
{
DBUG_RETURN(1);
}
#endif
if (do_hot_patch((void **)&trampoline_check_table_access, &trampoline_check_table_access_size,
(void *)check_table_access, (void *)audit_check_table_access, "check_table_access"))
(void *)check_table_access, (void *)audit_check_table_access, "check_table_access", &trampoline_check_table_access_saved_code))
{
DBUG_RETURN(1);
}
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100108
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID == 100224
target_function = (void *)*(bool (*)(THD *thd, const DDL_options_st &options, TABLE_LIST **start, uint *counter,
Sroutine_hash_entry **sroutine_to_open, uint flags, Prelocking_strategy *prelocking_strategy)) &open_tables;
#elif defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100108
target_function = (void *)*(bool (*)(THD *thd, const DDL_options_st &options, TABLE_LIST **start, uint *counter, uint flags,
Prelocking_strategy *prelocking_strategy)) &open_tables;
#elif MYSQL_VERSION_ID > 50505
@@ -2197,7 +2299,7 @@ static int audit_plugin_init(void *p)
target_function = (void *)*(int (*)(THD *thd, TABLE_LIST **start, uint *counter, uint flags)) &open_tables;
#endif
if (do_hot_patch((void **)&trampoline_open_tables, &trampoline_open_tables_size,
(void *)target_function, (void *)audit_open_tables, "open_tables"))
(void *)target_function, (void *)audit_open_tables, "open_tables", &trampoline_open_tables_saved_code))
{
DBUG_RETURN(1);
}
@@ -2205,7 +2307,7 @@ static int audit_plugin_init(void *p)
#if defined(MARIADB_BASE_VERSION)
target_function = (void*) end_connection;
if (do_hot_patch((void **)&trampoline_end_connection, &trampoline_end_connection_size,
(void *)target_function, (void *)audit_end_connection, "end_connection"))
(void *)target_function, (void *)audit_end_connection, "end_connection", &trampoline_end_connection_saved_code))
{
DBUG_RETURN(1);
}
@@ -2245,7 +2347,7 @@ static int audit_plugin_deinit(void *p)
Plugin status variables for SHOW STATUS
*/
static struct st_mysql_show_var audit_status[] =
static SHOW_VAR audit_status[] =
{
{ "Audit_version",
(char *) MYSQL_AUDIT_PLUGIN_VERSION "-" MYSQL_AUDIT_PLUGIN_REVISION,
@@ -2266,32 +2368,32 @@ static struct st_mysql_show_var audit_status[] =
static void json_log_file_enable(THD *thd, struct st_mysql_sys_var *var,
static void json_log_file_enable(THD *thd, SYS_VAR *var,
void *tgt, const void *save)
{
json_file_handler_enable = *(my_bool *) save ? TRUE : FALSE;
json_file_handler_enable = *(my_bool *) save ? true : false;
if (json_file_handler.is_init())
{
json_file_handler.set_enable(json_file_handler_enable);
}
}
static void json_log_file_flush(THD *thd, struct st_mysql_sys_var *var,
static void json_log_file_flush(THD *thd, SYS_VAR *var,
void *tgt, const void *save)
{
// always set to false. as we just flush if set to true and leave at 0
json_file_handler_flush = FALSE;
my_bool val = *(my_bool *) save ? TRUE : FALSE;
json_file_handler_flush = false;
my_bool val = *(my_bool *) save ? true : false;
if (val && json_file_handler.is_init())
{
json_file_handler.flush();
}
}
static void json_log_socket_enable(THD *thd, struct st_mysql_sys_var *var,
static void json_log_socket_enable(THD *thd, SYS_VAR *var,
void *tgt, const void *save)
{
json_socket_handler_enable = *(my_bool *) save ? TRUE : FALSE;
json_socket_handler_enable = *(my_bool *) save ? true : false;
if (json_socket_handler.is_init())
{
json_socket_handler.set_enable(json_socket_handler_enable);
@@ -2462,7 +2564,7 @@ static MYSQL_SYSVAR_ENUM(before_after, before_after_mode,
/*
* Plugin system vars
*/
static struct st_mysql_sys_var* audit_system_variables[] =
static SYS_VAR* audit_system_variables[] =
{
#ifdef HAVE_SESS_CONNECT_ATTRS
MYSQL_SYSVAR(sess_connect_attrs),
@@ -2511,18 +2613,44 @@ mysql_declare_plugin(audit_plugin)
plugin_type,
&audit_plugin,
PLUGIN_NAME,
"McAfee Inc",
"Musarubra US LLC",
"AUDIT plugin, creates a file mysql-audit.log to log activity",
PLUGIN_LICENSE_GPL,
audit_plugin_init, /* Plugin Init */
audit_plugin_deinit, /* Plugin Deinit */
0x0100 /* 1.0 */,
audit_status, /* status variables */
audit_plugin_init, /* Plugin Init */
#if !defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 80000
nullptr, /* check uninstall function */
#endif
audit_plugin_deinit, /* Plugin Deinit */
0x0100 /* 1.0 */,
audit_status, /* status variables */
audit_system_variables, /* system variables */
NULL /* config options */
NULL, /* config options */
#if MYSQL_VERSION_ID >= 50516
0 /* flags for plugin */
#endif
}
mysql_declare_plugin_end;
#if defined(MARIADB_BASE_VERSION) && MYSQL_VERSION_ID >= 100307
maria_declare_plugin(audit_plugin)
{
plugin_type, /* the plugin type (see include/mysql/plugin.h) */
&audit_plugin, /* pointer to type-specific plugin descriptor */
PLUGIN_NAME, /* plugin name */
"Musarubra US LLC", /* plugin author */
"AUDIT plugin, creates a file mysql-audit.log to log activity", /* the plugin description */
PLUGIN_LICENSE_GPL, /* the plugin license (see include/mysql/plugin.h) */
audit_plugin_init, /* Pointer to plugin initialization function */
audit_plugin_deinit, /* Pointer to plugin deinitialization function */
0x0100, /* Numeric version 0xAABB means AA.BB version */
audit_status, /* Status variables */
audit_system_variables, /* System variables */
"1.0", /* String version representation */
MariaDB_PLUGIN_MATURITY_STABLE /* Maturity (see include/mysql/plugin.h)*/
}
maria_declare_plugin_end;
#endif
static inline void init_peer_info()
{
memset(peer_info_init_value, '0', sizeof(peer_info_init_value)-1);
@@ -2542,32 +2670,7 @@ static inline void set_plugin_name_from_env()
}
}
#if MYSQL_VERSION_ID < 50505
/**
* DLL constructor method.
* We set here the audit plugin version to the same as the first built in plugin.
* This is so we can have a single lib for all versions (needed in 5.1)
*/
extern "C" void __attribute__ ((constructor)) audit_plugin_so_init(void)
{
if (mysqld_builtins && mysqld_builtins[0])
{
audit_plugin.interface_version = *(int *) mysqld_builtins[0]->info;
sql_print_information("%s Set interface version to: %d (%d)",
log_prefix, audit_plugin.interface_version,
audit_plugin.interface_version >> 8);
}
else
{
sql_print_error(
"%s mysqld_builtins are null. Plugin will not load unless the mysql version is: %d. \n",
log_prefix, audit_plugin.interface_version >> 8);
}
init_peer_info();
set_plugin_name_from_env();
}
#elif MYSQL_VERSION_ID < 50600
#if MYSQL_VERSION_ID < 50600
extern struct st_mysql_plugin *mysql_mandatory_plugins[];
extern "C" void __attribute__ ((constructor)) audit_plugin_so_init(void)
{

View File

@@ -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;
}

View File

@@ -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