Subversion Repositories

?revision_form?Rev ?revision_input??revision_submit??revision_endform?

Rev 24 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
24 magnus 1
Author: Raphael Geissert <geissert@debian.org>
2
Bug-Debian: https://bugs.debian.org/731860
3
Description: Avoid directory traversal when extracting archives
4
 by skipping over leading slashes and any prefix containing ".." components.
5
Forwarded: yes
6
 
7
--- a/lib/decode.c
8
+++ b/lib/decode.c
9
@@ -21,13 +21,42 @@
10
 # include <string.h>
11
 #endif
12
 
13
+char *
14
+safer_name_suffix (char const *file_name)
15
+{
16
+       char const *p, *t;
17
+       p = t = file_name;
18
+       while (*p == '/') t = ++p;
19
+       while (*p)
20
+       {
21
+               while (p[0] == '.' && p[0] == p[1] && p[2] == '/')
22
+               {
23
+                       p += 3;
24
+                       t = p;
25
+               }
26
+               /* advance pointer past the next slash */
27
+               while (*p && (p++)[0] != '/');
28
+       }
29
+
30
+       if (!*t)
31
+       {
32
+               t = ".";
33
+       }
34
+
35
+       if (t != file_name)
36
+       {
37
+               /* TODO: warn somehow that the path was modified */
38
+       }
39
+       return (char*)t;
40
+}
41
+
42
 
43
 /* determine full path name */
44
 char *
45
 th_get_pathname(TAR *t)
46
 {
47
        if (t->th_buf.gnu_longname)
48
-               return t->th_buf.gnu_longname;
49
+               return safer_name_suffix(t->th_buf.gnu_longname);
50
 
31 magnus 51
        /* allocate the th_pathname buffer if not already */
52
        if (t->th_pathname == NULL)
53
@@ -50,7 +79,7 @@ th_get_pathname(TAR *t)
24 magnus 54
        }
55
 
56
        /* will be deallocated in tar_close() */
31 magnus 57
-       return t->th_pathname;
58
+       return safer_name_suffix(t->th_pathname);
59
 }
60
 
61
 
24 magnus 62
--- a/lib/extract.c
63
+++ b/lib/extract.c
64
@@ -298,14 +298,14 @@ tar_extract_hardlink(TAR * t, char *real
65
        if (mkdirhier(dirname(filename)) == -1)
66
                return -1;
67
        libtar_hashptr_reset(&hp);
68
-       if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t),
69
+       if (libtar_hash_getkey(t->h, &hp, safer_name_suffix(th_get_linkname(t)),
70
                               (libtar_matchfunc_t)libtar_str_match) != 0)
71
        {
72
                lnp = (char *)libtar_hashptr_data(&hp);
73
                linktgt = &lnp[strlen(lnp) + 1];
74
        }
75
        else
76
-               linktgt = th_get_linkname(t);
77
+               linktgt = safer_name_suffix(th_get_linkname(t));
78
 
79
 #ifdef DEBUG
80
        printf("  ==> extracting: %s (link to %s)\n", filename, linktgt);
81
@@ -343,9 +343,9 @@ tar_extract_symlink(TAR *t, char *realna
82
 
83
 #ifdef DEBUG
84
        printf("  ==> extracting: %s (symlink to %s)\n",
85
-              filename, th_get_linkname(t));
86
+              filename, safer_name_suffix(th_get_linkname(t)));
87
 #endif
88
-       if (symlink(th_get_linkname(t), filename) == -1)
89
+       if (symlink(safer_name_suffix(th_get_linkname(t)), filename) == -1)
90
        {
91
 #ifdef DEBUG
92
                perror("symlink()");
93
--- a/lib/internal.h
94
+++ b/lib/internal.h
95
@@ -21,3 +21,4 @@
96
 #define TLS_THREAD
97
 #endif
98
 
99
+char* safer_name_suffix(char const*);
31 magnus 100
--- a/lib/output.c
101
+++ b/lib/output.c
102
@@ -123,9 +123,9 @@ th_print_long_ls(TAR *t)
103
                else
104
                        printf(" link to ");
105
                if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL)
106
-                       printf("%s", t->th_buf.gnu_longlink);
107
+                       printf("%s", safer_name_suffix(t->th_buf.gnu_longlink));
108
                else
109
-                       printf("%.100s", t->th_buf.linkname);
110
+                       printf("%.100s", safer_name_suffix(t->th_buf.linkname));
111
        }
112
 
113
        putchar('\n');