]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect/filemagic: switch to file.magic implementation
authorVictor Julien <vjulien@oisf.net>
Fri, 16 Jun 2023 13:07:13 +0000 (15:07 +0200)
committerVictor Julien <vjulien@oisf.net>
Wed, 5 Jul 2023 19:35:37 +0000 (21:35 +0200)
Replace implementation of the legacy `filemagic` keyword by the
implementation for the `file.magic` variant. This leads to better
performance and hooks the rules into the detection engine better.

Remove unittests that depended on the old logic.

Ticket: #6194.

src/detect-filemagic.c

index 628aa842fd9c21423466e11e35bc5d7806205ff4..f7ff87c99945f47bcaf283522623dada011edcf2 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2022 Open Information Security Foundation
+/* Copyright (C) 2007-2023 Open Information Security Foundation
  *
  * You can copy, redistribute or modify this Program under the terms of
  * the GNU General Public License version 2 as published by the Free
@@ -84,20 +84,7 @@ typedef struct DetectFilemagicThreadData {
     magic_t ctx;
 } DetectFilemagicThreadData;
 
-typedef struct DetectFilemagicData {
-    uint8_t *name; /** name of the file to match */
-    BmCtx *bm_ctx; /** BM context */
-    uint16_t len;  /** name length */
-    uint32_t flags;
-} DetectFilemagicData;
-
-static int DetectFilemagicMatch (DetectEngineThreadCtx *, Flow *,
-        uint8_t, File *, const Signature *, const SigMatchCtx *);
-static int DetectFilemagicSetup (DetectEngineCtx *, Signature *, const char *);
-#ifdef UNITTESTS
-static void DetectFilemagicRegisterTests(void);
-#endif
-static void DetectFilemagicFree(DetectEngineCtx *, void *);
+static int DetectFilemagicSetup(DetectEngineCtx *, Signature *, const char *);
 static int g_file_match_list_id = 0;
 
 static int DetectFilemagicSetupSticky(DetectEngineCtx *de_ctx, Signature *s, const char *str);
@@ -119,12 +106,7 @@ void DetectFilemagicRegister(void)
     sigmatch_table[DETECT_FILEMAGIC].name = "filemagic";
     sigmatch_table[DETECT_FILEMAGIC].desc = "match on the information libmagic returns about a file";
     sigmatch_table[DETECT_FILEMAGIC].url = "/rules/file-keywords.html#filemagic";
-    sigmatch_table[DETECT_FILEMAGIC].FileMatch = DetectFilemagicMatch;
     sigmatch_table[DETECT_FILEMAGIC].Setup = DetectFilemagicSetup;
-    sigmatch_table[DETECT_FILEMAGIC].Free  = DetectFilemagicFree;
-#ifdef UNITTESTS
-    sigmatch_table[DETECT_FILEMAGIC].RegisterTests = DetectFilemagicRegisterTests;
-#endif
     sigmatch_table[DETECT_FILEMAGIC].flags = SIGMATCH_QUOTES_MANDATORY|SIGMATCH_HANDLE_NEGATION;
     sigmatch_table[DETECT_FILEMAGIC].alternative = DETECT_FILE_MAGIC;
 
@@ -194,127 +176,6 @@ int FilemagicThreadLookup(magic_t *ctx, File *file)
     SCReturnInt(0);
 }
 
