/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 */ |