Commit cf57298af5336df2aece47ef16c290a3a81457dd
Committed by
Anthony Liguori
1 parent
230d4fa4
qemu-io: better input validation for vector-based commands
Fix up a couple of issues with validating the input of the various length arguments for the vectored I/O commands: - do the alignment check on each length instead the always 0 count argument - use a long long varibale for the cvtnum return value so that we can check wether it wasn't a number - check for a too large argument instead of truncating it Also refactor it into a common helper for all four calers and avoid parsing the numbers twice. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Showing
1 changed file
with
68 additions
and
150 deletions
qemu-io.c
| @@ -98,6 +98,57 @@ print_report(const char *op, struct timeval *t, int64_t offset, | @@ -98,6 +98,57 @@ print_report(const char *op, struct timeval *t, int64_t offset, | ||
| 98 | } | 98 | } |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | +/* | ||
| 102 | + * Parse multiple length statements for vectored I/O, and construct an I/O | ||
| 103 | + * vector matching it. | ||
| 104 | + */ | ||
| 105 | +static void * | ||
| 106 | +create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern) | ||
| 107 | +{ | ||
| 108 | + size_t *sizes = calloc(nr_iov, sizeof(size_t)); | ||
| 109 | + size_t count = 0; | ||
| 110 | + void *buf, *p; | ||
| 111 | + int i; | ||
| 112 | + | ||
| 113 | + for (i = 0; i < nr_iov; i++) { | ||
| 114 | + char *arg = argv[i]; | ||
| 115 | + long long len; | ||
| 116 | + | ||
| 117 | + len = cvtnum(arg); | ||
| 118 | + if (len < 0) { | ||
| 119 | + printf("non-numeric length argument -- %s\n", arg); | ||
| 120 | + return NULL; | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + /* should be SIZE_T_MAX, but that doesn't exist */ | ||
| 124 | + if (len > UINT_MAX) { | ||
| 125 | + printf("too large length argument -- %s\n", arg); | ||
| 126 | + return NULL; | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + if (len & 0x1ff) { | ||
| 130 | + printf("length argument %lld is not sector aligned\n", | ||
| 131 | + len); | ||
| 132 | + return NULL; | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + sizes[i] = len; | ||
| 136 | + count += len; | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + qemu_iovec_init(qiov, nr_iov); | ||
| 140 | + | ||
| 141 | + buf = p = qemu_io_alloc(count, pattern); | ||
| 142 | + | ||
| 143 | + for (i = 0; i < nr_iov; i++) { | ||
| 144 | + qemu_iovec_add(qiov, p, sizes[i]); | ||
| 145 | + p += sizes[i]; | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + free(sizes); | ||
| 149 | + return buf; | ||
| 150 | +} | ||
| 151 | + | ||
| 101 | static int do_read(char *buf, int64_t offset, int count, int *total) | 152 | static int do_read(char *buf, int64_t offset, int count, int *total) |
| 102 | { | 153 | { |
| 103 | int ret; | 154 | int ret; |
| @@ -375,10 +426,10 @@ readv_f(int argc, char **argv) | @@ -375,10 +426,10 @@ readv_f(int argc, char **argv) | ||
| 375 | struct timeval t1, t2; | 426 | struct timeval t1, t2; |
| 376 | int Cflag = 0, qflag = 0, vflag = 0; | 427 | int Cflag = 0, qflag = 0, vflag = 0; |
| 377 | int c, cnt; | 428 | int c, cnt; |
| 378 | - char *buf, *p; | 429 | + char *buf; |
| 379 | int64_t offset; | 430 | int64_t offset; |
| 380 | - int count = 0, total; | ||
| 381 | - int nr_iov, i; | 431 | + int total; |
| 432 | + int nr_iov; | ||
| 382 | QEMUIOVector qiov; | 433 | QEMUIOVector qiov; |
| 383 | int pattern = 0; | 434 | int pattern = 0; |
| 384 | int Pflag = 0; | 435 | int Pflag = 0; |
| @@ -420,40 +471,8 @@ readv_f(int argc, char **argv) | @@ -420,40 +471,8 @@ readv_f(int argc, char **argv) | ||
| 420 | return 0; | 471 | return 0; |
| 421 | } | 472 | } |
| 422 | 473 | ||
| 423 | - if (count & 0x1ff) { | ||
| 424 | - printf("count %d is not sector aligned\n", | ||
| 425 | - count); | ||
| 426 | - return 0; | ||
| 427 | - } | ||
| 428 | - | ||
| 429 | - for (i = optind; i < argc; i++) { | ||
| 430 | - size_t len; | ||
| 431 | - | ||
| 432 | - len = cvtnum(argv[i]); | ||
| 433 | - if (len < 0) { | ||
| 434 | - printf("non-numeric length argument -- %s\n", argv[i]); | ||
| 435 | - return 0; | ||
| 436 | - } | ||
| 437 | - count += len; | ||
| 438 | - } | ||
| 439 | - | ||
| 440 | nr_iov = argc - optind; | 474 | nr_iov = argc - optind; |
| 441 | - qemu_iovec_init(&qiov, nr_iov); | ||
| 442 | - buf = p = qemu_io_alloc(count, 0xab); | ||
| 443 | - for (i = 0; i < nr_iov; i++) { | ||
| 444 | - size_t len; | ||
| 445 | - | ||
| 446 | - len = cvtnum(argv[optind]); | ||
| 447 | - if (len < 0) { | ||
| 448 | - printf("non-numeric length argument -- %s\n", | ||
| 449 | - argv[optind]); | ||
| 450 | - return 0; | ||
| 451 | - } | ||
| 452 | - | ||
| 453 | - qemu_iovec_add(&qiov, p, len); | ||
| 454 | - p += len; | ||
| 455 | - optind++; | ||
| 456 | - } | 475 | + buf = create_iovec(&qiov, &argv[optind], nr_iov, 0xab); |
| 457 | 476 | ||
| 458 | gettimeofday(&t1, NULL); | 477 | gettimeofday(&t1, NULL); |
| 459 | cnt = do_aio_readv(&qiov, offset, &total); | 478 | cnt = do_aio_readv(&qiov, offset, &total); |
| @@ -465,12 +484,12 @@ readv_f(int argc, char **argv) | @@ -465,12 +484,12 @@ readv_f(int argc, char **argv) | ||
| 465 | } | 484 | } |
| 466 | 485 | ||
| 467 | if (Pflag) { | 486 | if (Pflag) { |
| 468 | - void* cmp_buf = malloc(count); | ||
| 469 | - memset(cmp_buf, pattern, count); | ||
| 470 | - if (memcmp(buf, cmp_buf, count)) { | 487 | + void* cmp_buf = malloc(qiov.size); |
| 488 | + memset(cmp_buf, pattern, qiov.size); | ||
| 489 | + if (memcmp(buf, cmp_buf, qiov.size)) { | ||
| 471 | printf("Pattern verification failed at offset %lld, " | 490 | printf("Pattern verification failed at offset %lld, " |
| 472 | - "%d bytes\n", | ||
| 473 | - (long long) offset, count); | 491 | + "%zd bytes\n", |
| 492 | + (long long) offset, qiov.size); | ||
| 474 | } | 493 | } |
| 475 | free(cmp_buf); | 494 | free(cmp_buf); |
| 476 | } | 495 | } |
| @@ -646,10 +665,10 @@ writev_f(int argc, char **argv) | @@ -646,10 +665,10 @@ writev_f(int argc, char **argv) | ||
| 646 | struct timeval t1, t2; | 665 | struct timeval t1, t2; |
| 647 | int Cflag = 0, qflag = 0; | 666 | int Cflag = 0, qflag = 0; |
| 648 | int c, cnt; | 667 | int c, cnt; |
| 649 | - char *buf, *p; | 668 | + char *buf; |
| 650 | int64_t offset; | 669 | int64_t offset; |
| 651 | - int count = 0, total; | ||
| 652 | - int nr_iov, i; | 670 | + int total; |
| 671 | + int nr_iov; | ||
| 653 | int pattern = 0xcd; | 672 | int pattern = 0xcd; |
| 654 | QEMUIOVector qiov; | 673 | QEMUIOVector qiov; |
| 655 | 674 | ||
| @@ -685,41 +704,8 @@ writev_f(int argc, char **argv) | @@ -685,41 +704,8 @@ writev_f(int argc, char **argv) | ||
| 685 | return 0; | 704 | return 0; |
| 686 | } | 705 | } |
| 687 | 706 | ||
| 688 | - if (count & 0x1ff) { | ||
| 689 | - printf("count %d is not sector aligned\n", | ||
| 690 | - count); | ||
| 691 | - return 0; | ||
| 692 | - } | ||
| 693 | - | ||
| 694 | - | ||
| 695 | - for (i = optind; i < argc; i++) { | ||
| 696 | - size_t len; | ||
| 697 | - | ||
| 698 | - len = cvtnum(argv[optind]); | ||
| 699 | - if (len < 0) { | ||
| 700 | - printf("non-numeric length argument -- %s\n", argv[i]); | ||
| 701 | - return 0; | ||
| 702 | - } | ||
| 703 | - count += len; | ||
| 704 | - } | ||
| 705 | - | ||
| 706 | nr_iov = argc - optind; | 707 | nr_iov = argc - optind; |
| 707 | - qemu_iovec_init(&qiov, nr_iov); | ||
| 708 | - buf = p = qemu_io_alloc(count, pattern); | ||
| 709 | - for (i = 0; i < nr_iov; i++) { | ||
| 710 | - size_t len; | ||
| 711 | - | ||
| 712 | - len = cvtnum(argv[optind]); | ||
| 713 | - if (len < 0) { | ||
| 714 | - printf("non-numeric length argument -- %s\n", | ||
| 715 | - argv[optind]); | ||
| 716 | - return 0; | ||
| 717 | - } | ||
| 718 | - | ||
| 719 | - qemu_iovec_add(&qiov, p, len); | ||
| 720 | - p += len; | ||
| 721 | - optind++; | ||
| 722 | - } | 708 | + buf = create_iovec(&qiov, &argv[optind], nr_iov, pattern); |
| 723 | 709 | ||
| 724 | gettimeofday(&t1, NULL); | 710 | gettimeofday(&t1, NULL); |
| 725 | cnt = do_aio_writev(&qiov, offset, &total); | 711 | cnt = do_aio_writev(&qiov, offset, &total); |
| @@ -859,9 +845,7 @@ aio_read_help(void) | @@ -859,9 +845,7 @@ aio_read_help(void) | ||
| 859 | static int | 845 | static int |
| 860 | aio_read_f(int argc, char **argv) | 846 | aio_read_f(int argc, char **argv) |
| 861 | { | 847 | { |
| 862 | - char *p; | ||
| 863 | - int count = 0; | ||
| 864 | - int nr_iov, i, c; | 848 | + int nr_iov, c; |
| 865 | struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx)); | 849 | struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx)); |
| 866 | BlockDriverAIOCB *acb; | 850 | BlockDriverAIOCB *acb; |
| 867 | 851 | ||
| @@ -902,40 +886,8 @@ aio_read_f(int argc, char **argv) | @@ -902,40 +886,8 @@ aio_read_f(int argc, char **argv) | ||
| 902 | return 0; | 886 | return 0; |
| 903 | } | 887 | } |
| 904 | 888 | ||
| 905 | - if (count & 0x1ff) { | ||
| 906 | - printf("count %d is not sector aligned\n", | ||
| 907 | - count); | ||
| 908 | - return 0; | ||
| 909 | - } | ||
| 910 | - | ||
| 911 | - for (i = optind; i < argc; i++) { | ||
| 912 | - size_t len; | ||
| 913 | - | ||
| 914 | - len = cvtnum(argv[i]); | ||
| 915 | - if (len < 0) { | ||
| 916 | - printf("non-numeric length argument -- %s\n", argv[i]); | ||
| 917 | - return 0; | ||
| 918 | - } | ||
| 919 | - count += len; | ||
| 920 | - } | ||
| 921 | - | ||
| 922 | nr_iov = argc - optind; | 889 | nr_iov = argc - optind; |
| 923 | - qemu_iovec_init(&ctx->qiov, nr_iov); | ||
| 924 | - ctx->buf = p = qemu_io_alloc(count, 0xab); | ||
| 925 | - for (i = 0; i < nr_iov; i++) { | ||
| 926 | - size_t len; | ||
| 927 | - | ||
| 928 | - len = cvtnum(argv[optind]); | ||
| 929 | - if (len < 0) { | ||
| 930 | - printf("non-numeric length argument -- %s\n", | ||
| 931 | - argv[optind]); | ||
| 932 | - return 0; | ||
| 933 | - } | ||
| 934 | - | ||
| 935 | - qemu_iovec_add(&ctx->qiov, p, len); | ||
| 936 | - p += len; | ||
| 937 | - optind++; | ||
| 938 | - } | 890 | + ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab); |
| 939 | 891 | ||
| 940 | gettimeofday(&ctx->t1, NULL); | 892 | gettimeofday(&ctx->t1, NULL); |
| 941 | acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov, | 893 | acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov, |
| @@ -983,9 +935,7 @@ aio_write_help(void) | @@ -983,9 +935,7 @@ aio_write_help(void) | ||
| 983 | static int | 935 | static int |
| 984 | aio_write_f(int argc, char **argv) | 936 | aio_write_f(int argc, char **argv) |
| 985 | { | 937 | { |
| 986 | - char *p; | ||
| 987 | - int count = 0; | ||
| 988 | - int nr_iov, i, c; | 938 | + int nr_iov, c; |
| 989 | int pattern = 0xcd; | 939 | int pattern = 0xcd; |
| 990 | struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx)); | 940 | struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx)); |
| 991 | BlockDriverAIOCB *acb; | 941 | BlockDriverAIOCB *acb; |
| @@ -1022,40 +972,8 @@ aio_write_f(int argc, char **argv) | @@ -1022,40 +972,8 @@ aio_write_f(int argc, char **argv) | ||
| 1022 | return 0; | 972 | return 0; |
| 1023 | } | 973 | } |
| 1024 | 974 | ||
| 1025 | - if (count & 0x1ff) { | ||
| 1026 | - printf("count %d is not sector aligned\n", | ||
| 1027 | - count); | ||
| 1028 | - return 0; | ||
| 1029 | - } | ||
| 1030 | - | ||
| 1031 | - for (i = optind; i < argc; i++) { | ||
| 1032 | - size_t len; | ||
| 1033 | - | ||
| 1034 | - len = cvtnum(argv[optind]); | ||
| 1035 | - if (len < 0) { | ||
| 1036 | - printf("non-numeric length argument -- %s\n", argv[i]); | ||
| 1037 | - return 0; | ||
| 1038 | - } | ||
| 1039 | - count += len; | ||
| 1040 | - } | ||
| 1041 | - | ||
| 1042 | nr_iov = argc - optind; | 975 | nr_iov = argc - optind; |
| 1043 | - qemu_iovec_init(&ctx->qiov, nr_iov); | ||
| 1044 | - ctx->buf = p = qemu_io_alloc(count, pattern); | ||
| 1045 | - for (i = 0; i < nr_iov; i++) { | ||
| 1046 | - size_t len; | ||
| 1047 | - | ||
| 1048 | - len = cvtnum(argv[optind]); | ||
| 1049 | - if (len < 0) { | ||
| 1050 | - printf("non-numeric length argument -- %s\n", | ||
| 1051 | - argv[optind]); | ||
| 1052 | - return 0; | ||
| 1053 | - } | ||
| 1054 | - | ||
| 1055 | - qemu_iovec_add(&ctx->qiov, p, len); | ||
| 1056 | - p += len; | ||
| 1057 | - optind++; | ||
| 1058 | - } | 976 | + ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern); |
| 1059 | 977 | ||
| 1060 | gettimeofday(&ctx->t1, NULL); | 978 | gettimeofday(&ctx->t1, NULL); |
| 1061 | acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov, | 979 | acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov, |