Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/util-coredump-config.c
Line
Count
Source
1
/* Copyright (C) 2007-2010 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 Eileen Donlon <emdonlo@gmail.com>
22
 *
23
 * Coredump configuration
24
 */
25
26
#include "suricata-common.h"
27
#include "util-coredump-config.h"
28
#include "conf.h"
29
#ifdef HAVE_SYS_RESOURCE_H
30
#include <sys/resource.h>
31
#endif
32
#ifdef HAVE_SYS_PRCTL_H
33
#include <sys/prctl.h>
34
#endif
35
#include "util-byte.h"
36
#include "util-debug.h"
37
38
#ifdef OS_WIN32
39
40
void CoredumpEnable(void) {
41
}
42
43
int32_t CoredumpLoadConfig(void) {
44
    /* todo: use the registry to get/set dump configuration */
45
    SCLogInfo("Configuring core dump is not yet supported on Windows.");
46
    return 0;
47
}
48
49
void CoredumpConfigRegisterTests(void)
50
{
51
}
52
53
#else
54
55
static bool unlimited = false;
56
static rlim_t max_dump = 0;
57
58
/**
59
 * \brief Enable coredumps on systems where coredumps can and need to
60
 * be enabled.
61
 */
62
void CoredumpEnable(void)
63
0
{
64
0
    if (!unlimited && !max_dump) {
65
0
        return;
66
0
    }
67
0
#if HAVE_SYS_PRCTL_H
68
    /* Linux specific core dump configuration; set dumpable flag if needed */
69
0
    int dumpable = 0;
70
0
    dumpable = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
71
0
    if (dumpable == -1) {
72
0
        SCLogNotice("Failed to get dumpable state of process, "
73
0
                    "core dumps may not be enabled: %s",
74
0
                strerror(errno));
75
0
    }
76
0
    else if (unlimited || max_dump > 0) {
77
        /* try to enable core dump for this process */
78
0
        if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
79
0
            SCLogInfo("Unable to make this process dumpable.");
80
0
        } else {
81
0
            SCLogDebug("Process is dumpable.");
82
0
        }
83
0
    }
84
    /* don't clear dumpable flag since this will have other effects;
85
     * just set dump size to 0 below */
86
0
#endif /* HAVE_SYS_PRCTL_H */
87
0
}
88
89
/**
90
 * \brief Configures the core dump size.
91
 *
92
 * \retval Returns 1 on success and 0 on failure.
93
 *
94
 */
