[PATCH 3/3] qemu_namespace: Don't leak mknod items that are being skipped over
Ján Tomko
jtomko at redhat.com
Fri Sep 4 16:16:52 UTC 2020
On a Friday in 2020, Michal Privoznik wrote:
>When building and populating domain NS a couple of functions is
>called that append paths to a string list. This string list is
>then inspected, one item at the time by
>qemuNamespacePrepareOneItem() which gathers all the info for
>given path (stat buffer, possible link target, ACLs, SELinux
>label) using qemuNamespaceMknodItemInit(). If the path needs to
>be created in the domain's private /dev then it's added onto this
>qemuNamespaceMknodData list which is freed later in the process.
>But, if the path does not need to be created in the domain's
>private /dev, then the memory allocated by
>qemuNamespaceMknodItemInit() is not freed anywhere leading to a
>leak.
>
>Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
>---
>
>Honestly, I think this patch looks ugly. Ideas are welcome.
>
> src/qemu/qemu_namespace.c | 42 +++++++++++++++++++++++++++++----------
> 1 file changed, 31 insertions(+), 11 deletions(-)
>
>diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c
>index 87f4fd8d58..917e140f6a 100644
>--- a/src/qemu/qemu_namespace.c
>+++ b/src/qemu/qemu_namespace.c
>@@ -1166,22 +1166,29 @@ qemuNamespacePrepareOneItem(qemuNamespaceMknodDataPtr data,
> size_t ndevMountsPath)
> {
> long ttl = sysconf(_SC_SYMLOOP_MAX);
>- const char *next = file;
>+ g_autofree char *next = g_strdup(file);
> size_t i;
>
> while (1) {
> qemuNamespaceMknodItem item = { 0 };
>+ bool added = false;
>+ bool isLink;
> int rc;
>
> rc = qemuNamespaceMknodItemInit(&item, cfg, vm, next);
@next gets consumed here. That seems to be the cause of all grief.
>- if (rc == -2) {
>- /* @file doesn't exist. We can break here. */
>- break;
>- } else if (rc < 0) {
>+ if (rc < 0) {
>+ qemuNamespaceMknodItemClear(&item);
>+
>+ if (rc == -2) {
>+ /* @file doesn't exist. We can break here. */
>+ break;
Strictly speaking, there is nothing to free yet because -2 is returned
pretty early. And ItemInit could be changed to clean up after itself
if it returns -1.
>+ }
> /* Some other (critical) error. */
> return -1;
> }
>
>+ isLink = S_ISLNK(item.sb.st_mode);
>+
If you move the next assignment here, nothing below the APPEND_ELEMENT_COPY
needs to access item anymore, so you can switch it to the non-copy
version and clear it unconditionally and use g_auto to clear it.
> if (STRPREFIX(next, QEMU_DEVPREFIX)) {
> for (i = 0; i < ndevMountsPath; i++) {
> if (STREQ(devMountsPath[i], "/dev"))
>@@ -1190,22 +1197,35 @@ qemuNamespacePrepareOneItem(qemuNamespaceMknodDataPtr data,
> break;
> }
>
>- if (i == ndevMountsPath &&
>- VIR_APPEND_ELEMENT_COPY(data->items, data->nitems, item) < 0)
>- return -1;
>+ if (i == ndevMountsPath) {
>+ if (VIR_APPEND_ELEMENT_COPY(data->items, data->nitems, item) < 0) {
>+ qemuNamespaceMknodItemClear(&item);
>+ return -1;
>+ }
>+ added = true;
>+ }
> }
>
>- if (!S_ISLNK(item.sb.st_mode))
>+ if (!isLink) {
>+ if (!added)
>+ qemuNamespaceMknodItemClear(&item);
> break;
>+ }
>
> if (ttl-- == 0) {
>+ if (!added)
>+ qemuNamespaceMknodItemClear(&item);
> virReportSystemError(ELOOP,
> _("Too many levels of symbolic links: %s"),
>- next);
>+ file);
> return -1;
This change makes sense on its own and can be separated.
> }
>
>- next = item.target;
>+ g_free(next);
Apart from the g_free/g_autofree mixup, this frees previous iteration's
item->file, possibly after it has been added to data->items. So we do need
to g_strdup it in ItemInit.
>+ next = g_strdup(item.target);
>+
If you add a second array to hold the thrown away items during this
function, you could leave the iterator const char*. Not sure whether
that is nicer or not.
Jano
>+ if (!added)
>+ qemuNamespaceMknodItemClear(&item);
> }
>
> return 0;
>--
>2.26.2
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20200904/b0b6eab7/attachment-0001.sig>
More information about the libvir-list
mailing list