]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MAJOR: trash must always be the size of a buffer
authorDavid du Colombier <dducolombier@exceliance.fr>
Wed, 16 May 2012 12:16:48 +0000 (14:16 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 16 May 2012 12:21:55 +0000 (14:21 +0200)
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.

include/types/global.h
src/acl.c
src/cfgparse.c
src/checks.c
src/dumpstats.c
src/haproxy.c
src/peers.c
src/proto_http.c
src/sock_raw.c
tests/0000-debug-stats.diff

index 83caf2192c0ea20a19289434dcb87740838042ce..b4fa23e0eeced4048b7c86210d0e2b0aec621129 100644 (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;
index 54c4e15d2bbaa2628813c568a19b11fa2bc8a7e8..8ec046ff02750dfb18a1b338f788632f5d1f10d6 100644 (file)
--- a/src/acl.c
+++ b/src/acl.c
@@ -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;
 
index 49d1dbe02190d5973e6f9bc7b65ad5a1b17f5978..b3ae050e14e9925129c76ca2e1701e7b614fdcb3 100644 (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 @@ stats_error_parsing:
                                        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) {
index 3604e5a0e08572197a9a4dd1f16c83a1c5520fdf..78ec4ad6dd7a2d5309054804fee24dd9cdbc11c2 100644 (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",
index 43cc275ae8596dd88f7374aa7d1539a2a016c386..b95418e94bffc04382d0ff4e35aa6ac2fa0063af 100644 (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
index 2afbb3b1a548d8e48300597af4d2a0978694e045..8d3e6e3764650521fd7c5b5d8af17a48ac56b56a 100644 (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.
index 5456410b58dd281fbcf96c21d685cf946e39f1d6..f39c7df355eecfd2de62bd5dc6a51c2633cad9dc 100644 (file)
@@ -231,7 +231,7 @@ switchstate:
                                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 @@ switchstate:
                                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 @@ switchstate:
                        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 @@ switchstate:
                                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 @@ switchstate:
                        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 @@ switchstate:
                                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 @@ switchstate:
                                                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 @@ switchstate:
                                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 @@ incomplete:
                                                        }
 
                                                        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 @@ incomplete:
                                                        }
 
                                                        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 @@ incomplete:
                                                }
 
                                                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 @@ incomplete:
                                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;
index f18ae724de59931909d263064f019c7b40f52f28..5250f2359c265e01607507d8323c7704a4540466 100644 (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 */;
index b7edbfc977683435f1f48badc3dda4a74fe48ba9..db38cd574e188ab2bb74c4a1034df2cb2f98f9d3 100644 (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;
index 7368e043b232e581e4d0dc2b7181b6ab42728b6f..223df2c365564e1b4879a1f361d9f51b8e0a972c 100644 (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, */