aboutsummaryrefslogtreecommitdiffstats
path: root/main/tar/CVE-2021-20193.patch
blob: c721f870bdeaccaf66c9e7cadd711ce4b3b18dca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
From d9d4435692150fa8ff68e1b1a473d187cc3fd777 Mon Sep 17 00:00:00 2001
From: Sergey Poznyakoff <gray@gnu.org>
Date: Sun, 17 Jan 2021 20:41:11 +0200
Subject: Fix memory leak in read_header

Bug reported in https://savannah.gnu.org/bugs/?59897

* src/list.c (read_header): Don't return directly from the loop.
Instead set the status and break.  Return the status.  Free
next_long_name and next_long_link before returning.
---
 src/list.c | 40 ++++++++++++++++++++++++++++------------
 1 file changed, 28 insertions(+), 12 deletions(-)

diff --git a/src/list.c b/src/list.c
index e40a5c8..d7ef441 100644
--- a/src/list.c
+++ b/src/list.c
@@ -408,26 +408,27 @@ read_header (union block **return_block, struct tar_stat_info *info,
 	     enum read_header_mode mode)
 {
   union block *header;
-  union block *header_copy;
   char *bp;
   union block *data_block;
   size_t size, written;
-  union block *next_long_name = 0;
-  union block *next_long_link = 0;
+  union block *next_long_name = NULL;
+  union block *next_long_link = NULL;
   size_t next_long_name_blocks = 0;
   size_t next_long_link_blocks = 0;
-
+  enum read_header status = HEADER_SUCCESS;
+  
   while (1)
     {
-      enum read_header status;
-
       header = find_next_block ();
       *return_block = header;
       if (!header)
-	return HEADER_END_OF_FILE;
+	{
+	  status = HEADER_END_OF_FILE;
+	  break;
+	}
 
       if ((status = tar_checksum (header, false)) != HEADER_SUCCESS)
-	return status;
+	break;
 
       /* Good block.  Decode file size and return.  */
 
@@ -437,7 +438,10 @@ read_header (union block **return_block, struct tar_stat_info *info,
 	{
 	  info->stat.st_size = OFF_FROM_HEADER (header->header.size);
 	  if (info->stat.st_size < 0)
-	    return HEADER_FAILURE;
+	    {
+	      status = HEADER_FAILURE;
+	      break;
+	    }
 	}
 
       if (header->header.typeflag == GNUTYPE_LONGNAME
@@ -447,10 +451,14 @@ read_header (union block **return_block, struct tar_stat_info *info,
 	  || header->header.typeflag == SOLARIS_XHDTYPE)
 	{
 	  if (mode == read_header_x_raw)
-	    return HEADER_SUCCESS_EXTENDED;
+	    {
+	      status = HEADER_SUCCESS_EXTENDED;
+	      break;
+	    }
 	  else if (header->header.typeflag == GNUTYPE_LONGNAME
 		   || header->header.typeflag == GNUTYPE_LONGLINK)
 	    {
+	      union block *header_copy;
 	      size_t name_size = info->stat.st_size;
 	      size_t n = name_size % BLOCKSIZE;
 	      size = name_size + BLOCKSIZE;
@@ -517,7 +525,10 @@ read_header (union block **return_block, struct tar_stat_info *info,
 	      xheader_decode_global (&xhdr);
 	      xheader_destroy (&xhdr);
 	      if (mode == read_header_x_global)
-		return HEADER_SUCCESS_EXTENDED;
+		{
+		  status = HEADER_SUCCESS_EXTENDED;
+		  break;
+		}
 	    }
 
 	  /* Loop!  */
@@ -536,6 +547,7 @@ read_header (union block **return_block, struct tar_stat_info *info,
 	      name = next_long_name->buffer + BLOCKSIZE;
 	      recent_long_name = next_long_name;
 	      recent_long_name_blocks = next_long_name_blocks;
+	      next_long_name = NULL;
 	    }
 	  else
 	    {
@@ -567,6 +579,7 @@ read_header (union block **return_block, struct tar_stat_info *info,
 	      name = next_long_link->buffer + BLOCKSIZE;
 	      recent_long_link = next_long_link;
 	      recent_long_link_blocks = next_long_link_blocks;
+	      next_long_link = NULL;
 	    }
 	  else
 	    {
@@ -578,9 +591,12 @@ read_header (union block **return_block, struct tar_stat_info *info,
 	    }
 	  assign_string (&info->link_name, name);
 
-	  return HEADER_SUCCESS;
+	  break;
 	}
     }
+  free (next_long_name);
+  free (next_long_link);
+  return status;
 }
 
 #define ISOCTAL(c) ((c)>='0'&&(c)<='7')
-- 
cgit v1.2.1