public inbox for git@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1] path-walk: fix NULL pointer dereference in error message
@ 2026-03-20 11:48 Yuvraj Singh Chauhan
  2026-03-20 15:16 ` D. Ben Knoble
  0 siblings, 1 reply; 7+ messages in thread
From: Yuvraj Singh Chauhan @ 2026-03-20 11:48 UTC (permalink / raw)
  To: git; +Cc: christian.couder, stolee, Yuvraj Singh Chauhan

When lookup_tree() or lookup_blob() cannot find a tree entry's object,
'o' is set to NULL via:

    o = child ? &child->object : NULL;

The subsequent null-check catches this correctly, but then dereferences
'o' to format the error message:

    error(_("failed to find object %s"), oid_to_hex(&o->oid));

This causes a segfault instead of the intended diagnostic output.

Fix this by using &entry.oid instead. 'entry' is the struct name_entry
populated by tree_entry() on each loop iteration and holds the OID of
the failing lookup -- which is exactly what the error should report.

This crash is reachable via git-backfill(1) when a tree entry's object
is absent from the local object database.

Signed-off-by: Yuvraj Singh Chauhan <ysinghcin@gmail.com>
---
 path-walk.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/path-walk.c b/path-walk.c
index 364e4cfa19..839582380c 100644
--- a/path-walk.c
+++ b/path-walk.c
@@ -171,7 +171,7 @@ static int add_tree_entries(struct path_walk_context *ctx,
 
 		if (!o) {
 			error(_("failed to find object %s"),
-			      oid_to_hex(&o->oid));
+			      oid_to_hex(&entry.oid));
 			return -1;
 		}
 
-- 
2.53.0.582.gca1db8a0f7


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v1] path-walk: fix NULL pointer dereference in error message
  2026-03-20 11:48 [PATCH v1] path-walk: fix NULL pointer dereference in error message Yuvraj Singh Chauhan
@ 2026-03-20 15:16 ` D. Ben Knoble
  2026-03-20 16:14   ` Derrick Stolee
                     ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: D. Ben Knoble @ 2026-03-20 15:16 UTC (permalink / raw)
  To: Yuvraj Singh Chauhan; +Cc: git, christian.couder, stolee

On Fri, Mar 20, 2026 at 7:50 AM Yuvraj Singh Chauhan
<ysinghcin@gmail.com> wrote:
>
> When lookup_tree() or lookup_blob() cannot find a tree entry's object,
> 'o' is set to NULL via:
>
>     o = child ? &child->object : NULL;
>
> The subsequent null-check catches this correctly, but then dereferences
> 'o' to format the error message:
>
>     error(_("failed to find object %s"), oid_to_hex(&o->oid));
>
> This causes a segfault instead of the intended diagnostic output.
>
> Fix this by using &entry.oid instead. 'entry' is the struct name_entry
> populated by tree_entry() on each loop iteration and holds the OID of
> the failing lookup -- which is exactly what the error should report.
>
> This crash is reachable via git-backfill(1) when a tree entry's object
> is absent from the local object database.
>
> Signed-off-by: Yuvraj Singh Chauhan <ysinghcin@gmail.com>
> ---
>  path-walk.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/path-walk.c b/path-walk.c
> index 364e4cfa19..839582380c 100644
> --- a/path-walk.c
> +++ b/path-walk.c
> @@ -171,7 +171,7 @@ static int add_tree_entries(struct path_walk_context *ctx,
>
>                 if (!o) {
>                         error(_("failed to find object %s"),
> -                             oid_to_hex(&o->oid));
> +                             oid_to_hex(&entry.oid));
>                         return -1;
>                 }
>
> --
> 2.53.0.582.gca1db8a0f7

Interesting find. I was hoping to see an easy way to reproduce hitting
this code, and after grepping around a bit I found a few places that
end up in this code (git-backfill and git-repo being the primary
callers of walk_objects_by_path), but on second glance I think "!o" is
current dead code.

When we compute "child" in either preceding branch using lookup_tree
or lookup_blob, we only return NULL if !quiet in the object_as_type
calls (assuming we hit the "else" case there, anyway). But quiet==0 in
both callers along this path, so !quiet will be truthy and we'll
error() out there instead, never returning to add_tree_entries.

Since I didn't quickly come up with a reproduction, I can't quite
prove this, anyway. It's also possible my analysis is based on code
that has since changed (I happened to have a537e3e6e9 (Merge branch
'sp/send-email-validate-charset' into next, 2026-03-06) checked out at
the moment).

Still, fixing such obviously wrong dereference is good, but I wonder
if we should go further?

You mentioned git-backfill with a tree missing from the local odb; do
you have a short reproduction script or test-case?

-- 
D. Ben Knoble

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v1] path-walk: fix NULL pointer dereference in error message
  2026-03-20 15:16 ` D. Ben Knoble