-/**
- * \brief match the specified filemagic
- *
- * \param t thread local vars
- * \param det_ctx pattern matcher thread local data
- * \param f *LOCKED* flow
- * \param flags direction flags
- * \param file file being inspected
- * \param s signature being inspected
- * \param m sigmatch that we will cast into DetectFilemagicData
- *
- * \retval 0 no match
- * \retval 1 match
- */
-static int DetectFilemagicMatch (DetectEngineThreadCtx *det_ctx,
-        Flow *f, uint8_t flags, File *file, const Signature *s, const SigMatchCtx *m)
-{
-    SCEnter();
-    int ret = 0;
-    DetectFilemagicData *filemagic = (DetectFilemagicData *)m;
-
-    DetectFilemagicThreadData *tfilemagic =
-        (DetectFilemagicThreadData *)DetectThreadCtxGetKeywordThreadCtx(det_ctx, g_magic_thread_ctx_id);
-    if (tfilemagic == NULL) {
-        SCReturnInt(0);
-    }
-
-    if (file->magic == NULL) {
-        FilemagicThreadLookup(&tfilemagic->ctx, file);
-    }
-
-    if (file->magic != NULL) {
-        SCLogDebug("magic %s", file->magic);
-
-        /* we include the \0 in the inspection, so patterns can match on the
-         * end of the string. */
-        if (BoyerMooreNocase(filemagic->name, filemagic->len, (uint8_t *)file->magic,
-                    strlen(file->magic) + 1, filemagic->bm_ctx) != NULL)
-        {
-#ifdef DEBUG
-            if (SCLogDebugEnabled()) {
-                char *name = SCMalloc(filemagic->len + 1);
-                if (name != NULL) {
-                    memcpy(name, filemagic->name, filemagic->len);
-                    name[filemagic->len] = '\0';
-                    SCLogDebug("will look for filemagic %s", name);
-                    SCFree(name);
-                }
-            }
-#endif
-
-            if (!(filemagic->flags & DETECT_CONTENT_NEGATED)) {
-                ret = 1;
-            }
-        } else if (filemagic->flags & DETECT_CONTENT_NEGATED) {
-            SCLogDebug("negated match");
-            ret = 1;
-        }
-    }
-
-    SCReturnInt(ret);
-}
-
-/**
- * \brief Parse the filemagic keyword
- *
- * \param de_ctx Pointer to the detection engine context
- * \param idstr Pointer to the user provided option
- *
- * \retval filemagic pointer to DetectFilemagicData on success
- * \retval NULL on failure
- */
-static DetectFilemagicData *DetectFilemagicParse (DetectEngineCtx *de_ctx, const char *str, bool negate)
-{
-    DetectFilemagicData *filemagic = NULL;
-
-    /* We have a correct filemagic option */
-    filemagic = SCMalloc(sizeof(DetectFilemagicData));
-    if (unlikely(filemagic == NULL))
-        goto error;
-
-    memset(filemagic, 0x00, sizeof(DetectFilemagicData));
-
-    if (DetectContentDataParse ("filemagic", str, &filemagic->name, &filemagic->len) == -1) {
-        goto error;
-    }
-
-    filemagic->bm_ctx = BoyerMooreNocaseCtxInit(filemagic->name, filemagic->len);
-    if (filemagic->bm_ctx == NULL) {
-        goto error;
-    }
-
-    if (negate) {
-        filemagic->flags |= DETECT_CONTENT_NEGATED;
-    }
-
-    SCLogDebug("flags %02X", filemagic->flags);
-    if (filemagic->flags & DETECT_CONTENT_NEGATED) {
-        SCLogDebug("negated filemagic");
-    }
-
-#ifdef DEBUG
-    if (SCLogDebugEnabled()) {
-        char *name = SCMalloc(filemagic->len + 1);
-        if (name != NULL) {
-            memcpy(name, filemagic->name, filemagic->len);
-            name[filemagic->len] = '\0';
-            SCLogDebug("will look for filemagic %s", name);
-            SCFree(name);
-        }
-    }
-#endif
-
-    return filemagic;
-
-error:
-    if (filemagic != NULL)
-        DetectFilemagicFree(de_ctx, filemagic);
-    return NULL;
-}
-
 static void *DetectFilemagicThreadInit(void *data /*@unused@*/)
 {
     DetectFilemagicThreadData *t = SCCalloc(1, sizeof(DetectFilemagicThreadData));
@@ -359,54 +220,40 @@ static void DetectFilemagicThreadFree(void *ctx)
  */
 static int DetectFilemagicSetup (DetectEngineCtx *de_ctx, Signature *s, const char *str)
 {
-    SigMatch *sm = NULL;
+    if (s->init_data->transforms.cnt) {
+        SCLogError("previous transforms not consumed before 'filemagic'");
+        SCReturnInt(-1);
+    }
+    s->init_data->list = DETECT_SM_LIST_NOTSET;
+    s->file_flags |= (FILE_SIG_NEED_FILE | FILE_SIG_NEED_MAGIC);
 
-    DetectFilemagicData *filemagic = DetectFilemagicParse(de_ctx, str, s->init_data->negated);
-    if (filemagic == NULL)
+    if (DetectContentSetup(de_ctx, s, str) < 0) {
         return -1;
+    }
 
-    g_magic_thread_ctx_id = DetectRegisterThreadCtxFuncs(
-            de_ctx, "filemagic", DetectFilemagicThreadInit, NULL, DetectFilemagicThreadFree, 1);
-    if (g_magic_thread_ctx_id == -1)
-        goto error;
-
-    /* Okay so far so good, lets get this into a SigMatch
-     * and put it in the Signature. */
-    sm = SigMatchAlloc();
+    SigMatch *sm = DetectGetLastSMFromLists(s, DETECT_CONTENT, -1);
     if (sm == NULL)
-        goto error;
-
-    sm->type = DETECT_FILEMAGIC;
-    sm->ctx = (void *)filemagic;
-
-    SigMatchAppendSMToList(s, sm, g_file_match_list_id);
-
-    s->file_flags |= (FILE_SIG_NEED_FILE|FILE_SIG_NEED_MAGIC);
-    return 0;
+        return -1;
 
-error:
-    DetectFilemagicFree(de_ctx, filemagic);
-    if (sm != NULL)
-        SCFree(sm);
-    return -1;
-}
+    DetectContentData *cd = (DetectContentData *)sm->ctx;
+    cd->flags |= DETECT_CONTENT_NOCASE;
+    /* Recreate the context with nocase chars */
+    SpmDestroyCtx(cd->spm_ctx);
+    cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1, de_ctx->spm_global_thread_ctx);
+    if (cd->spm_ctx == NULL) {
+        return -1;
+    }
+    if (DetectEngineContentModifierBufferSetup(
+                de_ctx, s, NULL, DETECT_FILE_MAGIC, g_file_magic_buffer_id, s->alproto) < 0)
+        return -1;
 
