Skip to content

Commit b2755c1

Browse files
pks-tgitster
authored andcommitted
hash: provide generic wrappers to update hash contexts
The hash context is supposed to be updated via the `git_hash_algo` structure, which contains a list of function pointers to update, clone or finalize a hashing context. This requires the callers to track which algorithm was used to initialize the context and continue to use the exact same algorithm. If they fail to do that correctly, it can happen that we start to access context state of one hash algorithm with functions of a different hash algorithm. The result would typically be a segfault, as could be seen e.g. in the patches part of 9842294 (Merge branch 'ps/weak-sha1-for-tail-sum-fix', 2025-01-01). The situation was significantly improved starting with 04292c3 (hash.h: drop unsafe_ function variants, 2025-01-23) and its parent commits. These refactorings ensure that it is not possible to mix up safe and unsafe variants of the same hash algorithm anymore. But in theory, it is still possible to mix up different hash algorithms with each other, even though this is a lot less likely to happen. But still, we can do better: instead of asking the caller to remember the hash algorithm used to initialize a context, we can instead make the context itself remember which algorithm it has been initialized with. If we do so, callers can use a set of generic helpers to update the context and don't need to be aware of the hash algorithm at all anymore. Adapt the context initialization functions to store the hash algorithm in the hashing context and introduce these generic helpers. Callers will be adapted in the subsequent commit. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 7346e34 commit b2755c1

File tree

2 files changed

+27
-0
lines changed

2 files changed

+27
-0
lines changed

hash.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ enum get_oid_result {
235235

236236
/* A suitably aligned type for stack allocations of hash contexts. */
237237
struct git_hash_ctx {
238+
const struct git_hash_algo *algop;
238239
union {
239240
git_SHA_CTX sha1;
240241
git_SHA_CTX_unsafe sha1_unsafe;
@@ -296,6 +297,26 @@ struct git_hash_algo {
296297
};
297298
extern const struct git_hash_algo hash_algos[GIT_HASH_NALGOS];
298299

300+
static inline void git_hash_clone(struct git_hash_ctx *dst, const struct git_hash_ctx *src)
301+
{
302+
src->algop->clone_fn(dst, src);
303+
}
304+
305+
static inline void git_hash_update(struct git_hash_ctx *ctx, const void *in, size_t len)
306+
{
307+
ctx->algop->update_fn(ctx, in, len);
308+
}
309+
310+
static inline void git_hash_final(unsigned char *hash, struct git_hash_ctx *ctx)
311+
{
312+
ctx->algop->final_fn(hash, ctx);
313+
}
314+
315+
static inline void git_hash_final_oid(struct object_id *oid, struct git_hash_ctx *ctx)
316+
{
317+
ctx->algop->final_oid_fn(oid, ctx);
318+
}
319+
299320
/*
300321
* Return a GIT_HASH_* constant based on the name. Returns GIT_HASH_UNKNOWN if
301322
* the name doesn't match a known algorithm.

object-file.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,13 @@ static const struct object_id null_oid_sha256 = {
8888

8989
static void git_hash_sha1_init(struct git_hash_ctx *ctx)
9090
{
91+
ctx->algop = &hash_algos[GIT_HASH_SHA1];
9192
git_SHA1_Init(&ctx->state.sha1);
9293
}
9394

9495
static void git_hash_sha1_clone(struct git_hash_ctx *dst, const struct git_hash_ctx *src)
9596
{
97+
dst->algop = src->algop;
9698
git_SHA1_Clone(&dst->state.sha1, &src->state.sha1);
9799
}
98100

@@ -115,11 +117,13 @@ static void git_hash_sha1_final_oid(struct object_id *oid, struct git_hash_ctx *
115117

116118
static void git_hash_sha1_init_unsafe(struct git_hash_ctx *ctx)
117119
{
120+
ctx->algop = unsafe_hash_algo(&hash_algos[GIT_HASH_SHA1]);
118121
git_SHA1_Init_unsafe(&ctx->state.sha1_unsafe);
119122
}
120123

121124
static void git_hash_sha1_clone_unsafe(struct git_hash_ctx *dst, const struct git_hash_ctx *src)
122125
{
126+
dst->algop = src->algop;
123127
git_SHA1_Clone_unsafe(&dst->state.sha1_unsafe, &src->state.sha1_unsafe);
124128
}
125129

@@ -143,11 +147,13 @@ static void git_hash_sha1_final_oid_unsafe(struct object_id *oid, struct git_has
143147

144148
static void git_hash_sha256_init(struct git_hash_ctx *ctx)
145149
{
150+
ctx->algop = unsafe_hash_algo(&hash_algos[GIT_HASH_SHA256]);
146151
git_SHA256_Init(&ctx->state.sha256);
147152
}
148153

149154
static void git_hash_sha256_clone(struct git_hash_ctx *dst, const struct git_hash_ctx *src)
150155
{
156+
dst->algop = src->algop;
151157
git_SHA256_Clone(&dst->state.sha256, &src->state.sha256);
152158
}
153159

0 commit comments

Comments
 (0)