php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #72919 Problem when writing php extension which provides a mysql auth mehtod
Submitted: 2016-08-22 09:47 UTC Modified: 2021-07-29 11:40 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: tobias dot mueller at hostpoint dot ch Assigned: cmb (profile)
Status: Closed Package: MySQL related
PHP Version: 5.6.25 OS: ALL
Private report: No CVE-ID: None
 [2016-08-22 09:47 UTC] tobias dot mueller at hostpoint dot ch
Description:
------------
MySQL provides the concept of proxy authentication which allows it to write a server side plugin to do specific authentication of a proxy user.

To make this work a client plugin is required. PHP comes with builtin authentication plugins for native auth, pam auth and sha256 auth.

I tried to write a new mysqlnd auth plugin for our custom mysql authentication. The code looks something like in test-script below.

The functionality works so far. The extension can be loaded, it handles the specific authentication well, but there is a segfault when php shuts down.

When I run the test script in gdb, the segfault happens in this code:

mysqlnd_plugin_end_apply_func (pDest=<optimized out>)
    at /home/tmueller/dev/php-5.6.24/ext/mysqlnd/mysqlnd_plugin.c:112
112		if (plugin_header->m.plugin_shutdown) {
(gdb) bt
#0  mysqlnd_plugin_end_apply_func (pDest=<optimized out>)
    at /home/tmueller/dev/php-5.6.24/ext/mysqlnd/mysqlnd_plugin.c:112

When I set a breakpoint on that location, there is a segfault when accessing member "m" of "plugin_header" struct. This happens because php unloads my extension before unloading the mysqlnd extension and so mysqlnd accesses a pointer which points to something that is not there anymore.

When I set a breakpoint, the situation is like that:

Breakpoint 1, mysqlnd_plugin_end_apply_func (pDest=<optimized out>)
    at /home/tmueller/dev/php-5.6.24/ext/mysqlnd/mysqlnd_plugin.c:112
112		if (plugin_header->m.plugin_shutdown) {
(gdb) p plugin_header
$9 = (struct st_mysqlnd_plugin_header *) 0x7ffff642b080
(gdb) p plugin_header->m
Cannot access memory at address 0x7ffff642b0c0

When I call "info sharedlibrary" in gdb in PHP_MINIT_FUNCTION of my extension, the shared object is loaded:

Breakpoint 1, zm_activate_wtauth (type=1, module_number=29) at /home/tmueller/dev/php-ext-wtauth/wtauth.c:111
warning: Source file is more recent than executable.

111	    return SUCCESS;
(gdb) info sharedlibrary
From                To                  Syms Read   Shared Object Library
0x00007ffff7ddaae0  0x00007ffff7df5490  Yes         /lib64/ld-linux-x86-64.so.2
0x00007ffff7bc2ad0  0x00007ffff7bd1eb9  Yes         /lib/x86_64-linux-gnu/libresolv.so.2
0x00007ffff78be610  0x00007ffff792d056  Yes         /lib/x86_64-linux-gnu/libm.so.6
0x00007ffff76b5ed0  0x00007ffff76b69ce  Yes         /lib/x86_64-linux-gnu/libdl.so.2
0x00007ffff737b9d0  0x00007ffff746249e  Yes (*)     /usr/lib/x86_64-linux-gnu/libxml2.so.2
0x00007ffff6fa8520  0x00007ffff70ed183  Yes         /lib/x86_64-linux-gnu/libc.so.6
0x00007ffff6d71e00  0x00007ffff6d81bf8  Yes (*)     /lib/x86_64-linux-gnu/libz.so.1
0x00007ffff6b500d0  0x00007ffff6b6424d  Yes (*)     /lib/x86_64-linux-gnu/liblzma.so.5
0x00007ffff622a900  0x00007ffff622aa70  Yes         /home/tmueller/test-root/lib/php/extensions/no-debug-non-zts-20131226/wtauth.so

On line 112 of mysqlnd_plugin.c in mysqlnd_plugin_end_apply_func it is not loaded anymore  

warning: Temporarily disabling breakpoints for unloaded shared library "/home/tmueller/test-root/lib/php/extensions/no-debug-non-zts-20131226/wtauth.so"

Breakpoint 2, mysqlnd_plugin_end_apply_func (pDest=<optimized out>)
    at /home/tmueller/dev/php-5.6.24/ext/mysqlnd/mysqlnd_plugin.c:112
112		if (plugin_header->m.plugin_shutdown) {
(gdb) info sharedlibrary
From                To                  Syms Read   Shared Object Library
0x00007ffff7ddaae0  0x00007ffff7df5490  Yes         /lib64/ld-linux-x86-64.so.2
0x00007ffff7bc2ad0  0x00007ffff7bd1eb9  Yes         /lib/x86_64-linux-gnu/libresolv.so.2
0x00007ffff78be610  0x00007ffff792d056  Yes         /lib/x86_64-linux-gnu/libm.so.6
0x00007ffff76b5ed0  0x00007ffff76b69ce  Yes         /lib/x86_64-linux-gnu/libdl.so.2
0x00007ffff737b9d0  0x00007ffff746249e  Yes (*)     /usr/lib/x86_64-linux-gnu/libxml2.so.2
0x00007ffff6fa8520  0x00007ffff70ed183  Yes         /lib/x86_64-linux-gnu/libc.so.6
0x00007ffff6d71e00  0x00007ffff6d81bf8  Yes (*)     /lib/x86_64-linux-gnu/libz.so.1
0x00007ffff6b500d0  0x00007ffff6b6424d  Yes (*)     /lib/x86_64-linux-gnu/liblzma.so.5

In our opinion there are two ways to solve the problem:

 1) Unregister the plugin in PHP_MSHUTDOWN_FUNCTION method of the extension

This solution currently is not possible because the mysqlnd_plugin_end_apply_func function does not appear in a header file and can not be used by our extension.

 2) Load mysqlnd code before our extension but unload our extension after unloading mysqlnd

This is to my knowledge not possible because php always unloads the extensions in reverse order as they were loaded.



Test script:
---------------
static zend_uchar *
mysqlnd_test_authorization_get_auth_data(struct st_mysqlnd_authentication_plugin * self,
								  size_t * auth_data_len,
								  MYSQLND_CONN_DATA * conn, const char * const user, const char * const passwd,
								  const size_t passwd_len, zend_uchar * auth_plugin_data, size_t auth_plugin_data_len,
								  const MYSQLND_OPTIONS * const options,
								  const MYSQLND_NET_OPTIONS * const net_options,
								  unsigned long mysql_flags
								  TSRMLS_DC)
{
	 // stuff her
}


static struct st_mysqlnd_authentication_plugin mysqlnd_test_authorization_plugin =
{
	{
		MYSQLND_PLUGIN_API_VERSION,
		"auth_plugin_test_authorization",
		MYSQLND_VERSION_ID,
		MYSQLND_VERSION,
		"PHP License 3.01",
		"Author",
		{
			NULL, /* no statistics , will be filled later if there are some */
			NULL, /* no statistics */
		},
		{
			NULL
		}
	},
	{/* methods */
		mysqlnd_test_authorization_get_auth_data
	}
};


void
test_auth_register_authentication_plugins(TSRMLS_D)
{
	TSRMLS_FETCH();
	mysqlnd_plugin_register_ex((struct st_mysqlnd_plugin_header *) &mysqlnd_test_authorization_plugin.plugin_header TSRMLS_CC);
}

PHP_MINIT_FUNCTION(testauth)
{	
    test_auth_register_authentication_plugins(TSRMLS_C);
    return SUCCESS;
}

PHP_MSHUTDOWN_FUNCTION(testauth)
{
    // What to do here
    return SUCCESS;
}

PHP_RINIT_FUNCTION(testauth)
{
    return SUCCESS;
}



Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-02-23 12:19 UTC] isundill at gmail dot com
Hello,

I had the same issue, and I solved the issue allocating the struct with malloc and freeing it in PHP_MSHUTDOWN_FUNCTION the second time the shutdown is called (it will be called the second time by the mysqlnd_plugin_end_apply_func function).

It's really not beautiful, but at least it doesn't leak nor cause segmentation fault.

isundil
 [2021-07-29 11:40 UTC] cmb@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: cmb
 [2021-07-29 11:40 UTC] cmb@php.net
This bug tracker is not a support forum.  If this is still an
issue for, please write to the internals mailing list[1].

[1] <https://www.php.net/mailing-lists.php#internals>
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Mar 19 10:01:30 2024 UTC