Skip to content

Commit 18bbc79

Browse files
committed
Merge branch 'gc/bare-repo-discovery'
Introduce a discovery.barerepository configuration variable that allows users to forbid discovery of bare repositories. * gc/bare-repo-discovery: setup.c: create `safe.bareRepository` safe.directory: use git_protected_config() config: learn `git_protected_config()` Documentation: define protected configuration Documentation/git-config.txt: add SCOPES section
2 parents e72d93e + 8d1a744 commit 18bbc79

File tree

10 files changed

+300
-56
lines changed

10 files changed

+300
-56
lines changed

Documentation/config/safe.txt

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
safe.bareRepository::
2+
Specifies which bare repositories Git will work with. The currently
3+
supported values are:
4+
+
5+
* `all`: Git works with all bare repositories. This is the default.
6+
* `explicit`: Git only works with bare repositories specified via
7+
the top-level `--git-dir` command-line option, or the `GIT_DIR`
8+
environment variable (see linkgit:git[1]).
9+
+
10+
If you do not use bare repositories in your workflow, then it may be
11+
beneficial to set `safe.bareRepository` to `explicit` in your global
12+
config. This will protect you from attacks that involve cloning a
13+
repository that contains a bare repository and running a Git command
14+
within that directory.
15+
+
16+
This config setting is only respected in protected configuration (see
17+
<<SCOPES>>). This prevents the untrusted repository from tampering with
18+
this value.
19+
120
safe.directory::
221
These config entries specify Git-tracked directories that are
322
considered safe even if they are owned by someone other than the
@@ -12,9 +31,9 @@ via `git config --add`. To reset the list of safe directories (e.g. to
1231
override any such directories specified in the system config), add a
1332
`safe.directory` entry with an empty value.
1433
+
15-
This config setting is only respected when specified in a system or global
16-
config, not when it is specified in a repository config, via the command
17-
line option `-c safe.directory=<path>`, or in environment variables.
34+
This config setting is only respected in protected configuration (see
35+
<<SCOPES>>). This prevents the untrusted repository from tampering with this
36+
value.
1837
+
1938
The value of this setting is interpolated, i.e. `~/<path>` expands to a
2039
path relative to the home directory and `%(prefix)/<path>` expands to a

Documentation/config/uploadpack.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ uploadpack.packObjectsHook::
4949
`pack-objects` to the hook, and expects a completed packfile on
5050
stdout.
5151
+
52-
Note that this configuration variable is ignored if it is seen in the
53-
repository-level config (this is a safety measure against fetching from
54-
untrusted repositories).
52+
Note that this configuration variable is only respected when it is specified
53+
in protected configuration (see <<SCOPES>>). This is a safety measure
54+
against fetching from untrusted repositories.
5555

5656
uploadpack.allowFilter::
5757
If this option is set, `upload-pack` will support partial

Documentation/git-config.txt

Lines changed: 72 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -297,23 +297,20 @@ The default is to use a pager.
297297
FILES
298298
-----
299299

300-
If not set explicitly with `--file`, there are four files where
301-
'git config' will search for configuration options:
300+
By default, 'git config' will read configuration options from multiple
301+
files:
302302

303303
$(prefix)/etc/gitconfig::
304304
System-wide configuration file.
305305

306306
$XDG_CONFIG_HOME/git/config::
307-
Second user-specific configuration file. If $XDG_CONFIG_HOME is not set
308-
or empty, `$HOME/.config/git/config` will be used. Any single-valued
309-
variable set in this file will be overwritten by whatever is in
310-
`~/.gitconfig`. It is a good idea not to create this file if
311-
you sometimes use older versions of Git, as support for this
312-
file was added fairly recently.
313-
314307
~/.gitconfig::
315-
User-specific configuration file. Also called "global"
316-
configuration file.
308+
User-specific configuration files. When the XDG_CONFIG_HOME environment
309+
variable is not set or empty, $HOME/.config/ is used as
310+
$XDG_CONFIG_HOME.
311+
+
312+
These are also called "global" configuration files. If both files exist, both
313+
files are read in the order given above.
317314

