BUG/MINOR: proxy: Missing calloc return value check in chash_init_server_tree

A memory allocation failure happening in chash_init_server_tree while
trying to allocate a server's lb_nodes item used in consistent hashing
would have resulted in a crash. This function is only called during
configuration parsing.

It was raised in GitHub issue #1233.
It could be backported to all stable branches.

(cherry picked from commit 476462010ecc2329e9ecba5afd20f84d9605d809)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit c5c5bc4e36ce4a6f3bc113c8e16824fdb276c220)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit a0320ad186fc4e71c1fec692a0e16c337d28c207)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
(cherry picked from commit 03f62de95fcf032e1c52725e8960960b5ebcfc07)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
diff --git a/include/proto/lb_chash.h b/include/proto/lb_chash.h
index 679dff3..54e2762 100644
--- a/include/proto/lb_chash.h
+++ b/include/proto/lb_chash.h
@@ -26,7 +26,7 @@
 #include <types/proxy.h>
 #include <types/server.h>
 
-void chash_init_server_tree(struct proxy *p);
+int chash_init_server_tree(struct proxy *p);
 struct server *chash_get_next_server(struct proxy *p, struct server *srvtoavoid);
 struct server *chash_get_server_hash(struct proxy *p, unsigned int hash, const struct server *avoid);
 
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 2523e21..4e3a691 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -3333,7 +3333,9 @@
 				init_server_map(curproxy);
 			} else if ((curproxy->lbprm.algo & BE_LB_PARM) == BE_LB_RR_RANDOM) {
 				curproxy->lbprm.algo |= BE_LB_LKUP_CHTREE | BE_LB_PROP_DYN;
-				chash_init_server_tree(curproxy);
+				if (chash_init_server_tree(curproxy) < 0) {
+					cfgerr++;
+				}
 			} else {
 				curproxy->lbprm.algo |= BE_LB_LKUP_RRTREE | BE_LB_PROP_DYN;
 				fwrr_init_server_groups(curproxy);
@@ -3353,7 +3355,9 @@
 		case BE_LB_KIND_HI:
 			if ((curproxy->lbprm.algo & BE_LB_HASH_TYPE) == BE_LB_HASH_CONS) {
 				curproxy->lbprm.algo |= BE_LB_LKUP_CHTREE | BE_LB_PROP_DYN;
-				chash_init_server_tree(curproxy);
+				if (chash_init_server_tree(curproxy) < 0) {
+					cfgerr++;
+				}
 			} else {
 				curproxy->lbprm.algo |= BE_LB_LKUP_MAP;
 				init_server_map(curproxy);
diff --git a/src/lb_chash.c b/src/lb_chash.c
index 23448df..c3b416d 100644
--- a/src/lb_chash.c
+++ b/src/lb_chash.c
@@ -26,6 +26,7 @@
 #include <types/server.h>
 
 #include <proto/backend.h>
+#include <proto/log.h>
 #include <proto/queue.h>
 
 /* Return next tree node after <node> which must still be in the tree, or be
@@ -467,8 +468,9 @@
  * constistent hashing. The servers receive an array of initialized nodes
  * with their assigned keys. It also sets p->lbprm.wdiv to the eweight to
  * uweight ratio.
+ * Return 0 in case of success, -1 in case of allocation failure.
  */
-void chash_init_server_tree(struct proxy *p)
+int chash_init_server_tree(struct proxy *p)
 {
 	struct server *srv;
 	struct eb_root init_head = EB_ROOT;
@@ -499,6 +501,10 @@
 		srv->lb_nodes_tot = srv->uweight * BE_WEIGHT_SCALE;
 		srv->lb_nodes_now = 0;
 		srv->lb_nodes = calloc(srv->lb_nodes_tot, sizeof(struct tree_occ));
+		if (!srv->lb_nodes) {
+			ha_alert("failed to allocate lb_nodes for server %s.\n", srv->id);
+			return -1;
+		}
 		for (node = 0; node < srv->lb_nodes_tot; node++) {
 			srv->lb_nodes[node].server = srv;
 			srv->lb_nodes[node].node.key = full_hash(srv->puid * SRV_EWGHT_RANGE + node);
@@ -507,4 +513,5 @@
 		if (srv_currently_usable(srv))
 			chash_queue_dequeue_srv(srv);
 	}
+	return 0;
 }