Browse code

readdb: refactored yara rule verification code

Kevin Lin authored on 2015/06/25 01:47:01
Showing 1 changed files
... ...
@@ -229,7 +229,7 @@ int cli_sigopts_handler(struct cli_matcher *root, const char *virname, const cha
229 229
 
230 230
         /* clamav-specific wildcards need to be handled here! */
231 231
         for (i = 0; i < strlen(hexcpy); ++i) {
232
-            size_t len = strlen(hexovr);
232
+           size_t len = strlen(hexovr);
233 233
 
234 234
             if (hexcpy[i] == '*' || hexcpy[i] == '|' || hexcpy[i] == ')') {
235 235
                 hexovr[len] = hexcpy[i];
... ...
@@ -3254,18 +3254,28 @@ static void ytable_delete(struct cli_ytable *ytable)
3254 3254
     }
3255 3255
 }
3256 3256
 
3257
-static int yara_subhex_verify(const char *hexstr)
3257
+static int yara_subhex_verify(const char *hexstr, const char *end, size_t *maxsublen)
3258 3258
 {
3259
-    size_t max_sublen = 0;
3260
-    const char *track = hexstr;
3261
-    int in = 0;
3259
+    size_t sublen = 0;
3260
+    const char *track;
3261
+    char in = 0;
3262
+    int hexbyte = 0;
3262 3263
 
3263
-    /* REQUIRES - subpatterns must be at least length 2 */
3264
-    while (*track != '\0' && max_sublen < 4) {
3265
-        switch(*track) {
3264
+    if (hexstr == end) {
3265
+        cli_warnmsg("load_oneyara[verify]: string has empty sequence\n");
3266
+        return CL_EMALFDB;
3267
+    }
3268
+
3269
+    track = hexstr;
3270
+    while (track != end) {
3271
+        switch (*track) {
3266 3272
         case '*':
3267 3273
         case '?':
3268
-            max_sublen = 0;
3274
+            if (*track == '?')
3275
+                hexbyte = !hexbyte;
3276
+            if (maxsublen && (sublen > *maxsublen))
3277
+                *maxsublen = sublen;
3278
+            sublen = 0;
3269 3279
             break;
3270 3280
         case '[':
3271 3281
         case '{':
... ...
@@ -3273,71 +3283,120 @@ static int yara_subhex_verify(const char *hexstr)
3273 3273
                 cli_warnmsg("load_oneyara[verify]: string has invalid nesting\n");
3274 3274
                 return CL_EMALFDB;
3275 3275
             }
3276
-            in = 1;
3276
+            if (hexbyte) {
3277
+                cli_warnmsg("load_oneyara[verify]: string has invalid hex sequence\n");
3278
+                return CL_EMALFDB;
3279
+            }
3280
+            if (maxsublen && (sublen > *maxsublen))
3281
+                *maxsublen = sublen;
3282
+            sublen = 0;
3283
+            in = *track;
3277 3284
             break;
3278 3285
         case ']':
3286
+            if (in != '[') {
3287
+                cli_warnmsg("load_oneyara[verify]: string has invalid ranged anchored\n");
3288
+                return CL_EMALFDB;
3289
+            }
3290
+            in = 0;
3291
+            break;
3279 3292
         case '}':
3280
-            if (!in) {
3281
-                cli_warnmsg("load_oneyara[verify]: string has invalid sequence close\n");
3293
+            if (in != '{') {
3294
+                cli_warnmsg("load_oneyara[verify]: string has invalid ranged wildcard\n");
3282 3295
                 return CL_EMALFDB;
3283 3296
             }
3284 3297
             in = 0;
3285 3298
             break;
3286 3299
         default:
3287
-            max_sublen++;
3300
+            if (!in) {
3301
+                if ((*track >= 'A' && *track <= 'F') ||
3302
+                    (*track >= 'a' && *track <= 'f') ||
3303
+                    (*track >= '0' && *track <= '9')) {
3304
+
3305
+                    hexbyte = !hexbyte;
3306
+                    sublen++;
3307
+                } else {
3308
+                    cli_warnmsg("load_oneyara[verify]: unknown character: %x\n", *track);
3309
+                    return CL_EMALFDB;
3310
+                }
3311
+            }
3288 3312
             break;
3289 3313
         }
3290 3314
 
3291 3315
         track++;
3292 3316
     }
3317
+
3293 3318
     if (in) {
3294
-        cli_warnmsg("load_oneyara[verify]: string has unterminated sequence\n");
3319
+        cli_warnmsg("load_oneyara[verify]: string has unterminated wildcard sequence\n");
3295 3320
         return CL_EMALFDB;
3296 3321
     }
3297
-    if (max_sublen < 4) {
3298
-        cli_warnmsg("load_oneyara[verify]: cannot find a static subpattern of length 2\n");
3322
+    if (hexbyte) {
3323
+        cli_warnmsg("load_oneyara[verify]: string has invalid hex sequence\n");
3299 3324
         return CL_EMALFDB;
3300 3325
     }
3326
+    if (maxsublen && (sublen > *maxsublen))
3327
+        *maxsublen = sublen;
3301 3328
 
3302 3329
     return CL_SUCCESS;
3303 3330
 }
3304 3331
 
3305
-static int yara_altstr_verify(const char *hexstr)
3332
+static int yara_altstr_verify(const char *hexstr, int lvl, const char **end)
3306 3333
 {
3307
-    const char *end;
3308
-    int i, range, lvl = 0;
3309
-
3310
-    for (i = 0; i < strlen(hexstr); i++) {
3311
-        if (hexstr[i] == '(') {
3312
-            lvl++;
3313
-            if (lvl > ACPATT_ALTN_MAXNEST) {
3314
-                cli_warnmsg("load_oneyara[verify]: string has unsupported alternating sequence (nest level)\n");
3315
-                return CL_EMALFDB;
3316
-            }
3317
-        } else if (hexstr[i] == ')') {
3318
-            if (!lvl) {
3319
-                break;
3320
-            }
3321
-        } else if (hexstr[i] == '{') { /* clamav converted '[' */
3322
-            end = &hexstr[i];
3323
-            while (*end != '}' && *end != '-' && *end != '\0')
3324
-                end++;
3334
+    const char *track, *sub;
3335
+    int ret, range;
3336
+    size_t offset;
3325 3337
 
3326
-            switch (*end) {
3327
-            case '\0':
3328
-                cli_warnmsg("load_oneyara[verify]: string has unsupported alternating sequence (unterminated ranged wildcard)\n");
3329
-                return CL_EMALFDB;
3330
-            case '-':
3331
-                cli_warnmsg("load_oneyara[verify]: string has unsupported alternating sequence (variable ranged wildcard)\n");
3332
-                return CL_EMALFDB;
3333
-            case '}':
3334
-                sscanf(&hexstr[i], "{%d}", &range);
3335
-                if (range >= 128) {
3336
-                    cli_warnmsg("load_oneyara[verify]: string has unsupported alternating sequence (128+ ranged wildcard)\n");
3338
+    if (lvl > ACPATT_ALTN_MAXNEST) {
3339
+        cli_warnmsg("load_oneyara[verify]: string has unsupported alternate sequence (nest level)\n");
3340
+        return CL_EMALFDB;
3341
+    }
3342
+
3343
+    track = hexstr;
3344
+    while ((offset = strcspn(track, "(|){}"))) {
3345
+        sub = track + offset;
3346
+        if (*sub == '\0') {
3347
+            cli_warnmsg("load_oneyara[verify]: string has unterminated alternate sequence\n");
3348
+            return CL_EMALFDB;
3349
+        }
3350
+
3351
+        /* verify subhex */
3352
+        if ((ret = yara_subhex_verify(track, sub, NULL)) != CL_SUCCESS)
3353
+            return ret;
3354
+
3355
+        track = sub;
3356
+        if (*track == '(') {
3357
+            if ((ret = yara_altstr_verify(track+1, lvl+1, &sub)) != CL_SUCCESS)
3358
+                return ret;
3359
+        } else if (*track == ')') {
3360
+            if (end)
3361
+                *end = track;
3362
+            break;
3363
+        } else if (*track == '{') { /* clamav converted '[' */
3364
+            if ((offset = strcspn(track, "}-"))) {
3365
+                sub = track + offset;
3366
+                switch (*sub) {
3367
+                case '\0':
3368
+                    cli_warnmsg("load_oneyara[verify]: string has unsupported alternating sequence (unterminated ranged wildcard)\n");
3337 3369
                     return CL_EMALFDB;
3370
+                case '-':
3371
+                    cli_warnmsg("load_oneyara[verify]: string has unsupported alternating sequence (variable ranged wildcard)\n");
3372
+                    return CL_EMALFDB;
3373
+                case '}':
3374
+                    sscanf(track, "{%d}", &range);
3375
+                    if (range >= 128) {
3376
+                        cli_warnmsg("load_oneyara[verify]: string has unsupported alternating sequence (128+ ranged wildcard)\n");
3377
+                        return CL_EMALFDB;
3378
+                    }
3338 3379
                 }
3380
+            } else {
3381
+                cli_warnmsg("load_oneyara[verify]: string has unsupported alternating sequence (unterminated ranged wildcard)\n");
3382
+                return CL_EMALFDB;
3339 3383
             }
3384
+        } else if (*track != '|') {
3385
+            cli_warnmsg("load_oneyara[verify]: string has unsupported alternating sequence (invalid sequence)\n");
3386
+            return CL_EMALFDB;
3340 3387
         }
3388
+
3389
+        track = ++sub;
3341 3390
     }
3342 3391
 
3343 3392
     return CL_SUCCESS;
... ...
@@ -3347,7 +3406,8 @@ static int yara_altstr_verify(const char *hexstr)
3347 3347
 static int yara_hexstr_verify(YR_STRING *string, const char *hexstr)
3348 3348
 {
3349 3349
     int ret = CL_SUCCESS;
3350
-    char *hexcpy, *track, *alt;
3350
+    const char *track, *end;
3351
+    size_t maxsublen = 0, length;
3351 3352
 
3352 3353
     /* Quick Check 1: NULL String */
3353 3354
     if (!hexstr || !string) {
... ...
@@ -3362,35 +3422,33 @@ static int yara_hexstr_verify(YR_STRING *string, const char *hexstr)
3362 3362
     }
3363 3363
 
3364 3364
     /* Long Check: No Alternating Strings, Subhex must be Length 2 */
3365
-    hexcpy = cli_strdup(hexstr);
3366
-    if (!hexcpy)
3367
-        return CL_EMEM;
3368
-    track = hexcpy;
3369
-    while ((alt = strchr(track, '('))) {
3370
-        char *start = alt+1;
3371
-        *alt = '\0';
3372
-
3373
-        alt = strchr(start, ')');
3374
-        *alt = '\0';
3365
+    track = hexstr;
3366
+    while ((end = strchr(track, '('))) {
3367
+        if (track != end) {
3368
+            if ((ret = yara_subhex_verify(track, end, &maxsublen)) != CL_SUCCESS)
3369
+                return ret;
3370
+        }
3375 3371
 
3376
-        ret = yara_subhex_verify(track);
3377
-        if (ret != CL_SUCCESS) {
3378
-            free(hexcpy);
3372
+        track = end + 1;
3373
+        if ((ret = yara_altstr_verify(track, 0, &end)) != CL_SUCCESS)
3379 3374
             return ret;
3380
-        }
3381 3375
 
3382
-        ret = yara_altstr_verify(start);
3383
-        if (ret != CL_SUCCESS) {
3384
-            free(hexcpy);
3376
+        track = end + 1;
3377
+    }
3378
+
3379
+    /* Check: Suffix (or Non-Alt Hex) */
3380
+    length = strlen(track);
3381
+    if (length > 0)
3382
+        if ((ret = yara_subhex_verify(track, track + length, &maxsublen)) != CL_SUCCESS)
3385 3383
             return ret;
3386
-        }
3387 3384
 
3388
-        track = alt+1;
3385
+    /* REQUIRES - Subpatterns must be at least length 2 */
3386
+    if (maxsublen < 2) {
3387
+        cli_warnmsg("load_oneyara[verify]: cannot find a static subpattern of length 2\n");
3388
+        return CL_EMALFDB;
3389 3389
     }
3390
-    ret = yara_subhex_verify(track);
3391
-    free(hexcpy);
3392 3390
 
3393
-    return ret;
3391
+    return CL_SUCCESS;
3394 3392
 }
3395 3393
 
3396 3394
 static unsigned int yara_total, yara_loaded, yara_malform, yara_empty, yara_complex;