| 1 | Author: Raphael Geissert <[email protected]>
|
| 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 | |
| 8 | |
| 9 | @@ -22,6 +22,36 @@
|
| 10 | #endif
|
| 11 |
|
| 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 | @@ -29,17 +59,17 @@ th_get_pathname(TAR *t)
|
| 47 | static char filename[MAXPATHLEN];
|
| 48 |
|
| 49 | if (t->th_buf.gnu_longname)
|
| 50 | - return t->th_buf.gnu_longname;
|
| 51 | + return safer_name_suffix(t->th_buf.gnu_longname);
|
| 52 |
|
| 53 | if (t->th_buf.prefix[0] != '\0')
|
| 54 | {
|
| 55 | snprintf(filename, sizeof(filename), "%.155s/%.100s",
|
| 56 | t->th_buf.prefix, t->th_buf.name);
|
| 57 | - return filename;
|
| 58 | + return safer_name_suffix(filename);
|
| 59 | }
|
| 60 |
|
| 61 | snprintf(filename, sizeof(filename), "%.100s", t->th_buf.name);
|
| 62 | - return filename;
|
| 63 | + return safer_name_suffix(filename);
|
| 64 | }
|
| 65 |
|
| 66 |
|
| 67 | |
| 68 | |
| 69 | @@ -298,14 +298,14 @@ tar_extract_hardlink(TAR * t, char *real
|
| 70 | if (mkdirhier(dirname(filename)) == -1)
|
| 71 | return -1;
|
| 72 | libtar_hashptr_reset(&hp);
|
| 73 | - if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t),
|
| 74 | + if (libtar_hash_getkey(t->h, &hp, safer_name_suffix(th_get_linkname(t)),
|
| 75 | (libtar_matchfunc_t)libtar_str_match) != 0)
|
| 76 | {
|
| 77 | lnp = (char *)libtar_hashptr_data(&hp);
|
| 78 | linktgt = &lnp[strlen(lnp) + 1];
|
| 79 | }
|
| 80 | else
|
| 81 | - linktgt = th_get_linkname(t);
|
| 82 | + linktgt = safer_name_suffix(th_get_linkname(t));
|
| 83 |
|
| 84 | #ifdef DEBUG
|
| 85 | printf(" ==> extracting: %s (link to %s)\n", filename, linktgt);
|
| 86 | @@ -343,9 +343,9 @@ tar_extract_symlink(TAR *t, char *realna
|
| 87 |
|
| 88 | #ifdef DEBUG
|
| 89 | printf(" ==> extracting: %s (symlink to %s)\n",
|
| 90 | - filename, th_get_linkname(t));
|
| 91 | + filename, safer_name_suffix(th_get_linkname(t)));
|
| 92 | #endif
|
| 93 | - if (symlink(th_get_linkname(t), filename) == -1)
|
| 94 | + if (symlink(safer_name_suffix(th_get_linkname(t)), filename) == -1)
|
| 95 | {
|
| 96 | #ifdef DEBUG
|
| 97 | perror("symlink()");
|
| 98 | |
| 99 | |
| 100 | @@ -15,3 +15,4 @@
|
| 101 |
|
| 102 | #include <libtar.h>
|
| 103 |
|
| 104 | +char* safer_name_suffix(char const*);
|
| 105 | |
| 106 | |
| 107 | @@ -123,9 +123,9 @@ th_print_long_ls(TAR *t)
|
| 108 | else
|
| 109 | printf(" link to ");
|
| 110 | if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL)
|
| 111 | - printf("%s", t->th_buf.gnu_longlink);
|
| 112 | + printf("%s", safer_name_suffix(t->th_buf.gnu_longlink));
|
| 113 | else
|
| 114 | - printf("%.100s", t->th_buf.linkname);
|
| 115 | + printf("%.100s", safer_name_suffix(t->th_buf.linkname));
|
| 116 | }
|
| 117 |
|
| 118 | putchar('\n');
|