318315
$GIT_DIR/config::
319316
Repository specific configuration file.
@@ -322,28 +319,80 @@ $GIT_DIR/config.worktree::
322319
This is optional and is only searched when
323320
`extensions.worktreeConfig` is present in $GIT_DIR/config.
324321

325-
If no further options are given, all reading options will read all of these
326-
files that are available. If the global or the system-wide configuration
327-
file are not available they will be ignored. If the repository configuration
328-
file is not available or readable, 'git config' will exit with a non-zero
329-
error code. However, in neither case will an error message be issued.
322+
You may also provide additional configuration parameters when running any
323+
git command by using the `-c` option. See linkgit:git[1] for details.
324+
325+
Options will be read from all of these files that are available. If the
326+
global or the system-wide configuration files are missing or unreadable they
327+
will be ignored. If the repository configuration file is missing or unreadable,
328+
'git config' will exit with a non-zero error code. An error message is produced
329+
if the file is unreadable, but not if it is missing.
330330

331331
The files are read in the order given above, with last value found taking
332332
precedence over values read earlier. When multiple values are taken then all
333333
values of a key from all files will be used.
334334

335-
You may override individual configuration parameters when running any git
336-
command by using the `-c` option. See linkgit:git[1] for details.
337-
338-
All writing options will per default write to the repository specific
335+
By default, options are only written to the repository specific
339336
configuration file. Note that this also affects options like `--replace-all`
340337
and `--unset`. *'git config' will only ever change one file at a time*.
341338

342-
You can override these rules using the `--global`, `--system`,
343-
`--local`, `--worktree`, and `--file` command-line options; see
344-
<<OPTIONS>> above.
339+
You can limit which configuration sources are read from or written to by
340+
specifying the path of a file with the `--file` option, or by specifying a
341+
configuration scope with `--system`, `--global`, `--local`, or `--worktree`.
342+
For more, see <<OPTIONS>> above.
343+
344+
[[SCOPES]]
345+
SCOPES
346+
------
347+
348+
Each configuration source falls within a configuration scope. The scopes
349+
are:
350+
351+
system::
352+
$(prefix)/etc/gitconfig
353+
354+
global::
355+
$XDG_CONFIG_HOME/git/config
356+
+
357+
~/.gitconfig
358+
359+
local::
360+
$GIT_DIR/config
361+
362+
worktree::
363+
$GIT_DIR/config.worktree
364+
365+
command::
366+
GIT_CONFIG_{COUNT,KEY,VALUE} environment variables (see <<ENVIRONMENT>>
367+
below)
368+
+
369+
the `-c` option
370+
371+
With the exception of 'command', each scope corresponds to a command line
372+
option: `--system`, `--global`, `--local`, `--worktree`.
373+
374+
When reading options, specifying a scope will only read options from the
375+
files within that scope. When writing options, specifying a scope will write
376+
to the files within that scope (instead of the repository specific
377+
configuration file). See <<OPTIONS>> above for a complete description.
378+
379+
Most configuration options are respected regardless of the scope it is
380+
defined in, but some options are only respected in certain scopes. See the
381+
respective option's documentation for the full details.
382+
383+
Protected configuration
384+
~~~~~~~~~~~~~~~~~~~~~~~
385+
386+
Protected configuration refers to the 'system', 'global', and 'command' scopes.
387+
For security reasons, certain options are only respected when they are
388+
specified in protected configuration, and ignored otherwise.
345389

390+
Git treats these scopes as if they are controlled by the user or a trusted
391+
administrator. This is because an attacker who controls these scopes can do
392+
substantial harm without using Git, so it is assumed that the user's environment
393+
protects these scopes against attackers.
346394

395+
[[ENVIRONMENT]]
347396
ENVIRONMENT
348397
-----------
349398

config.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,17 @@ static enum config_scope current_parsing_scope;
8181
static int pack_compression_seen;
8282
static int zlib_compression_seen;
8383