95
int32_t CoredumpLoadConfig (void)
96
11
{
97
11
#ifdef HAVE_SYS_RESOURCE_H
98
    /* get core dump configuration settings for suricata */
99
11
    int ret = 0;
100
11
    uint64_t max_dump64 = 0;
101
11
    uint32_t max_dump32 = 0;
102
11
    const char *dump_size_config = NULL;
103
11
    size_t rlim_size = sizeof(rlim_t);
104
105
11
    if (SCConfGet("coredump.max-dump", &dump_size_config) == 0) {
106
11
        SCLogDebug ("core dump size not specified");
107
11
        return 1;
108
11
    }
109
0
    if (dump_size_config == NULL) {
110
0
        SCLogError("malformed value for coredump.max-dump: NULL");
111
0
        return 0;
112
0
    }
113
0
    if (strcasecmp (dump_size_config, "unlimited") == 0) {
114
0
        unlimited = true;
115
0
    }
116
0
    else {
117
        /* disallow negative values */
118
0
        if (strchr (dump_size_config, '-') != NULL) {
119
0
            SCLogInfo ("Negative value for core dump size; ignored.");
120
0
            return 0;
121
0
        }
122
        /* the size of rlim_t is platform dependent */
123
0
        if (rlim_size > 8) {
124
0
            SCLogInfo ("Unexpected type for rlim_t");
125
0
            return 0;
126
0
        }
127
0
        if (rlim_size == 8) {
128
0
            ret = ByteExtractStringUint64(
129
0
                    &max_dump64, 10, strlen(dump_size_config), dump_size_config);
130
0
        }
131
0
        else if (rlim_size == 4) {
132
0
            ret = ByteExtractStringUint32(
133
0
                    &max_dump32, 10, strlen(dump_size_config), dump_size_config);
134
0
        }
135
0
        if (ret <= 0) {
136
0
            SCLogInfo ("Illegal core dump size: %s.", dump_size_config);
137
0
            return 0;
138
0
        }
139
140
0
        max_dump = rlim_size == 8 ? (rlim_t)max_dump64 : (rlim_t)max_dump32;
141
0
        if (max_dump == 0) {
142
0
            SCLogInfo("Max dump is 0, disable core dumping.");
143
0
        } else {
144
0
            SCLogInfo("Max dump is %" PRIu64, (uint64_t)max_dump);
145
0
        }
146
0
    }
147
148
0
    CoredumpEnable();
149
150
0
    struct rlimit lim;     /*existing limit*/
151
0
    struct rlimit new_lim; /*desired limit*/
152
153
    /* get the current core dump file configuration */
154
0
    if (getrlimit (RLIMIT_CORE, &lim) == -1) {
155
0
       SCLogInfo ("Can't read coredump limit for this process.");
156
0
        return 0;
157
0
    }
158
159
0
    if (unlimited) {
160
        /* we want no limit on coredump size */
161
0
        if (lim.rlim_max == RLIM_INFINITY && lim.rlim_cur == RLIM_INFINITY) {
162
0
            SCLogConfig ("Core dump size is unlimited.");
163
0
            return 1;
164
0
        }
165
0
        else {
166
0
            new_lim.rlim_max = RLIM_INFINITY;
167
0
            new_lim.rlim_cur = RLIM_INFINITY;
168
0
            if (setrlimit (RLIMIT_CORE, &new_lim) == 0) {
169
0
                SCLogConfig ("Core dump size set to unlimited.");
170
0
                return 1;
171
0
            }
172
0
            if (errno == EPERM) {
173
                /* couldn't raise the hard limit to unlimited;
174
                 * try increasing the soft limit to the hard limit instead */
175
0
                if (lim.rlim_cur < lim.rlim_max) {
176
0
                    new_lim.rlim_cur = lim.rlim_max;
177
0
                    if (setrlimit (RLIMIT_CORE, & new_lim) == 0) {
178
0
                        SCLogInfo ("Could not set core dump size to unlimited; core dump size set to the hard limit.");
179
0
                        return 0;
180
0
                    }
181
0
                    else {
182
0
                        SCLogInfo ("Failed to set core dump size to unlimited or to the hard limit.");
183
0
                        return 0;
184
0
                    }
185
0
                }
186
0
                SCLogInfo ("Could not set core dump size to unlimited; it's set to the hard limit.");
187
0
                return 0;
188
0
            }
189
0
        }
190
0
    }
191
0
    else {
192
        /* we want a non-infinite soft limit on coredump size */
193
0
        new_lim.rlim_cur = max_dump;
194
195
        /* check whether the hard limit needs to be adjusted */
196
0
        if (lim.rlim_max == RLIM_INFINITY) {
197
            /* keep the current value (unlimited) for the hard limit */
198
0
            new_lim.rlim_max = lim.rlim_max;
199
0
        }
200
0
#ifdef RLIM_SAVED_MAX
201
0
        else if (lim.rlim_max == RLIM_SAVED_MAX) {
202
            /* keep the current value (unknown) for the hard limit */
203
0
            new_lim.rlim_max = lim.rlim_max;
204
0
        }
205
0
#endif
206
0
        else if (lim.rlim_max <  max_dump) {
207
            /* need to raise the hard coredump size limit */
208
0
            new_lim.rlim_max =  max_dump;
209
0
        }
210
0
        else {
211
            /* hard limit is ample */
212
0
            new_lim.rlim_max = lim.rlim_max;
213
0
        }
214
0
        if (setrlimit (RLIMIT_CORE, &new_lim) == 0) {
215
0
            SCLogInfo ("Core dump setting attempted is %"PRIu64, (uint64_t) new_lim.rlim_cur);
216
0
            struct rlimit actual_lim;
217
0
            if (getrlimit (RLIMIT_CORE, &actual_lim) == 0) {
218
0
                if (actual_lim.rlim_cur == RLIM_INFINITY) {
219
0
                    SCLogConfig ("Core dump size set to unlimited.");
220
0
                }
221
0
#ifdef RLIM_SAVED_CUR
222
0
                else if (actual_lim.rlim_cur == RLIM_SAVED_CUR) {
223
0
                    SCLogInfo ("Core dump size set to soft limit.");
224
0
                }
225
0
#endif
226
0
                else {
227
0
                    SCLogInfo ("Core dump size set to %"PRIu64, (uint64_t) actual_lim.rlim_cur);
228
0
                }
229
0
            }
230
0
            return 1;
231
0
        }
232
233
0
        if (errno == EINVAL || errno == EPERM) {
234
            /* couldn't increase the hard limit, or the soft limit exceeded the hard
235
             * limit; try to raise the soft limit to the hard limit */
236
0
            if ((lim.rlim_cur < max_dump && lim.rlim_cur < lim.rlim_max)
237
0
#ifdef RLIM_SAVED_CUR
238
0
                || (lim.rlim_cur == RLIM_SAVED_CUR)
239
0
#endif
240
0
            ){
241
0
                new_lim.rlim_max = lim.rlim_max;
242
0
                new_lim.rlim_cur = lim.rlim_max;
243
0
                if (setrlimit (RLIMIT_CORE, &new_lim) == 0)  {
244
0
                    SCLogInfo("Core dump size set to the hard limit.");
245
0
                    return 0;
246
0
                }
247
0
            }
248
0
        }
249
0
    }
250
    /* failed to set the coredump limit */
251
0
    SCLogInfo("Couldn't set coredump size to %s.", dump_size_config);
252
0
#endif /* HAVE_SYS_RESOURCE_H */
253
0
    return 0;
254
0
}
255
256
#if defined UNITTESTS && defined HAVE_SYS_RESOURCE_H
257
#include "conf-yaml-loader.h"
258
259
static void ResetCoredumpConfig(void)
260
{
261
    unlimited = false;
262
    max_dump = 0;
263
}
264
265
/**
266
 * \test CoredumpConfigTest01 is a test for the coredump configuration
267
 *        with unlimited coredump size.
268
 */
