Blame SOURCES/libtar-1.2.11-CVE-2013-4397.patch

1199b1
From 8505fb844300f493b4e848d4461537a7bb0e8cc0 Mon Sep 17 00:00:00 2001
1199b1
From: Kamil Dudka <kdudka@redhat.com>
1199b1
Date: Fri, 4 Oct 2013 13:55:26 +0200
1199b1
Subject: [PATCH] libtar - fix CVE-2013-4397 libtar (upstream patch)
1199b1
1199b1
Heap-based buffer overflows by expanding a specially-crafted archive
1199b1
---
1199b1
 lib/block.c |   38 ++++++++++++++++++++++++--------------
1199b1
 1 files changed, 24 insertions(+), 14 deletions(-)
1199b1
1199b1
diff --git a/lib/block.c b/lib/block.c
1199b1
index 2917dc6..092bc28 100644
1199b1
--- a/lib/block.c
1199b1
+++ b/lib/block.c
1199b1
@@ -90,8 +90,8 @@ th_read_internal(TAR *t)
1199b1
 int
1199b1
 th_read(TAR *t)
1199b1
 {
1199b1
-	int i, j;
1199b1
-	size_t sz;
1199b1
+	int i;
1199b1
+	size_t sz, j, blocks;
1199b1
 	char *ptr;
1199b1
 
1199b1
 #ifdef DEBUG
1199b1
@@ -118,21 +118,26 @@ th_read(TAR *t)
1199b1
 	if (TH_ISLONGLINK(t))
1199b1
 	{
1199b1
 		sz = th_get_size(t);
1199b1
-		j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
1199b1
+		blocks = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
1199b1
+		if (blocks > ((size_t)-1 / T_BLOCKSIZE))
1199b1
+		{
1199b1
+			errno = E2BIG;
1199b1
+			return -1;
1199b1
+		}
1199b1
 #ifdef DEBUG
1199b1
 		printf("    th_read(): GNU long linkname detected "
1199b1
-		       "(%ld bytes, %d blocks)\n", sz, j);
1199b1
+		       "(%ld bytes, %d blocks)\n", sz, blocks);
1199b1
 #endif
1199b1
-		t->th_buf.gnu_longlink = (char *)malloc(j * T_BLOCKSIZE);
1199b1
+		t->th_buf.gnu_longlink = (char *)malloc(blocks * T_BLOCKSIZE);
1199b1
 		if (t->th_buf.gnu_longlink == NULL)
1199b1
 			return -1;
1199b1
 
1199b1
-		for (ptr = t->th_buf.gnu_longlink; j > 0;
1199b1
-		     j--, ptr += T_BLOCKSIZE)
1199b1
+		for (j = 0, ptr = t->th_buf.gnu_longlink; j < blocks;
1199b1
+		     j++, ptr += T_BLOCKSIZE)
1199b1
 		{
1199b1
 #ifdef DEBUG
1199b1
 			printf("    th_read(): reading long linkname "
1199b1
-			       "(%d blocks left, ptr == %ld)\n", j, ptr);
1199b1
+			       "(%d blocks left, ptr == %ld)\n", blocks-j, ptr);
1199b1
 #endif
1199b1
 			i = tar_block_read(t, ptr);
1199b1
 			if (i != T_BLOCKSIZE)
1199b1
@@ -163,21 +168,26 @@ th_read(TAR *t)
1199b1
 	if (TH_ISLONGNAME(t))
1199b1
 	{
1199b1
 		sz = th_get_size(t);
1199b1
-		j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
1199b1
+		blocks = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
1199b1
+		if (blocks > ((size_t)-1 / T_BLOCKSIZE))
1199b1
+		{
1199b1
+			errno = E2BIG;
1199b1
+			return -1;
1199b1
+		}
1199b1
 #ifdef DEBUG
1199b1
 		printf("    th_read(): GNU long filename detected "
1199b1
-		       "(%ld bytes, %d blocks)\n", sz, j);
1199b1
+		       "(%ld bytes, %d blocks)\n", sz, blocks);
1199b1
 #endif
1199b1
-		t->th_buf.gnu_longname = (char *)malloc(j * T_BLOCKSIZE);
1199b1
+		t->th_buf.gnu_longname = (char *)malloc(blocks * T_BLOCKSIZE);
1199b1
 		if (t->th_buf.gnu_longname == NULL)
1199b1
 			return -1;
1199b1
 
1199b1
-		for (ptr = t->th_buf.gnu_longname; j > 0;
1199b1
-		     j--, ptr += T_BLOCKSIZE)
1199b1
+		for (j = 0, ptr = t->th_buf.gnu_longname; j < blocks;
1199b1
+		     j++, ptr += T_BLOCKSIZE)
1199b1
 		{
1199b1
 #ifdef DEBUG
1199b1
 			printf("    th_read(): reading long filename "
1199b1
-			       "(%d blocks left, ptr == %ld)\n", j, ptr);
1199b1
+			       "(%d blocks left, ptr == %ld)\n", blocks-j, ptr);
1199b1
 #endif
1199b1
 			i = tar_block_read(t, ptr);
1199b1
 			if (i != T_BLOCKSIZE)
1199b1
-- 
1199b1
1.7.1
1199b1