Subversion Repositories libtar

Compare Revisions

Ignore whitespace Rev 16 → Rev 34

/tags/1.2.20-3/debian/patches/CVE-2013-4420.patch
0,0 → 1,113
Author: Raphael Geissert <geissert@debian.org>
Bug-Debian: https://bugs.debian.org/731860
Description: Avoid directory traversal when extracting archives
by skipping over leading slashes and any prefix containing ".." components.
Forwarded: yes
 
--- a/lib/decode.c
+++ b/lib/decode.c
@@ -22,13 +22,42 @@
# include <string.h>
#endif
+char *
+safer_name_suffix (char const *file_name)
+{
+ char const *p, *t;
+ p = t = file_name;
+ while (*p == '/') t = ++p;
+ while (*p)
+ {
+ while (p[0] == '.' && p[0] == p[1] && p[2] == '/')
+ {
+ p += 3;
+ t = p;
+ }
+ /* advance pointer past the next slash */
+ while (*p && (p++)[0] != '/');
+ }
+
+ if (!*t)
+ {
+ t = ".";
+ }
+
+ if (t != file_name)
+ {
+ /* TODO: warn somehow that the path was modified */
+ }
+ return (char*)t;
+}
+
/* determine full path name */
char *
th_get_pathname(TAR *t)
{
if (t->th_buf.gnu_longname)
- return t->th_buf.gnu_longname;
+ return safer_name_suffix(t->th_buf.gnu_longname);
/* allocate the th_pathname buffer if not already */
if (t->th_pathname == NULL)
@@ -51,7 +80,7 @@ th_get_pathname(TAR *t)
}
/* will be deallocated in tar_close() */
- return t->th_pathname;
+ return safer_name_suffix(t->th_pathname);
}
--- a/lib/extract.c
+++ b/lib/extract.c
@@ -298,14 +298,14 @@ tar_extract_hardlink(TAR * t, char *real
if (mkdirhier(dirname(filename)) == -1)
return -1;
libtar_hashptr_reset(&hp);
- if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t),
+ if (libtar_hash_getkey(t->h, &hp, safer_name_suffix(th_get_linkname(t)),
(libtar_matchfunc_t)libtar_str_match) != 0)
{
lnp = (char *)libtar_hashptr_data(&hp);
linktgt = &lnp[strlen(lnp) + 1];
}
else
- linktgt = th_get_linkname(t);
+ linktgt = safer_name_suffix(th_get_linkname(t));
#ifdef DEBUG
printf(" ==> extracting: %s (link to %s)\n", filename, linktgt);
@@ -343,9 +343,9 @@ tar_extract_symlink(TAR *t, char *realna
#ifdef DEBUG
printf(" ==> extracting: %s (symlink to %s)\n",
- filename, th_get_linkname(t));
+ filename, safer_name_suffix(th_get_linkname(t)));
#endif
- if (symlink(th_get_linkname(t), filename) == -1)
+ if (symlink(safer_name_suffix(th_get_linkname(t)), filename) == -1)
{
#ifdef DEBUG
perror("symlink()");
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -21,3 +21,4 @@
#define TLS_THREAD
#endif
+char* safer_name_suffix(char const*);
--- a/lib/output.c
+++ b/lib/output.c
@@ -123,9 +123,9 @@ th_print_long_ls(TAR *t)
else
printf(" link to ");
if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL)
- printf("%s", t->th_buf.gnu_longlink);
+ printf("%s", safer_name_suffix(t->th_buf.gnu_longlink));
else
- printf("%.100s", t->th_buf.linkname);
+ printf("%.100s", safer_name_suffix(t->th_buf.linkname));
}
putchar('\n');
/tags/1.2.20-3/debian/patches/no_maxpathlen.patch
0,0 → 1,466
Author: Svante Signell <svante.signell@telia.com>
Author: Petter Reinholdtsen <pere@hungry.com>
Author: Magnus Holmgren <magnus@debian.org>
Bug-Debian: http://bugs.debian.org/657116
Description: Fix FTBFS on Hurd by dynamically allocating path names.
Depends on no_static_buffers.patch, which introduced the th_pathname field.
 