269
static int CoredumpConfigTest01(void)
270
{
271
    char config[] = "\
272
%YAML 1.1\n\
273
---\n\
274
coredump:\n\
275
  max-dump: unlimited\n\
276
";
277
278
    int ret = 0;
279
    ResetCoredumpConfig();
280
    SCConfCreateContextBackup();
281
    SCConfInit();
282
283
    SCConfYamlLoadString(config, strlen(config));
284
    ret = CoredumpLoadConfig();
285
    FAIL_IF(errno != EPERM && ret != 1);
286
287
    FAIL_IF(unlimited != true);
288
    FAIL_IF(max_dump != 0);
289
290
    SCConfDeInit();
291
    SCConfRestoreContextBackup();
292
    PASS;
293
}
294
295
/**
296
 * \test CoredumpConfigTest02 is a test for the coredump configuration
297
 *        with a specific coredump size.
298
 */
299
static int CoredumpConfigTest02(void)
300
{
301
    char config[] = "\
302
%YAML 1.1\n\
303
---\n\
304
coredump:\n\
305
  max-dump: 1000000\n\
306
";
307
308
    int ret = 0;
309
    ResetCoredumpConfig();
310
    SCConfCreateContextBackup();
311
    SCConfInit();
312
313
    SCConfYamlLoadString(config, strlen(config));
314
    ret = CoredumpLoadConfig();
315
    FAIL_IF(errno != EPERM && ret != 1);
316
317
    FAIL_IF(unlimited != false);
318
    FAIL_IF(max_dump != 1000000);
319
320
    SCConfDeInit();
321
    SCConfRestoreContextBackup();
322
    PASS;
323
}
324
325
/**
326
 * \test CoredumpConfigTest03 is a test for the coredump configuration
327
 *        with an invalid coredump size.
328
 */
