@@ -412,8 +412,14 @@ PHP_FUNCTION(dns_check_record)
412412
413413#if HAVE_FULL_DNS_FUNCS
414414
415+ #define CHECKCP (n ) do { \
416+ if (cp + n > end) { \
417+ return NULL; \
418+ } \
419+ } while (0)
420+
415421/* {{{ php_parserr */
416- static u_char * php_parserr (u_char * cp , querybuf * answer , int type_to_fetch , int store , int raw , zval * * subarray )
422+ static u_char * php_parserr (u_char * cp , u_char * end , querybuf * answer , int type_to_fetch , int store , int raw , zval * * subarray )
417423{
418424 u_short type , class , dlen ;
419425 u_long ttl ;
@@ -425,16 +431,18 @@ static u_char *php_parserr(u_char *cp, querybuf *answer, int type_to_fetch, int
425431
426432 * subarray = NULL ;
427433
428- n = dn_expand (answer -> qb2 , answer -> qb2 + 65536 , cp , name , sizeof (name ) - 2 );
434+ n = dn_expand (answer -> qb2 , end , cp , name , sizeof (name ) - 2 );
429435 if (n < 0 ) {
430436 return NULL ;
431437 }
432438 cp += n ;
433439
440+ CHECKCP (10 );
434441 GETSHORT (type , cp );
435442 GETSHORT (class , cp );
436443 GETLONG (ttl , cp );
437444 GETSHORT (dlen , cp );
445+ CHECKCP (dlen );
438446 if (type_to_fetch != T_ANY && type != type_to_fetch ) {
439447 cp += dlen ;
440448 return cp ;
@@ -461,12 +469,14 @@ static u_char *php_parserr(u_char *cp, querybuf *answer, int type_to_fetch, int
461469
462470 switch (type ) {
463471 case DNS_T_A :
472+ CHECKCP (4 );
464473 add_assoc_string (* subarray , "type" , "A" , 1 );
465474 snprintf (name , sizeof (name ), "%d.%d.%d.%d" , cp [0 ], cp [1 ], cp [2 ], cp [3 ]);
466475 add_assoc_string (* subarray , "ip" , name , 1 );
467476 cp += dlen ;
468477 break ;
469478 case DNS_T_MX :
479+ CHECKCP (2 );
470480 add_assoc_string (* subarray , "type" , "MX" , 1 );
471481 GETSHORT (n , cp );
472482 add_assoc_long (* subarray , "pri" , n );
@@ -485,7 +495,7 @@ static u_char *php_parserr(u_char *cp, querybuf *answer, int type_to_fetch, int
485495 if (type == DNS_T_PTR ) {
486496 add_assoc_string (* subarray , "type" , "PTR" , 1 );
487497 }
488- n = dn_expand (answer -> qb2 , answer -> qb2 + 65536 , cp , name , (sizeof name ) - 2 );
498+ n = dn_expand (answer -> qb2 , end , cp , name , (sizeof name ) - 2 );
489499 if (n < 0 ) {
490500 return NULL ;
491501 }
@@ -495,18 +505,22 @@ static u_char *php_parserr(u_char *cp, querybuf *answer, int type_to_fetch, int
495505 case DNS_T_HINFO :
496506 /* See RFC 1010 for values */
497507 add_assoc_string (* subarray , "type" , "HINFO" , 1 );
508+ CHECKCP (1 );
498509 n = * cp & 0xFF ;
499510 cp ++ ;
511+ CHECKCP (n );
500512 add_assoc_stringl (* subarray , "cpu" , (char * )cp , n , 1 );
501513 cp += n ;
514+ CHECKCP (1 );
502515 n = * cp & 0xFF ;
503516 cp ++ ;
517+ CHECKCP (n );
504518 add_assoc_stringl (* subarray , "os" , (char * )cp , n , 1 );
505519 cp += n ;
506520 break ;
507521 case DNS_T_TXT :
508522 {
509- int ll = 0 ;
523+ int l1 = 0 , l2 = 0 ;
510524 zval * entries = NULL ;
511525
512526 add_assoc_string (* subarray , "type" , "TXT" , 1 );
@@ -515,37 +529,41 @@ static u_char *php_parserr(u_char *cp, querybuf *answer, int type_to_fetch, int
515529 MAKE_STD_ZVAL (entries );
516530 array_init (entries );
517531
518- while (ll < dlen ) {
519- n = cp [ll ];
520- if ((ll + n ) >= dlen ) {
532+ while (l1 < dlen ) {
533+ n = cp [l1 ];
534+ if ((l1 + n ) >= dlen ) {
521535 // Invalid chunk length, truncate
522- n = dlen - (ll + 1 );
536+ n = dlen - (l1 + 1 );
537+ }
538+ if (n ) {
539+ memcpy (tp + l2 , cp + l1 + 1 , n );
540+ add_next_index_stringl (entries , cp + l1 + 1 , n , 1 );
523541 }
524- memcpy (tp + ll , cp + ll + 1 , n );
525- add_next_index_stringl (entries , cp + ll + 1 , n , 1 );
526- ll = ll + n + 1 ;
542+ l1 = l1 + n + 1 ;
543+ l2 = l2 + n ;
527544 }
528- tp [dlen ] = '\0' ;
545+ tp [l2 ] = '\0' ;
529546 cp += dlen ;
530547
531- add_assoc_stringl (* subarray , "txt" , tp , ( dlen > 0 )? dlen - 1 : 0 , 0 );
548+ add_assoc_stringl (* subarray , "txt" , tp , l2 , 0 );
532549 add_assoc_zval (* subarray , "entries" , entries );
533550 }
534551 break ;
535552 case DNS_T_SOA :
536553 add_assoc_string (* subarray , "type" , "SOA" , 1 );
537- n = dn_expand (answer -> qb2 , answer -> qb2 + 65536 , cp , name , (sizeof name ) - 2 );
554+ n = dn_expand (answer -> qb2 , end , cp , name , (sizeof name ) - 2 );
538555 if (n < 0 ) {
539556 return NULL ;
540557 }
541558 cp += n ;
542559 add_assoc_string (* subarray , "mname" , name , 1 );
543- n = dn_expand (answer -> qb2 , answer -> qb2 + 65536 , cp , name , (sizeof name ) - 2 );
560+ n = dn_expand (answer -> qb2 , end , cp , name , (sizeof name ) - 2 );
544561 if (n < 0 ) {
545562 return NULL ;
546563 }
547564 cp += n ;
548565 add_assoc_string (* subarray , "rname" , name , 1 );
566+ CHECKCP (5 * 4 );
549567 GETLONG (n , cp );
550568 add_assoc_long (* subarray , "serial" , n );
551569 GETLONG (n , cp );
@@ -559,6 +577,7 @@ static u_char *php_parserr(u_char *cp, querybuf *answer, int type_to_fetch, int
559577 break ;
560578 case DNS_T_AAAA :
561579 tp = (u_char * )name ;
580+ CHECKCP (8 * 2 );
562581 for (i = 0 ; i < 8 ; i ++ ) {
563582 GETSHORT (s , cp );
564583 if (s != 0 ) {
@@ -593,6 +612,7 @@ static u_char *php_parserr(u_char *cp, querybuf *answer, int type_to_fetch, int
593612 case DNS_T_A6 :
594613 p = cp ;
595614 add_assoc_string (* subarray , "type" , "A6" , 1 );
615+ CHECKCP (1 );
596616 n = ((int )cp [0 ]) & 0xFF ;
597617 cp ++ ;
598618 add_assoc_long (* subarray , "masklen" , n );
@@ -628,6 +648,7 @@ static u_char *php_parserr(u_char *cp, querybuf *answer, int type_to_fetch, int
628648 cp ++ ;
629649 }
630650 for (i = (n + 8 ) / 16 ; i < 8 ; i ++ ) {
651+ CHECKCP (2 );
631652 GETSHORT (s , cp );
632653 if (s != 0 ) {
633654 if (tp > (u_char * )name ) {
@@ -657,7 +678,7 @@ static u_char *php_parserr(u_char *cp, querybuf *answer, int type_to_fetch, int
657678 tp [0 ] = '\0' ;
658679 add_assoc_string (* subarray , "ipv6" , name , 1 );
659680 if (cp < p + dlen ) {
660- n = dn_expand (answer -> qb2 , answer -> qb2 + 65536 , cp , name , (sizeof name ) - 2 );
681+ n = dn_expand (answer -> qb2 , end , cp , name , (sizeof name ) - 2 );
661682 if (n < 0 ) {
662683 return NULL ;
663684 }
@@ -666,36 +687,51 @@ static u_char *php_parserr(u_char *cp, querybuf *answer, int type_to_fetch, int
666687 }
667688 break ;
668689 case DNS_T_SRV :
690+ CHECKCP (3 * 2 );
669691 add_assoc_string (* subarray , "type" , "SRV" , 1 );
670692 GETSHORT (n , cp );
671693 add_assoc_long (* subarray , "pri" , n );
672694 GETSHORT (n , cp );
673695 add_assoc_long (* subarray , "weight" , n );
674696 GETSHORT (n , cp );
675697 add_assoc_long (* subarray , "port" , n );
676- n = dn_expand (answer -> qb2 , answer -> qb2 + 65536 , cp , name , (sizeof name ) - 2 );
698+ n = dn_expand (answer -> qb2 , end , cp , name , (sizeof name ) - 2 );
677699 if (n < 0 ) {
678700 return NULL ;
679701 }
680702 cp += n ;
681703 add_assoc_string (* subarray , "target" , name , 1 );
682704 break ;
683705 case DNS_T_NAPTR :
706+ CHECKCP (2 * 2 );
684707 add_assoc_string (* subarray , "type" , "NAPTR" , 1 );
685708 GETSHORT (n , cp );
686709 add_assoc_long (* subarray , "order" , n );
687710 GETSHORT (n , cp );
688711 add_assoc_long (* subarray , "pref" , n );
712+
713+ CHECKCP (1 );
689714 n = (cp [0 ] & 0xFF );
690- add_assoc_stringl (* subarray , "flags" , (char * )++ cp , n , 1 );
715+ cp ++ ;
716+ CHECKCP (n );
717+ add_assoc_stringl (* subarray , "flags" , (char * )cp , n , 1 );
691718 cp += n ;
719+
720+ CHECKCP (1 );
692721 n = (cp [0 ] & 0xFF );
693- add_assoc_stringl (* subarray , "services" , (char * )++ cp , n , 1 );
722+ cp ++ ;
723+ CHECKCP (n );
724+ add_assoc_stringl (* subarray , "services" , (char * )cp , n , 1 );
694725 cp += n ;
726+
727+ CHECKCP (1 );
695728 n = (cp [0 ] & 0xFF );
696- add_assoc_stringl (* subarray , "regex" , (char * )++ cp , n , 1 );
729+ cp ++ ;
730+ CHECKCP (n );
731+ add_assoc_stringl (* subarray , "regex" , (char * )cp , n , 1 );
697732 cp += n ;
698- n = dn_expand (answer -> qb2 , answer -> qb2 + 65536 , cp , name , (sizeof name ) - 2 );
733+
734+ n = dn_expand (answer -> qb2 , end , cp , name , (sizeof name ) - 2 );
699735 if (n < 0 ) {
700736 return NULL ;
701737 }
@@ -888,7 +924,7 @@ PHP_FUNCTION(dns_get_record)
888924 while (an -- && cp && cp < end ) {
889925 zval * retval ;
890926
891- cp = php_parserr (cp , & answer , type_to_fetch , store_results , raw , & retval );
927+ cp = php_parserr (cp , end , & answer , type_to_fetch , store_results , raw , & retval );
892928 if (retval != NULL && store_results ) {
893929 add_next_index_zval (return_value , retval );
894930 }
@@ -901,7 +937,7 @@ PHP_FUNCTION(dns_get_record)
901937 while (ns -- > 0 && cp && cp < end ) {
902938 zval * retval = NULL ;
903939
904- cp = php_parserr (cp , & answer , DNS_T_ANY , authns != NULL , raw , & retval );
940+ cp = php_parserr (cp , end , & answer , DNS_T_ANY , authns != NULL , raw , & retval );
905941 if (retval != NULL ) {
906942 add_next_index_zval (authns , retval );
907943 }
@@ -913,7 +949,7 @@ PHP_FUNCTION(dns_get_record)
913949 while (ar -- > 0 && cp && cp < end ) {
914950 zval * retval = NULL ;
915951
916- cp = php_parserr (cp , & answer , DNS_T_ANY , 1 , raw , & retval );
952+ cp = php_parserr (cp , end , & answer , DNS_T_ANY , 1 , raw , & retval );
917953 if (retval != NULL ) {
918954 add_next_index_zval (addtl , retval );
919955 }
0 commit comments