Compare commits

...

32 Commits

Author SHA1 Message Date
ac33201285 Git 2.5.6
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-05-05 12:50:38 +09:00
531788af95 Merge branch 'maint-2.4' into maint-2.5 2017-05-05 12:46:53 +09:00
4000b40209 Git 2.4.12
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-05-05 12:43:16 +09:00
5a4ffdf587 Merge branch 'jk/shell-no-repository-that-begins-with-dash' into maint-2.4
* jk/shell-no-repository-that-begins-with-dash:
  shell: disallow repo names beginning with dash
2017-05-05 12:17:55 +09:00
3ec804490a shell: disallow repo names beginning with dash
When a remote server uses git-shell, the client side will
connect to it like:

  ssh server "git-upload-pack 'foo.git'"

and we literally exec ("git-upload-pack", "foo.git"). In
early versions of upload-pack and receive-pack, we took a
repository argument and nothing else. But over time they
learned to accept dashed options. If the user passes a
repository name that starts with a dash, the results are
confusing at best (we complain of a bogus option instead of
a non-existent repository) and malicious at worst (the user
can start an interactive pager via "--help").

We could pass "--" to the sub-process to make sure the
user's argument is interpreted as a branch name. I.e.:

  git-upload-pack -- -foo.git

But adding "--" automatically would make us inconsistent
with a normal shell (i.e., when git-shell is not in use),
where "-foo.git" would still be an error. For that case, the
client would have to specify the "--", but they can't do so
reliably, as existing versions of git-shell do not allow
more than a single argument.

The simplest thing is to simply disallow "-" at the start of
the repo name argument. This hasn't worked either with or
without git-shell since version 1.0.0, and nobody has
complained.

Note that this patch just applies to do_generic_cmd(), which
runs upload-pack, receive-pack, and upload-archive. There
are two other types of commands that git-shell runs:

  - do_cvs_cmd(), but this already restricts the argument to
    be the literal string "server"

  - admin-provided commands in the git-shell-commands
    directory. We'll pass along arbitrary arguments there,
    so these commands could have similar problems. But these
    commands might actually understand dashed arguments, so
    we cannot just block them here. It's up to the writer of
    the commands to make sure they are safe. With great
    power comes great responsibility.

Reported-by: Timo Schmid <tschmid@ernw.de>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-05-05 12:07:27 +09:00
e568e563ad Git 2.5.5
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-17 11:24:59 -07:00
c638f3e4d5 Merge branch 'maint-2.4' into maint-2.5
* maint-2.4:
  Git 2.4.11
  list-objects: pass full pathname to callbacks
  list-objects: drop name_path entirely
  list-objects: convert name_path to a strbuf
  show_object_with_name: simplify by using path_name()
  http-push: stop using name_path
  tree-diff: catch integer overflow in combine_diff_path allocation
  add helpers for detecting size_t overflow
2016-03-17 11:24:14 -07:00
765428699a Git 2.4.11
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-17 11:23:05 -07:00
32c6dca8c4 Merge branch 'jk/path-name-safety-2.4' into maint-2.4
Bugfix patches were backported from the 'master' front to plug heap
corruption holes, to catch integer overflow in the computation of
pathname lengths, and to get rid of the name_path API.  Both of
these would have resulted in writing over an under-allocated buffer
when formulating pathnames while tree traversal.

* jk/path-name-safety-2.4:
  list-objects: pass full pathname to callbacks
  list-objects: drop name_path entirely
  list-objects: convert name_path to a strbuf
  show_object_with_name: simplify by using path_name()
  http-push: stop using name_path
  tree-diff: catch integer overflow in combine_diff_path allocation
  add helpers for detecting size_t overflow
2016-03-17 11:22:24 -07:00
2824e1841b list-objects: pass full pathname to callbacks
When we find a blob at "a/b/c", we currently pass this to
our show_object_fn callbacks as two components: "a/b/" and
"c". Callbacks which want the full value then call
path_name(), which concatenates the two. But this is an
inefficient interface; the path is a strbuf, and we could
simply append "c" to it temporarily, then roll back the
length, without creating a new copy.

So we could improve this by teaching the callsites of
path_name() this trick (and there are only 3). But we can
also notice that no callback actually cares about the
broken-down representation, and simply pass each callback
the full path "a/b/c" as a string. The callback code becomes
even simpler, then, as we do not have to worry about freeing
an allocated buffer, nor rolling back our modification to
the strbuf.

This is theoretically less efficient, as some callbacks
would not bother to format the final path component. But in
practice this is not measurable. Since we use the same
strbuf over and over, our work to grow it is amortized, and
we really only pay to memcpy a few bytes.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-16 10:41:04 -07:00
dc06dc8800 list-objects: drop name_path entirely
In the previous commit, we left name_path as a thin wrapper
around a strbuf. This patch drops it entirely. As a result,
every show_object_fn callback needs to be adjusted. However,
none of their code needs to be changed at all, because the
only use was to pass it to path_name(), which now handles
the bare strbuf.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-16 10:41:03 -07:00
f3badaed51 list-objects: convert name_path to a strbuf
The "struct name_path" data is examined in only two places:
we generate it in process_tree(), and we convert it to a
single string in path_name(). Everyone else just passes it
through to those functions.

We can further note that process_tree() already keeps a
single strbuf with the leading tree path, for use with
tree_entry_interesting().

Instead of building a separate name_path linked list, let's
just use the one we already build in "base". This reduces
the amount of code (especially tricky code in path_name()
which did not check for integer overflows caused by deep
or large pathnames).

It is also more efficient in some instances.  Any time we
were using tree_entry_interesting, we were building up the
strbuf anyway, so this is an immediate and obvious win
there. In cases where we were not, we trade off storing
"pathname/" in a strbuf on the heap for each level of the
path, instead of two pointers and an int on the stack (with
one pointer into the tree object). On a 64-bit system, the
latter is 20 bytes; so if path components are less than that
on average, this has lower peak memory usage.  In practice
it probably doesn't matter either way; we are already
holding in memory all of the tree objects leading up to each
pathname, and for normal-depth pathnames, we are only
talking about hundreds of bytes.

This patch leaves "struct name_path" as a thin wrapper
around the strbuf, to avoid disrupting callbacks. We should
fix them, but leaving it out makes this diff easier to view.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-16 10:41:03 -07:00
8eee9f9277 show_object_with_name: simplify by using path_name()
When "git rev-list" shows an object with its associated path
name, it does so by walking the name_path linked list and
printing each component (stopping at any embedded NULs or
newlines).

We'd like to eventually get rid of name_path entirely in
favor of a single buffer, and dropping this custom printing
code is part of that. As a first step, let's use path_name()
to format the list into a single buffer, and print that.
This is strictly less efficient than the original, but it's
a temporary step in the refactoring; our end game will be to
get the fully formatted name in the first place.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-16 10:41:03 -07:00
c6bd2a1dec http-push: stop using name_path
The graph traversal code here passes along a name_path to
build up the pathname at which we find each blob. But we
never actually do anything with the resulting names, making
it a waste of code and memory.

This usage came in aa1dbc9 (Update http-push functionality,
2006-03-07), and originally the result was passed to
"add_object" (which stored it, but didn't really use it,
either). But we stopped using that function in 1f1e895 (Add
"named object array" concept, 2006-06-19) in favor of
storing just the objects themselves.

Moreover, the generation of the name in process_tree() is
buggy. It sticks "name" onto the end of the name_path linked
list, and then passes it down again as it recurses (instead
of "entry.path"). So it's a good thing this was unused, as
the resulting path for "a/b/c/d" would end up as "a/a/a/a".

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-16 10:41:02 -07:00
d770187872 tree-diff: catch integer overflow in combine_diff_path allocation
A combine_diff_path struct has two "flex" members allocated
alongside the struct: a string to hold the pathname, and an
array of parent pointers. We use an "int" to compute this,
meaning we may easily overflow it if the pathname is
extremely long.

