Commit 22e132ff authored by Jiri Slaby's avatar Jiri Slaby Committed by Rusty Russell

Char: virtio_console, fix memory leak

Stanse found that in init_vqs, memory is leaked under certain
circumstanses (the fail path order is incorrect). Fix that by checking
allocations in one turn and free all of them at once if some fails
(some may be NULL, but this is OK).
Signed-off-by: default avatarJiri Slaby <jslaby@suse.cz>
Cc: Amit Shah <amit.shah@redhat.com>
Cc: virtualization@lists.linux-foundation.org
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 7ae4b866
...@@ -1547,31 +1547,16 @@ static int init_vqs(struct ports_device *portdev) ...@@ -1547,31 +1547,16 @@ static int init_vqs(struct ports_device *portdev)
nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2; nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2;
vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL); vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL);
if (!vqs) {
err = -ENOMEM;
goto fail;
}
io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL); io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL);
if (!io_callbacks) {
err = -ENOMEM;
goto free_vqs;
}
io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL); io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL);
if (!io_names) {
err = -ENOMEM;
goto free_callbacks;
}
portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
GFP_KERNEL); GFP_KERNEL);
if (!portdev->in_vqs) {
err = -ENOMEM;
goto free_names;
}
portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
GFP_KERNEL); GFP_KERNEL);
if (!portdev->out_vqs) { if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs ||
!portdev->out_vqs) {
err = -ENOMEM; err = -ENOMEM;
goto free_invqs; goto free;
} }
/* /*
...@@ -1605,7 +1590,7 @@ static int init_vqs(struct ports_device *portdev) ...@@ -1605,7 +1590,7 @@ static int init_vqs(struct ports_device *portdev)
io_callbacks, io_callbacks,
(const char **)io_names); (const char **)io_names);
if (err) if (err)
goto free_outvqs; goto free;
j = 0; j = 0;
portdev->in_vqs[0] = vqs[0]; portdev->in_vqs[0] = vqs[0];
...@@ -1621,23 +1606,19 @@ static int init_vqs(struct ports_device *portdev) ...@@ -1621,23 +1606,19 @@ static int init_vqs(struct ports_device *portdev)
portdev->out_vqs[i] = vqs[j + 1]; portdev->out_vqs[i] = vqs[j + 1];
} }
} }
kfree(io_callbacks);
kfree(io_names); kfree(io_names);
kfree(io_callbacks);
kfree(vqs); kfree(vqs);
return 0; return 0;
free_names: free:
kfree(io_names);
free_callbacks:
kfree(io_callbacks);
free_outvqs:
kfree(portdev->out_vqs); kfree(portdev->out_vqs);
free_invqs:
kfree(portdev->in_vqs); kfree(portdev->in_vqs);
free_vqs: kfree(io_names);
kfree(io_callbacks);
kfree(vqs); kfree(vqs);
fail:
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment