Go-based Git command DSL
Note: this issue should remain confidential until after the critical security release https://gitlab.com/gitlab-org/gitlab-ce/issues/65334
There have been a few exploits discovered that target Gitaly's git subprocess spawning (see #1682, #1799, #1801 (closed) #1802). While we have patched these specific exploits, more may emerge in the future.
At the root of this problem is a lack of validation from the various inputs that may end up in a git commands (note: normally these inputs come from RPC request parameters). Enforcing a strict policy for how these commands are formed may guard against some of these attacks.
One approach to enforcing better argument validation is to iteratively implement a Domain Specific Language (DSL) in Go for forming Git commands. This would allow us to specify a syntax for the various command components that would leverage the compiler for enforcement.
Git Command Status Quo
A partial listing of existing commands can be found by searching for git.BareCommand
or git.Command
usage. See other git command constructs in internal/git/command.go.
-
log example:
cmd, err := git.Command(ctx, repo, "log", "--format=%H", "--max-count=1", revision, "--", path)
-
fsck example:
args := []string{"--git-dir", repoPath, "fsck"} cmd, err := git.BareCommand(ctx, nil, &stdout, &stderr, env, args...)
-
archive example:
archiveCommand, err := git.Command(ctx, in.GetRepository(), "archive", "--format="+format, "--prefix="+in.GetPrefix()+"/", in.GetCommitId(), "--", path)
-
grep example:
cmd, err := git.Command(ctx, repo, "grep", "--ignore-case", "-I", // Don't match binary, there is no long-name for this one "--line-number", "--null", "--before-context", surroundContext, "--after-context", surroundContext, "--perl-regexp", "-e", // next arg is pattern, keep this last req.GetQuery(), string(req.GetRef()), )
-
catfile example:
batchCmdArgs := []string{"--git-dir", repoPath, "cat-file", "--batch"} batchCmd, err := git.BareCommand(ctx, stdinReader, nil, nil, env, batchCmdArgs...)