Bug #120489 MgmApiSession queries peer address from a moved-from NdbSocket
Description:
MgmApiSession::MgmApiSession() moves the accepted NdbSocket &&sock parameter into m_secure_socket, then later calls ndb_getpeername(sock.ndb_socket(), &addr) on the moved-from parameter.
NdbSocket move construction swaps the native socket handle into the destination and leaves the source object default-invalid. Therefore sock.ndb_socket() returns an invalid socket after the move. On POSIX this results in getpeername(-1, ...), which fails with EBADF.
As a result, the constructor does not resolve the peer address and m_name remains initialized as "unknown:0", making management API session logging/diagnostics misleading.
Relevant code path:
```cpp
MgmApiSession::MgmApiSession(class MgmtSrvr &mgm, NdbSocket &&sock,
Uint64 session_id)
: SocketServer::Session(m_secure_socket),
m_secure_socket(std::move(sock)),
...
m_name("unknown:0") {
...
ndb_sockaddr addr;
if (ndb_getpeername(sock.ndb_socket(), &addr) == 0) {
...
m_name.assfmt("%s", sockaddr_string);
}
}
```
How to repeat:
The following simplified program reproduces the ownership transfer issue using the same operation sequence as MgmApiSession: move an NdbSocket, then call ndb_getpeername() on the moved-from object versus the moved-to object.
```cpp
#include "util/NdbSocket.h"
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <iostream>
int main() {
int listener = ::socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_port = 0;
::bind(listener, reinterpret_cast<sockaddr *>(&addr), sizeof(addr));
::listen(listener, 1);
socklen_t addr_len = sizeof(addr);
::getsockname(listener, reinterpret_cast<sockaddr *>(&addr), &addr_len);
int client_fd = ::socket(AF_INET, SOCK_STREAM, 0);
::connect(client_fd, reinterpret_cast<sockaddr *>(&addr), addr_len);
int server_fd = ::accept(listener, nullptr, nullptr);
::close(listener);
NdbSocket sock(ndb_socket_create_from_native(server_fd));
NdbSocket m_secure_socket(std::move(sock));
ndb_sockaddr from_moved_param;
errno = 0;
int moved_result = ndb_getpeername(sock.ndb_socket(), &from_moved_param);
int moved_errno = errno;
ndb_sockaddr from_member;
errno = 0;
int member_result =
ndb_getpeername(m_secure_socket.ndb_socket(), &from_member);
int member_errno = errno;
std::cout << "moved-from sock valid: " << sock.is_valid() << "\n";
std::cout << "m_secure_socket valid: " << m_secure_socket.is_valid() << "\n";
std::cout << "ndb_getpeername(sock.ndb_socket()) result: "
<< moved_result << ", errno: " << moved_errno << "\n";
std::cout << "ndb_getpeername(m_secure_socket.ndb_socket()) result: "
<< member_result << ", errno: " << member_errno << "\n";
::close(client_fd);
::close(m_secure_socket.release_native_socket());
}
```
Observed output:
moved-from sock valid: 0
m_secure_socket valid: 1
ndb_getpeername(sock.ndb_socket()) result: 1, errno: 9
ndb_getpeername(m_secure_socket.ndb_socket()) result: 0, errno: 0
errno: 9 is EBADF, confirming that sock.ndb_socket() is invalid after std::move(sock), while m_secure_socket.ndb_socket() is valid.
Suggested fix:
Use the session-owned socket after the move:
```cpp
ndb_sockaddr addr;
if (ndb_getpeername(m_secure_socket.ndb_socket(), &addr) == 0) {
char addr_buf[NDB_ADDR_STRLEN];
char *addr_str = Ndb_inet_ntop(&addr, addr_buf, sizeof(addr_buf));
char buf[512];
char *sockaddr_string =
Ndb_combine_address_port(buf, sizeof(buf), addr_str, addr.get_port());
m_name.assfmt("%s", sockaddr_string);
}
```
Portions of this website are copyright © 2001, 2002 The PHP Group
Page generated in 0.038 sec. using MySQL 8.4.7-u6-cloud
Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the
respective copyright holders.
It is not reviewed in advance
by Oracle and does not necessarily represent the opinion of
Oracle or any other party.
Description: MgmApiSession::MgmApiSession() moves the accepted NdbSocket &&sock parameter into m_secure_socket, then later calls ndb_getpeername(sock.ndb_socket(), &addr) on the moved-from parameter. NdbSocket move construction swaps the native socket handle into the destination and leaves the source object default-invalid. Therefore sock.ndb_socket() returns an invalid socket after the move. On POSIX this results in getpeername(-1, ...), which fails with EBADF. As a result, the constructor does not resolve the peer address and m_name remains initialized as "unknown:0", making management API session logging/diagnostics misleading. Relevant code path: ```cpp MgmApiSession::MgmApiSession(class MgmtSrvr &mgm, NdbSocket &&sock, Uint64 session_id) : SocketServer::Session(m_secure_socket), m_secure_socket(std::move(sock)), ... m_name("unknown:0") { ... ndb_sockaddr addr; if (ndb_getpeername(sock.ndb_socket(), &addr) == 0) { ... m_name.assfmt("%s", sockaddr_string); } } ``` How to repeat: The following simplified program reproduces the ownership transfer issue using the same operation sequence as MgmApiSession: move an NdbSocket, then call ndb_getpeername() on the moved-from object versus the moved-to object. ```cpp #include "util/NdbSocket.h" #include <arpa/inet.h> #include <errno.h> #include <netinet/in.h> #include <sys/socket.h> #include <unistd.h> #include <iostream> int main() { int listener = ::socket(AF_INET, SOCK_STREAM, 0); sockaddr_in addr{}; addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); addr.sin_port = 0; ::bind(listener, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)); ::listen(listener, 1); socklen_t addr_len = sizeof(addr); ::getsockname(listener, reinterpret_cast<sockaddr *>(&addr), &addr_len); int client_fd = ::socket(AF_INET, SOCK_STREAM, 0); ::connect(client_fd, reinterpret_cast<sockaddr *>(&addr), addr_len); int server_fd = ::accept(listener, nullptr, nullptr); ::close(listener); NdbSocket sock(ndb_socket_create_from_native(server_fd)); NdbSocket m_secure_socket(std::move(sock)); ndb_sockaddr from_moved_param; errno = 0; int moved_result = ndb_getpeername(sock.ndb_socket(), &from_moved_param); int moved_errno = errno; ndb_sockaddr from_member; errno = 0; int member_result = ndb_getpeername(m_secure_socket.ndb_socket(), &from_member); int member_errno = errno; std::cout << "moved-from sock valid: " << sock.is_valid() << "\n"; std::cout << "m_secure_socket valid: " << m_secure_socket.is_valid() << "\n"; std::cout << "ndb_getpeername(sock.ndb_socket()) result: " << moved_result << ", errno: " << moved_errno << "\n"; std::cout << "ndb_getpeername(m_secure_socket.ndb_socket()) result: " << member_result << ", errno: " << member_errno << "\n"; ::close(client_fd); ::close(m_secure_socket.release_native_socket()); } ``` Observed output: moved-from sock valid: 0 m_secure_socket valid: 1 ndb_getpeername(sock.ndb_socket()) result: 1, errno: 9 ndb_getpeername(m_secure_socket.ndb_socket()) result: 0, errno: 0 errno: 9 is EBADF, confirming that sock.ndb_socket() is invalid after std::move(sock), while m_secure_socket.ndb_socket() is valid. Suggested fix: Use the session-owned socket after the move: ```cpp ndb_sockaddr addr; if (ndb_getpeername(m_secure_socket.ndb_socket(), &addr) == 0) { char addr_buf[NDB_ADDR_STRLEN]; char *addr_str = Ndb_inet_ntop(&addr, addr_buf, sizeof(addr_buf)); char buf[512]; char *sockaddr_string = Ndb_combine_address_port(buf, sizeof(buf), addr_str, addr.get_port()); m_name.assfmt("%s", sockaddr_string); } ```