>From 4714758d685a7c557a58233c863c1f95e27a664d Mon Sep 17 00:00:00 2001 From: Pavel Raiskup Date: Wed, 9 Jul 2014 14:04:17 +0200 Subject: [PATCH 2/2] create: do not segfault with --dereference Fix SIGSEGV during archiving of directory symbolic-link loop. Prior to version 1.26, tar failed with message "Cannot stat: Too many levels of symbolic links" but this limit does not "save" us anymore since the s/open/openat/ conversion. Original bugreport: https://bugzilla.redhat.com/show_bug.cgi?id=1115890 * src/create.c (dir_loop_point): New function detecting loops in directory path when --dereference is specified. (dump_dir): Don't recurse down when dir_loop_point alerts. * tests/deref01.at: New testcase. * tests/Makefile.am: Adjust for new testcase. * tests/testsuite.at: Likewise. * NEWS: Document. --- NEWS | 5 +++++ src/create.c | 31 ++++++++++++++++++++++++++++++- tests/Makefile.am | 1 + tests/deref01.at | 41 +++++++++++++++++++++++++++++++++++++++++ tests/testsuite.at | 1 + 5 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 tests/deref01.at diff --git a/NEWS b/NEWS index 616ec02..8a760b3 100644 --- a/NEWS +++ b/NEWS @@ -115,6 +115,11 @@ speed up archivation. scenarios) to save stack-space and thus avoid segfaults for rarely deep archived directories. +* Bug fixes + +Fix segfault during archiving of directory symbolic-link loop with +--dereference option. + * Manpages This release includes official tar(1) and rmt(8) manpages. diff --git a/src/create.c b/src/create.c index 29e9965..90bfff0 100644 --- a/src/create.c +++ b/src/create.c @@ -1096,6 +1096,25 @@ dump_regular_file (int fd, struct tar_stat_info *st) return dump_status_ok; } +static bool +dir_loop_point (const struct tar_stat_info* st) +{ + const struct tar_stat_info *ptr = st; + + if (!dereference_option) + return false; + + while (ptr->parent) + { + ptr = ptr->parent; + if (ptr->stat.st_dev == st->stat.st_dev + && ptr->stat.st_ino == st->stat.st_ino) + return true; + } + + return false; +} + /* Dump currently precessed directory in T. Return true if successful, false (emitting diagnostics) otherwise. Get ST's entries, recurse @@ -1196,7 +1215,17 @@ dump_dir (tour_t t) case exclusion_tag_none: { - char *directory = get_directory_entries (st); + char *directory; + + + if (dir_loop_point (st)) + { + WARN ((0, 0, _("%s: stopping recursion due to directory loop"), + st->orig_file_name)); + break; + } + + directory = get_directory_entries (st); if (! directory) { savedir_diag (st->orig_file_name); diff --git a/tests/Makefile.am b/tests/Makefile.am index f145929..9a783e5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -67,6 +67,7 @@ TESTSUITE_AT = \ delete03.at\ delete04.at\ delete05.at\ + deref01.at\ exclude.at\ exclude01.at\ exclude02.at\ diff --git a/tests/deref01.at b/tests/deref01.at new file mode 100644 index 0000000..30c499c --- /dev/null +++ b/tests/deref01.at @@ -0,0 +1,41 @@ +# Process this file with autom4te to create testsuite. -*- Autotest -*- +# +# Test suite for GNU tar. +# Copyright 2014 Free Software Foundation, Inc. + +# This file is part of GNU tar. + +# GNU tar is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# GNU tar is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Test description: +# Symlink loop on directory with --dereference option caused tar to end in +# infinite recursion ending on SIGSEGV. +# +# Original bugreport: +# https://bugzilla.redhat.com/show_bug.cgi?id=1115890 + +AT_SETUP([dereference: symlink loop]) +AT_KEYWORDS([create dereference deref01]) + +AT_TAR_CHECK([ +mkdir dir +ln -s ../dir dir/dir || AT_SKIP_TEST +tar -chf test.tar dir 2>/dev/null && tar -tf test.tar +], +[0], +[dir/ +dir/dir/ +]) + +AT_CLEANUP diff --git a/tests/testsuite.at b/tests/testsuite.at index 4b1c805..0b0a778 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -217,6 +217,7 @@ m4_include([recurse.at]) m4_include([recurs02.at]) m4_include([shortrec.at]) m4_include([iotty.at]) +m4_include([deref01.at]) AT_BANNER([The --same-order option]) m4_include([same-order01.at]) -- 2.5.0