Coverage Report

Created: 2025-11-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/util-storage.c
Line
Count
Source
1
/* Copyright (C) 2007-2013 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
 *  Storage API
24
 */
25
26
#include "suricata-common.h"
27
#include "util-unittest.h"
28
#include "util-storage.h"
29
#include "util-debug.h"
30
31
typedef struct StorageMapping_ {
32
    const char *name;
33
    StorageEnum type; // host, flow, tx, stream, ssn, etc
34
    unsigned int size;
35
    void *(*Alloc)(unsigned int);
36
    void (*Free)(void *);
37
} StorageMapping;
38
39
/** \brief list of StorageMapping used at registration time */
40
typedef struct StorageList_ {
41
    StorageMapping map;
42
    int id;
43
    struct StorageList_ *next;
44
} StorageList;
45
46
static StorageList *storage_list = NULL;
47
static int storage_max_id[STORAGE_MAX];
48
static int storage_registration_closed = 0;
49
static StorageMapping **storage_map = NULL;
50
51
static const char *StoragePrintType(StorageEnum type)
52
0
{
53
0
    switch(type) {
54
0
        case STORAGE_HOST:
55
0
            return "host";
56
0
        case STORAGE_FLOW:
57
0
            return "flow";
58
0
        case STORAGE_IPPAIR:
59
0
            return "ippair";
60
0
        case STORAGE_DEVICE:
61
0
            return "livedevice";
62
0
        case STORAGE_MAX:
63
0
            return "max";
64
0
    }
65
0
    return "invalid";
66
0
}
67
68
void StorageInit(void)
69
71
{
70
71
    memset(&storage_max_id, 0x00, sizeof(storage_max_id));
71
71
    storage_list = NULL;
72
71
    storage_map = NULL;
73
71
    storage_registration_closed = 0;
74
71
}
75
76
void StorageCleanup(void)
77
0
{
78
0
    if (storage_map) {
79
0
        int i;
80
0
        for (i = 0; i < STORAGE_MAX; i++) {
81
0
            if (storage_map[i] != NULL) {
82
0
                SCFree(storage_map[i]);
83
0
                storage_map[i] = NULL;
84
0
            }
85
0
        }
86
0
        SCFree(storage_map);
87
0
        storage_map = NULL;
88
0
    }
89
90
0
    StorageList *entry = storage_list;
91
0
    while (entry) {
92
0
        StorageList *next = entry->next;
93
0
        SCFree(entry);
94
0
        entry = next;
95
0
    }
96
97
0
    storage_list = NULL;
98
0
}
99
100
int StorageRegister(const StorageEnum type, const char *name, const unsigned int size, void *(*Alloc)(unsigned int), void (*Free)(void *))
101
569
{
102
569
    if (storage_registration_closed)
103
0
        return -1;
104
105
569
    if (type >= STORAGE_MAX || name == NULL || strlen(name) == 0 ||
106
569
            size == 0 || (size != sizeof(void *) && Alloc == NULL) || Free == NULL)
107
0
        return -1;
108
109
569
    StorageList *list = storage_list;
110
2.55k
    while (list) {
111
1.98k
        if (strcmp(name, list->map.name) == 0 && type == list->map.type) {
112
0
            SCLogError("storage for type \"%s\" with "
113
0
                       "name \"%s\" already registered",
114
0
                    StoragePrintType(type), name);
115
0
            return -1;
116
0
        }
117
118
1.98k
        list = list->next;
119
1.98k
    }
120
121
569
    StorageList *entry = SCMalloc(sizeof(StorageList));
122
569
    if (unlikely(entry == NULL))
123
0
        return -1;
124
125
569
    memset(entry, 0x00, sizeof(StorageList));
126
127
569
    entry->map.type = type;
128
569
    entry->map.name = name;
129
569
    entry->map.size = size;
130
569
    entry->map.Alloc = Alloc;
131
569
    entry->map.Free = Free;
132
133
569
    entry->id = storage_max_id[type]++;
134
569
    entry->next = storage_list;
135
569
    storage_list = entry;
136
137
569
    return entry->id;
138
569
}
139
140
int StorageFinalize(void)
141
71
{
142
71
    int count = 0;
143
71
    int i;
144
145
71
    storage_registration_closed = 1;
146
147
393
    for (i = 0; i < STORAGE_MAX; i++) {
148
322
        if (storage_max_id[i] > 0)
149
213
            count++;
150
322
    }
151
71
    if (count == 0)
152
0
        return 0;
153
154
71
    storage_map = SCMalloc(sizeof(StorageMapping *) * STORAGE_MAX);
155
71
    if (unlikely(storage_map == NULL)) {
156
0
        return -1;
157
0
    }
158
71
    memset(storage_map, 0x00, sizeof(StorageMapping *) * STORAGE_MAX);
159
160
393
    for (i = 0; i < STORAGE_MAX; i++) {
161
322
        if (storage_max_id[i] > 0) {
162
213
            storage_map[i] = SCMalloc(sizeof(StorageMapping) * storage_max_id[i]);
163
213
            if (storage_map[i] == NULL)
164
0
                return -1;
165
213
            memset(storage_map[i], 0x00, sizeof(StorageMapping) * storage_max_id[i]);
166
213
        }
167
322
    }
168
169
71
    StorageList *entry = storage_list;
170
634
    while (entry) {
171
563
        if (storage_map[entry->map.type] != NULL) {
172
563
            storage_map[entry->map.type][entry->id].name = entry->map.name;
173
563
            storage_map[entry->map.type][entry->id].type = entry->map.type;
174
563
            storage_map[entry->map.type][entry->id].size = entry->map.size;
175
563
            storage_map[entry->map.type][entry->id].Alloc = entry->map.Alloc;
176
563
            storage_map[entry->map.type][entry->id].Free = entry->map.Free;
177
563
        }
178
179
563
        StorageList *next = entry->next;
180
563
        SCFree(entry);
181
563
        entry = next;
182
563
    };
183
71
    storage_list = NULL;
184
185
#ifdef DEBUG
186
    for (i = 0; i < STORAGE_MAX; i++) {
187
        if (storage_map[i] == NULL)
188
            continue;
189
190
        int j;
191
        for (j = 0; j < storage_max_id[i]; j++) {
192
            StorageMapping *m = &storage_map[i][j];
193
            SCLogDebug("type \"%s\" name \"%s\" size \"%"PRIuMAX"\"",
194
                    StoragePrintType(m->type), m->name, (uintmax_t)m->size);
195
        }
196
    }
197
#endif
198
71
    return 0;
199
71
}
200
201
unsigned int StorageGetCnt(StorageEnum type)
202
0
{
203
0
    return storage_max_id[type];
204
0
}
205
206
/** \brief get the size of the void array used to store
207
 *         the pointers
208
 *  \retval size size in bytes, can return 0 if not storage is needed
209
 *
210
 *  \todo we could return -1 when registration isn't closed yet, however
211
 *        this will break lots of tests currently, so not doing it now */
