Blame SOURCES/0406-zfs-Fix-resource-leaks-while-constructing-path.patch

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