From 83ecd7781ef9028a17cdb24709202983677ba2d3 Mon Sep 17 00:00:00 2001 From: kientzle Date: Wed, 28 Apr 2004 18:53:07 +0000 Subject: Refuse to extract entries with '..' in pathname. Pointed out by: David Schultz --- usr.bin/tar/read.c | 47 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-) (limited to 'usr.bin') diff --git a/usr.bin/tar/read.c b/usr.bin/tar/read.c index 684a7ae..3023ddb 100644 --- a/usr.bin/tar/read.c +++ b/usr.bin/tar/read.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); static void list_item_verbose(struct bsdtar *, 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) @@ -68,7 +69,6 @@ read_archive(struct bsdtar *bsdtar, char mode) struct archive *a; struct archive_entry *entry; int format; - const char *name; int r; while (*bsdtar->argv) { @@ -123,12 +123,6 @@ read_archive(struct bsdtar *bsdtar, char mode) if (excluded(bsdtar, archive_entry_pathname(entry))) continue; - name = archive_entry_pathname(entry); - if (name[0] == '/' && !bsdtar->option_absolute_paths) { - name++; - archive_entry_set_pathname(entry, name); - } - if (mode == 't') { if (bsdtar->verbose < 2) safe_fprintf(stdout, "%s", @@ -156,6 +150,9 @@ read_archive(struct bsdtar *bsdtar, char mode) !yes("extract '%s'", archive_entry_pathname(entry))) continue; + if (security_problem(bsdtar, entry)) + continue; + /* * Format here is from SUSv2, including the * deferred '\n'. @@ -287,3 +284,39 @@ list_item_verbose(struct bsdtar *bsdtar, struct archive_entry *entry) else if (S_ISLNK(st->st_mode)) /* Symbolic link */ safe_fprintf(out, " -> %s", archive_entry_symlink(entry)); } + +/* + * 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. + */ +int +security_problem(struct bsdtar *bsdtar, struct archive_entry *entry) +{ + const char *name, *p; + + /* Strip leading '/' unless -P is specified. */ + name = archive_entry_pathname(entry); + if (name[0] == '/' && !bsdtar->option_absolute_paths) { + /* XXX gtar generates a warning the first time this happens. */ + name++; + archive_entry_set_pathname(entry, name); + } + + /* Reject any archive entry with '..' as a path element. */ + p = name; + while (p != NULL && p[0] != '\0') { + if (p[0] == '.' && p[1] == '.' && + (p[2] == '\0' || p[2] == '/')) { + bsdtar_warnc(0,"pathname contains ..; skipping %s", + name); + return (1); + } + while (*p != '/' && *p != '\0') + p++; + if (*p != '\0') + p++; + } + + return (0); +} -- cgit v1.1