212
unsigned int StorageGetSize(StorageEnum type)
213
2.82M
{
214
2.82M
    return storage_max_id[type] * sizeof(void *);
215
2.82M
}
216
217
void *StorageGetById(const Storage *storage, const StorageEnum type, const int id)
218
1.14M
{
219
#ifdef DEBUG
220
    BUG_ON(!storage_registration_closed);
221
#endif
222
1.14M
    SCLogDebug("storage %p id %d", storage, id);
223
1.14M
    if (storage == NULL)
224
0
        return NULL;
225
1.14M
    return storage[id];
226
1.14M
}
227
228
int StorageSetById(Storage *storage, const StorageEnum type, const int id, void *ptr)
229
3.45k
{
230
#ifdef DEBUG
231
    BUG_ON(!storage_registration_closed);
232
#endif
233
3.45k
    SCLogDebug("storage %p id %d", storage, id);
234
3.45k
    if (storage == NULL)
235
0
        return -1;
236
3.45k
    storage[id] = ptr;
237
3.45k
    return 0;
238
3.45k
}
239
240
void *StorageAllocByIdPrealloc(Storage *storage, StorageEnum type, int id)
241
0
{
242
#ifdef DEBUG
243
    BUG_ON(!storage_registration_closed);
244
#endif
245
0
    SCLogDebug("storage %p id %d", storage, id);
246
247
0
    StorageMapping *map = &storage_map[type][id];
248
0
    if (storage[id] == NULL && map->Alloc != NULL) {
249
0
        storage[id] = map->Alloc(map->size);
250
0
        if (storage[id] == NULL) {
251
0
            return NULL;
252
0
        }
253
0
    }
254
255
0
    return storage[id];
256
0
}
257
258
void *StorageAllocById(Storage **storage, StorageEnum type, int id)
259
0
{
260
#ifdef DEBUG
261
    BUG_ON(!storage_registration_closed);
262
#endif
263
0
    SCLogDebug("storage %p id %d", storage, id);
264
265
0
    StorageMapping *map = &storage_map[type][id];
266
0
    Storage *store = *storage;
267
0
    if (store == NULL) {
268
        // coverity[suspicious_sizeof : FALSE]
269
0
        store = SCMalloc(sizeof(void *) * storage_max_id[type]);
270
0
        if (unlikely(store == NULL))
271
0
        return NULL;
272
0
        memset(store, 0x00, sizeof(void *) * storage_max_id[type]);
273
0
    }
274
0
    SCLogDebug("store %p", store);
275
276
0
    if (store[id] == NULL && map->Alloc != NULL) {
277
0
        store[id] = map->Alloc(map->size);
278
0
        if (store[id] == NULL) {
279
0
            SCFree(store);
280
0
            *storage = NULL;
281
0
            return NULL;
282
0
        }
283
0
    }
284
285
0
    *storage = store;
286
0
    return store[id];
287
0
}
288
289
void StorageFreeById(Storage *storage, StorageEnum type, int id)
290
236
{
291
#ifdef DEBUG
292
    BUG_ON(!storage_registration_closed);
293
#endif
294
#ifdef UNITTESTS
295
    if (storage_map == NULL)
296
        return;
297
#endif
298
236
    SCLogDebug("storage %p id %d", storage, id);
299
300
236
    Storage *store = storage;
301
236
    if (store != NULL) {
302
236
        SCLogDebug("store %p", store);
303
236
        if (store[id] != NULL) {
304
236
            StorageMapping *map = &storage_map[type][id];
305
236
            map->Free(store[id]);
306
236
            store[id] = NULL;
307
236
        }
308
236
    }
309
236
}
310
311
void StorageFreeAll(Storage *storage, StorageEnum type)
312
477k
{
313
477k
    if (storage == NULL)
314
0
        return;
315
#ifdef DEBUG
316
    BUG_ON(!storage_registration_closed);
317
#endif
318
#ifdef UNITTESTS
319
    if (storage_map == NULL)
320
        return;
321
#endif
322
323
477k
    Storage *store = storage;
324
477k
    int i;
325
1.90M
    for (i = 0; i < storage_max_id[type]; i++) {
326
1.43M
        if (store[i] != NULL) {
327
1.66k
            StorageMapping *map = &storage_map[type][i];
328
1.66k
            map->Free(store[i]);
329
1.66k
            store[i] = NULL;
330
1.66k
        }
331
1.43M
    }
332
477k
}
333
334
void StorageFree(Storage **storage, StorageEnum type)
335
0
{
336
0
    if (*storage == NULL)
337
0
        return;
338
339
#ifdef DEBUG
340
    BUG_ON(!storage_registration_closed);
341
#endif
342
#ifdef UNITTESTS
343
    if (storage_map == NULL)
344
        return;
345
#endif
346
347
0
    Storage *store = *storage;
348
0
    int i;
349
0
    for (i = 0; i < storage_max_id[type]; i++) {
350
0
        if (store[i] != NULL) {
351
0
            StorageMapping *map = &storage_map[type][i];
352
0
            map->Free(store[i]);
353
0
            store[i] = NULL;
354
0
        }
355
0
    }
356
0
    SCFree(*storage);
357
    *storage = NULL;
358
0
}
359
360
#ifdef UNITTESTS
361
362
static void *StorageTestAlloc(unsigned int size)
363
{
364
    void *x = SCMalloc(size);
365
    return x;
366
}
367
static void StorageTestFree(void *x)
368
{
369
    if (x)
370
        SCFree(x);
371
}
372
373
static int StorageTest01(void)
374
{
375
    StorageInit();
376
377
    int id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestAlloc, StorageTestFree);
