]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] Handle long lines properly
authorKrzysztof Piotr Oledzki <ole@ans.pl>
Wed, 31 Oct 2007 23:33:12 +0000 (00:33 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 1 Nov 2007 22:00:51 +0000 (23:00 +0100)
Currently, there is a hidden line length limit in the haproxy, set
to 256-1 chars. With large acls (for example many hdr(host) matches)
it may be not enough and which is even worse, error message may
be totally confusing as everything above this limit is treated
as a next line:

echo -ne "frontend aqq 1.2.3.4:80\nmode http\nacl e hdr(host) -i X X X X X X X www.xx.example.com stats\n"|
 sed s/X/www.some-host-name.example.com/g > ha.cfg && haproxy -c -f ./ha.cfg

[WARNING] 300/163906 (11342) : parsing [./ha.cfg:4] : 'stats' ignored because frontend 'aqq' has no backend capability.

Recently I hit simmilar problem and it took me a while to find why
requests for "stats" are not handled properly.

This patch:
 - makes the limit configurable (LINESIZE)
 - increases default line length limit from 256 to 2048
 - increases MAX_LINE_ARGS from 40 to 64
 - fixes hidden assignment in fgets()
 - moves arg/end/args/line inside the loop, making code auditing easier
 - adds a check that shows error if the limit is reached
 - changes "*line++ = 0;" to "*line++ = '\0';" (cosmetics)

With this patch, when LINESIZE is defined to 256, above example produces:
[ALERT] 300/164724 (27364) : parsing [/tmp/ha.cfg:3]: line too long, limit: 255.
[ALERT] 300/164724 (27364) : Error reading configuration file : /tmp/ha.cfg

include/common/defaults.h
src/cfgparse.c

index 5b18767ca58d1ce80294fb7f26b9f1f663361cb5..1a69f40d9be4e58160afd6b499a9716c412b3c4c 100644 (file)
 #define REQURI_LEN      1024
 #define CAPTURE_LEN     64
 
+// maximum line size when parsing config
+#ifndef LINESIZE
+#define LINESIZE       2048
+#endif
+
 // max # args on a configuration line
-#define MAX_LINE_ARGS   40
+#define MAX_LINE_ARGS   64
 
 // max # of added headers per request
 #define MAX_NEWHDR      10
index 6fcf09fde31911746524121b116d26c7bc676799..e347cff8fbdfce70ba98d3297d749e58e71673f9 100644 (file)
@@ -2305,13 +2305,9 @@ int cfg_parse_listen(const char *file, int linenum, char **args)
  */
 int readcfgfile(const char *file)
 {
-       char thisline[256];
-       char *line;
+       char thisline[LINESIZE];
        FILE *f;
        int linenum = 0;
-       char *end;
-       char *args[MAX_LINE_ARGS + 1];
-       int arg;
        int cfgerr = 0;
        int confsect = CFG_NONE;
 
@@ -2323,11 +2319,25 @@ int readcfgfile(const char *file)
 
        init_default_instance();
 
-       while (fgets(line = thisline, sizeof(thisline), f) != NULL) {
+       while (fgets(thisline, sizeof(thisline), f) != NULL) {
+               int arg;
+               char *end;
+               char *args[MAX_LINE_ARGS + 1];
+               char *line = thisline;
+
                linenum++;
 
                end = line + strlen(line);
 
+               if (end-line == sizeof(thisline)-1 && *(end-1) != '\n') {
+                       /* Check if we reached the limit and the last char is not \n.
+                        * Watch out for the last line without the terminating '\n'!
+                        */
+                       Alert("parsing [%s:%d]: line too long, limit: %d.\n",
+                               file, linenum, sizeof(thisline)-1);
+                       return -1;
+               }
+
                /* skip leading spaces */
                while (isspace((unsigned char)*line))
                        line++;
@@ -2385,7 +2395,7 @@ int readcfgfile(const char *file)
                        }
                        else if (isspace((unsigned char)*line)) {
                                /* a non-escaped space is an argument separator */
-                               *line++ = 0;
+                               *line++ = '\0';
                                while (isspace((unsigned char)*line))
                                        line++;
                                args[++arg] = line;