Coverage Report

Created: 2025-11-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/detect-engine-file.c
Line
Count
Source
1
/* Copyright (C) 2007-2021 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
/**
19
 * \file
20
 *
21
 * \author Victor Julien <victor@inliniac.net>
22
 */
23
24
#include "suricata-common.h"
25
26
#include "decode.h"
27
28
#include "detect.h"
29
#include "detect-engine.h"
30
#include "detect-parse.h"
31
#include "detect-engine-state.h"
32
33
#include "detect-filestore.h"
34
35
#include "detect-engine-dcepayload.h"
36
#include "detect-engine-file.h"
37
38
#include "stream-tcp.h"
39
#include "stream-tcp-private.h"
40
#include "stream-tcp-reassemble.h"
41
42
#include "app-layer-parser.h"
43
#include "app-layer-protos.h"
44
#include "app-layer-htp.h"
45
#include "app-layer-smtp.h"
46
47
#include "util-unittest.h"
48
#include "util-unittest-helper.h"
49
#include "util-profiling.h"
50
#include "util-validate.h"
51
52
/**
53
 *  \brief Inspect the file inspecting keywords.
54
 *
55
 *  \param tv thread vars
56
 *  \param det_ctx detection engine thread ctx
57
 *  \param f flow
58
 *  \param s signature to inspect
59
 *
60
 *  \retval 0 no match
61
 *  \retval 1 match
62
 *  \retval 2 can't match
63
 *  \retval 3 can't match filestore signature
64
 */
65
static uint8_t DetectFileInspect(DetectEngineThreadCtx *det_ctx, Flow *f, const Signature *s,
66
        const SigMatchData *smd, uint8_t flags, FileContainer *ffc)
67
23.1k
{
68
23.1k
    uint8_t r = 0;
69
23.1k
    int match = 0;
70
23.1k
    int store_r = 0;
71
72
23.1k
    SCLogDebug("file inspection... %p", ffc);
73
74
46.2k
    for (File *file = ffc->head; file != NULL; file = file->next) {
75
23.1k
        SCLogDebug("file");
76
77
23.1k
        if (file->state == FILE_STATE_NONE) {
78
0
            SCLogDebug("file state FILE_STATE_NONE");
79
0
            continue;
80
0
        }
81
82
23.1k
        if ((s->file_flags & FILE_SIG_NEED_FILENAME) && file->name == NULL) {
83
0
            SCLogDebug("sig needs filename, but we don't have any");
84
0
            r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
85
0
            continue;
86
0
        }
87
88
23.1k
        uint64_t file_size = FileDataSize(file);
89
23.1k
        if ((s->file_flags & FILE_SIG_NEED_MAGIC) && file_size == 0) {
90
0
            SCLogDebug("sig needs file content, but we don't have any");
91
0
            r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
92
0
            continue;
93
0
        }
94
95
23.1k
        if ((s->file_flags & FILE_SIG_NEED_FILECONTENT) && file_size == 0) {
96
0
            SCLogDebug("sig needs file content, but we don't have any");
97
0
            r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
98
0
            continue;
99
0
        }
100
101
23.1k
        if ((s->file_flags & FILE_SIG_NEED_MD5) && (!(file->flags & FILE_MD5))) {
102
0
            SCLogDebug("sig needs file md5, but we don't have any");
103
0
            r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
104
0
            continue;
105
0
        }
106
107
23.1k
        if ((s->file_flags & FILE_SIG_NEED_SHA1) && (!(file->flags & FILE_SHA1))) {
108
0
            SCLogDebug("sig needs file sha1, but we don't have any");
109
0
            r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
110
0
            continue;
111
0
        }
112
113
23.1k
        if ((s->file_flags & FILE_SIG_NEED_SHA256) && (!(file->flags & FILE_SHA256))) {
114
0
            SCLogDebug("sig needs file sha256, but we don't have any");
115
0
            r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
116
0
            continue;
117
0
        }
118
119
23.1k
        if ((s->file_flags & FILE_SIG_NEED_SIZE) && file->state < FILE_STATE_CLOSED) {
120
89
            SCLogDebug("sig needs filesize, but state < FILE_STATE_CLOSED");
121
89
            r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
122
89
            continue;
123
89
        }
124
125
        /* run the file match functions. */
126
23.0k
        while (1) {
127
23.0k
            SCLogDebug("smd %p", smd);
128
129
23.0k
            if (sigmatch_table[smd->type].FileMatch != NULL) {
130
23.0k
                KEYWORD_PROFILING_START;
131
23.0k
                match = sigmatch_table[smd->type].FileMatch(det_ctx, f, flags, file, s, smd->ctx);
132
23.0k
                KEYWORD_PROFILING_END(det_ctx, smd->type, (match > 0));
133
23.0k
                if (match == 0) {
134
70
                    r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES;
135
70
                    break;
136
23.0k
                } else if (smd->is_last) {
137
22.9k
                    r = DETECT_ENGINE_INSPECT_SIG_MATCH;
138
22.9k
                    break;
139
22.9k
                }
140
23.0k
            }
141
15
            if (smd->is_last)
142
0
                break;
143
15
            smd++;
144
15
        }
145
146
        /* continue inspection for other files as we may want to store
147
         * those as well. We'll return 1 (match) regardless of their
148
         * results though */
149
23.0k
        if (r == DETECT_ENGINE_INSPECT_SIG_MATCH)
150
22.9k
            store_r = DETECT_ENGINE_INSPECT_SIG_MATCH;
151
152
        /* continue, this file may (or may not) be unable to match
153
         * maybe we have more that can :) */
154
23.0k
    }
155
156
23.1k
    if (r == DETECT_ENGINE_INSPECT_SIG_NO_MATCH && store_r == DETECT_ENGINE_INSPECT_SIG_MATCH) {
157
0
        SCLogDebug("stored MATCH, current file NOMATCH");
158
0
        SCReturnInt(DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES);
159
0
    }
160
161
23.1k
    if (store_r == DETECT_ENGINE_INSPECT_SIG_MATCH)
162
22.9k
        r = DETECT_ENGINE_INSPECT_SIG_MATCH;
163
23.1k
    SCReturnInt(r);
164
23.1k
}
165
166
/**
167
 *  \brief Inspect the file inspecting keywords against the state
168
 *
169
 *  \param det_ctx detection engine thread ctx
170
 *  \param f flow
171
 *  \param s signature to inspect
172
 *  \param alstate state
173
 *  \param flags direction flag
174
 *
175
 *  \retval 0 no match
176
 *  \retval 1 match
177
 *  \retval 2 can't match
178
 *  \retval 3 can't match filestore signature
179
 *
180
 *  \note flow is not locked at this time
181
 */
