Vulnerability: An issue was discovered in Oniguruma 6.2.0, as used in Oniguruma-mod in Ruby through 2.4.1 and mbstring in PHP through 7.1.5. A SIGSEGV occurs in left_adjust_char_head() during regular expression compilation. Invalid handling of reg->dmax in forward_search_range() could result in an invalid pointer dereference, normally as an immediate denial-of-service condition.
Vulnerability ID: CVE-2017-9229
CWE: CWE-476
Severity score: 2.9
Project: https://github.com/kkos/oniguruma
Published: 2017-05-24
File: src/regexec.c
Commit message: fix #59 : access to invalid address by reg->dmax value
Commit author: K.Kosako

Vulnerable version (before fix):
 forward_search_range(regex_t* reg, const UChar* str, const UChar* end, UChar* s,     }     else {       if (reg->dmax != ONIG_INFINITE_DISTANCE) {         *low = p - reg->dmax;         if (*low > s) {           *low = onigenc_get_right_adjust_char_head_with_prev(reg->enc, s,                                           *low, (const UChar** )low_prev);           if (low_prev && IS_NULL(*low_prev))             *low_prev = onigenc_get_prev_char_head(reg->enc,                                                    (pprev ? pprev : s), *low);         }         else {           if (low_prev)             *low_prev = onigenc_get_prev_char_head(reg->enc,                                                    (pprev ? pprev : str), *low);         }       }     }

Fixed version (after fix):
 forward_search_range(regex_t* reg, const UChar* str, const UChar* end, UChar* s,     }     else {       if (reg->dmax != ONIG_INFINITE_DISTANCE) {         if (p - str < reg->dmax) {           *low = (UChar* )str;           if (low_prev)             *low_prev = onigenc_get_prev_char_head(reg->enc, str, *low);         }         else {           *low = p - reg->dmax;           if (*low > s) {             *low = onigenc_get_right_adjust_char_head_with_prev(reg->enc, s,                                                  *low, (const UChar** )low_prev);             if (low_prev && IS_NULL(*low_prev))               *low_prev = onigenc_get_prev_char_head(reg->enc,                                                      (pprev ? pprev : s), *low);           }           else {             if (low_prev)               *low_prev = onigenc_get_prev_char_head(reg->enc,                                                      (pprev ? pprev : str), *low);           }         }       }     }

Patch:
patch: @@ -3235,18 +3235,25 @@ forward_search_range(regex_t* reg, const UChar* str, const UChar* end, UChar* s,
     }
     else {
       if (reg->dmax != ONIG_INFINITE_DISTANCE) {
-        *low = p - reg->dmax;
-        if (*low > s) {
-          *low = onigenc_get_right_adjust_char_head_with_prev(reg->enc, s,
-                                          *low, (const UChar** )low_prev);
-          if (low_prev && IS_NULL(*low_prev))
-            *low_prev = onigenc_get_prev_char_head(reg->enc,
-                                                   (pprev ? pprev : s), *low);
+        if (p - str < reg->dmax) {
+          *low = (UChar* )str;
+          if (low_prev)
+            *low_prev = onigenc_get_prev_char_head(reg->enc, str, *low);
         }
         else {
-          if (low_prev)
-            *low_prev = onigenc_get_prev_char_head(reg->enc,
-                                                   (pprev ? pprev : str), *low);
+          *low = p - reg->dmax;
+          if (*low > s) {
+            *low = onigenc_get_right_adjust_char_head_with_prev(reg->enc, s,
+                                                 *low, (const UChar** )low_prev);
+            if (low_prev && IS_NULL(*low_prev))
+              *low_prev = onigenc_get_prev_char_head(reg->enc,
+                                                     (pprev ? pprev : s), *low);
+          }
+          else {
+            if (low_prev)
+              *low_prev = onigenc_get_prev_char_head(reg->enc,
+                                                     (pprev ? pprev : str), *low);
+          }
         }
       }
     }
path: src/regexec.c