From 4a07f42b9832d517da67ece1ade318d4e565ab4f Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Mon, 17 May 2004 03:33:06 +0000 Subject: [PATCH] Make symlink protection a bit more useful: * Remove terminal symlinks so they can be replaced. * If -U, remove intermediate symlinks as well * Otherwise, refuse the extraction --- usr.bin/tar/bsdtar.c | 1 + usr.bin/tar/bsdtar.h | 1 + usr.bin/tar/read.c | 19 +++++++++++++++---- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/usr.bin/tar/bsdtar.c b/usr.bin/tar/bsdtar.c index 344e14cd9bc2..747f009ace19 100644 --- a/usr.bin/tar/bsdtar.c +++ b/usr.bin/tar/bsdtar.c @@ -285,6 +285,7 @@ main(int argc, char **argv) break; case 'U': /* GNU tar */ bsdtar->extract_flags |= ARCHIVE_EXTRACT_UNLINK; + bsdtar->option_unlink_first = 1; break; case 'u': /* SUSv2 */ if (mode != '\0') diff --git a/usr.bin/tar/bsdtar.h b/usr.bin/tar/bsdtar.h index e7416b893012..17eb1e0e65f2 100644 --- a/usr.bin/tar/bsdtar.h +++ b/usr.bin/tar/bsdtar.h @@ -58,6 +58,7 @@ struct bsdtar { char option_interactive; /* -w */ char option_no_subdirs; /* -d */ char option_stdout; /* -p */ + char option_unlink_first; /* -U */ char option_warn_links; /* -l */ /* If >= 0, then close this when done. */ diff --git a/usr.bin/tar/read.c b/usr.bin/tar/read.c index 5765f4cce4da..af1a28e7b759 100644 --- a/usr.bin/tar/read.c +++ b/usr.bin/tar/read.c @@ -335,7 +335,9 @@ security_problem(struct bsdtar *bsdtar, struct archive_entry *entry) * Gaurd against symlink tricks. Reject any archive entry whose * destination would be altered by a symlink. */ - /* XXX TODO: Make this faster!!! XXX */ + /* 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)); @@ -359,9 +361,18 @@ security_problem(struct bsdtar *bsdtar, struct archive_entry *entry) if (errno == ENOENT) break; } else if (S_ISLNK(st.st_mode)) { - bsdtar_warnc(0,"Cannot extract %s through symlink %s", - name, bsdtar->security->path); - return (1); + if (*pn == '\0') { + /* Last element is symlink; just remove it. */ + unlink(bsdtar->security->path); + } else if (bsdtar->option_unlink_first) { + /* User asked us to remove problems. */ + unlink(bsdtar->security->path); + } else { + bsdtar_warnc(0, + "Cannot extract %s through symlink %s", + name, bsdtar->security->path); + return (1); + } } }