--- a/compat/basename.c
+++ b/compat/basename.c
@@ -34,13 +34,25 @@ static char rcsid[] = "$OpenBSD: basenam
#include <errno.h>
#include <string.h>
#include <sys/param.h>
+#include <stdlib.h>
char *
openbsd_basename(path)
const char *path;
{
- static char bname[MAXPATHLEN];
+ static char *bname = NULL;
+ static size_t allocated = 0;
register const char *endp, *startp;
+ int len = 0;
+
+ if (!allocated) {
+ allocated = 64;
+ bname = malloc(allocated);
+ if (!bname) {
+ allocated = 0;
+ return NULL;
+ }
+ }
/* Empty or NULL string gets treated as "." */
if (path == NULL || *path == '\0') {
@@ -64,11 +76,19 @@ openbsd_basename(path)
while (startp > path && *(startp - 1) != '/')
startp--;
- if (endp - startp + 1 > sizeof(bname)) {
- errno = ENAMETOOLONG;
- return(NULL);
+ len = endp - startp + 1;
+
+ if (len + 1 > allocated) {
+ size_t new_allocated = 2*(len+1);
+ void *new_bname = malloc(new_allocated);
+ if (!new_bname)
+ return NULL;
+ allocated = new_allocated;
+ free(bname);
+ bname = new_bname;
}
- (void)strncpy(bname, startp, endp - startp + 1);
- bname[endp - startp + 1] = '\0';
+
+ (void)strncpy(bname, startp, len);
+ bname[len] = '\0';
return(bname);
}
--- a/compat/dirname.c
+++ b/compat/dirname.c
@@ -34,13 +34,25 @@ static char rcsid[] = "$OpenBSD: dirname
#include <errno.h>
#include <string.h>
#include <sys/param.h>
+#include <stdlib.h>
char *
openbsd_dirname(path)
const char *path;
{
- static char bname[MAXPATHLEN];
+ static char *bname = NULL;
+ static size_t allocated = 0;
register const char *endp;
+ int len;
+
+ if (!allocated) {
+ allocated = 64;
+ bname = malloc(allocated);
+ if (!bname) {
+ allocated = 0;
+ return NULL;
+ }
+ }
/* Empty or NULL string gets treated as "." */
if (path == NULL || *path == '\0') {
--- a/lib/append.c
+++ b/lib/append.c
@@ -38,7 +38,7 @@ typedef struct tar_dev tar_dev_t;
struct tar_ino
{
ino_t ti_ino;
- char ti_name[MAXPATHLEN];
+ char ti_name[];
};
typedef struct tar_ino tar_ino_t;
@@ -61,7 +61,7 @@ tar_append_file(TAR *t, const char *real
libtar_hashptr_t hp;
tar_dev_t *td = NULL;
tar_ino_t *ti = NULL;
- char path[MAXPATHLEN];
+ char *path = NULL;
#ifdef DEBUG
printf("==> tar_append_file(TAR=0x%lx (\"%s\"), realname=\"%s\", "
@@ -126,34 +126,39 @@ tar_append_file(TAR *t, const char *real
}
else
{
+ const char *name;
#ifdef DEBUG
printf("+++ adding entry: device (0x%lx,0x%lx), inode %ld "
"(\"%s\")...\n", major(s.st_dev), minor(s.st_dev),
s.st_ino, realname);
#endif
- ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t));
+ name = savename ? savename : realname;
+ ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t) + strlen(name) + 1);
if (ti == NULL)
return -1;
ti->ti_ino = s.st_ino;
- snprintf(ti->ti_name, sizeof(ti->ti_name), "%s",
- savename ? savename : realname);
+ snprintf(ti->ti_name, strlen(name) + 1, "%s", name);
libtar_hash_add(td->td_h, ti);
}
/* check if it's a symlink */
if (TH_ISSYM(t))
{
- i = readlink(realname, path, sizeof(path));
+ if ((path = malloc(s.st_size + 1)) == NULL)
+ return -1;
+ i = readlink(realname, path, s.st_size);
if (i == -1)
+ {
+ free(path);
return -1;
- if (i >= MAXPATHLEN)
- i = MAXPATHLEN - 1;
+ }
path[i] = '\0';
#ifdef DEBUG
printf(" tar_append_file(): encoding symlink \"%s\" -> "
"\"%s\"...\n", realname, path);
#endif
th_set_link(t, path);
+ free(path);
}
/* print file info */
--- a/lib/decode.c
+++ b/lib/decode.c
@@ -33,7 +33,8 @@ th_get_pathname(TAR *t)
/* allocate the th_pathname buffer if not already */
if (t->th_pathname == NULL)
{
- t->th_pathname = malloc(MAXPATHLEN * sizeof(char));
+ /* Allocate the maximum length of prefix + '/' + name + '\0' */
+ t->th_pathname = malloc(155 + 1 + 100 + 1);
if (t->th_pathname == NULL)
/* out of memory */
return NULL;
@@ -41,11 +42,11 @@ th_get_pathname(TAR *t)
if (t->th_buf.prefix[0] == '\0')
{
- snprintf(t->th_pathname, MAXPATHLEN, "%.100s", t->th_buf.name);
+ sprintf(t->th_pathname, "%.100s", t->th_buf.name);
}
else
{
- snprintf(t->th_pathname, MAXPATHLEN, "%.155s/%.100s",
+ sprintf(t->th_pathname, "%.155s/%.100s",
t->th_buf.prefix, t->th_buf.name);
}
--- a/lib/util.c
+++ b/lib/util.c
@@ -15,6 +15,7 @@
#include <stdio.h>
#include <sys/param.h>
#include <errno.h>
+#include <stdlib.h>
#ifdef STDC_HEADERS
# include <string.h>
@@ -25,13 +26,15 @@
int
path_hashfunc(char *key, int numbuckets)
{
- char buf[MAXPATHLEN];
+ char *buf;
char *p;
+ int i;
- strcpy(buf, key);
+ buf = strdup(key);
p = basename(buf);
-
- return (((unsigned int)p[0]) % numbuckets);
+ i = ((unsigned int)p[0]) % numbuckets;
+ free(buf);
+ return (i);
}
@@ -77,15 +80,26 @@ ino_hash(ino_t *inode)
int
mkdirhier(char *path)
{
- char src[MAXPATHLEN], dst[MAXPATHLEN] = "";
- char *dirp, *nextp = src;
- int retval = 1;
+ char *src, *dst = NULL;
+ char *dirp, *nextp = NULL;
+ int retval = 1, len;
+
+ len = strlen(path);
+ if ((src = strdup(path)) == NULL)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+ nextp = src;
- if (strlcpy(src, path, sizeof(src)) > sizeof(src))
+ /* Make room for // with absolute paths */
+ if ((dst = malloc(len + 2)) == NULL)
{
- errno = ENAMETOOLONG;
+ free(src);
+ errno = ENOMEM;
return -1;
}
+ dst[0] = '\0';
if (path[0] == '/')
strcpy(dst, "/");
@@ -102,12 +116,18 @@ mkdirhier(char *path)
if (mkdir(dst, 0777) == -1)
{
if (errno != EEXIST)
+ {
+ free(src);
+ free(dst);
return -1;
+ }
}
else
retval = 0;
}
+ free(src);
+ free(dst);
return retval;
}
--- a/lib/wrapper.c
+++ b/lib/wrapper.c
@@ -16,6 +16,7 @@
#include <sys/param.h>
#include <dirent.h>
#include <errno.h>
+#include <stdlib.h>
#ifdef STDC_HEADERS
# include <string.h>
@@ -26,8 +27,8 @@ int
tar_extract_glob(TAR *t, char *globname, char *prefix)
{
char *filename;
- char buf[MAXPATHLEN];
- int i;
+ char *buf = NULL;
+ int i, len;
while ((i = th_read(t)) == 0)
{
@@ -41,11 +42,25 @@ tar_extract_glob(TAR *t, char *globname,
if (t->options & TAR_VERBOSE)
th_print_long_ls(t);
if (prefix != NULL)
- snprintf(buf, sizeof(buf), "%s/%s", prefix, filename);
+ {
+ len = strlen(prefix) + 1 + strlen(filename);
+ if ((buf = malloc(len + 1)) == NULL)
+ return -1;
+ sprintf(buf, "%s/%s", prefix, filename);
+ }
else
- strlcpy(buf, filename, sizeof(buf));
+ {
+ len = strlen(filename);
+ if ((buf = malloc(len + 1)) == NULL)
+ return -1;
+ strcpy(buf, filename);
+ }
if (tar_extract_file(t, buf) != 0)
+ {
+ free(buf);
return -1;
+ }
+ free(buf);
}
return (i == 1 ? 0 : -1);
@@ -56,8 +71,9 @@ int
tar_extract_all(TAR *t, char *prefix)
{
char *filename;
- char buf[MAXPATHLEN];
- int i;
+ char *buf = NULL;
+ size_t bufsize = 0;
+ int i, len;
#ifdef DEBUG
printf("==> tar_extract_all(TAR *t, \"%s\")\n",
@@ -73,15 +89,29 @@ tar_extract_all(TAR *t, char *prefix)
if (t->options & TAR_VERBOSE)
th_print_long_ls(t);
if (prefix != NULL)
- snprintf(buf, sizeof(buf), "%s/%s", prefix, filename);
+ {
+ len = strlen(prefix) + 1 + strlen(filename);
+ if ((buf = malloc(len + 1)) == NULL)
+ return -1;
+ sprintf(buf, "%s/%s", prefix, filename);
+ }
else
- strlcpy(buf, filename, sizeof(buf));
+ {
+ len = strlen(filename);
+ if ((buf = malloc(len + 1)) == NULL)
+ return -1;
+ strcpy(buf, filename);
+ }
#ifdef DEBUG
printf(" tar_extract_all(): calling tar_extract_file(t, "
"\"%s\")\n", buf);
#endif
if (tar_extract_file(t, buf) != 0)
+ {
+ free(buf);
return -1;
+ }
+ free(buf);
}
return (i == 1 ? 0 : -1);
@@ -91,11 +121,14 @@ tar_extract_all(TAR *t, char *prefix)
int
tar_append_tree(TAR *t, char *realdir, char *savedir)
{
- char realpath[MAXPATHLEN];
- char savepath[MAXPATHLEN];
+ char *realpath = NULL;
+ size_t realpathsize = 0;
+ char *savepath = NULL;
+ size_t savepathsize = 0;
struct dirent *dent;
DIR *dp;
struct stat s;
+ int len;
#ifdef DEBUG
printf("==> tar_append_tree(0x%lx, \"%s\", \"%s\")\n",
@@ -122,11 +155,21 @@ tar_append_tree(TAR *t, char *realdir, c
strcmp(dent->d_name, "..") == 0)
continue;
- snprintf(realpath, MAXPATHLEN, "%s/%s", realdir,
+ len = strlen(realdir) + 1 + strlen(dent->d_name);
+ if ((realpath = malloc(len + 1)) == NULL)
+ return -1;
+ snprintf(realpath, len + 1, "%s/%s", realdir,
dent->d_name);
if (savedir)
- snprintf(savepath, MAXPATHLEN, "%s/%s", savedir,
+ {
+ len = strlen(savedir) + 1 + strlen(dent->d_name);
+ if ((savepath = malloc(len + 1)) == NULL) {
+ free(realpath);
+ return -1;
+ }
+ snprintf(savepath, len + 1, "%s/%s", savedir,
dent->d_name);
+ }
if (lstat(realpath, &s) != 0)
return -1;
@@ -135,13 +178,23 @@ tar_append_tree(TAR *t, char *realdir, c
{
if (tar_append_tree(t, realpath,
(savedir ? savepath : NULL)) != 0)
+ {
+ free(realpath);
+ free(savepath);
return -1;
+ }
continue;
}
if (tar_append_file(t, realpath,
(savedir ? savepath : NULL)) != 0)
+ {
+ free(realpath);
+ free(savepath);
return -1;
+ }
+ free(realpath);
+ free(savepath);
}
closedir(dp);
--- a/libtar/libtar.c
+++ b/libtar/libtar.c
@@ -111,8 +111,9 @@ create(char *tarfile, char *rootdir, lib
{
TAR *t;
char *pathname;
- char buf[MAXPATHLEN];
+ char *buf = NULL;
libtar_listptr_t lp;
+ int len;
if (tar_open(&t, tarfile,
#ifdef HAVE_LIBZ
@@ -133,17 +134,29 @@ create(char *tarfile, char *rootdir, lib
{
pathname = (char *)libtar_listptr_data(&lp);
if (pathname[0] != '/' && rootdir != NULL)
- snprintf(buf, sizeof(buf), "%s/%s", rootdir, pathname);
+ {
+ len = strlen(rootdir) + 1 + strlen(pathname);
+ if ((buf = malloc(len + 1)) == NULL)
+ return -1;
+ snprintf(buf, len + 1, "%s/%s", rootdir, pathname);
+ }
else
- strlcpy(buf, pathname, sizeof(buf));
+ {
+ len = strlen(pathname);
+ if ((buf = malloc(len + 1)) == NULL)
+ return -1;
+ strlcpy(buf, pathname, len + 1);
+ }
if (tar_append_tree(t, buf, pathname) != 0)
{
fprintf(stderr,
"tar_append_tree(\"%s\", \"%s\"): %s\n", buf,
pathname, strerror(errno));
tar_close(t);
+ free(buf);
return -1;
}
+ free(buf);
}
if (tar_append_eof(t) != 0)
/tags/1.2.20-3/debian/patches/no_static_buffers.patch
0,0 → 1,82
From: Kamil Dudka <kdudka@redhat.com>
Date: Wed, 23 Oct 2013 13:04:22 +0000 (+0200)
Origin: http://repo.or.cz/w/libtar.git/commitdiff/ec613af2e9371d7a3e1f7c7a6822164a4255b4d1
Subject: decode: avoid using a static buffer in th_get_pathname()
 
decode: avoid using a static buffer in th_get_pathname()
 
A solution suggested by Chris Frey:
https://lists.feep.net:8080/pipermail/libtar/2013-October/000377.html
 
Note this can break programs that expect sizeof(TAR) to be fixed.
 
--- a/lib/decode.c
+++ b/lib/decode.c
@@ -13,6 +13,7 @@
#include <internal.h>
#include <stdio.h>
+#include <stdlib.h>
#include <sys/param.h>
#include <pwd.h>
#include <grp.h>
@@ -26,20 +27,30 @@
char *
th_get_pathname(TAR *t)
{
- static TLS_THREAD char filename[MAXPATHLEN];
-
if (t->th_buf.gnu_longname)
return t->th_buf.gnu_longname;
- if (t->th_buf.prefix[0] != '\0')
+ /* allocate the th_pathname buffer if not already */
+ if (t->th_pathname == NULL)
+ {
+ t->th_pathname = malloc(MAXPATHLEN * sizeof(char));
+ if (t->th_pathname == NULL)
+ /* out of memory */
+ return NULL;
+ }
+
+ if (t->th_buf.prefix[0] == '\0')
+ {
+ snprintf(t->th_pathname, MAXPATHLEN, "%.100s", t->th_buf.name);
+ }
+ else
{
- snprintf(filename, sizeof(filename), "%.155s/%.100s",
+ snprintf(t->th_pathname, MAXPATHLEN, "%.155s/%.100s",
t->th_buf.prefix, t->th_buf.name);
- return filename;
}
- snprintf(filename, sizeof(filename), "%.100s", t->th_buf.name);
- return filename;
+ /* will be deallocated in tar_close() */
+ return t->th_pathname;
}
--- a/lib/handle.c
+++ b/lib/handle.c
@@ -121,6 +121,7 @@ tar_close(TAR *t)
libtar_hash_free(t->h, ((t->oflags & O_ACCMODE) == O_RDONLY
? free
: (libtar_freefunc_t)tar_dev_free));
+ free(t->th_pathname);
free(t);
return i;
--- a/lib/libtar.h
+++ b/lib/libtar.h
@@ -85,6 +85,9 @@ typedef struct
int options;
struct tar_header th_buf;
libtar_hash_t *h;
+
+ /* introduced in libtar 1.2.21 */
+ char *th_pathname;
}
TAR;
/tags/1.2.20-3/debian/patches/series
0,0 → 1,4
no_static_buffers.patch
no_maxpathlen.patch
CVE-2013-4420.patch
th_get_size-unsigned-int.patch
/tags/1.2.20-3/debian/patches/th_get_size-unsigned-int.patch
0,0 → 1,52
Origin: http://repo.or.cz/w/libtar.git/commitdiff/e4c1f2974258d6a325622cfd712873d49b5e7a73
From: Chris Frey <cdfrey@foursquare.net>
Date: Thu, 24 Oct 2013 18:52:44 -0400
Subject: [PATCH] Change th_get_size() macro to return unsigned int
 
On systems where size_t is larger than an int (and larger than
unsigned int), then in various places in the library, where
stuff like this happens:
 
size_t sz = th_get_size(t);
 
then the int value returned from th_get_size() is sign extended to
some unwieldy amount.
 
On 64bit systems, this can yield extremely large values.
 
By fixing this problem in the header, and only for th_get_size(),
we avoid breaking the API of the function call oct_to_int()
(which arguably should return an unsigned int, since the sscanf()
it uses expects to yield an unsigned int). We also fix the library,
which uses th_get_size() internally to assign sizes to size_t.
 
The drawback is that not all client code that uses th_get_size()
will be fixed, until they recompile, but they will automatically
take advantage of the bugs fixed *inside* the library.
 
The remaining th_get_*() functions operate on modes and CRC values
and the like, and should be fine, remaining as ints.
 
Thanks very much to Magnus Holmgren for catching this behaviour.
https://lists.feep.net:8080/pipermail/libtar/2013-October/000365.html
---
lib/libtar.h | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
 
diff --git a/lib/libtar.h b/lib/libtar.h
index 2fefee0..13bb82d 100644
--- a/lib/libtar.h
+++ b/lib/libtar.h
@@ -185,7 +185,11 @@ int th_write(TAR *t);
/* decode tar header info */
#define th_get_crc(t) oct_to_int((t)->th_buf.chksum)
-#define th_get_size(t) oct_to_int((t)->th_buf.size)
+/* We cast from int (what oct_to_int() returns) to
+ unsigned int, to avoid unwieldy sign extensions
+ from occurring on systems where size_t is bigger than int,
+ since th_get_size() is often stored into a size_t. */
+#define th_get_size(t) ((unsigned int)oct_to_int((t)->th_buf.size))
#define th_get_mtime(t) oct_to_int((t)->th_buf.mtime)
#define th_get_devmajor(t) oct_to_int((t)->th_buf.devmajor)
#define th_get_devminor(t) oct_to_int((t)->th_buf.devminor)