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
393 393
                            const std::string &address,
394 394
                            Wt::AsioWrapper::error_code &errc)
395 395
{
396
  tcp_listeners_.push_back(TcpListener(asio::ip::tcp::acceptor(wt_.ioService()), TcpConnectionPtr()));
397
  asio::ip::tcp::acceptor &tcp_acceptor = tcp_listeners_.back().acceptor;
396
  tcp_listeners_.push_back(std::make_shared<TcpListener>(asio::ip::tcp::acceptor(wt_.ioService()), TcpConnectionPtr()));
397
  asio::ip::tcp::acceptor &tcp_acceptor = tcp_listeners_.back()->acceptor;
398 398
  tcp_acceptor.open(endpoint.protocol());
399 399
  tcp_acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true));
400 400
#ifndef WT_WIN32
......
406 406

  
407 407
    LOG_INFO_S(&wt_, "started server: " << addressString("http", endpoint, address));
408 408

  
409
    tcp_listeners_.back().new_connection.reset
409
    tcp_listeners_.back()->new_connection.reset
410 410
      (new TcpConnection(wt_.ioService(), this, connection_manager_,
411 411
                         request_handler_));
412 412
  } else {
......
450 450
                            const std::string &address,
451 451
                            Wt::AsioWrapper::error_code &errc)
452 452
{
453
  ssl_listeners_.push_back(SslListener(asio::ip::tcp::acceptor(wt_.ioService()), SslConnectionPtr()));
454
  asio::ip::tcp::acceptor &ssl_acceptor = ssl_listeners_.back().acceptor;
453
  ssl_listeners_.push_back(std::make_shared<SslListener>(asio::ip::tcp::acceptor(wt_.ioService()), SslConnectionPtr()));
454
  asio::ip::tcp::acceptor &ssl_acceptor = ssl_listeners_.back()->acceptor;
455 455
  ssl_acceptor.open(endpoint.protocol());
456 456
  ssl_acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true));
457 457
#ifndef WT_WIN32
......
463 463

  
464 464
    LOG_INFO_S(&wt_, "started server: " << addressString("https", endpoint, address));
465 465

  
466
    ssl_listeners_.back().new_connection.reset
466
    ssl_listeners_.back()->new_connection.reset
467 467
      (new SslConnection(wt_.ioService(), this, ssl_context_, connection_manager_,
468 468
                         request_handler_));
469 469
  } else {
......
481 481
    if (ssl_listeners_.empty())
482 482
      return -1;
483 483
    else
484
      return ssl_listeners_.front().acceptor.local_endpoint().port();
484
      return ssl_listeners_.front()->acceptor.local_endpoint().port();
485 485
#else // HTTP_WITH_SSL
486 486
    return -1;
487 487
#endif // HTTP_WITH_SSL
488 488
  }
489 489

  
490
  return tcp_listeners_.front().acceptor.local_endpoint().port();
490
  return tcp_listeners_.front()->acceptor.local_endpoint().port();
491 491
}
492 492

  
493 493
void Server::startAccept()
......
502 502
   * need to access the ConnectionManager mutex in any case).
503 503
   */
504 504
  for (std::size_t i = 0; i < tcp_listeners_.size(); ++i) {
505
    asio::ip::tcp::acceptor &acceptor = tcp_listeners_[i].acceptor;
506
    TcpConnectionPtr &new_connection = tcp_listeners_[i].new_connection;
505
    asio::ip::tcp::acceptor &acceptor = tcp_listeners_[i]->acceptor;
506
    TcpConnectionPtr &new_connection = tcp_listeners_[i]->new_connection;
507 507
    acceptor.async_accept(new_connection->socket(),
508 508
                          accept_strand_.wrap(
509 509
                            std::bind(&Server::handleTcpAccept, this,
510
                                        &tcp_listeners_[i],
510
                                        tcp_listeners_[i],
511 511
                                        std::placeholders::_1)));
512 512
  }