329
static int CoredumpConfigTest03(void)
330
{
331
    char config[] = "\
332
%YAML 1.1\n\
333
---\n\
334
coredump:\n\
335
  max-dump: -1000000\n\
336
";
337
338
    ResetCoredumpConfig();
339
    SCConfCreateContextBackup();
340
    SCConfInit();
341
342
    SCConfYamlLoadString(config, strlen(config));
343
    FAIL_IF(CoredumpLoadConfig() != 0);
344
345
    FAIL_IF(unlimited != false);
346
    FAIL_IF(max_dump != 0);
347
348
    SCConfDeInit();
349
    SCConfRestoreContextBackup();
350
    PASS;
351
}
352
353
/**
354
 * \test CoredumpConfigTest04 is a test for the coredump configuration
355
 *        with a non-numeric coredump size.
356
 */
357
static int CoredumpConfigTest04(void)
358
{
359
    char config[] = "\
360
%YAML 1.1\n\
361
---\n\
362
coredump:\n\
363
  max-dump: a\n\
364
";
365
366
    ResetCoredumpConfig();
367
    SCConfCreateContextBackup();
368
    SCConfInit();
369
370
    SCConfYamlLoadString(config, strlen(config));
371
    FAIL_IF(CoredumpLoadConfig() != 0);
372
373
    FAIL_IF(unlimited != false);
374
    FAIL_IF(max_dump != 0);
375
376
    SCConfDeInit();
377
    SCConfRestoreContextBackup();
378
    PASS;
379
}
380
381
/**
382
 * \test CoredumpConfigTest05 is a test for the coredump configuration
383
 *        with a zero coredump size.
384
 */
385
static int CoredumpConfigTest05(void)
386
{
387
    char config[] = "\
388
%YAML 1.1\n\
389
---\n\
390
coredump:\n\
391
  max-dump: 0\n\
392
";
393
394
    int ret = 0;
395
    ResetCoredumpConfig();
396
    SCConfCreateContextBackup();
397
    SCConfInit();
398
399
    SCConfYamlLoadString(config, strlen(config));
400
    ret = CoredumpLoadConfig();
401
    /* should return 1 because zero coredump size is allowed. */
402
    FAIL_IF(errno != EPERM && ret != 1);
403
404
    FAIL_IF(unlimited != false);
405
    FAIL_IF(max_dump != 0);
406
407
    SCConfDeInit();
408
    SCConfRestoreContextBackup();
409
    PASS;
410
}
411
#endif /* UNITTESTS */
412
413
void CoredumpConfigRegisterTests(void)
414
0
{
415
#if defined UNITTESTS && defined HAVE_SYS_RESOURCE_H
416
    UtRegisterTest("CoredumpConfigTest01", CoredumpConfigTest01);
417
    UtRegisterTest("CoredumpConfigTest02", CoredumpConfigTest02);
418
    UtRegisterTest("CoredumpConfigTest03", CoredumpConfigTest03);
419
    UtRegisterTest("CoredumpConfigTest04", CoredumpConfigTest04);
420
    UtRegisterTest("CoredumpConfigTest05", CoredumpConfigTest05);
421
#endif /* UNITTESTS */
422
0
}
423
424
#endif /* OS_WIN32 */