comparison src/core/ngx_parse.c @ 6011:429a8c65f0a7

Core: overflow detection in ngx_parse_time() (ticket #732).
author Ruslan Ermilov <ru@nginx.com>
date Tue, 17 Mar 2015 00:26:20 +0300
parents 040e2736e8dc
children 4ccb37b04454
comparison
equal deleted inserted replaced
6010:040e2736e8dc 6011:429a8c65f0a7
101 ngx_int_t 101 ngx_int_t
102 ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec) 102 ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
103 { 103 {
104 u_char *p, *last; 104 u_char *p, *last;
105 ngx_int_t value, total, scale; 105 ngx_int_t value, total, scale;
106 ngx_uint_t max, valid; 106 ngx_int_t max, cutoff, cutlim;
107 ngx_uint_t valid;
107 enum { 108 enum {
108 st_start = 0, 109 st_start = 0,
109 st_year, 110 st_year,
110 st_month, 111 st_month,
111 st_week, 112 st_week,
118 } step; 119 } step;
119 120
120 valid = 0; 121 valid = 0;
121 value = 0; 122 value = 0;
122 total = 0; 123 total = 0;
124 cutoff = NGX_MAX_INT_T_VALUE / 10;
125 cutlim = NGX_MAX_INT_T_VALUE % 10;
123 step = is_sec ? st_start : st_month; 126 step = is_sec ? st_start : st_month;
124 127
125 p = line->data; 128 p = line->data;
126 last = p + line->len; 129 last = p + line->len;
127 130
128 while (p < last) { 131 while (p < last) {
129 132
130 if (*p >= '0' && *p <= '9') { 133 if (*p >= '0' && *p <= '9') {
134 if (value >= cutoff && (value > cutoff || *p - '0' > cutlim)) {
135 return NGX_ERROR;
136 }
137
131 value = value * 10 + (*p++ - '0'); 138 value = value * 10 + (*p++ - '0');
132 valid = 1; 139 valid = 1;
133 continue; 140 continue;
134 } 141 }
135 142
138 case 'y': 145 case 'y':
139 if (step > st_start) { 146 if (step > st_start) {
140 return NGX_ERROR; 147 return NGX_ERROR;
141 } 148 }
142 step = st_year; 149 step = st_year;
143 max = NGX_MAX_INT32_VALUE / (60 * 60 * 24 * 365); 150 max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 365);
144 scale = 60 * 60 * 24 * 365; 151 scale = 60 * 60 * 24 * 365;
145 break; 152 break;
146 153
147 case 'M': 154 case 'M':
148 if (step >= st_month) { 155 if (step >= st_month) {
149 return NGX_ERROR; 156 return NGX_ERROR;
150 } 157 }
151 step = st_month; 158 step = st_month;
152 max = NGX_MAX_INT32_VALUE / (60 * 60 * 24 * 30); 159 max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 30);
153 scale = 60 * 60 * 24 * 30; 160 scale = 60 * 60 * 24 * 30;
154 break; 161 break;
155 162
156 case 'w': 163 case 'w':
157 if (step >= st_week) { 164 if (step >= st_week) {
158 return NGX_ERROR; 165 return NGX_ERROR;
159 } 166 }
160 step = st_week; 167 step = st_week;
161 max = NGX_MAX_INT32_VALUE / (60 * 60 * 24 * 7); 168 max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 7);
162 scale = 60 * 60 * 24 * 7; 169 scale = 60 * 60 * 24 * 7;
163 break; 170 break;
164 171
165 case 'd': 172 case 'd':
166 if (step >= st_day) { 173 if (step >= st_day) {
167 return NGX_ERROR; 174 return NGX_ERROR;
168 } 175 }
169 step = st_day; 176 step = st_day;
170 max = NGX_MAX_INT32_VALUE / (60 * 60 * 24); 177 max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24);
171 scale = 60 * 60 * 24; 178 scale = 60 * 60 * 24;
172 break; 179 break;
173 180
174 case 'h': 181 case 'h':
175 if (step >= st_hour) { 182 if (step >= st_hour) {
176 return NGX_ERROR; 183 return NGX_ERROR;
177 } 184 }
178 step = st_hour; 185 step = st_hour;
179 max = NGX_MAX_INT32_VALUE / (60 * 60); 186 max = NGX_MAX_INT_T_VALUE / (60 * 60);
180 scale = 60 * 60; 187 scale = 60 * 60;
181 break; 188 break;
182 189
183 case 'm': 190 case 'm':
184 if (*p == 's') { 191 if (*p == 's') {
185 if (is_sec || step >= st_msec) { 192 if (is_sec || step >= st_msec) {
186 return NGX_ERROR; 193 return NGX_ERROR;
187 } 194 }
188 p++; 195 p++;
189 step = st_msec; 196 step = st_msec;
190 max = NGX_MAX_INT32_VALUE; 197 max = NGX_MAX_INT_T_VALUE;
191 scale = 1; 198 scale = 1;
192 break; 199 break;
193 } 200 }
194 201
195 if (step >= st_min) { 202 if (step >= st_min) {
196 return NGX_ERROR; 203 return NGX_ERROR;
197 } 204 }
198 step = st_min; 205 step = st_min;
199 max = NGX_MAX_INT32_VALUE / 60; 206 max = NGX_MAX_INT_T_VALUE / 60;
200 scale = 60; 207 scale = 60;
201 break; 208 break;
202 209
203 case 's': 210 case 's':
204 if (step >= st_sec) { 211 if (step >= st_sec) {
205 return NGX_ERROR; 212 return NGX_ERROR;
206 } 213 }
207 step = st_sec; 214 step = st_sec;
208 max = NGX_MAX_INT32_VALUE; 215 max = NGX_MAX_INT_T_VALUE;
209 scale = 1; 216 scale = 1;
210 break; 217 break;
211 218
212 case ' ': 219 case ' ':
213 if (step >= st_sec) { 220 if (step >= st_sec) {
214 return NGX_ERROR; 221 return NGX_ERROR;
215 } 222 }
216 step = st_last; 223 step = st_last;
217 max = NGX_MAX_INT32_VALUE; 224 max = NGX_MAX_INT_T_VALUE;
218 scale = 1; 225 scale = 1;
219 break; 226 break;
220 227
221 default: 228 default:
222 return NGX_ERROR; 229 return NGX_ERROR;
225 if (step != st_msec && !is_sec) { 232 if (step != st_msec && !is_sec) {
226 scale *= 1000; 233 scale *= 1000;
227 max /= 1000; 234 max /= 1000;
228 } 235 }
229 236
230 if ((ngx_uint_t) value > max) { 237 if (value > max) {
231 return NGX_ERROR; 238 return NGX_ERROR;
232 } 239 }
233 240
234 total += value * scale; 241 value *= scale;
235 242
236 if ((ngx_uint_t) total > NGX_MAX_INT32_VALUE) { 243 if (total > NGX_MAX_INT_T_VALUE - value) {
237 return NGX_ERROR; 244 return NGX_ERROR;
238 } 245 }
246
247 total += value;
239 248
240 value = 0; 249 value = 0;
241 250
242 while (p < last && *p == ' ') { 251 while (p < last && *p == ' ') {
243 p++; 252 p++;
244 } 253 }
245 } 254 }
246 255
247 if (valid) { 256 if (!valid) {
248 return total + value * (is_sec ? 1 : 1000); 257 return NGX_ERROR;
249 } 258 }
250 259
251 return NGX_ERROR; 260 if (!is_sec) {
261 if (value > NGX_MAX_INT_T_VALUE / 1000) {
262 return NGX_ERROR;
263 }
264
265 value *= 1000;
266 }
267
268 if (total > NGX_MAX_INT_T_VALUE - value) {
269 return NGX_ERROR;
270 }
271
272 return total + value;
252 } 273 }