Commit cf57298af5336df2aece47ef16c290a3a81457dd

Authored by Christoph Hellwig
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,