Skip to content

Commit 1e6c8ba

Browse files
committed
Merge branch 'jc/hash-object' into maint
"hash-object --literally" introduced in v2.2 was not prepared to take a really long object type name. * jc/hash-object: write_sha1_file(): do not use a separate sha1[] array t1007: add hash-object --literally tests hash-object --literally: fix buffer overrun with extra-long object type git-hash-object.txt: document --literally option
2 parents 5d53433 + 1427a7f commit 1e6c8ba

File tree

5 files changed

+43
-9
lines changed

5 files changed

+43
-9
lines changed

Documentation/git-hash-object.txt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ git-hash-object - Compute object ID and optionally creates a blob from a file
99
SYNOPSIS
1010
--------
1111
[verse]
12-
'git hash-object' [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>...
12+
'git hash-object' [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin [--literally]] [--] <file>...
1313
'git hash-object' [-t <type>] [-w] --stdin-paths [--no-filters] < <list-of-paths>
1414

1515
DESCRIPTION
@@ -51,7 +51,13 @@ OPTIONS
5151
Hash the contents as is, ignoring any input filter that would
5252
have been chosen by the attributes mechanism, including the end-of-line
5353
conversion. If the file is read from standard input then this
54-
is always implied, unless the --path option is given.
54+
is always implied, unless the `--path` option is given.
55+
56+
--literally::
57+
Allow `--stdin` to hash any garbage into a loose object which might not
58+
otherwise pass standard object parsing or git-fsck checks. Useful for
59+
stress-testing Git itself or reproducing characteristics of corrupt or
60+
bogus objects encountered in the wild.
5561

5662
GIT
5763
---

builtin/hash-object.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,8 @@ static int hash_literally(unsigned char *sha1, int fd, const char *type, unsigne
2222

2323
if (strbuf_read(&buf, fd, 4096) < 0)
2424
ret = -1;
25-
else if (flags & HASH_WRITE_OBJECT)
26-
ret = write_sha1_file(buf.buf, buf.len, type, sha1);
2725
else
28-
ret = hash_sha1_file(buf.buf, buf.len, type, sha1);
26+
ret = hash_sha1_file_literally(buf.buf, buf.len, type, sha1, flags);
2927
strbuf_release(&buf);
3028
return ret;
3129
}

cache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,7 @@ static inline const unsigned char *lookup_replace_object_extended(const unsigned
874874
extern int sha1_object_info(const unsigned char *, unsigned long *);
875875
extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
876876
extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
877+
extern int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type, unsigned char *sha1, unsigned flags);
877878
extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
878879
extern int force_object_loose(const unsigned char *sha1, time_t mtime);
879880
extern int git_open_noatime(const char *name);

sha1_file.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3009,23 +3009,41 @@ static int freshen_packed_object(const unsigned char *sha1)
30093009
return 1;
30103010
}
30113011

3012-
int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *returnsha1)
3012+
int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1)
30133013
{
3014-
unsigned char sha1[20];
30153014
char hdr[32];
30163015
int hdrlen;
30173016

30183017
/* Normally if we have it in the pack then we do not bother writing
30193018
* it out into .git/objects/??/?{38} file.
30203019
*/
30213020
write_sha1_file_prepare(buf, len, type, sha1, hdr, &hdrlen);
3022-
if (returnsha1)
3023-
hashcpy(returnsha1, sha1);
30243021
if (freshen_packed_object(sha1) || freshen_loose_object(sha1))
30253022
return 0;
30263023
return write_loose_object(sha1, hdr, hdrlen, buf, len, 0);
30273024
}
30283025

3026+
int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type,
3027+
unsigned char *sha1, unsigned flags)
3028+
{
3029+
char *header;
3030+
int hdrlen, status = 0;
3031+
3032+
/* type string, SP, %lu of the length plus NUL must fit this */
3033+
header = xmalloc(strlen(type) + 32);
3034+
write_sha1_file_prepare(buf, len, type, sha1, header, &hdrlen);
3035+
3036+
if (!(flags & HASH_WRITE_OBJECT))
3037+
goto cleanup;
3038+
if (freshen_packed_object(sha1) || freshen_loose_object(sha1))
3039+
goto cleanup;
3040+
status = write_loose_object(sha1, header, hdrlen, buf, len, 0);
3041+
3042+
cleanup:
3043+
free(header);
3044+
return status;
3045+
}
3046+
30293047
int force_object_loose(const unsigned char *sha1, time_t mtime)
30303048
{
30313049
void *buf;

t/t1007-hash-object.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,4 +209,15 @@ test_expect_success 'hash-object complains about truncated type name' '
209209
test_must_fail git hash-object -t bl --stdin </dev/null
210210
'
211211

212+
test_expect_success '--literally' '
213+
t=1234567890 &&
214+
echo example | git hash-object -t $t --literally --stdin
215+
'
216+
217+
test_expect_success '--literally with extra-long type' '
218+
t=12345678901234567890123456789012345678901234567890 &&
219+
t="$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t$t" &&
220+
echo example | git hash-object -t $t --literally --stdin
221+
'
222+
212223
test_done

0 commit comments

Comments
 (0)