suricata
util-coredump-config.c
Go to the documentation of this file.
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 
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 {
64  if (!unlimited && !max_dump) {
65  return;
66  }
67 #if HAVE_SYS_PRCTL_H
68  /* Linux specific core dump configuration; set dumpable flag if needed */
69  int dumpable = 0;
70  dumpable = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
71  if (dumpable == -1) {
72  SCLogNotice("Failed to get dumpable state of process, "
73  "core dumps may not be enabled: %s",
74  strerror(errno));
75  }
76  else if (unlimited || max_dump > 0) {
77  /* try to enable core dump for this process */
78  if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
79  SCLogInfo("Unable to make this process dumpable.");
80  } else {
81  SCLogDebug("Process is dumpable.");
82  }
83  }
84  /* don't clear dumpable flag since this will have other effects;
85  * just set dump size to 0 below */
86 #endif /* HAVE_SYS_PRCTL_H */
87 }
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 {
97 #ifdef HAVE_SYS_RESOURCE_H
98  /* get core dump configuration settings for suricata */
99  int ret = 0;
100  uint64_t max_dump64 = 0;
101  uint32_t max_dump32 = 0;
102  const char *dump_size_config = NULL;
103  size_t rlim_size = sizeof(rlim_t);
104 
105  if (SCConfGet("coredump.max-dump", &dump_size_config) == 0) {
106  SCLogDebug ("core dump size not specified");
107  return 1;
108  }
109  if (dump_size_config == NULL) {
110  SCLogError("malformed value for coredump.max-dump: NULL");
111  return 0;
112  }
113  if (strcasecmp (dump_size_config, "unlimited") == 0) {
114  unlimited = true;
115  }
116  else {
117  /* disallow negative values */
118  if (strchr (dump_size_config, '-') != NULL) {
119  SCLogInfo ("Negative value for core dump size; ignored.");
120  return 0;
121  }
122  /* the size of rlim_t is platform dependent */
123  if (rlim_size > 8) {
124  SCLogInfo ("Unexpected type for rlim_t");
125  return 0;
126  }
127  if (rlim_size == 8) {
129  &max_dump64, 10, strlen(dump_size_config), dump_size_config);
130  }
131  else if (rlim_size == 4) {
133  &max_dump32, 10, strlen(dump_size_config), dump_size_config);
134  }
135  if (ret <= 0) {
136  SCLogInfo ("Illegal core dump size: %s.", dump_size_config);
137  return 0;
138  }
139 
140  max_dump = rlim_size == 8 ? (rlim_t)max_dump64 : (rlim_t)max_dump32;
141  if (max_dump == 0) {
142  SCLogInfo("Max dump is 0, disable core dumping.");
143  } else {
144  SCLogInfo("Max dump is %" PRIu64, (uint64_t)max_dump);
145  }
146  }
147 
148  CoredumpEnable();
149 
150  struct rlimit lim; /*existing limit*/
151  struct rlimit new_lim; /*desired limit*/
152 
153  /* get the current core dump file configuration */
154  if (getrlimit (RLIMIT_CORE, &lim) == -1) {
155  SCLogInfo ("Can't read coredump limit for this process.");
156  return 0;
157  }
158 
159  if (unlimited) {
160  /* we want no limit on coredump size */
161  if (lim.rlim_max == RLIM_INFINITY && lim.rlim_cur == RLIM_INFINITY) {
162  SCLogConfig ("Core dump size is unlimited.");
163  return 1;
164  }
165  else {
166  new_lim.rlim_max = RLIM_INFINITY;
167  new_lim.rlim_cur = RLIM_INFINITY;
168  if (setrlimit (RLIMIT_CORE, &new_lim) == 0) {
169  SCLogConfig ("Core dump size set to unlimited.");
170  return 1;
171  }
172  if (errno == EPERM) {
173  /* couldn't raise the hard limit to unlimited;
174  * try increasing the soft limit to the hard limit instead */
175  if (lim.rlim_cur < lim.rlim_max) {
176  new_lim.rlim_cur = lim.rlim_max;
177  if (setrlimit (RLIMIT_CORE, & new_lim) == 0) {
178  SCLogInfo ("Could not set core dump size to unlimited; core dump size set to the hard limit.");
179  return 0;
180  }
181  else {
182  SCLogInfo ("Failed to set core dump size to unlimited or to the hard limit.");
183  return 0;
184  }
185  }
186  SCLogInfo ("Could not set core dump size to unlimited; it's set to the hard limit.");
187  return 0;
188  }
189  }
190  }
191  else {
192  /* we want a non-infinite soft limit on coredump size */
193  new_lim.rlim_cur = max_dump;
194 
195  /* check whether the hard limit needs to be adjusted */
196  if (lim.rlim_max == RLIM_INFINITY) {
197  /* keep the current value (unlimited) for the hard limit */
198  new_lim.rlim_max = lim.rlim_max;
199  }
200 #ifdef RLIM_SAVED_MAX
201  else if (lim.rlim_max == RLIM_SAVED_MAX) {
202  /* keep the current value (unknown) for the hard limit */
203  new_lim.rlim_max = lim.rlim_max;
204  }
205 #endif
206  else if (lim.rlim_max < max_dump) {
207  /* need to raise the hard coredump size limit */
208  new_lim.rlim_max = max_dump;
209  }
210  else {
211  /* hard limit is ample */
212  new_lim.rlim_max = lim.rlim_max;
213  }
214  if (setrlimit (RLIMIT_CORE, &new_lim) == 0) {
215  SCLogInfo ("Core dump setting attempted is %"PRIu64, (uint64_t) new_lim.rlim_cur);
216  struct rlimit actual_lim;
217  if (getrlimit (RLIMIT_CORE, &actual_lim) == 0) {
218  if (actual_lim.rlim_cur == RLIM_INFINITY) {
219  SCLogConfig ("Core dump size set to unlimited.");
220  }
221 #ifdef RLIM_SAVED_CUR
222  else if (actual_lim.rlim_cur == RLIM_SAVED_CUR) {
223  SCLogInfo ("Core dump size set to soft limit.");
224  }
225 #endif
226  else {
227  SCLogInfo ("Core dump size set to %"PRIu64, (uint64_t) actual_lim.rlim_cur);
228  }
229  }
230  return 1;
231  }
232 
233  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  if ((lim.rlim_cur < max_dump && lim.rlim_cur < lim.rlim_max)
237 #ifdef RLIM_SAVED_CUR
238  || (lim.rlim_cur == RLIM_SAVED_CUR)
239 #endif
240  ){
241  new_lim.rlim_max = lim.rlim_max;
242  new_lim.rlim_cur = lim.rlim_max;
243  if (setrlimit (RLIMIT_CORE, &new_lim) == 0) {
244  SCLogInfo("Core dump size set to the hard limit.");
245  return 0;
246  }
247  }
248  }
249  }
250  /* failed to set the coredump limit */
251  SCLogInfo("Couldn't set coredump size to %s.", dump_size_config);
252 #endif /* HAVE_SYS_RESOURCE_H */
253  return 0;
254 }
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();
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();
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();
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();
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();
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();
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();
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();
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();
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();
409  PASS;
410 }
411 #endif /* UNITTESTS */
412 
414 {
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 }
423 
424 #endif /* OS_WIN32 */
util-byte.h
SCConfYamlLoadString
int SCConfYamlLoadString(const char *string, size_t len)
Load configuration from a YAML string.
Definition: conf-yaml-loader.c:523
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:275
util-coredump-config.h
SCConfGet
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:350
ByteExtractStringUint32
int ByteExtractStringUint32(uint32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:239
ByteExtractStringUint64
int ByteExtractStringUint64(uint64_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:234
CoredumpConfigRegisterTests
void CoredumpConfigRegisterTests(void)
Definition: util-coredump-config.c:413
SCConfInit
void SCConfInit(void)
Initialize the configuration system.
Definition: conf.c:120
util-debug.h
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
CoredumpLoadConfig
int32_t CoredumpLoadConfig(void)
Configures the core dump size.
Definition: util-coredump-config.c:95
conf-yaml-loader.h
conf.h
SCConfCreateContextBackup
void SCConfCreateContextBackup(void)
Creates a backup of the conf_hash hash_table used by the conf API.
Definition: conf.c:684
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:225
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
suricata-common.h
SCConfDeInit
void SCConfDeInit(void)
De-initializes the configuration system.
Definition: conf.c:703
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:267
SCConfRestoreContextBackup
void SCConfRestoreContextBackup(void)
Restores the backup of the hash_table present in backup_conf_hash back to conf_hash.
Definition: conf.c:694
CoredumpEnable
void CoredumpEnable(void)
Enable coredumps on systems where coredumps can and need to be enabled.
Definition: util-coredump-config.c:62
SCLogNotice
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:243