1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2015 Tatsuhiro Tsujikawa
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #include "shrpx_worker_process.h"
26 
27 #include <sys/types.h>
28 #ifdef HAVE_UNISTD_H
29 #  include <unistd.h>
30 #endif // HAVE_UNISTD_H
31 #include <sys/resource.h>
32 #include <sys/wait.h>
33 #include <grp.h>
34 
35 #include <cinttypes>
36 #include <cstdlib>
37 
38 #include <openssl/rand.h>
39 
40 #include <ev.h>
41 
42 #include <ares.h>
43 
44 #include "shrpx_config.h"
45 #include "shrpx_connection_handler.h"
46 #include "shrpx_log_config.h"
47 #include "shrpx_worker.h"
48 #include "shrpx_accept_handler.h"
49 #include "shrpx_http2_upstream.h"
50 #include "shrpx_http2_session.h"
51 #include "shrpx_memcached_dispatcher.h"
52 #include "shrpx_memcached_request.h"
53 #include "shrpx_process.h"
54 #include "shrpx_tls.h"
55 #include "shrpx_log.h"
56 #include "util.h"
57 #include "app_helper.h"
58 #include "template.h"
59 #include "xsi_strerror.h"
60 
61 using namespace nghttp2;
62 
63 namespace shrpx {
64 
65 namespace {
drop_privileges(neverbleed_t * nb)66 void drop_privileges(
67 #ifdef HAVE_NEVERBLEED
68     neverbleed_t *nb
69 #endif // HAVE_NEVERBLEED
70 ) {
71   std::array<char, STRERROR_BUFSIZE> errbuf;
72   auto config = get_config();
73 
74   if (getuid() == 0 && config->uid != 0) {
75 #ifdef HAVE_NEVERBLEED
76     if (nb) {
77       neverbleed_setuidgid(nb, config->user.c_str(), 1);
78     }
79 #endif // HAVE_NEVERBLEED
80 
81     if (initgroups(config->user.c_str(), config->gid) != 0) {
82       auto error = errno;
83       LOG(FATAL) << "Could not change supplementary groups: "
84                  << xsi_strerror(error, errbuf.data(), errbuf.size());
85       exit(EXIT_FAILURE);
86     }
87     if (setgid(config->gid) != 0) {
88       auto error = errno;
89       LOG(FATAL) << "Could not change gid: "
90                  << xsi_strerror(error, errbuf.data(), errbuf.size());
91       exit(EXIT_FAILURE);
92     }
93     if (setuid(config->uid) != 0) {
94       auto error = errno;
95       LOG(FATAL) << "Could not change uid: "
96                  << xsi_strerror(error, errbuf.data(), errbuf.size());
97       exit(EXIT_FAILURE);
98     }
99     if (setuid(0) != -1) {
100       LOG(FATAL) << "Still have root privileges?";
101       exit(EXIT_FAILURE);
102     }
103   }
104 }
105 } // namespace
106 
107 namespace {
graceful_shutdown(ConnectionHandler * conn_handler)108 void graceful_shutdown(ConnectionHandler *conn_handler) {
109   if (conn_handler->get_graceful_shutdown()) {
110     return;
111   }
112 
113   LOG(NOTICE) << "Graceful shutdown signal received";
114 
115   conn_handler->set_graceful_shutdown(true);
116 
117   // TODO What happens for the connections not established in the
118   // kernel?
119   conn_handler->accept_pending_connection();
120   conn_handler->delete_acceptor();
121 
122   conn_handler->graceful_shutdown_worker();
123 
124   auto single_worker = conn_handler->get_single_worker();
125   if (single_worker) {
126     if (single_worker->get_worker_stat()->num_connections == 0) {
127       ev_break(conn_handler->get_loop());
128     }
129 
130     return;
131   }
132 }
133 } // namespace
134 
135 namespace {
reopen_log(ConnectionHandler * conn_handler)136 void reopen_log(ConnectionHandler *conn_handler) {
137   LOG(NOTICE) << "Reopening log files: worker process (thread main)";
138 
139   auto config = get_config();
140   auto &loggingconf = config->logging;
141 
142   (void)reopen_log_files(loggingconf);
143   redirect_stderr_to_errorlog(loggingconf);
144 
145   conn_handler->worker_reopen_log_files();
146 }
147 } // namespace
148 
149 namespace {
ipc_readcb(struct ev_loop * loop,ev_io * w,int revents)150 void ipc_readcb(struct ev_loop *loop, ev_io *w, int revents) {
151   auto conn_handler = static_cast<ConnectionHandler *>(w->data);
152   std::array<uint8_t, 1024> buf;
153   ssize_t nread;
154   while ((nread = read(w->fd, buf.data(), buf.size())) == -1 && errno == EINTR)
155     ;
156   if (nread == -1) {
157     auto error = errno;
158     LOG(ERROR) << "Failed to read data from ipc channel: errno=" << error;
159     return;
160   }
161 
162   if (nread == 0) {
163     // IPC socket closed.  Perform immediate shutdown.
164     LOG(FATAL) << "IPC socket is closed.  Perform immediate shutdown.";
165     nghttp2_Exit(EXIT_FAILURE);
166   }
167 
168   for (ssize_t i = 0; i < nread; ++i) {
169     switch (buf[i]) {
170     case SHRPX_IPC_GRACEFUL_SHUTDOWN:
171       graceful_shutdown(conn_handler);
172       break;
173     case SHRPX_IPC_REOPEN_LOG:
174       reopen_log(conn_handler);
175       break;
176     }
177   }
178 }
179 } // namespace
180 
181 namespace {
generate_ticket_key(TicketKey & ticket_key)182 int generate_ticket_key(TicketKey &ticket_key) {
183   ticket_key.cipher = get_config()->tls.ticket.cipher;
184   ticket_key.hmac = EVP_sha256();
185   ticket_key.hmac_keylen = EVP_MD_size(ticket_key.hmac);
186 
187   assert(static_cast<size_t>(EVP_CIPHER_key_length(ticket_key.cipher)) <=
188          ticket_key.data.enc_key.size());
189   assert(ticket_key.hmac_keylen <= ticket_key.data.hmac_key.size());
190 
191   if (LOG_ENABLED(INFO)) {
192     LOG(INFO) << "enc_keylen=" << EVP_CIPHER_key_length(ticket_key.cipher)
193               << ", hmac_keylen=" << ticket_key.hmac_keylen;
194   }
195 
196   if (RAND_bytes(reinterpret_cast<unsigned char *>(&ticket_key.data),
197                  sizeof(ticket_key.data)) == 0) {
198     return -1;
199   }
200 
201   return 0;
202 }
203 } // namespace
204 
205 namespace {
renew_ticket_key_cb(struct ev_loop * loop,ev_timer * w,int revents)206 void renew_ticket_key_cb(struct ev_loop *loop, ev_timer *w, int revents) {
207   auto conn_handler = static_cast<ConnectionHandler *>(w->data);
208   const auto &old_ticket_keys = conn_handler->get_ticket_keys();
209 
210   auto ticket_keys = std::make_shared<TicketKeys>();
211   LOG(NOTICE) << "Renew new ticket keys";
212 
213   // If old_ticket_keys is not empty, it should contain at least 2
214   // keys: one for encryption, and last one for the next encryption
215   // key but decryption only.  The keys in between are old keys and
216   // decryption only.  The next key is provided to ensure to mitigate
217   // possible problem when one worker encrypt new key, but one worker,
218   // which did not take the that key yet, and cannot decrypt it.
219   //
220   // We keep keys for get_config()->tls_session_timeout seconds.  The
221   // default is 12 hours.  Thus the maximum ticket vector size is 12.
222   if (old_ticket_keys) {
223     auto &old_keys = old_ticket_keys->keys;
224     auto &new_keys = ticket_keys->keys;
225 
226     assert(!old_keys.empty());
227 
228     auto max_tickets =
229         static_cast<size_t>(std::chrono::duration_cast<std::chrono::hours>(
230                                 get_config()->tls.session_timeout)
231                                 .count());
232 
233     new_keys.resize(std::min(max_tickets, old_keys.size() + 1));
234     std::copy_n(std::begin(old_keys), new_keys.size() - 1,
235                 std::begin(new_keys) + 1);
236   } else {
237     ticket_keys->keys.resize(1);
238   }
239 
240   auto &new_key = ticket_keys->keys[0];
241 
242   if (generate_ticket_key(new_key) != 0) {
243     if (LOG_ENABLED(INFO)) {
244       LOG(INFO) << "failed to generate ticket key";
245     }
246     conn_handler->set_ticket_keys(nullptr);
247     conn_handler->set_ticket_keys_to_worker(nullptr);
248     return;
249   }
250 
251   if (LOG_ENABLED(INFO)) {
252     LOG(INFO) << "ticket keys generation done";
253     assert(ticket_keys->keys.size() >= 1);
254     LOG(INFO) << 0 << " enc+dec: "
255               << util::format_hex(ticket_keys->keys[0].data.name);
256     for (size_t i = 1; i < ticket_keys->keys.size(); ++i) {
257       auto &key = ticket_keys->keys[i];
258       LOG(INFO) << i << " dec: " << util::format_hex(key.data.name);
259     }
260   }
261 
262   conn_handler->set_ticket_keys(ticket_keys);
263   conn_handler->set_ticket_keys_to_worker(ticket_keys);
264 }
265 } // namespace
266 
267 namespace {
memcached_get_ticket_key_cb(struct ev_loop * loop,ev_timer * w,int revents)268 void memcached_get_ticket_key_cb(struct ev_loop *loop, ev_timer *w,
269                                  int revents) {
270   auto conn_handler = static_cast<ConnectionHandler *>(w->data);
271   auto dispatcher = conn_handler->get_tls_ticket_key_memcached_dispatcher();
272 
273   auto req = std::make_unique<MemcachedRequest>();
274   req->key = "nghttpx:tls-ticket-key";
275   req->op = MemcachedOp::GET;
276   req->cb = [conn_handler, w](MemcachedRequest *req, MemcachedResult res) {
277     switch (res.status_code) {
278     case MemcachedStatusCode::NO_ERROR:
279       break;
280     case MemcachedStatusCode::EXT_NETWORK_ERROR:
281       conn_handler->on_tls_ticket_key_network_error(w);
282       return;
283     default:
284       conn_handler->on_tls_ticket_key_not_found(w);
285       return;
286     }
287 
288     // |version (4bytes)|len (2bytes)|key (variable length)|...
289     // (len, key) pairs are repeated as necessary.
290 
291     auto &value = res.value;
292     if (value.size() < 4) {
293       LOG(WARN) << "Memcached: tls ticket key value is too small: got "
294                 << value.size();
295       conn_handler->on_tls_ticket_key_not_found(w);
296       return;
297     }
298     auto p = value.data();
299     auto version = util::get_uint32(p);
300     // Currently supported version is 1.
301     if (version != 1) {
302       LOG(WARN) << "Memcached: tls ticket key version: want 1, got " << version;
303       conn_handler->on_tls_ticket_key_not_found(w);
304       return;
305     }
306 
307     auto end = p + value.size();
308     p += 4;
309 
310     auto &ticketconf = get_config()->tls.ticket;
311 
312     size_t expectedlen;
313     size_t enc_keylen;
314     size_t hmac_keylen;
315     if (ticketconf.cipher == EVP_aes_128_cbc()) {
316       expectedlen = 48;
317       enc_keylen = 16;
318       hmac_keylen = 16;
319     } else if (ticketconf.cipher == EVP_aes_256_cbc()) {
320       expectedlen = 80;
321       enc_keylen = 32;
322       hmac_keylen = 32;
323     } else {
324       return;
325     }
326 
327     auto ticket_keys = std::make_shared<TicketKeys>();
328 
329     for (; p != end;) {
330       if (end - p < 2) {
331         LOG(WARN) << "Memcached: tls ticket key data is too small";
332         conn_handler->on_tls_ticket_key_not_found(w);
333         return;
334       }
335       auto len = util::get_uint16(p);
336       p += 2;
337       if (len != expectedlen) {
338         LOG(WARN) << "Memcached: wrong tls ticket key size: want "
339                   << expectedlen << ", got " << len;
340         conn_handler->on_tls_ticket_key_not_found(w);
341         return;
342       }
343       if (p + len > end) {
344         LOG(WARN) << "Memcached: too short tls ticket key payload: want " << len
345                   << ", got " << (end - p);
346         conn_handler->on_tls_ticket_key_not_found(w);
347         return;
348       }
349       auto key = TicketKey();
350       key.cipher = ticketconf.cipher;
351       key.hmac = EVP_sha256();
352       key.hmac_keylen = hmac_keylen;
353 
354       std::copy_n(p, key.data.name.size(), std::begin(key.data.name));
355       p += key.data.name.size();
356 
357       std::copy_n(p, enc_keylen, std::begin(key.data.enc_key));
358       p += enc_keylen;
359 
360       std::copy_n(p, hmac_keylen, std::begin(key.data.hmac_key));
361       p += hmac_keylen;
362 
363       ticket_keys->keys.push_back(std::move(key));
364     }
365 
366     conn_handler->on_tls_ticket_key_get_success(ticket_keys, w);
367   };
368 
369   if (LOG_ENABLED(INFO)) {
370     LOG(INFO) << "Memcached: tls ticket key get request sent";
371   }
372 
373   dispatcher->add_request(std::move(req));
374 }
375 
376 } // namespace
377 
378 #ifdef HAVE_NEVERBLEED
379 namespace {
nb_child_cb(struct ev_loop * loop,ev_child * w,int revents)380 void nb_child_cb(struct ev_loop *loop, ev_child *w, int revents) {
381   log_chld(w->rpid, w->rstatus, "neverbleed process");
382 
383   ev_child_stop(loop, w);
384 
385   LOG(FATAL) << "neverbleed process exitted; aborting now";
386 
387   nghttp2_Exit(EXIT_FAILURE);
388 }
389 } // namespace
390 #endif // HAVE_NEVERBLEED
391 
worker_process_event_loop(WorkerProcessConfig * wpconf)392 int worker_process_event_loop(WorkerProcessConfig *wpconf) {
393   int rv;
394   std::array<char, STRERROR_BUFSIZE> errbuf;
395   (void)errbuf;
396 
397   auto config = get_config();
398 
399   if (reopen_log_files(config->logging) != 0) {
400     LOG(FATAL) << "Failed to open log file";
401     return -1;
402   }
403 
404   rv = ares_library_init(ARES_LIB_INIT_ALL);
405   if (rv != 0) {
406     LOG(FATAL) << "ares_library_init failed: " << ares_strerror(rv);
407     return -1;
408   }
409 
410   auto loop = EV_DEFAULT;
411 
412   auto gen = util::make_mt19937();
413 
414   auto conn_handler = std::make_unique<ConnectionHandler>(loop, gen);
415 
416   for (auto &addr : config->conn.listener.addrs) {
417     conn_handler->add_acceptor(
418         std::make_unique<AcceptHandler>(&addr, conn_handler.get()));
419   }
420 
421 #ifdef HAVE_NEVERBLEED
422   std::array<char, NEVERBLEED_ERRBUF_SIZE> nb_errbuf;
423   auto nb = std::make_unique<neverbleed_t>();
424   if (neverbleed_init(nb.get(), nb_errbuf.data()) != 0) {
425     LOG(FATAL) << "neverbleed_init failed: " << nb_errbuf.data();
426     return -1;
427   }
428 
429   LOG(NOTICE) << "neverbleed process [" << nb->daemon_pid << "] spawned";
430 
431   conn_handler->set_neverbleed(nb.get());
432 
433   ev_child nb_childev;
434 
435   ev_child_init(&nb_childev, nb_child_cb, nb->daemon_pid, 0);
436   nb_childev.data = nullptr;
437   ev_child_start(loop, &nb_childev);
438 #endif // HAVE_NEVERBLEED
439 
440   MemchunkPool mcpool;
441 
442   ev_timer renew_ticket_key_timer;
443   if (tls::upstream_tls_enabled(config->conn)) {
444     auto &ticketconf = config->tls.ticket;
445     auto &memcachedconf = ticketconf.memcached;
446 
447     if (!memcachedconf.host.empty()) {
448       SSL_CTX *ssl_ctx = nullptr;
449 
450       if (memcachedconf.tls) {
451         ssl_ctx = conn_handler->create_tls_ticket_key_memcached_ssl_ctx();
452       }
453 
454       conn_handler->set_tls_ticket_key_memcached_dispatcher(
455           std::make_unique<MemcachedDispatcher>(
456               &ticketconf.memcached.addr, loop, ssl_ctx,
457               StringRef{memcachedconf.host}, &mcpool, gen));
458 
459       ev_timer_init(&renew_ticket_key_timer, memcached_get_ticket_key_cb, 0.,
460                     0.);
461       renew_ticket_key_timer.data = conn_handler.get();
462       // Get first ticket keys.
463       memcached_get_ticket_key_cb(loop, &renew_ticket_key_timer, 0);
464     } else {
465       bool auto_tls_ticket_key = true;
466       if (!ticketconf.files.empty()) {
467         if (!ticketconf.cipher_given) {
468           LOG(WARN)
469               << "It is strongly recommended to specify "
470                  "--tls-ticket-key-cipher=aes-128-cbc (or "
471                  "tls-ticket-key-cipher=aes-128-cbc in configuration file) "
472                  "when --tls-ticket-key-file is used for the smooth "
473                  "transition when the default value of --tls-ticket-key-cipher "
474                  "becomes aes-256-cbc";
475         }
476         auto ticket_keys = read_tls_ticket_key_file(
477             ticketconf.files, ticketconf.cipher, EVP_sha256());
478         if (!ticket_keys) {
479           LOG(WARN) << "Use internal session ticket key generator";
480         } else {
481           conn_handler->set_ticket_keys(std::move(ticket_keys));
482           auto_tls_ticket_key = false;
483         }
484       }
485       if (auto_tls_ticket_key) {
486         // Generate new ticket key every 1hr.
487         ev_timer_init(&renew_ticket_key_timer, renew_ticket_key_cb, 0., 1_h);
488         renew_ticket_key_timer.data = conn_handler.get();
489         ev_timer_again(loop, &renew_ticket_key_timer);
490 
491         // Generate first session ticket key before running workers.
492         renew_ticket_key_cb(loop, &renew_ticket_key_timer, 0);
493       }
494     }
495   }
496 
497   if (config->single_thread) {
498     rv = conn_handler->create_single_worker();
499     if (rv != 0) {
500       return -1;
501     }
502   } else {
503 #ifndef NOTHREADS
504     sigset_t set;
505     sigemptyset(&set);
506     sigaddset(&set, SIGCHLD);
507 
508     rv = pthread_sigmask(SIG_BLOCK, &set, nullptr);
509     if (rv != 0) {
510       LOG(ERROR) << "Blocking SIGCHLD failed: "
511                  << xsi_strerror(rv, errbuf.data(), errbuf.size());
512       return -1;
513     }
514 #endif // !NOTHREADS
515 
516     rv = conn_handler->create_worker_thread(config->num_worker);
517     if (rv != 0) {
518       return -1;
519     }
520 
521 #ifndef NOTHREADS
522     rv = pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
523     if (rv != 0) {
524       LOG(ERROR) << "Unblocking SIGCHLD failed: "
525                  << xsi_strerror(rv, errbuf.data(), errbuf.size());
526       return -1;
527     }
528 #endif // !NOTHREADS
529   }
530 
531   drop_privileges(
532 #ifdef HAVE_NEVERBLEED
533       nb.get()
534 #endif // HAVE_NEVERBLEED
535   );
536 
537   ev_io ipcev;
538   ev_io_init(&ipcev, ipc_readcb, wpconf->ipc_fd, EV_READ);
539   ipcev.data = conn_handler.get();
540   ev_io_start(loop, &ipcev);
541 
542   if (tls::upstream_tls_enabled(config->conn) && !config->tls.ocsp.disabled) {
543     if (config->tls.ocsp.startup) {
544       conn_handler->set_enable_acceptor_on_ocsp_completion(true);
545       conn_handler->disable_acceptor();
546     }
547 
548     conn_handler->proceed_next_cert_ocsp();
549   }
550 
551   if (LOG_ENABLED(INFO)) {
552     LOG(INFO) << "Entering event loop";
553   }
554 
555   ev_run(loop, 0);
556 
557   conn_handler->cancel_ocsp_update();
558 
559   // Destroy SSL_CTX held in conn_handler before killing neverbleed
560   // daemon.  Otherwise priv_rsa_finish yields "write error" and
561   // worker process aborts.
562   conn_handler.reset();
563 
564 #ifdef HAVE_NEVERBLEED
565   assert(nb->daemon_pid > 0);
566 
567   rv = kill(nb->daemon_pid, SIGTERM);
568   if (rv != 0) {
569     auto error = errno;
570     LOG(ERROR) << "Could not send signal to neverbleed daemon: errno=" << error;
571   }
572 
573   while ((rv = waitpid(nb->daemon_pid, nullptr, 0)) == -1 && errno == EINTR)
574     ;
575   if (rv == -1) {
576     auto error = errno;
577     LOG(ERROR) << "Error occurred while we were waiting for the completion "
578                   "of neverbleed process: errno="
579                << error;
580   }
581 #endif // HAVE_NEVERBLEED
582 
583   ares_library_cleanup();
584 
585   return 0;
586 }
587 
588 } // namespace shrpx
589