public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Junio C Hamano <gitster@pobox.com>
To: Linus Torvalds <torvalds@linux-foundation.org>,
	Jeff King <peff@peff.net>
Cc: Josh Boyer <jwboyer@fedoraproject.org>,
	"Linux-Kernel\@Vger. Kernel. Org" <linux-kernel@vger.kernel.org>,
	twaugh@redhat.com, Git Mailing List <git@vger.kernel.org>
Subject: Re: patch-2.7.3 no longer applies relative symbolic link patches
Date: Wed, 28 Jan 2015 22:05:56 -0800	[thread overview]
Message-ID: <xmqqfvauf7ej.fsf@gitster.dls.corp.google.com> (raw)
In-Reply-To: <xmqqa914klg0.fsf@gitster.dls.corp.google.com> (Junio C. Hamano's message of "Tue, 27 Jan 2015 12:39:11 -0800")

Junio C Hamano <gitster@pobox.com> writes:

> Junio C Hamano <gitster@pobox.com> writes:
>
>> If the user wants to apply a patch that touches ../etc/shadow, is
>> the tool in the place to complain?"
>
> Let me take this part back.
>
> I think "git apply" should behave closely to "git apply --index"
> (which is used by "git am" unless there is a very good reason not to
> (and "'git apply --index' behaves differently from GNU patch, and we
> should match what the latter does" is not a very good reason).  When
> the index guards the working tree, we do not follow any symlink,
> whether the destination is inside the current directory or not.
>
> I however do not think the current "git apply" notices that it will
> overwrite a path beyond a symlink---we may need to fix that if that
> is the case.  I'll see what I can find (but I'll be doing 2.3-rc2
> today so it may be later this week).

Yikes.  It turns out that the index is what protects us from going
outside the working tree.  "apply --index" (hence "am") is immune
against the CVE-2015-1196, but that is not because we do not follow
symbolic links.

Also the solution is not just a simple has_symlink_leading_path().
Here is tonight's snapshot of what I've found out (not tested beyond
passing the test suite including the new test added by the patch).

-- >8 --
Subject: [PATCH] apply: refuse touching a file beyond symlink

Because Git tracks symbolic links as symbolic links, a path that has
a symbolic link in its leading part (e.g. path/to/dir being a
symbolic link to somewhere else, be it inside or outside the working
tree) can never appear in a patch that validly apply, unless the
same patch first removes the symbolic link.

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.

 - We cannot directly use has_symlink_leading_path() even when we
   are applying 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.  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 result of applying patch is already kept track of
   by fn_table logic for us.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin/apply.c                 | 44 +++++++++++++++++++++++++++++++++++++++++
 t/t4122-apply-symlink-inside.sh | 37 ++++++++++++++++++++++++++++++++++
 2 files changed, 81 insertions(+)

diff --git a/builtin/apply.c b/builtin/apply.c
index ef32e4f..da088c5 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..8b11bc6 100755
--- a/t/t4122-apply-symlink-inside.sh
+++ b/t/t4122-apply-symlink-inside.sh
@@ -52,4 +52,41 @@ test_expect_success 'check result' '
 
 '
 
+test_expect_success 'do not follow symbolic link' '
+
+	git reset --hard &&
+	test_ln_s_add ../i386/dir 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_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_done
-- 
2.3.0-rc2-149-gdd42ee9


  reply	other threads:[~2015-01-29  6:06 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 [this message]
2015-01-29  6:34           ` Junio C Hamano
2015-01-29 20:45             ` [PATCH] apply: refuse touching a file beyond symlink Junio C Hamano
2015-01-29 22:15               ` 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=xmqqfvauf7ej.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