changeset 554:2b9e388c61f1 NGINX_0_8_23

nginx 0.8.23 *) Security: now SSL/TLS renegotiation is disabled. Thanks to Maxim Dounin. *) Bugfix: listen unix domain socket did not inherit while online upgrade. *) Bugfix: the "unix:" parameter of the "set_real_ip_from" directive did not without yet another directive with any IP address. *) Bugfix: segmentation fault and infinite looping in resolver. *) Bugfix: in resolver. Thanks to Artem Bokhan.
author Igor Sysoev <http://sysoev.ru>
date Wed, 11 Nov 2009 00:00:00 +0300
parents 8da5668048b4
children 48b3f4b6bc38
files CHANGES CHANGES.ru src/core/nginx.h src/core/ngx_conf_file.c src/core/ngx_connection.c src/core/ngx_resolver.c src/event/ngx_event_openssl.c src/event/ngx_event_openssl.h src/http/modules/ngx_http_realip_module.c src/http/modules/perl/nginx.pm src/http/ngx_http_copy_filter_module.c src/http/ngx_http_file_cache.c src/mail/ngx_mail_smtp_handler.c src/os/unix/ngx_file_aio_read.c src/os/unix/ngx_files.c src/os/unix/ngx_files.h src/os/unix/ngx_linux_aio_read.c src/os/unix/ngx_posix_init.c src/os/unix/ngx_process_cycle.c
diffstat 19 files changed, 180 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,21 @@
 
+Changes with nginx 0.8.23                                        11 Nov 2009
+
+    *) Security: now SSL/TLS renegotiation is disabled.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: listen unix domain socket did not inherit while online 
+       upgrade.
+
+    *) Bugfix: the "unix:" parameter of the "set_real_ip_from" directive 
+       did not without yet another directive with any IP address.
+
+    *) Bugfix: segmentation fault and infinite looping in resolver.
+
+    *) Bugfix: in resolver.
+       Thanks to Artem Bokhan.
+
+
 Changes with nginx 0.8.22                                        03 Nov 2009
 
     *) Feature: the "proxy_bind", "fastcgi_bind", and "memcached_bind" 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,21 @@
 
+Изменения в nginx 0.8.23                                          11.11.2009
+
+    *) Безопасность: теперь SSL/TLS renegotiation запрещено.
+       Спасибо Максиму Дунину.
+
+    *) Исправление: listen unix domain сокет не наследовались во время 
+       обновления без перерыва.
+
+    *) Исправление: параметр "unix:" в директиве set_real_ip_from не 
+       работал без ещё одной директивы с любым IP-адресом.
+
+    *) Исправление: segmentation fault и зацикливания в resolver'е.
+
+    *) Исправление: в resolver'е.
+       Спасибо Артёму Бохану.
+
+
 Изменения в nginx 0.8.22                                          03.11.2009
 
     *) Добавление: директивы proxy_bind, fastcgi_bind и memcached_bind.
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version         8022
-#define NGINX_VERSION      "0.8.22"
+#define nginx_version         8023
+#define NGINX_VERSION      "0.8.23"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -261,7 +261,7 @@ done:
         if (ngx_close_file(fd) == NGX_FILE_ERROR) {
             ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
                           ngx_close_file_n " %s failed",
-                          cf->conf_file->file.name.data);
+                          filename->data);
             return NGX_CONF_ERROR;
         }
 
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -117,11 +117,20 @@ ngx_set_inherited_sockets(ngx_cycle_t *c
 #if (NGX_HAVE_INET6)
         case AF_INET6:
              ls[i].addr_text_max_len = NGX_INET6_ADDRSTRLEN;
+             len = NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1;
+             break;
+#endif
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+        case AF_UNIX:
+             ls[i].addr_text_max_len = NGX_UNIX_ADDRSTRLEN;
+             len = NGX_UNIX_ADDRSTRLEN;
              break;
 #endif
 
         case AF_INET:
              ls[i].addr_text_max_len = NGX_INET_ADDRSTRLEN;
+             len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
              break;
 
         default:
@@ -132,8 +141,6 @@ ngx_set_inherited_sockets(ngx_cycle_t *c
             continue;
         }
 
-        len = ls[i].addr_text_max_len + sizeof(":65535") - 1;
-
         ls[i].addr_text.data = ngx_pnalloc(cycle->pool, len);
         if (ls[i].addr_text.data == NULL) {
             return NGX_ERROR;
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -464,6 +464,7 @@ ngx_resolve_name_locked(ngx_resolver_t *
 
             ctx->next = rn->waiting;
             rn->waiting = ctx;
+            ctx->state = NGX_AGAIN;
 
             return NGX_AGAIN;
         }
@@ -625,6 +626,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx
 
             ctx->next = rn->waiting;
             rn->waiting = ctx;
+            ctx->state = NGX_AGAIN;
 
             /* unlock addr mutex */
 
@@ -1752,7 +1754,8 @@ ngx_resolver_create_name_query(ngx_resol
     query->nns_hi = 0; query->nns_lo = 0;
     query->nar_hi = 0; query->nar_lo = 0;
 
-    p += sizeof(ngx_resolver_query_t) + 1 + ctx->name.len + 1;
+    p += sizeof(ngx_resolver_query_t)
+         + ctx->name.len ? (1 + ctx->name.len + 1) : 1;
 
     qs = (ngx_resolver_qs_t *) p;
 
@@ -1900,6 +1903,12 @@ done:
         return NGX_OK;
     }
 
+    if (len == -1) {
+        name->len = 0;
+        name->data = NULL;
+        return NGX_OK;
+    }
+
     dst = ngx_resolver_alloc(r, len);
     if (dst == NULL) {
         return NGX_ERROR;
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -15,6 +15,8 @@ typedef struct {
 
 
 static int ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store);
+static void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where,
+    int ret);
 static void ngx_ssl_handshake_handler(ngx_event_t *ev);
 static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n);
 static void ngx_ssl_write_handler(ngx_event_t *wev);
@@ -175,6 +177,8 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_
 
     SSL_CTX_set_read_ahead(ssl->ctx, 1);
 
+    SSL_CTX_set_info_callback(ssl->ctx, ngx_ssl_info_callback);
+
     return NGX_OK;
 }
 
