commit 00fc2bb90963db33831c38e507e38a9391a433ea from: Stefan Sperling date: Wed Jul 16 13:48:03 2025 UTC introduce gotsys_ref_name_is_valid() We need to enforce additional restrictions on reference names specified in gotsys.conf in order to prevent escaping to arbitrary gotd.conf syntax. Add test coverage. commit - 97b40d32ed205c32841ce663899df2669f835253 commit + 00fc2bb90963db33831c38e507e38a9391a433ea blob - 18b5a178440f33fea8c8aa22d775a03b49c959f0 blob + 3b4293f212cd39c09fc0b944debb82296d969d75 --- gotsys/gotsys.h +++ gotsys/gotsys.h @@ -121,6 +121,7 @@ struct gotsys_conf { void gotsys_conf_init(struct gotsys_conf *); const struct got_error *gotsys_conf_parse(const char *, struct gotsys_conf *, int *); +int gotsys_ref_name_is_valid(char *); void gotsys_authorized_key_free(struct gotsys_authorized_key *); void gotsys_authorized_keys_list_purge(struct gotsys_authorized_keys_list *); void gotsys_user_free(struct gotsys_user *); blob - e76b20d277095e0aab05b355b91befb7045962fd blob + 08b407f0d09827e5b609d2b71ef87965e3228586 --- gotsys/parse.y +++ gotsys/parse.y @@ -1120,6 +1120,33 @@ conf_user_authorized_key(char *keytype, char *keydata, STAILQ_INSERT_TAIL(&user->authorized_keys, key, entry); return NULL; +} + +/* + * Reference name restrictions specific to gotsys.conf. + * Exclude symbols which could be used to escape from strings and write + * arbitrary gotd.conf snippets. Also exclude whitespace because newlines + * are relevant to the parser. + */ +int +gotsys_ref_name_is_valid(char *refname) +{ + const char *s; + const char forbidden[] = { '\'', '"', '{' , '}', '=' }; + size_t i; + + s = refname; + while (*s) { + for (i = 0; i < nitems(forbidden); i++) { + if (*s == forbidden[i]) + return 0; + } + if (isspace((unsigned char)s[0])) + return 0; + s++; + } + + return 1; } static int @@ -1131,7 +1158,8 @@ refname_is_valid(char *refname) return 0; } - if (!got_ref_name_is_valid(refname)) { + if (!got_ref_name_is_valid(refname) || + !gotsys_ref_name_is_valid(refname)) { yyerror("invalid reference name: %s", refname); return 0; } blob - cd4dfe61444049bb6012ccddeb973b174dbe2083 blob + 5bd0e83515bd1d7c8a3a6c47b024bb737e84d76d --- regress/gotsysd/test_gotsysd.sh +++ regress/gotsysd/test_gotsysd.sh @@ -1171,6 +1171,91 @@ EOF cat > ${testroot}/stderr.expected </dev/null + ret=$? + if [ $ret -ne 0 ]; then + echo "got checkout failed unexpectedly" >&2 + test_done "$testroot" 1 + return 1 + fi + + crypted_vm_pw=`echo ${GOTSYSD_VM_PASSWORD} | encrypt | tr -d '\n'` + crypted_pw=`echo ${GOTSYSD_DEV_PASSWORD} | encrypt | tr -d '\n'` + sshkey=`cat ${GOTSYSD_SSH_PUBKEY}` + + # An attempt to send an invalid gotsys.conf file + cat > ${testroot}/wt/gotsys.conf < $testroot/stdout 2> $testroot/stderr + ret=$? + if [ $ret -eq 0 ]; then + echo "gotsys check succeeded unexpectedly" >&2 + test_done "$testroot" 1 + return 1 + fi + + echo "gotsys: ${testroot}/wt/gotsys.conf: line 18: invalid reference name: refs/heads/mai\"n" \ + > $testroot/stderr.expected + cmp -s $testroot/stderr.expected $testroot/stderr + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/stderr.expected $testroot/stderr + test_done "$testroot" "$ret" + return 1 + fi + + (cd ${testroot}/wt && got commit -m "commit a bad gotsys.conf" \ + >/dev/null) + local commit_id=`git_show_head $testroot/${GOTSYS_REPO}` + + got send -q -i ${GOTSYSD_SSH_KEY} -r ${testroot}/${GOTSYS_REPO} \ + > $testroot/stdout 2> $testroot/stderr + ret=$? + if [ $ret -eq 0 ]; then + echo "got send succeeded unexpectedly" >&2 + test_done "$testroot" 1 + return 1 + fi + + cat > ${testroot}/stderr.expected <