Skip to content

Commit ba1d9cc

Browse files
committed
Fix bug #69522 - do not allow int overflow
1 parent e2bbf0a commit ba1d9cc

File tree

1 file changed

+70
-69
lines changed

1 file changed

+70
-69
lines changed

ext/standard/pack.c

Lines changed: 70 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ PHP_FUNCTION(pack)
148148
}
149149
else if (c >= '0' && c <= '9') {
150150
arg = atoi(&format[i]);
151-
151+
152152
while (format[i] >= '0' && format[i] <= '9' && i < formatlen) {
153153
i++;
154154
}
@@ -158,8 +158,8 @@ PHP_FUNCTION(pack)
158158
/* Handle special arg '*' for all codes and check argv overflows */
159159
switch ((int) code) {
160160
/* Never uses any args */
161-
case 'x':
162-
case 'X':
161+
case 'x':
162+
case 'X':
163163
case '@':
164164
if (arg < 0) {
165165
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: '*' ignored", code);
@@ -168,9 +168,9 @@ PHP_FUNCTION(pack)
168168
break;
169169

170170
/* Always uses one arg */
171-
case 'a':
172-
case 'A':
173-
case 'h':
171+
case 'a':
172+
case 'A':
173+
case 'h':
174174
case 'H':
175175
if (currentarg >= num_args) {
176176
efree(argv);
@@ -192,20 +192,20 @@ PHP_FUNCTION(pack)
192192
break;
193193

194194
/* Use as many args as specified */
195-
case 'c':
196-
case 'C':
197-
case 's':
198-
case 'S':
199-
case 'i':
195+
case 'c':
196+
case 'C':
197+
case 's':
198+
case 'S':
199+
case 'i':
200200
case 'I':
201-
case 'l':
202-
case 'L':
203-
case 'n':
204-
case 'N':
205-
case 'v':
201+
case 'l':
202+
case 'L':
203+
case 'n':
204+
case 'N':
205+
case 'v':
206206
case 'V':
207-
case 'f':
208-
case 'd':
207+
case 'f':
208+
case 'd':
209209
if (arg < 0) {
210210
arg = num_args - currentarg;
211211
}
@@ -243,34 +243,34 @@ PHP_FUNCTION(pack)
243243
int arg = formatargs[i];
244244

245245
switch ((int) code) {
246-
case 'h':
247-
case 'H':
246+
case 'h':
247+
case 'H':
248248
INC_OUTPUTPOS((arg + (arg % 2)) / 2,1) /* 4 bit per arg */
249249
break;
250250

251-
case 'a':
251+
case 'a':
252252
case 'A':
253-
case 'c':
253+
case 'c':
254254
case 'C':
255255
case 'x':
256256
INC_OUTPUTPOS(arg,1) /* 8 bit per arg */
257257
break;
258258

259-
case 's':
260-
case 'S':
261-
case 'n':
259+
case 's':
260+
case 'S':
261+
case 'n':
262262
case 'v':
263263
INC_OUTPUTPOS(arg,2) /* 16 bit per arg */
264264
break;
265265

266-
case 'i':
266+
case 'i':
267267
case 'I':
268268
INC_OUTPUTPOS(arg,sizeof(int))
269269
break;
270270

271-
case 'l':
272-
case 'L':
273-
case 'N':
271+
case 'l':
272+
case 'L':
273+
case 'N':
274274
case 'V':
275275
INC_OUTPUTPOS(arg,4) /* 32 bit per arg */
276276
break;
@@ -313,8 +313,8 @@ PHP_FUNCTION(pack)
313313
zval **val;
314314

315315
switch ((int) code) {
316-
case 'a':
317-
case 'A':
316+
case 'a':
317+
case 'A':
318318
memset(&output[outputpos], (code == 'a') ? '\0' : ' ', arg);
319319
val = argv[currentarg++];
320320
if (Z_ISREF_PP(val)) {
@@ -326,7 +326,7 @@ PHP_FUNCTION(pack)
326326
outputpos += arg;
327327
break;
328328

329-
case 'h':
329+
case 'h':
330330
case 'H': {
331331
int nibbleshift = (code == 'h') ? 0 : 4;
332332
int first = 1;
@@ -372,17 +372,17 @@ PHP_FUNCTION(pack)
372372
break;
373373
}
374374

375-
case 'c':
375+
case 'c':
376376
case 'C':
377377
while (arg-- > 0) {
378378
php_pack(argv[currentarg++], 1, byte_map, &output[outputpos]);
379379
outputpos++;
380380
}
381381
break;
382382

383-
case 's':
384-
case 'S':
385-
case 'n':
383+
case 's':
384+
case 'S':
385+
case 'n':
386386
case 'v': {
387387
int *map = machine_endian_short_map;
388388

@@ -399,17 +399,17 @@ PHP_FUNCTION(pack)
399399
break;
400400
}
401401

402-
case 'i':
403-
case 'I':
402+
case 'i':
403+
case 'I':
404404
while (arg-- > 0) {
405405
php_pack(argv[currentarg++], sizeof(int), int_map, &output[outputpos]);
406406
outputpos += sizeof(int);
407407
}
408408
break;
409409

410-
case 'l':
411-
case 'L':
412-
case 'N':
410+
case 'l':
411+
case 'L':
412+
case 'N':
413413
case 'V': {
414414
int *map = machine_endian_long_map;
415415

@@ -503,7 +503,7 @@ static long php_unpack(char *data, int size, int issigned, int *map)
503503

504504
/* unpack() is based on Perl's unpack(), but is modified a bit from there.
505505
* Rather than depending on error-prone ordered lists or syntactically
506-
* unpleasant pass-by-reference, we return an object with named parameters
506+
* unpleasant pass-by-reference, we return an object with named parameters
507507
* (like *_fetch_object()). Syntax is "f[repeat]name/...", where "f" is the
508508
* formatter char (like pack()), "[repeat]" is the optional repeater argument,
509509
* and "name" is the name of the variable to use.
@@ -576,51 +576,51 @@ PHP_FUNCTION(unpack)
576576

577577
switch ((int) type) {
578578
/* Never use any input */
579-
case 'X':
579+
case 'X':
580580
size = -1;
581581
break;
582582

583583
case '@':
584584
size = 0;
585585
break;
586586

587-
case 'a':
587+
case 'a':
588588
case 'A':
589589
size = arg;
590590
arg = 1;
591591
break;
592592

593-
case 'h':
594-
case 'H':
593+
case 'h':
594+
case 'H':
595595
size = (arg > 0) ? (arg + (arg % 2)) / 2 : arg;
596596
arg = 1;
597597
break;
598598

599599
/* Use 1 byte of input */
600-
case 'c':
600+
case 'c':
601601
case 'C':
602602
case 'x':
603603
size = 1;
604604
break;
605605

606606
/* Use 2 bytes of input */
607-
case 's':
608-
case 'S':
609-
case 'n':
607+
case 's':
608+
case 'S':
609+
case 'n':
610610
case 'v':
611611
size = 2;
612612
break;
613613

614614
/* Use sizeof(int) bytes of input */
615-
case 'i':
615+
case 'i':
616616
case 'I':
617617
size = sizeof(int);
618618
break;
619619

620620
/* Use 4 bytes of input */
621-
case 'l':
622-
case 'L':
623-
case 'N':
621+
case 'l':
622+
case 'L':
623+
case 'N':
624624
case 'V':
625625
size = 4;
626626
break;
@@ -657,12 +657,13 @@ PHP_FUNCTION(unpack)
657657

658658
if (size != 0 && size != -1 && INT_MAX - size + 1 < inputpos) {
659659
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: integer overflow", type);
660-
inputpos = 0;
660+
zval_dtor(return_value);
661+
RETURN_FALSE;
661662
}
662663

663664
if ((inputpos + size) <= inputlen) {
664665
switch ((int) type) {
665-
case 'a':
666+
case 'a':
666667
case 'A': {
667668
char pad = (type == 'a') ? '\0' : ' ';
668669
int len = inputlen - inputpos; /* Remaining string */
@@ -683,8 +684,8 @@ PHP_FUNCTION(unpack)
683684
add_assoc_stringl(return_value, n, &input[inputpos], len + 1, 1);
684685
break;
685686
}
686-
687-
case 'h':
687+
688+
case 'h':
688689
case 'H': {
689690
int len = (inputlen - inputpos) * 2; /* Remaining */
690691
int nibbleshift = (type == 'h') ? 0 : 4;
@@ -695,9 +696,9 @@ PHP_FUNCTION(unpack)
695696
/* If size was given take minimum of len and size */
696697
if (size >= 0 && len > (size * 2)) {
697698
len = size * 2;
698-
}
699+
}
699700

700-
if (argb > 0) {
701+
if (len > 0 && argb > 0) {
701702
len -= argb % 2;
702703
}
703704

@@ -727,17 +728,17 @@ PHP_FUNCTION(unpack)
727728
break;
728729
}
729730

730-
case 'c':
731+
case 'c':
731732
case 'C': {
732733
int issigned = (type == 'c') ? (input[inputpos] & 0x80) : 0;
733734
long v = php_unpack(&input[inputpos], 1, issigned, byte_map);
734735
add_assoc_long(return_value, n, v);
735736
break;
736737
}
737738

738-
case 's':
739-
case 'S':
740-
case 'n':
739+
case 's':
740+
case 'S':
741+
case 'n':
741742
case 'v': {
742743
long v;
743744
int issigned = 0;
@@ -756,7 +757,7 @@ PHP_FUNCTION(unpack)
756757
break;
757758
}
758759

759-
case 'i':
760+
case 'i':
760761
case 'I': {
761762
long v;
762763
int issigned = 0;
@@ -770,9 +771,9 @@ PHP_FUNCTION(unpack)
770771
break;
771772
}
772773

773-
case 'l':
774-
case 'L':
775-
case 'N':
774+
case 'l':
775+
case 'L':
776+
case 'N':
776777
case 'V': {
777778
int issigned = 0;
778779
int *map = machine_endian_long_map;
@@ -795,7 +796,7 @@ PHP_FUNCTION(unpack)
795796
v |= php_unpack(&input[inputpos], 4, issigned, map);
796797
if (sizeof(long) > 4) {
797798
if (type == 'l') {
798-
v = (signed int) v;
799+
v = (signed int) v;
799800
} else {
800801
v = (unsigned int) v;
801802
}

0 commit comments

Comments
 (0)