BUG/MAJOR: trash must always be the size of a buffer

Before it was possible to resize the buffers using global.tune.bufsize,
the trash has always been the size of a buffer by design. Unfortunately,
the recent buffer sizing at runtime forgot to adjust the trash, resulting
in it being too short for content rewriting if buffers were enlarged from
the default value.

The bug was encountered in 1.4 so the fix must be backported there.
This commit is contained in:
David du Colombier 2012-05-16 14:16:48 +02:00 committed by Willy Tarreau
parent 7823de3d90
commit 7af4605ef7
10 changed files with 56 additions and 50 deletions

View File

@ -116,7 +116,8 @@ extern int relative_pid; /* process id starting at 1 */
extern int actconn; /* # of active sessions */
extern int listeners;
extern int jobs; /* # of active jobs */
extern char trash[BUFSIZE];
extern char *trash;
extern int trashlen;
extern char *swap_buffer;
extern int nb_oldpids; /* contains the number of old pids found */
extern const int zero;

View File

@ -1271,7 +1271,7 @@ static int acl_read_patterns_from_file( struct acl_keyword *aclkw,
opaque = 0;
pattern = NULL;
args[1] = "";
while (fgets(trash, sizeof(trash), file) != NULL) {
while (fgets(trash, trashlen, file) != NULL) {
line++;
c = trash;

View File

@ -528,6 +528,8 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
global.tune.bufsize = atol(args[1]);
if (global.tune.maxrewrite >= global.tune.bufsize / 2)
global.tune.maxrewrite = global.tune.bufsize / 2;
trashlen = global.tune.bufsize;
trash = realloc(trash, trashlen);
}
else if (!strcmp(args[0], "tune.maxrewrite")) {
if (*(args[1]) == 0) {
@ -1032,7 +1034,7 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
continue;
if (strcmp(kwl->kw[index].kw, args[0]) == 0) {
/* prepare error message just in case */
snprintf(trash, sizeof(trash),
snprintf(trash, trashlen,
"error near '%s' in '%s' section", args[0], "global");
rc = kwl->kw[index].parse(args, CFG_GLOBAL, NULL, NULL, &errmsg);
if (rc < 0) {
@ -3016,7 +3018,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
goto out;
}
expr = sample_parse_expr(args, &myidx, trash, sizeof(trash));
expr = sample_parse_expr(args, &myidx, trash, trashlen);
if (!expr) {
Alert("parsing [%s:%d] : '%s': %s\n", file, linenum, args[0], trash);
err_code |= ERR_ALERT | ERR_FATAL;
@ -5255,7 +5257,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
continue;
if (strcmp(kwl->kw[index].kw, args[0]) == 0) {
/* prepare error message just in case */
snprintf(trash, sizeof(trash),
snprintf(trash, trashlen,
"error near '%s' in %s section", args[0], cursection);
rc = kwl->kw[index].parse(args, CFG_LISTEN, curproxy, &defproxy, &errmsg);
if (rc < 0) {

View File

@ -237,7 +237,7 @@ static void set_server_check_status(struct server *s, short status, char *desc)
int health, rise, fall, state;
chunk_init(&msg, trash, sizeof(trash));
chunk_init(&msg, trash, trashlen);
/* FIXME begin: calculate local version of the health/rise/fall/state */
health = s->health;
@ -401,7 +401,7 @@ void set_server_down(struct server *s)
*/
xferred = redistribute_pending(s);
chunk_init(&msg, trash, sizeof(trash));
chunk_init(&msg, trash, trashlen);
if (s->state & SRV_MAINTAIN) {
chunk_printf(&msg,
@ -483,7 +483,7 @@ void set_server_up(struct server *s) {
*/
xferred = check_for_pending(s);
chunk_init(&msg, trash, sizeof(trash));
chunk_init(&msg, trash, trashlen);
if (old_state & SRV_MAINTAIN) {
chunk_printf(&msg,
@ -529,7 +529,7 @@ static void set_server_disabled(struct server *s) {
*/
xferred = redistribute_pending(s);
chunk_init(&msg, trash, sizeof(trash));
chunk_init(&msg, trash, trashlen);
chunk_printf(&msg,
"Load-balancing on %sServer %s/%s is disabled",
@ -565,7 +565,7 @@ static void set_server_enabled(struct server *s) {
*/
xferred = check_for_pending(s);
chunk_init(&msg, trash, sizeof(trash));
chunk_init(&msg, trash, trashlen);
chunk_printf(&msg,
"Load-balancing on %sServer %s/%s is enabled again",

View File

@ -573,7 +573,7 @@ static void stats_sock_table_key_request(struct stream_interface *si, char **arg
if (show) {
struct chunk msg;
chunk_init(&msg, trash, sizeof(trash));
chunk_init(&msg, trash, trashlen);
if (!stats_dump_table_head_to_buffer(&msg, si, px, px))
return;
stats_dump_table_entry_to_buffer(&msg, si, px, ts);
@ -922,7 +922,7 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line)
}
/* return server's effective weight at the moment */
snprintf(trash, sizeof(trash), "%d (initial %d)\n", sv->uweight, sv->iweight);
snprintf(trash, trashlen, "%d (initial %d)\n", sv->uweight, sv->iweight);
bi_putstr(si->ib, trash);
return 1;
}
@ -1385,7 +1385,7 @@ static void cli_io_handler(struct stream_interface *si)
if (buffer_almost_full(si->ib))
break;
reql = bo_getline(si->ob, trash, sizeof(trash));
reql = bo_getline(si->ob, trash, trashlen);
if (reql <= 0) { /* closed or EOL not found */
if (reql == 0)
break;
@ -1561,7 +1561,7 @@ static int stats_dump_raw_to_buffer(struct stream_interface *si)
struct chunk msg;
unsigned int up;
chunk_init(&msg, trash, sizeof(trash));
chunk_init(&msg, trash, trashlen);
switch (si->applet.state) {
case STAT_ST_INIT:
@ -1677,7 +1677,7 @@ static int stats_http_redir(struct stream_interface *si, struct uri_auth *uri)
struct session *s = si->applet.private;
struct chunk msg;
chunk_init(&msg, trash, sizeof(trash));
chunk_init(&msg, trash, trashlen);
switch (si->applet.state) {
case STAT_ST_INIT:
@ -1781,7 +1781,7 @@ static int stats_dump_http(struct stream_interface *si, struct uri_auth *uri)
struct chunk msg;
unsigned int up;
chunk_init(&msg, trash, sizeof(trash));
chunk_init(&msg, trash, trashlen);
switch (si->applet.state) {
case STAT_ST_INIT:
@ -2151,7 +2151,7 @@ static int stats_dump_proxy(struct stream_interface *si, struct proxy *px, struc
struct listener *l;
struct chunk msg;
chunk_init(&msg, trash, sizeof(trash));
chunk_init(&msg, trash, trashlen);
switch (si->applet.ctx.stats.px_st) {
case STAT_PX_ST_INIT:
@ -3205,7 +3205,7 @@ static int stats_dump_full_sess_to_buffer(struct stream_interface *si)
extern const char *monthname[12];
char pn[INET6_ADDRSTRLEN];
chunk_init(&msg, trash, sizeof(trash));
chunk_init(&msg, trash, trashlen);
sess = si->applet.ctx.sess.target;
if (si->applet.ctx.sess.section > 0 && si->applet.ctx.sess.uid != sess->uniq_id) {
@ -3459,7 +3459,7 @@ static int stats_dump_sess_to_buffer(struct stream_interface *si)
return 1;
}
chunk_init(&msg, trash, sizeof(trash));
chunk_init(&msg, trash, trashlen);
switch (si->applet.state) {
case STAT_ST_INIT:
@ -3680,7 +3680,7 @@ static int stats_table_request(struct stream_interface *si, bool show)
return 1;
}
chunk_init(&msg, trash, sizeof(trash));
chunk_init(&msg, trash, trashlen);
while (si->applet.state != STAT_ST_FIN) {
switch (si->applet.state) {
@ -3875,7 +3875,7 @@ static int stats_dump_errors_to_buffer(struct stream_interface *si)
if (unlikely(si->ib->flags & (BF_WRITE_ERROR|BF_SHUTW)))
return 1;
chunk_init(&msg, trash, sizeof(trash));
chunk_init(&msg, trash, trashlen);
if (!si->applet.ctx.errors.px) {
/* the function had not been called yet, let's prepare the

View File

@ -143,7 +143,8 @@ static int *oldpids = NULL;
static int oldpids_sig; /* use USR1 or TERM */
/* this is used to drain data, and as a temporary buffer for sprintf()... */
char trash[BUFSIZE];
char *trash = NULL;
int trashlen = BUFSIZE;
/* this buffer is always the same size as standard buffers and is used for
* swapping data inside a buffer.
@ -301,7 +302,7 @@ void sig_dump_state(struct sig_handler *sh)
send_log(p, LOG_NOTICE, "SIGHUP received, dumping servers states for proxy %s.\n", p->id);
while (s) {
snprintf(trash, sizeof(trash),
snprintf(trash, trashlen,
"SIGHUP: Server %s/%s is %s. Conn: %d act, %d pend, %lld tot.",
p->id, s->id,
(s->state & SRV_RUNNING) ? "UP" : "DOWN",
@ -313,18 +314,18 @@ void sig_dump_state(struct sig_handler *sh)
/* FIXME: those info are a bit outdated. We should be able to distinguish between FE and BE. */
if (!p->srv) {
snprintf(trash, sizeof(trash),
snprintf(trash, trashlen,
"SIGHUP: Proxy %s has no servers. Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
p->id,
p->feconn, p->beconn, p->totpend, p->nbpend, p->fe_counters.cum_conn, p->be_counters.cum_conn);
} else if (p->srv_act == 0) {
snprintf(trash, sizeof(trash),
snprintf(trash, trashlen,
"SIGHUP: Proxy %s %s ! Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
p->id,
(p->srv_bck) ? "is running on backup servers" : "has no server available",
p->feconn, p->beconn, p->totpend, p->nbpend, p->fe_counters.cum_conn, p->be_counters.cum_conn);
} else {
snprintf(trash, sizeof(trash),
snprintf(trash, trashlen,
"SIGHUP: Proxy %s has %d active servers and %d backup servers available."
" Conn: act(FE+BE): %d+%d, %d pend (%d unass), tot(FE+BE): %lld+%lld.",
p->id, p->srv_act, p->srv_bck,
@ -359,6 +360,8 @@ void init(int argc, char **argv)
char *progname;
char *change_dir = NULL;
trash = malloc(trashlen);
/* NB: POSIX does not make it mandatory for gethostname() to NULL-terminate
* the string in case of truncation, and at least FreeBSD appears not to do
* it.

View File

@ -231,7 +231,7 @@ static void peer_io_handler(struct stream_interface *si)
si->applet.st0 = PEER_SESSION_GETVERSION;
/* fall through */
case PEER_SESSION_GETVERSION:
reql = bo_getline(si->ob, trash, sizeof(trash));
reql = bo_getline(si->ob, trash, trashlen);
if (reql <= 0) { /* closed or EOL not found */
if (reql == 0)
goto out;
@ -262,7 +262,7 @@ static void peer_io_handler(struct stream_interface *si)
si->applet.st0 = PEER_SESSION_GETHOST;
/* fall through */
case PEER_SESSION_GETHOST:
reql = bo_getline(si->ob, trash, sizeof(trash));
reql = bo_getline(si->ob, trash, trashlen);
if (reql <= 0) { /* closed or EOL not found */
if (reql == 0)
goto out;
@ -292,7 +292,7 @@ static void peer_io_handler(struct stream_interface *si)
case PEER_SESSION_GETPEER: {
struct peer *curpeer;
char *p;
reql = bo_getline(si->ob, trash, sizeof(trash));
reql = bo_getline(si->ob, trash, trashlen);
if (reql <= 0) { /* closed or EOL not found */
if (reql == 0)
goto out;
@ -345,7 +345,7 @@ static void peer_io_handler(struct stream_interface *si)
size_t key_size;
char *p;
reql = bo_getline(si->ob, trash, sizeof(trash));
reql = bo_getline(si->ob, trash, trashlen);
if (reql <= 0) { /* closed or EOL not found */
if (reql == 0)
goto out;
@ -446,7 +446,7 @@ static void peer_io_handler(struct stream_interface *si)
case PEER_SESSION_SENDSUCCESS:{
struct peer_session *ps = (struct peer_session *)si->applet.private;
repl = snprintf(trash, sizeof(trash), "%d\n", PEER_SESSION_SUCCESSCODE);
repl = snprintf(trash, trashlen, "%d\n", PEER_SESSION_SUCCESSCODE);
repl = bi_putblk(si->ib, trash, repl);
if (repl <= 0) {
if (repl == -1)
@ -497,7 +497,7 @@ static void peer_io_handler(struct stream_interface *si)
struct peer_session *ps = (struct peer_session *)si->applet.private;
/* Send headers */
repl = snprintf(trash, sizeof(trash),
repl = snprintf(trash, trashlen,
PEER_SESSION_PROTO_NAME " 1.0\n%s\n%s %d\n%s %lu %d\n",
ps->peer->id,
localpeer,
@ -506,7 +506,7 @@ static void peer_io_handler(struct stream_interface *si)
ps->table->table->type,
(int)ps->table->table->key_size);
if (repl >= sizeof(trash)) {
if (repl >= trashlen) {
si->applet.st0 = PEER_SESSION_END;
goto switchstate;
}
@ -529,7 +529,7 @@ static void peer_io_handler(struct stream_interface *si)
if (si->ib->flags & BF_WRITE_PARTIAL)
ps->statuscode = PEER_SESSION_CONNECTEDCODE;
reql = bo_getline(si->ob, trash, sizeof(trash));
reql = bo_getline(si->ob, trash, trashlen);
if (reql <= 0) { /* closed or EOL not found */
if (reql == 0)
goto out;
@ -904,7 +904,7 @@ static void peer_io_handler(struct stream_interface *si)
}
ts = eb32_entry(eb, struct stksess, upd);
msglen = peer_prepare_datamsg(ts, ps, trash, sizeof(trash));
msglen = peer_prepare_datamsg(ts, ps, trash, trashlen);
if (msglen) {
/* message to buffer */
repl = bi_putblk(si->ib, trash, msglen);
@ -938,7 +938,7 @@ static void peer_io_handler(struct stream_interface *si)
}
ts = eb32_entry(eb, struct stksess, upd);
msglen = peer_prepare_datamsg(ts, ps, trash, sizeof(trash));
msglen = peer_prepare_datamsg(ts, ps, trash, trashlen);
if (msglen) {
/* message to buffer */
repl = bi_putblk(si->ib, trash, msglen);
@ -996,7 +996,7 @@ static void peer_io_handler(struct stream_interface *si)
}
ts = eb32_entry(eb, struct stksess, upd);
msglen = peer_prepare_datamsg(ts, ps, trash, sizeof(trash));
msglen = peer_prepare_datamsg(ts, ps, trash, trashlen);
if (msglen) {
/* message to buffer */
repl = bi_putblk(si->ib, trash, msglen);
@ -1016,7 +1016,7 @@ static void peer_io_handler(struct stream_interface *si)
goto out;
}
case PEER_SESSION_EXIT:
repl = snprintf(trash, sizeof(trash), "%d\n", si->applet.st1);
repl = snprintf(trash, trashlen, "%d\n", si->applet.st1);
if (bi_putblk(si->ib, trash, repl) == -1)
goto out;

View File

@ -390,14 +390,14 @@ const char http_is_ver_token[256] = {
static void http_silent_debug(int line, struct session *s)
{
int size = 0;
size += snprintf(trash + size, sizeof(trash) - size,
size += snprintf(trash + size, trashlen - size,
"[%04d] req: p=%d(%d) s=%d bf=%08x an=%08x data=%p size=%d l=%d w=%p r=%p o=%p sm=%d fw=%ld tf=%08x\n",
line,
s->si[0].state, s->si[0].fd, s->txn.req.msg_state, s->req->flags, s->req->analysers,
s->req->data, s->req->size, s->req->l, s->req->w, s->req->r, s->req->p, s->req->o, s->req->to_forward, s->txn.flags);
write(-1, trash, size);
size = 0;
size += snprintf(trash + size, sizeof(trash) - size,
size += snprintf(trash + size, trashlen - size,
" %04d rep: p=%d(%d) s=%d bf=%08x an=%08x data=%p size=%d l=%d w=%p r=%p o=%p sm=%d fw=%ld\n",
line,
s->si[1].state, s->si[1].fd, s->txn.rsp.msg_state, s->rep->flags, s->rep->analysers,
@ -766,7 +766,7 @@ void perform_http_redirect(struct session *s, struct stream_interface *si)
/* 1: create the response header */
rdr.len = strlen(HTTP_302);
rdr.str = trash;
rdr.size = sizeof(trash);
rdr.size = trashlen;
memcpy(rdr.str, HTTP_302, rdr.len);
srv = target_srv(&s->target);
@ -2888,7 +2888,7 @@ int http_process_req_common(struct session *s, struct buffer *req, int an_bit, s
realm = do_stats?STATS_DEFAULT_REALM:px->id;
sprintf(trash, (txn->flags & TX_USE_PX_CONN) ? HTTP_407_fmt : HTTP_401_fmt, realm);
chunk_initlen(&msg, trash, sizeof(trash), strlen(trash));
chunk_initlen(&msg, trash, trashlen, strlen(trash));
txn->status = 401;
stream_int_retnclose(req->prod, &msg);
/* on 401 we still count one error, because normal browsing
@ -2996,7 +2996,7 @@ int http_process_req_common(struct session *s, struct buffer *req, int an_bit, s
}
if (ret) {
struct chunk rdr = { .str = trash, .size = sizeof(trash), .len = 0 };
struct chunk rdr = { .str = trash, .size = trashlen, .len = 0 };
const char *msg_fmt;
/* build redirect message */
@ -3657,7 +3657,7 @@ int http_send_name_header(struct http_txn *txn, struct proxy* be, const char* sr
hdr_val += hdr_name_len;
*hdr_val++ = ':';
*hdr_val++ = ' ';
hdr_val += strlcpy2(hdr_val, srv_name, trash + sizeof(trash) - hdr_val);
hdr_val += strlcpy2(hdr_val, srv_name, trash + trashlen - hdr_val);
http_header_add_tail2(&txn->req, &txn->hdr_idx, trash, hdr_val - trash);
return 0;
@ -7290,7 +7290,7 @@ void debug_hdr(const char *dir, struct session *t, const char *start, const char
len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
dir, (unsigned short)t->req->prod->fd, (unsigned short)t->req->cons->fd);
max = end - start;
UBOUND(max, sizeof(trash) - len - 1);
UBOUND(max, trashlen - len - 1);
len += strlcpy2(trash + len, start, max + 1);
trash[len++] = '\n';
if (write(1, trash, len) < 0) /* shut gcc warning */;

View File

@ -529,7 +529,7 @@ static int sock_raw_write_loop(struct stream_interface *si, struct buffer *b)
* (which is recomputed every time since it's constant). If
* it is positive, it means we have to send from the start.
*/
ret = make_proxy_line(trash, sizeof(trash),
ret = make_proxy_line(trash, trashlen,
&b->prod->addr.from, &b->prod->addr.to);
if (!ret)
return -1;

View File

@ -35,12 +35,12 @@ index ddadddd..28bbfce 100644
+
+ if (1) {
+ for (i=0; i<16096; i++)
+ chunk_printf(&msg, sizeof(trash), "*");
+ chunk_printf(&msg, trashlen, "*");
+
+ chunk_printf(&msg, sizeof(trash), "\n");
+ chunk_printf(&msg, trashlen, "\n");
+#if 0
if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
chunk_printf(&msg, sizeof(trash),
chunk_printf(&msg, trashlen,
/* name, queue */
@@ -694,6 +702,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri)
px->failed_req,
@ -48,7 +48,7 @@ index ddadddd..28bbfce 100644
px->state == PR_STIDLE ? "FULL" : "STOP");
+#endif
} else {
chunk_printf(&msg, sizeof(trash),
chunk_printf(&msg, trashlen,
/* pxid, name, queue cur, queue max, */