diff options
| author | Tim Kientzle <kientzle@FreeBSD.org> | 2007-08-25 04:33:13 +0000 |
|---|---|---|
| committer | Tim Kientzle <kientzle@FreeBSD.org> | 2007-08-25 04:33:13 +0000 |
| commit | cb43e1fdfee1d975ace60eecc3370a1a7e4cd833 (patch) | |
| tree | 912fe15c51f53acccd57458b706196e512429c20 /usr.bin/tar | |
| parent | 82403d924700bd6fb2657f69bb1b79521c272210 (diff) | |
Notes
Diffstat (limited to 'usr.bin/tar')
| -rw-r--r-- | usr.bin/tar/bsdtar.c | 9 | ||||
| -rw-r--r-- | usr.bin/tar/read.c | 137 |
2 files changed, 9 insertions, 137 deletions
diff --git a/usr.bin/tar/bsdtar.c b/usr.bin/tar/bsdtar.c index d2e5cc6973ff..faec8ec8b0de 100644 --- a/usr.bin/tar/bsdtar.c +++ b/usr.bin/tar/bsdtar.c @@ -210,6 +210,11 @@ static const struct option tar_longopts[] = { { NULL, 0, NULL, 0 } }; +/* A basic set of security flags to request from libarchive. */ +#define SECURITY \ + (ARCHIVE_EXTRACT_SECURE_SYMLINKS \ + | ARCHIVE_EXTRACT_SECURE_NODOTDOT) + int main(int argc, char **argv) { @@ -258,6 +263,9 @@ main(int argc, char **argv) /* Default: preserve mod time on extract */ bsdtar->extract_flags = ARCHIVE_EXTRACT_TIME; + /* Default: Perform basic security checks. */ + bsdtar->extract_flags |= SECURITY; + /* Defaults for root user: */ if (bsdtar->user_uid == 0) { /* --same-owner */ @@ -461,6 +469,7 @@ main(int argc, char **argv) break; #endif case 'P': /* GNU tar */ + bsdtar->extract_flags &= ~SECURITY; bsdtar->option_absolute_paths = 1; break; case 'p': /* GNU tar, star */ diff --git a/usr.bin/tar/read.c b/usr.bin/tar/read.c index 59899aeefdec..b0c5d2c8edea 100644 --- a/usr.bin/tar/read.c +++ b/usr.bin/tar/read.c @@ -69,11 +69,9 @@ __FBSDID("$FreeBSD$"); #include "bsdtar.h" -static void cleanup_security(struct bsdtar *); static void list_item_verbose(struct bsdtar *, FILE *, struct archive_entry *); static void read_archive(struct bsdtar *bsdtar, char mode); -static int security_problem(struct bsdtar *, struct archive_entry *); void tar_mode_t(struct bsdtar *bsdtar) @@ -216,15 +214,6 @@ read_archive(struct bsdtar *bsdtar, char mode) } fprintf(out, "\n"); } else { - /* - * Skip security problems before prompting. - * Otherwise, the user may be confused that a - * file they wanted to extract was - * subsequently skipped. - */ - if (security_problem(bsdtar, entry)) - continue; - if (bsdtar->option_interactive && !yes("extract '%s'", archive_entry_pathname(entry))) continue; @@ -265,7 +254,6 @@ read_archive(struct bsdtar *bsdtar, char mode) archive_format_name(a), archive_compression_name(a)); archive_read_finish(a); - cleanup_security(bsdtar); } @@ -367,128 +355,3 @@ list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry) else if (S_ISLNK(st->st_mode)) /* Symbolic link */ safe_fprintf(out, " -> %s", archive_entry_symlink(entry)); } - -/* - * Structure for storing path of last successful security check. - */ -struct security { - char *path; - size_t path_size; -}; - -/* - * Check for a variety of security issues. Fix what we can here, - * generate warnings as appropriate, return non-zero to prevent - * this entry from being extracted. - */ -static int -security_problem(struct bsdtar *bsdtar, struct archive_entry *entry) -{ - struct stat st; - const char *name, *pn; - char *p; - int r; - - /* -P option forces us to just accept all pathnames as-is. */ - if (bsdtar->option_absolute_paths) - return (0); - - name = archive_entry_pathname(entry); - - /* Reject any archive entry with '..' as a path element. */ - pn = name; - while (pn != NULL && pn[0] != '\0') { - if (pn[0] == '.' && pn[1] == '.' && - (pn[2] == '\0' || pn[2] == '/')) { - bsdtar_warnc(bsdtar, 0, - "Skipping pathname containing .."); - bsdtar->return_value = 1; - return (1); - } - pn = strchr(pn, '/'); - if (pn != NULL) - pn++; - } - - /* - * Gaurd against symlink tricks. Reject any archive entry whose - * destination would be altered by a symlink. - */ - /* XXX TODO: Make this faster by comparing current path to - * prefix of last successful check to avoid duplicate lstat() - * calls. XXX */ - pn = name; - if (bsdtar->security == NULL) { - bsdtar->security = malloc(sizeof(*bsdtar->security)); - if (bsdtar->security == NULL) - bsdtar_errc(bsdtar, 1, errno, "No Memory"); - bsdtar->security->path_size = MAXPATHLEN + 1; - bsdtar->security->path = malloc(bsdtar->security->path_size); - if (bsdtar->security->path == NULL) - bsdtar_errc(bsdtar, 1, errno, "No Memory"); - } - if (strlen(name) >= bsdtar->security->path_size) { - free(bsdtar->security->path); - while (strlen(name) >= bsdtar->security->path_size) - bsdtar->security->path_size *= 2; - bsdtar->security->path = malloc(bsdtar->security->path_size); - if (bsdtar->security->path == NULL) - bsdtar_errc(bsdtar, 1, errno, "No Memory"); - } - p = bsdtar->security->path; - while (pn != NULL && pn[0] != '\0') { - *p++ = *pn++; - while (*pn != '\0' && *pn != '/') - *p++ = *pn++; - p[0] = '\0'; - r = lstat(bsdtar->security->path, &st); - if (r != 0) { - if (errno == ENOENT) - break; - } else if (S_ISLNK(st.st_mode)) { - if (pn[0] == '\0') { - /* - * Last element is symlink; remove it - * so we can overwrite it with the - * item being extracted. - */ - if (!S_ISLNK(archive_entry_mode(entry))) { - /* - * Warn only if the symlink is being - * replaced with a non-symlink. - */ - bsdtar_warnc(bsdtar, 0, - "Removing symlink %s", - bsdtar->security->path); - } - if (unlink(bsdtar->security->path)) - bsdtar_errc(bsdtar, 1, errno, - "Unlink failed"); - /* Symlink gone. No more problem! */ - return (0); - } else if (bsdtar->option_unlink_first) { - /* User asked us to remove problems. */ - if (unlink(bsdtar->security->path)) - bsdtar_errc(bsdtar, 1, errno, - "Unlink failed"); - } else { - bsdtar_warnc(bsdtar, 0, - "Cannot extract %s through symlink %s", - name, bsdtar->security->path); - bsdtar->return_value = 1; - return (1); - } - } - } - - return (0); -} - -static void -cleanup_security(struct bsdtar *bsdtar) -{ - if (bsdtar->security != NULL) { - free(bsdtar->security->path); - free(bsdtar->security); - } -} |
