#define YAML_VERSION_MAJOR 1
#define YAML_VERSION_MINOR 1
+/* The maximum level of recursion allowed while parsing the YAML
+ * file. */
+#define RECURSION_LIMIT 128
+
/* Sometimes we'll have to create a node name on the fly (integer
* conversion, etc), so this is a default length to allocate that will
* work most of the time. */
static char *conf_dirname = NULL;
-static int ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq);
+static int ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq, int rlevel);
/* Configuration processing states. */
enum conf_state {
yaml_parser_set_input_file(&parser, file);
- if (ConfYamlParse(&parser, parent, 0) != 0) {
+ if (ConfYamlParse(&parser, parent, 0, 0) != 0) {
SCLogError(SC_ERR_CONF_YAML_ERROR,
"Failed to include configuration file %s", filename);
goto done;
* \retval 0 on success, -1 on failure.
*/
static int
-ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq)
+ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq, int rlevel)
{
ConfNode *node = parent;
yaml_event_t event;
int done = 0;
int state = 0;
int seq_idx = 0;
+ int retval = 0;
+
+ if (rlevel++ > RECURSION_LIMIT) {
+ FatalError(SC_ERR_FATAL, "Recursion limit reached while parsing "
+ "configuration file, aborting.");
+ }
while (!done) {
if (!yaml_parser_parse(parser, &event)) {
SCLogError(SC_ERR_CONF_YAML_ERROR,
"Failed to parse configuration file at line %" PRIuMAX ": %s\n",
(uintmax_t)parser->problem_mark.line, parser->problem);
- return -1;
+ retval = -1;
+ break;
}
if (event.type == YAML_DOCUMENT_START_EVENT) {
else {
seq_node = ConfNodeNew();
if (unlikely(seq_node == NULL)) {
- return -1;
+ goto fail;
}
seq_node->name = SCStrdup(sequence_node_name);
if (unlikely(seq_node->name == NULL)) {
SCFree(seq_node);
- return -1;
+ goto fail;
}
seq_node->val = SCStrdup(value);
if (unlikely(seq_node->val == NULL)) {
SCFree(seq_node->name);
- return -1;
+ goto fail;
}
}
TAILQ_INSERT_TAIL(&parent->head, seq_node, next);
}
else if (event.type == YAML_SEQUENCE_START_EVENT) {
SCLogDebug("event.type=YAML_SEQUENCE_START_EVENT; state=%d", state);
- if (ConfYamlParse(parser, node, 1) != 0)
+ if (ConfYamlParse(parser, node, 1, rlevel) != 0)
goto fail;
node->is_seq = 1;
state = CONF_KEY;
}
else if (event.type == YAML_SEQUENCE_END_EVENT) {
SCLogDebug("event.type=YAML_SEQUENCE_END_EVENT; state=%d", state);
- return 0;
+ done = 1;
}
else if (event.type == YAML_MAPPING_START_EVENT) {
SCLogDebug("event.type=YAML_MAPPING_START_EVENT; state=%d", state);
else {
seq_node = ConfNodeNew();
if (unlikely(seq_node == NULL)) {
- return -1;
+ goto fail;
}
seq_node->name = SCStrdup(sequence_node_name);
if (unlikely(seq_node->name == NULL)) {
SCFree(seq_node);
- return -1;
+ goto fail;
}
}
seq_node->is_seq = 1;
TAILQ_INSERT_TAIL(&node->head, seq_node, next);
- if (ConfYamlParse(parser, seq_node, 0) != 0)
+ if (ConfYamlParse(parser, seq_node, 0, rlevel) != 0)
goto fail;
}
else {
- if (ConfYamlParse(parser, node, inseq) != 0)
+ if (ConfYamlParse(parser, node, inseq, rlevel) != 0)
goto fail;
}
state = CONF_KEY;
fail:
yaml_event_delete(&event);
- return -1;
+ retval = -1;
+ break;
}
- return 0;
+ rlevel--;
+ return retval;
}
/**
}
yaml_parser_set_input_file(&parser, infile);
- ret = ConfYamlParse(&parser, root, 0);
+ ret = ConfYamlParse(&parser, root, 0, 0);
yaml_parser_delete(&parser);
fclose(infile);
exit(EXIT_FAILURE);
}
yaml_parser_set_input_string(&parser, (const unsigned char *)string, len);
- ret = ConfYamlParse(&parser, root, 0);
+ ret = ConfYamlParse(&parser, root, 0, 0);
yaml_parser_delete(&parser);
return ret;
}
}
yaml_parser_set_input_file(&parser, infile);
- ret = ConfYamlParse(&parser, root, 0);
+ ret = ConfYamlParse(&parser, root, 0, 0);
yaml_parser_delete(&parser);
fclose(infile);