cmdline: check size of result buffer to avoid overflow
authorOlivier Matz <zer0@droids-corp.org>
Sun, 2 Jan 2011 18:45:51 +0000 (19:45 +0100)
committerOlivier Matz <zer0@droids-corp.org>
Sun, 13 Mar 2011 10:03:24 +0000 (11:03 +0100)
Signed-off-by: Olivier Matz <zer0@droids-corp.org>
14 files changed:
src/extension_example/parse_obj_list.c
src/extension_example/parse_obj_list.h
src/genconf/parse_confnode.c
src/genconf/parse_confnode.h
src/lib/cmdline_parse.c
src/lib/cmdline_parse.h
src/lib/cmdline_parse_etheraddr.c
src/lib/cmdline_parse_etheraddr.h
src/lib/cmdline_parse_ipaddr.c
src/lib/cmdline_parse_ipaddr.h
src/lib/cmdline_parse_num.c
src/lib/cmdline_parse_num.h
src/lib/cmdline_parse_string.c
src/lib/cmdline_parse_string.h

index 21fc019..aa743cf 100644 (file)
@@ -47,13 +47,17 @@ struct cmdline_token_ops token_obj_list_ops = {
 };
 
 int
-parse_obj_list(cmdline_parse_token_hdr_t *tk, const char *buf, void *res)
+parse_obj_list(cmdline_parse_token_hdr_t *tk, const char *buf, void *res,
+              unsigned ressize)
 {
        struct token_obj_list *tk2 = (struct token_obj_list *)tk;
        struct token_obj_list_data *tkd = &tk2->obj_list_data;
        struct object *o;
        unsigned int token_len = 0;
 
+       if (res && ressize < sizeof(struct object *))
+               return -1;
+
        token_len = strlen(buf);
 
        SLIST_FOREACH(o, tkd->list, next) {
index 1aeb7eb..3bde83e 100644 (file)
@@ -56,9 +56,10 @@ typedef struct token_obj_list parse_token_obj_list_t;
 
 extern struct cmdline_token_ops token_obj_list_ops;
 
-int parse_obj_list(cmdline_parse_token_hdr_t *tk, const char *srcbuf, void *res);
+int parse_obj_list(cmdline_parse_token_hdr_t *tk, const char *srcbuf,
+                  void *res, unsigned ressize);
 int complete_get_nb_obj_list(cmdline_parse_token_hdr_t *tk);
-int complete_get_elt_obj_list(cmdline_parse_token_hdr_t *tk, int idx, 
+int complete_get_elt_obj_list(cmdline_parse_token_hdr_t *tk, int idx,
                              char *dstbuf, unsigned int size);
 int get_help_obj_list(cmdline_parse_token_hdr_t *tk, char *dstbuf, unsigned int size);
 
index 5c8202b..b25166f 100644 (file)
@@ -135,7 +135,8 @@ get_from_idx(struct confnode *n, unsigned int *cur, unsigned int idx,
 }
 
 int
-parse_conf_node(cmdline_parse_token_hdr_t *tk, const char *buf, void *res)
+parse_conf_node(cmdline_parse_token_hdr_t *tk, const char *buf, void *res,
+               unsigned ressize)
 {
        struct token_conf_node *tk2 = (struct token_conf_node *)tk;
        struct token_conf_node_data *tkd = &tk2->conf_node_data;
@@ -144,6 +145,9 @@ parse_conf_node(cmdline_parse_token_hdr_t *tk, const char *buf, void *res)
        unsigned int token_len = 0;
        char token[CMDLINE_MAX_TOKEN_SIZE];
 
+       if (res && ressize < sizeof(struct confnode *))
+               return -1;
+
        /* if token is too big... */
        token_len = snprintf(token, sizeof(token), "%s", buf);
        if (token_len >= sizeof(token))
index e47f679..83a925a 100644 (file)
@@ -44,7 +44,8 @@ typedef struct token_conf_node parse_token_conf_node_t;
 
 extern struct cmdline_token_ops token_conf_node_ops;
 
-int parse_conf_node(cmdline_parse_token_hdr_t *tk, const char *srcbuf, void *res);
+int parse_conf_node(cmdline_parse_token_hdr_t *tk, const char *srcbuf,
+                   void *res, unsigned ressize);
 int complete_get_nb_conf_node(cmdline_parse_token_hdr_t *tk);
 int complete_get_elt_conf_node(cmdline_parse_token_hdr_t *tk, int idx,
                              char *dstbuf, unsigned int size);
index 37ccc23..060a8e9 100644 (file)
@@ -202,7 +202,7 @@ int cmdline_unquote_token(char *dst, unsigned dstlen,
  */
 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 *resbuf, unsigned resbuf_size)
 {
        unsigned int token_num=0;
        cmdline_parse_token_hdr_t * token_p;
@@ -231,12 +231,18 @@ match_inst(cmdline_parse_inst_t *inst, const char *buf,
                if (n == -EINVAL)
                        return -EINVAL;
 
-               if (result_buf)
+               if (resbuf == NULL)
+                       res = token_hdr.ops->parse(token_p, token_str, NULL, 0);
+               else {
+                       unsigned rb_sz;
+                       void *rb = (char *)resbuf + token_hdr.offset;
+                       if (token_hdr.offset > resbuf_size)
+                               return -ENOBUFS;
+                       rb_sz = resbuf_size - token_hdr.offset;
                        res = token_hdr.ops->parse(token_p, token_str,
-                                                (char *)result_buf +
-                                                token_hdr.offset);
-               else
-                       res = token_hdr.ops->parse(token_p, token_str, NULL);
+                                                  rb, rb_sz);
+               }
+
                if (res < 0)
                        break;
 
@@ -287,7 +293,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_MAX_DSTBUF_SIZE];
        void (*f)(void *, struct cmdline *, void *) = NULL;
        void *data = NULL;
        int comment = 0;
@@ -343,7 +349,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;
@@ -440,7 +446,7 @@ 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");
@@ -528,7 +534,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];
index 146f15c..e9e6308 100644 (file)
@@ -81,6 +81,7 @@
 #define CMDLINE_PARSE_COMPLETED_BUFFER  2
 
 #define CMDLINE_MAX_TOKEN_SIZE 128 /* including '\0' */
+#define CMDLINE_MAX_DSTBUF_SIZE 1024
 
 /**
  * Stores a pointer to the ops struct, and the offset: the place to
@@ -97,27 +98,30 @@ typedef struct cmdline_token_hdr cmdline_parse_token_hdr_t;
  *
  * parse() takes the token as first argument, then the source buffer
  * starting at the token we want to parse. The 3rd arg is a pointer
- * where we store the parsed data (as binary). It returns the number of
- * parsed chars on success and a negative value on error.
+ * where we store the parsed data (as binary), and the 4th arg is the
+ * size of this area. It returns 0 on success and a negative value on
+ * error.
  *
  * complete_get_nb() returns the number of possible values for this
  * token if completion is possible. If it is NULL or if it returns 0,
  * no completion is possible.
  *
  * complete_get_elt() copy in dstbuf (the size is specified in the
- * parameter) the i-th possible completion for this token.  returns 0
- * on success or and a negative value on error.
+ * parameter) the i-th possible completion for this token. Return 0
+ * on success or a negative value on error.
  *
  * get_help() fills the dstbuf with the help for the token. It returns
  * -1 on error and 0 on success.
  */
 struct cmdline_token_ops {
        /** parse(token ptr, buf, res pts) */
-       int (*parse)(cmdline_parse_token_hdr_t *, const char *, void *);
+       int (*parse)(cmdline_parse_token_hdr_t *, const char *, void *,
+                    unsigned int);
        /** return the num of possible choices for this token */
        int (*complete_get_nb)(cmdline_parse_token_hdr_t *);
        /** return the elt x for this token (token, idx, dstbuf, size) */
-       int (*complete_get_elt)(cmdline_parse_token_hdr_t *, int, char *, unsigned int);
+       int (*complete_get_elt)(cmdline_parse_token_hdr_t *, int, char *,
+                               unsigned int);
        /** get help for this token (token, dstbuf, size) */
        int (*get_help)(cmdline_parse_token_hdr_t *, char *, unsigned int);
 };
index e0528c5..7a50e02 100644 (file)
@@ -110,13 +110,16 @@ my_ether_aton(const char *a)
 
 int
 cmdline_parse_etheraddr(__attribute__((unused)) cmdline_parse_token_hdr_t *tk,
-                       const char *buf, void *res)
+                       const char *buf, void *res, unsigned ressize)
 {
        unsigned int token_len = 0;
        char ether_str[ETHER_ADDRSTRLEN];
        struct ether_addr *etheraddr = res;
        struct ether_addr *tmp;
 
+       if (res && ressize < sizeof(struct ether_addr))
+               return -1;
+
        /* if token is too big... */
        token_len = snprintf(ether_str, sizeof(ether_str), "%s", buf);
        if (token_len >= sizeof(ether_str))
index eb63f8b..23e54e9 100644 (file)
@@ -76,7 +76,7 @@ typedef struct cmdline_token_etheraddr cmdline_parse_token_etheraddr_t;
 extern struct cmdline_token_ops cmdline_token_etheraddr_ops;
 
 int cmdline_parse_etheraddr(cmdline_parse_token_hdr_t *tk, const char *srcbuf,
-                           void *res);
+                           void *res, unsigned ressize);
 int cmdline_get_help_etheraddr(cmdline_parse_token_hdr_t *tk, char *dstbuf,
                               unsigned int size);
 
index 37b2f3b..cb41562 100644 (file)
@@ -290,7 +290,8 @@ inet_pton6(const char *src, unsigned char *dst)
 }
 
 int
-cmdline_parse_ipaddr(cmdline_parse_token_hdr_t *tk, const char *buf, void *res)
+cmdline_parse_ipaddr(cmdline_parse_token_hdr_t *tk, const char *buf, void *res,
+                    unsigned ressize)
 {
        struct cmdline_token_ipaddr *tk2 = (struct cmdline_token_ipaddr *)tk;
        unsigned int token_len = 0;
@@ -299,6 +300,9 @@ cmdline_parse_ipaddr(cmdline_parse_token_hdr_t *tk, const char *buf, void *res)
        char *prefix, *prefix_end;
        long prefixlen;
 
+       if (res && ressize < sizeof(cmdline_ipaddr_t))
+               return -1;
+
        /* if token is too big... */
        token_len = snprintf(ip_str, sizeof(ip_str), "%s", buf);
        if (token_len >= sizeof(ip_str))
index f262998..33670eb 100644 (file)
@@ -91,7 +91,7 @@ typedef struct cmdline_token_ipaddr cmdline_parse_token_ipaddr_t;
 extern struct cmdline_token_ops cmdline_token_ipaddr_ops;
 
 int cmdline_parse_ipaddr(cmdline_parse_token_hdr_t *tk, const char *srcbuf,
-                        void *res);
+                        void *res, unsigned ressize);
 int cmdline_get_help_ipaddr(cmdline_parse_token_hdr_t *tk, char *dstbuf,
                            unsigned int size);
 
index cd3ca1e..8ef2964 100644 (file)
@@ -121,10 +121,45 @@ add_to_res(unsigned int c, uint64_t *res, unsigned int base)
        return 0;
 }
 
