|
|
The following patches fix two security bugs: |
|
|
1. buffer overflows (CAN-2004-0234) |
|
|
2. directory traversal problems (CAN-2004-0235) |
|
|
3. symlink vulnerability |
|
|
|
|
|
--- src/header.c.orig 2000-10-05 19:36:03.000000000 +0200 |
|
|
+++ src/header.c 2004-04-21 14:30:52.000000000 +0200 |
|
|
@@ -538,6 +538,10 @@ |
|
|
/* |
|
|
* filename |
|
|
*/ |
|
|
+ if (header_size >= 256) { |
|
|
+ fprintf(stderr, "Possible buffer overflow hack attack, type #1\n"); |
|
|
+ exit(109); |
|
|
+ } |
|
|
for (i = 0; i < header_size - 3; i++) |
|
|
hdr->name[i] = (char) get_byte(); |
|
|
hdr->name[header_size - 3] = '\0'; |
|
|
@@ -547,6 +551,10 @@ |
|
|
/* |
|
|
* directory |
|
|
*/ |
|
|
+ if (header_size >= FILENAME_LENGTH) { |
|
|
+ fprintf(stderr, "Possible buffer overflow hack attack, type #2\n"); |
|
|
+ exit(110); |
|
|
+ } |
|
|
for (i = 0; i < header_size - 3; i++) |
|
|
dirname[i] = (char) get_byte(); |
|
|
dirname[header_size - 3] = '\0'; |
|
|
--- src/lhext.c.orig 2000-10-04 16:57:38.000000000 +0200 |
|
|
+++ src/lhext.c 2004-04-21 14:30:52.000000000 +0200 |
|
|
@@ -190,8 +190,13 @@ |
|
|
q = (char *) rindex(hdr->name, '/') + 1; |
|
|
} |
|
|
else { |
|
|
+ if (is_directory_traversal(q)) { |
|
|
+ fprintf(stderr, "Possible directory traversal hack attempt in %s\n", q); |
|
|
+ exit(111); |
|
|
+ } |
|
|
+ |
|
|
if (*q == '/') { |
|
|
- q++; |
|
|
+ while (*q == '/') { q++; } |
|
|
/* |
|
|
* if OSK then strip device name |
|
|
*/ |
|
|
@@ -419,6 +424,33 @@ |
|
|
return; |
|
|
} |
|
|
|
|
|
+int |
|
|
+is_directory_traversal(char *string) |
|
|
+{ |
|
|
+ unsigned int type = 0; /* 0 = new, 1 = only dots, 2 = other chars than dots */ |
|
|
+ char *temp; |
|
|
+ |
|
|
+ temp = string; |
|
|
+ |
|
|
+ while (*temp != 0) { |
|
|
+ if (temp[0] == '/') { |
|
|
+ if (type == 1) { return 1; } |
|
|
+ type = 0; |
|
|
+ temp++; |
|
|
+ continue; |
|
|
+ } |
|
|
+ |
|
|
+ if ((temp[0] == '.') && (type < 2)) |
|
|
+ type = 1; |
|
|
+ if (temp[0] != '.') |
|
|
+ type = 2; |
|
|
+ |
|
|
+ temp++; |
|
|
+ } /* while */ |
|
|
+ |
|
|
+ return (type == 1); |
|
|
+} |
|
|
+ |
|
|
/* Local Variables: */ |
|
|
/* mode:c */ |
|
|
/* tab-width:4 */ |
|
|
--- src/lhext.c.symlink 2000-10-04 10:57:38.000000000 -0400 |
|
|
+++ src/lhext.c 2003-05-19 22:55:57.000000000 -0400 |
|
|
@@ -351,6 +351,7 @@ extract_one(afp, hdr) |
|
|
} |
|
|
|
|
|
unlink(bb1); |
|
|
+ make_parent_path(bb1); |
|
|
l_code = symlink(bb2, bb1); |
|
|
if (l_code < 0) { |
|
|
if (quiet != TRUE) |
|
|
################################################################ |
|
|
The following patches are fixing the following Security bugs: |
|
|
Fixed multiple vulnerabilities; bug #62618 from GenToo |
|
|
Gentoo Linux Security Advisory GLSA 200409-13 |
|
|
CAN-2004-0694, CAN-2004-0745, CAN-2004-0769, CAN-2004-0771 |
|
|
################################################################ |
|
|
Index: src/lha.h |
|
|
--- src/lha.h.orig 2000-10-05 19:35:38 +0200 |
|
|
+++ src/lha.h 2004-09-20 14:59:52 +0200 |
|
|
@@ -16,6 +16,7 @@ |
|
|
#include <sys/types.h> |
|
|
#include <sys/file.h> |
|
|
#include <sys/stat.h> |
|
|
+#include <stdlib.h> |
|
|
|
|
|
#include <signal.h> |
|
|
|
|
|
Index: src/lha_macro.h |
|
|
--- src/lha_macro.h.orig 2000-10-04 16:57:38 +0200 |
|
|
+++ src/lha_macro.h 2004-09-20 14:59:52 +0200 |
|
|
@@ -53,7 +53,7 @@ |
|
|
#define SEEK_SET 0 |
|
|
#define SEEK_CUR 1 |
|
|
#define SEEK_END 2 |
|
|
-#endif /* SEEK_SET |
|
|
+#endif /* SEEK_SET */ |
|
|
|
|
|
|
|
|
/* non-integral functions */ |
|
|
Index: src/lharc.c |
|
|
--- src/lharc.c.orig 2000-10-05 19:33:34 +0200 |
|
|
+++ src/lharc.c 2004-09-20 14:59:52 +0200 |
|
|
@@ -830,9 +830,10 @@ |
|
|
DIRENTRY *dp; |
|
|
struct stat tmp_stbuf, arc_stbuf, fil_stbuf; |
|
|
|
|
|
- strcpy(newname, name); |
|
|
+ strncpy(newname, name, sizeof(newname)); |
|
|
+ newname[sizeof(newname)-1] = 0; |
|
|
len = strlen(name); |
|
|
- if (len > 0 && newname[len - 1] != '/') |
|
|
+ if (len > 0 && newname[len - 1] != '/' && len < (sizeof(newname)-1)) |
|
|
newname[len++] = '/'; |
|
|
|
|
|
dirp = opendir(name); |
|
|
@@ -846,6 +847,11 @@ |
|
|
|
|
|
for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { |
|
|
n = NAMLEN(dp); |
|
|
+ if (len >= (sizeof(newname)-1) || |
|
|
+ (len+n) >= (sizeof(newname)-1) || |
|
|
+ n <= 0 || |
|
|
+ (len+n) <= 0) |
|
|
+ break; |
|
|
strncpy(newname + len, dp->d_name, n); |
|
|
newname[len + n] = '\0'; |
|
|
if (GETSTAT(newname, &fil_stbuf) < 0) |
|
|
@@ -903,7 +909,8 @@ |
|
|
strcpy(temporary_name, TMP_FILENAME_TEMPLATE); |
|
|
} |
|
|
else { |
|
|
- sprintf(temporary_name, "%s/lhXXXXXX", extract_directory); |
|
|
+ snprintf(temporary_name, sizeof(temporary_name), |
|
|
+ "%s/lhXXXXXX", extract_directory); |
|
|
} |
|
|
#ifdef MKSTEMP |
|
|
mkstemp(temporary_name); |
|
|
@@ -913,10 +920,16 @@ |
|
|
#else |
|
|
char *p, *s; |
|
|
|
|
|
- strcpy(temporary_name, archive_name); |
|
|
+ strncpy(temporary_name, archive_name, sizeof(temporary_name)); |
|
|
+ temporary_name[sizeof(temporary_name)-1] = 0; |
|
|
for (p = temporary_name, s = (char *) 0; *p; p++) |
|
|
if (*p == '/') |
|
|
s = p; |
|
|
+ |
|
|
+ if( sizeof(temporary_name) - ((size_t) (s-temporary_name)) - 1 |
|
|
+ <= strlen("lhXXXXXX")) |
|
|
+ exit(-1); |
|
|
+ |
|
|
strcpy((s ? s + 1 : temporary_name), "lhXXXXXX"); |
|
|
#ifdef MKSTEMP |
|
|
mkstemp(temporary_name); |
|
|
@@ -1052,7 +1065,8 @@ |
|
|
|
|
|
if (open_old_archive_1(archive_name, &fp)) |
|
|
return fp; |
|
|
- sprintf(expanded_archive_name, "%s.lzh", archive_name); |
|
|
+ snprintf(expanded_archive_name, sizeof(expanded_archive_name), |
|
|
+ "%s.lzh", archive_name); |
|
|
if (open_old_archive_1(expanded_archive_name, &fp)) { |
|
|
archive_name = expanded_archive_name; |
|
|
return fp; |
|
|
@@ -1061,7 +1075,8 @@ |
|
|
* if ( (errno&0xffff)!=E_PNNF ) { archive_name = |
|
|
* expanded_archive_name; return NULL; } |
|
|
*/ |
|
|
- sprintf(expanded_archive_name, "%s.lzs", archive_name); |
|
|
+ snprintf(expanded_archive_name, sizeof(expanded_archive_name), |
|
|
+ "%s.lzs", archive_name); |
|
|
if (open_old_archive_1(expanded_archive_name, &fp)) { |
|
|
archive_name = expanded_archive_name; |
|
|
return fp; |
|
|
Index: src/lhext.c |
|
|
--- src/lhext.c.orig 2004-09-20 14:59:52 +0200 |
|
|
+++ src/lhext.c 2004-09-20 14:59:52 +0200 |
|
|
@@ -82,7 +82,8 @@ |
|
|
register char *p; |
|
|
|
|
|
/* make parent directory name into PATH for recursive call */ |
|
|
- strcpy(path, name); |
|
|
+ memset(path, 0, sizeof(path)); |
|
|
+ strncpy(path, name, sizeof(path)-1); |
|
|
for (p = path + strlen(path); p > path; p--) |
|
|
if (p[-1] == '/') { |
|
|
*--p = '\0'; |
|
|
@@ -212,9 +213,11 @@ |
|
|
} |
|
|
|
|
|
if (extract_directory) |
|
|
- sprintf(name, "%s/%s", extract_directory, q); |
|
|
- else |
|
|
- strcpy(name, q); |
|
|
+ snprintf(name, sizeof(name), "%s/%s", extract_directory, q); |
|
|
+ else { |
|
|
+ strncpy(name, q, sizeof(name)); |
|
|
+ name[sizeof(name) - 1] = '\0'; |
|
|
+ } |
|
|
|
|
|
|
|
|
/* LZHDIRS_METHOD<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĥإå<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>å<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */ |
|
|
@@ -335,7 +338,8 @@ |
|
|
if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK) { |
|
|
char buf[256], *bb1, *bb2; |
|
|
int l_code; |
|
|
- strcpy(buf, name); |
|
|
+ strncpy(buf, name, sizeof(buf)); |
|
|
+ buf[sizeof(buf)-1] = 0; |
|
|
bb1 = strtok(buf, "|"); |
|
|
bb2 = strtok(NULL, "|"); |
|
|
|
|
|
@@ -365,9 +369,10 @@ |
|
|
if (quiet != TRUE) { |
|
|
printf("Symbolic Link %s -> %s\n", bb1, bb2); |
|
|
} |
|
|
- strcpy(name, bb1); /* Symbolic's name set */ |
|
|
+ strncpy(name, bb1, 255); /* Symbolic's name set */ |
|
|
+ name[255] = 0; |
|
|
#else |
|
|
- sprintf(buf, "%s -> %s", bb1, bb2); |
|
|
+ sprintf(buf, sizeof(buf), "%s -> %s", bb1, bb2); |
|
|
warning("Can't make Symbolic Link", buf); |
|
|
return; |
|
|
#endif |
|
|
Index: src/lhlist.c |
|
|
--- src/lhlist.c.orig 2000-10-04 16:57:38 +0200 |
|
|
+++ src/lhlist.c 2004-09-20 14:59:52 +0200 |
|
|
@@ -250,7 +250,8 @@ |
|
|
printf(" %s", hdr->name); |
|
|
else { |
|
|
char buf[256], *b1, *b2; |
|
|
- strcpy(buf, hdr->name); |
|
|
+ strncpy(buf, hdr->name, sizeof(buf)); |
|
|
+ buf[sizeof(buf)-1] = 0; |
|
|
b1 = strtok(buf, "|"); |
|
|
b2 = strtok(NULL, "|"); |
|
|
printf(" %s -> %s", b1, b2); |
|
|
Index: src/util.c |
|
|
--- src/util.c.orig 2000-10-04 16:57:38 +0200 |
|
|
+++ src/util.c 2004-09-20 14:59:52 +0200 |
|
|
@@ -276,21 +276,27 @@ |
|
|
char *path; |
|
|
{ |
|
|
int stat, rtn = 0; |
|
|
- char *cmdname; |
|
|
- if ((cmdname = (char *) malloc(strlen(RMDIRPATH) + 1 + strlen(path) + 1)) |
|
|
- == 0) |
|
|
+ pid_t child; |
|
|
+ |
|
|
+ |
|
|
+ /* XXX thomas: shell meta chars in path could exec commands */ |
|
|
+ /* therefore we should avoid using system() */ |
|
|
+ if ((child = fork()) < 0) |
|
|
+ return (-1); /* fork error */ |
|
|
+ else if (child) { /* parent process */ |
|
|
+ while (child != wait(&stat)) /* ignore signals */ |
|
|
+ continue; |
|
|
+ } |
|
|
+ else { /* child process */ |
|
|
+ execl(RMDIRPATH, "rmdir", path, (char *) 0); |
|
|
+ /* never come here except execl is error */ |
|
|
return (-1); |
|
|
- strcpy(cmdname, RMDIRPATH); |
|
|
- *(cmdname + strlen(RMDIRPATH)) = ' '; |
|
|
- strcpy(cmdname + strlen(RMDIRPATH) + 1, path); |
|
|
- if ((stat = system(cmdname)) < 0) |
|
|
- rtn = -1; /* fork or exec error */ |
|
|
- else if (stat) { /* RMDIR command error */ |
|
|
- errno = EIO; |
|
|
- rtn = -1; |
|
|
} |
|
|
- free(cmdname); |
|
|
- return (rtn); |
|
|
+ if (stat != 0) { |
|
|
+ errno = EIO; /* cannot get error num. */ |
|
|
+ return (-1); |
|
|
+ } |
|
|
+ return (0); |
|
|
} |
|
|
|
|
|
/* ------------------------------------------------------------------------ */ |
|
|
Index: src/header.c |
|
|
--- src/header.c.orig 2004-09-20 14:59:52 +0200 |
|
|
+++ src/header.c 2004-09-20 14:59:52 +0200 |
|
|
@@ -656,8 +656,17 @@ |
|
|
} |
|
|
|
|
|
if (dir_length) { |
|
|
+ if ((dir_length + name_length) > sizeof(dirname)) { |
|
|
+ fprintf(stderr, "Insufficient buffer size\n"); |
|
|
+ exit(112); |
|
|
+ } |
|
|
strcat(dirname, hdr->name); |
|
|
- strcpy(hdr->name, dirname); |
|
|
+ |
|
|
+ if ((dir_length + name_length) > sizeof(hdr->name)) { |
|
|
+ fprintf(stderr, "Insufficient buffer size\n"); |
|
|
+ exit(112); |
|
|
+ } |
|
|
+ strncpy(hdr->name, dirname, sizeof(hdr->name)); |
|
|
name_length += dir_length; |
|
|
} |
|
|
|
|
|
|