We can fix this by using size_t, and checking for overflow
with the st_add helper.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-16 10:41:02 -07:00
935de81289 add helpers for detecting size_t overflow
Performing computations on size_t variables that we feed to
xmalloc and friends can be dangerous, as an integer overflow
can cause us to allocate a much smaller chunk than we
realized.

We already have unsigned_add_overflows(), but let's add
unsigned_mult_overflows() to that. Furthermore, rather than
have each site manually check and die on overflow, we can
provide some helpers that will:

  - promote the arguments to size_t, so that we know we are
    doing our computation in the same size of integer that
    will ultimately be fed to xmalloc

  - check and die on overflow

  - return the result so that computations can be done in
    the parameter list of xmalloc.

These functions are a lot uglier to use than normal
arithmetic operators (you have to do "st_add(foo, bar)"
instead of "foo + bar"). To at least limit the damage, we
also provide multi-valued versions. So rather than:

  st_add(st_add(a, b), st_add(c, d));

you can write:

  st_add4(a, b, c, d);

This isn't nearly as elegant as a varargs function, but it's
a lot harder to get it wrong. You don't have to remember to
add a sentinel value at the end, and the compiler will
complain if you get the number of arguments wrong. This
patch adds only the numbered variants required to convert
the current code base; we can easily add more later if
needed.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-16 10:41:02 -07:00
24358560c3 Git 2.5.4
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-28 15:34:28 -07:00
11a458befc Sync with 2.4.10 2015-09-28 15:33:56 -07:00
a2558fb8e1 Git 2.4.10
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-28 15:30:30 -07:00
6343e2f6f2 Sync with 2.3.10 2015-09-28 15:28:31 -07:00
18b58f707f Git 2.3.10
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-28 15:26:52 -07:00
92cdfd2131 Merge branch 'jk/xdiff-memory-limits' into maint-2.3 2015-09-28 14:59:28 -07:00
83c4d38017 merge-file: enforce MAX_XDIFF_SIZE on incoming files
The previous commit enforces MAX_XDIFF_SIZE at the
interfaces to xdiff: xdi_diff (which calls xdl_diff) and
ll_xdl_merge (which calls xdl_merge).

But we have another direct call to xdl_merge in
merge-file.c. If it were written today, this probably would
just use the ll_merge machinery. But it predates that code,
and uses slightly different options to xdl_merge (e.g.,
ZEALOUS_ALNUM).

We could try to abstract out an xdi_merge to match the
existing xdi_diff, but even that is difficult. Rather than
simply report error, we try to treat large files as binary,
and that distinction would happen outside of xdi_merge.

The simplest fix is to just replicate the MAX_XDIFF_SIZE
check in merge-file.c.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-28 14:58:13 -07:00
dcd1742e56 xdiff: reject files larger than ~1GB
The xdiff code is not prepared to handle extremely large
files. It uses "int" in many places, which can overflow if
we have a very large number of lines or even bytes in our
input files. This can cause us to produce incorrect diffs,
with no indication that the output is wrong. Or worse, we
may even underallocate a buffer whose size is the result of
an overflowing addition.

