Project

General

Profile

Bug #11301 » 0002-WT-11302-avoid-use-after-free-with-closed-listeners.patch

Roel Standaert, 03/09/2023 05:21 PM

View differences:

src/http/Server.C
const std::string &address,
Wt::AsioWrapper::error_code &errc)
{
tcp_listeners_.push_back(TcpListener(asio::ip::tcp::acceptor(wt_.ioService()), TcpConnectionPtr()));
asio::ip::tcp::acceptor &tcp_acceptor = tcp_listeners_.back().acceptor;
tcp_listeners_.push_back(std::make_shared<TcpListener>(asio::ip::tcp::acceptor(wt_.ioService()), TcpConnectionPtr()));
asio::ip::tcp::acceptor &tcp_acceptor = tcp_listeners_.back()->acceptor;
tcp_acceptor.open(endpoint.protocol());
tcp_acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true));
#ifndef WT_WIN32
......
LOG_INFO_S(&wt_, "started server: " << addressString("http", endpoint, address));
tcp_listeners_.back().new_connection.reset
tcp_listeners_.back()->new_connection.reset
(new TcpConnection(wt_.ioService(), this, connection_manager_,
request_handler_));
} else {
......
const std::string &address,
Wt::AsioWrapper::error_code &errc)
{
ssl_listeners_.push_back(SslListener(asio::ip::tcp::acceptor(wt_.ioService()), SslConnectionPtr()));
asio::ip::tcp::acceptor &ssl_acceptor = ssl_listeners_.back().acceptor;
ssl_listeners_.push_back(std::make_shared<SslListener>(asio::ip::tcp::acceptor(wt_.ioService()), SslConnectionPtr()));
asio::ip::tcp::acceptor &ssl_acceptor = ssl_listeners_.back()->acceptor;
ssl_acceptor.open(endpoint.protocol());
ssl_acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true));
#ifndef WT_WIN32
......
LOG_INFO_S(&wt_, "started server: " << addressString("https", endpoint, address));
ssl_listeners_.back().new_connection.reset
ssl_listeners_.back()->new_connection.reset
(new SslConnection(wt_.ioService(), this, ssl_context_, connection_manager_,
request_handler_));
} else {
......
if (ssl_listeners_.empty())
return -1;
else
return ssl_listeners_.front().acceptor.local_endpoint().port();
return ssl_listeners_.front()->acceptor.local_endpoint().port();
#else // HTTP_WITH_SSL
return -1;
#endif // HTTP_WITH_SSL
}
return tcp_listeners_.front().acceptor.local_endpoint().port();
return tcp_listeners_.front()->acceptor.local_endpoint().port();
}
void Server::startAccept()
......
* need to access the ConnectionManager mutex in any case).
*/
for (std::size_t i = 0; i < tcp_listeners_.size(); ++i) {
asio::ip::tcp::acceptor &acceptor = tcp_listeners_[i].acceptor;
TcpConnectionPtr &new_connection = tcp_listeners_[i].new_connection;
asio::ip::tcp::acceptor &acceptor = tcp_listeners_[i]->acceptor;
TcpConnectionPtr &new_connection = tcp_listeners_[i]->new_connection;
acceptor.async_accept(new_connection->socket(),
accept_strand_.wrap(
std::bind(&Server::handleTcpAccept, this,
&tcp_listeners_[i],
tcp_listeners_[i],
std::placeholders::_1)));
}
#ifdef HTTP_WITH_SSL
for (std::size_t i = 0; i < ssl_listeners_.size(); ++i) {
asio::ip::tcp::acceptor &acceptor = ssl_listeners_[i].acceptor;
SslConnectionPtr &new_connection = ssl_listeners_[i].new_connection;
asio::ip::tcp::acceptor &acceptor = ssl_listeners_[i]->acceptor;
SslConnectionPtr &new_connection = ssl_listeners_[i]->new_connection;
acceptor.async_accept(new_connection->socket(),
accept_strand_.wrap(
std::bind(&Server::handleSslAccept, this,
&ssl_listeners_[i],
ssl_listeners_[i],
std::placeholders::_1)));
}
#endif // HTTP_WITH_SSL
......
if (!err) {
// tcp_listeners_.front() should be fine here:
// it should be the only acceptor when this is a session process
auto port = tcp_listeners_.front().acceptor.local_endpoint().port();
auto port = tcp_listeners_.front()->acceptor.local_endpoint().port();
Wt::WStringStream ss;
ss << "port:" << port << "\n";
auto buf = std::make_shared<std::string>(ss.str());
......
void Server::handleResume()
{
for (std::size_t i = 0; i < tcp_listeners_.size(); ++i)
tcp_listeners_[i].acceptor.close();
tcp_listeners_[i]->acceptor.close();
tcp_listeners_.clear();
#ifdef HTTP_WITH_SSL
for (std::size_t i = 0; i < ssl_listeners_.size(); ++i)
ssl_listeners_[i].acceptor.close();
ssl_listeners_[i]->acceptor.close();
ssl_listeners_.clear();
#endif // HTTP_WITH_SSL
start();
}
void Server::handleTcpAccept(TcpListener *listener, const Wt::AsioWrapper::error_code& e)
void Server::handleTcpAccept(const std::weak_ptr<TcpListener>& listener,
const Wt::AsioWrapper::error_code& e)
{
if (!e) {
connection_manager_.start(listener->new_connection);
listener->new_connection.reset(new TcpConnection(wt_.ioService(), this,
connection_manager_, request_handler_));
} else if (!listener->acceptor.is_open()) {
auto l = listener.lock();
if (!l || (e && !l->acceptor.is_open())) {
// server shutdown
LOG_DEBUG("handleTcpAccept: async_accept error (acceptor closed, probably server shutdown): " << e.message());
LOG_DEBUG("handleTcpAccept: async_accept error (no listener, probably server shutdown): " << e.message());
return;
}
if (!e) {
connection_manager_.start(l->new_connection);
l->new_connection.reset(new TcpConnection(wt_.ioService(), this,
connection_manager_, request_handler_));
} else {
LOG_ERROR("handleTcpAccept: async_accept error: " << e.message());
}
listener->acceptor.async_accept(listener->new_connection->socket(),
accept_strand_.wrap(
std::bind(&Server::handleTcpAccept, this,
listener, std::placeholders::_1)));
l->acceptor.async_accept(l->new_connection->socket(),
accept_strand_.wrap(
std::bind(&Server::handleTcpAccept, this,
listener, std::placeholders::_1)));
}
#ifdef HTTP_WITH_SSL
void Server::handleSslAccept(SslListener *listener, const Wt::AsioWrapper::error_code& e)
void Server::handleSslAccept(const std::weak_ptr<SslListener>& listener,
const Wt::AsioWrapper::error_code& e)
{
if (!e) {
connection_manager_.start(listener->new_connection);
listener->new_connection.reset(new SslConnection(wt_.ioService(), this,
ssl_context_, connection_manager_, request_handler_));
} else if (!listener->acceptor.is_open()) {
auto l = listener.lock();
if (!l || (e && !l->acceptor.is_open())) {
// server shutdown
LOG_DEBUG("handleSslAccept: async_accept error (acceptor closed, probably server shutdown): " << e.message());
LOG_DEBUG("handleSslAccept: async_accept error (no listener, probably server shutdown): " << e.message());
return;
}
if (!e) {
connection_manager_.start(l->new_connection);
l->new_connection.reset(new SslConnection(wt_.ioService(), this,
ssl_context_, connection_manager_, request_handler_));
} else {
LOG_ERROR("handleSslAccept: async_accept error: " << e.message());
}
listener->acceptor.async_accept(listener->new_connection->socket(),
accept_strand_.wrap(
std::bind(&Server::handleSslAccept, this,
listener, std::placeholders::_1)));
l->acceptor.async_accept(l->new_connection->socket(),
accept_strand_.wrap(
std::bind(&Server::handleSslAccept, this,
listener, std::placeholders::_1)));
}
#endif // HTTP_WITH_SSL
......
// operations. Once all operations have finished the io_service::run() call
// will exit.
for (std::size_t i = 0; i < tcp_listeners_.size(); ++i)
tcp_listeners_[i].acceptor.close();
tcp_listeners_[i]->acceptor.close();
tcp_listeners_.clear();
#ifdef HTTP_WITH_SSL
for (std::size_t i = 0; i < ssl_listeners_.size(); ++i)
ssl_listeners_[i].acceptor.close();
ssl_listeners_[i]->acceptor.close();
ssl_listeners_.clear();
#endif // HTTP_WITH_SSL
src/http/Server.h
#include "Wt/WLogger.h"
#include <memory>
namespace http {
namespace server {
......
void closeParentConnection();
/// Handle completion of an asynchronous accept operation.
void handleTcpAccept(TcpListener *listener, const Wt::AsioWrapper::error_code& e);
void handleTcpAccept(const std::weak_ptr<TcpListener>& listener,
const Wt::AsioWrapper::error_code& e);
/// Handle a request to stop the server.
void handleStop();
......
Wt::AsioWrapper::strand accept_strand_;
/// Acceptors used to listen for incoming http connections.
std::vector<TcpListener> tcp_listeners_;
std::vector<std::shared_ptr<TcpListener>> tcp_listeners_;
#ifdef HTTP_WITH_SSL
struct SslListener {
......
asio::ssl::context ssl_context_;
/// Acceptors used to listen for incoming https connections
std::vector<SslListener> ssl_listeners_;
std::vector<std::shared_ptr<SslListener>> ssl_listeners_;
/// Add new SSL listener, called from start()
void addSslListener(asio::ip::tcp::resolver &resolver,
......
Wt::AsioWrapper::error_code &errc);
/// Handle completion of an asynchronous SSL accept operation.
void handleSslAccept(SslListener *listener, const Wt::AsioWrapper::error_code& e);
void handleSslAccept(const std::weak_ptr<SslListener>& listener,
const Wt::AsioWrapper::error_code& e);
#endif // HTTP_WITH_SSL
void handleTimeout(asio::steady_timer *timer,
(4-4/4)