@ 2026-03-20 16:14   ` Derrick Stolee
  2026-03-23  9:45     ` Yuvraj Singh Chauhan
  2026-03-20 17:08   ` Junio C Hamano
  2026-03-20 18:54   ` René Scharfe
  2 siblings, 1 reply; 7+ messages in thread
From: Derrick Stolee @ 2026-03-20 16:14 UTC (permalink / raw)
  To: D. Ben Knoble, Yuvraj Singh Chauhan; +Cc: git, christian.couder

On 3/20/2026 11:16 AM, D. Ben Knoble wrote:
> On Fri, Mar 20, 2026 at 7:50 AM Yuvraj Singh Chauhan
> <ysinghcin@gmail.com> wrote:
>> @@ -171,7 +171,7 @@ static int add_tree_entries(struct path_walk_context *ctx,
>>
>>                 if (!o) {
>>                         error(_("failed to find object %s"),
>> -                             oid_to_hex(&o->oid));
>> +                             oid_to_hex(&entry.oid));
>>                         return -1;
>>                 }
>>
>> --
>> 2.53.0.582.gca1db8a0f7
> 
> Interesting find. I was hoping to see an easy way to reproduce hitting
> this code, and after grepping around a bit I found a few places that
> end up in this code (git-backfill and git-repo being the primary
> callers of walk_objects_by_path), but on second glance I think "!o" is
> current dead code.

I can appreciate that the existing code is clearly incorrect, so
tooling scanning code for defects would find this even if we can't
easily create a test case to demonstrate it.
 
> Still, fixing such obviously wrong dereference is good, but I wonder
> if we should go further?
> 
> You mentioned git-backfill with a tree missing from the local odb; do
> you have a short reproduction script or test-case?

I imagine that it would be difficult to set up such a case, but maybe
it would follow these steps (based on existing 'git backfill' tests
that start with a partial clone):

1. Make a bare, blobless partial clone of the server repo.

2. Explode the client repo's object store into loose objects.

3. Delete a loose tree object, but one that isn't a commit's root
   tree. It must be a child tree.

In this case, we should hit this issue. Blobless partial clones
expect all reachable trees to exist locally and so are not prepared
to download missing trees on-demand.

Thanks,
-Stolee


 


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v1] path-walk: fix NULL pointer dereference in error message
  2026-03-20 15:16 ` D. Ben Knoble
  2026-03-20 16:14   ` Derrick Stolee
@ 2026-03-20 17:08   ` Junio C Hamano
  2026-03-20 18:54   ` René Scharfe
  2 siblings, 0 replies; 7+ messages in thread
From: Junio C Hamano @ 2026-03-20 17:08 UTC (permalink / raw)
  To: D. Ben Knoble; +Cc: Yuvraj Singh Chauhan, git, christian.couder, stolee

"D. Ben Knoble" <ben.knoble@gmail.com> writes:

> You mentioned git-backfill with a tree missing from the local odb; do
> you have a short reproduction script or test-case?

