]> git.ipfire.org Git - thirdparty/git.git/commitdiff
receive-pack: fix crash on out-of-namespace symref
authorTroels Thomsen <troels@thomsen.io>
Sat, 27 Dec 2025 15:40:14 +0000 (15:40 +0000)
committerJunio C Hamano <gitster@pobox.com>
Sun, 28 Dec 2025 05:05:41 +0000 (14:05 +0900)
`check_aliased_update_internal()` detects when a symbolic ref and its
target are being updated in the same push. It does this by building a
list of ref names without the optional namespace prefix. When a symbolic
ref within a namespace points to a ref outside the namespace,
`strip_namespace()` returns NULL which leads to a segfault.

A NULL check preventing this particular issue was repurposed in
ded8393610. Rather than reintroducing it, we can instead build a list of
fully qualified ref names. This prevents the crash, preserves the
consistency check from da3efdb17b, and allows updates to all symbolic
refs.

Signed-off-by: Troels Thomsen <troels@thomsen.io>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/receive-pack.c
t/t5509-fetch-push-namespaces.sh

index c9288a9c7e382bd19193d8b94268e0d0bec2c7f8..cfb17f9352fd2e498975f5d96cc5bda816c98b9b 100644 (file)
@@ -1685,7 +1685,6 @@ static void check_aliased_update_internal(struct command *cmd,
                cmd->error_string = "broken symref";
                return;
        }
-       dst_name = strip_namespace(dst_name);
 
        if (!(item = string_list_lookup(list, dst_name)))
                return;
@@ -1730,10 +1729,13 @@ static void check_aliased_updates(struct command *commands)
 {
        struct command *cmd;
        struct string_list ref_list = STRING_LIST_INIT_NODUP;
+       struct strbuf ref_name = STRBUF_INIT;
 
        for (cmd = commands; cmd; cmd = cmd->next) {
-               struct string_list_item *item =
-                       string_list_append(&ref_list, cmd->ref_name);
+               struct string_list_item *item;
+               strbuf_reset(&ref_name);
+               strbuf_addf(&ref_name, "%s%s", get_git_namespace(), cmd->ref_name);
+               item = string_list_append(&ref_list, ref_name.buf);
                item->util = (void *)cmd;
        }
        string_list_sort(&ref_list);
@@ -1743,6 +1745,7 @@ static void check_aliased_updates(struct command *commands)
                        check_aliased_update(cmd, &ref_list);
        }
 
+       strbuf_release(&ref_name);
        string_list_clear(&ref_list, 0);
 }
 
index 095df1a7535d5793c7500e87f54b8ffc93a901d4..3c333ccc5f97e22b16e179f3ffeccadb2468123b 100755 (executable)
@@ -175,4 +175,17 @@ test_expect_success 'denyCurrentBranch and unborn branch with ref namespace' '
        )
 '
 
+test_expect_success 'pushing to symref pointing outside the namespace' '
+       (
+               cd pushee &&
+               git symbolic-ref refs/namespaces/namespace/refs/heads/main refs/heads/main &&
+               cd ../original &&
+               git push pushee-namespaced main &&
+               git ls-remote pushee-unnamespaced refs/heads/main >actual &&
+               printf "$commit1\trefs/heads/main\n" >expected &&
+               printf "$commit1\trefs/namespaces/namespace/refs/heads/main\n" >>expected &&
+               test_cmp expected actual
+       )
+'
+
 test_done