378
    if (id < 0)
379
        goto error;
380
    id = StorageRegister(STORAGE_HOST, "variable", 24, StorageTestAlloc, StorageTestFree);
381
    if (id < 0)
382
        goto error;
383
    id = StorageRegister(STORAGE_FLOW, "store", sizeof(void *), StorageTestAlloc, StorageTestFree);
384
    if (id < 0)
385
        goto error;
386
387
    if (StorageFinalize() < 0)
388
        goto error;
389
390
    StorageCleanup();
391
    return 1;
392
error:
393
    StorageCleanup();
394
    return 0;
395
}
396
397
struct StorageTest02Data {
398
    int abc;
399
};
400
401
static void *StorageTest02Init(unsigned int size)
402
{
403
    struct StorageTest02Data *data = (struct StorageTest02Data *)SCMalloc(size);
404
    if (data != NULL)
405
        data->abc = 1234;
406
    return (void *)data;
407
}
408
409
static int StorageTest02(void)
410
{
411
    struct StorageTest02Data *test = NULL;
412
413
    StorageInit();
414
415
    int id1 = StorageRegister(STORAGE_HOST, "test", 4, StorageTest02Init, StorageTestFree);
416
    if (id1 < 0) {
417
        printf("StorageRegister failed (2): ");
418
        goto error;
419
    }
420
    int id2 = StorageRegister(STORAGE_HOST, "test2", 4, StorageTest02Init, StorageTestFree);
421
    if (id2 < 0) {
422
        printf("StorageRegister failed (2): ");
423
        goto error;
424
    }
425
426
    if (StorageFinalize() < 0) {
427
        printf("StorageFinalize failed: ");
428
        goto error;
429
    }
430
431
    Storage *storage = NULL;
432
    void *data = StorageAllocById(&storage, STORAGE_HOST, id1);
433
    if (data == NULL) {
434
        printf("StorageAllocById failed, data == NULL, storage %p: ", storage);
435
        goto error;
436
    }
437
    test = (struct StorageTest02Data *)data;
438
    if (test->abc != 1234) {
439
        printf("setup failed, test->abc != 1234, but %d (1):", test->abc);
440
        goto error;
441
    }
442
    test->abc = 4321;
443
444
    data = StorageAllocById(&storage, STORAGE_HOST, id2);
445
    if (data == NULL) {
446
        printf("StorageAllocById failed, data == NULL, storage %p: ", storage);
447
        goto error;
448
    }
449
    test = (struct StorageTest02Data *)data;
450
    if (test->abc != 1234) {
451
        printf("setup failed, test->abc != 1234, but %d (2):", test->abc);
452
        goto error;
453
    }
454
455
    data = StorageGetById(storage, STORAGE_HOST, id1);
456
    if (data == NULL) {
457
        printf("StorageAllocById failed, data == NULL, storage %p: ", storage);
458
        goto error;
459
    }
460
    test = (struct StorageTest02Data *)data;
461
    if (test->abc != 4321) {
462
        printf("setup failed, test->abc != 4321, but %d (3):", test->abc);
463
        goto error;
464
    }
465
466
    //StorageFreeById(storage, STORAGE_HOST, id1);
467
    //StorageFreeById(storage, STORAGE_HOST, id2);
468
469
    StorageFree(&storage, STORAGE_HOST);
470
471
    StorageCleanup();
472
    return 1;
473
error:
474
    StorageCleanup();
475
    return 0;
476
}
477
478
static int StorageTest03(void)
479
{
480
    StorageInit();
481
482
    int id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestAlloc, StorageTestFree);
