diff options
| author | Junio C Hamano <gitster@pobox.com> | 2025-01-28 13:02:23 -0800 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2025-01-28 13:02:23 -0800 |
| commit | f8b9821f7d4f5239911794d03ac74edf27d711e6 (patch) | |
| tree | 4cf87268de803d58cef4c03bcc685fbd1657bf4c | |
| parent | 3ddeb7f3373ae0e309d9df62ada24375afa456c7 (diff) | |
| parent | 98046591b96a213e05d17569b1645e772df91b90 (diff) | |
| download | git-f8b9821f7d4f5239911794d03ac74edf27d711e6.tar.gz | |
Merge branch 'jk/pack-header-parse-alignment-fix'
It was possible for "git unpack-objects" and "git index-pack" to
make an unaligned access, which has been corrected.
* jk/pack-header-parse-alignment-fix:
index-pack, unpack-objects: use skip_prefix to avoid magic number
index-pack, unpack-objects: use get_be32() for reading pack header
parse_pack_header_option(): avoid unaligned memory writes
packfile: factor out --pack_header argument parsing
bswap.h: squelch potential sparse -Wcast-truncate warnings
| -rw-r--r-- | builtin/index-pack.c | 30 | ||||
| -rw-r--r-- | builtin/unpack-objects.c | 31 | ||||
| -rw-r--r-- | compat/bswap.h | 24 | ||||
| -rw-r--r-- | pack.h | 3 | ||||
| -rw-r--r-- | packfile.c | 20 | ||||
| -rw-r--r-- | packfile.h | 6 |
6 files changed, 64 insertions, 50 deletions
diff --git a/builtin/index-pack.c b/builtin/index-pack.c index 7025c32fbb..6ffbb7ce35 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -380,16 +380,18 @@ static const char *open_pack_file(const char *pack_name) static void parse_pack_header(void) { - struct pack_header *hdr = fill(sizeof(struct pack_header)); + unsigned char *hdr = fill(sizeof(struct pack_header)); /* Header consistency check */ - if (hdr->hdr_signature != htonl(PACK_SIGNATURE)) + if (get_be32(hdr) != PACK_SIGNATURE) die(_("pack signature mismatch")); - if (!pack_version_ok(hdr->hdr_version)) + hdr += 4; + if (!pack_version_ok_native(get_be32(hdr))) die(_("pack version %"PRIu32" unsupported"), - ntohl(hdr->hdr_version)); + get_be32(hdr)); + hdr += 4; - nr_objects = ntohl(hdr->hdr_entries); + nr_objects = get_be32(hdr); use(sizeof(struct pack_header)); } @@ -1956,19 +1958,11 @@ int cmd_index_pack(int argc, warning(_("no threads support, ignoring %s"), arg); nr_threads = 1; } - } else if (starts_with(arg, "--pack_header=")) { - struct pack_header *hdr; - char *c; - - hdr = (struct pack_header *)input_buffer; - hdr->hdr_signature = htonl(PACK_SIGNATURE); - hdr->hdr_version = htonl(strtoul(arg + 14, &c, 10)); - if (*c != ',') - die(_("bad %s"), arg); - hdr->hdr_entries = htonl(strtoul(c + 1, &c, 10)); - if (*c) - die(_("bad %s"), arg); - input_len = sizeof(*hdr); + } else if (skip_prefix(arg, "--pack_header=", &arg)) { + if (parse_pack_header_option(arg, + input_buffer, + &input_len) < 0) + die(_("bad --pack_header: %s"), arg); } else if (!strcmp(arg, "-v")) { verbose = 1; } else if (!strcmp(arg, "--progress-title")) { diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c index a1c28e97e7..f6b9825fb0 100644 --- a/builtin/unpack-objects.c +++ b/builtin/unpack-objects.c @@ -18,6 +18,7 @@ #include "progress.h" #include "decorate.h" #include "fsck.h" +#include "packfile.h" static int dry_run, quiet, recover, has_errors, strict; static const char unpack_usage[] = "git unpack-objects [-n] [-q] [-r] [--strict]"; @@ -578,15 +579,16 @@ static void unpack_one(unsigned nr) static void unpack_all(void) { int i; - struct pack_header *hdr = fill(sizeof(struct pack_header)); + unsigned char *hdr = fill(sizeof(struct pack_header)); - nr_objects = ntohl(hdr->hdr_entries); - - if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE) + if (get_be32(hdr) != PACK_SIGNATURE) die("bad pack file"); - if (!pack_version_ok(hdr->hdr_version)) + hdr += 4; + if (!pack_version_ok_native(get_be32(hdr))) die("unknown pack file version %"PRIu32, - ntohl(hdr->hdr_version)); + get_be32(hdr)); + hdr += 4; + nr_objects = get_be32(hdr); use(sizeof(struct pack_header)); if (!quiet) @@ -647,19 +649,10 @@ int cmd_unpack_objects(int argc, fsck_set_msg_types(&fsck_options, arg); continue; } - if (starts_with(arg, "--pack_header=")) { - struct pack_header *hdr; - char *c; - - hdr = (struct pack_header *)buffer; - hdr->hdr_signature = htonl(PACK_SIGNATURE); - hdr->hdr_version = htonl(strtoul(arg + 14, &c, 10)); - if (*c != ',') - die("bad %s", arg); - hdr->hdr_entries = htonl(strtoul(c + 1, &c, 10)); - if (*c) - die("bad %s", arg); - len = sizeof(*hdr); + if (skip_prefix(arg, "--pack_header=", &arg)) { + if (parse_pack_header_option(arg, + buffer, &len) < 0) + die(_("bad --pack_header: %s"), arg); continue; } if (skip_prefix(arg, "--max-input-size=", &arg)) { diff --git a/compat/bswap.h b/compat/bswap.h index 512f6f4b99..b34054f2bd 100644 --- a/compat/bswap.h +++ b/compat/bswap.h @@ -171,23 +171,23 @@ static inline uint64_t get_be64(const void *ptr) static inline void put_be32(void *ptr, uint32_t value) { unsigned char *p = ptr; - p[0] = value >> 24; - p[1] = value >> 16; - p[2] = value >> 8; - p[3] = value >> 0; + p[0] = (value >> 24) & 0xff; + p[1] = (value >> 16) & 0xff; + p[2] = (value >> 8) & 0xff; + p[3] = (value >> 0) & 0xff; } static inline void put_be64(void *ptr, uint64_t value) { unsigned char *p = ptr; - p[0] = value >> 56; - p[1] = value >> 48; - p[2] = value >> 40; - p[3] = value >> 32; - p[4] = value >> 24; - p[5] = value >> 16; - p[6] = value >> 8; - p[7] = value >> 0; + p[0] = (value >> 56) & 0xff; + p[1] = (value >> 48) & 0xff; + p[2] = (value >> 40) & 0xff; + p[3] = (value >> 32) & 0xff; + p[4] = (value >> 24) & 0xff; + p[5] = (value >> 16) & 0xff; + p[6] = (value >> 8) & 0xff; + p[7] = (value >> 0) & 0xff; } #endif /* COMPAT_BSWAP_H */ @@ -13,7 +13,8 @@ struct repository; */ #define PACK_SIGNATURE 0x5041434b /* "PACK" */ #define PACK_VERSION 2 -#define pack_version_ok(v) ((v) == htonl(2) || (v) == htonl(3)) +#define pack_version_ok(v) pack_version_ok_native(ntohl(v)) +#define pack_version_ok_native(v) ((v) == 2 || (v) == 3) struct pack_header { uint32_t hdr_signature; uint32_t hdr_version; diff --git a/packfile.c b/packfile.c index cc7ab6403a..2d80d80cb3 100644 --- a/packfile.c +++ b/packfile.c @@ -2315,3 +2315,23 @@ int is_promisor_object(struct repository *r, const struct object_id *oid) } return oidset_contains(&promisor_objects, oid); } + +int parse_pack_header_option(const char *in, unsigned char *out, unsigned int *len) +{ + unsigned char *hdr; + char *c; + + hdr = out; + put_be32(hdr, PACK_SIGNATURE); + hdr += 4; + put_be32(hdr, strtoul(in, &c, 10)); + hdr += 4; + if (*c != ',') + return -1; + put_be32(hdr, strtoul(c + 1, &c, 10)); + hdr += 4; + if (*c) + return -1; + *len = hdr - out; + return 0; +} diff --git a/packfile.h b/packfile.h index 58104fa009..00ada7a938 100644 --- a/packfile.h +++ b/packfile.h @@ -216,4 +216,10 @@ int is_promisor_object(struct repository *r, const struct object_id *oid); int load_idx(const char *path, const unsigned int hashsz, void *idx_map, size_t idx_size, struct packed_git *p); +/* + * Parse a --pack_header option as accepted by index-pack and unpack-objects, + * turning it into the matching bytes we'd find in a pack. + */ +int parse_pack_header_option(const char *in, unsigned char *out, unsigned int *len); + #endif |
