Skip to content

Fix GH-8979: Possible Memory Leak with SSL-enabled MySQL connections #10909

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

nielsdos
Copy link
Member

Fixes GH-8979

The stream context inside mysqlnd_vio::enable_ssl() is leaking. In particular: when php_stream_context_set() get called the refcount of context is increased by 1, which means that context will now have a refcount of 2. Later on we remove the context from the stream by calling php_stream_context_set(stream, NULL) but that leaves our context with a refcount of 1, and therefore it's never destroyed. In my test case this yielded a leak of 1456 bytes per connection (but could be more depending on your settings ofc).

Annoyingly, Valgrind doesn't find it because the context is still in the EG(regular_list) and will thus be destroyed at the end of the request. However, I still think this bug needs to be fixed because as the users in the issue report already mentioned: there can be long-running PHP scripts.

Fix it by decreasing the refcount to transfer the ownership.


We don't seem to have any SSL mysqlnd tests? I tested the bug using the reproduction instructions in the linked issue which uses an external server behind SSL.

The stream context inside `mysqlnd_vio::enable_ssl()` is leaking.
In particular: when `php_stream_context_set()` get called the refcount
of `context` is increased by 1, which means that `context` will now
have a refcount of 2. Later on we remove the context from the stream
by calling `php_stream_context_set(stream, NULL)` but that leaves our
`context` with a refcount of 1, and therefore it's never destroyed.
In my test case this yielded a leak of 1456 bytes per connection
(but could be more depending on your settings ofc).

Annoyingly, Valgrind doesn't find it because the context is still
in the `EG(regular_list)` and will thus be destroyed at the end of
the request. However, I still think this bug needs to be fixed because
as the users in the issue report already mentioned:
there can be long-running PHP scripts.

Fix it by decreasing the refcount to transfer the ownership.
@devnexen
Copy link
Member

We don't seem to have any SSL mysqlnd tests? I tested the bug using the reproduction instructions in the linked issue which uses an external server behind SSL.

Do you think it would be too complicated to add one ? real question, I have no idea honestly.

@Girgias Girgias requested a review from kamil-tekiela March 23, 2023 13:21
@Girgias
Copy link
Member

Girgias commented Mar 23, 2023

This looks sensible but I'd like for @kamil-tekiela to have a look as AFAIK he did some stuff on the MySQLnd driver recently

@kamil-tekiela
Copy link
Member

I don't really know how php_stream_context_set works but if you say this fixes the problem then that's fine with me. I tried to test it myself but I don't have the time to find SSL server I can test it against. Can you please test it with persistent connections? Just add "p:" to the host and check if the connection can be established, and re-established on consecutive runs.

I can't find any uses of this function with second argument NULL. Are we sure it should not be fixed within the function? Again, not really understanding how it works.

We don't have tests for SSL and I don't know how we could add one. We would need an SSL server but I don't know if we can do that in CI.

@nielsdos
Copy link
Member Author

I tried to test it myself but I don't have the time to find SSL server I can test it against.

I used the reporter's database service. I made an account & database on that. I can send you the DB credentials along with a .zip with the script & ini configuration file in private if you want to test it.

Can you please test it with persistent connections? Just add "p:" to the host and check if the connection can be established, and re-established on consecutive runs.

Works fine under ASAN.

I can't find any uses of this function with second argument NULL. Are we sure it should not be fixed within the function? Again, not really understanding how it works.

That call is fine. What is happening is that php_stream_context_set(stream, context) increases the reference count of context by 1, which is expected because we indeed have 2 references to context. Then the driver sets up the SSL stuff, and when it's done with that it uses php_stream_context_set(stream, NULL) to detach the context from the stream. The context will now again have a refcount of 1. There are no more users of context in the application, but the last reference isn't destroyed. Eventually the context is destroyed at the end of the request because it's in EG(regular_list), but for long-running PHP processes this is problematic. By manually decreasing the refcount by 1 again, we make sure that when the stream detaches the context, the context is destroyed and removed from EG(regular_list).

We don't have tests for SSL and I don't know how we could add one. We would need an SSL server but I don't know if we can do that in CI.

Yeah this sounds pretty hard tbh. I know you can run mysql in a mode that allows both SSL and non-SSL connections. But I don't know how this would work with certificates etc for CI.

@kamil-tekiela
Copy link
Member

I used the reporter's database service. I made an account & database on that. I can send you the DB credentials along with a .zip with the script & ini configuration file in private if you want to test it.

Yes, please. If you can send it to my email and I will review over the weekend.

@nielsdos
Copy link
Member Author

I used the reporter's database service. I made an account & database on that. I can send you the DB credentials along with a .zip with the script & ini configuration file in private if you want to test it.

Yes, please. If you can send it to my email and I will review over the weekend.

Great! Done that now, thanks :)

Copy link
Member

@kamil-tekiela kamil-tekiela left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I tested it myself and I can't find any problems.

@nielsdos nielsdos closed this in 8930bf8 Mar 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants