1*4882a593SmuzhiyunFrom 89bdab965805e8d54d7f75349024e1a11cbe2eb8 Mon Sep 17 00:00:00 2001
2*4882a593SmuzhiyunFrom: Paulo Flabiano Smorigo <pfsmorigo@canonical.com>
3*4882a593SmuzhiyunDate: Mon, 14 Dec 2020 18:54:49 -0300
4*4882a593SmuzhiyunSubject: [PATCH] zfs: Fix resource leaks while constructing path
5*4882a593Smuzhiyun
6*4882a593SmuzhiyunThere are several exit points in dnode_get_path() that are causing possible
7*4882a593Smuzhiyunmemory leaks.
8*4882a593Smuzhiyun
9*4882a593SmuzhiyunIn the while(1) the correct exit mechanism should not be to do a direct return,
10*4882a593Smuzhiyunbut to instead break out of the loop, setting err first if it is not already set.
11*4882a593Smuzhiyun
12*4882a593SmuzhiyunThe reason behind this is that the dnode_path is a linked list, and while doing
13*4882a593Smuzhiyunthrough this loop, it is being allocated and built up - the only way to
14*4882a593Smuzhiyuncorrectly unravel it is to traverse it, which is what is being done at the end
15*4882a593Smuzhiyunof the function outside of the loop.
16*4882a593Smuzhiyun
17*4882a593SmuzhiyunSeveral of the existing exit points correctly did a break, but not all so this
18*4882a593Smuzhiyunchange makes that more consistent and should resolve the leaking of memory as
19*4882a593Smuzhiyunfound by Coverity.
20*4882a593Smuzhiyun
21*4882a593SmuzhiyunFixes: CID 73741
22*4882a593Smuzhiyun
23*4882a593SmuzhiyunSigned-off-by: Paulo Flabiano Smorigo <pfsmorigo@canonical.com>
24*4882a593SmuzhiyunSigned-off-by: Darren Kenny <darren.kenny@oracle.com>
25*4882a593SmuzhiyunReviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
26*4882a593SmuzhiyunSigned-off-by: Stefan Sørensen <stefan.sorensen@spectralink.com>
27*4882a593Smuzhiyun---
28*4882a593Smuzhiyun grub-core/fs/zfs/zfs.c | 30 +++++++++++++++++++++---------
29*4882a593Smuzhiyun 1 file changed, 21 insertions(+), 9 deletions(-)
30*4882a593Smuzhiyun
31*4882a593Smuzhiyundiff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c
32*4882a593Smuzhiyunindex 0c42cba..9087a72 100644
33*4882a593Smuzhiyun--- a/grub-core/fs/zfs/zfs.c
34*4882a593Smuzhiyun+++ b/grub-core/fs/zfs/zfs.c
35*4882a593Smuzhiyun@@ -2836,8 +2836,8 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun       if (dnode_path->dn.dn.dn_type != DMU_OT_DIRECTORY_CONTENTS)
38*4882a593Smuzhiyun 	{
39*4882a593Smuzhiyun-	  grub_free (path_buf);
40*4882a593Smuzhiyun-	  return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
41*4882a593Smuzhiyun+	  err = grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory"));
42*4882a593Smuzhiyun+	  break;
43*4882a593Smuzhiyun 	}
44*4882a593Smuzhiyun       err = zap_lookup (&(dnode_path->dn), cname, &objnum,
45*4882a593Smuzhiyun 			data, subvol->case_insensitive);
46*4882a593Smuzhiyun@@ -2879,11 +2879,18 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
47*4882a593Smuzhiyun 		       << SPA_MINBLOCKSHIFT);
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun 	      if (blksz == 0)
50*4882a593Smuzhiyun-		return grub_error(GRUB_ERR_BAD_FS, "0-sized block");
51*4882a593Smuzhiyun+                {
52*4882a593Smuzhiyun+                  err = grub_error (GRUB_ERR_BAD_FS, "0-sized block");
53*4882a593Smuzhiyun+                  break;
54*4882a593Smuzhiyun+                }
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun 	      sym_value = grub_malloc (sym_sz);
57*4882a593Smuzhiyun 	      if (!sym_value)
58*4882a593Smuzhiyun-		return grub_errno;
59*4882a593Smuzhiyun+		{
60*4882a593Smuzhiyun+		  err = grub_errno;
61*4882a593Smuzhiyun+		  break;
62*4882a593Smuzhiyun+		}
63*4882a593Smuzhiyun+
64*4882a593Smuzhiyun 	      for (block = 0; block < (sym_sz + blksz - 1) / blksz; block++)
65*4882a593Smuzhiyun 		{
66*4882a593Smuzhiyun 		  void *t;
67*4882a593Smuzhiyun@@ -2893,7 +2900,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
68*4882a593Smuzhiyun 		  if (err)
69*4882a593Smuzhiyun 		    {
70*4882a593Smuzhiyun 		      grub_free (sym_value);
71*4882a593Smuzhiyun-		      return err;
72*4882a593Smuzhiyun+		      break;
73*4882a593Smuzhiyun 		    }
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun 		  movesize = sym_sz - block * blksz;
76*4882a593Smuzhiyun@@ -2903,6 +2910,8 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
77*4882a593Smuzhiyun 		  grub_memcpy (sym_value + block * blksz, t, movesize);
78*4882a593Smuzhiyun 		  grub_free (t);
79*4882a593Smuzhiyun 		}
80*4882a593Smuzhiyun+		if (err)
81*4882a593Smuzhiyun+		  break;
82*4882a593Smuzhiyun 	      free_symval = 1;
83*4882a593Smuzhiyun 	    }
84*4882a593Smuzhiyun 	  path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1);
85*4882a593Smuzhiyun@@ -2911,7 +2920,8 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
86*4882a593Smuzhiyun 	      grub_free (oldpathbuf);
87*4882a593Smuzhiyun 	      if (free_symval)
88*4882a593Smuzhiyun 		grub_free (sym_value);
89*4882a593Smuzhiyun-	      return grub_errno;
90*4882a593Smuzhiyun+	      err = grub_errno;
91*4882a593Smuzhiyun+	      break;
92*4882a593Smuzhiyun 	    }
93*4882a593Smuzhiyun 	  grub_memcpy (path, sym_value, sym_sz);
94*4882a593Smuzhiyun 	  if (free_symval)
95*4882a593Smuzhiyun@@ -2949,11 +2959,12 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun 	      err = zio_read (bp, dnode_path->dn.endian, &sahdrp, NULL, data);
98*4882a593Smuzhiyun 	      if (err)
99*4882a593Smuzhiyun-		return err;
100*4882a593Smuzhiyun+	        break;
101*4882a593Smuzhiyun 	    }
102*4882a593Smuzhiyun 	  else
103*4882a593Smuzhiyun 	    {
104*4882a593Smuzhiyun-	      return grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
105*4882a593Smuzhiyun+	      err = grub_error (GRUB_ERR_BAD_FS, "filesystem is corrupt");
106*4882a593Smuzhiyun+	      break;
107*4882a593Smuzhiyun 	    }
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun 	  hdrsize = SA_HDR_SIZE (((sa_hdr_phys_t *) sahdrp));
110*4882a593Smuzhiyun@@ -2974,7 +2985,8 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn,
111*4882a593Smuzhiyun 	      if (!path_buf)
112*4882a593Smuzhiyun 		{
113*4882a593Smuzhiyun 		  grub_free (oldpathbuf);
114*4882a593Smuzhiyun-		  return grub_errno;
115*4882a593Smuzhiyun+		  err = grub_errno;
116*4882a593Smuzhiyun+		  break;
117*4882a593Smuzhiyun 		}
118*4882a593Smuzhiyun 	      grub_memcpy (path, sym_value, sym_sz);
119*4882a593Smuzhiyun 	      path [sym_sz] = 0;
120*4882a593Smuzhiyun--
121*4882a593Smuzhiyun2.14.2
122*4882a593Smuzhiyun
123