From: Junio C Hamano <gitster@pobox.com>
To: Git Mailing List <git@vger.kernel.org>
Cc: Jeff King <peff@peff.net>, Josh Boyer <jwboyer@fedoraproject.org>,
"Linux-Kernel\@Vger. Kernel. Org" <linux-kernel@vger.kernel.org>,
twaugh@redhat.com, Linus Torvalds <torvalds@linux-foundation.org>
Subject: [PATCH] apply: refuse touching a file beyond symlink
Date: Thu, 29 Jan 2015 12:45:22 -0800 [thread overview]
Message-ID: <xmqqa911e2ot.fsf_-_@gitster.dls.corp.google.com> (raw)
In-Reply-To: <xmqqtwzadrj8.fsf@gitster.dls.corp.google.com> (Junio C. Hamano's message of "Wed, 28 Jan 2015 22:34:03 -0800")
Because Git tracks symbolic links as symbolic links, a path that has
a symbolic link in its leading part (e.g. path/to/dir/file, where
path/to/dir is a symbolic link to somewhere else, be it inside or
outside the working tree) can never appear in a patch that validly
applies, unless the same patch first removes the symbolic link to
allow a directory to be there.
Detect and reject such a patch. Things to note:
- Unfortunately, we cannot reuse the has_symlink_leading_path()
from dir.c, as that is only about the working tree, but "git
apply" can be told to apply the patch only to the index or to
both the index and to the working tree.
- We cannot directly use has_symlink_leading_path() even when we
are applying only to the working tree, as an early patch of a
valid input may remove a symbolic link path/to/dir and then a
later patch of the input may create a path path/to/dir/file, but
"git apply" first checks the input without touching either the
index or the working tree. The leading symbolic link check must
be done on the interim result we compute in-core (i.e. after the
first patch, there is no path/to/dir symbolic link and it is
perfectly valid to create path/to/dir/file).
Similarly, when an input creates a symbolic link path/to/dir and
then creates a file path/to/dir/file, we need to flag it as an
error without actually creating path/to/dir symbolic link in the
filesystem.
Instead, for any patch in the input that leaves a path (i.e. a non
deletion) in the result, we check all leading paths against interim
result and then either the index or the working tree. The interim
results of applying patches are kept track of by fn_table logic for
us already, so use it to fiture out if existing a symbolic link will
cause problems, if a new symbolic link that will cause problems will
appear, etc.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
* At least I convinced myself enough to say that I do not seem to
be breaking things with this patch, after taking patches out of
dozens of random pairs of commits from the Linux kernel history
and applying them using this version ;-) No code change since
last night's snapshot, but the test script is a bit more thorough
in this version.
builtin/apply.c | 44 +++++++++++++++++++++++++++++
t/t4122-apply-symlink-inside.sh | 62 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 106 insertions(+)
diff --git a/builtin/apply.c b/builtin/apply.c
index ef32e4f..dcb44fb 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -3483,6 +3483,46 @@ static int check_to_create(const char *new_name, int ok_if_exists)
return 0;
}
+static int path_is_beyond_symlink(const char *name_)
+{
+ struct strbuf name = STRBUF_INIT;
+
+ strbuf_addstr(&name, name_);
+ do {
+ struct patch *previous;
+
+ while (--name.len && name.buf[name.len] != '/')
+ ; /* scan backwards */
+ if (!name.len)
+ break;
+ name.buf[name.len] = '\0';
+ previous = in_fn_table(name.buf);
+ if (previous) {
+ if (!was_deleted(previous) &&
+ !to_be_deleted(previous) &&
+ previous->new_mode &&
+ S_ISLNK(previous->new_mode))
+ goto symlink_found;
+ } else if (check_index) {
+ int pos = cache_name_pos(name.buf, name.len);
+ if (0 <= pos &&
+ S_ISLNK(active_cache[pos]->ce_mode))
+ goto symlink_found;
+ } else {
+ struct stat st;
+ if (!lstat(name.buf, &st) && S_ISLNK(st.st_mode))
+ goto symlink_found;
+ }
+ } while (1);
+
+ strbuf_release(&name);
+ return 0;
+symlink_found:
+ strbuf_release(&name);
+ return 1;
+
+}
+
/*
* Check and apply the patch in-core; leave the result in patch->result
* for the caller to write it out to the final destination.
@@ -3570,6 +3610,10 @@ static int check_patch(struct patch *patch)
}
}
+ if (!patch->is_delete && path_is_beyond_symlink(patch->new_name))
+ return error(_("affected file '%s' is beyond a symbolic link"),
+ patch->new_name);
+
if (apply_data(patch, &st, ce) < 0)
return error(_("%s: patch does not apply"), name);
patch->rejected = 0;
diff --git a/t/t4122-apply-symlink-inside.sh b/t/t4122-apply-symlink-inside.sh
index 70b3a06..0a8de4a 100755
--- a/t/t4122-apply-symlink-inside.sh
+++ b/t/t4122-apply-symlink-inside.sh
@@ -52,4 +52,66 @@ test_expect_success 'check result' '
'
+test_expect_success SYMLINKS 'do not follow symbolic link (setup)' '
+
+ git reset --hard &&
+ ln -s ../i386/dir arch/x86_64/dir &&
+ git add arch/x86_64/dir &&
+ git diff HEAD >add_symlink.patch &&
+ git reset --hard &&
+
+ mkdir arch/x86_64/dir &&
+ >arch/x86_64/dir/file &&
+ git add arch/x86_64/dir/file &&
+ git diff HEAD >add_file.patch &&
+ git reset --hard &&
+ rm -fr arch/x86_64/dir &&
+
+ cat add_symlink.patch add_file.patch >patch &&
+
+ mkdir arch/i386/dir
+'
+
+test_expect_success SYMLINKS 'do not follow symbolic link (same input)' '
+
+ # same input creates a confusihng symbolic link
+ test_must_fail git apply patch 2>error-wt &&
+ test_i18ngrep "beyond a symbolic link" error-wt &&
+ test ! -e arch/x86_64/dir &&
+ test ! -e arch/i386/dir/file &&
+
+ test_must_fail git apply --index patch 2>error-ix &&
+ test_i18ngrep "beyond a symbolic link" error-ix &&
+ test ! -e arch/x86_64/dir &&
+ test ! -e arch/i386/dir/file &&
+ test_must_fail git ls-files --error-unmatch arch/x86_64/dir &&
+ test_must_fail git ls-files --error-unmatch arch/i386/dir &&
+
+ test_must_fail git apply --cached patch 2>error-ct &&
+ test_i18ngrep "beyond a symbolic link" error-ct &&
+ test_must_fail git ls-files --error-unmatch arch/x86_64/dir &&
+ test_must_fail git ls-files --error-unmatch arch/i386/dir
+'
+
+test_expect_success SYMLINKS 'do not follow symbolic link (existing)' '
+
+ # existing symbolic link
+ git reset --hard &&
+ ln -s ../i386/dir arch/x86_64/dir &&
+ git add arch/x86_64/dir &&
+
+ test_must_fail git apply add_file.patch 2>error-wt-file &&
+ test_i18ngrep "beyond a symbolic link" error-wt-file &&
+ test ! -e arch/i386/dir/file &&
+
+ test_must_fail git apply --index add_file.patch 2>error-ix-file &&
+ test_i18ngrep "beyond a symbolic link" error-ix-file &&
+ test ! -e arch/i386/dir/file &&
+ test_must_fail git ls-files --error-unmatch arch/i386/dir &&
+
+ test_must_fail git apply --cached add_file.patch 2>error-ct-file &&
+ test_i18ngrep "beyond a symbolic link" error-ct-file &&
+ test_must_fail git ls-files --error-unmatch arch/i386/dir
+'
+
test_done
--
2.3.0-rc2-153-g9e53805
next prev parent reply other threads:[~2015-01-29 20:45 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-01-26 16:29 patch-2.7.3 no longer applies relative symbolic link patches Josh Boyer
2015-01-26 16:32 ` Josh Boyer
2015-01-26 20:44 ` Linus Torvalds
2015-01-26 21:01 ` David Kastrup
2015-01-26 21:07 ` Josh Boyer
2015-01-26 21:30 ` Linus Torvalds
2015-01-26 21:35 ` Junio C Hamano
2015-01-26 21:50 ` Linus Torvalds
2015-01-27 15:47 ` Andreas Gruenbacher
2015-01-31 21:27 ` Andreas Gruenbacher
2015-01-26 22:15 ` Josh Boyer
2015-01-27 3:27 ` Junio C Hamano
2015-01-27 20:39 ` Junio C Hamano
2015-01-29 6:05 ` Junio C Hamano
2015-01-29 6:34 ` Junio C Hamano
2015-01-29 20:45 ` Junio C Hamano [this message]
2015-01-29 22:15 ` [PATCH] apply: refuse touching a file beyond symlink Stefan Beller
2015-01-29 23:48 ` [PATCH 2/1] apply: reject input that touches outside $cwd Junio C Hamano
2015-01-30 18:24 ` Jeff King
2015-01-30 19:07 ` Junio C Hamano
2015-01-30 19:16 ` Jeff King
2015-01-30 9:04 ` [PATCH] apply: refuse touching a file beyond symlink Christian Couder
2015-01-30 18:11 ` Jeff King
2015-01-30 19:42 ` Junio C Hamano
2015-01-30 19:46 ` Jeff King
2015-01-30 19:48 ` Junio C Hamano
2015-01-30 20:07 ` Jeff King
2015-01-30 20:32 ` Junio C Hamano
2015-01-30 20:11 ` Junio C Hamano
2015-01-30 20:16 ` Jeff King
2015-01-30 20:20 ` Junio C Hamano
2015-01-30 20:48 ` Jeff King
2015-01-30 21:10 ` Junio C Hamano
2015-01-30 21:50 ` Junio C Hamano
2015-01-27 15:26 ` patch-2.7.3 no longer applies relative symbolic link patches Andreas Gruenbacher
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=xmqqa911e2ot.fsf_-_@gitster.dls.corp.google.com \
--to=gitster@pobox.com \
--cc=git@vger.kernel.org \
--cc=jwboyer@fedoraproject.org \
--cc=linux-kernel@vger.kernel.org \
--cc=peff@peff.net \
--cc=torvalds@linux-foundation.org \
--cc=twaugh@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox