changeset 316:24def6198d7f NGINX_0_5_28

nginx 0.5.28 *) Security: the "msie_refresh" directive allowed XSS. Thanks to Maxim Boguk. *) Bugfix: a segmentation fault might occur in worker process if the "auth_http_header" directive was used. Thanks to Maxim Dounin. *) Bugfix: a segmentation fault occurred in worker process if the CRAM-MD5 authentication method was used, but it was not enabled. *) Bugfix: a segmentation fault might occur in worker process if the eventport method was used.
author Igor Sysoev <http://sysoev.ru>
date Tue, 17 Jul 2007 00:00:00 +0400
parents 32a7c84208fa
children c012154f05d1
files CHANGES CHANGES.ru src/core/nginx.c src/core/nginx.h src/core/ngx_string.c src/core/ngx_string.h src/event/modules/ngx_eventport_module.c src/http/modules/ngx_http_dav_module.c src/http/modules/perl/nginx.pm src/http/ngx_http_request_body.c src/http/ngx_http_special_response.c src/mail/ngx_mail_auth_http_module.c src/mail/ngx_mail_handler.c
diffstat 13 files changed, 100 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,19 @@
 
+Changes with nginx 0.5.28                                        17 Jun 2007
+
+    *) Security: the "msie_refresh" directive allowed XSS.
+
+    *) Bugfix: a segmentation fault might occur in worker process if the 
+       "auth_http_header" directive was used.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: a segmentation fault occurred in worker process if the 
+       CRAM-MD5 authentication method was used, but it was not enabled.
+
+    *) Bugfix: a segmentation fault might occur in worker process if the 
+       eventport method was used.
+
+
 Changes with nginx 0.5.27                                        09 Jul 2007
 
     *) Bugfix: if remote SSI subrequest was used, then posterior local file 
@@ -215,7 +230,7 @@ Changes with nginx 0.5.13               
        send timeout only.
 
     *) Bugfix: nginx could not be built on platforms different from i386, 
-       amd64, sparc и ppc; bug appeared in 0.5.8.
+       amd64, sparc and ppc; bug appeared in 0.5.8.
 
 
 Changes with nginx 0.5.12                                        12 Feb 2007
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,20 @@
 
+Изменения в nginx 0.5.28                                          17.06.2007
+
+    *) Безопасность: при использовании директивы msie_refresh был возможен 
+       XSS.
+
+    *) Исправление: при использовании директивы auth_http_header в рабочем 
+       процессе мог произойти segmentation fault.
+       Спасибо Максиму Дунину.
+
+    *) Исправление: если использовался метод аутентификации CRAM-MD5, но он 
+       не был разрешён, то в рабочем процессе происходил segmentation fault.
+
+    *) Исправление: в рабочем процессе мог произойти segmentation fault, 
+       если использовался метод eventport.
+
+
 Изменения в nginx 0.5.27                                          09.07.2007
 
     *) Исправление: при использовании удалённого подзапроса в SSI 
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -796,6 +796,7 @@ ngx_core_module_init_conf(ngx_cycle_t *c
 
     if (ccf->user == (uid_t) NGX_CONF_UNSET_UINT && geteuid() == 0) {
 
+        ngx_set_errno(0);
         pwd = getpwnam(NGX_USER);
         if (pwd == NULL) {
             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
@@ -806,6 +807,7 @@ ngx_core_module_init_conf(ngx_cycle_t *c
         ccf->username = NGX_USER;
         ccf->user = pwd->pw_uid;
 
+        ngx_set_errno(0);
         grp = getgrnam(NGX_GROUP);
         if (grp == NULL) {
             ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
@@ -920,6 +922,7 @@ ngx_set_user(ngx_conf_t *cf, ngx_command
 
     ccf->username = (char *) value[1].data;
 
+    ngx_set_errno(0);
     pwd = getpwnam((const char *) value[1].data);
     if (pwd == NULL) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
@@ -931,6 +934,7 @@ ngx_set_user(ngx_conf_t *cf, ngx_command
 
     group = (char *) ((cf->args->nelts == 2) ? value[1].data : value[2].data);
 
+    ngx_set_errno(0);
     grp = getgrnam(group);
     if (grp == NULL) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.5.27"
+#define NGINX_VERSION      "0.5.28"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -1025,7 +1025,7 @@ ngx_escape_uri(u_char *dst, u_char *src,
         0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
 
                     /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
-        0x800000ad, /* 0000 0000 0000 0000  0000 0000 1010 1101 */
+        0x000000ad, /* 0000 0000 0000 0000  0000 0000 1010 1101 */
 
                     /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
         0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */
@@ -1039,18 +1039,30 @@ ngx_escape_uri(u_char *dst, u_char *src,
         0xffffffff  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
     };
 
+                    /* " ", """, "'", %00-%1F, %7F-%FF */
 
-    switch (type) {
-    case NGX_ESCAPE_HTML:
-        escape = html;
-        break;
-    case NGX_ESCAPE_ARGS:
-        escape = args;
-        break;
-    default:
-        escape = uri;
-        break;
-    }
+    static uint32_t   refresh[] = {
+        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+
+                    /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
+        0x00000085, /* 0000 0000 0000 0000  0000 0000 1000 0101 */
+
+                    /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
+        0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */
+
+                    /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
+        0x80000000, /* 1000 0000 0000 0000  0000 0000 0000 0000 */
+
+        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+        0xffffffff  /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+    };
+
+    static uint32_t  *map[] = { uri, args, html, refresh };
+
+
+    escape = map[type];
 
     if (dst == NULL) {
 
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -142,6 +142,7 @@ u_char *ngx_utf_cpystrn(u_char *dst, u_c
 #define NGX_ESCAPE_URI       0
 #define NGX_ESCAPE_ARGS      1
 #define NGX_ESCAPE_HTML      2
+#define NGX_ESCAPE_REFRESH   3
 
 #define NGX_UNESCAPE_URI     1
 
--- a/src/event/modules/ngx_eventport_module.c
+++ b/src/event/modules/ngx_eventport_module.c
@@ -514,6 +514,10 @@ ngx_eventport_process_events(ngx_cycle_t
 
                 } else {
                     rev->handler(rev);
+
+                    if (ev->closed) {
+                        continue;
+                    }
                 }
 
                 if (rev->accept) {
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -239,9 +239,7 @@ ngx_http_dav_put_handler(ngx_http_reques
 
 #if !(NGX_WIN32)
 
-    if (ngx_change_file_access(temp->data, dlcf->access)
-        == NGX_FILE_ERROR)
-    {
+    if (ngx_change_file_access(temp->data, dlcf->access) == NGX_FILE_ERROR) {
         err = ngx_errno;
         not_found = NGX_HTTP_INTERNAL_SERVER_ERROR;
         failed = ngx_change_file_access_n;
--- 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.5.27';
+our $VERSION = '0.5.28';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -88,6 +88,7 @@ ngx_http_read_client_request_body(ngx_ht
         }
 
         post_handler(r);
+
         return NGX_OK;
     }
 
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -315,6 +315,7 @@ ngx_http_special_response_handler(ngx_ht
 {
     u_char                    *p;
     size_t                     msie_refresh;
+    uintptr_t                  escape;
     ngx_int_t                  rc;
     ngx_buf_t                 *b;
     ngx_str_t                 *uri, *location;
@@ -496,17 +497,19 @@ ngx_http_special_response_handler(ngx_ht
         r->headers_out.content_length = NULL;
     }
 
-    msie_refresh = 0;
-    location = NULL;
-
     if (clcf->msie_refresh
         && r->headers_in.msie
         && (error == NGX_HTTP_MOVED_PERMANENTLY
             || error == NGX_HTTP_MOVED_TEMPORARILY))
     {
+
         location = &r->headers_out.location->value;
+
+        escape = 2 * ngx_escape_uri(NULL, location->data, location->len,
+                                    NGX_ESCAPE_REFRESH);
+
         msie_refresh = sizeof(ngx_http_msie_refresh_head) - 1
-                       + location->len
+                       + escape + location->len
                        + sizeof(ngx_http_msie_refresh_tail) - 1;
 
         r->err_status = NGX_HTTP_OK;
@@ -514,6 +517,11 @@ ngx_http_special_response_handler(ngx_ht
         r->headers_out.content_length_n = msie_refresh;
         r->headers_out.location->hash = 0;
         r->headers_out.location = NULL;
+
+    } else {
+        location = NULL;
+        escape = 0;
+        msie_refresh = 0;
     }
 
     ngx_http_clear_accept_ranges(r);
@@ -595,7 +603,13 @@ ngx_http_special_response_handler(ngx_ht
         p = ngx_cpymem(b->pos, ngx_http_msie_refresh_head,
                        sizeof(ngx_http_msie_refresh_head) - 1);
 
-        p = ngx_cpymem(p, location->data, location->len);
+        if (escape == 0) {
+            p = ngx_cpymem(p, location->data, location->len);
+
+        } else {
+            p = (u_char *) ngx_escape_uri(p, location->data, location->len,
+                                          NGX_ESCAPE_REFRESH);
+        }
 
         b->last = ngx_cpymem(p, ngx_http_msie_refresh_tail,
                              sizeof(ngx_http_msie_refresh_tail) - 1);
--- a/src/mail/ngx_mail_auth_http_module.c
+++ b/src/mail/ngx_mail_auth_http_module.c
@@ -1169,6 +1169,7 @@ ngx_mail_auth_http_create_request(ngx_ma
                 + sizeof(CRLF) - 1
           + sizeof("Client-IP: ") - 1 + s->connection->addr_text.len
                 + sizeof(CRLF) - 1
+          + ahcf->header.len
           + sizeof(CRLF) - 1;
 
     b = ngx_create_temp_buf(pool, len);
--- a/src/mail/ngx_mail_handler.c
+++ b/src/mail/ngx_mail_handler.c
@@ -708,7 +708,10 @@ ngx_pop3_auth_state(ngx_event_t *rev)
                                               (u_char *) "CRAM-MD5", 8)
                               == 0)
                 {
-                    if (s->args.nelts != 1) {
+                    if (!(cscf->pop3_auth_methods
+                          & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)
+                        || s->args.nelts != 1)
+                    {
                         rc = NGX_MAIL_PARSE_INVALID_COMMAND;
                         break;
                     }
@@ -1368,7 +1371,13 @@ ngx_smtp_auth_state(ngx_event_t *rev)
                                               (u_char *) "CRAM-MD5", 8)
                               == 0)
                 {
-                    if (s->args.nelts != 1) {
+                    cscf = ngx_mail_get_module_srv_conf(s,
+                                                        ngx_mail_core_module);
+
+                    if (!(cscf->smtp_auth_methods
+                          & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)
+                        || s->args.nelts != 1)
+                    {
                         rc = NGX_MAIL_PARSE_INVALID_COMMAND;
                         break;
                     }