+static int check_res_size(struct cmdline_token_num_data *nd, unsigned ressize)
+{
+       switch (nd->type) {
+               case INT8:
+               case UINT8:
+                       if (ressize < sizeof(int8_t))
+                               return -1;
+                       break;
+               case INT16:
+               case UINT16:
+                       if (ressize < sizeof(int16_t))
+                               return -1;
+                       break;
+               case INT32:
+               case UINT32:
+                       if (ressize < sizeof(int32_t))
+                               return -1;
+                       break;
+               case INT64:
+               case UINT64:
+                       if (ressize < sizeof(int64_t))
+                               return -1;
+                       break;
+#ifdef CMDLINE_HAVE_FLOAT
+               case FLOAT:
+                       if (ressize < sizeof(float))
+                               return -1;
+                       break;
+#endif
+               default:
+                       return -1;
+       }
+       return 0;
+}
 
 /* parse an int or a float */
 int
-cmdline_parse_num(cmdline_parse_token_hdr_t *tk, const char *srcbuf, void *res)
+cmdline_parse_num(cmdline_parse_token_hdr_t *tk, const char *srcbuf,
+                 void *res, unsigned ressize)
 {
        struct cmdline_token_num_data nd;
        enum num_parse_state_t st = START;
@@ -137,6 +172,12 @@ cmdline_parse_num(cmdline_parse_token_hdr_t *tk, const char *srcbuf, void *res)
 
        memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd));
 
