# HG changeset patch # User Igor Sysoev # Date 1334174400 -14400 # Node ID ad45b044f1e52444ae37750572f0ee59444adf7e # Parent 3f5d0be5ee742ae3b2bce95cc50f5ff27df0e2fa nginx 1.1.19 *) Security: specially crafted mp4 file might allow to overwrite memory locations in a worker process if the ngx_http_mp4_module was used, potentially resulting in arbitrary code execution (CVE-2012-2089). Thanks to Matthew Daley. *) Bugfix: nginx/Windows might be terminated abnormally. Thanks to Vincent Lee. *) Bugfix: nginx hogged CPU if all servers in an upstream were marked as "backup". *) Bugfix: the "allow" and "deny" directives might be inherited incorrectly if they were used with IPv6 addresses. *) Bugfix: the "modern_browser" and "ancient_browser" directives might be inherited incorrectly. *) Bugfix: timeouts might be handled incorrectly on Solaris/SPARC. *) Bugfix: in the ngx_http_mp4_module. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,28 @@ +Changes with nginx 1.1.19 12 Apr 2012 + + *) Security: specially crafted mp4 file might allow to overwrite memory + locations in a worker process if the ngx_http_mp4_module was used, + potentially resulting in arbitrary code execution (CVE-2012-2089). + Thanks to Matthew Daley. + + *) Bugfix: nginx/Windows might be terminated abnormally. + Thanks to Vincent Lee. + + *) Bugfix: nginx hogged CPU if all servers in an upstream were marked as + "backup". + + *) Bugfix: the "allow" and "deny" directives might be inherited + incorrectly if they were used with IPv6 addresses. + + *) Bugfix: the "modern_browser" and "ancient_browser" directives might + be inherited incorrectly. + + *) Bugfix: timeouts might be handled incorrectly on Solaris/SPARC. + + *) Bugfix: in the ngx_http_mp4_module. + + Changes with nginx 1.1.18 28 Mar 2012 *) Change: keepalive connections are no longer disabled for Safari by diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,29 @@ +Изменения в nginx 1.1.19 12.04.2012 + + *) Безопасность: при обработке специально созданного mp4 файла модулем + ngx_http_mp4_module могли перезаписываться области памяти рабочего + процесса, что могло приводить к выполнению произвольного кода + (CVE-2012-2089). + Спасибо Matthew Daley. + + *) Исправление: nginx/Windows мог завершаться аварийно. + Спасибо Vincent Lee. + + *) Исправление: nginx нагружал процессор, если все серверы в upstream'е + были помечены флагом backup. + + *) Исправление: директивы allow и deny могли наследоваться некорректно, + если в них использовались IPv6 адреса. + + *) Исправление: директивы modern_browser и ancient_browser могли + наследоваться некорректно. + + *) Исправление: таймауты могли работать некорректно на Solaris/SPARC. + + *) Исправление: в модуле ngx_http_mp4_module. + + Изменения в nginx 1.1.18 28.03.2012 *) Изменение: теперь keepalive соединения не запрещены для Safari по diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1001018 -#define NGINX_VERSION "1.1.18" +#define nginx_version 1001019 +#define NGINX_VERSION "1.1.19" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -14,7 +14,7 @@ /* - * AAAA number of agruments + * AAAA number of arguments * FF command flags * TT command type, i.e. HTTP "location" or "server" command */ diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -708,7 +708,7 @@ ngx_close_listening_sockets(ngx_cycle_t /* * it seems that Linux-2.6.x OpenVZ sends events * for closed shared listening sockets unless - * the events was explicity deleted + * the events was explicitly deleted */ ngx_del_event(c->read, NGX_READ_EVENT, 0); diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -808,7 +808,7 @@ failed: * reallocated if ctx->alloc is nonzero * * ctx->alloc - a size of data structure that is allocated at every level - * and is initilialized by ctx->init_handler() + * and is initialized by ctx->init_handler() * * ctx->log - a log * diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -44,11 +44,7 @@ ngx_inet_addr(u_char *text, size_t len) return INADDR_NONE; } - if (n != 3) { - return INADDR_NONE; - } - - if (octet < 256) { + if (n == 3 && octet < 256) { addr = (addr << 8) + octet; return htonl(addr); } @@ -407,6 +403,10 @@ ngx_ptocidr(ngx_str_t *text, ngx_cidr_t #if (NGX_HAVE_INET6) case AF_INET6: + if (shift > 128) { + return NGX_ERROR; + } + addr = cidr->u.in6.addr.s6_addr; mask = cidr->u.in6.mask.s6_addr; rc = NGX_OK; @@ -416,7 +416,7 @@ ngx_ptocidr(ngx_str_t *text, ngx_cidr_t s = (shift > 8) ? 8 : shift; shift -= s; - mask[i] = (u_char) (0 - (1 << (8 - s))); + mask[i] = (u_char) (0xffu << (8 - s)); if (addr[i] != (addr[i] & mask[i])) { rc = NGX_DONE; @@ -428,9 +428,12 @@ ngx_ptocidr(ngx_str_t *text, ngx_cidr_t #endif default: /* AF_INET */ + if (shift > 32) { + return NGX_ERROR; + } if (shift) { - cidr->u.in.mask = htonl((ngx_uint_t) (0 - (1 << (32 - shift)))); + cidr->u.in.mask = htonl((uint32_t) (0xffffffffu << (32 - shift))); } else { /* x86 compilers use a shl instruction that shifts by modulo 32 */ @@ -459,7 +462,7 @@ ngx_parse_addr(ngx_pool_t *pool, ngx_add struct sockaddr_in6 *sin6; /* - * prevent MSVC8 waring: + * prevent MSVC8 warning: * potentially uninitialized local variable 'inaddr6' used */ ngx_memzero(inaddr6.s6_addr, sizeof(struct in6_addr)); diff --git a/src/core/ngx_murmurhash.h b/src/core/ngx_murmurhash.h --- a/src/core/ngx_murmurhash.h +++ b/src/core/ngx_murmurhash.h @@ -16,4 +16,4 @@ uint32_t ngx_murmur_hash2(u_char *data, size_t len); -#endif /* _NGX_CRC_H_INCLUDED_ */ +#endif /* _NGX_MURMURHASH_H_INCLUDED_ */ diff --git a/src/core/ngx_rbtree.c b/src/core/ngx_rbtree.c --- a/src/core/ngx_rbtree.c +++ b/src/core/ngx_rbtree.c @@ -136,8 +136,7 @@ ngx_rbtree_insert_timer_value(ngx_rbtree /* node->key < temp->key */ - p = ((ngx_rbtree_key_int_t) node->key - (ngx_rbtree_key_int_t) temp->key - < 0) + p = ((ngx_rbtree_key_int_t) (node->key - temp->key) < 0) ? &temp->left : &temp->right; if (*p == sentinel) { diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -33,7 +33,7 @@ volatile ngx_str_t ngx_cached_http #if !(NGX_WIN32) /* - * locatime() and localtime_r() are not Async-Signal-Safe functions, therefore, + * localtime() and localtime_r() are not Async-Signal-Safe functions, therefore, * they must not be called by a signal handler, so we use the cached * GMT offset value. Fortunately the value is changed only two times a year. */ @@ -308,7 +308,7 @@ ngx_gmtime(time_t t, ngx_tm_t *tp) /* * The "days" should be adjusted to 1 only, however, some March 1st's go * to previous year, so we adjust them to 2. This causes also shift of the - * last Feburary days to next year, but we catch the case when "yday" + * last February days to next year, but we catch the case when "yday" * becomes negative. */ diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c --- a/src/event/modules/ngx_epoll_module.c +++ b/src/event/modules/ngx_epoll_module.c @@ -445,7 +445,7 @@ ngx_epoll_del_event(ngx_event_t *ev, ngx /* * when the file descriptor is closed, the epoll automatically deletes - * it from its queue, so we do not need to delete explicity the event + * it from its queue, so we do not need to delete explicitly the event * before the closing the file descriptor */ @@ -524,7 +524,7 @@ ngx_epoll_del_connection(ngx_connection_ /* * when the file descriptor is closed the epoll automatically deletes - * it from its queue so we do not need to delete explicity the event + * it from its queue so we do not need to delete explicitly the event * before the closing the file descriptor */ diff --git a/src/event/modules/ngx_eventport_module.c b/src/event/modules/ngx_eventport_module.c --- a/src/event/modules/ngx_eventport_module.c +++ b/src/event/modules/ngx_eventport_module.c @@ -322,7 +322,7 @@ ngx_eventport_del_event(ngx_event_t *ev, /* * when the file descriptor is closed, the event port automatically - * dissociates it from the port, so we do not need to dissociate explicity + * dissociates it from the port, so we do not need to dissociate explicitly * the event before the closing the file descriptor */ diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c --- a/src/event/modules/ngx_kqueue_module.c +++ b/src/event/modules/ngx_kqueue_module.c @@ -377,7 +377,7 @@ ngx_kqueue_del_event(ngx_event_t *ev, ng /* * when the file descriptor is closed the kqueue automatically deletes - * its filters so we do not need to delete explicity the event + * its filters so we do not need to delete explicitly the event * before the closing the file descriptor. */ diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -489,7 +489,7 @@ ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_s /* * Elliptic-Curve Diffie-Hellman parameters are either "named curves" - * from RFC 4492 section 5.1.1, or explicitely described curves over + * from RFC 4492 section 5.1.1, or explicitly described curves over * binary fields. OpenSSL only supports the "named curves", which provide * maximum interoperability. */ diff --git a/src/event/ngx_event_timer.c b/src/event/ngx_event_timer.c --- a/src/event/ngx_event_timer.c +++ b/src/event/ngx_event_timer.c @@ -67,7 +67,7 @@ ngx_event_find_timer(void) ngx_mutex_unlock(ngx_event_timer_mutex); - timer = (ngx_msec_int_t) node->key - (ngx_msec_int_t) ngx_current_msec; + timer = (ngx_msec_int_t) (node->key - ngx_current_msec); return (ngx_msec_t) (timer > 0 ? timer : 0); } @@ -95,8 +95,7 @@ ngx_event_expire_timers(void) /* node->key <= ngx_current_time */ - if ((ngx_msec_int_t) node->key - (ngx_msec_int_t) ngx_current_msec <= 0) - { + if ((ngx_msec_int_t) (node->key - ngx_current_msec) <= 0) { ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer)); #if (NGX_THREADS) diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c --- a/src/http/modules/ngx_http_access_module.c +++ b/src/http/modules/ngx_http_access_module.c @@ -351,14 +351,19 @@ ngx_http_access_merge_loc_conf(ngx_conf_ ngx_http_access_loc_conf_t *prev = parent; ngx_http_access_loc_conf_t *conf = child; +#if (NGX_HAVE_INET6) + + if (conf->rules == NULL && conf->rules6 == NULL) { + conf->rules = prev->rules; + conf->rules6 = prev->rules6; + } + +#else + if (conf->rules == NULL) { conf->rules = prev->rules; } -#if (NGX_HAVE_INET6) - if (conf->rules6 == NULL) { - conf->rules6 = prev->rules6; - } #endif return NGX_CONF_OK; diff --git a/src/http/modules/ngx_http_browser_module.c b/src/http/modules/ngx_http_browser_module.c --- a/src/http/modules/ngx_http_browser_module.c +++ b/src/http/modules/ngx_http_browser_module.c @@ -458,10 +458,11 @@ ngx_http_browser_merge_conf(ngx_conf_t * * with a real skip value. The zero value means Opera. */ - if (conf->modern_browsers == NULL) { + if (conf->modern_browsers == NULL && conf->modern_unlisted_browsers == 0) { conf->modern_browsers = prev->modern_browsers; + conf->modern_unlisted_browsers = prev->modern_unlisted_browsers; - } else { + } else if (conf->modern_browsers != NULL) { browsers = conf->modern_browsers->elts; for (i = 0; i < conf->modern_browsers->nelts; i++) { @@ -501,8 +502,9 @@ found: } } - if (conf->ancient_browsers == NULL) { + if (conf->ancient_browsers == NULL && conf->netscape4 == 0) { conf->ancient_browsers = prev->ancient_browsers; + conf->netscape4 = prev->netscape4; } if (conf->modern_browser_value == NULL) { diff --git a/src/http/modules/ngx_http_degradation_module.c b/src/http/modules/ngx_http_degradation_module.c --- a/src/http/modules/ngx_http_degradation_module.c +++ b/src/http/modules/ngx_http_degradation_module.c @@ -126,7 +126,7 @@ ngx_http_degraded(ngx_http_request_t *r) * ELF/i386 is loaded at 0x08000000, 128M * ELF/amd64 is loaded at 0x00400000, 4M * - * use a function address to substract the loading address + * use a function address to subtract the loading address */ sbrk_size = (size_t) sbrk(0) - ((uintptr_t) ngx_palloc & ~0x3FFFFF); diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -156,6 +156,7 @@ typedef struct { #define ngx_mp4_atom_header(mp4) (mp4->buffer_pos - 8) #define ngx_mp4_atom_data(mp4) mp4->buffer_pos +#define ngx_mp4_atom_data_size(t) (uint64_t) (sizeof(t) - 8) #define ngx_mp4_atom_next(mp4, n) mp4->buffer_pos += n; mp4->offset += n @@ -204,7 +205,7 @@ typedef struct { static ngx_int_t ngx_http_mp4_process(ngx_http_mp4_file_t *mp4); static ngx_int_t ngx_http_mp4_read_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_atom_handler_t *atom, uint64_t atom_data_size); -static ngx_int_t ngx_http_mp4_read(ngx_http_mp4_file_t *mp4); +static ngx_int_t ngx_http_mp4_read(ngx_http_mp4_file_t *mp4, size_t size); static ngx_int_t ngx_http_mp4_read_ftyp_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_read_moov_atom(ngx_http_mp4_file_t *mp4, @@ -265,7 +266,7 @@ static ngx_int_t ngx_http_mp4_update_sts ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_read_stsz_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); -static void ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4, +static ngx_int_t ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_read_stco_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); @@ -701,7 +702,9 @@ ngx_http_mp4_process(ngx_http_mp4_file_t return NGX_ERROR; } - ngx_http_mp4_update_stsz_atom(mp4, &trak[i]); + if (ngx_http_mp4_update_stsz_atom(mp4, &trak[i]) != NGX_OK) { + return NGX_ERROR; + } if (trak[i].out[NGX_HTTP_MP4_CO64_DATA].buf) { if (ngx_http_mp4_update_co64_atom(mp4, &trak[i]) != NGX_OK) { @@ -752,7 +755,7 @@ ngx_http_mp4_process(ngx_http_mp4_file_t - start_offset; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, - "mp4 adjustment:%D", adjustment); + "mp4 adjustment:%O", adjustment); for (i = 0; i < mp4->trak.nelts; i++) { if (trak[i].out[NGX_HTTP_MP4_CO64_DATA].buf) { @@ -793,10 +796,8 @@ ngx_http_mp4_read_atom(ngx_http_mp4_file while (mp4->offset < end) { - if (mp4->buffer_pos + sizeof(uint32_t) > mp4->buffer_end) { - if (ngx_http_mp4_read(mp4) != NGX_OK) { - return NGX_ERROR; - } + if (ngx_http_mp4_read(mp4, sizeof(uint32_t)) != NGX_OK) { + return NGX_ERROR; } atom_header = mp4->buffer_pos; @@ -813,17 +814,14 @@ ngx_http_mp4_read_atom(ngx_http_mp4_file if (atom_size == 1) { - if (mp4->buffer_pos + sizeof(ngx_mp4_atom_header64_t) - > mp4->buffer_end) + if (ngx_http_mp4_read(mp4, sizeof(ngx_mp4_atom_header64_t)) + != NGX_OK) { - if (ngx_http_mp4_read(mp4) != NGX_OK) { - return NGX_ERROR; - } - - atom_header = mp4->buffer_pos; + return NGX_ERROR; } /* 64-bit atom size */ + atom_header = mp4->buffer_pos; atom_size = ngx_mp4_get_64value(atom_header + 8); atom_header_size = sizeof(ngx_mp4_atom_header64_t); @@ -835,20 +833,26 @@ ngx_http_mp4_read_atom(ngx_http_mp4_file } } - if (mp4->buffer_pos + sizeof(ngx_mp4_atom_header_t) > mp4->buffer_end) { - if (ngx_http_mp4_read(mp4) != NGX_OK) { - return NGX_ERROR; - } - - atom_header = mp4->buffer_pos; + if (ngx_http_mp4_read(mp4, sizeof(ngx_mp4_atom_header_t)) != NGX_OK) { + return NGX_ERROR; } + atom_header = mp4->buffer_pos; atom_name = atom_header + sizeof(uint32_t); ngx_log_debug4(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 atom: %*s @%O:%uL", 4, atom_name, mp4->offset, atom_size); + if (atom_size > (uint64_t) (NGX_MAX_OFF_T_VALUE - mp4->offset) + || mp4->offset + (off_t) atom_size > end) + { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 atom too large:%uL", + mp4->file.name.data, atom_size); + return NGX_ERROR; + } + for (n = 0; atom[n].name; n++) { if (ngx_strncmp(atom_name, atom[n].name, 4) == 0) { @@ -875,14 +879,24 @@ ngx_http_mp4_read_atom(ngx_http_mp4_file static ngx_int_t -ngx_http_mp4_read(ngx_http_mp4_file_t *mp4) +ngx_http_mp4_read(ngx_http_mp4_file_t *mp4, size_t size) { - ngx_int_t n; + ssize_t n; + + if (mp4->buffer_pos + size <= mp4->buffer_end) { + return NGX_OK; + } if (mp4->offset + (off_t) mp4->buffer_size > mp4->end) { mp4->buffer_size = (size_t) (mp4->end - mp4->offset); } + if (mp4->buffer_size < size) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 file truncated", mp4->file.name.data); + return NGX_ERROR; + } + if (mp4->buffer == NULL) { mp4->buffer = ngx_palloc(mp4->request->pool, mp4->buffer_size); if (mp4->buffer == NULL) { @@ -890,7 +904,6 @@ ngx_http_mp4_read(ngx_http_mp4_file_t *m } mp4->buffer_start = mp4->buffer; - mp4->buffer_end = mp4->buffer + mp4->buffer_size; } n = ngx_read_file(&mp4->file, mp4->buffer_start, mp4->buffer_size, @@ -900,11 +913,15 @@ ngx_http_mp4_read(ngx_http_mp4_file_t *m return NGX_ERROR; } - if (n == 0) { - return NGX_OK; + if ((size_t) n != mp4->buffer_size) { + ngx_log_error(NGX_LOG_CRIT, mp4->file.log, 0, + ngx_read_file_n " read only %z of %z from \"%s\"", + n, mp4->buffer_size, mp4->file.name.data); + return NGX_ERROR; } mp4->buffer_pos = mp4->buffer_start; + mp4->buffer_end = mp4->buffer_start + mp4->buffer_size; return NGX_OK; } @@ -919,7 +936,9 @@ ngx_http_mp4_read_ftyp_atom(ngx_http_mp4 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 ftyp atom"); - if (atom_data_size > 1024) { + if (atom_data_size > 1024 + || ngx_mp4_atom_data(mp4) + atom_data_size > mp4->buffer_end) + { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 ftyp atom is too large:%uL", mp4->file.name.data, atom_data_size); @@ -1168,6 +1187,12 @@ ngx_http_mp4_read_mvhd_atom(ngx_http_mp4 mvhd64_atom = (ngx_mp4_mvhd64_atom_t *) atom_header; ngx_mp4_set_atom_name(atom_header, 'm', 'v', 'h', 'd'); + if (ngx_mp4_atom_data_size(ngx_mp4_mvhd_atom_t) > atom_data_size) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 mvhd atom too small", mp4->file.name.data); + return NGX_ERROR; + } + if (mvhd_atom->version[0] == 0) { /* version 0: 32-bit duration */ timescale = ngx_mp4_get_32value(mvhd_atom->timescale); @@ -1175,6 +1200,14 @@ ngx_http_mp4_read_mvhd_atom(ngx_http_mp4 } else { /* version 1: 64-bit duration */ + + if (ngx_mp4_atom_data_size(ngx_mp4_mvhd64_atom_t) > atom_data_size) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 mvhd atom too small", + mp4->file.name.data); + return NGX_ERROR; + } + timescale = ngx_mp4_get_32value(mvhd64_atom->timescale); duration = ngx_mp4_get_64value(mvhd64_atom->duration); } @@ -1345,12 +1378,26 @@ ngx_http_mp4_read_tkhd_atom(ngx_http_mp4 tkhd64_atom = (ngx_mp4_tkhd64_atom_t *) atom_header; ngx_mp4_set_atom_name(tkhd_atom, 't', 'k', 'h', 'd'); + if (ngx_mp4_atom_data_size(ngx_mp4_tkhd_atom_t) > atom_data_size) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 tkhd atom too small", mp4->file.name.data); + return NGX_ERROR; + } + if (tkhd_atom->version[0] == 0) { /* version 0: 32-bit duration */ duration = ngx_mp4_get_32value(tkhd_atom->duration); } else { /* version 1: 64-bit duration */ + + if (ngx_mp4_atom_data_size(ngx_mp4_tkhd64_atom_t) > atom_data_size) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 tkhd atom too small", + mp4->file.name.data); + return NGX_ERROR; + } + duration = ngx_mp4_get_64value(tkhd64_atom->duration); } @@ -1474,6 +1521,12 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4 mdhd64_atom = (ngx_mp4_mdhd64_atom_t *) atom_header; ngx_mp4_set_atom_name(mdhd_atom, 'm', 'd', 'h', 'd'); + if (ngx_mp4_atom_data_size(ngx_mp4_mdhd_atom_t) > atom_data_size) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 mdhd atom too small", mp4->file.name.data); + return NGX_ERROR; + } + if (mdhd_atom->version[0] == 0) { /* version 0: everything is 32-bit */ timescale = ngx_mp4_get_32value(mdhd_atom->timescale); @@ -1481,6 +1534,14 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4 } else { /* version 1: 64-bit duration and 32-bit timescale */ + + if (ngx_mp4_atom_data_size(ngx_mp4_mdhd64_atom_t) > atom_data_size) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 mdhd atom too small", + mp4->file.name.data); + return NGX_ERROR; + } + timescale = ngx_mp4_get_32value(mdhd64_atom->timescale); duration = ngx_mp4_get_64value(mdhd64_atom->duration); } @@ -1756,12 +1817,9 @@ ngx_http_mp4_read_stsd_atom(ngx_http_mp4 ngx_mp4_set_32value(stsd_atom->size, atom_size); ngx_mp4_set_atom_name(stsd_atom, 's', 't', 's', 'd'); - if ((uint64_t) (sizeof(ngx_mp4_stsd_atom_t) - sizeof(ngx_mp4_atom_header_t)) - > atom_data_size) - { + if (ngx_mp4_atom_data_size(ngx_mp4_stsd_atom_t) > atom_data_size) { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, - "\"%s\" mp4 stsd atom too large", - mp4->file.name.data); + "\"%s\" mp4 stsd atom too small", mp4->file.name.data); return NGX_ERROR; } @@ -1825,21 +1883,28 @@ ngx_http_mp4_read_stts_atom(ngx_http_mp4 stts_atom = (ngx_mp4_stts_atom_t *) atom_header; ngx_mp4_set_atom_name(stts_atom, 's', 't', 't', 's'); + if (ngx_mp4_atom_data_size(ngx_mp4_stts_atom_t) > atom_data_size) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 stts atom too small", mp4->file.name.data); + return NGX_ERROR; + } + entries = ngx_mp4_get_32value(stts_atom->entries); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mp4 time-to-sample entries:%uD", entries); + if (ngx_mp4_atom_data_size(ngx_mp4_stts_atom_t) + + entries * sizeof(ngx_mp4_stts_entry_t) > atom_data_size) + { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 stts atom too small", mp4->file.name.data); + return NGX_ERROR; + } + atom_table = atom_header + sizeof(ngx_mp4_stts_atom_t); atom_end = atom_table + entries * sizeof(ngx_mp4_stts_entry_t); - if ((uint64_t) (atom_end - stts_atom->version) > atom_data_size) { - ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, - "\"%s\" mp4 stts atom too large", - mp4->file.name.data); - return NGX_ERROR; - } - trak = ngx_mp4_last_trak(mp4); trak->time_to_sample_entries = entries; @@ -1910,7 +1975,7 @@ ngx_http_mp4_update_stts_atom(ngx_http_m if (start_time < (uint64_t) count * duration) { start_sample += (ngx_uint_t) (start_time / duration); - count -= start_sample; + count -= (uint32_t) (start_time / duration); ngx_mp4_set_32value(entry->count, count); goto found; } @@ -1973,6 +2038,12 @@ ngx_http_mp4_read_stss_atom(ngx_http_mp4 stss_atom = (ngx_http_mp4_stss_atom_t *) atom_header; ngx_mp4_set_atom_name(stss_atom, 's', 't', 's', 's'); + if (ngx_mp4_atom_data_size(ngx_http_mp4_stss_atom_t) > atom_data_size) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 stss atom too small", mp4->file.name.data); + return NGX_ERROR; + } + entries = ngx_mp4_get_32value(stss_atom->entries); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, @@ -1988,14 +2059,16 @@ ngx_http_mp4_read_stss_atom(ngx_http_mp4 atom->pos = atom_header; atom->last = atom_table; - atom_end = atom_table + entries * sizeof(uint32_t); - - if ((uint64_t) (atom_end - stss_atom->version) > atom_data_size) { + if (ngx_mp4_atom_data_size(ngx_http_mp4_stss_atom_t) + + entries * sizeof(uint32_t) > atom_data_size) + { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, - "\"%s\" mp4 stss atom too large", mp4->file.name.data); + "\"%s\" mp4 stss atom too small", mp4->file.name.data); return NGX_ERROR; } + atom_end = atom_table + entries * sizeof(uint32_t); + data = &trak->stss_data_buf; data->temporary = 1; data->pos = atom_table; @@ -2118,6 +2191,12 @@ ngx_http_mp4_read_ctts_atom(ngx_http_mp4 ctts_atom = (ngx_mp4_ctts_atom_t *) atom_header; ngx_mp4_set_atom_name(ctts_atom, 'c', 't', 't', 's'); + if (ngx_mp4_atom_data_size(ngx_mp4_ctts_atom_t) > atom_data_size) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 ctts atom too small", mp4->file.name.data); + return NGX_ERROR; + } + entries = ngx_mp4_get_32value(ctts_atom->entries); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, @@ -2133,14 +2212,16 @@ ngx_http_mp4_read_ctts_atom(ngx_http_mp4 atom->pos = atom_header; atom->last = atom_table; - atom_end = atom_table + entries * sizeof(ngx_mp4_ctts_entry_t); - - if ((uint64_t) (atom_end - ctts_atom->version) > atom_data_size) { + if (ngx_mp4_atom_data_size(ngx_mp4_ctts_atom_t) + + entries * sizeof(ngx_mp4_ctts_entry_t) > atom_data_size) + { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, - "\"%s\" mp4 ctts atom too large", mp4->file.name.data); + "\"%s\" mp4 ctts atom too small", mp4->file.name.data); return NGX_ERROR; } + atom_end = atom_table + entries * sizeof(ngx_mp4_ctts_entry_t); + data = &trak->ctts_data_buf; data->temporary = 1; data->pos = atom_table; @@ -2251,21 +2332,28 @@ ngx_http_mp4_read_stsc_atom(ngx_http_mp4 stsc_atom = (ngx_mp4_stsc_atom_t *) atom_header; ngx_mp4_set_atom_name(stsc_atom, 's', 't', 's', 'c'); + if (ngx_mp4_atom_data_size(ngx_mp4_stsc_atom_t) > atom_data_size) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 stsc atom too small", mp4->file.name.data); + return NGX_ERROR; + } + entries = ngx_mp4_get_32value(stsc_atom->entries); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "sample-to-chunk entries:%uD", entries); + if (ngx_mp4_atom_data_size(ngx_mp4_stsc_atom_t) + + entries * sizeof(ngx_mp4_stsc_entry_t) > atom_data_size) + { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 stsc atom too small", mp4->file.name.data); + return NGX_ERROR; + } + atom_table = atom_header + sizeof(ngx_mp4_stsc_atom_t); atom_end = atom_table + entries * sizeof(ngx_mp4_stsc_entry_t); - if ((uint64_t) (atom_end - stsc_atom->version) > atom_data_size) { - ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, - "\"%s\" mp4 stsc atom too large", - mp4->file.name.data); - return NGX_ERROR; - } - trak = ngx_mp4_last_trak(mp4); trak->sample_to_chunk_entries = entries; @@ -2317,6 +2405,13 @@ ngx_http_mp4_update_stsc_atom(ngx_http_m return NGX_ERROR; } + if (trak->sample_to_chunk_entries == 0) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "zero number of entries in stsc atom in \"%s\"", + mp4->file.name.data); + return NGX_ERROR; + } + start_sample = (uint32_t) trak->start_sample; entries = trak->sample_to_chunk_entries - 1; @@ -2458,6 +2553,12 @@ ngx_http_mp4_read_stsz_atom(ngx_http_mp4 stsz_atom = (ngx_mp4_stsz_atom_t *) atom_header; ngx_mp4_set_atom_name(stsz_atom, 's', 't', 's', 'z'); + if (ngx_mp4_atom_data_size(ngx_mp4_stsz_atom_t) > atom_data_size) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 stsz atom too small", mp4->file.name.data); + return NGX_ERROR; + } + size = ngx_mp4_get_32value(stsz_atom->uniform_size); entries = ngx_mp4_get_32value(stsz_atom->entries); @@ -2477,15 +2578,17 @@ ngx_http_mp4_read_stsz_atom(ngx_http_mp4 trak->out[NGX_HTTP_MP4_STSZ_ATOM].buf = atom; if (size == 0) { - atom_end = atom_table + entries * sizeof(uint32_t); - - if ((uint64_t) (atom_end - stsz_atom->version) > atom_data_size) { + if (ngx_mp4_atom_data_size(ngx_mp4_stsz_atom_t) + + entries * sizeof(uint32_t) > atom_data_size) + { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, - "\"%s\" mp4 stsz atom too large", + "\"%s\" mp4 stsz atom too small", mp4->file.name.data); return NGX_ERROR; } + atom_end = atom_table + entries * sizeof(uint32_t); + data = &trak->stsz_data_buf; data->temporary = 1; data->pos = atom_table; @@ -2507,7 +2610,7 @@ ngx_http_mp4_read_stsz_atom(ngx_http_mp4 } -static void +static ngx_int_t ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak) { @@ -2528,6 +2631,13 @@ ngx_http_mp4_update_stsz_atom(ngx_http_m data = trak->out[NGX_HTTP_MP4_STSZ_DATA].buf; if (data) { + if (trak->start_sample > trak->sample_sizes_entries) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "start time is out mp4 stsz samples in \"%s\"", + mp4->file.name.data); + return NGX_ERROR; + } + data->pos += trak->start_sample * sizeof(uint32_t); end = (uint32_t *) data->pos; @@ -2548,6 +2658,8 @@ ngx_http_mp4_update_stsz_atom(ngx_http_m ngx_mp4_set_32value(stsz_atom->entries, trak->sample_sizes_entries - trak->start_sample); } + + return NGX_OK; } @@ -2577,19 +2689,27 @@ ngx_http_mp4_read_stco_atom(ngx_http_mp4 stco_atom = (ngx_mp4_stco_atom_t *) atom_header; ngx_mp4_set_atom_name(stco_atom, 's', 't', 'c', 'o'); + if (ngx_mp4_atom_data_size(ngx_mp4_stco_atom_t) > atom_data_size) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 stco atom too small", mp4->file.name.data); + return NGX_ERROR; + } + entries = ngx_mp4_get_32value(stco_atom->entries); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "chunks:%uD", entries); + if (ngx_mp4_atom_data_size(ngx_mp4_stco_atom_t) + + entries * sizeof(uint32_t) > atom_data_size) + { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 stco atom too small", mp4->file.name.data); + return NGX_ERROR; + } + atom_table = atom_header + sizeof(ngx_mp4_stco_atom_t); atom_end = atom_table + entries * sizeof(uint32_t); - if ((uint64_t) (atom_end - stco_atom->version) > atom_data_size) { - ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, - "\"%s\" mp4 stco atom too large", mp4->file.name.data); - return NGX_ERROR; - } - trak = ngx_mp4_last_trak(mp4); trak->chunks = entries; @@ -2638,6 +2758,13 @@ ngx_http_mp4_update_stco_atom(ngx_http_m return NGX_ERROR; } + if (trak->start_chunk > trak->chunks) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "start time is out mp4 stco chunks in \"%s\"", + mp4->file.name.data); + return NGX_ERROR; + } + data->pos += trak->start_chunk * sizeof(uint32_t); atom_size = sizeof(ngx_mp4_stco_atom_t) + (data->last - data->pos); trak->size += atom_size; @@ -2713,19 +2840,27 @@ ngx_http_mp4_read_co64_atom(ngx_http_mp4 co64_atom = (ngx_mp4_co64_atom_t *) atom_header; ngx_mp4_set_atom_name(co64_atom, 'c', 'o', '6', '4'); + if (ngx_mp4_atom_data_size(ngx_mp4_co64_atom_t) > atom_data_size) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 co64 atom too small", mp4->file.name.data); + return NGX_ERROR; + } + entries = ngx_mp4_get_32value(co64_atom->entries); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "chunks:%uD", entries); + if (ngx_mp4_atom_data_size(ngx_mp4_co64_atom_t) + + entries * sizeof(uint64_t) > atom_data_size) + { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 co64 atom too small", mp4->file.name.data); + return NGX_ERROR; + } + atom_table = atom_header + sizeof(ngx_mp4_co64_atom_t); atom_end = atom_table + entries * sizeof(uint64_t); - if ((uint64_t) (atom_end - co64_atom->version) > atom_data_size) { - ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, - "\"%s\" mp4 co64 atom too large", mp4->file.name.data); - return NGX_ERROR; - } - trak = ngx_mp4_last_trak(mp4); trak->chunks = entries; @@ -2774,6 +2909,13 @@ ngx_http_mp4_update_co64_atom(ngx_http_m return NGX_ERROR; } + if (trak->start_chunk > trak->chunks) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "start time is out mp4 co64 chunks in \"%s\"", + mp4->file.name.data); + return NGX_ERROR; + } + data->pos += trak->start_chunk * sizeof(uint64_t); atom_size = sizeof(ngx_mp4_co64_atom_t) + (data->last - data->pos); trak->size += atom_size; diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -714,7 +714,7 @@ ngx_http_ssi_body_filter(ngx_http_reques if (ctx->params.nelts > NGX_HTTP_SSI_MAX_PARAMS) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "too many SSI command paramters: \"%V\"", + "too many SSI command parameters: \"%V\"", &ctx->command); goto ssi_error; } diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -50,7 +50,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '1.1.18'; +our $VERSION = '1.1.19'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1417,7 +1417,7 @@ ngx_http_optimize_servers(ngx_conf_t *cf /* * check whether all name-based servers have the same - * configuraiton as a default server for given address:port + * configuration as a default server for given address:port */ addr = port[p].addrs.elts; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -1228,20 +1228,29 @@ ngx_http_core_try_files_phase(ngx_http_r len = tf->name.len; } - /* 16 bytes are preallocation */ - reserve = ngx_abs((ssize_t) (len - r->uri.len)) + alias + 16; + if (!alias) { + reserve = len > r->uri.len ? len - r->uri.len : 0; + +#if (NGX_PCRE) + } else if (clcf->regex) { + reserve = len; +#endif + + } else { + reserve = len > r->uri.len - alias ? len - (r->uri.len - alias) : 0; + } if (reserve > allocated) { - /* we just need to allocate path and to copy a root */ - - if (ngx_http_map_uri_to_path(r, &path, &root, reserve) == NULL) { + /* 16 bytes are preallocation */ + allocated = reserve + 16; + + if (ngx_http_map_uri_to_path(r, &path, &root, allocated) == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_OK; } name = path.data + root; - allocated = path.len - root - (r->uri.len - alias); } if (tf->values == NULL) { diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -1097,7 +1097,7 @@ ngx_http_parse_complex_uri(ngx_http_requ /* * we use "ch = *p++" inside the cycle, but this operation is safe, - * because after the URI there is always at least one charcter: + * because after the URI there is always at least one character: * the line feed */ diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -1196,7 +1196,7 @@ ngx_http_upstream_connect(ngx_http_reque { /* * the r->request_body->buf can be reused for one request only, - * the subrequests should allocate their own temporay bufs + * the subrequests should allocate their own temporary bufs */ u->output.free = ngx_alloc_chain_link(r->pool); diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -49,6 +49,13 @@ ngx_http_upstream_init_round_robin(ngx_c n += server[i].naddrs; } + if (n == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no servers in upstream \"%V\" in %s:%ui", + &us->host, us->file_name, us->line); + return NGX_ERROR; + } + peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t) + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1)); if (peers == NULL) { diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -112,7 +112,7 @@ static ngx_int_t ngx_http_variable_pid(n /* * the $http_host, $http_user_agent, $http_referer, $http_via, * and $http_x_forwarded_for variables may be handled by generic - * ngx_http_variable_unknown_header_in(), but for perfomance reasons + * ngx_http_variable_unknown_header_in(), but for performance reasons * they are handled using dedicated entries */ diff --git a/src/os/unix/ngx_daemon.c b/src/os/unix/ngx_daemon.c --- a/src/os/unix/ngx_daemon.c +++ b/src/os/unix/ngx_daemon.c @@ -9,7 +9,8 @@ #include -ngx_int_t ngx_daemon(ngx_log_t *log) +ngx_int_t +ngx_daemon(ngx_log_t *log) { int fd; diff --git a/src/os/unix/ngx_freebsd_rfork_thread.c b/src/os/unix/ngx_freebsd_rfork_thread.c --- a/src/os/unix/ngx_freebsd_rfork_thread.c +++ b/src/os/unix/ngx_freebsd_rfork_thread.c @@ -11,14 +11,14 @@ /* * The threads implementation uses the rfork(RFPROC|RFTHREAD|RFMEM) syscall * to create threads. All threads use the stacks of the same size mmap()ed - * below the main stack. Thus the current thread id is determinated via + * below the main stack. Thus the current thread id is determined via * the stack pointer value. * * The mutex implementation uses the ngx_atomic_cmp_set() operation * to acquire a mutex and the SysV semaphore to wait on a mutex and to wake up * the waiting threads. The light mutex does not use semaphore, so after * spinning in the lock the thread calls sched_yield(). However the light - * mutecies are intended to be used with the "trylock" operation only. + * mutexes are intended to be used with the "trylock" operation only. * The SysV semop() is a cheap syscall, particularly if it has little sembuf's * and does not use SEM_UNDO. * diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -18,7 +18,7 @@ * as the 11 full 1460-bytes packets, then one incomplete 324-bytes packet, * and then again the 11 full 1460-bytes packets. * - * Threfore we use the TCP_NOPUSH option (similar to Linux's TCP_CORK) + * Therefore we use the TCP_NOPUSH option (similar to Linux's TCP_CORK) * to postpone the sending - it not only sends a header and the first part of * the file in one packet, but also sends the file pages in the full packets. * diff --git a/src/os/unix/ngx_gcc_atomic_sparc64.h b/src/os/unix/ngx_gcc_atomic_sparc64.h --- a/src/os/unix/ngx_gcc_atomic_sparc64.h +++ b/src/os/unix/ngx_gcc_atomic_sparc64.h @@ -15,7 +15,7 @@ * r0 = [r1]; * } * - * so "r0 == r2" means that the operation was successfull. + * so "r0 == r2" means that the operation was successful. * * * The "r" means the general register. diff --git a/src/os/unix/ngx_setproctitle.c b/src/os/unix/ngx_setproctitle.c --- a/src/os/unix/ngx_setproctitle.c +++ b/src/os/unix/ngx_setproctitle.c @@ -21,7 +21,7 @@ * from argv[0] for our process title. * * The Solaris's standard /bin/ps does not show the changed process title. - * You have to use "/usr/ucb/ps -w" instead. Besides, the UCB ps dos not + * You have to use "/usr/ucb/ps -w" instead. Besides, the UCB ps does not * show a new title if its length less than the origin command line length. * To avoid it we append to a new title the origin command line in the * parenthesis.