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 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,
... ...