We're much better off to tell the user that we cannot diff
or merge such a large file. This patch covers both cases,
but in slightly different ways:

  1. For merging, we notice the large file and cleanly fall
     back to a binary merge (which is effectively "we cannot
     merge this").

  2. For diffing, we make the binary/text distinction much
     earlier, and in many different places. For this case,
     we'll use the xdi_diff as our choke point, and reject
     any diff there before it hits the xdiff code.

     This means in most cases we'll die() immediately after.
     That's not ideal, but in practice we shouldn't
     generally hit this code path unless the user is trying
     to do something tricky. We already consider files
     larger than core.bigfilethreshold to be binary, so this
     code would only kick in when that is circumvented
     (either by bumping that value, or by using a
     .gitattribute to mark a file as diffable).

     In other words, we can avoid being "nice" here, because
     there is already nice code that tries to do the right
     thing. We are adding the suspenders to the nice code's
     belt, so notice when it has been worked around (both to
     protect the user from malicious inputs, and because it
     is better to die() than generate bogus output).

The maximum size was chosen after experimenting with feeding
large files to the xdiff code. It's just under a gigabyte,
which leaves room for two obvious cases:

  - a diff3 merge conflict result on files of maximum size X
    could be 3*X plus the size of the markers, which would
    still be only about 3G, which fits in a 32-bit int.

  - some of the diff code allocates arrays of one int per
    record. Even if each file consists only of blank lines,
    then a file smaller than 1G will have fewer than 1G
    records, and therefore the int array will fit in 4G.

Since the limit is arbitrary anyway, I chose to go under a
gigabyte, to leave a safety margin (e.g., we would not want
to overflow by allocating "(records + 1) * sizeof(int)" or
similar.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-28 14:57:23 -07:00
3efb988098 react to errors in xdi_diff
When we call into xdiff to perform a diff, we generally lose
the return code completely. Typically by ignoring the return
of our xdi_diff wrapper, but sometimes we even propagate
that return value up and then ignore it later.  This can
lead to us silently producing incorrect diffs (e.g., "git
log" might produce no output at all, not even a diff header,
for a content-level diff).

In practice this does not happen very often, because the
typical reason for xdiff to report failure is that it
malloc() failed (it uses straight malloc, and not our
xmalloc wrapper).  But it could also happen when xdiff
triggers one our callbacks, which returns an error (e.g.,
outf() in builtin/rerere.c tries to report a write failure
in this way). And the next patch also plans to add more
failure modes.

Let's notice an error return from xdiff and react
appropriately. In most of the diff.c code, we can simply
die(), which matches the surrounding code (e.g., that is
what we do if we fail to load a file for diffing in the
first place). This is not that elegant, but we are probably
better off dying to let the user know there was a problem,
rather than simply generating bogus output.

We could also just die() directly in xdi_diff, but the
callers typically have a bit more context, and can provide a
better message (and if we do later decide to pass errors up,
we're one step closer to doing so).

There is one interesting case, which is in diff_grep(). Here
if we cannot generate the diff, there is nothing to match,
and we silently return "no hits". This is actually what the
existing code does already, but we make it a little more
explicit.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-28 14:57:10 -07:00
f2df3104ce Merge branch 'jk/transfer-limit-redirection' into maint-2.3 2015-09-28 14:46:05 -07:00
df37727a65 Merge branch 'jk/transfer-limit-protocol' into maint-2.3 2015-09-28 14:33:27 -07:00
b258116462 http: limit redirection depth
By default, libcurl will follow circular http redirects
forever. Let's put a cap on this so that somebody who can
trigger an automated fetch of an arbitrary repository (e.g.,
for CI) cannot convince git to loop infinitely.

The value chosen is 20, which is the same default that
Firefox uses.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-25 15:32:28 -07:00
f4113cac0c http: limit redirection to protocol-whitelist
Previously, libcurl would follow redirection to any protocol
it was compiled for support with. This is desirable to allow
redirection from HTTP to HTTPS. However, it would even
successfully allow redirection from HTTP to SFTP, a protocol
that git does not otherwise support at all. Furthermore
git's new protocol-whitelisting could be bypassed by
following a redirect within the remote helper, as it was
only enforced at transport selection time.

This patch limits redirects within libcurl to HTTP, HTTPS,
FTP and FTPS. If there is a protocol-whitelist present, this
list is limited to those also allowed by the whitelist. As
redirection happens from within libcurl, it is impossible
for an HTTP redirect to a protocol implemented within
another remote helper.

When the curl version git was compiled with is too old to
support restrictions on protocol redirection, we warn the
user if GIT_ALLOW_PROTOCOL restrictions were requested. This
is a little inaccurate, as even without that variable in the
environment, we would still restrict SFTP, etc, and we do
not warn in that case. But anything else means we would
literally warn every time git accesses an http remote.

This commit includes a test, but it is not as robust as we
would hope. It redirects an http request to ftp, and checks
that curl complained about the protocol, which means that we
are relying on curl's specific error message to know what
happened. Ideally we would redirect to a working ftp server
and confirm that we can clone without protocol restrictions,
and not with them. But we do not have a portable way of
providing an ftp server, nor any other protocol that curl
supports (https is the closest, but we would have to deal
with certificates).

[jk: added test and version warning]

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-25 15:30:39 -07:00
5088d3b387 transport: refactor protocol whitelist code
The current callers only want to die when their transport is
prohibited. But future callers want to query the mechanism
without dying.

Let's break out a few query functions, and also save the
results in a static list so we don't have to re-parse for
each query.

Based-on-a-patch-by: Blake Burkhart <bburky@bburky.com>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-25 15:28:36 -07:00
33cfccbbf3 submodule: allow only certain protocols for submodule fetches
Some protocols (like git-remote-ext) can execute arbitrary
code found in the URL. The URLs that submodules use may come
from arbitrary sources (e.g., .gitmodules files in a remote
repository). Let's restrict submodules to fetching from a
known-good subset of protocols.

Note that we apply this restriction to all submodule
commands, whether the URL comes from .gitmodules or not.
This is more restrictive than we need to be; for example, in
the tests we run:

  git submodule add ext::...

which should be trusted, as the URL comes directly from the
command line provided by the user. But doing it this way is
simpler, and makes it much less likely that we would miss a
case. And since such protocols should be an exception
(especially because nobody who clones from them will be able
to update the submodules!), it's not likely to inconvenience
anyone in practice.

Reported-by: Blake Burkhart <bburky@bburky.com>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-23 11:35:48 -07:00
a5adaced2e transport: add a protocol-whitelist environment variable
If we are cloning an untrusted remote repository into a
sandbox, we may also want to fetch remote submodules in
order to get the complete view as intended by the other
side. However, that opens us up to attacks where a malicious
user gets us to clone something they would not otherwise
have access to (this is not necessarily a problem by itself,
but we may then act on the cloned contents in a way that
exposes them to the attacker).

Ideally such a setup would sandbox git entirely away from
high-value items, but this is not always practical or easy
to set up (e.g., OS network controls may block multiple
protocols, and we would want to enable some but not others).

We can help this case by providing a way to restrict
particular protocols. We use a whitelist in the environment.
This is more annoying to set up than a blacklist, but
defaults to safety if the set of protocols git supports
grows). If no whitelist is specified, we continue to default
to allowing all protocols (this is an "unsafe" default, but
since the minority of users will want this sandboxing
effect, it is the only sensible one).

A note on the tests: ideally these would all be in a single
test file, but the git-daemon and httpd test infrastructure
is an all-or-nothing proposition rather than a test-by-test
prerequisite. By putting them all together, we would be
unable to test the file-local code on machines without
apache.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-09-23 11:35:48 -07:00
49 changed files with 623 additions and 179 deletions

View File

@ -0,0 +1,18 @@
Git v2.3.10 Release Notes
=========================
Fixes since v2.3.9
------------------
* xdiff code we use to generate diffs is not prepared to handle
extremely large files. It uses "int" in many places, which can
overflow if we have a very large number of lines or even bytes in
our input files, for example. Cap the input size to soemwhere
around 1GB for now.
* Some protocols (like git-remote-ext) can execute arbitrary code
found in the URL. The URLs that submodules use may come from
arbitrary sources (e.g., .gitmodules files in a remote
repository), and can hurt those who blindly enable recursive
fetch. Restrict the allowed protocols to well known and safe
ones.

View File

@ -0,0 +1,18 @@
Git v2.4.10 Release Notes
=========================
Fixes since v2.4.9
------------------
* xdiff code we use to generate diffs is not prepared to handle
extremely large files. It uses "int" in many places, which can
overflow if we have a very large number of lines or even bytes in
our input files, for example. Cap the input size to soemwhere
around 1GB for now.
* Some protocols (like git-remote-ext) can execute arbitrary code
found in the URL. The URLs that submodules use may come from
arbitrary sources (e.g., .gitmodules files in a remote
repository), and can hurt those who blindly enable recursive
fetch. Restrict the allowed protocols to well known and safe
ones.

View File

@ -0,0 +1,11 @@
Git v2.4.11 Release Notes
=========================
Fixes since v2.4.10
-------------------
* Bugfix patches were backported from the 'master' front to plug heap
corruption holes, to catch integer overflow in the computation of
pathname lengths, and to get rid of the name_path API. Both of
these would have resulted in writing over an under-allocated buffer
when formulating pathnames while tree traversal.

View File

@ -0,0 +1,12 @@
Git v2.4.12 Release Notes
=========================
Fixes since v2.4.11
-------------------
* "git-shell" rejects a request to serve a repository whose name
begins with a dash, which makes it no longer possible to get it
confused into spawning service programs like "git-upload-pack" with
an option like "--help", which in turn would spawn an interactive
pager, instead of working with the repository user asked to access
(i.e. the one whose name is "--help").

View File

@ -0,0 +1,18 @@
Git v2.5.4 Release Notes
========================
Fixes since v2.5.4
------------------
* xdiff code we use to generate diffs is not prepared to handle
extremely large files. It uses "int" in many places, which can
overflow if we have a very large number of lines or even bytes in
our input files, for example. Cap the input size to soemwhere
around 1GB for now.
* Some protocols (like git-remote-ext) can execute arbitrary code
found in the URL. The URLs that submodules use may come from
arbitrary sources (e.g., .gitmodules files in a remote
repository), and can hurt those who blindly enable recursive
fetch. Restrict the allowed protocols to well known and safe
ones.

View File

@ -0,0 +1,11 @@
Git v2.5.5 Release Notes
========================
Fixes since v2.5.4
------------------
* Bugfix patches were backported from the 'master' front to plug heap
corruption holes, to catch integer overflow in the computation of
pathname lengths, and to get rid of the name_path API. Both of
these would have resulted in writing over an under-allocated buffer
when formulating pathnames while tree traversal.

View File

@ -0,0 +1,12 @@
Git v2.5.6 Release Notes
========================
Fixes since v2.5.5
------------------
* "git-shell" rejects a request to serve a repository whose name
begins with a dash, which makes it no longer possible to get it
confused into spawning service programs like "git-upload-pack" with
an option like "--help", which in turn would spawn an interactive
pager, instead of working with the repository user asked to access
(i.e. the one whose name is "--help").

View File

@ -43,17 +43,23 @@ unreleased) version of Git, that is available from the 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
* link:v2.5.3/git.html[documentation for release 2.5.3]
* link:v2.5.6/git.html[documentation for release 2.5.6]
* release notes for
link:RelNotes/2.5.6.txt[2.5.6],
link:RelNotes/2.5.5.txt[2.5.5],
link:RelNotes/2.5.4.txt[2.5.4],
link:RelNotes/2.5.3.txt[2.5.3],
link:RelNotes/2.5.2.txt[2.5.2],
link:RelNotes/2.5.1.txt[2.5.1],
link:RelNotes/2.5.0.txt[2.5].
* link:v2.4.9/git.html[documentation for release 2.4.9]
* link:v2.4.12/git.html[documentation for release 2.4.12]
* release notes for
link:RelNotes/2.4.12.txt[2.4.12],
link:RelNotes/2.4.11.txt[2.4.11],
link:RelNotes/2.4.10.txt[2.4.10],
link:RelNotes/2.4.9.txt[2.4.9],
link:RelNotes/2.4.8.txt[2.4.8],
link:RelNotes/2.4.7.txt[2.4.7],
@ -65,9 +71,10 @@ Documentation for older releases are available here:
link:RelNotes/2.4.1.txt[2.4.1],
link:RelNotes/2.4.0.txt[2.4].
* link:v2.3.9/git.html[documentation for release 2.3.9]
* link:v2.3.10/git.html[documentation for release 2.3.10]
* release notes for
link:RelNotes/2.3.10.txt[2.3.10],
link:RelNotes/2.3.9.txt[2.3.9],
link:RelNotes/2.3.8.txt[2.3.8],
link:RelNotes/2.3.7.txt[2.3.7],
@ -1076,6 +1083,33 @@ GIT_ICASE_PATHSPECS::
an operation has touched every ref (e.g., because you are
cloning a repository to make a backup).
`GIT_ALLOW_PROTOCOL`::
If set, provide a colon-separated list of protocols which are
allowed to be used with fetch/push/clone. This is useful to
restrict recursive submodule initialization from an untrusted
repository. Any protocol not mentioned will be disallowed (i.e.,
this is a whitelist, not a blacklist). If the variable is not
set at all, all protocols are enabled. The protocol names
currently used by git are:
- `file`: any local file-based path (including `file://` URLs,
or local paths)
- `git`: the anonymous git protocol over a direct TCP
connection (or proxy, if configured)
- `ssh`: git over ssh (including `host:path` syntax,
`git+ssh://`, etc).
- `rsync`: git over rsync
- `http`: git over http, both "smart http" and "dumb http".
Note that this does _not_ include `https`; if you want both,
you should specify both as `http:https`.
- any external helpers are named by their protocol (e.g., use
`hg` to allow the `git-remote-hg` helper)
Discussion[[Discussion]]
------------------------

View File

@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
DEF_VER=v2.5.3
DEF_VER=v2.5.6
LF='
'

View File

@ -1 +1 @@
Documentation/RelNotes/2.5.3.txt
Documentation/RelNotes/2.5.6.txt

View File

@ -973,7 +973,10 @@ static void pass_blame_to_parent(struct scoreboard *sb,
fill_origin_blob(&sb->revs->diffopt, target, &file_o);
num_get_patch++;
diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d);
if (diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d))
die("unable to generate diff (%s -> %s)",
sha1_to_hex(parent->commit->object.sha1),
sha1_to_hex(target->commit->object.sha1));
/* The rest are the same as the parent */
blame_chunk(&d.dstq, &d.srcq, INT_MAX, d.offset, INT_MAX, parent);
*d.dstq = NULL;
@ -1119,7 +1122,9 @@ static void find_copy_in_blob(struct scoreboard *sb,
* file_p partially may match that image.
*/
memset(split, 0, sizeof(struct blame_entry [3]));
diff_hunks(file_p, &file_o, 1, handle_split_cb, &d);
if (diff_hunks(file_p, &file_o, 1, handle_split_cb, &d))
die("unable to generate diff (%s)",
sha1_to_hex(parent->commit->object.sha1));
/* remainder, if any, all match the preimage */
handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split);
}

