mirror of https://github.com/xemu-project/xemu.git
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>
This commit is contained in:
parent
230d4fa48b
commit
cf57298af5
218
qemu-io.c
218
qemu-io.c
|
@ -98,6 +98,57 @@ print_report(const char *op, struct timeval *t, int64_t offset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse multiple length statements for vectored I/O, and construct an I/O
|
||||||
|
* vector matching it.
|
||||||
|
*/
|
||||||
|
static void *
|
||||||
|
create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern)
|
||||||
|
{
|
||||||
|
size_t *sizes = calloc(nr_iov, sizeof(size_t));
|
||||||
|
size_t count = 0;
|
||||||
|
void *buf, *p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < nr_iov; i++) {
|
||||||
|
char *arg = argv[i];
|
||||||
|
long long len;
|
||||||
|
|
||||||
|
len = cvtnum(arg);
|
||||||
|
if (len < 0) {
|
||||||
|
printf("non-numeric length argument -- %s\n", arg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* should be SIZE_T_MAX, but that doesn't exist */
|
||||||
|
if (len > UINT_MAX) {
|
||||||
|
printf("too large length argument -- %s\n", arg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len & 0x1ff) {
|
||||||
|
printf("length argument %lld is not sector aligned\n",
|
||||||
|
len);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sizes[i] = len;
|
||||||
|
count += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_iovec_init(qiov, nr_iov);
|
||||||
|
|
||||||
|
buf = p = qemu_io_alloc(count, pattern);
|
||||||
|
|
||||||
|
for (i = 0; i < nr_iov; i++) {
|
||||||
|
qemu_iovec_add(qiov, p, sizes[i]);
|
||||||
|
p += sizes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
free(sizes);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
static int do_read(char *buf, int64_t offset, int count, int *total)
|
static int do_read(char *buf, int64_t offset, int count, int *total)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -375,10 +426,10 @@ readv_f(int argc, char **argv)
|
||||||
struct timeval t1, t2;
|
struct timeval t1, t2;
|
||||||
int Cflag = 0, qflag = 0, vflag = 0;
|
int Cflag = 0, qflag = 0, vflag = 0;
|
||||||
int c, cnt;
|
int c, cnt;
|
||||||
char *buf, *p;
|
char *buf;
|
||||||
int64_t offset;
|
int64_t offset;
|
||||||
int count = 0, total;
|
int total;
|
||||||
int nr_iov, i;
|
int nr_iov;
|
||||||
QEMUIOVector qiov;
|
QEMUIOVector qiov;
|
||||||
int pattern = 0;
|
int pattern = 0;
|
||||||
int Pflag = 0;
|
int Pflag = 0;
|
||||||
|
@ -420,40 +471,8 @@ readv_f(int argc, char **argv)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count & 0x1ff) {
|
|
||||||
printf("count %d is not sector aligned\n",
|
|
||||||
count);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = optind; i < argc; i++) {
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
len = cvtnum(argv[i]);
|
|
||||||
if (len < 0) {
|
|
||||||
printf("non-numeric length argument -- %s\n", argv[i]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
count += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
nr_iov = argc - optind;
|
nr_iov = argc - optind;
|
||||||
qemu_iovec_init(&qiov, nr_iov);
|
buf = create_iovec(&qiov, &argv[optind], nr_iov, 0xab);
|
||||||
buf = p = qemu_io_alloc(count, 0xab);
|
|
||||||
for (i = 0; i < nr_iov; i++) {
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
len = cvtnum(argv[optind]);
|
|
||||||
if (len < 0) {
|
|
||||||
printf("non-numeric length argument -- %s\n",
|
|
||||||
argv[optind]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_iovec_add(&qiov, p, len);
|
|
||||||
p += len;
|
|
||||||
optind++;
|
|
||||||
}
|
|
||||||
|
|
||||||
gettimeofday(&t1, NULL);
|
gettimeofday(&t1, NULL);
|
||||||
cnt = do_aio_readv(&qiov, offset, &total);
|
cnt = do_aio_readv(&qiov, offset, &total);
|
||||||
|
@ -465,12 +484,12 @@ readv_f(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Pflag) {
|
if (Pflag) {
|
||||||
void* cmp_buf = malloc(count);
|
void* cmp_buf = malloc(qiov.size);
|
||||||
memset(cmp_buf, pattern, count);
|
memset(cmp_buf, pattern, qiov.size);
|
||||||
if (memcmp(buf, cmp_buf, count)) {
|
if (memcmp(buf, cmp_buf, qiov.size)) {
|
||||||
printf("Pattern verification failed at offset %lld, "
|
printf("Pattern verification failed at offset %lld, "
|
||||||
"%d bytes\n",
|
"%zd bytes\n",
|
||||||
(long long) offset, count);
|
(long long) offset, qiov.size);
|
||||||
}
|
}
|
||||||
free(cmp_buf);
|
free(cmp_buf);
|
||||||
}
|
}
|
||||||
|
@ -646,10 +665,10 @@ writev_f(int argc, char **argv)
|
||||||
struct timeval t1, t2;
|
struct timeval t1, t2;
|
||||||
int Cflag = 0, qflag = 0;
|
int Cflag = 0, qflag = 0;
|
||||||
int c, cnt;
|
int c, cnt;
|
||||||
char *buf, *p;
|
char *buf;
|
||||||
int64_t offset;
|
int64_t offset;
|
||||||
int count = 0, total;
|
int total;
|
||||||
int nr_iov, i;
|
int nr_iov;
|
||||||
int pattern = 0xcd;
|
int pattern = 0xcd;
|
||||||
QEMUIOVector qiov;
|
QEMUIOVector qiov;
|
||||||
|
|
||||||
|
@ -685,41 +704,8 @@ writev_f(int argc, char **argv)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count & 0x1ff) {
|
|
||||||
printf("count %d is not sector aligned\n",
|
|
||||||
count);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for (i = optind; i < argc; i++) {
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
len = cvtnum(argv[optind]);
|
|
||||||
if (len < 0) {
|
|
||||||
printf("non-numeric length argument -- %s\n", argv[i]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
count += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
nr_iov = argc - optind;
|
nr_iov = argc - optind;
|
||||||
qemu_iovec_init(&qiov, nr_iov);
|
buf = create_iovec(&qiov, &argv[optind], nr_iov, pattern);
|
||||||
buf = p = qemu_io_alloc(count, pattern);
|
|
||||||
for (i = 0; i < nr_iov; i++) {
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
len = cvtnum(argv[optind]);
|
|
||||||
if (len < 0) {
|
|
||||||
printf("non-numeric length argument -- %s\n",
|
|
||||||
argv[optind]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_iovec_add(&qiov, p, len);
|
|
||||||
p += len;
|
|
||||||
optind++;
|
|
||||||
}
|
|
||||||
|
|
||||||
gettimeofday(&t1, NULL);
|
gettimeofday(&t1, NULL);
|
||||||
cnt = do_aio_writev(&qiov, offset, &total);
|
cnt = do_aio_writev(&qiov, offset, &total);
|
||||||
|
@ -859,9 +845,7 @@ aio_read_help(void)
|
||||||
static int
|
static int
|
||||||
aio_read_f(int argc, char **argv)
|
aio_read_f(int argc, char **argv)
|
||||||
{
|
{
|
||||||
char *p;
|
int nr_iov, c;
|
||||||
int count = 0;
|
|
||||||
int nr_iov, i, c;
|
|
||||||
struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
|
struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
|
||||||
BlockDriverAIOCB *acb;
|
BlockDriverAIOCB *acb;
|
||||||
|
|
||||||
|
@ -902,40 +886,8 @@ aio_read_f(int argc, char **argv)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count & 0x1ff) {
|
|
||||||
printf("count %d is not sector aligned\n",
|
|
||||||
count);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = optind; i < argc; i++) {
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
len = cvtnum(argv[i]);
|
|
||||||
if (len < 0) {
|
|
||||||
printf("non-numeric length argument -- %s\n", argv[i]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
count += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
nr_iov = argc - optind;
|
nr_iov = argc - optind;
|
||||||
qemu_iovec_init(&ctx->qiov, nr_iov);
|
ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab);
|
||||||
ctx->buf = p = qemu_io_alloc(count, 0xab);
|
|
||||||
for (i = 0; i < nr_iov; i++) {
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
len = cvtnum(argv[optind]);
|
|
||||||
if (len < 0) {
|
|
||||||
printf("non-numeric length argument -- %s\n",
|
|
||||||
argv[optind]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_iovec_add(&ctx->qiov, p, len);
|
|
||||||
p += len;
|
|
||||||
optind++;
|
|
||||||
}
|
|
||||||
|
|
||||||
gettimeofday(&ctx->t1, NULL);
|
gettimeofday(&ctx->t1, NULL);
|
||||||
acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
|
acb = bdrv_aio_readv(bs, ctx->offset >> 9, &ctx->qiov,
|
||||||
|
@ -983,9 +935,7 @@ aio_write_help(void)
|
||||||
static int
|
static int
|
||||||
aio_write_f(int argc, char **argv)
|
aio_write_f(int argc, char **argv)
|
||||||
{
|
{
|
||||||
char *p;
|
int nr_iov, c;
|
||||||
int count = 0;
|
|
||||||
int nr_iov, i, c;
|
|
||||||
int pattern = 0xcd;
|
int pattern = 0xcd;
|
||||||
struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
|
struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
|
||||||
BlockDriverAIOCB *acb;
|
BlockDriverAIOCB *acb;
|
||||||
|
@ -1022,40 +972,8 @@ aio_write_f(int argc, char **argv)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count & 0x1ff) {
|
|
||||||
printf("count %d is not sector aligned\n",
|
|
||||||
count);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = optind; i < argc; i++) {
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
len = cvtnum(argv[optind]);
|
|
||||||
if (len < 0) {
|
|
||||||
printf("non-numeric length argument -- %s\n", argv[i]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
count += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
nr_iov = argc - optind;
|
nr_iov = argc - optind;
|
||||||
qemu_iovec_init(&ctx->qiov, nr_iov);
|
ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern);
|
||||||
ctx->buf = p = qemu_io_alloc(count, pattern);
|
|
||||||
for (i = 0; i < nr_iov; i++) {
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
len = cvtnum(argv[optind]);
|
|
||||||
if (len < 0) {
|
|
||||||
printf("non-numeric length argument -- %s\n",
|
|
||||||
argv[optind]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_iovec_add(&ctx->qiov, p, len);
|
|
||||||
p += len;
|
|
||||||
optind++;
|
|
||||||
}
|
|
||||||
|
|
||||||
gettimeofday(&ctx->t1, NULL);
|
gettimeofday(&ctx->t1, NULL);
|
||||||
acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
|
acb = bdrv_aio_writev(bs, ctx->offset >> 9, &ctx->qiov,
|
||||||
|
|
Loading…
Reference in New Issue