+       /* check that we have enough room in res */
+       if (res) {
+               if (check_res_size(&nd, ressize) < 0)
+                       return -1;
+       }
+
        while (st != ERROR && c != '\0') {
                debug_printf("%c %x -> ", c, c);
                switch (st) {
index 26a0d40..1b8c79d 100644 (file)
@@ -91,7 +91,7 @@ typedef struct cmdline_token_num cmdline_parse_token_num_t;
 extern struct cmdline_token_ops cmdline_token_num_ops;
 
 int cmdline_parse_num(cmdline_parse_token_hdr_t *tk,
-                     const char *srcbuf, void *res);
+                     const char *srcbuf, void *res, unsigned ressize);
 int cmdline_get_help_num(cmdline_parse_token_hdr_t *tk,
                         char *dstbuf, unsigned int size);
 
index 775024c..1b9fdb8 100644 (file)
@@ -127,12 +127,16 @@ static int parse_fixed_string(struct cmdline_token_string_data *sd,
 }
 
 int
-cmdline_parse_string(cmdline_parse_token_hdr_t *tk, const char *buf, void *res)
+cmdline_parse_string(cmdline_parse_token_hdr_t *tk, const char *buf, void *res,
+                    unsigned ressize)
 {
        struct cmdline_token_string *tk2 = (struct cmdline_token_string *)tk;
        struct cmdline_token_string_data *sd = &tk2->string_data;;
        unsigned int token_len;
 
+       if (res && ressize < STR_TOKEN_SIZE)
+               return -1;
+
        token_len = strlen(buf);
 
        if (token_len >= (STR_TOKEN_SIZE - 1) || token_len == 0)
index a91a5b5..d435f81 100644 (file)
@@ -65,7 +65,7 @@
 #include "cmdline_parse.h"
 
 /* size of a parsed string */
-#define STR_TOKEN_SIZE 128
+#define STR_TOKEN_SIZE CMDLINE_MAX_TOKEN_SIZE
 
 typedef char cmdline_fixed_string_t[STR_TOKEN_SIZE];
 
@@ -82,7 +82,7 @@ typedef struct cmdline_token_string cmdline_parse_token_string_t;
 extern struct cmdline_token_ops cmdline_token_string_ops;
 
 int cmdline_parse_string(cmdline_parse_token_hdr_t *tk, const char *srcbuf,
-                        void *res);
+                        void *res, unsigned ressize);
 int cmdline_complete_get_nb_string(cmdline_parse_token_hdr_t *tk);
 int cmdline_complete_get_elt_string(cmdline_parse_token_hdr_t *tk, int idx,
                                    char *dstbuf, unsigned int size);