-/**
- * \brief this function will free memory associated with DetectFilemagicData
- *
- * \param filemagic pointer to DetectFilemagicData
- */
-static void DetectFilemagicFree(DetectEngineCtx *de_ctx, void *ptr)
-{
-    if (ptr != NULL) {
-        DetectFilemagicData *filemagic = (DetectFilemagicData *)ptr;
-        if (filemagic->bm_ctx != NULL) {
-            BoyerMooreCtxDeInit(filemagic->bm_ctx);
-        }
-        if (filemagic->name != NULL)
-            SCFree(filemagic->name);
-        SCFree(filemagic);
+    if (g_magic_thread_ctx_id == -1) {
+        g_magic_thread_ctx_id = DetectRegisterThreadCtxFuncs(
+                de_ctx, "filemagic", DetectFilemagicThreadInit, NULL, DetectFilemagicThreadFree, 1);
+        if (g_magic_thread_ctx_id == -1)
+            return -1;
     }
+    return 0;
 }
 
 /* file.magic implementation */
@@ -577,54 +424,5 @@ static int PrefilterMpmFilemagicRegister(DetectEngineCtx *de_ctx, SigGroupHead *
             mpm_reg->app_v2.alproto, mpm_reg->app_v2.tx_min_progress,
             pectx, PrefilterMpmFilemagicFree, mpm_reg->pname);
 }
-#ifdef UNITTESTS /* UNITTESTS */
-
-/**
- * \test DetectFilemagicTestParse01
- */
-static int DetectFilemagicTestParse01 (void)
-{
-    DetectFilemagicData *dnd = DetectFilemagicParse(NULL, "secret.pdf", false);
-    FAIL_IF_NULL(dnd);
-    DetectFilemagicFree(NULL, dnd);
-    PASS;
-}
 
-/**
- * \test DetectFilemagicTestParse02
- */
-static int DetectFilemagicTestParse02 (void)
-{
-    DetectFilemagicData *dnd = DetectFilemagicParse(NULL, "backup.tar.gz", false);
-    FAIL_IF_NULL(dnd);
-    FAIL_IF_NOT(dnd->len == 13);
-    FAIL_IF_NOT(memcmp(dnd->name, "backup.tar.gz", 13) == 0);
-    DetectFilemagicFree(NULL, dnd);
-    PASS;
-}
-
-/**
- * \test DetectFilemagicTestParse03
- */
-static int DetectFilemagicTestParse03 (void)
-{
-    DetectFilemagicData *dnd = DetectFilemagicParse(NULL, "cmd.exe", false);
-    FAIL_IF_NULL(dnd);
-    FAIL_IF_NOT(dnd->len == 7);
-    FAIL_IF_NOT(memcmp(dnd->name, "cmd.exe", 7) == 0);
-    DetectFilemagicFree(NULL, dnd);
-    PASS;
-}
-
-/**
- * \brief this function registers unit tests for DetectFilemagic
- */
-void DetectFilemagicRegisterTests(void)
-{
-    UtRegisterTest("DetectFilemagicTestParse01", DetectFilemagicTestParse01);
-    UtRegisterTest("DetectFilemagicTestParse02", DetectFilemagicTestParse02);
-    UtRegisterTest("DetectFilemagicTestParse03", DetectFilemagicTestParse03);
-}
-#endif /* UNITTESTS */
 #endif /* HAVE_MAGIC */
-