Interesting thing to ask.  THe code looks correct, though.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v1] path-walk: fix NULL pointer dereference in error message
  2026-03-20 15:16 ` D. Ben Knoble
  2026-03-20 16:14   ` Derrick Stolee
  2026-03-20 17:08   ` Junio C Hamano
@ 2026-03-20 18:54   ` René Scharfe
  2026-03-22 14:21     ` D. Ben Knoble
  2 siblings, 1 reply; 7+ messages in thread
From: René Scharfe @ 2026-03-20 18:54 UTC (permalink / raw)
  To: D. Ben Knoble, Yuvraj Singh Chauhan; +Cc: git, christian.couder, stolee

On 3/20/26 4:16 PM, D. Ben Knoble wrote:
> 
> When we compute "child" in either preceding branch using lookup_tree
> or lookup_blob, we only return NULL if !quiet in the object_as_type
> calls (assuming we hit the "else" case there, anyway). But quiet==0 in
> both callers along this path, so !quiet will be truthy and we'll
> error() out there instead, never returning to add_tree_entries.

error() just prints a message, it doesn't end the program.

> Since I didn't quickly come up with a reproduction, I can't quite
> prove this, anyway. It's also possible my analysis is based on code
> that has since changed (I happened to have a537e3e6e9 (Merge branch
> 'sp/send-email-validate-charset' into next, 2026-03-06) checked out at
> the moment).

We could build a tree referencing an object using a mismatched
type to hit that.  It's possible by removing the type check from
builtin/mktree.c:mktree_line(), then using the resulting twisted tool:

   $ commit=$(git rev-parse HEAD)
   $ tree=$(printf "100644 blob $commit\tcommit\n" | git_evil mktree)

> Still, fixing such obviously wrong dereference is good, but I wonder
> if we should go further?
> 
> You mentioned git-backfill with a tree missing from the local odb; do
> you have a short reproduction script or test-case?

I don't know about backfill, but this would work:

  $ echo $tree | git pack-objects --path-walk --all foo

René


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v1] path-walk: fix NULL pointer dereference in error message
  2026-03-20 18:54   ` René Scharfe
@ 2026-03-22 14:21     ` D. Ben Knoble
  0 siblings, 0 replies; 7+ messages in thread
From: D. Ben Knoble @ 2026-03-22 14:21 UTC (permalink / raw)
  To: René Scharfe; +Cc: Yuvraj Singh Chauhan, git, christian.couder, stolee

On Fri, Mar 20, 2026 at 2:54 PM René Scharfe <l.s.r@web.de> wrote:
>
> On 3/20/26 4:16 PM, D. Ben Knoble wrote:
> >
> > When we compute "child" in either preceding branch using lookup_tree
> > or lookup_blob, we only return NULL if !quiet in the object_as_type
> > calls (assuming we hit the "else" case there, anyway). But quiet==0 in
> > both callers along this path, so !quiet will be truthy and we'll
> > error() out there instead, never returning to add_tree_entries.
>
> error() just prints a message, it doesn't end the program.

Ah, thanks! The rest is probably moot then.

>
> > Since I didn't quickly come up with a reproduction, I can't quite
> > prove this, anyway. It's also possible my analysis is based on code
> > that has since changed (I happened to have a537e3e6e9 (Merge branch
> > 'sp/send-email-validate-charset' into next, 2026-03-06) checked out at
> > the moment).
>
> We could build a tree referencing an object using a mismatched
> type to hit that.  It's possible by removing the type check from
> builtin/mktree.c:mktree_line(), then using the resulting twisted tool:
>
>    $ commit=$(git rev-parse HEAD)
>    $ tree=$(printf "100644 blob $commit\tcommit\n" | git_evil mktree)
>
> > Still, fixing such obviously wrong dereference is good, but I wonder
> > if we should go further?
> >
> > You mentioned git-backfill with a tree missing from the local odb; do
> > you have a short reproduction script or test-case?
>
> I don't know about backfill, but this would work:
>
>   $ echo $tree | git pack-objects --path-walk --all foo
>
> René
>

Thanks all.

-- 
D. Ben Knoble

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v1] path-walk: fix NULL pointer dereference in error message
  2026-03-20 16:14   ` Derrick Stolee
