|
From 5bff05986c501d9ffb67873b60472f9c2a2e41be Mon Sep 17 00:00:00 2001
|
|
From: Willy Tarreau <w@1wt.eu>
|
|
Date: Wed, 13 May 2015 12:24:53 +0200
|
|
Subject: [PATCH 8/8] BUG/MEDIUM: checks: do not dereference a list as a
|
|
tcpcheck struct
|
|
|
|
The method used to skip to next rule in the list is wrong, it assumes
|
|
that the list element starts at the same offset as the rule. It happens
|
|
to be true on most architectures since the list is the first element for
|
|
now but it's definitely wrong. Now the code doesn't crash anymore when
|
|
the struct list is moved anywhere else in the struct tcpcheck_rule.
|
|
|
|
This fix must be backported to 1.5.
|
|
(cherry picked from commit 5581c27b579cbfc53afb0ca04cdeebe7e2200131)
|
|
[wt: changes from 1.6 : no tcp-check comments, check becomes s->proxy]
|
|
---
|
|
src/cfgparse.c | 18 +++++++-----------
|
|
src/checks.c | 15 +++++++++------
|
|
2 files changed, 16 insertions(+), 17 deletions(-)
|
|
|
|
diff --git a/src/cfgparse.c b/src/cfgparse.c
|
|
index dba59d1..e04eff8 100644
|
|
--- a/src/cfgparse.c
|
|
+++ b/src/cfgparse.c
|
|
@@ -4362,20 +4362,16 @@ stats_error_parsing:
|
|
const char *ptr_arg;
|
|
int cur_arg;
|
|
struct tcpcheck_rule *tcpcheck;
|
|
- struct list *l;
|
|
|
|
/* check if first rule is also a 'connect' action */
|
|
- l = (struct list *)&curproxy->tcpcheck_rules;
|
|
- if (l->p != l->n) {
|
|
- tcpcheck = (struct tcpcheck_rule *)l->n;
|
|
+ tcpcheck = LIST_NEXT(&curproxy->tcpcheck_rules, struct tcpcheck_rule *, list);
|
|
|
|
- if (&tcpcheck->list != &curproxy->tcpcheck_rules
|
|
- && tcpcheck->action != TCPCHK_ACT_CONNECT) {
|
|
- Alert("parsing [%s:%d] : first step MUST also be a 'connect' when there is a 'connect' step in the tcp-check ruleset.\n",
|
|
- file, linenum);
|
|
- err_code |= ERR_ALERT | ERR_FATAL;
|
|
- goto out;
|
|
- }
|
|
+ if (&tcpcheck->list != &curproxy->tcpcheck_rules
|
|
+ && tcpcheck->action != TCPCHK_ACT_CONNECT) {
|
|
+ Alert("parsing [%s:%d] : first step MUST also be a 'connect' when there is a 'connect' step in the tcp-check ruleset.\n",
|
|
+ file, linenum);
|
|
+ err_code |= ERR_ALERT | ERR_FATAL;
|
|
+ goto out;
|
|
}
|
|
|
|
cur_arg = 2;
|
|
diff --git a/src/checks.c b/src/checks.c
|
|
index e13d561..27a23b2 100644
|
|
--- a/src/checks.c
|
|
+++ b/src/checks.c
|
|
@@ -1444,7 +1444,10 @@ static int connect_chk(struct task *t)
|
|
quickack = check->type == 0 || check->type == PR_O2_TCPCHK_CHK;
|
|
|
|
if (check->type == PR_O2_TCPCHK_CHK && !LIST_ISEMPTY(&s->proxy->tcpcheck_rules)) {
|
|
- struct tcpcheck_rule *r = (struct tcpcheck_rule *) s->proxy->tcpcheck_rules.n;
|
|
+ struct tcpcheck_rule *r;
|
|
+
|
|
+ r = LIST_NEXT(&s->proxy->tcpcheck_rules, struct tcpcheck_rule *, list);
|
|
+
|
|
/* if first step is a 'connect', then tcpcheck_main must run it */
|
|
if (r->action == TCPCHK_ACT_CONNECT) {
|
|
tcpcheck_main(conn);
|
|
@@ -1952,7 +1955,7 @@ static void tcpcheck_main(struct connection *conn)
|
|
/* have 'next' point to the next rule or NULL if we're on the
|
|
* last one, connect() needs this.
|
|
*/
|
|
- next = (struct tcpcheck_rule *)check->current_step->list.n;
|
|
+ next = LIST_NEXT(&check->current_step->list, struct tcpcheck_rule *, list);
|
|
|
|
if (&next->list == head)
|
|
next = NULL;
|
|
@@ -2055,7 +2058,7 @@ static void tcpcheck_main(struct connection *conn)
|
|
}
|
|
|
|
/* allow next rule */
|
|
- check->current_step = (struct tcpcheck_rule *)check->current_step->list.n;
|
|
+ check->current_step = LIST_NEXT(&check->current_step->list, struct tcpcheck_rule *, list);
|
|
|
|
if (&check->current_step->list == head)
|
|
break;
|
|
@@ -2112,7 +2115,7 @@ static void tcpcheck_main(struct connection *conn)
|
|
*check->bo->p = '\0'; /* to make gdb output easier to read */
|
|
|
|
/* go to next rule and try to send */
|
|
- check->current_step = (struct tcpcheck_rule *)check->current_step->list.n;
|
|
+ check->current_step = LIST_NEXT(&check->current_step->list, struct tcpcheck_rule *, list);
|
|
|
|
if (&check->current_step->list == head)
|
|
break;
|
|
@@ -2200,7 +2203,7 @@ static void tcpcheck_main(struct connection *conn)
|
|
/* matched and was supposed to => OK, next step */
|
|
else {
|
|
/* allow next rule */
|
|
- check->current_step = (struct tcpcheck_rule *)check->current_step->list.n;
|
|
+ check->current_step = LIST_NEXT(&check->current_step->list, struct tcpcheck_rule *, list);
|
|
|
|
if (&check->current_step->list == head)
|
|
break;
|
|
@@ -2215,7 +2218,7 @@ static void tcpcheck_main(struct connection *conn)
|
|
/* not matched and was not supposed to => OK, next step */
|
|
if (check->current_step->inverse) {
|
|
/* allow next rule */
|
|
- check->current_step = (struct tcpcheck_rule *)check->current_step->list.n;
|
|
+ check->current_step = LIST_NEXT(&check->current_step->list, struct tcpcheck_rule *, list);
|
|
|
|
if (&check->current_step->list == head)
|
|
break;
|
|
--
|
|
2.0.5
|
|
|