mirror of
https://github.com/git/git.git
synced 2026-08-08 17:11:48 +00:00
Merge branch 'bc/restrict-hex-to-lowercase' into seen
The parser for hex object names has been updated to reject uppercase hexadecimal characters when running in the breaking changes mode, in preparation for Git 3.0. * bc/restrict-hex-to-lowercase: hex: allow only lowercase object IDs in breaking changes mode object-name: use hexval hex: label usages of hex parsing for object IDs hex: make hex_to_bytes accept kind of hex to use hex: allow specifying hex type with hex2chr hex: add functionality for lowercase-only hex
This commit is contained in:
@@ -171,6 +171,11 @@ JGit, libgit2 and Gitoxide need to support it.
|
||||
matches the default branch name used in new repositories by many of the
|
||||
big Git forges.
|
||||
|
||||
* Git will accept hex object IDs only in lowercase. The fact that Git has
|
||||
historically allowed uppercase characters in hex object IDs has been the
|
||||
source of a variety of bugs and security problems in software using Git. We
|
||||
don't expect most users to notice any change.
|
||||
|
||||
* Git will require Rust as a mandatory part of the build process. While Git
|
||||
already started to adopt Rust in Git 2.49, all parts written in Rust are
|
||||
optional for the time being. This includes:
|
||||
|
||||
@@ -1866,7 +1866,7 @@ static void repack_local_links(void)
|
||||
while (strbuf_getline_lf(&line, out) != EOF) {
|
||||
unsigned char binary[GIT_MAX_RAWSZ];
|
||||
if (line.len != the_hash_algo->hexsz ||
|
||||
!hex_to_bytes(binary, line.buf, line.len))
|
||||
!hex_to_bytes(binary, line.buf, line.len, HEX_KIND_MIXED))
|
||||
die(_("index-pack: Expecting full hex object ID lines only from pack-objects."));
|
||||
|
||||
/*
|
||||
|
||||
2
color.c
2
color.c
@@ -72,7 +72,7 @@ static int get_hex_color(const char **inp, int width, unsigned char *out)
|
||||
unsigned int val;
|
||||
|
||||
assert(width == 1 || width == 2);
|
||||
val = (hexval(in[0]) << 4) | hexval(in[width - 1]);
|
||||
val = (hexval(in[0], HEX_KIND_MIXED) << 4) | hexval(in[width - 1], HEX_KIND_MIXED);
|
||||
if (val & ~0xff)
|
||||
return -1;
|
||||
*inp += width;
|
||||
|
||||
@@ -112,7 +112,7 @@ static void loose_objs_stats(struct strbuf *buf, const char *path)
|
||||
while ((e = readdir_skip_dot_and_dotdot(dir)) != NULL)
|
||||
if (get_dtype(e, &count_path, 0) == DT_DIR &&
|
||||
strlen(e->d_name) == 2 &&
|
||||
!hex_to_bytes(&c, e->d_name, 1)) {
|
||||
!hex_to_bytes(&c, e->d_name, 1, HEX_KIND_OID)) {
|
||||
strbuf_setlen(&count_path, base_path_len);
|
||||
strbuf_addf(&count_path, "%s/", e->d_name);
|
||||
total += (count = count_files(&count_path));
|
||||
|
||||
39
hex-ll.c
39
hex-ll.c
@@ -36,10 +36,45 @@ const signed char hexval_table[256] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* f8-ff */
|
||||
};
|
||||
|
||||
int hex_to_bytes(unsigned char *binary, const char *hex, size_t len)
|
||||
const signed char hexval_lc_table[256] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 00-07 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 08-0f */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 10-17 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 18-1f */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 20-27 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 28-2f */
|
||||
0, 1, 2, 3, 4, 5, 6, 7, /* 30-37 */
|
||||
8, 9, -1, -1, -1, -1, -1, -1, /* 38-3f */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 40-47 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 48-4f */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 50-57 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 58-5f */
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, /* 60-67 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 68-67 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 70-77 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 78-7f */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 80-87 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 88-8f */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 90-97 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* 98-9f */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* a0-a7 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* a8-af */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* b0-b7 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* b8-bf */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* c0-c7 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* c8-cf */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* d0-d7 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* d8-df */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* e0-e7 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* e8-ef */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* f0-f7 */
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, /* f8-ff */
|
||||
};
|
||||
|
||||
int hex_to_bytes(unsigned char *binary, const char *hex, size_t len, enum hexkind kind)
|
||||
{
|
||||
for (; len; len--, hex += 2) {
|
||||
unsigned int val = (hexval(hex[0]) << 4) | hexval(hex[1]);
|
||||
unsigned int val = (hexval(hex[0], kind) << 4) | hexval(hex[1], kind);
|
||||
|
||||
if (val & ~0xff)
|
||||
return -1;
|
||||
|
||||
24
hex-ll.h
24
hex-ll.h
@@ -1,20 +1,32 @@
|
||||
#ifndef HEX_LL_H
|
||||
#define HEX_LL_H
|
||||
|
||||
enum hexkind {
|
||||
HEX_KIND_MIXED = 0,
|
||||
HEX_KIND_LOWER = 1,
|
||||
};
|
||||
|
||||
#ifdef WITH_BREAKING_CHANGES
|
||||
#define HEX_KIND_OID HEX_KIND_LOWER
|
||||
#else
|
||||
#define HEX_KIND_OID HEX_KIND_MIXED
|
||||
#endif
|
||||
|
||||
extern const signed char hexval_table[256];
|
||||
static inline unsigned int hexval(unsigned char c)
|
||||
extern const signed char hexval_lc_table[256];
|
||||
static inline unsigned int hexval(unsigned char c, enum hexkind kind)
|
||||
{
|
||||
return hexval_table[c];
|
||||
return kind == HEX_KIND_MIXED ? hexval_table[c] : hexval_lc_table[c];
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert two consecutive hexadecimal digits into a char. Return a
|
||||
* negative value on error. Don't run over the end of short strings.
|
||||
*/
|
||||
static inline int hex2chr(const char *s)
|
||||
static inline int hex2chr(const char *s, enum hexkind kind)
|
||||
{
|
||||
unsigned int val = hexval(s[0]);
|
||||
return (val & ~0xf) ? val : (val << 4) | hexval(s[1]);
|
||||
unsigned int val = hexval(s[0], kind);
|
||||
return (val & ~0xf) ? val : (val << 4) | hexval(s[1], kind);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -22,6 +34,6 @@ static inline int hex2chr(const char *s)
|
||||
* values to `binary` as `len` bytes. Return 0 on success, or -1 if
|
||||
* the input does not consist of hex digits).
|
||||
*/
|
||||
int hex_to_bytes(unsigned char *binary, const char *hex, size_t len);
|
||||
int hex_to_bytes(unsigned char *binary, const char *hex, size_t len, enum hexkind kind);
|
||||
|
||||
#endif
|
||||
|
||||
2
hex.c
2
hex.c
@@ -9,7 +9,7 @@ static int get_hash_hex_algop(const char *hex, unsigned char *hash,
|
||||
const struct git_hash_algo *algop)
|
||||
{
|
||||
for (size_t i = 0; i < algop->rawsz; i++) {
|
||||
int val = hex2chr(hex);
|
||||
int val = hex2chr(hex, HEX_KIND_OID);
|
||||
if (val < 0)
|
||||
return -1;
|
||||
*hash++ = val;
|
||||
|
||||
@@ -1031,12 +1031,13 @@ static int get_oid_hex_from_objpath(const char *path, struct object_id *oid)
|
||||
if (strlen(path) != the_hash_algo->hexsz + 1)
|
||||
return -1;
|
||||
|
||||
if (hex_to_bytes(oid->hash, path, 1))
|
||||
if (hex_to_bytes(oid->hash, path, 1, HEX_KIND_OID))
|
||||
return -1;
|
||||
path += 2;
|
||||
path++; /* skip '/' */
|
||||
|
||||
return hex_to_bytes(oid->hash + 1, path, the_hash_algo->rawsz - 1);
|
||||
return hex_to_bytes(oid->hash + 1, path, the_hash_algo->rawsz - 1,
|
||||
HEX_KIND_OID);
|
||||
}
|
||||
|
||||
static void process_ls_object(struct remote_ls_ctx *ls)
|
||||
|
||||
@@ -396,7 +396,7 @@ static int decode_q_segment(struct strbuf *out, const struct strbuf *q_seg,
|
||||
int ch, d = *in;
|
||||
if (d == '\n' || !d)
|
||||
break; /* drop trailing newline */
|
||||
ch = hex2chr(in);
|
||||
ch = hex2chr(in, HEX_KIND_MIXED);
|
||||
if (ch >= 0) {
|
||||
strbuf_addch(out, ch);
|
||||
in += 2;
|
||||
|
||||
5
notes.c
5
notes.c
@@ -428,7 +428,7 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
|
||||
goto handle_non_note;
|
||||
|
||||
if (hex_to_bytes(object_oid.hash + prefix_len, entry.path,
|
||||
hashsz - prefix_len))
|
||||
hashsz - prefix_len, HEX_KIND_MIXED))
|
||||
goto handle_non_note; /* entry.path is not a SHA1 */
|
||||
|
||||
memset(object_oid.hash + hashsz, 0, GIT_MAX_RAWSZ - hashsz);
|
||||
@@ -442,7 +442,8 @@ static void load_subtree(struct notes_tree *t, struct leaf_node *subtree,
|
||||
/* internal nodes must be trees */
|
||||
goto handle_non_note;
|
||||
|
||||
if (hex_to_bytes(object_oid.hash + len++, entry.path, 1))
|
||||
if (hex_to_bytes(object_oid.hash + len++, entry.path, 1,
|
||||
HEX_KIND_OID))
|
||||
goto handle_non_note; /* entry.path is not a SHA1 */
|
||||
|
||||
/*
|
||||
|
||||
@@ -1071,7 +1071,7 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr,
|
||||
strbuf_add(path, de->d_name, namelen);
|
||||
if (namelen == algop->hexsz - 2 &&
|
||||
!hex_to_bytes(oid.hash + 1, de->d_name,
|
||||
algop->rawsz - 1)) {
|
||||
algop->rawsz - 1, HEX_KIND_OID)) {
|
||||
oid_set_algo(&oid, algop);
|
||||
memset(oid.hash + algop->rawsz, 0,
|
||||
GIT_MAX_RAWSZ - algop->rawsz);
|
||||
|
||||
@@ -236,17 +236,10 @@ static int parse_oid_prefix(const char *name, int len,
|
||||
{
|
||||
for (int i = 0; i < len; i++) {
|
||||
unsigned char c = name[i];
|
||||
unsigned char val;
|
||||
if (c >= '0' && c <= '9') {
|
||||
val = c - '0';
|
||||
} else if (c >= 'a' && c <= 'f') {
|
||||
val = c - 'a' + 10;
|
||||
} else if (c >= 'A' && c <='F') {
|
||||
val = c - 'A' + 10;
|
||||
c -= 'A' - 'a';
|
||||
} else {
|
||||
int val = hexval(c, HEX_KIND_OID);
|
||||
|
||||
if (val < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hex_out)
|
||||
hex_out[i] = c;
|
||||
|
||||
@@ -378,10 +378,10 @@ int packet_length(const char lenbuf_hex[4], size_t size)
|
||||
{
|
||||
if (size < 4)
|
||||
BUG("buffer too small");
|
||||
return hexval(lenbuf_hex[0]) << 12 |
|
||||
hexval(lenbuf_hex[1]) << 8 |
|
||||
hexval(lenbuf_hex[2]) << 4 |
|
||||
hexval(lenbuf_hex[3]);
|
||||
return hexval(lenbuf_hex[0], HEX_KIND_MIXED) << 12 |
|
||||
hexval(lenbuf_hex[1], HEX_KIND_MIXED) << 8 |
|
||||
hexval(lenbuf_hex[2], HEX_KIND_MIXED) << 4 |
|
||||
hexval(lenbuf_hex[3], HEX_KIND_MIXED);
|
||||
}
|
||||
|
||||
static const char *find_packfile_uri_path(const char *buffer)
|
||||
|
||||
@@ -3636,7 +3636,7 @@ static void append_literal(const char *cp, const char *ep, struct ref_formatting
|
||||
if (cp[1] == '%')
|
||||
cp++;
|
||||
else {
|
||||
int ch = hex2chr(cp + 1);
|
||||
int ch = hex2chr(cp + 1, HEX_KIND_MIXED);
|
||||
if (0 <= ch) {
|
||||
strbuf_addch(s, ch);
|
||||
cp += 3;
|
||||
|
||||
2
strbuf.c
2
strbuf.c
@@ -457,7 +457,7 @@ size_t strbuf_expand_literal(struct strbuf *sb, const char *placeholder)
|
||||
return 1;
|
||||
case 'x':
|
||||
/* %x00 == NUL, %x0a == LF, etc. */
|
||||
ch = hex2chr(placeholder + 1);
|
||||
ch = hex2chr(placeholder + 1, HEX_KIND_MIXED);
|
||||
if (ch < 0)
|
||||
return 0;
|
||||
strbuf_addch(sb, ch);
|
||||
|
||||
@@ -60,6 +60,11 @@ test_expect_success 'works with one good rev' '
|
||||
test "$rev_head" = "$HASH4"
|
||||
'
|
||||
|
||||
test_expect_success WITH_BREAKING_CHANGES 'rejects uppercase revs' '
|
||||
UC_HASH=$(echo "$HASH1" | tr a-f A-F) &&
|
||||
test_must_fail git rev-parse --verify "$UC_HASH"
|
||||
'
|
||||
|
||||
test_expect_success 'fails with any bad rev or many good revs' '
|
||||
test_must_fail git rev-parse --verify 2>error &&
|
||||
test_grep "single revision" error &&
|
||||
|
||||
@@ -349,7 +349,7 @@ test_expect_success 'verify after commit-graph-chain corruption (base)' '
|
||||
test_must_fail git commit-graph verify 2>test_err &&
|
||||
grep -v "^+" test_err >err &&
|
||||
test_grep "invalid commit-graph chain" err &&
|
||||
corrupt_file "$graphdir/commit-graph-chain" 30 "A" &&
|
||||
corrupt_file "$graphdir/commit-graph-chain" 30 "a" &&
|
||||
test_must_fail git commit-graph verify 2>test_err &&
|
||||
grep -v "^+" test_err >err &&
|
||||
test_grep "unable to find all commit-graph files" err
|
||||
@@ -364,7 +364,7 @@ test_expect_success 'verify after commit-graph-chain corruption (tip)' '
|
||||
test_must_fail git commit-graph verify 2>test_err &&
|
||||
grep -v "^+" test_err >err &&
|
||||
test_grep "invalid commit-graph chain" err &&
|
||||
corrupt_file "$graphdir/commit-graph-chain" 70 "A" &&
|
||||
corrupt_file "$graphdir/commit-graph-chain" 70 "b" &&
|
||||
test_must_fail git commit-graph verify 2>test_err &&
|
||||
grep -v "^+" test_err >err &&
|
||||
test_grep "unable to find all commit-graph files" err
|
||||
|
||||
2
url.c
2
url.c
@@ -62,7 +62,7 @@ static char *url_decode_internal(const char **query, int len,
|
||||
}
|
||||
|
||||
if (c == '%' && (len < 0 || len >= 3)) {
|
||||
int val = hex2chr(q + 1);
|
||||
int val = hex2chr(q + 1, HEX_KIND_MIXED);
|
||||
if (0 < val) {
|
||||
strbuf_addch(out, val);
|
||||
q += 3;
|
||||
|
||||
@@ -50,7 +50,7 @@ static int append_normalized_escapes(struct strbuf *buf,
|
||||
if (ch == '%') {
|
||||
if (from_len < 2)
|
||||
return 0;
|
||||
ch = hex2chr(from);
|
||||
ch = hex2chr(from, HEX_KIND_MIXED);
|
||||
if (ch < 0)
|
||||
return 0;
|
||||
from += 2;
|
||||
|
||||
Reference in New Issue
Block a user