View File

@ -75,7 +75,8 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
names[i] = argv[i];
if (read_mmfile(mmfs + i, fname))
return -1;
if (buffer_is_binary(mmfs[i].ptr, mmfs[i].size))
if (mmfs[i].size > MAX_XDIFF_SIZE ||
buffer_is_binary(mmfs[i].ptr, mmfs[i].size))
return error("Cannot merge binary files: %s",
argv[i]);
}

View File

@ -118,7 +118,8 @@ static void show_diff(struct merge_list *entry)
if (!dst.ptr)
size = 0;
dst.size = size;
xdi_diff(&src, &dst, &xpp, &xecfg, &ecb);
if (xdi_diff(&src, &dst, &xpp, &xecfg, &ecb))
die("unable to generate diff");
free(src.ptr);
free(dst.ptr);
}

View File

@ -2284,21 +2284,11 @@ static void show_commit(struct commit *commit, void *data)
index_commit_for_bitmap(commit);
}
static void show_object(struct object *obj,
const struct name_path *path, const char *last,
void *data)
static void show_object(struct object *obj, const char *name, void *data)
{
char *name = path_name(path, last);
add_preferred_base_object(name);
add_object_entry(obj->sha1, obj->type, name, 0);
obj->flags |= OBJECT_ADDED;
/*
* We will have generated the hash from the name,
* but not saved a pointer to it - we can free it
*/
free((char *)name);
}
static void show_edge(struct commit *commit)
@ -2480,8 +2470,7 @@ static int get_object_list_from_bitmap(struct rev_info *revs)
}
static void record_recent_object(struct object *obj,
const struct name_path *path,
const char *last,
const char *name,
void *data)
{
sha1_array_append(&recent_objects, obj->sha1);

View File

@ -29,9 +29,10 @@ static int diff_two(const char *file1, const char *label1,
xdemitconf_t xecfg;
xdemitcb_t ecb;
mmfile_t minus, plus;
int ret;
if (read_mmfile(&minus, file1) || read_mmfile(&plus, file2))
return 1;
return -1;
printf("--- a/%s\n+++ b/%s\n", label1, label2);
fflush(stdout);
@ -40,11 +41,11 @@ static int diff_two(const char *file1, const char *label1,
memset(&xecfg, 0, sizeof(xecfg));
xecfg.ctxlen = 3;
ecb.outf = outf;
xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
ret = xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
free(minus.ptr);
free(plus.ptr);
return 0;
return ret;
}
int cmd_rerere(int argc, const char **argv, const char *prefix)
@ -104,7 +105,8 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
for (i = 0; i < merge_rr.nr; i++) {
const char *path = merge_rr.items[i].string;
const char *name = (const char *)merge_rr.items[i].util;
diff_two(rerere_path(name, "preimage"), path, path, path);
if (diff_two(rerere_path(name, "preimage"), path, path, path))
die("unable to generate diff for %s", name);
}
else
usage_with_options(rerere_usage, options);

View File

@ -177,9 +177,7 @@ static void finish_commit(struct commit *commit, void *data)
free_commit_buffer(commit);
}
static void finish_object(struct object *obj,
const struct name_path *path, const char *name,
void *cb_data)
static void finish_object(struct object *obj, const char *name, void *cb_data)
{
struct rev_list_info *info = cb_data;
if (obj->type == OBJ_BLOB && !has_sha1_file(obj->sha1))
@ -188,15 +186,13 @@ static void finish_object(struct object *obj,
parse_object(obj->sha1);
}
static void show_object(struct object *obj,
const struct name_path *path, const char *component,
void *cb_data)
static void show_object(struct object *obj, const char *name, void *cb_data)
{
struct rev_list_info *info = cb_data;
finish_object(obj, path, component, cb_data);
finish_object(obj, name, cb_data);
if (info->flags & REV_LIST_QUIET)
return;
show_object_with_name(stdout, obj, path, component);
show_object_with_name(stdout, obj, name);
}
static void show_edge(struct commit *commit)

View File

@ -419,8 +419,10 @@ static void combine_diff(const struct object_id *parent, unsigned int mode,
state.num_parent = num_parent;
state.n = n;
xdi_diff_outf(&parent_file, result_file, consume_line, &state,
&xpp, &xecfg);
if (xdi_diff_outf(&parent_file, result_file, consume_line, &state,
&xpp, &xecfg))
die("unable to generate combined diff for %s",
oid_to_hex(parent));
free(parent_file.ptr);
/* Assign line numbers for this parent.

View File

@ -9,6 +9,7 @@
#include "url.h"
#include "string-list.h"
#include "sha1-array.h"
#include "transport.h"
static char *server_capabilities;
static const char *parse_feature_value(const char *, const char *, int *);
@ -694,6 +695,8 @@ struct child_process *git_connect(int fd[2], const char *url,
else
target_host = xstrdup(hostandport);
transport_check_allowed("git");
/* These underlying connection commands die() if they
* cannot connect.
*/
@ -727,6 +730,7 @@ struct child_process *git_connect(int fd[2], const char *url,
int putty, tortoiseplink = 0;
char *ssh_host = hostandport;
const char *port = NULL;
transport_check_allowed("ssh");
get_host_and_port(&ssh_host, &port);
if (!port)
@ -781,6 +785,7 @@ struct child_process *git_connect(int fd[2], const char *url,
/* remove repo-local variables from the environment */
conn->env = local_repo_env;
conn->use_shell = 1;
transport_check_allowed("file");
}
argv_array_push(&conn->args, cmd.buf);

26
diff.c
View File

@ -1033,8 +1033,9 @@ static void diff_words_show(struct diff_words_data *diff_words)
xpp.flags = 0;
/* as only the hunk header will be parsed, we need a 0-context */
xecfg.ctxlen = 0;
xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words,
&xpp, &xecfg);
if (xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words,
&xpp, &xecfg))
die("unable to generate word diff");
free(minus.ptr);
free(plus.ptr);
if (diff_words->current_plus != diff_words->plus.text.ptr +
@ -2441,8 +2442,9 @@ static void builtin_diff(const char *name_a,
xecfg.ctxlen = strtoul(v, NULL, 10);
if (o->word_diff)
init_diff_words_data(&ecbdata, o, one, two);
xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata,
&xpp, &xecfg);
if (xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata,
&xpp, &xecfg))
die("unable to generate diff for %s", one->path);
if (o->word_diff)
free_diff_words_data(&ecbdata);
if (textconv_one)
@ -2519,8 +2521,9 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
xpp.flags = o->xdl_opts;
xecfg.ctxlen = o->context;
xecfg.interhunkctxlen = o->interhunkcontext;
xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat,
&xpp, &xecfg);
if (xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat,
&xpp, &xecfg))
die("unable to generate diffstat for %s", one->path);
}
diff_free_filespec_data(one);
@ -2566,8 +2569,9 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
memset(&xecfg, 0, sizeof(xecfg));
xecfg.ctxlen = 1; /* at least one context line */
xpp.flags = 0;
xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data,
&xpp, &xecfg);
if (xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data,
&xpp, &xecfg))
die("unable to generate checkdiff for %s", one->path);
if (data.ws_rule & WS_BLANK_AT_EOF) {
struct emit_callback ecbdata;
@ -4508,8 +4512,10 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
xpp.flags = 0;
xecfg.ctxlen = 3;
xecfg.flags = 0;
xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data,
&xpp, &xecfg);
if (xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data,
&xpp, &xecfg))
return error("unable to generate patch-id diff for %s",
p->one->path);
}
git_SHA1_Final(sha1, &ctx);

