|
|
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 |
|