Skip to content

Commit fc30a7c

Browse files
committed
Use /dev/null in invalidate_fd to avoid infinite loop in OpenSSL
Thanks to Andy Bakun / @thwarted for identifying the issue and suggesting the /dev/null workaround.
1 parent 4827da7 commit fc30a7c

File tree

1 file changed

+12
-8
lines changed

1 file changed

+12
-8
lines changed

ext/mysql2/client.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -169,26 +169,30 @@ static void *nogvl_connect(void *ptr) {
169169

170170
#ifndef _WIN32
171171
/*
172-
* Redirect clientfd to a dummy socket for mysql_close to
173-
* write, shutdown, and close on as a no-op.
174-
* We do this hack because we want to call mysql_close to release
175-
* memory, but do not want mysql_close to drop connections in the
176-
* parent if the socket got shared in fork.
172+
* Redirect clientfd to /dev/null for mysql_close and SSL_close to write,
173+
* shutdown, and close. The hack is needed to prevent shutdown() from breaking
174+
* a socket that may be in use by the parent or other processes after fork.
175+
*
176+
* /dev/null is used to absorb writes; previously a dummy socket was used, but
177+
* it could not abosrb writes and caused openssl to go into an infinite loop.
178+
*
177179
* Returns Qtrue or Qfalse (success or failure)
180+
*
181+
* Note: if this function is needed on Windows, use "nul" instead of "/dev/null"
178182
*/
179183
static VALUE invalidate_fd(int clientfd)
180184
{
181185
#ifdef SOCK_CLOEXEC
182186
/* Atomically set CLOEXEC on the new FD in case another thread forks */
183-
int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
187+
int sockfd = open("/dev/null", O_RDWR | O_CLOEXEC);
184188
if (sockfd < 0) {
185189
/* Maybe SOCK_CLOEXEC is defined but not available on this kernel */
186-
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
190+
int sockfd = open("/dev/null", O_RDWR);
187191
fcntl(sockfd, F_SETFD, FD_CLOEXEC);
188192
}
189193
#else
190194
/* Well we don't have SOCK_CLOEXEC, so just set FD_CLOEXEC quickly */
191-
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
195+
int sockfd = open("/dev/null", O_RDWR);
192196
fcntl(sockfd, F_SETFD, FD_CLOEXEC);
193197
#endif
194198

0 commit comments

Comments
 (0)