Skip to content

Commit 8f8eea8

Browse files
committed
Sync with 2.35.4
* maint-2.35: Git 2.35.4 Git 2.34.4 Git 2.33.4 Git 2.32.3 Git 2.31.4 Git 2.30.5 setup: tighten ownership checks post CVE-2022-24765 git-compat-util: allow root to access both SUDO_UID and root owned t0034: add negative tests and allow git init to mostly work under sudo git-compat-util: avoid failing dir ownership checks if running privileged t: regression git needs safe.directory when using sudo
2 parents dc8c8de + 359da65 commit 8f8eea8

File tree

11 files changed

+282
-12
lines changed

11 files changed

+282
-12
lines changed

Documentation/RelNotes/2.30.5.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Git v2.30.5 Release Notes
2+
=========================
3+
4+
This release contains minor fix-ups for the changes that went into
5+
Git 2.30.3 and 2.30.4, addressing CVE-2022-29187.
6+
7+
* The safety check that verifies a safe ownership of the Git
8+
worktree is now extended to also cover the ownership of the Git
9+
directory (and the `.git` file, if there is any).
10+
11+
Carlo Marcelo Arenas Belón (1):
12+
setup: tighten ownership checks post CVE-2022-24765

Documentation/RelNotes/2.31.4.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Git v2.31.4 Release Notes
2+
=========================
3+
4+
This release merges up the fixes that appear in v2.30.5 to address
5+
the security issue CVE-2022-29187; see the release notes for that
6+
version for details.

Documentation/RelNotes/2.32.3.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Git v2.32.3 Release Notes
2+
=========================
3+
4+
This release merges up the fixes that appear in v2.30.5 and
5+
v2.31.4 to address the security issue CVE-2022-29187; see the
6+
release notes for these versions for details.

Documentation/RelNotes/2.33.4.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Git v2.33.4 Release Notes
2+
=========================
3+
4+
This release merges up the fixes that appear in v2.30.5, v2.31.4
5+
and v2.32.3 to address the security issue CVE-2022-29187; see
6+
the release notes for these versions for details.

Documentation/RelNotes/2.34.4.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Git v2.34.4 Release Notes
2+
=========================
3+
4+
This release merges up the fixes that appear in v2.30.5, v2.31.4,
5+
v2.32.3 and v2.33.4 to address the security issue CVE-2022-29187;
6+
see the release notes for these versions for details.

Documentation/RelNotes/2.35.4.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Git v2.35.4 Release Notes
2+
=========================
3+
4+
This release merges up the fixes that appear in v2.30.5,
5+
v2.31.4, v2.32.3, v2.33.4 and v2.34.4 to address the security
6+
issue CVE-2022-29187; see the release notes for these versions
7+
for details.

Documentation/config/safe.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,17 @@ directory was listed in the `safe.directory` list. If `safe.directory=*`
2626
is set in system config and you want to re-enable this protection, then
2727
initialize your list with an empty value before listing the repositories
2828
that you deem safe.
29+
+
30+
As explained, Git only allows you to access repositories owned by
31+
yourself, i.e. the user who is running Git, by default. When Git
32+
is running as 'root' in a non Windows platform that provides sudo,
33+
however, git checks the SUDO_UID environment variable that sudo creates
34+
and will allow access to the uid recorded as its value in addition to
35+
the id from 'root'.
36+
This is to make it easy to perform a common sequence during installation
37+
"make && sudo make install". A git process running under 'sudo' runs as
38+
'root' but the 'sudo' command exports the environment variable to record
39+
which id the original user has.
40+
If that is not what you would prefer and want git to only trust
41+
repositories that are owned by root instead, then you can remove
42+
the `SUDO_UID` variable from root's environment before invoking git.

git-compat-util.h

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,12 +437,68 @@ static inline int git_offset_1st_component(const char *path)
437437
#endif
438438

