Browse code

bcomp - fixing issue with whitespacing padding, fixing issue with little endian extraction of odd nibbled hex sequences, refactoring hex/decimal auto checking and hex buffer normalization code, fixing issue with normalization where it was possible to evaluate unwanted hex bytes, fixing issue with big endian conversion of decimal extracted sequence values after use of cli_strntoul

Mickey Sola authored on 2018/10/24 04:28:50
Showing 2 changed files
... ...
@@ -553,10 +553,12 @@ cl_error_t cli_bcomp_scanbuf(const unsigned char *buffer, size_t buffer_length,
553 553
  * @param bm the byte comparison meta data struct, contains all the other info needed to do the comparison
554 554
  *
555 555
  */
556
-cl_error_t cli_bcomp_compare_check(const unsigned char* buffer, size_t buffer_length, int offset, struct cli_bcomp_meta *bm)
556
+cl_error_t cli_bcomp_compare_check(const unsigned char* f_buffer, size_t buffer_length, int offset, struct cli_bcomp_meta *bm)
557 557
 {
558 558
 
559 559
     uint32_t byte_len = 0;
560
+    uint32_t pad_len = 0;
561
+    uint32_t norm_len = 0;
560 562
     uint32_t length = 0;
561 563
     uint32_t i = 0;
562 564
     cl_error_t ret = 0;
... ...
@@ -564,9 +566,10 @@ cl_error_t cli_bcomp_compare_check(const unsigned char* buffer, size_t buffer_le
564 564
     uint16_t opt_val = 0;
565 565
     int64_t value = 0;
566 566
     const unsigned char* end_buf = NULL;
567
+    const unsigned char* buffer = NULL;
567 568
     unsigned char* tmp_buffer = NULL;
568 569
 
569
-    if (!buffer || !bm) {
570
+    if (!f_buffer || !bm) {
570 571
         bcm_dbgmsg("cli_bcomp_compare_check: a param is null\n");
571 572
         return CL_ENULLARG;
572 573
     }
... ...
@@ -590,71 +593,40 @@ cl_error_t cli_bcomp_compare_check(const unsigned char* buffer, size_t buffer_le
590 590
 
591 591
     /* jump to byte compare offset, then store off specified bytes into a null terminated buffer */
592 592
     offset += bm->offset;
593
-    buffer += offset;
593
+    f_buffer += offset;
594 594
 
595
-    bcm_dbgmsg("cli_bcomp_compare_check: literal extracted bytes before comparison %.*s\n", byte_len, buffer);
595
+    bcm_dbgmsg("cli_bcomp_compare_check: literal extracted bytes before comparison %.*s\n", byte_len, f_buffer);
596
+
597
+    /* normalize buffer for whitespace */
598
+
599
+    opt_val = opt & 0x000F;
600
+    if ( !(opt_val & CLI_BCOMP_BIN) ) {
601
+        buffer = cli_bcomp_normalize_buffer(f_buffer, byte_len, &pad_len, opt, 1);
602
+        if (NULL == buffer) {
603
+            cli_errmsg("cli_bcomp_compare_check: unable to whitespace normalize temp buffer, allocation failed\n");
604
+            return CL_EMEM;
605
+        }
606
+
607
+        /* adjust byte_len accordingly */
608
+        byte_len -= pad_len;
609
+    }
596 610
 
597 611
     /* normalize buffer for little endian vals */
598 612
     opt_val = opt & 0x00F0;
599 613
     if (opt_val == CLI_BCOMP_LE) {
600 614
         opt_val = opt & 0x000F;
601
-        if (opt_val & CLI_BCOMP_HEX || opt_val & CLI_BCOMP_AUTO) {
602
-            tmp_buffer = cli_calloc(byte_len+1, sizeof(char));
615
+        if ( !(opt_val & CLI_BCOMP_BIN) ) {
616
+            tmp_buffer = cli_bcomp_normalize_buffer(f_buffer, byte_len, NULL, opt, 0);
603 617
             if (NULL == tmp_buffer) {
604
-                cli_errmsg("cli_bcomp_compare_check: unable to allocate memory for temp buffer\n");
618
+                cli_errmsg("cli_bcomp_compare_check: unable to normalize temp, allocation failed\n");
605 619
                 return CL_EMEM;
606 620
             }
607
-
608
-            if (byte_len == 1) {
609
-                tmp_buffer[0] = buffer[0];
610
-            } else {
611
-                for (i = 0; i < byte_len; i = i+2) {
612
-                    if (((int32_t) byte_len - (int32_t) i) - 2 >= 0) {
613
-                        if ( isxdigit(buffer[byte_len-i-2]) || toupper(buffer[byte_len-i-2]) == 'X' ) {
614
-                            tmp_buffer[i] = buffer[byte_len-i-2];
615
-                        } else {
616
-                            tmp_buffer[i] = '0';
617
-                        }
618
-                    }
619
-
620
-                    if ( isxdigit(buffer[byte_len-i-1]) || toupper(buffer[byte_len-i-1]) == 'X' ) {
621
-                        tmp_buffer[i+1] = buffer[byte_len-i-1];
622
-                    } else {
623
-                        tmp_buffer[i+1] = '0';
624
-                    }
625
-                }
626
-            }
627
-            tmp_buffer[byte_len+1] = '\0';
628
-            bcm_dbgmsg("cli_bcomp_compare_check: normalized extracted bytes before comparison %.*s\n", byte_len, tmp_buffer);
629 621
         }
630 622
     }
631 623
 
632 624
     opt_val = opt;
633 625
     if (opt_val & CLI_BCOMP_AUTO) {
634
-        if (tmp_buffer) {
635
-            /* tmp_buffer is based on the size of byte_len, so we can check against that safely */
636
-            if ((opt & 0x00F0) & CLI_BCOMP_LE && byte_len >= 3) {
637
-                if(!strncmp((char*) &tmp_buffer[byte_len-2], "0x", 2) || !strncmp((char*) &tmp_buffer[byte_len-2], "0X", 2)) {
638
-                    tmp_buffer[byte_len-2] = '\0';
639
-                    bcm_dbgmsg("cli_bcomp_compare_check: adjusted bytes before comparison %.*s\n", byte_len-2, tmp_buffer);
640
-                    opt |= CLI_BCOMP_HEX;
641
-                } else {
642
-                    opt |= CLI_BCOMP_DEC;
643
-                }
644
-            }
645
-            else if(!strncmp((char*) tmp_buffer, "0x", 2) || !strncmp((char*) tmp_buffer, "0X", 2)) {
646
-                opt |= CLI_BCOMP_HEX;
647
-            } else {
648
-                opt |= CLI_BCOMP_DEC;
649
-            }
650
-        } else {
651
-            if(!strncmp((char*) buffer, "0x", 2) || !strncmp((char*) buffer, "0X", 2)) {
652
-                opt |= CLI_BCOMP_HEX;
653
-            } else {
654
-                opt |= CLI_BCOMP_DEC;
655
-            }
656
-        }
657
-        opt ^= CLI_BCOMP_AUTO;
626
+        opt = cli_bcomp_chk_hex(f_buffer, opt_val, byte_len, 0);
658 627
     }
659 628
 
660 629
     /* grab the first byte to handle byte length options to convert the string appropriately */
... ...
@@ -671,7 +643,7 @@ cl_error_t cli_bcomp_compare_check(const unsigned char* buffer, size_t buffer_le
671 671
             }
672 672
             /*hle*/
673 673
             if (opt & CLI_BCOMP_EXACT) {
674
-                if (tmp_buffer+byte_len != end_buf) {
674
+                if (tmp_buffer+byte_len != end_buf || pad_len != 0) {
675 675
 
676 676
                     free(tmp_buffer);
677 677
                     bcm_dbgmsg("cli_bcomp_compare_check: couldn't extract the exact number of requested bytes\n");
... ...
@@ -691,7 +663,7 @@ cl_error_t cli_bcomp_compare_check(const unsigned char* buffer, size_t buffer_le
691 691
             }
692 692
             /*hbe*/
693 693
             if (opt & CLI_BCOMP_EXACT) {
694
-                if (buffer+byte_len != end_buf) {
694
+                if (buffer+byte_len != end_buf || pad_len != 0) {
695 695
 
696 696
                     bcm_dbgmsg("cli_bcomp_compare_check: couldn't extract the exact number of requested bytes\n");
697 697
                     return CL_CLEAN;
... ...
@@ -717,24 +689,23 @@ cl_error_t cli_bcomp_compare_check(const unsigned char* buffer, size_t buffer_le
717 717
             }
718 718
             /*dbe*/
719 719
             if (opt & CLI_BCOMP_EXACT) {
720
-                if (buffer+byte_len != end_buf) {
720
+                if (buffer+byte_len != end_buf || pad_len != 0) {
721 721
 
722 722
                     bcm_dbgmsg("cli_bcomp_compare_check: couldn't extract the exact number of requested bytes\n");
723 723
                     return CL_CLEAN;
724 724
                 }
725 725
             }
726 726
 
727
-            value = be64_to_host(value);
728 727
             break;
729 728
 
730 729
         /*il*/
731 730
         case CLI_BCOMP_BIN | CLI_BCOMP_LE:
732 731
             /* exact byte_length option is implied for binary extraction */
733 732
             switch (byte_len) {
734
-                case 1: value = (*(int8_t*) buffer);                           break;
735
-                case 2: value =   (int16_t) le16_to_host( *(int16_t*) buffer); break;
736
-                case 4: value =   (int32_t) le32_to_host( *(int32_t*) buffer); break;
737
-                case 8: value =   (int64_t) le64_to_host( *(int64_t*) buffer); break;
733
+                case 1: value = (*(int8_t*) f_buffer);                           break;
734
+                case 2: value =   (int16_t) le16_to_host( *(int16_t*) f_buffer); break;
735
+                case 4: value =   (int32_t) le32_to_host( *(int32_t*) f_buffer); break;
736
+                case 8: value =   (int64_t) le64_to_host( *(int64_t*) f_buffer); break;
738 737
 
739 738
                 default:
740 739
                     bcm_dbgmsg("cli_bcomp_compare_check: invalid byte size for binary integer field (%u)\n", byte_len);
... ...
@@ -746,10 +717,10 @@ cl_error_t cli_bcomp_compare_check(const unsigned char* buffer, size_t buffer_le
746 746
         case CLI_BCOMP_BIN | CLI_BCOMP_BE:
747 747
             /* exact byte_length option is implied for binary extraction */
748 748
             switch (byte_len) {
749
-                case 1: value = ( *(int8_t*) buffer);                           break;
750
-                case 2: value =    (int16_t) be16_to_host( *(int16_t*) buffer); break;
751
-                case 4: value =    (int32_t) be32_to_host( *(int32_t*) buffer); break;
752
-                case 8: value =    (int64_t) be64_to_host( *(int64_t*) buffer); break;
749
+                case 1: value = ( *(int8_t*) f_buffer);                           break;
750
+                case 2: value =    (int16_t) be16_to_host( *(int16_t*) f_buffer); break;
751
+                case 4: value =    (int32_t) be32_to_host( *(int32_t*) f_buffer); break;
752
+                case 8: value =    (int64_t) be64_to_host( *(int64_t*) f_buffer); break;
753 753
 
754 754
                 default:
755 755
                     bcm_dbgmsg("cli_bcomp_compare_check: invalid byte size for binary integer field (%u)\n", byte_len);
... ...
@@ -818,6 +789,165 @@ cl_error_t cli_bcomp_compare_check(const unsigned char* buffer, size_t buffer_le
818 818
 }
819 819
 
820 820
 /**
821
+ * @brief checks to see if an ascii buffer should be considered hex or not
822
+ *
823
+ * @param buffer is the buffer to evaluate
824
+ * @param opts the bcomp opts bitfield to set/evaluate during the check
825
+ * @param len the length of the buffer, must be larger than 3 bytes
826
+ * @param check_only specifies whether to return true/false or the modified opt value
827
+ *
828
+ * @return if check only is set, it will return true or false, otherwise it returns a modifiied byte compare bitfield
829
+ */
830
+uint16_t cli_bcomp_chk_hex(const unsigned char* buffer, uint16_t opt, uint32_t len, uint32_t check_only) {
831
+
832
+    uint16_t check = 0;
833
+
834
+    if (!buffer || len < 3) {
835
+        return check_only ? check : opt;
836
+    }
837
+
838
+    if(!strncmp((char*) buffer, "0x", 2) || !strncmp((char*) buffer, "0X", 2)) {
839
+        opt |= CLI_BCOMP_HEX;
840
+        check = 1;
841
+    } else {
842
+        opt |= CLI_BCOMP_DEC;
843
+        check = 0;
844
+    }
845
+    opt ^= CLI_BCOMP_AUTO;
846
+
847
+    return check_only ? check : opt;
848
+}
849
+
850
+/**
851
+ * @brief multipurpose buffer normalization support function for bytcompare
852
+ *
853
+ * Currently can be used to normalize a little endian hex buffer to big endian.
854
+ * Can also be used to trim whitespace from the front of the buffer.
855
+ *
856
+ * @param buffer is the ascii bytes which are to be normalized
857
+ * @param byte_len is the length of these bytes
858
+ * @param pad_len if the address passed is non-null function will store the amount of whitespace found in bytes
859
+ * @param opt the byte compare option bitfield
860
+ * @param whitespace_only if true will only do whitespace normalization, will not perform whitespace
861
+ * normalization if set to no
862
+ *
863
+ * @return returns an allocated, normalized buffer or NULL if an allocation error has occurred
864
+ */
865
+unsigned char* cli_bcomp_normalize_buffer(const unsigned char* buffer, uint32_t byte_len, uint32_t *pad_len,  uint16_t opt, uint16_t whitespace_only) {
866
+    uint32_t norm_len = 0;
867
+    uint32_t pad = 0;
868
+    uint32_t i = 0;
869
+    uint16_t opt_val = 0;
870
+    uint16_t hex = 0;
871
+    unsigned char* tmp_buffer = NULL;
872
+    unsigned char* hex_buffer = NULL;
873
+
874
+    if (!buffer) {
875
+        cli_errmsg("cli_bcomp_compare_check: unable to normalize temp buffer, params null\n");
876
+        return NULL;
877
+    }
878
+
879
+    if (whitespace_only) {
880
+        for(i = 0; i < byte_len; i++) {
881
+            if (isspace(buffer[i])) {
882
+                bcm_dbgmsg("cli_bcomp_compare_check: buffer has whitespace \n");
883
+                pad++;
884
+            } else {
885
+                /* break on first non-padding whitespace */
886
+                break;
887
+            }
888
+        }
889
+        /* keep in mind byte_len is a stack variable so this won't change byte_len in our calling functioning */
890
+        byte_len = byte_len - pad;
891
+        tmp_buffer = cli_calloc(byte_len+1, sizeof(char));
892
+        if (NULL == tmp_buffer) {
893
+            cli_errmsg("cli_bcomp_compare_check: unable to allocate memory for whitespace normalized temp buffer\n");
894
+            return NULL;
895
+        }
896
+        memset(tmp_buffer, '0', byte_len+1);
897
+        memcpy(tmp_buffer, buffer+pad, byte_len);
898
+        tmp_buffer[byte_len] = '\0';
899
+        if (pad_len) {
900
+            *pad_len = pad;
901
+        }
902
+        return tmp_buffer;
903
+    }
904
+
905
+    opt_val = opt & 0x000F;
906
+    if (opt_val & CLI_BCOMP_HEX || opt_val & CLI_BCOMP_AUTO) {
907
+        norm_len = (byte_len % 2) == 0 ? byte_len : byte_len + 1;
908
+        tmp_buffer = cli_calloc(norm_len+1, sizeof(char));
909
+        if (NULL == tmp_buffer) {
910
+            cli_errmsg("cli_bcomp_compare_check: unable to allocate memory for normalized temp buffer\n");
911
+            return NULL;
912
+        }
913
+
914
+        hex_buffer = cli_calloc(norm_len+1, sizeof(char));
915
+        if(NULL == hex_buffer) {
916
+            free(tmp_buffer);
917
+            cli_errmsg("cli_bcomp_compare_check: unable to reallocate memory for hex buffer\n");
918
+            return NULL;
919
+        }
920
+
921
+        memset(tmp_buffer, '0', norm_len+1);
922
+        memset(hex_buffer, '0', norm_len+1);
923
+
924
+        if (byte_len == 1) {
925
+            tmp_buffer[0] = buffer[0];
926
+        } else {
927
+
928
+            if (norm_len == byte_len + 1) {
929
+                opt_val = opt;
930
+                if (cli_bcomp_chk_hex(buffer, opt_val, byte_len, 1)) {
931
+                    memcpy(hex_buffer+3, buffer+2, byte_len-2);
932
+                    hex_buffer[0] = 'x';
933
+                } else {
934
+                    memcpy(hex_buffer+1, buffer, byte_len);
935
+                }
936
+            } else {
937
+                opt_val = opt;
938
+                memcpy(hex_buffer, buffer, byte_len);
939
+                if (cli_bcomp_chk_hex(buffer, opt_val, byte_len, 1)) {
940
+                    hex_buffer[0] = 'x';
941
+                }
942
+            }
943
+
944
+            for (i = 0; i < norm_len; i = i+2) {
945
+                if (((int32_t) norm_len - (int32_t) i) - 2 >= 0) {
946
+                    /* 0000BA -> B0000A */
947
+                    if ( isxdigit(hex_buffer[norm_len-i-2]) || toupper(hex_buffer[norm_len-i-2]) == 'X' ) {
948
+                        if ( isxdigit(hex_buffer[norm_len-i-2]) ) {
949
+                            hex = 1;
950
+                        }
951
+                        tmp_buffer[i] = hex_buffer[norm_len-i-2];
952
+                    } else {
953
+                        /* non-hex detected, our current buffer is invalid so zero it out and continue */
954
+                        memset(tmp_buffer, '0', norm_len+1);
955
+                        hex = 0;
956
+                    }
957
+                }
958
+
959
+                /* 0000BA -> 0A00B0 */
960
+                if ( isxdigit(hex_buffer[norm_len-i-1]) || toupper(hex_buffer[norm_len-i-1]) == 'X' ) {
961
+                        if ( isxdigit(hex_buffer[norm_len-i-2]) ) {
962
+                            hex = 1;
963
+                        }
964
+                        tmp_buffer[i+1] = hex_buffer[norm_len-i-1];
965
+                } else {
966
+                    /* non-hex detected, our current buffer is invalid so zero it out and continue */
967
+                    memset(tmp_buffer, '0', norm_len+1);
968
+                    hex = 0;
969
+                }
970
+            }
971
+        }
972
+        tmp_buffer[norm_len+1] = '\0';
973
+        bcm_dbgmsg("cli_bcomp_compare_check: normalized extracted bytes before comparison %.*s\n", byte_len, tmp_buffer);
974
+    }
975
+
976
+    return tmp_buffer;
977
+}
978
+
979
+/**
821 980
  * @brief cleans up the byte compare data struct
822 981
  *
823 982
  * @param root the root matcher struct whose mempool instance the bcomp struct has been allocated with
... ...
@@ -64,7 +64,10 @@ struct cli_bcomp_comp {
64 64
 
65 65
 cl_error_t cli_bcomp_addpatt(struct cli_matcher *root, const char *virname, const char* hexsig, const uint32_t *lsigid, unsigned int options);
66 66
 cl_error_t cli_bcomp_scanbuf(const unsigned char *buffer, size_t buffer_length, const char **virname, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, cli_ctx *ctx);
67
-cl_error_t cli_bcomp_compare_check(const unsigned char *buffer, size_t buffer_length, int offset, struct cli_bcomp_meta *bm);
67
+cl_error_t cli_bcomp_compare_check(const unsigned char *f_buffer, size_t buffer_length, int offset, struct cli_bcomp_meta *bm);
68 68
 void cli_bcomp_freemeta(struct cli_matcher *root, struct cli_bcomp_meta *bm);
69
+uint16_t cli_bcomp_chk_hex(const unsigned char* buffer, uint16_t opt, uint32_t len, uint32_t check_only);
70
+unsigned char* cli_bcomp_normalize_buffer(const unsigned char* buffer, uint32_t byte_len, uint32_t *pad_len,  uint16_t opt, uint16_t whitespace_only);
71
+
69 72
 
70 73
 #endif