4
diff.h
View File

@ -221,8 +221,8 @@ struct combine_diff_path {
} parent[FLEX_ARRAY];
};
#define combine_diff_path_size(n, l) \
(sizeof(struct combine_diff_path) + \
sizeof(struct combine_diff_parent) * (n) + (l) + 1)
st_add4(sizeof(struct combine_diff_path), (l), 1, \
st_mult(sizeof(struct combine_diff_parent), (n)))
extern void show_combined_diff(struct combine_diff_path *elem, int num_parent,
int dense, struct rev_info *);

View File

@ -62,8 +62,8 @@ static int diff_grep(mmfile_t *one, mmfile_t *two,
ecbdata.hit = 0;
xecfg.ctxlen = o->context;
xecfg.interhunkctxlen = o->interhunkcontext;
xdi_diff_outf(one, two, diffgrep_consume, &ecbdata,
&xpp, &xecfg);
if (xdi_diff_outf(one, two, diffgrep_consume, &ecbdata, &xpp, &xecfg))
return 0;
return ecbdata.hit;
}

View File

@ -96,6 +96,14 @@
#define unsigned_add_overflows(a, b) \
((b) > maximum_unsigned_value_of_type(a) - (a))
/*
* Returns true if the multiplication of "a" and "b" will
* overflow. The types of "a" and "b" must match and must be unsigned.
* Note that this macro evaluates "a" twice!
*/
#define unsigned_mult_overflows(a, b) \
((a) && (b) > maximum_unsigned_value_of_type(a) / (a))
#ifdef __GNUC__
#define TYPEOF(x) (__typeof__(x))
#else
@ -699,6 +707,32 @@ extern void release_pack_memory(size_t);
typedef void (*try_to_free_t)(size_t);
extern try_to_free_t set_try_to_free_routine(try_to_free_t);
static inline size_t st_add(size_t a, size_t b)
{
if (unsigned_add_overflows(a, b))
die("size_t overflow: %"PRIuMAX" + %"PRIuMAX,
(uintmax_t)a, (uintmax_t)b);
return a + b;
}
#define st_add3(a,b,c) st_add((a),st_add((b),(c)))
#define st_add4(a,b,c,d) st_add((a),st_add3((b),(c),(d)))
static inline size_t st_mult(size_t a, size_t b)
{
if (unsigned_mult_overflows(a, b))
die("size_t overflow: %"PRIuMAX" * %"PRIuMAX,
(uintmax_t)a, (uintmax_t)b);
return a * b;
}
static inline size_t st_sub(size_t a, size_t b)
{
if (a < b)
die("size_t underflow: %"PRIuMAX" - %"PRIuMAX,
(uintmax_t)a, (uintmax_t)b);
return a - b;
}
#ifdef HAVE_ALLOCA_H
# include <alloca.h>
# define xalloca(size) (alloca(size))

View File

@ -22,6 +22,15 @@ require_work_tree
wt_prefix=$(git rev-parse --show-prefix)
cd_to_toplevel
# Restrict ourselves to a vanilla subset of protocols; the URLs
# we get are under control of a remote repository, and we do not
# want them kicking off arbitrary git-remote-* programs.
#
# If the user has already specified a set of allowed protocols,
# we assume they know what they're doing and use that instead.
: ${GIT_ALLOW_PROTOCOL=file:git:http:https:ssh}
export GIT_ALLOW_PROTOCOL
command=
branch=
force=

View File