439439
#ifndef is_path_owned_by_current_user
440+
441+
#ifdef __TANDEM
442+
#define ROOT_UID 65535
443+
#else
444+
#define ROOT_UID 0
445+
#endif
446+
447+
/*
448+
* Do not use this function when
449+
* (1) geteuid() did not say we are running as 'root', or
450+
* (2) using this function will compromise the system.
451+
*
452+
* PORTABILITY WARNING:
453+
* This code assumes uid_t is unsigned because that is what sudo does.
454+
* If your uid_t type is signed and all your ids are positive then it
455+
* should all work fine.
456+
* If your version of sudo uses negative values for uid_t or it is
457+
* buggy and return an overflowed value in SUDO_UID, then git might
458+
* fail to grant access to your repository properly or even mistakenly
459+
* grant access to someone else.
460+
* In the unlikely scenario this happened to you, and that is how you
461+
* got to this message, we would like to know about it; so sent us an
462+
* email to [email protected] indicating which platform you are
463+
* using and which version of sudo, so we can improve this logic and
464+
* maybe provide you with a patch that would prevent this issue again
465+
* in the future.
466+
*/
467+
static inline void extract_id_from_env(const char *env, uid_t *id)
468+
{
469+
const char *real_uid = getenv(env);
470+
471+
/* discard anything empty to avoid a more complex check below */
472+
if (real_uid && *real_uid) {
473+
char *endptr = NULL;
474+
unsigned long env_id;
475+
476+
errno = 0;
477+
/* silent overflow errors could trigger a bug here */
478+
env_id = strtoul(real_uid, &endptr, 10);
479+
if (!*endptr && !errno)
480+
*id = env_id;
481+
}
482+
}
483+
440484
static inline int is_path_owned_by_current_uid(const char *path)
441485
{
442486
struct stat st;
487+
uid_t euid;
488+
443489
if (lstat(path, &st))
444490
return 0;
445-
return st.st_uid == geteuid();
491+
492+
euid = geteuid();
493+
if (euid == ROOT_UID)
494+
{
495+
if (st.st_uid == ROOT_UID)
496+
return 1;
497+
else
498+
extract_id_from_env("SUDO_UID", &euid);
499+
}
500+
501+
return st.st_uid == euid;
446502
}
447503

448504
#define is_path_owned_by_current_user is_path_owned_by_current_uid

setup.c

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,14 +1120,32 @@ static int safe_directory_cb(const char *key, const char *value, void *d)
11201120
return 0;
11211121
}
11221122

1123-
static int ensure_valid_ownership(const char *path)
1123+
/*
1124+
* Check if a repository is safe, by verifying the ownership of the
1125+
* worktree (if any), the git directory, and the gitfile (if any).
1126+
*
1127+
* Exemptions for known-safe repositories can be added via `safe.directory`
1128+
* config settings; for non-bare repositories, their worktree needs to be
1129+
* added, for bare ones their git directory.
1130+
*/
1131+
static int ensure_valid_ownership(const char *gitfile,
1132+
const char *worktree, const char *gitdir)
11241133
{
1125-
struct safe_directory_data data = { .path = path };
1134+
struct safe_directory_data data = {
1135+
.path = worktree ? worktree : gitdir
1136+
};
11261137

11271138
if (!git_env_bool("GIT_TEST_ASSUME_DIFFERENT_OWNER", 0) &&
1128-
is_path_owned_by_current_user(path))
1139+
(!gitfile || is_path_owned_by_current_user(gitfile)) &&
1140+
(!worktree || is_path_owned_by_current_user(worktree)) &&
1141+
(!gitdir || is_path_owned_by_current_user(gitdir)))
11291142
return 1;
11301143

1144+
/*
1145+
* data.path is the "path" that identifies the repository and it is
1146+
* constant regardless of what failed above. data.is_safe should be
1147+
* initialized to false, and might be changed by the callback.
1148+
*/
11311149
read_very_early_config(safe_directory_cb, &data);
11321150

