Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/vole.git

Write over SSH with a registered key:

git clone ssh://git@rodent.software:2222/vole.git

A free and open-source forge that lives in your Git repo.

Fuzz the parsers that read untrusted input

16bf0ebf8054de5044a52f93d156402542f0f71a · Keenan Nemetz · 10d ago · parent 70ba9a69

Fuzz the parsers that read untrusted input

The SSH exec line, the Git HTTP route, and the LFS packet stream are all
hand-written parsers on bytes a client controls, and each was covered only by a
table of examples someone thought to write.

Six targets, each asserting a property rather than waiting for a panic: the
command parser cannot invent bytes and its output survives being quoted back, a
route re-routes from its own parts and never names more than one path segment, a
repository argument is a name and not a path, and the packet reader's lines
survive being framed again. The seeds are the shapes the clients actually send,
so go test ./... keeps guarding them and a fuzz target costs a push nothing.

The route fuzzer found one gap on its first run: /git/.git/info/refs gave back an
empty repository name with ok set, and only the store refused it. A route that
answers ok now means a name the rest of the path applies to.

Closes #96.

server/githttp/githttp.go +10−3

@@ -125,12 +125,19 @@ func Route(path string) (name, rest string, ok bool) {
125 125 if i <= 0 {
126 126 return "", "", false
127 127 }
128 dir := trimmed[:i]
128 name = trimmed[:i]
129 129 rest = trimmed[i+1:]
130 if !strings.HasSuffix(dir, ".git") {
130 if !strings.HasSuffix(name, ".git") {
131 131 return "", "", false
132 132 }
133 return strings.TrimSuffix(dir, ".git"), rest, true
133 name = strings.TrimSuffix(name, ".git")
134 // "/git/.git/info/refs" names no repository. The store refuses an empty name
135 // as well, but a route that answers ok has to mean a name the rest of the path
136 // can be applied to, or the next caller has to remember to check.
137 if name == "" {
138 return "", "", false
139 }
140 return name, rest, true
134 141 }
135 142
136 143 // IsPush reports whether a request is asking to write.