hi, SECURITY FIX for nginx OPENBSD_5_1 branch.
resolves: CVE-2012-2089 - Buffer overflow in the ngx_http_mp4_module CVE-2012-1180 - Memory disclosure with specially crafted backend responses OK ?
Index: Makefile =================================================================== RCS file: /cvs/ports/www/nginx/Makefile,v retrieving revision 1.48 diff -u -p -r1.48 Makefile --- Makefile 18 Jan 2012 10:00:52 -0000 1.48 +++ Makefile 15 Apr 2012 15:20:12 -0000 @@ -2,6 +2,7 @@ COMMENT= robust and small HTTP server and mail proxy server +REVISION= 0 DISTNAME= nginx-1.0.11 CATEGORIES= www Index: patches/patch-src_http_modules_ngx_http_fastcgi_module_c =================================================================== RCS file: patches/patch-src_http_modules_ngx_http_fastcgi_module_c diff -N patches/patch-src_http_modules_ngx_http_fastcgi_module_c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-src_http_modules_ngx_http_fastcgi_module_c 15 Apr 2012 15:20:12 -0000 @@ -0,0 +1,23 @@ +$OpenBSD$ + +SECURITY FIX: +CVE-2012-1180 - Memory disclosure with specially crafted backend responses +patch from upstream: http://nginx.org/download/patch.2012.memory.txt + +--- src/http/modules/ngx_http_fastcgi_module.c.orig Wed Dec 14 13:13:25 2011 ++++ src/http/modules/ngx_http_fastcgi_module.c Sun Apr 15 12:00:09 2012 +@@ -1445,10 +1445,10 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) + h->lowcase_key = h->key.data + h->key.len + 1 + + h->value.len + 1; + +- ngx_cpystrn(h->key.data, r->header_name_start, +- h->key.len + 1); +- ngx_cpystrn(h->value.data, r->header_start, +- h->value.len + 1); ++ ngx_memcpy(h->key.data, r->header_name_start, h->key.len); ++ h->key.data[h->key.len] = '\0'; ++ ngx_memcpy(h->value.data, r->header_start, h->value.len); ++ h->value.data[h->value.len] = '\0'; + } + + h->hash = r->header_hash; Index: patches/patch-src_http_modules_ngx_http_mp4_module_c =================================================================== RCS file: patches/patch-src_http_modules_ngx_http_mp4_module_c diff -N patches/patch-src_http_modules_ngx_http_mp4_module_c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-src_http_modules_ngx_http_mp4_module_c 15 Apr 2012 15:20:14 -0000 @@ -0,0 +1,588 @@ +$OpenBSD$ + +SECURITY FIX: +CVE-2012-2089 - Buffer overflow in the ngx_http_mp4_module +patch from upstream: http://nginx.org/download/patch.2012.mp4.txt + +--- src/http/modules/ngx_http_mp4_module.c.orig Wed Dec 14 16:02:37 2011 ++++ src/http/modules/ngx_http_mp4_module.c Sun Apr 15 12:11:24 2012 +@@ -155,6 +155,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 + + +@@ -203,7 +204,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, +@@ -264,7 +265,7 @@ static ngx_int_t ngx_http_mp4_update_stsc_atom(ngx_htt + 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); +@@ -692,7 +693,9 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) + 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) { +@@ -784,10 +787,8 @@ ngx_http_mp4_read_atom(ngx_http_mp4_file_t *mp4, + + 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; +@@ -804,17 +805,14 @@ ngx_http_mp4_read_atom(ngx_http_mp4_file_t *mp4, + + 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); + +@@ -826,20 +824,26 @@ ngx_http_mp4_read_atom(ngx_http_mp4_file_t *mp4, + } + } + +- 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) { +@@ -866,14 +870,24 @@ ngx_http_mp4_read_atom(ngx_http_mp4_file_t *mp4, + + + 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) { +@@ -881,7 +895,6 @@ ngx_http_mp4_read(ngx_http_mp4_file_t *mp4) + } + + 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, +@@ -891,11 +904,15 @@ ngx_http_mp4_read(ngx_http_mp4_file_t *mp4) + 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; + } +@@ -910,7 +927,9 @@ ngx_http_mp4_read_ftyp_atom(ngx_http_mp4_file_t *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); +@@ -1159,6 +1178,12 @@ ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *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); +@@ -1166,6 +1191,14 @@ ngx_http_mp4_read_mvhd_atom(ngx_http_mp4_file_t *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); + } +@@ -1336,12 +1369,26 @@ ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *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); + } + +@@ -1465,6 +1512,12 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *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); +@@ -1472,6 +1525,14 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *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); + } +@@ -1747,12 +1808,9 @@ ngx_http_mp4_read_stsd_atom(ngx_http_mp4_file_t *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; + } + +@@ -1816,21 +1874,28 @@ ngx_http_mp4_read_stts_atom(ngx_http_mp4_file_t *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); + +- 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) { ++ 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 large", +- mp4->file.name.data); ++ "\"%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); ++ + trak = ngx_mp4_last_trak(mp4); + trak->time_to_sample_entries = entries; + +@@ -1964,6 +2029,12 @@ ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *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, +@@ -1979,14 +2050,16 @@ ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *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; +@@ -2109,6 +2182,12 @@ ngx_http_mp4_read_ctts_atom(ngx_http_mp4_file_t *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, +@@ -2124,14 +2203,16 @@ ngx_http_mp4_read_ctts_atom(ngx_http_mp4_file_t *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; +@@ -2242,21 +2323,28 @@ ngx_http_mp4_read_stsc_atom(ngx_http_mp4_file_t *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); + +- 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) { ++ 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 large", +- mp4->file.name.data); ++ "\"%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); ++ + trak = ngx_mp4_last_trak(mp4); + trak->sample_to_chunk_entries = entries; + +@@ -2308,6 +2396,13 @@ ngx_http_mp4_update_stsc_atom(ngx_http_mp4_file_t *mp4 + 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; + +@@ -2447,6 +2542,12 @@ ngx_http_mp4_read_stsz_atom(ngx_http_mp4_file_t *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); + +@@ -2466,15 +2567,17 @@ ngx_http_mp4_read_stsz_atom(ngx_http_mp4_file_t *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; +@@ -2496,7 +2599,7 @@ ngx_http_mp4_read_stsz_atom(ngx_http_mp4_file_t *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) + { +@@ -2517,6 +2620,13 @@ ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4 + 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; + +@@ -2537,6 +2647,8 @@ ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4 + ngx_mp4_set_32value(stsz_atom->entries, + trak->sample_sizes_entries - trak->start_sample); + } ++ ++ return NGX_OK; + } + + +@@ -2566,19 +2678,27 @@ ngx_http_mp4_read_stco_atom(ngx_http_mp4_file_t *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); + +- 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) { ++ 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 large", mp4->file.name.data); ++ "\"%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); ++ + trak = ngx_mp4_last_trak(mp4); + trak->chunks = entries; + +@@ -2627,6 +2747,13 @@ ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4 + 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; +@@ -2702,19 +2829,27 @@ ngx_http_mp4_read_co64_atom(ngx_http_mp4_file_t *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); + +- 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) { ++ 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 large", mp4->file.name.data); ++ "\"%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); ++ + trak = ngx_mp4_last_trak(mp4); + trak->chunks = entries; + +@@ -2759,6 +2894,13 @@ ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4 + if (data == NULL) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "no mp4 co64 atoms were found in \"%s\"", ++ mp4->file.name.data); ++ 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; + } Index: patches/patch-src_http_modules_ngx_http_proxy_module_c =================================================================== RCS file: patches/patch-src_http_modules_ngx_http_proxy_module_c diff -N patches/patch-src_http_modules_ngx_http_proxy_module_c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-src_http_modules_ngx_http_proxy_module_c 15 Apr 2012 15:20:14 -0000 @@ -0,0 +1,21 @@ +$OpenBSD$ + +SECURITY FIX: +CVE-2012-1180 - Memory disclosure with specially crafted backend responses +patch from upstream: http://nginx.org/download/patch.2012.memory.txt + +--- src/http/modules/ngx_http_proxy_module.c.orig Wed Dec 14 13:13:25 2011 ++++ src/http/modules/ngx_http_proxy_module.c Sun Apr 15 12:00:09 2012 +@@ -1277,8 +1277,10 @@ ngx_http_proxy_process_header(ngx_http_request_t *r) + h->value.data = h->key.data + h->key.len + 1; + h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1; + +- ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1); +- ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1); ++ ngx_memcpy(h->key.data, r->header_name_start, h->key.len); ++ h->key.data[h->key.len] = '\0'; ++ ngx_memcpy(h->value.data, r->header_start, h->value.len); ++ h->value.data[h->value.len] = '\0'; + + if (h->key.len == r->lowcase_index) { + ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len); Index: patches/patch-src_http_modules_ngx_http_scgi_module_c =================================================================== RCS file: patches/patch-src_http_modules_ngx_http_scgi_module_c diff -N patches/patch-src_http_modules_ngx_http_scgi_module_c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-src_http_modules_ngx_http_scgi_module_c 15 Apr 2012 15:20:14 -0000 @@ -0,0 +1,21 @@ +$OpenBSD$ + +SECURITY FIX: +CVE-2012-1180 - Memory disclosure with specially crafted backend responses +patch from upstream: http://nginx.org/download/patch.2012.memory.txt + +--- src/http/modules/ngx_http_scgi_module.c.orig Wed Dec 14 13:28:13 2011 ++++ src/http/modules/ngx_http_scgi_module.c Sun Apr 15 12:00:09 2012 +@@ -898,8 +898,10 @@ ngx_http_scgi_process_header(ngx_http_request_t *r) + h->value.data = h->key.data + h->key.len + 1; + h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1; + +- ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1); +- ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1); ++ ngx_memcpy(h->key.data, r->header_name_start, h->key.len); ++ h->key.data[h->key.len] = '\0'; ++ ngx_memcpy(h->value.data, r->header_start, h->value.len); ++ h->value.data[h->value.len] = '\0'; + + if (h->key.len == r->lowcase_index) { + ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len); Index: patches/patch-src_http_modules_ngx_http_uwsgi_module_c =================================================================== RCS file: patches/patch-src_http_modules_ngx_http_uwsgi_module_c diff -N patches/patch-src_http_modules_ngx_http_uwsgi_module_c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-src_http_modules_ngx_http_uwsgi_module_c 15 Apr 2012 15:20:14 -0000 @@ -0,0 +1,21 @@ +$OpenBSD$ + +SECURITY FIX: +CVE-2012-1180 - Memory disclosure with specially crafted backend responses +patch from upstream: http://nginx.org/download/patch.2012.memory.txt + +--- src/http/modules/ngx_http_uwsgi_module.c.orig Wed Dec 14 13:13:25 2011 ++++ src/http/modules/ngx_http_uwsgi_module.c Sun Apr 15 12:00:09 2012 +@@ -946,8 +946,10 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r) + h->value.data = h->key.data + h->key.len + 1; + h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1; + +- ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1); +- ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1); ++ ngx_memcpy(h->key.data, r->header_name_start, h->key.len); ++ h->key.data[h->key.len] = '\0'; ++ ngx_memcpy(h->value.data, r->header_start, h->value.len); ++ h->value.data[h->value.len] = '\0'; + + if (h->key.len == r->lowcase_index) { + ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len); Index: patches/patch-src_http_ngx_http_parse_c =================================================================== RCS file: patches/patch-src_http_ngx_http_parse_c diff -N patches/patch-src_http_ngx_http_parse_c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-src_http_ngx_http_parse_c 15 Apr 2012 15:20:14 -0000 @@ -0,0 +1,57 @@ +$OpenBSD$ + +SECURITY FIX: +CVE-2012-1180 - Memory disclosure with specially crafted backend responses +patch from upstream: http://nginx.org/download/patch.2012.memory.txt + +--- src/http/ngx_http_parse.c.orig Wed Jun 23 13:34:54 2010 ++++ src/http/ngx_http_parse.c Sun Apr 15 12:00:49 2012 +@@ -813,6 +813,10 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_ + break; + } + ++ if (ch == '\0') { ++ return NGX_HTTP_PARSE_INVALID_HEADER; ++ } ++ + r->invalid_header = 1; + + break; +@@ -875,6 +879,10 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_ + break; + } + ++ if (ch == '\0') { ++ return NGX_HTTP_PARSE_INVALID_HEADER; ++ } ++ + r->invalid_header = 1; + + break; +@@ -893,6 +901,8 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_ + r->header_start = p; + r->header_end = p; + goto done; ++ case '\0': ++ return NGX_HTTP_PARSE_INVALID_HEADER; + default: + r->header_start = p; + state = sw_value; +@@ -914,6 +924,8 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_ + case LF: + r->header_end = p; + goto done; ++ case '\0': ++ return NGX_HTTP_PARSE_INVALID_HEADER; + } + break; + +@@ -927,6 +939,8 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_ + break; + case LF: + goto done; ++ case '\0': ++ return NGX_HTTP_PARSE_INVALID_HEADER; + default: + state = sw_value; + break;
