summaryrefslogtreecommitdiff
blob: 01fbc53ec26cb717930e468d9a198e4dab311e19 (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
Fix directory traversals issues.

Since .dz files normally just have relative directory trees:
pak/
pak/file
pak/subdir/file

we strip out all the components which ascend in the directory tree

http://bugs.gentoo.org/93079

--- a/main.c
+++ b/main.c
@@ -77,6 +77,48 @@ int dzRead (int inlen)
 	return 1;
 }
 
+#define IS_SEP(c) (c == '/' || c == ':' || c == '\\')
+void scrub_name(char *smee)
+{
+	char *paths[] = { "../", "..\\", "..:", NULL};
+	size_t p, i, len;
+	char scrubit, scrubbed;
+
+	scrubbed = 0;
+	len = strlen(smee);
+	i = 0;
+	scrubit = 1;
+
+	/* search the path and scrub out all relative paths */
+	while (i + 3 < len) {
+		for (p = 0; paths[p]; ++p) {
+			if (scrubit && !strncmp(paths[p], smee+i, 3)) {
+				scrubbed = 1;
+				memset(smee+i, '\0', 3);
+				i += 2;
+				break;
+			}
+		}
+		scrubit = IS_SEP(smee[i]) || smee[i] == '\0';
+		++i;
+	}
+
+	if (!scrubbed)
+		return;
+
+	/* condense the string over all the scrubbed bits */
+	p = 0;
+	for (i = 0; i < len; ++i) {
+		while (p < len && smee[p] == '\0')
+			++p;
+		if (p == len) {
+			smee[i] = '\0';
+			break;
+		}
+		smee[i] = smee[p++];
+	}
+}
+
 int dzReadDirectoryEntry (direntry_t *de)
 {
 	char *s;
@@ -102,6 +144,7 @@ int dzReadDirectoryEntry (direntry_t *de
 	s = Dzip_malloc(de->len);
 	dzFile_Read(s, de->len);
 	de->name = s;
+	scrub_name(de->name);
 	if (de->pak && de->type != TYPE_PAK)
 		return 1;	/* dont mess with dirchar inside pakfiles */
 	do
--- a/v1code.c
+++ b/v1code.c
@@ -201,6 +201,7 @@ void demv1_dxentities(void)
 
 }
 
+extern void scrub_name(char *smee);
 void dzUncompressV1 (int testing)
 {
 	int i, inlen = 0;
@@ -221,6 +222,7 @@ void dzUncompressV1 (int testing)
 	{
 		de = directory + i;
 		crcval = INITCRC;
+		scrub_name(de->name);
 		printf("%s %s",action,de->name);
 		fflush(stdout);