#include <haproxy/cfgcond-t.h>
const struct cond_pred_kw *cfg_lookup_cond_pred(const char *str);
-int cfg_parse_cond_term(const char **text, struct cfg_cond_term **term, char **err, const char **errptr);
+int cfg_parse_cond_term(const char **text, struct cfg_cond_term **term, char **err, const char **errptr, int maxdepth);
int cfg_eval_cond_term(const struct cfg_cond_term *term, char **err);
void cfg_free_cond_term(struct cfg_cond_term *term);
-int cfg_parse_cond_and(const char **text, struct cfg_cond_and **expr, char **err, const char **errptr);
+int cfg_parse_cond_and(const char **text, struct cfg_cond_and **expr, char **err, const char **errptr, int maxdepth);
int cfg_eval_cond_and(struct cfg_cond_and *expr, char **err);
void cfg_free_cond_and(struct cfg_cond_and *expr);
-int cfg_parse_cond_expr(const char **text, struct cfg_cond_expr **expr, char **err, const char **errptr);
+int cfg_parse_cond_expr(const char **text, struct cfg_cond_expr **expr, char **err, const char **errptr, int maxdepth);
int cfg_eval_cond_expr(struct cfg_cond_expr *expr, char **err);
void cfg_free_cond_expr(struct cfg_cond_expr *expr);
* untouched on failure. On success, the caller must free <term> using
* cfg_free_cond_term(). An error will be set in <err> on error, and only
* in this case. In this case the first bad character will be reported in
- * <errptr>.
+ * <errptr>. <maxdepth> corresponds to the maximum recursion depth permitted,
+ * it is decremented on each recursive call and the parsing will fail one
+ * reaching <= 0.
*/
-int cfg_parse_cond_term(const char **text, struct cfg_cond_term **term, char **err, const char **errptr)
+int cfg_parse_cond_term(const char **text, struct cfg_cond_term **term, char **err, const char **errptr, int maxdepth)
{
struct cfg_cond_term *t;
const char *in = *text;
if (!*in) /* empty term does not parse */
return 0;
+ *term = NULL;
+ if (maxdepth <= 0)
+ goto fail0;
+
t = *term = calloc(1, sizeof(**term));
if (!t) {
memprintf(err, "memory allocation error while parsing conditional expression '%s'", *text);
t->args = NULL;
do { in++; } while (*in == ' ' || *in == '\t');
- ret = cfg_parse_cond_expr(&in, &t->expr, err, errptr);
+ ret = cfg_parse_cond_expr(&in, &t->expr, err, errptr, maxdepth - 1);
if (ret == -1)
goto fail2;
if (ret == 0)
* on failure. On success, the caller will have to free all lower-level
* allocated structs using cfg_free_cond_expr(). An error will be set in
* <err> on error, and only in this case. In this case the first bad
- * character will be reported in <errptr>.
+ * character will be reported in <errptr>. <maxdepth> corresponds to the
+ * maximum recursion depth permitted, it is decremented on each recursive
+ * call and the parsing will fail one reaching <= 0.
*/
-int cfg_parse_cond_and(const char **text, struct cfg_cond_and **expr, char **err, const char **errptr)
+int cfg_parse_cond_and(const char **text, struct cfg_cond_and **expr, char **err, const char **errptr, int maxdepth)
{
struct cfg_cond_and *e;
const char *in = *text;
if (!*in) /* empty expr does not parse */
return 0;
+ *expr = NULL;
+ if (maxdepth <= 0) {
+ memprintf(err, "unparsable conditional sub-expression '%s'", in);
+ if (errptr)
+ *errptr = in;
+ goto done;
+ }
+
e = *expr = calloc(1, sizeof(**expr));
if (!e) {
memprintf(err, "memory allocation error while parsing conditional expression '%s'", *text);
goto done;
}
- ret = cfg_parse_cond_term(&in, &e->left, err, errptr);
+ ret = cfg_parse_cond_term(&in, &e->left, err, errptr, maxdepth - 1);
if (ret == -1) // parse error, error already reported
goto done;
while (*in == ' ' || *in == '\t')
in++;
- ret = cfg_parse_cond_and(&in, &e->right, err, errptr);
+ ret = cfg_parse_cond_and(&in, &e->right, err, errptr, maxdepth - 1);
if (ret > 0)
*text = in;
done:
* on failure. On success, the caller will have to free all lower-level
* allocated structs using cfg_free_cond_expr(). An error will be set in
* <err> on error, and only in this case. In this case the first bad
- * character will be reported in <errptr>.
+ * character will be reported in <errptr>. <maxdepth> corresponds to the
+ * maximum recursion depth permitted, it is decremented on each recursive call
+ * and the parsing will fail one reaching <= 0.
*/
-int cfg_parse_cond_expr(const char **text, struct cfg_cond_expr **expr, char **err, const char **errptr)
+int cfg_parse_cond_expr(const char **text, struct cfg_cond_expr **expr, char **err, const char **errptr, int maxdepth)
{
struct cfg_cond_expr *e;
const char *in = *text;
if (!*in) /* empty expr does not parse */
return 0;
+ *expr = NULL;
+ if (maxdepth <= 0) {
+ memprintf(err, "unparsable conditional expression '%s'", in);
+ if (errptr)
+ *errptr = in;
+ goto done;
+ }
+
e = *expr = calloc(1, sizeof(**expr));
if (!e) {
memprintf(err, "memory allocation error while parsing conditional expression '%s'", *text);
goto done;
}
- ret = cfg_parse_cond_and(&in, &e->left, err, errptr);
+ ret = cfg_parse_cond_and(&in, &e->left, err, errptr, maxdepth - 1);
if (ret == -1) // parse error, error already reported
goto done;
while (*in == ' ' || *in == '\t')
in++;
- ret = cfg_parse_cond_expr(&in, &e->right, err, errptr);
+ ret = cfg_parse_cond_expr(&in, &e->right, err, errptr, maxdepth - 1);
if (ret > 0)
*text = in;
done:
if (!*text) /* note: empty = false */
return 0;
- ret = cfg_parse_cond_expr(&text, &expr, err, errptr);
+ ret = cfg_parse_cond_expr(&text, &expr, err, errptr, MAX_CFG_RECURSION);
if (ret != 0) {
if (ret == -1) // parse error, error already reported
goto done;