182
uint8_t DetectFileInspectGeneric(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
183
        const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f,
184
        uint8_t flags, void *alstate, void *tx, uint64_t tx_id)
185
52.5k
{
186
52.5k
    SCEnter();
187
52.5k
    DEBUG_VALIDATE_BUG_ON(f->alstate != alstate);
188
189
52.5k
    const uint8_t direction = flags & (STREAM_TOSERVER|STREAM_TOCLIENT);
190
52.5k
    AppLayerGetFileState files = AppLayerParserGetTxFiles(f, alstate, tx, direction);
191
52.5k
    FileContainer *ffc = files.fc;
192
52.5k
    SCLogDebug("tx %p tx_id %" PRIu64 " ffc %p ffc->head %p sid %u", tx, tx_id, ffc,
193
52.5k
            ffc ? ffc->head : NULL, s->id);
194
52.5k
    if (ffc == NULL) {
195
21.0k
        SCReturnInt(DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES);
196
31.5k
    } else if (ffc->head == NULL) {
197
8.35k
        SCReturnInt(DETECT_ENGINE_INSPECT_SIG_NO_MATCH);
198
8.35k
    }
199
200
23.1k
    uint8_t r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
201
23.1k
    uint8_t match = DetectFileInspect(det_ctx, f, s, engine->smd, flags, ffc);
202
23.1k
    if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) {
203
22.9k
        r = DETECT_ENGINE_INSPECT_SIG_MATCH;
204
22.9k
    } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) {
205
0
        SCLogDebug("sid %u can't match on this transaction", s->id);
206
0
        r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
207
159
    } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES) {
208
70
        SCLogDebug("sid %u can't match on this transaction (file sig)", s->id);
209
70
        r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES;
210
89
    } else if (match == DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES) {
211
0
        SCLogDebug("match with more files ahead");
212
0
        r = match;
213
0
    }
214
215
23.1k
    SCReturnInt(r);
216
52.5k
}