When using test-pmd with flow director in FreeBSD, the application will
segfault/Bus error while parsing the command-line. This is due to how
each commands result structure is represented during parsing, where the offsets
for each tokens value is stored in a character array(char result_buf[BUFSIZ])
in cmdline_parse()(./lib/librte_cmdline/cmdline_parse.c).

The overflow occurs where BUFSIZ is less than the size of a commands result
structure, in this case "struct cmd_pkt_filter_result"
(app/test-pmd/cmdline.c) is 1088 bytes and BUFSIZ on FreeBSD is 1024 bytes as
opposed to 8192 bytes on Linux.

The problem can be reproduced by running test-pmd on FreeBSD:
./testpmd -c 0x3 -n 4 -- -i --portmask=0x3 --pkt-filter-mode=perfect
And adding a filter:
add_perfect_filter 0 udp src 192.168.0.0 1024 dst 192.168.0.0 1024 flexbytes
0x800 vlan 0 queue 0 soft 0x17

This patch removes the OS dependency on BUFSIZ and defines and uses a
library #define CMDLINE_PARSE_RESULT_BUFSIZE 8192

Added boundary checking to ensure this buffer size cannot overflow, with
an error message being produced.

Suggested-by: Olivier MATZ <olivier.matz at 6wind.com>
http://git.droids-corp.org/?p=libcmdline.git;a=commitdiff;h=b1d5b169352e57df3fc14c51ffad4b83f3e5613f

Signed-off-by: Alan Carew <alan.carew at intel.com>
---
 lib/librte_cmdline/cmdline_parse.c | 22 +++++++++++++++-------
 lib/librte_cmdline/cmdline_parse.h |  3 +++
 2 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/lib/librte_cmdline/cmdline_parse.c 
b/lib/librte_cmdline/cmdline_parse.c
index 940480d..f86f163 100644
--- a/lib/librte_cmdline/cmdline_parse.c
+++ b/lib/librte_cmdline/cmdline_parse.c
@@ -138,7 +138,7 @@ nb_common_chars(const char * s1, const char * s2)
  */
 static int
 match_inst(cmdline_parse_inst_t *inst, const char *buf,
-          unsigned int nb_match_token, void * result_buf)
+          unsigned int nb_match_token, void *result_buf, unsigned 
result_buf_size)
 {
        unsigned int token_num=0;
        cmdline_parse_token_hdr_t * token_p;
@@ -162,10 +162,18 @@ match_inst(cmdline_parse_inst_t *inst, const char *buf,
                if ( isendofline(*buf) || iscomment(*buf) )
                        break;

-               if (result_buf)
+               if (result_buf) {
+                       if (token_hdr.offset > result_buf_size) {
+                               printf("Parse error(%s:%d): Token offset(%u) 
exceeds maximum "
+                               "size(%u)\n", __FILE__, __LINE__, 
token_hdr.offset,
+                               result_buf_size);
+                               return -ENOBUFS;
+                       }
+
                        n = token_hdr.ops->parse(token_p, buf,
                                                 (char *)result_buf +
                                                 token_hdr.offset);
+               }
                else
                        n = token_hdr.ops->parse(token_p, buf, NULL);

@@ -219,7 +227,7 @@ cmdline_parse(struct cmdline *cl, const char * buf)
        unsigned int inst_num=0;
        cmdline_parse_inst_t *inst;
        const char *curbuf;
-       char result_buf[BUFSIZ];
+       char result_buf[CMDLINE_PARSE_RESULT_BUFSIZE];
        void (*f)(void *, struct cmdline *, void *) = NULL;
        void *data = NULL;
        int comment = 0;
@@ -280,7 +288,7 @@ cmdline_parse(struct cmdline *cl, const char * buf)
                debug_printf("INST %d\n", inst_num);

                /* fully parsed */
-               tok = match_inst(inst, buf, 0, result_buf);
+               tok = match_inst(inst, buf, 0, result_buf, sizeof(result_buf));

                if (tok > 0) /* we matched at least one token */
                        err = CMDLINE_PARSE_BAD_ARGS;
@@ -377,10 +385,10 @@ cmdline_complete(struct cmdline *cl, const char *buf, int 
*state,
                inst = ctx[inst_num];
                while (inst) {
                        /* parse the first tokens of the inst */
-                       if (nb_token && match_inst(inst, buf, nb_token, NULL))
+                       if (nb_token && match_inst(inst, buf, nb_token, NULL, 
0))
                                goto next;

-                       debug_printf("instruction match \n");
+                       debug_printf("instruction match\n");
                        token_p = inst->tokens[nb_token];
                        if (token_p)
                                memcpy(&token_hdr, token_p, sizeof(token_hdr));
@@ -471,7 +479,7 @@ cmdline_complete(struct cmdline *cl, const char *buf, int 
*state,
                /* we need to redo it */
                inst = ctx[inst_num];

-               if (nb_token && match_inst(inst, buf, nb_token, NULL))
+               if (nb_token && match_inst(inst, buf, nb_token, NULL, 0))
                        goto next2;

                token_p = inst->tokens[nb_token];
diff --git a/lib/librte_cmdline/cmdline_parse.h 
b/lib/librte_cmdline/cmdline_parse.h
index f18836d..dae53ba 100644
--- a/lib/librte_cmdline/cmdline_parse.h
+++ b/lib/librte_cmdline/cmdline_parse.h
@@ -80,6 +80,9 @@ extern "C" {
 #define CMDLINE_PARSE_COMPLETE_AGAIN    1
 #define CMDLINE_PARSE_COMPLETED_BUFFER  2

+/* maximum buffer size for parsed result */
+#define CMDLINE_PARSE_RESULT_BUFSIZE 8192
+
 /**
  * Stores a pointer to the ops struct, and the offset: the place to
  * write the parsed result in the destination structure.
-- 
1.9.3

Reply via email to