nghttpx: Fix worker process crash with neverbleed write error
This commit is contained in:
parent
e329479a99
commit
0422f8a844
|
@ -115,6 +115,9 @@ ConnectionHandler::ConnectionHandler(struct ev_loop *loop, std::mt19937 &gen)
|
||||||
: gen_(gen),
|
: gen_(gen),
|
||||||
single_worker_(nullptr),
|
single_worker_(nullptr),
|
||||||
loop_(loop),
|
loop_(loop),
|
||||||
|
#ifdef HAVE_NEVERBLEED
|
||||||
|
nb_(nullptr),
|
||||||
|
#endif // HAVE_NEVERBLEED
|
||||||
tls_ticket_key_memcached_get_retry_count_(0),
|
tls_ticket_key_memcached_get_retry_count_(0),
|
||||||
tls_ticket_key_memcached_fail_count_(0),
|
tls_ticket_key_memcached_fail_count_(0),
|
||||||
worker_round_robin_cnt_(get_config()->api.enabled ? 1 : 0),
|
worker_round_robin_cnt_(get_config()->api.enabled ? 1 : 0),
|
||||||
|
@ -205,12 +208,12 @@ int ConnectionHandler::create_single_worker() {
|
||||||
all_ssl_ctx_, indexed_ssl_ctx_, cert_tree_.get()
|
all_ssl_ctx_, indexed_ssl_ctx_, cert_tree_.get()
|
||||||
#ifdef HAVE_NEVERBLEED
|
#ifdef HAVE_NEVERBLEED
|
||||||
,
|
,
|
||||||
nb_.get()
|
nb_
|
||||||
#endif // HAVE_NEVERBLEED
|
#endif // HAVE_NEVERBLEED
|
||||||
);
|
);
|
||||||
auto cl_ssl_ctx = tls::setup_downstream_client_ssl_context(
|
auto cl_ssl_ctx = tls::setup_downstream_client_ssl_context(
|
||||||
#ifdef HAVE_NEVERBLEED
|
#ifdef HAVE_NEVERBLEED
|
||||||
nb_.get()
|
nb_
|
||||||
#endif // HAVE_NEVERBLEED
|
#endif // HAVE_NEVERBLEED
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -227,7 +230,7 @@ int ConnectionHandler::create_single_worker() {
|
||||||
if (memcachedconf.tls) {
|
if (memcachedconf.tls) {
|
||||||
session_cache_ssl_ctx = tls::create_ssl_client_context(
|
session_cache_ssl_ctx = tls::create_ssl_client_context(
|
||||||
#ifdef HAVE_NEVERBLEED
|
#ifdef HAVE_NEVERBLEED
|
||||||
nb_.get(),
|
nb_,
|
||||||
#endif // HAVE_NEVERBLEED
|
#endif // HAVE_NEVERBLEED
|
||||||
tlsconf.cacert, memcachedconf.cert_file,
|
tlsconf.cacert, memcachedconf.cert_file,
|
||||||
memcachedconf.private_key_file, nullptr);
|
memcachedconf.private_key_file, nullptr);
|
||||||
|
@ -256,12 +259,12 @@ int ConnectionHandler::create_worker_thread(size_t num) {
|
||||||
all_ssl_ctx_, indexed_ssl_ctx_, cert_tree_.get()
|
all_ssl_ctx_, indexed_ssl_ctx_, cert_tree_.get()
|
||||||
# ifdef HAVE_NEVERBLEED
|
# ifdef HAVE_NEVERBLEED
|
||||||
,
|
,
|
||||||
nb_.get()
|
nb_
|
||||||
# endif // HAVE_NEVERBLEED
|
# endif // HAVE_NEVERBLEED
|
||||||
);
|
);
|
||||||
auto cl_ssl_ctx = tls::setup_downstream_client_ssl_context(
|
auto cl_ssl_ctx = tls::setup_downstream_client_ssl_context(
|
||||||
# ifdef HAVE_NEVERBLEED
|
# ifdef HAVE_NEVERBLEED
|
||||||
nb_.get()
|
nb_
|
||||||
# endif // HAVE_NEVERBLEED
|
# endif // HAVE_NEVERBLEED
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -285,7 +288,7 @@ int ConnectionHandler::create_worker_thread(size_t num) {
|
||||||
if (memcachedconf.tls) {
|
if (memcachedconf.tls) {
|
||||||
session_cache_ssl_ctx = tls::create_ssl_client_context(
|
session_cache_ssl_ctx = tls::create_ssl_client_context(
|
||||||
# ifdef HAVE_NEVERBLEED
|
# ifdef HAVE_NEVERBLEED
|
||||||
nb_.get(),
|
nb_,
|
||||||
# endif // HAVE_NEVERBLEED
|
# endif // HAVE_NEVERBLEED
|
||||||
tlsconf.cacert, memcachedconf.cert_file,
|
tlsconf.cacert, memcachedconf.cert_file,
|
||||||
memcachedconf.private_key_file, nullptr);
|
memcachedconf.private_key_file, nullptr);
|
||||||
|
@ -802,7 +805,7 @@ SSL_CTX *ConnectionHandler::create_tls_ticket_key_memcached_ssl_ctx() {
|
||||||
|
|
||||||
auto ssl_ctx = tls::create_ssl_client_context(
|
auto ssl_ctx = tls::create_ssl_client_context(
|
||||||
#ifdef HAVE_NEVERBLEED
|
#ifdef HAVE_NEVERBLEED
|
||||||
nb_.get(),
|
nb_,
|
||||||
#endif // HAVE_NEVERBLEED
|
#endif // HAVE_NEVERBLEED
|
||||||
tlsconf.cacert, memcachedconf.cert_file, memcachedconf.private_key_file,
|
tlsconf.cacert, memcachedconf.cert_file, memcachedconf.private_key_file,
|
||||||
nullptr);
|
nullptr);
|
||||||
|
@ -813,12 +816,7 @@ SSL_CTX *ConnectionHandler::create_tls_ticket_key_memcached_ssl_ctx() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_NEVERBLEED
|
#ifdef HAVE_NEVERBLEED
|
||||||
void ConnectionHandler::set_neverbleed(std::unique_ptr<neverbleed_t> nb) {
|
void ConnectionHandler::set_neverbleed(neverbleed_t *nb) { nb_ = nb; }
|
||||||
nb_ = std::move(nb);
|
|
||||||
}
|
|
||||||
|
|
||||||
neverbleed_t *ConnectionHandler::get_neverbleed() const { return nb_.get(); }
|
|
||||||
|
|
||||||
#endif // HAVE_NEVERBLEED
|
#endif // HAVE_NEVERBLEED
|
||||||
|
|
||||||
void ConnectionHandler::handle_serial_event() {
|
void ConnectionHandler::handle_serial_event() {
|
||||||
|
|
|
@ -160,8 +160,7 @@ public:
|
||||||
const std::vector<SSL_CTX *> &get_indexed_ssl_ctx(size_t idx) const;
|
const std::vector<SSL_CTX *> &get_indexed_ssl_ctx(size_t idx) const;
|
||||||
|
|
||||||
#ifdef HAVE_NEVERBLEED
|
#ifdef HAVE_NEVERBLEED
|
||||||
void set_neverbleed(std::unique_ptr<neverbleed_t> nb);
|
void set_neverbleed(neverbleed_t *nb);
|
||||||
neverbleed_t *get_neverbleed() const;
|
|
||||||
#endif // HAVE_NEVERBLEED
|
#endif // HAVE_NEVERBLEED
|
||||||
|
|
||||||
// Send SerialEvent SEV_REPLACE_DOWNSTREAM to this object.
|
// Send SerialEvent SEV_REPLACE_DOWNSTREAM to this object.
|
||||||
|
@ -210,7 +209,7 @@ private:
|
||||||
struct ev_loop *loop_;
|
struct ev_loop *loop_;
|
||||||
std::vector<std::unique_ptr<AcceptHandler>> acceptors_;
|
std::vector<std::unique_ptr<AcceptHandler>> acceptors_;
|
||||||
#ifdef HAVE_NEVERBLEED
|
#ifdef HAVE_NEVERBLEED
|
||||||
std::unique_ptr<neverbleed_t> nb_;
|
neverbleed_t *nb_;
|
||||||
#endif // HAVE_NEVERBLEED
|
#endif // HAVE_NEVERBLEED
|
||||||
ev_timer disable_acceptor_timer_;
|
ev_timer disable_acceptor_timer_;
|
||||||
ev_timer ocsp_timer_;
|
ev_timer ocsp_timer_;
|
||||||
|
|
|
@ -411,35 +411,30 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
|
||||||
|
|
||||||
auto gen = util::make_mt19937();
|
auto gen = util::make_mt19937();
|
||||||
|
|
||||||
ConnectionHandler conn_handler(loop, gen);
|
auto conn_handler = make_unique<ConnectionHandler>(loop, gen);
|
||||||
|
|
||||||
for (auto &addr : config->conn.listener.addrs) {
|
for (auto &addr : config->conn.listener.addrs) {
|
||||||
conn_handler.add_acceptor(make_unique<AcceptHandler>(&addr, &conn_handler));
|
conn_handler->add_acceptor(
|
||||||
|
make_unique<AcceptHandler>(&addr, conn_handler.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_NEVERBLEED
|
#ifdef HAVE_NEVERBLEED
|
||||||
{
|
std::array<char, NEVERBLEED_ERRBUF_SIZE> nb_errbuf;
|
||||||
std::array<char, NEVERBLEED_ERRBUF_SIZE> nb_errbuf;
|
auto nb = make_unique<neverbleed_t>();
|
||||||
auto nb = make_unique<neverbleed_t>();
|
if (neverbleed_init(nb.get(), nb_errbuf.data()) != 0) {
|
||||||
if (neverbleed_init(nb.get(), nb_errbuf.data()) != 0) {
|
LOG(FATAL) << "neverbleed_init failed: " << nb_errbuf.data();
|
||||||
LOG(FATAL) << "neverbleed_init failed: " << nb_errbuf.data();
|
return -1;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(NOTICE) << "neverbleed process [" << nb->daemon_pid << "] spawned";
|
|
||||||
|
|
||||||
conn_handler.set_neverbleed(std::move(nb));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto nb = conn_handler.get_neverbleed();
|
LOG(NOTICE) << "neverbleed process [" << nb->daemon_pid << "] spawned";
|
||||||
|
|
||||||
|
conn_handler->set_neverbleed(nb.get());
|
||||||
|
|
||||||
ev_child nb_childev;
|
ev_child nb_childev;
|
||||||
if (nb) {
|
|
||||||
ev_child_init(&nb_childev, nb_child_cb, nb->daemon_pid, 0);
|
|
||||||
nb_childev.data = nullptr;
|
|
||||||
ev_child_start(loop, &nb_childev);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
ev_child_init(&nb_childev, nb_child_cb, nb->daemon_pid, 0);
|
||||||
|
nb_childev.data = nullptr;
|
||||||
|
ev_child_start(loop, &nb_childev);
|
||||||
#endif // HAVE_NEVERBLEED
|
#endif // HAVE_NEVERBLEED
|
||||||
|
|
||||||
MemchunkPool mcpool;
|
MemchunkPool mcpool;
|
||||||
|
@ -453,17 +448,17 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
|
||||||
SSL_CTX *ssl_ctx = nullptr;
|
SSL_CTX *ssl_ctx = nullptr;
|
||||||
|
|
||||||
if (memcachedconf.tls) {
|
if (memcachedconf.tls) {
|
||||||
ssl_ctx = conn_handler.create_tls_ticket_key_memcached_ssl_ctx();
|
ssl_ctx = conn_handler->create_tls_ticket_key_memcached_ssl_ctx();
|
||||||
}
|
}
|
||||||
|
|
||||||
conn_handler.set_tls_ticket_key_memcached_dispatcher(
|
conn_handler->set_tls_ticket_key_memcached_dispatcher(
|
||||||
make_unique<MemcachedDispatcher>(
|
make_unique<MemcachedDispatcher>(
|
||||||
&ticketconf.memcached.addr, loop, ssl_ctx,
|
&ticketconf.memcached.addr, loop, ssl_ctx,
|
||||||
StringRef{memcachedconf.host}, &mcpool, gen));
|
StringRef{memcachedconf.host}, &mcpool, gen));
|
||||||
|
|
||||||
ev_timer_init(&renew_ticket_key_timer, memcached_get_ticket_key_cb, 0.,
|
ev_timer_init(&renew_ticket_key_timer, memcached_get_ticket_key_cb, 0.,
|
||||||
0.);
|
0.);
|
||||||
renew_ticket_key_timer.data = &conn_handler;
|
renew_ticket_key_timer.data = conn_handler.get();
|
||||||
// Get first ticket keys.
|
// Get first ticket keys.
|
||||||
memcached_get_ticket_key_cb(loop, &renew_ticket_key_timer, 0);
|
memcached_get_ticket_key_cb(loop, &renew_ticket_key_timer, 0);
|
||||||
} else {
|
} else {
|
||||||
|
@ -483,14 +478,14 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
|
||||||
if (!ticket_keys) {
|
if (!ticket_keys) {
|
||||||
LOG(WARN) << "Use internal session ticket key generator";
|
LOG(WARN) << "Use internal session ticket key generator";
|
||||||
} else {
|
} else {
|
||||||
conn_handler.set_ticket_keys(std::move(ticket_keys));
|
conn_handler->set_ticket_keys(std::move(ticket_keys));
|
||||||
auto_tls_ticket_key = false;
|
auto_tls_ticket_key = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (auto_tls_ticket_key) {
|
if (auto_tls_ticket_key) {
|
||||||
// Generate new ticket key every 1hr.
|
// Generate new ticket key every 1hr.
|
||||||
ev_timer_init(&renew_ticket_key_timer, renew_ticket_key_cb, 0., 1_h);
|
ev_timer_init(&renew_ticket_key_timer, renew_ticket_key_cb, 0., 1_h);
|
||||||
renew_ticket_key_timer.data = &conn_handler;
|
renew_ticket_key_timer.data = conn_handler.get();
|
||||||
ev_timer_again(loop, &renew_ticket_key_timer);
|
ev_timer_again(loop, &renew_ticket_key_timer);
|
||||||
|
|
||||||
// Generate first session ticket key before running workers.
|
// Generate first session ticket key before running workers.
|
||||||
|
@ -500,7 +495,7 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config->single_thread) {
|
if (config->single_thread) {
|
||||||
rv = conn_handler.create_single_worker();
|
rv = conn_handler->create_single_worker();
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -518,7 +513,7 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
|
||||||
}
|
}
|
||||||
#endif // !NOTHREADS
|
#endif // !NOTHREADS
|
||||||
|
|
||||||
rv = conn_handler.create_worker_thread(config->num_worker);
|
rv = conn_handler->create_worker_thread(config->num_worker);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -535,22 +530,22 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
|
||||||
|
|
||||||
drop_privileges(
|
drop_privileges(
|
||||||
#ifdef HAVE_NEVERBLEED
|
#ifdef HAVE_NEVERBLEED
|
||||||
nb
|
nb.get()
|
||||||
#endif // HAVE_NEVERBLEED
|
#endif // HAVE_NEVERBLEED
|
||||||
);
|
);
|
||||||
|
|
||||||
ev_io ipcev;
|
ev_io ipcev;
|
||||||
ev_io_init(&ipcev, ipc_readcb, wpconf->ipc_fd, EV_READ);
|
ev_io_init(&ipcev, ipc_readcb, wpconf->ipc_fd, EV_READ);
|
||||||
ipcev.data = &conn_handler;
|
ipcev.data = conn_handler.get();
|
||||||
ev_io_start(loop, &ipcev);
|
ev_io_start(loop, &ipcev);
|
||||||
|
|
||||||
if (tls::upstream_tls_enabled(config->conn) && !config->tls.ocsp.disabled) {
|
if (tls::upstream_tls_enabled(config->conn) && !config->tls.ocsp.disabled) {
|
||||||
if (config->tls.ocsp.startup) {
|
if (config->tls.ocsp.startup) {
|
||||||
conn_handler.set_enable_acceptor_on_ocsp_completion(true);
|
conn_handler->set_enable_acceptor_on_ocsp_completion(true);
|
||||||
conn_handler.disable_acceptor();
|
conn_handler->disable_acceptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
conn_handler.proceed_next_cert_ocsp();
|
conn_handler->proceed_next_cert_ocsp();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
|
@ -559,27 +554,29 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
|
||||||
|
|
||||||
ev_run(loop, 0);
|
ev_run(loop, 0);
|
||||||
|
|
||||||
conn_handler.cancel_ocsp_update();
|
conn_handler->cancel_ocsp_update();
|
||||||
|
|
||||||
|
// Destroy SSL_CTX held in conn_handler before killing neverbleed
|
||||||
|
// daemon. Otherwise priv_rsa_finish yields "write error" and
|
||||||
|
// worker process aborts.
|
||||||
|
conn_handler.reset();
|
||||||
|
|
||||||
#ifdef HAVE_NEVERBLEED
|
#ifdef HAVE_NEVERBLEED
|
||||||
if (nb) {
|
assert(nb->daemon_pid > 0);
|
||||||
assert(nb->daemon_pid > 0);
|
|
||||||
|
|
||||||
rv = kill(nb->daemon_pid, SIGTERM);
|
rv = kill(nb->daemon_pid, SIGTERM);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
auto error = errno;
|
auto error = errno;
|
||||||
LOG(ERROR) << "Could not send signal to neverbleed daemon: errno="
|
LOG(ERROR) << "Could not send signal to neverbleed daemon: errno=" << error;
|
||||||
<< error;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
while ((rv = waitpid(nb->daemon_pid, nullptr, 0)) == -1 && errno == EINTR)
|
while ((rv = waitpid(nb->daemon_pid, nullptr, 0)) == -1 && errno == EINTR)
|
||||||
;
|
;
|
||||||
if (rv == -1) {
|
if (rv == -1) {
|
||||||
auto error = errno;
|
auto error = errno;
|
||||||
LOG(ERROR) << "Error occurred while we were waiting for the completion "
|
LOG(ERROR) << "Error occurred while we were waiting for the completion "
|
||||||
"of neverbleed process: errno="
|
"of neverbleed process: errno="
|
||||||
<< error;
|
<< error;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif // HAVE_NEVERBLEED
|
#endif // HAVE_NEVERBLEED
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue