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

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;