@@ -350,6 +354,22 @@ ngx_http_ssl_verify_callback(int ok, X50
 }
 
 
+static void
+ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret)
+{
+    ngx_connection_t  *c;
+
+    if (where & SSL_CB_HANDSHAKE_START) {
+        c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
+
+        if (c->ssl->handshaked) {
+            c->ssl->renegotiation = 1;
+            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL renegotiation");
+        }
+    }
+}
+
+
 ngx_int_t
 ngx_ssl_generate_rsa512_key(ngx_ssl_t *ssl)
 {
@@ -587,6 +607,11 @@ ngx_ssl_handshake(ngx_connection_t *c)
         c->recv_chain = ngx_ssl_recv_chain;
         c->send_chain = ngx_ssl_send_chain;
 
+        /* initial handshake done, disable renegotiation (CVE-2009-3555) */
+        if (c->ssl->connection->s3) {
+            c->ssl->connection->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
+        }
+
         return NGX_OK;
     }
 
@@ -789,6 +814,21 @@ ngx_ssl_handle_recv(ngx_connection_t *c,
     int        sslerr;
     ngx_err_t  err;
 
+    if (c->ssl->renegotiation) {
+        /*
+         * disable renegotiation (CVE-2009-3555):
+         * OpenSSL (at least up to 0.9.8l) does not handle disabled
+         * renegotiation gracefully, so drop connection here
+         */
+
+        ngx_log_error(NGX_LOG_NOTICE, c->log, 0, "SSL renegotiation disabled");
+
+        c->ssl->no_wait_shutdown = 1;
+        c->ssl->no_send_shutdown = 1;
+
+        return NGX_ERROR;
+    }
+
     if (n > 0) {
 
         if (c->ssl->saved_write_handler) {
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -41,6 +41,7 @@ typedef struct {
     ngx_event_handler_pt        saved_write_handler;
 
     unsigned                    handshaked:1;
+    unsigned                    renegotiation:1;
     unsigned                    buffer:1;
     unsigned                    no_wait_shutdown:1;
     unsigned                    no_send_shutdown:1;
--- a/src/http/modules/ngx_http_realip_module.c
+++ b/src/http/modules/ngx_http_realip_module.c
@@ -126,7 +126,12 @@ ngx_http_realip_handler(ngx_http_request
 
     rlcf = ngx_http_get_module_loc_conf(r, ngx_http_realip_module);
 
-    if (rlcf->from == NULL) {
+    if (rlcf->from == NULL
+#if (NGX_HAVE_UNIX_DOMAIN)
+        && !rlcf->unixsock
+#endif
+       )
+    {
         return NGX_DECLINED;
     }
 
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -47,7 +47,7 @@ our @EXPORT = qw(
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '0.8.22';
+our $VERSION = '0.8.23';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http_copy_filter_module.c
+++ b/src/http/ngx_http_copy_filter_module.c
@@ -118,7 +118,7 @@ ngx_http_copy_filter(ngx_http_request_t 
         ctx->filter_ctx = r;
 
 #if (NGX_HAVE_FILE_AIO)
-        if (clcf->aio) {
+        if (ngx_file_aio && clcf->aio) {
             ctx->aio_handler = ngx_http_copy_aio_handler;
 #if (NGX_HAVE_AIO_SENDFILE)
             c->aio_sendfile = (clcf->aio == NGX_HTTP_AIO_SENDFILE);
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -12,6 +12,8 @@
 
 static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r,
     ngx_http_cache_t *c);
+static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r,
+    ngx_http_cache_t *c);
 #if (NGX_HAVE_FILE_AIO)
 static void ngx_http_cache_aio_event_handler(ngx_event_t *ev);
 #endif
@@ -330,36 +332,9 @@ ngx_http_file_cache_read(ngx_http_reques
 
     c = r->cache;
 
-#if (NGX_HAVE_FILE_AIO)
-    {
-    ngx_http_core_loc_conf_t      *clcf;
-
-    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
-    if (clcf->aio) {
-        n = ngx_file_aio_read(&c->file, c->buf->pos, c->body_start, 0, r->pool);
-
-        if (n == NGX_AGAIN) {
-            c->file.aio->data = r;
-            c->file.aio->handler = ngx_http_cache_aio_event_handler;
+    n = ngx_http_file_cache_aio_read(r, c);
 
-            r->main->blocked++;
-            r->aio = 1;
-
-            return NGX_AGAIN;
-        }
-
-    } else {
-        n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
-    }
-    }
-#else
-
-    n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
-
-#endif
-
-    if (n == NGX_ERROR) {
+    if (n < 0) {
         return n;
     }
 
@@ -432,8 +407,46 @@ ngx_http_file_cache_read(ngx_http_reques
 }
 
 
+static ssize_t
+ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c)
+{
 #if (NGX_HAVE_FILE_AIO)
+    ssize_t                    n;
+    ngx_http_core_loc_conf_t  *clcf;
 
+    if (!ngx_file_aio) {
+        goto noaio;
+    }
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    if (!clcf->aio) {
+        goto noaio;
+    }
+
+    n = ngx_file_aio_read(&c->file, c->buf->pos, c->body_start, 0, r->pool);
+
+    if (n != NGX_AGAIN) {
+        return n;
+    }
+
+    c->file.aio->data = r;
+    c->file.aio->handler = ngx_http_cache_aio_event_handler;
+
+    r->main->blocked++;
+    r->aio = 1;
+
+    return NGX_AGAIN;
+
+noaio:
+
+#endif
+
+    return ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
+}
+
+
+#if (NGX_HAVE_FILE_AIO)
 
 static void
 ngx_http_cache_aio_event_handler(ngx_event_t *ev)
--- a/src/mail/ngx_mail_smtp_handler.c
+++ b/src/mail/ngx_mail_smtp_handler.c
@@ -191,7 +191,7 @@ ngx_mail_smtp_resolve_name_handler(ngx_r
 
     if (ctx->state) {
         ngx_log_error(NGX_LOG_ERR, c->log, 0,
-                      "%V could not be resolved (%i: %s)",
+                      "\"%V\" could not be resolved (%i: %s)",
                       &ctx->name, ctx->state,
                       ngx_resolver_strerror(ctx->state));
 
--- a/src/os/unix/ngx_file_aio_read.c
+++ b/src/os/unix/ngx_file_aio_read.c
@@ -39,12 +39,11 @@ ssize_t
 ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
     ngx_pool_t *pool)
 {
-    int                 n;
-    ngx_event_t        *ev;
-    ngx_event_aio_t    *aio;
-    static ngx_uint_t   enosys = 0;
+    int               n;
+    ngx_event_t      *ev;
+    ngx_event_aio_t  *aio;
 
-    if (enosys) {
+    if (!ngx_file_aio) {
         return ngx_read_file(file, buf, size, offset);
     }
 
@@ -116,7 +115,7 @@ ngx_file_aio_read(ngx_file_t *file, u_ch
                       "aio_read(\"%V\") failed", &file->name);
 
         if (n == NGX_ENOSYS) {
-            enosys = 1;
+            ngx_file_aio = 0;
             return ngx_read_file(file, buf, size, offset);
         }
 
--- a/src/os/unix/ngx_files.c
+++ b/src/os/unix/ngx_files.c
@@ -8,6 +8,13 @@
 #include <ngx_core.h>
 
 
+#if (NGX_HAVE_FILE_AIO)
+
+ngx_uint_t  ngx_file_aio = 1;
+
+#endif
+
+
 ssize_t
 ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
 {
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -313,6 +313,8 @@ size_t ngx_fs_bsize(u_char *name);
 ssize_t ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size,
     off_t offset, ngx_pool_t *pool);
 
+extern ngx_uint_t  ngx_file_aio;
+
 #endif
 
 
--- a/src/os/unix/ngx_linux_aio_read.c
+++ b/src/os/unix/ngx_linux_aio_read.c
@@ -27,13 +27,12 @@ ssize_t
 ngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset,
     ngx_pool_t *pool)
 {
-    long                n;
-    struct iocb        *piocb[1];
-    ngx_event_t        *ev;
-    ngx_event_aio_t    *aio;
-    static ngx_uint_t   enosys = 0;
+    long              n;
+    struct iocb      *piocb[1];
+    ngx_event_t      *ev;
+    ngx_event_aio_t  *aio;
 
-    if (enosys) {
+    if (!ngx_file_aio) {
         return ngx_read_file(file, buf, size, offset);
     }
 
@@ -109,7 +108,7 @@ ngx_file_aio_read(ngx_file_t *file, u_ch
                   "io_submit(\"%V\") failed", &file->name);
 
     if (n == NGX_ENOSYS) {
-        enosys = 1;
+        ngx_file_aio = 0;
         return ngx_read_file(file, buf, size, offset);
     }
 
--- a/src/os/unix/ngx_posix_init.c
+++ b/src/os/unix/ngx_posix_init.c
@@ -44,8 +44,6 @@ ngx_os_init(ngx_log_t *log)
     ngx_pagesize = getpagesize();
     ngx_cacheline_size = NGX_CPU_CACHE_LINE;
 
-    n = ngx_pagesize;
-
     for (n = ngx_pagesize; n >>= 1; ngx_pagesize_shift++) { /* void */ }
 
     if (ngx_ncpu == 0) {
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -86,7 +86,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy
     u_char            *p;
     size_t             size;
     ngx_int_t          i;
-    ngx_uint_t         n;
+    ngx_uint_t         n, sigio;
     sigset_t           set;
     struct itimerval   itv;
     ngx_uint_t         live;
@@ -139,11 +139,13 @@ ngx_master_process_cycle(ngx_cycle_t *cy
 
     ngx_new_binary = 0;
     delay = 0;
+    sigio = 0;
     live = 1;
 
     for ( ;; ) {
         if (delay) {
             if (ngx_sigalrm) {
+                sigio = 0;
                 delay *= 2;
                 ngx_sigalrm = 0;
             }
@@ -168,7 +170,8 @@ ngx_master_process_cycle(ngx_cycle_t *cy
 
         ngx_time_update(0, 0);
 
-        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up");
+        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+                       "wake up, sigio %i", sigio);
 
         if (ngx_reap) {
             ngx_reap = 0;
@@ -186,6 +189,13 @@ ngx_master_process_cycle(ngx_cycle_t *cy
                 delay = 50;
             }
 
+            if (sigio) {
+                sigio--;
+                continue;
+            }
+
+            sigio = ccf->worker_processes + 2 /* cache processes */;
+
             if (delay > 1000) {
                 ngx_signal_worker_processes(cycle, SIGKILL);
             } else {