Search code examples
mysqlpluginssegmentation-faultmysql-plugins

How do I step through a broken MySQL plugin?


I am trying to create a working proof-of-concept for a MySQL authorization plugin. I created and compiled my code, deployed to /usr/lib/mysql/plugin, and installed it with the following statement:

INSTALL PLUGIN auth_token SONAME 'auth_token.so'

I then attempted to create a user:

CREATE USER 'plugin_user'@'%' IDENTIFIED WITH auth_token BY RANDOM PASSWORD

Every time I run this, I get the response: Error Code: 2013. Lost connection to MySQL server during query. I looked at the syslog and I can see that my plugin is causing the server to crash:

Apr 10 19:11:32 sandbox systemd[1]: Started MySQL Community Server.
Apr 10 19:12:17 sandbox mysqld[10169]: 2024-04-10T19:12:17Z UTC - mysqld got signal 11 ;
Apr 10 19:12:17 sandbox mysqld[10169]: Most likely, you have hit a bug, but this error can also be caused by malfunctioning hardware.
Apr 10 19:12:17 sandbox mysqld[10169]: BuildID[sha1]=2acbd229b2cf8b640b93084ba33099e6af38fd44
Apr 10 19:12:17 sandbox mysqld[10169]: Thread pointer: 0x7fd0a2e422b0
Apr 10 19:12:17 sandbox mysqld[10169]: Attempting backtrace. You can use the following information to find out
Apr 10 19:12:17 sandbox mysqld[10169]: where mysqld died. If you see no messages after this, something went
Apr 10 19:12:17 sandbox mysqld[10169]: terribly wrong...
Apr 10 19:12:17 sandbox mysqld[10169]: stack_bottom = 7fd08830dc40 thread_stack 0x100000
Apr 10 19:12:17 sandbox mysqld[10169]: /usr/sbin/mysqld(my_print_stacktrace(unsigned char const*, unsigned long)+0x41) [0x563146bdeb31]
Apr 10 19:12:17 sandbox mysqld[10169]: /usr/sbin/mysqld(print_fatal_signal(int)+0x3bc) [0x5631461ef82c]
Apr 10 19:12:17 sandbox mysqld[10169]: /usr/sbin/mysqld(handle_fatal_signal+0x95) [0x5631461ef8d5]
Apr 10 19:12:17 sandbox mysqld[10169]: /lib/x86_64-linux-gnu/libc.so.6(+0x42520) [0x7fd0b4ae4520]
Apr 10 19:12:17 sandbox mysqld[10169]: /usr/lib/mysql/plugin/auth_token.so(generate_auth_string_hash(char const*, unsigned long, char*, unsigned long*)+0x20) [0x7fd0a45c765e]
Apr 10 19:12:17 sandbox mysqld[10169]: /usr/sbin/mysqld(set_and_validate_user_attributes(THD*, LEX_USER*, acl_table::Pod_user_what_to_update&, bool, bool, Table_ref*, bool*, char const*, std::__cxx11::list<random_password_info, std::allocator<random_password_info> >&, I_multi_factor_auth**, bool)+0xd10) [0x563146290a20]
Apr 10 19:12:17 sandbox mysqld[10169]: /usr/sbin/mysqld(mysql_create_user(THD*, List<LEX_USER>&, bool, bool)+0xb8a) [0x563146295c1a]
Apr 10 19:12:17 sandbox mysqld[10169]: /usr/sbin/mysqld(mysql_execute_command(THD*, bool)+0x22ce) [0x5631460bc92e]
Apr 10 19:12:17 sandbox mysqld[10169]: /usr/sbin/mysqld(dispatch_sql_command(THD*, Parser_state*)+0x57c) [0x5631460be98c]
Apr 10 19:12:17 sandbox mysqld[10169]: /usr/sbin/mysqld(dispatch_command(THD*, COM_DATA const*, enum_server_command)+0x1a4f) [0x5631460c0b7f]
Apr 10 19:12:17 sandbox mysqld[10169]: /usr/sbin/mysqld(do_command(THD*)+0x24d) [0x5631460c16dd]
Apr 10 19:12:17 sandbox mysqld[10169]: /usr/sbin/mysqld(+0xc019f0) [0x5631461f09f0]
Apr 10 19:12:17 sandbox mysqld[10169]: /usr/sbin/mysqld(+0x19afaee) [0x563146f9eaee]
Apr 10 19:12:17 sandbox mysqld[10169]: /lib/x86_64-linux-gnu/libc.so.6(+0x94ac3) [0x7fd0b4b36ac3]
Apr 10 19:12:17 sandbox kernel: [ 4456.951774] audit: type=1400 audit(1712776337.978:37): apparmor="DENIED" operation="open" profile="/usr/sbin/mysqld" name="/proc/10169/task/10217/mem" pid=10169 comm="connection" requested_mask="r" denied_mask="r" fsuid=114 ouid=114
Apr 10 19:12:17 sandbox mysqld[10169]: /lib/x86_64-linux-gnu/libc.so.6(+0x126850) [0x7fd0b4bc8850]
Apr 10 19:12:17 sandbox mysqld[10169]: Trying to get some variables.
Apr 10 19:12:17 sandbox mysqld[10169]: Some pointers may be invalid and cause the dump to abort.
Apr 10 19:12:17 sandbox mysqld[10169]: Query (7fd0a33148c0): is an invalid pointer
Apr 10 19:12:17 sandbox mysqld[10169]: Connection ID (thread ID): 9
Apr 10 19:12:17 sandbox mysqld[10169]: Status: NOT_KILLED
Apr 10 19:12:17 sandbox mysqld[10169]: The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains
Apr 10 19:12:17 sandbox mysqld[10169]: information that should help you find out what is causing the crash.
Apr 10 19:12:18 sandbox systemd[1]: mysql.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
Apr 10 19:12:18 sandbox systemd[1]: mysql.service: Failed with result 'exit-code'.
Apr 10 19:12:18 sandbox systemd[1]: mysql.service: Consumed 1.070s CPU time.
Apr 10 19:12:18 sandbox systemd[1]: mysql.service: Scheduled restart job, restart counter is at 1.
Apr 10 19:12:18 sandbox systemd[1]: Stopped MySQL Community Server.

The backtrace provided by MySQL is helpful insofar as identifying the broken function is concerned, but I do not know why the function is breaking. Also, if I run UNINSTALL PLUGIN auth_token then I get a segmentation fault and no backtrace whatsoever.

Is there a way I can step through my code with a debugger?


Solution

  • Attach gdb to the mysqld process and set a breakpoint at your function generate_auth_string_hash. Then single step through your program. Use p to print information like variable values.