|
|
b1bcb2 |
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
|
b1bcb2 |
From: Paulo Flabiano Smorigo <pfsmorigo@canonical.com>
|
|
|
b1bcb2 |
Date: Mon, 14 Dec 2020 18:54:49 -0300
|
|
|
b1bcb2 |
Subject: [PATCH] zfs: Fix resource leaks while constructing path
|
|
|
b1bcb2 |
|
|
|
b1bcb2 |
There are several exit points in dnode_get_path() that are causing possible
|
|
|
b1bcb2 |
memory leaks.
|
|
|
b1bcb2 |
|
|
|
b1bcb2 |
In the while(1) the correct exit mechanism should not be to do a direct return,
|
|
|
b1bcb2 |
but to instead break out of the loop, setting err first if it is not already set.
|
|
|
b1bcb2 |
|
|
|
b1bcb2 |
The reason behind this is that the dnode_path is a linked list, and while doing
|
|
|
b1bcb2 |
through this loop, it is being allocated and built up - the only way to
|
|
|
b1bcb2 |
correctly unravel it is to traverse it, which is what is being done at the end
|
|
|
b1bcb2 |
of the function outside of the loop.
|
|
|
b1bcb2 |
|
|
|
b1bcb2 |
Several of the existing exit points correctly did a break, but not all so this
|
|
|
b1bcb2 |
change makes that more consistent and should resolve the leaking of memory as
|
|
|
b1bcb2 |
found by Coverity.
|
|
|
b1bcb2 |
|
|
|
b1bcb2 |
Fixes: CID 73741
|
|
|
b1bcb2 |
|
|
|
b1bcb2 |
Signed-off-by: Paulo Flabiano Smorigo <pfsmorigo@canonical.com>
|
|
|
b1bcb2 |
Signed-off-by: Darren Kenny <darren.kenny@oracle.com>
|
|
|
b1bcb2 |
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
|
|
b1bcb2 |
---
|
|
|
b1bcb2 |
grub-core/fs/zfs/zfs.c | 30 ++++++++++++++++++++++--------
|
|
|
b1bcb2 |
1 file changed, 22 insertions(+), 8 deletions(-)
|
|
|
b1bcb2 |
|
|
|
b1bcb2 |
diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c
|
|
|
b1bcb2 |
index f607b9b56b9..467fa7ee9ea 100644
|
|
|
b1bcb2 |
--- a/grub-core/fs/zfs/zfs.c
|
|
|
b1bcb2 |
+++ b/grub-core/fs/zfs/zfs.c
|
|
|
b1bcb2 |
@@ -2771,8 +2771,8 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
|
|
|
b1bcb2 |
|
|
|
b1bcb2 |
if (dnode_path->dn.dn.dn_type != DMU_OT_DIRECTORY_CONTENTS)
|
|
|
b1bcb2 |
{
|
|
|
b1bcb2 |
- grub_free (path_buf);
|
|
|
b1bcb2 |
- return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
|
|
|
b1bcb2 |
+ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
|
|
|
b1bcb2 |
+ break;
|
|
|
b1bcb2 |
}
|
|
|
b1bcb2 |
err = zap_lookup (&(dnode_path->dn), cname, &objnum,
|
|
|
b1bcb2 |
data, subvol->case_insensitive);
|
|
|
b1bcb2 |
@@ -2815,7 +2815,11 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
|
|
|
b1bcb2 |
|
|
|
b1bcb2 |
sym_value = grub_malloc (sym_sz);
|
|
|
b1bcb2 |
if (!sym_value)
|
|
|
b1bcb2 |
- return grub_errno;
|
|
|
b1bcb2 |
+ {
|
|
|
b1bcb2 |
+ err = grub_errno;
|
|
|
b1bcb2 |
+ break;
|
|
|
b1bcb2 |
+ }
|
|
|
b1bcb2 |
+
|
|
|
b1bcb2 |
for (block = 0; block < (sym_sz + blksz - 1) / blksz; block++)
|
|
|
b1bcb2 |
{
|
|
|
b1bcb2 |
void *t;
|
|
|
b1bcb2 |
@@ -2823,7 +2827,10 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
|
|
|
b1bcb2 |
|
|
|
b1bcb2 |
err = dmu_read (&(dnode_path->dn), block, &t, 0, data);
|
|
|
b1bcb2 |
if (err)
|
|
|
b1bcb2 |
- return err;
|
|
|
b1bcb2 |
+ {
|
|
|
b1bcb2 |
+ grub_free (sym_value);
|
|
|
b1bcb2 |
+ break;
|
|
|
b1bcb2 |
+ }
|
|
|
b1bcb2 |
|
|
|
b1bcb2 |
movesize = sym_sz - block * blksz;
|
|
|
b1bcb2 |
if (movesize > blksz)
|
|
|
b1bcb2 |
@@ -2832,13 +2839,18 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
|
|
|
b1bcb2 |
grub_memcpy (sym_value + block * blksz, t, movesize);
|
|
|
b1bcb2 |
grub_free (t);
|
|
|
b1bcb2 |
}
|
|
|
b1bcb2 |
+ if (err)
|
|
|
b1bcb2 |
+ break;
|
|
|
b1bcb2 |
free_symval = 1;
|
|
|
b1bcb2 |
}
|
|
|
b1bcb2 |
path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1);
|
|
|
b1bcb2 |
if (!path_buf)
|
|
|
b1bcb2 |
{
|
|
|
b1bcb2 |
grub_free (oldpathbuf);
|
|
|
b1bcb2 |
- return grub_errno;
|
|
|
b1bcb2 |
+ if (free_symval)
|
|
|
b1bcb2 |
+ grub_free (sym_value);
|
|
|
b1bcb2 |
+ err = grub_errno;
|
|
|
b1bcb2 |
+ break;
|
|
|
b1bcb2 |
}
|
|
|
b1bcb2 |
grub_memcpy (path, sym_value, sym_sz);
|
|
|
b1bcb2 |
if (free_symval)
|
|
|
b1bcb2 |
@@ -2876,11 +2888,12 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
|
|
|
b1bcb2 |
|
|
|
b1bcb2 |
err = zio_read (bp, dnode_path->dn.endian, &sahdrp, NULL, data);
|
|
|
b1bcb2 |
if (err)
|
|
|
b1bcb2 |
- return err;
|
|
|
b1bcb2 |
+ break;
|
|
|
b1bcb2 |
}
|
|
|
b1bcb2 |
else
|
|
|
b1bcb2 |
{
|
|
|
b1bcb2 |
- return grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
|
|
|
b1bcb2 |
+ err = grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
|
|
|
b1bcb2 |
+ break;
|
|
|
b1bcb2 |
}
|
|
|
b1bcb2 |
|
|
|
b1bcb2 |
hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
|
|
|
b1bcb2 |
@@ -2901,7 +2914,8 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
|
|
|
b1bcb2 |
if (!path_buf)
|
|
|
b1bcb2 |
{
|
|
|
b1bcb2 |
grub_free (oldpathbuf);
|
|
|
b1bcb2 |
- return grub_errno;
|
|
|
b1bcb2 |
+ err = grub_errno;
|
|
|
b1bcb2 |
+ break;
|
|
|
b1bcb2 |
}
|
|
|
b1bcb2 |
grub_memcpy (path, sym_value, sym_sz);
|
|
|
b1bcb2 |
path [sym_sz] = 0;
|