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 | 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 | 152 | static int do_read(char *buf, int64_t offset, int count, int *total) |
102 | 153 | { |
103 | 154 | int ret; |
... | ... | @@ -375,10 +426,10 @@ readv_f(int argc, char **argv) |
375 | 426 | struct timeval t1, t2; |
376 | 427 | int Cflag = 0, qflag = 0, vflag = 0; |
377 | 428 | int c, cnt; |
378 | - char *buf, *p; | |
429 | + char *buf; | |
379 | 430 | int64_t offset; |
380 | - int count = 0, total; | |
381 | - int nr_iov, i; | |
431 | + int total; | |
432 | + int nr_iov; | |
382 | 433 | QEMUIOVector qiov; |
383 | 434 | int pattern = 0; |
384 | 435 | int Pflag = 0; |
... | ... | @@ -420,40 +471,8 @@ readv_f(int argc, char **argv) |
420 | 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 | 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 | 477 | gettimeofday(&t1, NULL); |
459 | 478 | cnt = do_aio_readv(&qiov, offset, &total); |
... | ... | @@ -465,12 +484,12 @@ readv_f(int argc, char **argv) |
465 | 484 | } |
466 | 485 | |
467 | 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 | 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 | 494 | free(cmp_buf); |
476 | 495 | } |
... | ... | @@ -646,10 +665,10 @@ writev_f(int argc, char **argv) |
646 | 665 | struct timeval t1, t2; |
647 | 666 | int Cflag = 0, qflag = 0; |
648 | 667 | int c, cnt; |
649 | - char *buf, *p; | |
668 | + char *buf; | |
650 | 669 | int64_t offset; |
651 | - int count = 0, total; | |
652 | - int nr_iov, i; | |
670 | + int total; | |
671 | + int nr_iov; | |
653 | 672 | int pattern = 0xcd; |
654 | 673 | QEMUIOVector qiov; |
655 | 674 | |
... | ... | @@ -685,41 +704,8 @@ writev_f(int argc, char **argv) |
685 | 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 | 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 | 710 | gettimeofday(&t1, NULL); |
725 | 711 | cnt = do_aio_writev(&qiov, offset, &total); |
... | ... | @@ -859,9 +845,7 @@ aio_read_help(void) |
859 | 845 | static int |
860 | 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 | 849 | struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx)); |
866 | 850 | BlockDriverAIOCB *acb; |
867 | 851 | |
... | ... | @@ -902,40 +886,8 @@ aio_read_f(int argc, char **argv) |
902 | 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 | 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 | 892 | gettimeofday(&ctx->t1, NULL); |
941 | 893 | acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov, |
... | ... | @@ -983,9 +935,7 @@ aio_write_help(void) |
983 | 935 | static int |
984 | 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 | 939 | int pattern = 0xcd; |
990 | 940 | struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx)); |
991 | 941 | BlockDriverAIOCB *acb; |
... | ... | @@ -1022,40 +972,8 @@ aio_write_f(int argc, char **argv) |
1022 | 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 | 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 | 978 | gettimeofday(&ctx->t1, NULL); |
1061 | 979 | acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov, | ... | ... |