Skip to content

Commit 4430ecf

Browse files
committed
Bug#31468581 - INVALID PID IN UNIX SOCKET LOCK FILE
Description =========== X Plugin has its own "lock" file format, to be able to detect if it was reserved by classic protocol or x protocol. Both classic and X unix-socket handlers kills processes that wrote the "lockfile", thus the mechanism was introduced to minimize chance to kill "wrong" process. When user configured the classic protocol unix-socket file, to the same value as it was assigned to X unix-socket, then in that case he was forced to remove manually the X lock-file. Fix === The file format of X unix socket lock files was aligned to classic mainly to make easier fixing wrong configuration of `mysqld` when there is no direct access to the host. RB: 27395 Reviewed-by: Tomasz Stepniak <tomasz.s.stepniak@oracle.com>
1 parent 3f1f580 commit 4430ecf

File tree

4 files changed

+76
-29
lines changed

4 files changed

+76
-29
lines changed

mysql-test/suite/x/r/connection_unixsocket_invalid.result

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ Application terminated with expected error: No such file or directory, while con
2222
ok
2323
Application terminated with expected error: Not a directory, while connecting to SOCKET (code 2002)
2424
ok
25-
call mtr.add_suppression("Plugin mysqlx reported: .Setup of socket: '\(.+\)' failed, lock file wasn't allocated by X Plugin");
26-
call mtr.add_suppression("Plugin mysqlx reported: .* X Plugin won't be accessible through UNIX socket");
25+
call mtr.add_suppression("Plugin mysqlx reported: 'X Plugins UNIX socket must use different file than MySQL server. X Plugin won't be accessible through UNIX socket");
2726
# restart: --loose-mysqlx-socket= SOCKET
2827
# restart: --loose-mysqlx-socket= SOCKET
2928
RUN SELECT CONNECTION_TYPE from performance_schema.threads where processlist_command='Query';

mysql-test/suite/x/t/connection_unixsocket_invalid.test

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,7 @@ exec $MYSQLXTEST
6666

6767
# Use the same socket as mysqld uses
6868
# X Plugin should fail with allocation
69-
call mtr.add_suppression("Plugin mysqlx reported: .Setup of socket: '\(.+\)' failed, lock file wasn't allocated by X Plugin");
70-
call mtr.add_suppression("Plugin mysqlx reported: .* X Plugin won't be accessible through UNIX socket");
69+
call mtr.add_suppression("Plugin mysqlx reported: 'X Plugins UNIX socket must use different file than MySQL server. X Plugin won't be accessible through UNIX socket");
7170

7271
--replace_regex $UNIX_SOCKET_REGEX
7372
let $restart_parameters = restart: --loose-mysqlx-socket=$MASTER_MYSOCK;