@ -1276,9 +1276,7 @@ static struct object_list **add_one_object(struct object *obj, struct object_lis
}
static struct object_list **process_blob(struct blob *blob,
struct object_list **p,
struct name_path *path,
const char *name)
struct object_list **p)
{
struct object *obj = &blob->object;
@ -1292,14 +1290,11 @@ static struct object_list **process_blob(struct blob *blob,
}
static struct object_list **process_tree(struct tree *tree,
struct object_list **p,
struct name_path *path,
const char *name)
struct object_list **p)
{
struct object *obj = &tree->object;
struct tree_desc desc;
struct name_entry entry;
struct name_path me;
obj->flags |= LOCAL;
@ -1309,21 +1304,17 @@ static struct object_list **process_tree(struct tree *tree,
die("bad tree object %s", sha1_to_hex(obj->sha1));
obj->flags |= SEEN;
name = xstrdup(name);
p = add_one_object(obj, p);
me.up = path;
me.elem = name;
me.elem_len = strlen(name);
init_tree_desc(&desc, tree->buffer, tree->size);
while (tree_entry(&desc, &entry))
switch (object_type(entry.mode)) {
case OBJ_TREE:
p = process_tree(lookup_tree(entry.sha1), p, &me, name);
p = process_tree(lookup_tree(entry.sha1), p);
break;
case OBJ_BLOB:
p = process_blob(lookup_blob(entry.sha1), p, &me, name);
p = process_blob(lookup_blob(entry.sha1), p);
break;
default:
/* Subproject commit - not in this repository */
@ -1342,7 +1333,7 @@ static int get_delta(struct rev_info *revs, struct remote_lock *lock)
int count = 0;
while ((commit = get_revision(revs)) != NULL) {
p = process_tree(commit->tree, p, NULL, "");
p = process_tree(commit->tree, p);
commit->object.flags |= LOCAL;
if (!(commit->object.flags & UNINTERESTING))
count += add_send_request(&commit->object, lock);
@ -1361,11 +1352,11 @@ static int get_delta(struct rev_info *revs, struct remote_lock *lock)
continue;
}
if (obj->type == OBJ_TREE) {
p = process_tree((struct tree *)obj, p, NULL, name);
p = process_tree((struct tree *)obj, p);
continue;
}
if (obj->type == OBJ_BLOB) {
p = process_blob((struct blob *)obj, p, NULL, name);
p = process_blob((struct blob *)obj, p);
continue;
}
die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);

18
http.c
View File

@ -9,6 +9,7 @@
#include "version.h"
#include "pkt-line.h"
#include "gettext.h"
#include "transport.h"
int active_requests;
int http_is_verbose;
@ -340,6 +341,7 @@ static void set_curl_keepalive(CURL *c)
static CURL *get_curl_handle(void)
{
CURL *result = curl_easy_init();
long allowed_protocols = 0;
if (!result)
die("curl_easy_init failed");
@ -394,11 +396,27 @@ static CURL *get_curl_handle(void)
}
curl_easy_setopt(result, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(result, CURLOPT_MAXREDIRS, 20);
#if LIBCURL_VERSION_NUM >= 0x071301
curl_easy_setopt(result, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
#elif LIBCURL_VERSION_NUM >= 0x071101
curl_easy_setopt(result, CURLOPT_POST301, 1);
#endif
#if LIBCURL_VERSION_NUM >= 0x071304
if (is_transport_allowed("http"))
allowed_protocols |= CURLPROTO_HTTP;
if (is_transport_allowed("https"))
allowed_protocols |= CURLPROTO_HTTPS;
if (is_transport_allowed("ftp"))
allowed_protocols |= CURLPROTO_FTP;
if (is_transport_allowed("ftps"))
allowed_protocols |= CURLPROTO_FTPS;
curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS, allowed_protocols);
#else
if (transport_restrict_protocols())
warning("protocol restrictions not applied to curl redirects because\n"
"your curl version is too old (>= 7.19.4)");
#endif
if (getenv("GIT_CURL_VERBOSE"))
curl_easy_setopt(result, CURLOPT_VERBOSE, 1);

View File

@ -325,7 +325,7 @@ static int collect_diff_cb(long start_a, long count_a,
return 0;
}
static void collect_diff(mmfile_t *parent, mmfile_t *target, struct diff_ranges *out)
static int collect_diff(mmfile_t *parent, mmfile_t *target, struct diff_ranges *out)
{
struct collect_diff_cbdata cbdata = {NULL};
xpparam_t xpp;
@ -340,7 +340,7 @@ static void collect_diff(mmfile_t *parent, mmfile_t *target, struct diff_ranges
xecfg.hunk_func = collect_diff_cb;
memset(&ecb, 0, sizeof(ecb));
ecb.priv = &cbdata;
xdi_diff(parent, target, &xpp, &xecfg, &ecb);
return xdi_diff(parent, target, &xpp, &xecfg, &ecb);
}
/*
@ -1030,7 +1030,8 @@ static int process_diff_filepair(struct rev_info *rev,
}
diff_ranges_init(&diff);
collect_diff(&file_parent, &file_target, &diff);
if (collect_diff(&file_parent, &file_target, &diff))
die("unable to generate diff for %s", pair->one->path);
/* NEEDSWORK should apply some heuristics to prevent mismatches */
free(rg->path);

View File

@ -11,11 +11,12 @@
static void process_blob(struct rev_info *revs,
struct blob *blob,
show_object_fn show,
struct name_path *path,
struct strbuf *path,
const char *name,
void *cb_data)
{
struct object *obj = &blob->object;
size_t pathlen;
if (!revs->blob_objects)
return;
@ -24,7 +25,11 @@ static void process_blob(struct rev_info *revs,
if (obj->flags & (UNINTERESTING | SEEN))
return;
obj->flags |= SEEN;
show(obj, path, name, cb_data);
pathlen = path->len;
strbuf_addstr(path, name);
show(obj, path->buf, cb_data);
strbuf_setlen(path, pathlen);
}
/*
@ -52,7 +57,7 @@ static void process_blob(struct rev_info *revs,
static void process_gitlink(struct rev_info *revs,
const unsigned char *sha1,
show_object_fn show,
struct name_path *path,
struct strbuf *path,
const char *name,
void *cb_data)
{
@ -62,7 +67,6 @@ static void process_gitlink(struct rev_info *revs,
static void process_tree(struct rev_info *revs,
struct tree *tree,
show_object_fn show,
struct name_path *path,
struct strbuf *base,
const char *name,
void *cb_data)
@ -70,7 +74,6 @@ static void process_tree(struct rev_info *revs,
struct object *obj = &tree->object;
struct tree_desc desc;
struct name_entry entry;
struct name_path me;
enum interesting match = revs->diffopt.pathspec.nr == 0 ?
all_entries_interesting: entry_not_interesting;
int baselen = base->len;
@ -86,17 +89,12 @@ static void process_tree(struct rev_info *revs,
return;
die("bad tree object %s", sha1_to_hex(obj->sha1));
}
obj->flags |= SEEN;
show(obj, path, name, cb_data);
me.up = path;
me.elem = name;
me.elem_len = strlen(name);
if (!match) {
strbuf_addstr(base, name);
if (base->len)
strbuf_addch(base, '/');
}
obj->flags |= SEEN;
strbuf_addstr(base, name);
show(obj, base->buf, cb_data);
if (base->len)
strbuf_addch(base, '/');
init_tree_desc(&desc, tree->buffer, tree->size);
@ -113,16 +111,16 @@ static void process_tree(struct rev_info *revs,
if (S_ISDIR(entry.mode))
process_tree(revs,
lookup_tree(entry.sha1),
show, &me, base, entry.path,
show, base, entry.path,
cb_data);
else if (S_ISGITLINK(entry.mode))
process_gitlink(revs, entry.sha1,
show, &me, entry.path,
show, base, entry.path,
cb_data);
else
process_blob(revs,
lookup_blob(entry.sha1),
show, &me, entry.path,
show, base, entry.path,
cb_data);
}
strbuf_setlen(base, baselen);
@ -213,19 +211,19 @@ void traverse_commit_list(struct rev_info *revs,
continue;
if (obj->type == OBJ_TAG) {
obj->flags |= SEEN;
show_object(obj, NULL, name, data);
show_object(obj, name, data);
continue;
}
if (!path)
path = "";
if (obj->type == OBJ_TREE) {
process_tree(revs, (struct tree *)obj, show_object,
NULL, &base, path, data);
&base, path, data);
continue;
}
if (obj->type == OBJ_BLOB) {
process_blob(revs, (struct blob *)obj, show_object,
NULL, path, data);
&base, path, data);
continue;
}
die("unknown pending object %s (%s)",

View File

@ -2,7 +2,7 @@
#define LIST_OBJECTS_H
typedef void (*show_commit_fn)(struct commit *, void *);
typedef void (*show_object_fn)(struct object *, const struct name_path *, const char *, void *);
typedef void (*show_object_fn)(struct object *, const char *, void *);
void traverse_commit_list(struct rev_info *, show_commit_fn, show_object_fn, void *);
typedef void (*show_edge_fn)(struct commit *);

View File

@ -89,7 +89,10 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
xmparam_t xmp;
assert(opts);
if (buffer_is_binary(orig->ptr, orig->size) ||
if (orig->size > MAX_XDIFF_SIZE ||
src1->size > MAX_XDIFF_SIZE ||
src2->size > MAX_XDIFF_SIZE ||
buffer_is_binary(orig->ptr, orig->size) ||
buffer_is_binary(src1->ptr, src1->size) ||
buffer_is_binary(src2->ptr, src2->size)) {
return ll_binary_merge(drv_unused, result,

View File

@ -148,8 +148,7 @@ static uint32_t find_object_pos(const unsigned char *sha1)
return entry->in_pack_pos;
}
static void show_object(struct object *object, const struct name_path *path,
const char *last, void *data)
static void show_object(struct object *object, const char *name, void *data)
{
struct bitmap *base = data;
bitmap_set(base, find_object_pos(object->sha1));

View File

@ -422,19 +422,15 @@ static int ext_index_add_object(struct object *object, const char *name)
return bitmap_pos + bitmap_git.pack->num_objects;
}
static void show_object(struct object *object, const struct name_path *path,
const char *last, void *data)
static void show_object(struct object *object, const char *name, void *data)
{
struct bitmap *base = data;
int bitmap_pos;
bitmap_pos = bitmap_position(object->sha1);
if (bitmap_pos < 0) {
char *name = path_name(path, last);
if (bitmap_pos < 0)
bitmap_pos = ext_index_add_object(object, name);
free(name);
}
bitmap_set(base, bitmap_pos);
}
@ -902,9 +898,8 @@ struct bitmap_test_data {
size_t seen;
};
static void test_show_object(struct object *object,
const struct name_path *path,
const char *last, void *data)
static void test_show_object(struct object *object, const char *name,
void *data)
{
struct bitmap_test_data *tdata = data;
int bitmap_pos;

View File

@ -37,15 +37,14 @@ static int add_one_ref(const char *path, const struct object_id *oid,
* The traversal will have already marked us as SEEN, so we
* only need to handle any progress reporting here.
*/
static void mark_object(struct object *obj, const struct name_path *path,
const char *name, void *data)
static void mark_object(struct object *obj, const char *name, void *data)
{
update_progress(data);
}
static void mark_commit(struct commit *c, void *data)
{
mark_object(&c->object, NULL, NULL, data);
mark_object(&c->object, NULL, data);
}
struct recent_data {

View File

@ -21,69 +21,13 @@
volatile show_early_output_fn_t show_early_output;
char *path_name(const struct name_path *path, const char *name)
void show_object_with_name(FILE *out, struct object *obj, const char *name)
{
const struct name_path *p;
char *n, *m;
int nlen = strlen(name);
int len = nlen + 1;
for (p = path; p; p = p->up) {
if (p->elem_len)
len += p->elem_len + 1;
}
n = xmalloc(len);
m = n + len - (nlen + 1);
strcpy(m, name);
for (p = path; p; p = p->up) {
if (p->elem_len) {
m -= p->elem_len + 1;
memcpy(m, p->elem, p->elem_len);
m[p->elem_len] = '/';
}
}
return n;
}
static int show_path_component_truncated(FILE *out, const char *name, int len)
{
int cnt;
for (cnt = 0; cnt < len; cnt++) {
int ch = name[cnt];
if (!ch || ch == '\n')
return -1;
fputc(ch, out);
}
return len;
}
static int show_path_truncated(FILE *out, const struct name_path *path)
{
int emitted, ours;
if (!path)
return 0;
emitted = show_path_truncated(out, path->up);
if (emitted < 0)
return emitted;
if (emitted)
fputc('/', out);
ours = show_path_component_truncated(out, path->elem, path->elem_len);
if (ours < 0)
return ours;
return ours || emitted;
}
void show_object_with_name(FILE *out, struct object *obj,
const struct name_path *path, const char *component)
{
struct name_path leaf;
leaf.up = (struct name_path *)path;
leaf.elem = component;
leaf.elem_len = strlen(component);
const char *p;
fprintf(out, "%s ", sha1_to_hex(obj->sha1));
show_path_truncated(out, &leaf);
for (p = name; *p && *p != '\n'; p++)
fputc(*p, out);
fputc('\n', out);
}

View File

@ -256,16 +256,9 @@ extern void put_revision_mark(const struct rev_info *revs,
extern void mark_parents_uninteresting(struct commit *commit);
extern void mark_tree_uninteresting(struct tree *tree);
struct name_path {
struct name_path *up;
int elem_len;
const char *elem;
};
char *path_name(struct strbuf *path, const char *name);
char *path_name(const struct name_path *path, const char *name);
extern void show_object_with_name(FILE *, struct object *,
const struct name_path *, const char *);
extern void show_object_with_name(FILE *, struct object *, const char *);
extern void add_pending_object(struct rev_info *revs,
struct object *obj, const char *name);

View File

@ -13,7 +13,7 @@ static int do_generic_cmd(const char *me, char *arg)
const char *my_argv[4];
setup_path();
if (!arg || !(arg = sq_dequote(arg)))
if (!arg || !(arg = sq_dequote(arg)) || *arg == '-')
die("bad argument");
if (!starts_with(me, "git-"))
die("bad command");

View File

@ -119,6 +119,10 @@ RewriteRule ^/smart-redir-perm/(.*)$ /smart/$1 [R=301]
RewriteRule ^/smart-redir-temp/(.*)$ /smart/$1 [R=302]
RewriteRule ^/smart-redir-auth/(.*)$ /auth/smart/$1 [R=301]
RewriteRule ^/smart-redir-limited/(.*)/info/refs$ /smart/$1/info/refs [R=301]
RewriteRule ^/ftp-redir/(.*)$ ftp://localhost:1000/$1 [R=302]
RewriteRule ^/loop-redir/x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-(.*) /$1 [R=302]
RewriteRule ^/loop-redir/(.*)$ /loop-redir/x-$1 [R=302]
<IfDefine SSL>
LoadModule ssl_module modules/mod_ssl.so

96
t/lib-proto-disable.sh Normal file
View File

@ -0,0 +1,96 @@
# Test routines for checking protocol disabling.
# test cloning a particular protocol
# $1 - description of the protocol
# $2 - machine-readable name of the protocol
# $3 - the URL to try cloning
test_proto () {
desc=$1
proto=$2
url=$3
test_expect_success "clone $1 (enabled)" '
rm -rf tmp.git &&
(
GIT_ALLOW_PROTOCOL=$proto &&
export GIT_ALLOW_PROTOCOL &&
git clone --bare "$url" tmp.git
)
'
test_expect_success "fetch $1 (enabled)" '
(
cd tmp.git &&
GIT_ALLOW_PROTOCOL=$proto &&
export GIT_ALLOW_PROTOCOL &&
git fetch
)
'
test_expect_success "push $1 (enabled)" '
(
cd tmp.git &&
GIT_ALLOW_PROTOCOL=$proto &&
export GIT_ALLOW_PROTOCOL &&
git push origin HEAD:pushed
)
'
test_expect_success "push $1 (disabled)" '
(
cd tmp.git &&
GIT_ALLOW_PROTOCOL=none &&
export GIT_ALLOW_PROTOCOL &&
test_must_fail git push origin HEAD:pushed
)
'
test_expect_success "fetch $1 (disabled)" '
(
cd tmp.git &&
GIT_ALLOW_PROTOCOL=none &&
export GIT_ALLOW_PROTOCOL &&
test_must_fail git fetch
)
'
test_expect_success "clone $1 (disabled)" '
rm -rf tmp.git &&
(
GIT_ALLOW_PROTOCOL=none &&
export GIT_ALLOW_PROTOCOL &&
test_must_fail git clone --bare "$url" tmp.git
)
'
}
# set up an ssh wrapper that will access $host/$repo in the
# trash directory, and enable it for subsequent tests.
setup_ssh_wrapper () {
test_expect_success 'setup ssh wrapper' '
write_script ssh-wrapper <<-\EOF &&
echo >&2 "ssh: $*"
host=$1; shift
cd "$TRASH_DIRECTORY/$host" &&
eval "$*"
EOF
GIT_SSH="$PWD/ssh-wrapper" &&
export GIT_SSH &&
export TRASH_DIRECTORY
'
}
# set up a wrapper that can be used with remote-ext to
# access repositories in the "remote" directory of trash-dir,
# like "ext::fake-remote %S repo.git"
setup_ext_wrapper () {
test_expect_success 'setup ext wrapper' '
write_script fake-remote <<-\EOF &&
echo >&2 "fake-remote: $*"
cd "$TRASH_DIRECTORY/remote" &&
eval "$*"
EOF
PATH=$TRASH_DIRECTORY:$PATH &&
export TRASH_DIRECTORY
'
}

14
t/t5810-proto-disable-local.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh
test_description='test disabling of local paths in clone/fetch'
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-proto-disable.sh"
test_expect_success 'setup repository to clone' '
test_commit one
'
test_proto "file://" file "file://$PWD"
test_proto "path" file .
test_done

20
t/t5811-proto-disable-git.sh Executable file
View File

@ -0,0 +1,20 @@
#!/bin/sh
test_description='test disabling of git-over-tcp in clone/fetch'
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-proto-disable.sh"
. "$TEST_DIRECTORY/lib-git-daemon.sh"
start_git_daemon
test_expect_success 'create git-accessible repo' '
bare="$GIT_DAEMON_DOCUMENT_ROOT_PATH/repo.git" &&
test_commit one &&
git --bare init "$bare" &&
git push "$bare" HEAD &&
>"$bare/git-daemon-export-ok" &&
git -C "$bare" config daemon.receivepack true
'
test_proto "git://" git "$GIT_DAEMON_URL/repo.git"
test_done

33
t/t5812-proto-disable-http.sh Executable file
View File

@ -0,0 +1,33 @@
#!/bin/sh
test_description='test disabling of git-over-http in clone/fetch'
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-proto-disable.sh"
. "$TEST_DIRECTORY/lib-httpd.sh"
start_httpd
test_expect_success 'create git-accessible repo' '
bare="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
test_commit one &&
git --bare init "$bare" &&
git push "$bare" HEAD &&
git -C "$bare" config http.receivepack true
'
test_proto "smart http" http "$HTTPD_URL/smart/repo.git"
test_expect_success 'curl redirects respect whitelist' '
test_must_fail env GIT_ALLOW_PROTOCOL=http:https \
git clone "$HTTPD_URL/ftp-redir/repo.git" 2>stderr &&
{
test_i18ngrep "ftp.*disabled" stderr ||
test_i18ngrep "your curl version is too old"
}
'
test_expect_success 'curl limits redirects' '
test_must_fail git clone "$HTTPD_URL/loop-redir/smart/repo.git"
'
stop_httpd
test_done

20
t/t5813-proto-disable-ssh.sh Executable file
View File

@ -0,0 +1,20 @@
#!/bin/sh
test_description='test disabling of git-over-ssh in clone/fetch'
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-proto-disable.sh"
setup_ssh_wrapper
test_expect_success 'setup repository to clone' '
test_commit one &&
mkdir remote &&
git init --bare remote/repo.git &&
git push remote/repo.git HEAD
'
test_proto "host:path" ssh "remote:repo.git"
test_proto "ssh://" ssh "ssh://remote/$PWD/remote/repo.git"
test_proto "git+ssh://" ssh "git+ssh://remote/$PWD/remote/repo.git"
test_done

18
t/t5814-proto-disable-ext.sh Executable file
View File

@ -0,0 +1,18 @@
#!/bin/sh
test_description='test disabling of remote-helper paths in clone/fetch'
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-proto-disable.sh"
setup_ext_wrapper
test_expect_success 'setup repository to clone' '
test_commit one &&
mkdir remote &&
git init --bare remote/repo.git &&
git push remote/repo.git HEAD
'
test_proto "remote-helper" ext "ext::fake-remote %S repo.git"
test_done

43
t/t5815-submodule-protos.sh Executable file
View File

@ -0,0 +1,43 @@
#!/bin/sh
test_description='test protocol whitelisting with submodules'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-proto-disable.sh
setup_ext_wrapper
setup_ssh_wrapper
test_expect_success 'setup repository with submodules' '
mkdir remote &&
git init remote/repo.git &&
(cd remote/repo.git && test_commit one) &&
# submodule-add should probably trust what we feed it on the cmdline,
# but its implementation is overly conservative.
GIT_ALLOW_PROTOCOL=ssh git submodule add remote:repo.git ssh-module &&
GIT_ALLOW_PROTOCOL=ext git submodule add "ext::fake-remote %S repo.git" ext-module &&
git commit -m "add submodules"
'
test_expect_success 'clone with recurse-submodules fails' '
test_must_fail git clone --recurse-submodules . dst
'
test_expect_success 'setup individual updates' '
rm -rf dst &&
git clone . dst &&
git -C dst submodule init
'
test_expect_success 'update of ssh allowed' '
git -C dst submodule update ssh-module
'
test_expect_success 'update of ext not allowed' '
test_must_fail git -C dst submodule update ext-module
'
test_expect_success 'user can override whitelist' '
GIT_ALLOW_PROTOCOL=ext git -C dst submodule update ext-module
'
test_done

View File

@ -1043,6 +1043,8 @@ int transport_helper_init(struct transport *transport, const char *name)
struct helper_data *data = xcalloc(1, sizeof(*data));
data->name = name;
transport_check_allowed(name);
if (getenv("GIT_TRANSPORT_HELPER_DEBUG"))
debug = 1;

View File

@ -912,6 +912,42 @@ static int external_specification_len(const char *url)
return strchr(url, ':') - url;
}
static const struct string_list *protocol_whitelist(void)
{
static int enabled = -1;
static struct string_list allowed = STRING_LIST_INIT_DUP;
if (enabled < 0) {
const char *v = getenv("GIT_ALLOW_PROTOCOL");
if (v) {
string_list_split(&allowed, v, ':', -1);
string_list_sort(&allowed);
enabled = 1;
} else {
enabled = 0;
}
}
return enabled ? &allowed : NULL;
}
int is_transport_allowed(const char *type)
{
const struct string_list *allowed = protocol_whitelist();
return !allowed || string_list_has_string(allowed, type);
}
void transport_check_allowed(const char *type)
{
if (!is_transport_allowed(type))
die("transport '%s' not allowed", type);
}
int transport_restrict_protocols(void)
{
return !!protocol_whitelist();
}
struct transport *transport_get(struct remote *remote, const char *url)
{
const char *helper;
@ -943,12 +979,14 @@ struct transport *transport_get(struct remote *remote, const char *url)
if (helper) {
transport_helper_init(ret, helper);
} else if (starts_with(url, "rsync:")) {
transport_check_allowed("rsync");
ret->get_refs_list = get_refs_via_rsync;
ret->fetch = fetch_objs_via_rsync;
ret->push = rsync_transport_push;
ret->smart_options = NULL;
} else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) {
struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
transport_check_allowed("file");
ret->data = data;
ret->get_refs_list = get_refs_from_bundle;
ret->fetch = fetch_refs_from_bundle;
@ -960,7 +998,10 @@ struct transport *transport_get(struct remote *remote, const char *url)
|| starts_with(url, "ssh://")
|| starts_with(url, "git+ssh://")
|| starts_with(url, "ssh+git://")) {
/* These are builtin smart transports. */
/*
* These are builtin smart transports; "allowed" transports
* will be checked individually in git_connect.
*/
struct git_transport_data *data = xcalloc(1, sizeof(*data));
ret->data = data;
ret->set_option = NULL;

View File

@ -133,6 +133,24 @@ struct transport {
/* Returns a transport suitable for the url */
struct transport *transport_get(struct remote *, const char *);
/*
* Check whether a transport is allowed by the environment. Type should
* generally be the URL scheme, as described in Documentation/git.txt
*/
int is_transport_allowed(const char *type);
/*
* Check whether a transport is allowed by the environment,
* and die otherwise.
*/
void transport_check_allowed(const char *type);
/*
* Returns true if the user has attempted to turn on protocol
* restrictions at all.
*/
int transport_restrict_protocols(void);
/* Transport options which apply to git:// and scp-style URLs */
/* The program to use on the remote side to send a pack */

View File

@ -124,8 +124,8 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,
unsigned mode, const unsigned char *sha1)
{
struct combine_diff_path *p;
int len = base->len + pathlen;
int alloclen = combine_diff_path_size(nparent, len);
size_t len = st_add(base->len, pathlen);
size_t alloclen = combine_diff_path_size(nparent, len);
/* if last->next is !NULL - it is a pre-allocated memory, we can reuse */
p = last->next;

View File

@ -131,6 +131,9 @@ int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t co
mmfile_t a = *mf1;
mmfile_t b = *mf2;
if (mf1->size > MAX_XDIFF_SIZE || mf2->size > MAX_XDIFF_SIZE)
return -1;
trim_common_tail(&a, &b, xecfg->ctxlen);
return xdl_diff(&a, &b, xpp, xecfg, xecb);

View File

@ -3,6 +3,13 @@
#include "xdiff/xdiff.h"
/*
* xdiff isn't equipped to handle content over a gigabyte;
* we make the cutoff 1GB - 1MB to give some breathing
* room for constant-sized additions (e.g., merge markers)
*/
#define MAX_XDIFF_SIZE (1024UL * 1024 * 1023)
typedef void (*xdiff_emit_consume_fn)(void *, char *, unsigned long);
int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb);