,从而创建一个非常大的值,并触发一个BUG。例如:
$ {
printf '[foo "'
perl -e 'print "a" x 2**31'
echo '"]bar = value'
} >huge
$ git config --file=huge --list
fatal: BUG: strbuf_setlen() beyond buffer
虽然这显然是一个我们不关心支持的愚蠢情况,但有几个原因值得修复它,即切换到
- 我们应该尽量避免触发BUG断言
- 避免整数截断或溢出可以树立一个好的榜样,并使得更容易审计代码以查找更重要的问题
- BUG的结果是在这种情况下发生的,因为我们变成了负数。如果我们使用2**32个subsection,我们将变成一个小的正数值,并且实际上会生成错误的输出(我们的键的subsection将被截断)。
config
: reject parsing of files over INT_MAX
Signed-off-by: Jeff King
While the last few commits have made it possible for the config parser to handle config files up to the limits of size_t,
the rest of the code isn't really ready for this. In particular, we often feed the keys as strings into printf "%s" format specifiers. And because the printf family of functions must return an int to specify the result, they complain. Here are two concrete examples (using glibc; we're in uncharted territory here so results may vary):
Generate a gigantic .gitmodules file like this:
git submodule add /some/other/repo foo
{
printf '[submodule "'
perl -e 'print "a" x 2**31'
echo '"]path = foo'
} >.gitmodules
git commit -m 'huge gitmodule'
then try this:
$ git show
BUG: strbuf.c:397: your vsnprintf is broken (returned -1)
The problem is that we end up calling:
strbuf_addf(&sb, "submodule.%s.ignore", submodule_name)
which relies on vsnprintf(), and that function has no way to report back a size larger than INT_MAX
.
Taking that same file, try this:
git config --file=.gitmodules --list --name-only
On my system it produces an output with exactly 4GB of spaces. I confirmed in a debugger that we reach the config callback with the key intact: it's 2147483663 bytes and full of a's. But when we print it with this call:
printf("%s%c", key_, term);
we just get the spaces.
So given the fact that these are insane cases which we have no need to support, the weird behavior from feeding the results to printf even if the code is careful, and the possibility of uncareful code introducing its own integer truncation issues, let's just declare INT_MAX
as a limit for parsing config files.
We'll enforce the limit in get_next_char()
, which generalizes over all sources (blobs, files, etc) and covers any element we're parsing (whether section, key, value, etc). For simplicity, the limit is over the length of the _whole
_ file, so you couldn't have two 1GB values in the same file. This should be perfectly fine, as the expected size for config files is generally kilobytes at most.
With this patch both cases above will yield:
fatal: bad config line 1 in file .gitmodules
That's not an amazing error message, but the parser isn't set up to provide specific messages (it just breaks out of the parsing loop and gives that generic error even if see a syntactic issue). And we really wouldn't expect to see this case outside of somebody maliciously probing the limits of the config system.
's/=.*//'
。 - umläute