483
    if (id < 0)
484
        goto error;
485
    id = StorageRegister(STORAGE_HOST, "test", 8, StorageTestAlloc, StorageTestFree);
486
    if (id != -1) {
487
        printf("duplicate registration should have failed: ");
488
        goto error;
489
    }
490
491
    id = StorageRegister(STORAGE_HOST, "test1", 6, NULL, StorageTestFree);
492
    if (id != -1) {
493
        printf("duplicate registration should have failed (2): ");
494
        goto error;
495
    }
496
497
    id = StorageRegister(STORAGE_HOST, "test2", 8, StorageTestAlloc, NULL);
498
    if (id != -1) {
499
        printf("duplicate registration should have failed (3): ");
500
        goto error;
501
    }
502
503
    id = StorageRegister(STORAGE_HOST, "test3", 0, StorageTestAlloc, StorageTestFree);
504
    if (id != -1) {
505
        printf("duplicate registration should have failed (4): ");
506
        goto error;
507
    }
508
509
    id = StorageRegister(STORAGE_HOST, "", 8, StorageTestAlloc, StorageTestFree);
510
    if (id != -1) {
511
        printf("duplicate registration should have failed (5): ");
512
        goto error;
513
    }
514
515
    id = StorageRegister(STORAGE_HOST, NULL, 8, StorageTestAlloc, StorageTestFree);
516
    if (id != -1) {
517
        printf("duplicate registration should have failed (6): ");
518
        goto error;
519
    }
520
521
    id = StorageRegister(STORAGE_MAX, "test4", 8, StorageTestAlloc, StorageTestFree);
522
    if (id != -1) {
523
        printf("duplicate registration should have failed (7): ");
524
        goto error;
525
    }
526
527
    id = StorageRegister(38, "test5", 8, StorageTestAlloc, StorageTestFree);
528
    if (id != -1) {
529
        printf("duplicate registration should have failed (8): ");
530
        goto error;
531
    }
532
533
    id = StorageRegister(-1, "test6", 8, StorageTestAlloc, StorageTestFree);
534
    if (id != -1) {
535
        printf("duplicate registration should have failed (9): ");
536
        goto error;
537
    }
538
539
    StorageCleanup();
540
    return 1;
541
error:
542
    StorageCleanup();
543
    return 0;
544
}
545
546
void StorageRegisterTests(void)
547
{
548
    UtRegisterTest("StorageTest01", StorageTest01);
549
    UtRegisterTest("StorageTest02", StorageTest02);
550
    UtRegisterTest("StorageTest03", StorageTest03);
551
}
552
#endif