• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

62.86
/src/detect-engine-file.c
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
{
873✔
68
    uint8_t r = 0;
873✔
69
    int match = 0;
873✔
70
    int store_r = 0;
873✔
71

72
    SCLogDebug("file inspection... %p", ffc);
873✔
73

74
    for (File *file = ffc->head; file != NULL; file = file->next) {
1,746✔
75
        SCLogDebug("file");
873✔
76

77
        if (file->state == FILE_STATE_NONE) {
873✔
78
            SCLogDebug("file state FILE_STATE_NONE");
×
79
            continue;
×
80
        }
×
81

82
        if ((s->file_flags & FILE_SIG_NEED_FILENAME) && file->name == NULL) {
873✔
83
            SCLogDebug("sig needs filename, but we don't have any");
×
84
            r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
×
85
            continue;
×
86
        }
×
87

88
        uint64_t file_size = FileDataSize(file);
873✔
89
        if ((s->file_flags & FILE_SIG_NEED_MAGIC) && file_size == 0) {
873✔
90
            SCLogDebug("sig needs file content, but we don't have any");
×
91
            r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
×
92
            continue;
×
93
        }
×
94

95
        if ((s->file_flags & FILE_SIG_NEED_FILECONTENT) && file_size == 0) {
873✔
96
            SCLogDebug("sig needs file content, but we don't have any");
×
97
            r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
×
98
            continue;
×
99
        }
×
100

101
        if ((s->file_flags & FILE_SIG_NEED_MD5) && (!(file->flags & FILE_MD5))) {
873✔
UNCOV
102
            SCLogDebug("sig needs file md5, but we don't have any");
×
UNCOV
103
            r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
×
UNCOV
104
            continue;
×
UNCOV
105
        }
×
106

107
        if ((s->file_flags & FILE_SIG_NEED_SHA1) && (!(file->flags & FILE_SHA1))) {
873✔
108
            SCLogDebug("sig needs file sha1, but we don't have any");
×
109
            r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
×
110
            continue;
×
111
        }
×
112

113
        if ((s->file_flags & FILE_SIG_NEED_SHA256) && (!(file->flags & FILE_SHA256))) {
873✔
UNCOV
114
            SCLogDebug("sig needs file sha256, but we don't have any");
×
UNCOV
115
            r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
×
UNCOV
116
            continue;
×
UNCOV
117
        }
×
118

119
        if ((s->file_flags & FILE_SIG_NEED_SIZE) && file->state < FILE_STATE_CLOSED) {
873✔
120
            SCLogDebug("sig needs filesize, but state < FILE_STATE_CLOSED");
74✔
121
            r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
74✔
122
            continue;
74✔
123
        }
74✔
124

125
        /* run the file match functions. */
126
        while (1) {
799✔
127
            SCLogDebug("smd %p", smd);
799✔
128

129
            if (sigmatch_table[smd->type].FileMatch != NULL) {
799✔
130
                KEYWORD_PROFILING_START;
799✔
131
                match = sigmatch_table[smd->type].FileMatch(det_ctx, f, flags, file, s, smd->ctx);
799✔
132
                KEYWORD_PROFILING_END(det_ctx, smd->type, (match > 0));
799✔
133
                if (match == 0) {
799✔
134
                    r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES;
65✔
135
                    break;
65✔
136
                } else if (smd->is_last) {
734✔
137
                    r = DETECT_ENGINE_INSPECT_SIG_MATCH;
734✔
138
                    break;
734✔
139
                }
734✔
140
            }
799✔
141
            if (smd->is_last)
×
142
                break;
×
143
            smd++;
×
144
        }
×
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
        if (r == DETECT_ENGINE_INSPECT_SIG_MATCH)
799✔
150
            store_r = DETECT_ENGINE_INSPECT_SIG_MATCH;
734✔
151

152
        /* continue, this file may (or may not) be unable to match
153
         * maybe we have more that can :) */
154
    }
799✔
155

156
    if (r == DETECT_ENGINE_INSPECT_SIG_NO_MATCH && store_r == DETECT_ENGINE_INSPECT_SIG_MATCH) {
873✔
157
        SCLogDebug("stored MATCH, current file NOMATCH");
×
158
        SCReturnInt(DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES);
×
159
    }
×
160

161
    if (store_r == DETECT_ENGINE_INSPECT_SIG_MATCH)
873✔
162
        r = DETECT_ENGINE_INSPECT_SIG_MATCH;
734✔
163
    SCReturnInt(r);
873✔
164
}
873✔
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
{
8,411✔
186
    SCEnter();
8,411✔
187
    DEBUG_VALIDATE_BUG_ON(f->alstate != alstate);
8,411✔
188

189
    const uint8_t direction = flags & (STREAM_TOSERVER|STREAM_TOCLIENT);
8,411✔
190
    AppLayerGetFileState files = AppLayerParserGetTxFiles(f, tx, direction);
8,411✔
191
    FileContainer *ffc = files.fc;
8,411✔
192
    SCLogDebug("tx %p tx_id %" PRIu64 " ffc %p ffc->head %p sid %u", tx, tx_id, ffc,
8,411✔
193
            ffc ? ffc->head : NULL, s->id);
8,411✔
194
    if (ffc == NULL) {
8,411✔
195
        SCReturnInt(DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES);
7,434✔
196
    } else if (ffc->head == NULL) {
7,434✔
197
        SCReturnInt(DETECT_ENGINE_INSPECT_SIG_NO_MATCH);
104✔
198
    }
104✔
199

200
    uint8_t r = DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
873✔
201
    uint8_t match = DetectFileInspect(det_ctx, f, s, engine->smd, flags, ffc);
873✔
202
    if (match == DETECT_ENGINE_INSPECT_SIG_MATCH) {
873✔
203
        r = DETECT_ENGINE_INSPECT_SIG_MATCH;
734✔
204
    } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH) {
734✔
205
        SCLogDebug("sid %u can't match on this transaction", s->id);
×
206
        r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH;
×
207
    } else if (match == DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES) {
139✔
208
        SCLogDebug("sid %u can't match on this transaction (file sig)", s->id);
65✔
209
        r = DETECT_ENGINE_INSPECT_SIG_CANT_MATCH_FILES;
65✔
210
    } else if (match == DETECT_ENGINE_INSPECT_SIG_MATCH_MORE_FILES) {
74✔
211
        SCLogDebug("match with more files ahead");
×
212
        r = match;
×
213
    }
×
214

215
    SCReturnInt(r);
873✔
216
}
8,411✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc