From: Olivier Matz Date: Sun, 2 Jan 2011 18:45:51 +0000 (+0100) Subject: cmdline: check size of result buffer to avoid overflow X-Git-Url: http://git.droids-corp.org/?p=libcmdline.git;a=commitdiff_plain;h=b1d5b169352e57df3fc14c51ffad4b83f3e5613f cmdline: check size of result buffer to avoid overflow Signed-off-by: Olivier Matz --- diff --git a/src/extension_example/parse_obj_list.c b/src/extension_example/parse_obj_list.c index 21fc019..aa743cf 100644 --- a/src/extension_example/parse_obj_list.c +++ b/src/extension_example/parse_obj_list.c @@ -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) { diff --git a/src/extension_example/parse_obj_list.h b/src/extension_example/parse_obj_list.h index 1aeb7eb..3bde83e 100644 --- a/src/extension_example/parse_obj_list.h +++ b/src/extension_example/parse_obj_list.h @@ -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); diff --git a/src/genconf/parse_confnode.c b/src/genconf/parse_confnode.c index 5c8202b..b25166f 100644 --- a/src/genconf/parse_confnode.c +++ b/src/genconf/parse_confnode.c @@ -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)) diff --git a/src/genconf/parse_confnode.h b/src/genconf/parse_confnode.h index e47f679..83a925a 100644 --- a/src/genconf/parse_confnode.h +++ b/src/genconf/parse_confnode.h @@ -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); diff --git a/src/lib/cmdline_parse.c b/src/lib/cmdline_parse.c index 37ccc23..060a8e9 100644 --- a/src/lib/cmdline_parse.c +++ b/src/lib/cmdline_parse.c @@ -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]; diff --git a/src/lib/cmdline_parse.h b/src/lib/cmdline_parse.h index 146f15c..e9e6308 100644 --- a/src/lib/cmdline_parse.h +++ b/src/lib/cmdline_parse.h @@ -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); }; diff --git a/src/lib/cmdline_parse_etheraddr.c b/src/lib/cmdline_parse_etheraddr.c index e0528c5..7a50e02 100644 --- a/src/lib/cmdline_parse_etheraddr.c +++ b/src/lib/cmdline_parse_etheraddr.c @@ -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)) diff --git a/src/lib/cmdline_parse_etheraddr.h b/src/lib/cmdline_parse_etheraddr.h index eb63f8b..23e54e9 100644 --- a/src/lib/cmdline_parse_etheraddr.h +++ b/src/lib/cmdline_parse_etheraddr.h @@ -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); diff --git a/src/lib/cmdline_parse_ipaddr.c b/src/lib/cmdline_parse_ipaddr.c index 37b2f3b..cb41562 100644 --- a/src/lib/cmdline_parse_ipaddr.c +++ b/src/lib/cmdline_parse_ipaddr.c @@ -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)) diff --git a/src/lib/cmdline_parse_ipaddr.h b/src/lib/cmdline_parse_ipaddr.h index f262998..33670eb 100644 --- a/src/lib/cmdline_parse_ipaddr.h +++ b/src/lib/cmdline_parse_ipaddr.h @@ -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); diff --git a/src/lib/cmdline_parse_num.c b/src/lib/cmdline_parse_num.c index cd3ca1e..8ef2964 100644 --- a/src/lib/cmdline_parse_num.c +++ b/src/lib/cmdline_parse_num.c @@ -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) { diff --git a/src/lib/cmdline_parse_num.h b/src/lib/cmdline_parse_num.h index 26a0d40..1b8c79d 100644 --- a/src/lib/cmdline_parse_num.h +++ b/src/lib/cmdline_parse_num.h @@ -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); diff --git a/src/lib/cmdline_parse_string.c b/src/lib/cmdline_parse_string.c index 775024c..1b9fdb8 100644 --- a/src/lib/cmdline_parse_string.c +++ b/src/lib/cmdline_parse_string.c @@ -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) diff --git a/src/lib/cmdline_parse_string.h b/src/lib/cmdline_parse_string.h index a91a5b5..d435f81 100644 --- a/src/lib/cmdline_parse_string.h +++ b/src/lib/cmdline_parse_string.h @@ -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);