Re: [Qemu-devel] [PATCH v5 09/12] VMDK: open/read/write for monolithicFlat image

2011-06-30 Thread Stefan Hajnoczi
On Thu, Jun 30, 2011 at 2:57 AM, Fam Zheng famc...@gmail.com wrote:
 On Wed, Jun 29, 2011 at 11:57 PM, Stefan Hajnoczi stefa...@gmail.com wrote:
 On Tue, Jun 28, 2011 at 2:32 AM, Fam Zheng famc...@gmail.com wrote:
 +        /* trim the quotation marks around */
 +        if (fname[0] == '') {
 +            memmove(fname, fname + 1, strlen(fname) + 1);

 This copies 1 byte too many, just strlen(fname) will do.
 I meant to copy the NULL terminator too.

Yes.  The problem is the copying starts at fname + 1 but strlen(3)
starts at fname.  So there is already an extra byte.  The + 1 adds an
additional byte after the NUL.


Stefan



Re: [Qemu-devel] [PATCH v5 09/12] VMDK: open/read/write for monolithicFlat image

2011-06-29 Thread Stefan Hajnoczi
On Tue, Jun 28, 2011 at 2:32 AM, Fam Zheng famc...@gmail.com wrote:
 +/* find an option value out of descriptor file */
 +static int vmdk_parse_description(const char *desc, const char *opt_name,
 +        char *buf, int buf_size)
 +{
 +    char *opt_pos, *opt_end;
 +    const char *end = desc + strlen(desc);
 +
 +    opt_pos = strstr(desc, opt_name);
 +    if (!opt_pos) {
 +        return -1;
 +    }
 +    /* Skip =\ following opt_name */
 +    opt_pos += strlen(opt_name) + 2;
 +    if (opt_pos = end) {
 +        return -1;
 +    }

This can produce false positives because strstr(desc, opt_name) will
match anything that contains the opt_name string.  Also we don't
verify that =\ follow the opt_name.  Luckily we only use this for
createType which will hopefully never cause false positives.

 +    opt_end = opt_pos;
 +    while (opt_end  end  *opt_end != '') {
 +        opt_end++;
 +    }
 +    if (opt_end == end || buf_size  opt_end - opt_pos + 1) {
 +        return -1;
 +    }
 +    pstrcpy(buf, opt_end - opt_pos + 1, opt_pos);
 +    return 0;
 +}
 +
 +static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
 +        const char *desc_file_path)
 +{
 +    int ret = 0;
 +    int r;
 +    char access[11];
 +    char type[11];
 +    char fname[512];
 +    const char *p = desc;
 +    int64_t sectors = 0;
 +    int64_t flat_offset;
 +
 +    while (*p) {
 +        if (strncmp(p, RW, strlen(RW))) {
 +            goto next_line;
 +        }

This check is duplicated below and can be removed.

 +        /* parse extent line:
 +         * RW [size in sectors] FLAT file-name.vmdk OFFSET
 +         * or
 +         * RW [size in sectors] SPARSE file-name.vmdk
 +         */
 +        flat_offset = -1;
 +        sscanf(p, %10s %lld %10s %512s,
 +                access, sectors, type, fname);

Please check the sscanf(3) return value to ensure the format string
matched.  The value of access[], type[], fname[], sectors will be
unchanged at the point where sscanf(3) fails so your checks will not
work.

Declared as char fname[512] but using %512s format string.  The
format string needs to be 511 to leave space for the NUL terminator.

 +        if (!strcmp(type, FLAT)) {
 +            sscanf(p, %10s %lld %10s %512s %lld,
 +                access, sectors, type, fname, flat_offset);
 +            if (flat_offset == -1) {
 +                return -EINVAL;
 +            }
 +        }
 +
 +        /* trim the quotation marks around */
 +        if (fname[0] == '') {
 +            memmove(fname, fname + 1, strlen(fname) + 1);

This copies 1 byte too many, just strlen(fname) will do.

 +            if (fname[strlen(fname) - 1] == '') {
 +                fname[strlen(fname) - 1] = '\0';
 +            }
 +        }

If starts as fname[] = {'', '\0'} then this if statement checks
fname[-1] == ''!

 +        if (!(strlen(access)  sectors  strlen(type)  strlen(fname))) {
 +            goto next_line;
 +        }

These can be replaced by checking the sscanf(3) return value above.
Validating sectors is still a good idea though.

 +        if (strcmp(type, FLAT)  strcmp(type, SPARSE)) {
 +            goto next_line;
 +        }
 +        if (strcmp(access, RW)) {
 +            goto next_line;
 +        }
 +        ret++;

This variable is unused.

 +        /* save to extents array */
 +        if (!strcmp(type, FLAT)) {
 +            /* FLAT extent */
 +            char extent_path[PATH_MAX];
 +            BlockDriverState *extent_file;
 +            BlockDriver *drv;
 +            VmdkExtent *extent;
 +
 +            extent_file = bdrv_new();
 +            drv = bdrv_find_format(file);
 +            if (!drv) {

bdrv_delete(extent_file);

 +                return -EINVAL;
 +            }
 +            path_combine(extent_path, sizeof(extent_path),
 +                    desc_file_path, fname);
 +            r = bdrv_open(extent_file, extent_path,
 +                    BDRV_O_RDWR | BDRV_O_NO_BACKING, drv);

We should honor the bs-open_flags.  Otherwise
cache=none|writeback|writethrough|unsafe is ignored on the actual
extent files.

 +            if (r) {

bdrv_delete(extent_file);

 +                return -EINVAL;
 +            }
 +            extent = vmdk_add_extent(bs, extent_file, true, sectors,
 +                            0, 0, 0, 0, sectors);
 +            extent-flat_start_offset = flat_offset;
 +        } else {
 +            /* SPARSE extent, not supported for now */
 +            fprintf(stderr,
 +                VMDK: Not supported extent type \%s\.\n, type);
 +            return -ENOTSUP;
 +        }
 +next_line:
 +        /* move to next line */
 +        while (*p  *p != '\n') {
 +            p++;
 +        }
 +        p++;
 +    }
 +    return 0;
 +}
 +
 +static int vmdk_open_desc_file(BlockDriverState *bs, int flags)
 +{
 +    int ret;
 +    char buf[2048];
 +    char ct[128];
 +    BDRVVmdkState *s = bs-opaque;
 +
 +    ret = bdrv_pread(bs-file, 0, buf, sizeof(buf));
 +    if (ret  0) {
 +        return 

Re: [Qemu-devel] [PATCH v5 09/12] VMDK: open/read/write for monolithicFlat image

2011-06-29 Thread Fam Zheng
On Wed, Jun 29, 2011 at 11:57 PM, Stefan Hajnoczi stefa...@gmail.com wrote:
 On Tue, Jun 28, 2011 at 2:32 AM, Fam Zheng famc...@gmail.com wrote:
 +/* find an option value out of descriptor file */
 +static int vmdk_parse_description(const char *desc, const char *opt_name,
 +        char *buf, int buf_size)
 +{
 +    char *opt_pos, *opt_end;
 +    const char *end = desc + strlen(desc);
 +
 +    opt_pos = strstr(desc, opt_name);
 +    if (!opt_pos) {
 +        return -1;
 +    }
 +    /* Skip =\ following opt_name */
 +    opt_pos += strlen(opt_name) + 2;
 +    if (opt_pos = end) {
 +        return -1;
 +    }

 This can produce false positives because strstr(desc, opt_name) will
 match anything that contains the opt_name string.  Also we don't
 verify that =\ follow the opt_name.  Luckily we only use this for
 createType which will hopefully never cause false positives.

 +    opt_end = opt_pos;
 +    while (opt_end  end  *opt_end != '') {
 +        opt_end++;
 +    }
 +    if (opt_end == end || buf_size  opt_end - opt_pos + 1) {
 +        return -1;
 +    }
 +    pstrcpy(buf, opt_end - opt_pos + 1, opt_pos);
 +    return 0;
 +}
 +
 +static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
 +        const char *desc_file_path)
 +{
 +    int ret = 0;
 +    int r;
 +    char access[11];
 +    char type[11];
 +    char fname[512];
 +    const char *p = desc;
 +    int64_t sectors = 0;
 +    int64_t flat_offset;
 +
 +    while (*p) {
 +        if (strncmp(p, RW, strlen(RW))) {
 +            goto next_line;
 +        }

 This check is duplicated below and can be removed.

 +        /* parse extent line:
 +         * RW [size in sectors] FLAT file-name.vmdk OFFSET
 +         * or
 +         * RW [size in sectors] SPARSE file-name.vmdk
 +         */
 +        flat_offset = -1;
 +        sscanf(p, %10s %lld %10s %512s,
 +                access, sectors, type, fname);

 Please check the sscanf(3) return value to ensure the format string
 matched.  The value of access[], type[], fname[], sectors will be
 unchanged at the point where sscanf(3) fails so your checks will not
 work.

 Declared as char fname[512] but using %512s format string.  The
 format string needs to be 511 to leave space for the NUL terminator.

 +        if (!strcmp(type, FLAT)) {
 +            sscanf(p, %10s %lld %10s %512s %lld,
 +                access, sectors, type, fname, flat_offset);
 +            if (flat_offset == -1) {
 +                return -EINVAL;
 +            }
 +        }
 +
 +        /* trim the quotation marks around */
 +        if (fname[0] == '') {
 +            memmove(fname, fname + 1, strlen(fname) + 1);

 This copies 1 byte too many, just strlen(fname) will do.
I meant to copy the NULL terminator too.

 +            if (fname[strlen(fname) - 1] == '') {
 +                fname[strlen(fname) - 1] = '\0';
 +            }
 +        }

 If starts as fname[] = {'', '\0'} then this if statement checks
 fname[-1] == ''!

 +        if (!(strlen(access)  sectors  strlen(type)  strlen(fname))) {
 +            goto next_line;
 +        }

 These can be replaced by checking the sscanf(3) return value above.
 Validating sectors is still a good idea though.

 +        if (strcmp(type, FLAT)  strcmp(type, SPARSE)) {
 +            goto next_line;
 +        }
 +        if (strcmp(access, RW)) {
 +            goto next_line;
 +        }
 +        ret++;

 This variable is unused.

 +        /* save to extents array */
 +        if (!strcmp(type, FLAT)) {
 +            /* FLAT extent */
 +            char extent_path[PATH_MAX];
 +            BlockDriverState *extent_file;
 +            BlockDriver *drv;
 +            VmdkExtent *extent;
 +
 +            extent_file = bdrv_new();
 +            drv = bdrv_find_format(file);
 +            if (!drv) {

 bdrv_delete(extent_file);

 +                return -EINVAL;
 +            }
 +            path_combine(extent_path, sizeof(extent_path),
 +                    desc_file_path, fname);
 +            r = bdrv_open(extent_file, extent_path,
 +                    BDRV_O_RDWR | BDRV_O_NO_BACKING, drv);

 We should honor the bs-open_flags.  Otherwise
 cache=none|writeback|writethrough|unsafe is ignored on the actual
 extent files.

 +            if (r) {

 bdrv_delete(extent_file);

 +                return -EINVAL;
 +            }
 +            extent = vmdk_add_extent(bs, extent_file, true, sectors,
 +                            0, 0, 0, 0, sectors);
 +            extent-flat_start_offset = flat_offset;
 +        } else {
 +            /* SPARSE extent, not supported for now */
 +            fprintf(stderr,
 +                VMDK: Not supported extent type \%s\.\n, type);
 +            return -ENOTSUP;
 +        }
 +next_line:
 +        /* move to next line */
 +        while (*p  *p != '\n') {
 +            p++;
 +        }
 +        p++;
 +    }
 +    return 0;
 +}
 +
 +static int vmdk_open_desc_file(BlockDriverState *bs, int flags)
 +{
 +    int ret;
 +    char buf[2048];
 +