513 513

  
514 514
#ifdef HTTP_WITH_SSL
515 515
  for (std::size_t i = 0; i < ssl_listeners_.size(); ++i) {
516
    asio::ip::tcp::acceptor &acceptor = ssl_listeners_[i].acceptor;
517
    SslConnectionPtr &new_connection = ssl_listeners_[i].new_connection;
516
    asio::ip::tcp::acceptor &acceptor = ssl_listeners_[i]->acceptor;
517
    SslConnectionPtr &new_connection = ssl_listeners_[i]->new_connection;
518 518
    acceptor.async_accept(new_connection->socket(),
519 519
                          accept_strand_.wrap(
520 520
                            std::bind(&Server::handleSslAccept, this,
521
                                        &ssl_listeners_[i],
521
                                        ssl_listeners_[i],
522 522
                                        std::placeholders::_1)));
523 523
  }
524 524
#endif // HTTP_WITH_SSL
......
539 539
  if (!err) {
540 540
    // tcp_listeners_.front() should be fine here:
541 541
    // it should be the only acceptor when this is a session process
542
    auto port = tcp_listeners_.front().acceptor.local_endpoint().port();
542
    auto port = tcp_listeners_.front()->acceptor.local_endpoint().port();
543 543
    Wt::WStringStream ss;
544 544
    ss << "port:" << port << "\n";
545 545
    auto buf = std::make_shared<std::string>(ss.str());
......
595 595
void Server::handleResume()
596 596
{
597 597
  for (std::size_t i = 0; i < tcp_listeners_.size(); ++i)
598
    tcp_listeners_[i].acceptor.close();
598
    tcp_listeners_[i]->acceptor.close();
599 599
  tcp_listeners_.clear();
600 600

  
601 601
#ifdef HTTP_WITH_SSL
602 602
  for (std::size_t i = 0; i < ssl_listeners_.size(); ++i)
603
    ssl_listeners_[i].acceptor.close();
603
    ssl_listeners_[i]->acceptor.close();
604 604
  ssl_listeners_.clear();
605 605
#endif // HTTP_WITH_SSL
606 606

  
607 607
  start();
608 608
}
609 609

  
610
void Server::handleTcpAccept(TcpListener *listener, const Wt::AsioWrapper::error_code& e)
610
void Server::handleTcpAccept(const std::weak_ptr<TcpListener>& listener,
611
                             const Wt::AsioWrapper::error_code& e)
611 612
{
612
  if (!e) {
613
    connection_manager_.start(listener->new_connection);
614
    listener->new_connection.reset(new TcpConnection(wt_.ioService(), this,
615
                                                     connection_manager_, request_handler_));
616
  } else if (!listener->acceptor.is_open()) {
613
  auto l = listener.lock();
614
  if (!l || (e && !l->acceptor.is_open())) {
617 615
    // server shutdown
618
    LOG_DEBUG("handleTcpAccept: async_accept error (acceptor closed, probably server shutdown): " << e.message());
616
    LOG_DEBUG("handleTcpAccept: async_accept error (no listener, probably server shutdown): " << e.message());
619 617
    return;
618
  }
619

  
620
  if (!e) {
621
    connection_manager_.start(l->new_connection);
622
    l->new_connection.reset(new TcpConnection(wt_.ioService(), this,
623
                                              connection_manager_, request_handler_));
620 624
  } else {
621 625
    LOG_ERROR("handleTcpAccept: async_accept error: " << e.message());
622 626
  }
623 627

  
624
  listener->acceptor.async_accept(listener->new_connection->socket(),
625
                                  accept_strand_.wrap(
626
                                          std::bind(&Server::handleTcpAccept, this,
627
                                                    listener, std::placeholders::_1)));
628
  l->acceptor.async_accept(l->new_connection->socket(),
629
                           accept_strand_.wrap(
630
                                   std::bind(&Server::handleTcpAccept, this,
631
                                             listener, std::placeholders::_1)));
628 632
}
629 633

  
630 634
#ifdef HTTP_WITH_SSL
631
void Server::handleSslAccept(SslListener *listener, const Wt::AsioWrapper::error_code& e)
635
void Server::handleSslAccept(const std::weak_ptr<SslListener>& listener,
636
                             const Wt::AsioWrapper::error_code& e)
632 637
{
633
  if (!e) {
634
    connection_manager_.start(listener->new_connection);
635
    listener->new_connection.reset(new SslConnection(wt_.ioService(), this,
636
                                                     ssl_context_, connection_manager_, request_handler_));
637
  } else if (!listener->acceptor.is_open()) {
638
  auto l = listener.lock();
639
  if (!l || (e && !l->acceptor.is_open())) {
638 640
    // server shutdown
639
    LOG_DEBUG("handleSslAccept: async_accept error (acceptor closed, probably server shutdown): " << e.message());
641
    LOG_DEBUG("handleSslAccept: async_accept error (no listener, probably server shutdown): " << e.message());
640 642
    return;
643
  }
644

  
645
  if (!e) {
646
    connection_manager_.start(l->new_connection);
647
    l->new_connection.reset(new SslConnection(wt_.ioService(), this,
648
                                              ssl_context_, connection_manager_, request_handler_));
641 649
  } else {
642 650
    LOG_ERROR("handleSslAccept: async_accept error: " << e.message());
643 651
  }
644 652

  
645
  listener->acceptor.async_accept(listener->new_connection->socket(),
646
                                  accept_strand_.wrap(
647
                                          std::bind(&Server::handleSslAccept, this,
648
                                                    listener, std::placeholders::_1)));
653
  l->acceptor.async_accept(l->new_connection->socket(),
654
                           accept_strand_.wrap(
655
                                   std::bind(&Server::handleSslAccept, this,
656
                                             listener, std::placeholders::_1)));
649 657
}
650 658
#endif // HTTP_WITH_SSL
651 659

  
......
663 671
  // operations. Once all operations have finished the io_service::run() call
664 672
  // will exit.
665 673
  for (std::size_t i = 0; i < tcp_listeners_.size(); ++i)
666
    tcp_listeners_[i].acceptor.close();
674
    tcp_listeners_[i]->acceptor.close();
667 675
  tcp_listeners_.clear();
668 676

  
669 677
#ifdef HTTP_WITH_SSL
670 678
  for (std::size_t i = 0; i < ssl_listeners_.size(); ++i)
671
    ssl_listeners_[i].acceptor.close();
679
    ssl_listeners_[i]->acceptor.close();
672 680
  ssl_listeners_.clear();
673 681
#endif // HTTP_WITH_SSL
674 682

  
src/http/Server.h
31 31

  
32 32
#include "Wt/WLogger.h"
33 33

  
34
#include <memory>
35

  
34 36
namespace http {
35 37
namespace server {
36 38

  
......
110 112
  void closeParentConnection();
111 113

  
112 114
  /// Handle completion of an asynchronous accept operation.
113
  void handleTcpAccept(TcpListener *listener, const Wt::AsioWrapper::error_code& e);
115
  void handleTcpAccept(const std::weak_ptr<TcpListener>& listener,
116
                       const Wt::AsioWrapper::error_code& e);
114 117

  
115 118
  /// Handle a request to stop the server.
116 119
  void handleStop();
......
134 137
  Wt::AsioWrapper::strand accept_strand_;
135 138

  
136 139
  /// Acceptors used to listen for incoming http connections.
137
  std::vector<TcpListener> tcp_listeners_;
140
  std::vector<std::shared_ptr<TcpListener>> tcp_listeners_;
138 141

  
139 142
#ifdef HTTP_WITH_SSL
140 143
  struct SslListener {
......
149 152
  asio::ssl::context ssl_context_;
150 153

  
151 154
  /// Acceptors used to listen for incoming https connections
152
  std::vector<SslListener> ssl_listeners_;
155
  std::vector<std::shared_ptr<SslListener>> ssl_listeners_;
153 156

  
154 157
  /// Add new SSL listener, called from start()
155 158
  void addSslListener(asio::ip::tcp::resolver &resolver,
......
162 165
                      Wt::AsioWrapper::error_code &errc);
163 166

  
164 167
  /// Handle completion of an asynchronous SSL accept operation.
165
  void handleSslAccept(SslListener *listener, const Wt::AsioWrapper::error_code& e);
168
  void handleSslAccept(const std::weak_ptr<SslListener>& listener,
169
                       const Wt::AsioWrapper::error_code& e);
166 170
#endif // HTTP_WITH_SSL
167 171

  
168 172
  void handleTimeout(asio::steady_timer *timer,
169
- 
(4-4/4)