When Go runs a program with os.exec, it uses the LookPath function to
look up the path name if the path does not contain a path separator. On
Unix, this provides the standard Unix semantics by looking in PATH.
However, on Windows, it also looks in the current directory as well to
emulate the behavior of CMD.
Unfortunately, this is a well-known security flaw on Windows and similar
behavior there is the source for several whole classes of security
vulnerabilities. This leads to an untrusted repository being able to
create a git.bat file that gets executed in preference to our trusted
path for the git binary.
Since we don't want to rely on Go fixing this behavior, let's import
some code from Go to provide the Unix semantics for LookPath, which are
secure if the user hasn't put the current directory in PATH. That
should provide secure behavior in this case. Fortunately, our code goes
through one particular place to run all commands, so this is a
relatively simple fix.
Update the various copyright and license files to reflect our imported
code.
Currently, the subprocess package reads from the environment as it's
created at startup when the init function is called. However, we'll
soon want to modify the environment in this case before it gets
processed, so let's change the code to use a mutex to initialize the
environment once before using it and simply call that before using the
environment we've set up.
We'll want to reset the environment as well in a future commit, so let's
be sure to add a function for that. We reuse the same internal function
and just ignore the return value to make our code paths simpler.
Trace all command execution at the time when the command starts.
Previously, only "simple" execution created trace entries, leading to
mysterious gaps in trace logs where time passed but it looked like
nothing was happening.
Git’s configuration option submodule.recurse makes it more convenient to
use submodules. If set to true, top-level checkouts will recurse into
all submodules. Additionally, Git will pass an environment variable
called GIT_INTERNAL_SUPER_PREFIX to the respective submodule’s path
relative to its parent repository to each child process, including git
lfs filter-process.
In turn, Git LFS spawns a couple of Git processes, for instance, when
checking the minimum required Git version, reading Git configuration
values, or obtaining the object name of a commit with git rev-parse.
In the current implementation, Git LFS would forward the environment
variable GIT_INTERNAL_SUPER_PREFIX to Git unchanged. This is problematic
because the presence of this environment variable will make Git behave
as if the command-line option --super-prefix had been passed to the
respective Git command. However, many commands don’t support the
--super-prefix command-line option. This includes git version, git
config, and git rev-parse. Consequently, these Git processes, as spawned
by Git LFS, would immediately fail with a usage error.
In short, users of submodule.recurse = true would get errors when
working in repositories with at least one Git-LFS-enabled submodule.
This patch fixes the issue by removing the GIT_INTERNAL_SUPER_PREFIX
environment variable from the environment Git LFS passes to Git child
processes.
The code which allocated and used a pty on Unix systems was unused, but
it did bring in a dependency on the github.com/kr/pty module. This
module is unmaintained and doesn't compile with gccgo. Since we no
longer need the pty code or this module, remove both of them.
We currently have a function to shell quote a list of strings, but in
some cases we may want to just quote a single string. To avoid the
complexity of having to create a bunch of temporaries and then index out
the result, create a function that shell quotes just a single string.
There are a small number of places where we'll want to pass data to the
shell. Add a function which formats a command name and arguments into a
command that invokes "sh -c" with the appropriate args. Additionally
add a form that quotes its arguments, and use this in the SSH code,
which wants to pass data to the shell.
Add the slash to the list of characters which don't require quoting for
the shell. No POSIX-compatible shell requires escaping the slash, and
ignoring it for the purposes of escaping lets us write cleaner,
nicer-to-read trace output.
Don't do the same with the backslash, which while being the equivalent
on Windows, is handled specially by POSIX shells.
In a future commit, we'll be adding some additional shell-related
handling which logically belongs to the subprocess package. To avoid an
import loop, move the ShellQuote function and its required variable from
the tools package to the subprocess package. Update the only caller of
this function.
This commit contains no functional change.
Replicate `lfs/gitscanner_cmd` in `subprocess/buffered_cmd` using
subprocess/cmd. In subsequent commits we will migrate all functions
users of `lfs/gitscanner_cmd` to `subprocess/buffered_cmd` and
afterwards remove `lfs/gitscanner_cmd`.
This commit copies-down some utility methods introduced as part of the API change in Go 1.6. These changes are convenient to use here, since they auto-truncate stderr error output.
Revert this commit when moving to Go 1.6.
ExitError conditions now return a plain error with message like:
Error running git [config --system filter.lfs.clean git-lfs clean -- %f]: 'error: could not lock config file /etc/gitconfig: Permission denied' 'exit status 255'
Also:
* Made Set/Unset Config commands return errors when they occur.
* Made install attribute set fail properly with an error message e.g. if permission-denied. Previously this failed silently and reported success.
***NOTE*** this commit contains Go 1.6-specific APIs. The following commit will remove those, and that following commit can be reverted when Go >= 1.6 is required.