Do not read past the end of fmt_desc[]
authorBart Van Assche <bvanassche@acm.org>
Sun, 24 May 2020 03:39:47 +0000 (20:39 -0700)
committerBart Van Assche <bvanassche@acm.org>
Sun, 24 May 2020 03:46:42 +0000 (20:46 -0700)
Callers of parse_format() pass a size in bytes while the parse_format()
function itself expects a number of elements. Fix this by making the
fmt_desc[] array NULL-terminated. This patch fixes the following Coverity
complaint:

CID 300986 (#1 of 1): Out-of-bounds access (OVERRUN)
overrun-buffer-arg: Overrunning array fmt_desc of 1 24-byte elements by
passing it to a function which accesses it at element index 23 (byte
offset 575) using argument 24U.

Cc: Roman Pen <r.peniaev@gmail.com>
Fixes: 634bd210c17a ("lib/pattern: add set of functions to parse combined pattern input")
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
lib/pattern.c
lib/pattern.h
options.c

index 04d3065795944af4332fd59127b669a261a98647..680a12be7efc8fd232a4afa6f917c76c07bfa858 100644 (file)
@@ -205,7 +205,6 @@ static const char *parse_number(const char *beg, char *out,
  * @parsed - number of bytes which were already parsed so far
  * @out_len - length of the output buffer
  * @fmt_desc - format descriptor array, what we expect to find
- * @fmt_desc_sz - size of the format descriptor array
  * @fmt - format array, the output
  * @fmt_sz - size of format array
  *
@@ -223,19 +222,18 @@ static const char *parse_number(const char *beg, char *out,
 static const char *parse_format(const char *in, char *out, unsigned int parsed,
                                unsigned int out_len, unsigned int *filled,
                                const struct pattern_fmt_desc *fmt_desc,
-                               unsigned int fmt_desc_sz,
                                struct pattern_fmt *fmt, unsigned int fmt_sz)
 {
        int i;
        struct pattern_fmt *f = NULL;
        unsigned int len = 0;
 
-       if (!out_len || !fmt_desc || !fmt_desc_sz || !fmt || !fmt_sz)
+       if (!out_len || !fmt_desc || !fmt || !fmt_sz)
                return NULL;
 
        assert(*in == '%');
 
-       for (i = 0; i < fmt_desc_sz; i++) {
+       for (i = 0; fmt_desc[i].fmt; i++) {
                const struct pattern_fmt_desc *desc;
 
                desc = &fmt_desc[i];
@@ -267,7 +265,6 @@ static const char *parse_format(const char *in, char *out, unsigned int parsed,
  * @out - output buffer where parsed result will be put
  * @out_len - lengths of the output buffer
  * @fmt_desc - array of pattern format descriptors [input]
- * @fmt_desc_sz - size of the format descriptor array
  * @fmt - array of pattern formats [output]
  * @fmt_sz - pointer where the size of pattern formats array stored [input],
  *           after successfull parsing this pointer will contain the number
@@ -311,7 +308,6 @@ static const char *parse_format(const char *in, char *out, unsigned int parsed,
 int parse_and_fill_pattern(const char *in, unsigned int in_len,
                           char *out, unsigned int out_len,
                           const struct pattern_fmt_desc *fmt_desc,
-                          unsigned int fmt_desc_sz,
                           struct pattern_fmt *fmt,
                           unsigned int *fmt_sz_out)
 {
@@ -340,8 +336,7 @@ int parse_and_fill_pattern(const char *in, unsigned int in_len,
                        break;
                case '%':
                        end = parse_format(beg, out, out - out_beg, out_len,
-                                          &filled, fmt_desc, fmt_desc_sz,
-                                          fmt, fmt_rem);
+                                          &filled, fmt_desc, fmt, fmt_rem);
                        parsed_fmt = 1;
                        break;
                default:
index 2d655ad0d059dbc6bb8bd57069ae11d059a980a6..a6d9d6b4275cf863c86c0b9978fa4dd36b239e80 100644 (file)
@@ -24,7 +24,6 @@ struct pattern_fmt {
 int parse_and_fill_pattern(const char *in, unsigned int in_len,
                           char *out, unsigned int out_len,
                           const struct pattern_fmt_desc *fmt_desc,
-                          unsigned int fmt_desc_sz,
                           struct pattern_fmt *fmt,
                           unsigned int *fmt_sz_out);
 
index bb450fffae27137428d77924ae98972687b38a95..85a0f490a0721d5ce3b54af6d890576c0b9b26de 100644 (file)
--- a/options.c
+++ b/options.c
@@ -24,7 +24,8 @@ static const struct pattern_fmt_desc fmt_desc[] = {
                .fmt   = "%o",
                .len   = FIELD_SIZE(struct io_u *, offset),
                .paste = paste_blockoff
-       }
+       },
+       { }
 };
 
 /*
@@ -1339,7 +1340,7 @@ static int str_buffer_pattern_cb(void *data, const char *input)
 
        /* FIXME: for now buffer pattern does not support formats */
        ret = parse_and_fill_pattern(input, strlen(input), td->o.buffer_pattern,
-                                    MAX_PATTERN_SIZE, NULL, 0, NULL, NULL);
+                                    MAX_PATTERN_SIZE, NULL, NULL, NULL);
        if (ret < 0)
                return 1;
 
@@ -1388,7 +1389,7 @@ static int str_verify_pattern_cb(void *data, const char *input)
 
        td->o.verify_fmt_sz = ARRAY_SIZE(td->o.verify_fmt);
        ret = parse_and_fill_pattern(input, strlen(input), td->o.verify_pattern,
-                                    MAX_PATTERN_SIZE, fmt_desc, sizeof(fmt_desc),
+                                    MAX_PATTERN_SIZE, fmt_desc,
                                     td->o.verify_fmt, &td->o.verify_fmt_sz);
        if (ret < 0)
                return 1;