84+
/*
85+
* Config that comes from trusted scopes, namely:
86+
* - CONFIG_SCOPE_SYSTEM (e.g. /etc/gitconfig)
87+
* - CONFIG_SCOPE_GLOBAL (e.g. $HOME/.gitconfig, $XDG_CONFIG_HOME/git)
88+
* - CONFIG_SCOPE_COMMAND (e.g. "-c" option, environment variables)
89+
*
90+
* This is declared here for code cleanliness, but unlike the other
91+
* static variables, this does not hold config parser state.
92+
*/
93+
static struct config_set protected_config;
94+
8495
static int config_file_fgetc(struct config_source *conf)
8596
{
8697
return getc_unlocked(conf->u.file);
@@ -2378,6 +2389,11 @@ int git_configset_add_file(struct config_set *cs, const char *filename)
23782389
return git_config_from_file(config_set_callback, filename, cs);
23792390
}
23802391

2392+
int git_configset_add_parameters(struct config_set *cs)
2393+
{
2394+
return git_config_from_parameters(config_set_callback, cs);
2395+
}
2396+
23812397
int git_configset_get_value(struct config_set *cs, const char *key, const char **value)
23822398
{
23832399
const struct string_list *values = NULL;
@@ -2619,6 +2635,33 @@ int repo_config_get_pathname(struct repository *repo,
26192635
return ret;
26202636
}
26212637

2638+
/* Read values into protected_config. */
2639+
static void read_protected_config(void)
2640+
{
2641+
char *xdg_config = NULL, *user_config = NULL, *system_config = NULL;
2642+
2643+
git_configset_init(&protected_config);
2644+
2645+
system_config = git_system_config();
2646+
git_global_config(&user_config, &xdg_config);
2647+
2648+
git_configset_add_file(&protected_config, system_config);
2649+
git_configset_add_file(&protected_config, xdg_config);
2650+
git_configset_add_file(&protected_config, user_config);
2651+
git_configset_add_parameters(&protected_config);
2652+
2653+
free(system_config);
2654+
free(xdg_config);
2655+
free(user_config);
2656+
}
2657+
2658+
void git_protected_config(config_fn_t fn, void *data)
2659+
{
2660+
if (!protected_config.hash_initialized)
2661+
read_protected_config();
2662+
configset_iter(&protected_config, fn, data);
2663+
}
2664+
26222665
/* Functions used historically to read configuration from 'the_repository' */
26232666
void git_config(config_fn_t fn, void *data)
26242667
{

config.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,15 @@ void git_configset_init(struct config_set *cs);
446446
*/
447447
int git_configset_add_file(struct config_set *cs, const char *filename);
448448

449+
/**
450+
* Parses command line options and environment variables, and adds the
451+
* variable-value pairs to the `config_set`. Returns 0 on success, or -1
452+
* if there is an error in parsing. The caller decides whether to free
453+
* the incomplete configset or continue using it when the function
454+
* returns -1.
455+
*/
456+
int git_configset_add_parameters(struct config_set *cs);
457+
449458
/**
450459
* Finds and returns the value list, sorted in order of increasing priority
451460
* for the configuration variable `key` and config set `cs`. When the
@@ -505,6 +514,13 @@ int repo_config_get_maybe_bool(struct repository *repo,
505514
int repo_config_get_pathname(struct repository *repo,
506515
const char *key, const char **dest);
507516

517+
/*
518+
* Functions for reading protected config. By definition, protected
519+
* config ignores repository config, so these do not take a `struct
520+
* repository` parameter.
521+
*/
522+
void git_protected_config(config_fn_t fn, void *data);
523+
508524
/**
509525
* Querying For Specific Variables
510526
* -------------------------------

setup.c

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
static int inside_git_dir = -1;
1111
static int inside_work_tree = -1;
1212
static int work_tree_config_is_bogus;
13+
enum allowed_bare_repo {
14+
ALLOWED_BARE_REPO_EXPLICIT = 0,
15+
ALLOWED_BARE_REPO_ALL,
16+
};
1317

1418
static struct startup_info the_startup_info;
1519
struct startup_info *startup_info = &the_startup_info;
@@ -1155,11 +1159,51 @@ static int ensure_valid_ownership(const char *gitfile,
11551159
* constant regardless of what failed above. data.is_safe should be
11561160
* initialized to false, and might be changed by the callback.
11571161
*/
1158-
read_very_early_config(safe_directory_cb, &data);
1162+
git_protected_config(safe_directory_cb, &data);
11591163

11601164
return data.is_safe;
11611165
}
11621166

1167+
static int allowed_bare_repo_cb(const char *key, const char *value, void *d)
1168+
{
1169+
enum allowed_bare_repo *allowed_bare_repo = d;
1170+
1171+
if (strcasecmp(key, "safe.bareRepository"))
1172+
return 0;
1173+
1174+
if (!strcmp(value, "explicit")) {
1175+
*allowed_bare_repo = ALLOWED_BARE_REPO_EXPLICIT;
1176+
return 0;
1177+
}
1178+
if (!strcmp(value, "all")) {
1179+
*allowed_bare_repo = ALLOWED_BARE_REPO_ALL;
1180+
return 0;
1181+
}
1182+
return -1;
1183+
}
1184+
1185+
static enum allowed_bare_repo get_allowed_bare_repo(void)
1186+
{
1187+
enum allowed_bare_repo result = ALLOWED_BARE_REPO_ALL;
1188+
git_protected_config(allowed_bare_repo_cb, &result);
1189+
return result;
1190+
}
1191+
1192+
static const char *allowed_bare_repo_to_string(
1193+
enum allowed_bare_repo allowed_bare_repo)
1194+
{
1195+
switch (allowed_bare_repo) {
1196+
case ALLOWED_BARE_REPO_EXPLICIT:
1197+
return "explicit";
1198+
case ALLOWED_BARE_REPO_ALL:
1199+
return "all";
1200+
default:
1201+
BUG("invalid allowed_bare_repo %d",
1202+
allowed_bare_repo);
1203+
}
1204+
return NULL;
1205+
}
1206+
11631207
enum discovery_result {
11641208
GIT_DIR_NONE = 0,
11651209
GIT_DIR_EXPLICIT,
@@ -1169,7 +1213,8 @@ enum discovery_result {
11691213
GIT_DIR_HIT_CEILING = -1,
11701214
GIT_DIR_HIT_MOUNT_POINT = -2,
11711215
GIT_DIR_INVALID_GITFILE = -3,
1172-
GIT_DIR_INVALID_OWNERSHIP = -4
1216+
GIT_DIR_INVALID_OWNERSHIP = -4,
1217+
GIT_DIR_DISALLOWED_BARE = -5,
11731218
};
11741219

11751220
/*
@@ -1297,6 +1342,8 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
12971342
}
12981343

12991344
if (is_git_directory(dir->buf)) {
1345+
if (get_allowed_bare_repo() == ALLOWED_BARE_REPO_EXPLICIT)
1346+
return GIT_DIR_DISALLOWED_BARE;
13001347
if (!ensure_valid_ownership(NULL, NULL, dir->buf))
13011348
return GIT_DIR_INVALID_OWNERSHIP;
13021349
strbuf_addstr(gitdir, ".");
@@ -1443,6 +1490,14 @@ const char *setup_git_directory_gently(int *nongit_ok)
14431490
}
14441491
*nongit_ok = 1;
14451492
break;
1493+
case GIT_DIR_DISALLOWED_BARE:
1494+
if (!nongit_ok) {
1495+
die(_("cannot use bare repository '%s' (safe.bareRepository is '%s')"),
1496+
dir.buf,
1497+
allowed_bare_repo_to_string(get_allowed_bare_repo()));
1498+
}
1499+
*nongit_ok = 1;
1500+
break;
14461501
case GIT_DIR_NONE:
14471502
/*
14481503
* As a safeguard against setup_git_directory_gently_1 returning

0 commit comments

Comments
 (0)