11331151
return data.is_safe;
@@ -1215,6 +1233,8 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
12151233
current_device = get_device_or_die(dir->buf, NULL, 0);
12161234
for (;;) {
12171235
int offset = dir->len, error_code = 0;
1236+
char *gitdir_path = NULL;
1237+
char *gitfile = NULL;
12181238

12191239
if (offset > min_offset)
12201240
strbuf_addch(dir, '/');
@@ -1225,21 +1245,50 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
12251245
if (die_on_error ||
12261246
error_code == READ_GITFILE_ERR_NOT_A_FILE) {
12271247
/* NEEDSWORK: fail if .git is not file nor dir */
1228-
if (is_git_directory(dir->buf))
1248+
if (is_git_directory(dir->buf)) {
12291249
gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT;
1250+
gitdir_path = xstrdup(dir->buf);
1251+
}
12301252
} else if (error_code != READ_GITFILE_ERR_STAT_FAILED)
12311253
return GIT_DIR_INVALID_GITFILE;
1232-
}
1254+
} else
1255+
gitfile = xstrdup(dir->buf);
1256+
/*
1257+
* Earlier, we tentatively added DEFAULT_GIT_DIR_ENVIRONMENT
1258+
* to check that directory for a repository.
1259+
* Now trim that tentative addition away, because we want to
1260+
* focus on the real directory we are in.
1261+
*/
12331262
strbuf_setlen(dir, offset);
12341263
if (gitdirenv) {
1235-
if (!ensure_valid_ownership(dir->buf))
1236-
return GIT_DIR_INVALID_OWNERSHIP;
1237-
strbuf_addstr(gitdir, gitdirenv);
1238-
return GIT_DIR_DISCOVERED;
1264+
enum discovery_result ret;
1265+
1266+
if (ensure_valid_ownership(gitfile,
1267+
dir->buf,
1268+
(gitdir_path ? gitdir_path : gitdirenv))) {
1269+
strbuf_addstr(gitdir, gitdirenv);
1270+
ret = GIT_DIR_DISCOVERED;
1271+
} else
1272+
ret = GIT_DIR_INVALID_OWNERSHIP;
1273+
1274+
/*
1275+
* Earlier, during discovery, we might have allocated
1276+
* string copies for gitdir_path or gitfile so make
1277+
* sure we don't leak by freeing them now, before
1278+
* leaving the loop and function.
1279+
*
1280+
* Note: gitdirenv will be non-NULL whenever these are
1281+
* allocated, therefore we need not take care of releasing
1282+
* them outside of this conditional block.
1283+
*/
1284+
free(gitdir_path);
1285+
free(gitfile);
1286+
1287+
return ret;
12391288
}
12401289

12411290
if (is_git_directory(dir->buf)) {
1242-
if (!ensure_valid_ownership(dir->buf))
1291+
if (!ensure_valid_ownership(NULL, NULL, dir->buf))
12431292
return GIT_DIR_INVALID_OWNERSHIP;
12441293
strbuf_addstr(gitdir, ".");
12451294
return GIT_DIR_BARE;
@@ -1377,7 +1426,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
13771426
struct strbuf quoted = STRBUF_INIT;
13781427

13791428
sq_quote_buf_pretty(&quoted, dir.buf);
1380-
die(_("unsafe repository ('%s' is owned by someone else)\n"
1429+
die(_("detected dubious ownership in repository at '%s'\n"
13811430
"To add an exception for this directory, call:\n"
13821431
"\n"
13831432
"\tgit config --global --add safe.directory %s"),

t/lib-sudo.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Helpers for running git commands under sudo.
2+
3+
# Runs a scriplet passed through stdin under sudo.
4+
run_with_sudo () {
5+
local ret
6+
local RUN="$TEST_DIRECTORY/$$.sh"
7+
write_script "$RUN" "$TEST_SHELL_PATH"
8+
# avoid calling "$RUN" directly so sudo doesn't get a chance to
9+
# override the shell, add aditional restrictions or even reject
10+
# running the script because its security policy deem it unsafe
11+
sudo "$TEST_SHELL_PATH" -c "\"$RUN\""
12+
ret=$?
13+
rm -f "$RUN"
14+
return $ret
15+
}

0 commit comments

Comments
 (0)