Skip to content

Commit 3c05f5c

Browse files
committed
harden mod_lbmethod_heartbeat integer parsing and slot math
1 parent 140c0bc commit 3c05f5c

1 file changed

Lines changed: 58 additions & 7 deletions

File tree

modules/proxy/balancers/mod_lbmethod_heartbeat.c

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
#include "ap_slotmem.h"
2323
#include "heartbeat.h"
2424

25+
#include <errno.h>
26+
#include <limits.h>
27+
2528
#ifndef LBM_HEARTBEAT_MAX_LASTSEEN
2629
/* If we haven't seen a heartbeat in the last N seconds, don't count this IP
2730
* as allive.
@@ -61,6 +64,28 @@ typedef struct ctx_servers {
6164
apr_hash_t *servers;
6265
} ctx_servers_t;
6366

67+
static int hb_parse_int(const char *val, int min, int max, int *result)
68+
{
69+
apr_int64_t parsed;
70+
char *end = NULL;
71+
72+
if (!val || !*val) {
73+
return 0;
74+
}
75+
76+
errno = 0;
77+
parsed = apr_strtoi64(val, &end, 10);
78+
if (errno == ERANGE || end == val || *end != '\0') {
79+
return 0;
80+
}
81+
if (parsed < min || parsed > max) {
82+
return 0;
83+
}
84+
85+
*result = (int)parsed;
86+
return 1;
87+
}
88+
6489
static void
6590
argstr_to_table(apr_pool_t *p, char *str, apr_table_t *parms)
6691
{
@@ -179,19 +204,31 @@ static apr_status_t readfile_heartbeats(const char *path, apr_hash_t *servers,
179204
argstr_to_table(pool, apr_pstrdup(pool, t), hbt);
180205

181206
if ((val = apr_table_get(hbt, "busy"))) {
182-
server->busy = atoi(val);
207+
int parsed;
208+
if (hb_parse_int(val, 0, INT_MAX, &parsed)) {
209+
server->busy = parsed;
210+
}
183211
}
184212

185213
if ((val = apr_table_get(hbt, "ready"))) {
186-
server->ready = atoi(val);
214+
int parsed;
215+
if (hb_parse_int(val, 0, INT_MAX, &parsed)) {
216+
server->ready = parsed;
217+
}
187218
}
188219

189220
if ((val = apr_table_get(hbt, "lastseen"))) {
190-
server->seen = atoi(val);
221+
int parsed;
222+
if (hb_parse_int(val, 0, INT_MAX, &parsed)) {
223+
server->seen = parsed;
224+
}
191225
}
192226

193227
if ((val = apr_table_get(hbt, "port"))) {
194-
server->port = atoi(val);
228+
int parsed;
229+
if (hb_parse_int(val, 1, 65535, &parsed)) {
230+
server->port = parsed;
231+
}
195232
}
196233

197234
if (server->busy == 0 && server->ready != 0) {
@@ -312,7 +349,13 @@ static proxy_worker *find_best_hb(proxy_balancer *balancer,
312349
if (PROXY_WORKER_IS_USABLE(*worker)) {
313350
server->worker = *worker;
314351
if (server->seen < LBM_HEARTBEAT_MAX_LASTSEEN) {
315-
openslots += server->ready;
352+
apr_uint32_t ready = (apr_uint32_t)server->ready;
353+
if (ready > APR_UINT32_MAX - openslots) {
354+
openslots = APR_UINT32_MAX;
355+
}
356+
else {
357+
openslots += ready;
358+
}
316359
APR_ARRAY_PUSH(up_servers, hb_server_t *) = server;
317360
}
318361
}
@@ -325,12 +368,20 @@ static proxy_worker *find_best_hb(proxy_balancer *balancer,
325368
pick = ap_random_pick(0, openslots);
326369

327370
for (i = 0; i < up_servers->nelts; i++) {
371+
apr_uint32_t upper;
328372
server = APR_ARRAY_IDX(up_servers, i, hb_server_t *);
329-
if (pick >= c && pick <= c + server->ready) {
373+
if ((apr_uint32_t)server->ready > APR_UINT32_MAX - c) {
374+
upper = APR_UINT32_MAX;
375+
}
376+
else {
377+
upper = c + (apr_uint32_t)server->ready;
378+
}
379+
380+
if (pick >= c && pick <= upper) {
330381
mycandidate = server->worker;
331382
}
332383

333-
c += server->ready;
384+
c = upper;
334385
}
335386
}
336387

0 commit comments

Comments
 (0)