From 3c8913bbc676603072b03d568438e5bbafbc83b4 Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Fri, 16 Oct 2026 06:09:53 -1000 Subject: Gate a readme ending in a colon like a disk path trust-scan-config passed any readme holding a colon as a tracked file, while the parser takes one only when a path follows the colon, so a scanned repository could still name a file on disk outside itself. The two now share one test. --- source/cgit.c | 6 ++---- source/scan-tree.c | 6 +++--- source/shared.c | 7 +++++++ source/shared.h | 6 ++++++ 4 files changed, 18 insertions(+), 7 deletions(-) (limited to 'source') diff --git a/source/cgit.c b/source/cgit.c index 633b011..82c496e 100644 --- a/source/cgit.c +++ b/source/cgit.c @@ -1035,10 +1035,8 @@ static void parse_readme(const char *readme, char **filename, char **ref, struct if (!readme || !readme[0]) return; - // A colon separates a ref from a path, so a setting carrying one names - // a file tracked in the repository rather than one on disk. - colon = strchr(readme, ':'); - if (colon && strlen(colon) > 1) { + if (cgit_readme_is_tracked(readme)) { + colon = strchr(readme, ':'); if (colon == readme && ctx.qry.head) *ref = xstrdup(ctx.qry.head); else if (colon == readme && repo->defbranch) diff --git a/source/scan-tree.c b/source/scan-tree.c index 035e4e1..b941ec5 100644 --- a/source/scan-tree.c +++ b/source/scan-tree.c @@ -52,8 +52,8 @@ static int is_git_dir(const char *path) * A repository's own files belong to whoever can push to it, so the keys * that run a command, put raw markup on the page, hand a file to the browser * as markup, read a file off the disk or place a link wait on - * trust-scan-config. A readme naming a git object, the form with a colon, - * only reads from the repository and passes. + * trust-scan-config. A readme naming a tracked file only reads from the + * repository and passes. */ static int trusted_key(const char *name, const char *value) { @@ -70,7 +70,7 @@ static int trusted_key(const char *name, const char *value) !strcmp(name, "logo-link") || !strcmp(name, "clone-url") || !strcmp(name, "enable-html-serving") || - (!strcmp(name, "readme") && !strchr(value, ':')); + (!strcmp(name, "readme") && !cgit_readme_is_tracked(value)); if (!untrusted) return 1; fprintf(stderr, "[cgit] Ignoring %s in %s: trust-scan-config is not set\n", name, diff --git a/source/shared.c b/source/shared.c index befd3e5..6e69666 100644 --- a/source/shared.c +++ b/source/shared.c @@ -739,3 +739,10 @@ char *cgit_get_mimetype_for_filename(const char *filename) fclose(file); return NULL; } + +int cgit_readme_is_tracked(const char *readme) +{ + const char *colon = strchr(readme, ':'); + + return colon && colon[1]; +} diff --git a/source/shared.h b/source/shared.h index ca2ac6a..13932c8 100644 --- a/source/shared.h +++ b/source/shared.h @@ -109,6 +109,12 @@ extern char *cgit_expand_macros(const char *text); extern char *cgit_get_mimetype_for_filename(const char *filename); +/* + * Whether a readme setting names a file tracked in the repository, written + * as ref:path or :path, rather than a file on the server's disk. + */ +extern int cgit_readme_is_tracked(const char *readme); + /* * Whether a revision from the request is a hex object id or a possible ref * name, the only forms cgit hands to git. -- cgit