@ 2026-03-23  9:45     ` Yuvraj Singh Chauhan
  0 siblings, 0 replies; 7+ messages in thread
From: Yuvraj Singh Chauhan @ 2026-03-23  9:45 UTC (permalink / raw)
  To: Derrick Stolee; +Cc: D. Ben Knoble, git, christian.couder

On Fri, Mar 20, 2026 at 12:14:19PM -0400, Derrick Stolee wrote:
> On 3/20/2026 11:16 AM, D. Ben Knoble wrote:
> > On Fri, Mar 20, 2026 at 7:50 AM Yuvraj Singh Chauhan
> > <ysinghcin@gmail.com> wrote:
> >> @@ -171,7 +171,7 @@ static int add_tree_entries(struct path_walk_context *ctx,
> >>
> >>                 if (!o) {
> >>                         error(_("failed to find object %s"),
> >> -                             oid_to_hex(&o->oid));
> >> +                             oid_to_hex(&entry.oid));
> >>                         return -1;
> >>                 }
> >>
> >> --
> >> 2.53.0.582.gca1db8a0f7
> > 
> > Interesting find. I was hoping to see an easy way to reproduce hitting
> > this code, and after grepping around a bit I found a few places that
> > end up in this code (git-backfill and git-repo being the primary
> > callers of walk_objects_by_path), but on second glance I think "!o" is
> > current dead code.
> 
> I can appreciate that the existing code is clearly incorrect, so
> tooling scanning code for defects would find this even if we can't
> easily create a test case to demonstrate it.
>  
> > Still, fixing such obviously wrong dereference is good, but I wonder
> > if we should go further?
> > 
> > You mentioned git-backfill with a tree missing from the local odb; do
> > you have a short reproduction script or test-case?
> 
> I imagine that it would be difficult to set up such a case, but maybe
> it would follow these steps (based on existing 'git backfill' tests
> that start with a partial clone):
> 
> 1. Make a bare, blobless partial clone of the server repo.
> 
> 2. Explode the client repo's object store into loose objects.
> 
> 3. Delete a loose tree object, but one that isn't a commit's root
>    tree. It must be a child tree.
> 
> In this case, we should hit this issue. Blobless partial clones
> expect all reachable trees to exist locally and so are not prepared
> to download missing trees on-demand.
> 
> Thanks,
> -Stolee

Thanks for the suggestions on how to reproduce this.
I traced through the code paths and believe the scenario described
(blobless partial clone, explode objects, delete a child tree) would
not actually reach the '!o' branch. Here is my reasoning:

When add_tree_entries() encounters a child tree entry whose OID is
missing from the ODB, it calls lookup_tree(). Since the OID was never
previously registered in the parsed object hash, lookup_object()
returns NULL, and lookup_tree() falls through to create_object() which
allocates a shell object. So 'child' is non-NULL, 'o' is non-NULL, 
and the '!o' check is not reached.
The missing object would instead fail later: when the path-walk tries
to visit the child tree via a subsequent add_tree_entries() call,
repo_parse_tree_gently() attempts to read it from the ODB, fails, and
returns the "bad tree object" error at the top of the function.

The '!o' path is reachable when the OID in a tree entry was
"previously registered" in the parsed object hash with a different
type. In that case, lookup_blob() or lookup_tree() calls
object_as_type(), which detects the type conflict and returns NULL.
This is what happens with a corrupt/confused tree that references a
commit OID as a blob entry, the commit was already registered during
the revision walk, so object_as_type(obj, OBJ_BLOB, 0) returns NULL.
For v2, I've added a test that exercises exactly this path:
    # Create a tree with a blob entry pointing to a commit object
    commit=$(git rev-parse HEAD)
    bad_tree=$(perl -e 'print "100644 confused\0" . pack("H*", $ARGV[0])' \
    "$commit" | git hash-object -w --stdin -t tree)
    git pack-objects --path-walk --all /tmp/test-pack <<< "$bad_tree"
This constructs a tree where mode 100644 (blob) has a commit OID.
During --path-walk, the commit is registered as OBJ_COMMIT by the
revision walk via --all, so when the tree entry is processed,
lookup_blob() → object_as_type() returns NULL, triggering the bug.

Please review

Sincerely,
Yuvraj

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-03-23  9:45 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-20 11:48 [PATCH v1] path-walk: fix NULL pointer dereference in error message Yuvraj Singh Chauhan
2026-03-20 15:16 ` D. Ben Knoble
2026-03-20 16:14   ` Derrick Stolee
2026-03-23  9:45     ` Yuvraj Singh Chauhan
2026-03-20 17:08   ` Junio C Hamano
2026-03-20 18:54   ` René Scharfe
2026-03-22 14:21     ` D. Ben Knoble

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox