commit 076101f2df32331f84fa9fe38d8394716e955814 from: Stefan Sperling via: Thomas Adam date: Tue Jul 22 08:17:38 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 - 1b4b319ba6b74f3f066fdfc75995ea5241507caa commit + 076101f2df32331f84fa9fe38d8394716e955814 blob - 7b5191095a645e3f1b5c9ade40cbf3811d5c5f42 blob + d6c4206f6fde168542a00fd487891e6fa296621a --- gotsys/gotsys.h +++ gotsys/gotsys.h @@ -120,6 +120,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 - ebf1ff2a03bb1cd0a418e4a821cdd5a0f9d3a4e0 blob + bddef6d8953e3a78b7c1f65ddf31d79b77773d82 --- gotsys/parse.y +++ gotsys/parse.y @@ -1060,6 +1060,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 @@ -1071,7 +1098,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 - d7e399f5f7a3fefc412700402b3d12be575bb36d blob + cee6986bf6095cfe5d4b8356cda3408ed7b8f7f5 --- 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 <