plugin/x/src/io/xpl_listener_unix_socket.cc

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ class Unixsocket_creator {
178178
return false;
179179
#else
180180
char buffer[8];
181+
char *pid_begin = buffer;
181182
const char x_prefix = 'X';
182183
const pid_t cur_pid = m_system_interface->get_pid();
183184
const std::string lock_filename =
@@ -242,15 +243,12 @@ class Unixsocket_creator {
242243
}
243244
buffer[len] = '\0';
244245

245-
if (x_prefix != buffer[0]) {
246-
error_message = "lock file wasn't allocated by X Plugin ";
247-
error_message += lock_filename;
248-
249-
return false;
246+
if (x_prefix == pid_begin[0]) {
247+
++pid_begin;
250248
}
251249

252250
pid_t parent_pid = m_system_interface->get_ppid();
253-
pid_t read_pid = atoi(buffer + 1);
251+
pid_t read_pid = atoi(pid_begin);
254252

255253
if (read_pid <= 0) {
256254
error_message = "invalid PID in UNIX socket lock file ";
@@ -282,9 +280,7 @@ class Unixsocket_creator {
282280
}
283281
}
284282

285-
// The "X" should fail legacy UNIX socket lock-file allocation
286-
snprintf(buffer, sizeof(buffer), "%c%d\n", x_prefix,
287-
static_cast<int>(cur_pid));
283+
snprintf(buffer, sizeof(buffer), "%d\n", static_cast<int>(cur_pid));
288284
if (lockfile_fd->write(buffer, strlen(buffer)) !=
289285
static_cast<signed>(strlen(buffer))) {
290286
error_message = String_formatter()

unittest/gunit/xplugin/xpl/listener_unix_socket_t.cc

Lines changed: 69 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,17 @@ const int FSYNC_ERR = -1;
5757
const int FSYNC_OK = 0;
5858
const int CLOSE_ERR = -1;
5959
const int CLOSE_OK = 0;
60+
const int CURRENT_PPID = 2;
6061
const int CURRENT_PID = 6;
61-
const char *const UNIX_SOCKET_FILE_CONTENT = "X6\n"; // "X%d" % CURRENT_PID
62+
const char *const UNIX_SOCKET_FILE_CONTENT_OLD = "X6\n"; // "X%d" % CURRENT_PID
63+
const char *const UNIX_SOCKET_FILE_CONTENT = "6\n"; // "%d" % CURRENT_PID
6264
const char *const UNIX_SOCKET_FILE = "/tmp/xplugin_test.sock";
6365
const char *const UNIX_SOCKET_LOCK_FILE = "/tmp/xplugin_test.sock.lock";
6466

67+
ACTION_P(SetArg0ToPChar, value) { strcpy(static_cast<char *>(arg0), value); }
68+
ACTION_P(SetArg0ToChar, value) { *static_cast<char *>(arg0) = value; }
69+
ACTION_P(SetArg0ToChar2, value) { (static_cast<char *>(arg0)[1]) = value; }
70+
6571
MATCHER(EqInvalidSocket, "") {
6672
return INVALID_SOCKET == mysql_socket_getfd(arg);
6773
}
@@ -97,6 +103,29 @@ class Listener_unix_socket_testsuite : public Test {
97103
BACKLOG);
98104
}
99105

106+
void assert_valid_lock_file_but_kills_old() {
107+
EXPECT_CALL(*m_mock_system, get_pid()).WillOnce(Return(CURRENT_PID));
108+
EXPECT_CALL(*m_mock_factory, open_file(StrEq(UNIX_SOCKET_LOCK_FILE), _, _))
109+
.WillOnce(Return(m_mock_file_invalid))
110+
.WillOnce(Return(m_mock_file))
111+
.WillOnce(Return(m_mock_file));
112+
EXPECT_CALL(*m_mock_system, get_errno()).WillOnce(Return(EEXIST));
113+
EXPECT_CALL(*m_mock_file, read(_, _))
114+
.WillOnce(DoAll(SetArg0ToPChar("X101"), Return(4)))
115+
.WillOnce(Return(0));
116+
EXPECT_CALL(*m_mock_system, get_ppid()).WillOnce(Return(CURRENT_PPID));
117+
118+
EXPECT_CALL(*m_mock_system, kill(101, _)).WillOnce(Return(1));
119+
EXPECT_CALL(*m_mock_file, write(EqCastToCStr(UNIX_SOCKET_FILE_CONTENT),
120+
strlen(UNIX_SOCKET_FILE_CONTENT)))
121+
.WillOnce(Return(strlen(UNIX_SOCKET_FILE_CONTENT)));
122+
EXPECT_CALL(*m_mock_system, unlink(StrEq(UNIX_SOCKET_LOCK_FILE)));
123+
EXPECT_CALL(*m_mock_file, fsync()).WillOnce(Return(FSYNC_OK));
124+
EXPECT_CALL(*m_mock_file, close())
125+
.WillOnce(Return(CLOSE_OK))
126+
.WillOnce(Return(CLOSE_OK));
127+
}
128+
100129
void assert_valid_lock_file() {
101130
EXPECT_CALL(*m_mock_system, get_pid()).WillOnce(Return(CURRENT_PID));
102131
EXPECT_CALL(*m_mock_factory, open_file(StrEq(UNIX_SOCKET_LOCK_FILE), _, _))
@@ -108,9 +137,7 @@ class Listener_unix_socket_testsuite : public Test {
108137
EXPECT_CALL(*m_mock_file, close()).WillOnce(Return(CLOSE_OK));
109138
}
110139

111-
void assert_setup_listener_successful() {
112-
ASSERT_NO_FATAL_FAILURE(assert_valid_lock_file());
113-
140+
void assert_unix_socket_listen() {
114141
EXPECT_CALL(*m_mock_factory, create_socket(_, AF_UNIX, SOCK_STREAM, 0))
115142
.WillOnce(Return(m_mock_socket));
116143
EXPECT_CALL(*m_mock_system, unlink(StrEq(UNIX_SOCKET_FILE)));
@@ -123,6 +150,11 @@ class Listener_unix_socket_testsuite : public Test {
123150

124151
std::shared_ptr<iface::Socket> socket = m_mock_socket;
125152
EXPECT_CALL(m_mock_socket_events, listen(socket, _)).WillOnce(Return(true));
153+
}
154+
155+
void assert_setup_listener_successful() {
156+
ASSERT_NO_FATAL_FAILURE(assert_valid_lock_file());
157+
ASSERT_NO_FATAL_FAILURE(assert_unix_socket_listen());
126158

127159
ASSERT_TRUE(sut->setup_listener(nullptr));
128160
ASSERT_TRUE(sut->get_state().is(iface::Listener::State::k_prepared));
@@ -138,6 +170,21 @@ class Listener_unix_socket_testsuite : public Test {
138170
ASSERT_TRUE(Mock::VerifyAndClearExpectations(m_mock_factory.get()));
139171
}
140172

173+
void assert_close_listener() {
174+
EXPECT_CALL(*m_mock_factory, create_system_interface())
175+
.WillRepeatedly(Return(m_mock_system));
176+
EXPECT_CALL(*m_mock_socket, get_socket_fd()).WillOnce(Return(SOCKET_OK));
177+
EXPECT_CALL(*m_mock_socket, close());
178+
EXPECT_CALL(*m_mock_system, unlink(StrEq(UNIX_SOCKET_LOCK_FILE)))
179+
.WillOnce(Return(UNLINK_OK));
180+
EXPECT_CALL(*m_mock_system, unlink(StrEq(UNIX_SOCKET_FILE)))
181+
.WillOnce(Return(UNLINK_OK));
182+
183+
sut->close_listener();
184+
185+
ASSERT_NO_FATAL_FAILURE(assert_and_clear_mocks());
186+
}
187+
141188
std::shared_ptr<mock::Socket> m_mock_socket;
142189
std::shared_ptr<mock::Socket> m_mock_socket_invalid;
143190
std::shared_ptr<mock::System> m_mock_system;
@@ -149,9 +196,6 @@ class Listener_unix_socket_testsuite : public Test {
149196
std::shared_ptr<Listener_unix_socket> sut;
150197
};
151198

152-
ACTION_P(SetArg0ToChar, value) { *static_cast<char *>(arg0) = value; }
153-
ACTION_P(SetArg0ToChar2, value) { (static_cast<char *>(arg0)[1]) = value; }
154-
155199
TEST_F(Listener_unix_socket_testsuite,
156200
unixsocket_try_to_create_empty_unixsocket_filename) {
157201
#if defined(HAVE_SYS_UN_H)
@@ -259,6 +303,7 @@ TEST_F(Listener_unix_socket_testsuite, unixsocket_read_not_x_plugin_lockfile) {
259303
std::ref(m_mock_socket_events),
260304
BACKLOG);
261305

306+
EXPECT_CALL(*m_mock_system, get_ppid()).WillOnce(Return(CURRENT_PPID));
262307
EXPECT_CALL(*m_mock_system, get_pid()).WillOnce(Return(CURRENT_PID));
263308
EXPECT_CALL(*m_mock_factory, open_file(StrEq(UNIX_SOCKET_LOCK_FILE), _, _))
264309
.WillOnce(Return(m_mock_file_invalid))
@@ -502,17 +547,25 @@ TEST_F(Listener_unix_socket_testsuite, close_listener_closes_valid_socket) {
502547
#if defined(HAVE_SYS_UN_H)
503548
ASSERT_NO_FATAL_FAILURE(assert_setup_listener_successful());
504549

505-
EXPECT_CALL(*m_mock_factory, create_system_interface())
506-
.WillRepeatedly(Return(m_mock_system));
507-
EXPECT_CALL(*m_mock_socket, get_socket_fd()).WillOnce(Return(SOCKET_OK));
508-
EXPECT_CALL(*m_mock_socket, close());
509-
EXPECT_CALL(*m_mock_system, unlink(StrEq(UNIX_SOCKET_LOCK_FILE)))
510-
.WillOnce(Return(UNLINK_OK));
511-
EXPECT_CALL(*m_mock_system, unlink(StrEq(UNIX_SOCKET_FILE)))
512-
.WillOnce(Return(UNLINK_OK));
513-
sut->close_listener();
550+
ASSERT_NO_FATAL_FAILURE(assert_close_listener());
551+
#endif
552+
}
553+
554+
TEST_F(Listener_unix_socket_testsuite, unixsocket_read_old_x_plugin_lockfile) {
555+
#if defined(HAVE_SYS_UN_H)
556+
sut = std::make_shared<Listener_unix_socket>(m_mock_factory, UNIX_SOCKET_FILE,
557+
std::ref(m_mock_socket_events),
558+
BACKLOG);
559+
560+
ASSERT_NO_FATAL_FAILURE(assert_valid_lock_file_but_kills_old());
561+
ASSERT_NO_FATAL_FAILURE(assert_unix_socket_listen());
562+
563+
ASSERT_TRUE(sut->setup_listener(nullptr));
564+
ASSERT_TRUE(sut->get_state().is(iface::Listener::State::k_prepared));
514565

515566
ASSERT_NO_FATAL_FAILURE(assert_and_clear_mocks());
567+
568+
ASSERT_NO_FATAL_FAILURE(assert_close_listener());
516569
#endif
517570
}
518571

0 commit comments

Comments
 (0)