summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2022-07-05 23:47:15 -0400
committerEdward Thomson <ethomson@edwardthomson.com>2022-07-06 14:34:06 -0400
commita0c5275c7942bccbc2c5d686a21f989792b2bc82 (patch)
tree1b3c5f823c19da28b8ecb217e60bdb8f5a337284
parentaf50c16f1214334470d2599ab0a4b0f01032a655 (diff)
downloadlibgit2-a0c5275c7942bccbc2c5d686a21f989792b2bc82.tar.gz
repo: allow users running with sudo to access their repositories
In the ownership checks implemented for CVE-2022-24765, we disallowed users to access their own repositories when running with `sudo`. Examine the `SUDO_UID` environment variable and allow users running with `sudo`. This matches git's behavior.
-rw-r--r--src/fs_path.c51
-rw-r--r--src/fs_path.h7
-rw-r--r--src/repository.c3
3 files changed, 45 insertions, 16 deletions
diff --git a/src/fs_path.c b/src/fs_path.c
index c4cd4f3d6..e9e76ea7b 100644
--- a/src/fs_path.c
+++ b/src/fs_path.c
@@ -1928,27 +1928,36 @@ done:
#else
+static int sudo_uid_lookup(uid_t *out)
+{
+ git_str uid_str = GIT_STR_INIT;
+ int64_t uid;
+ int error;
+
+ if ((error = git__getenv(&uid_str, "SUDO_UID")) == 0 &&
+ (error = git__strntol64(&uid, uid_str.ptr, uid_str.size, NULL, 10)) == 0 &&
+ uid == (int64_t)((uid_t)uid)) {
+ *out = (uid_t)uid;
+ }
+
+ git_str_dispose(&uid_str);
+ return error;
+}
+
int git_fs_path_owner_is(
bool *out,
const char *path,
git_fs_path_owner_t owner_type)
{
- uid_t uids[2] = { 0 };
- size_t uid_count = 0, i;
struct stat st;
+ uid_t euid, sudo_uid;
if (mock_owner) {
*out = ((mock_owner & owner_type) != 0);
return 0;
}
- if (owner_type & GIT_FS_PATH_OWNER_CURRENT_USER)
- uids[uid_count++] = geteuid();
-
- if (owner_type & GIT_FS_PATH_OWNER_ADMINISTRATOR)
- uids[uid_count++] = 0;
-
- *out = false;
+ euid = geteuid();
if (p_lstat(path, &st) != 0) {
if (errno == ENOENT)
@@ -1958,13 +1967,27 @@ int git_fs_path_owner_is(
return -1;
}
- for (i = 0; i < uid_count; i++) {
- if (uids[i] == st.st_uid) {
- *out = true;
- break;
- }
+ if ((owner_type & GIT_FS_PATH_OWNER_CURRENT_USER) != 0 &&
+ st.st_uid == euid) {
+ *out = true;
+ return 0;
+ }
+
+ if ((owner_type & GIT_FS_PATH_OWNER_ADMINISTRATOR) != 0 &&
+ st.st_uid == 0) {
+ *out = true;
+ return 0;
+ }
+
+ if ((owner_type & GIT_FS_PATH_OWNER_RUNNING_SUDO) != 0 &&
+ euid == 0 &&
+ sudo_uid_lookup(&sudo_uid) == 0 &&
+ st.st_uid == sudo_uid) {
+ *out = true;
+ return 0;
}
+ *out = false;
return 0;
}
diff --git a/src/fs_path.h b/src/fs_path.h
index 928644a9d..6be649ff7 100644
--- a/src/fs_path.h
+++ b/src/fs_path.h
@@ -747,8 +747,13 @@ typedef enum {
*/
GIT_FS_PATH_USER_IS_ADMINISTRATOR = (1 << 2),
+ /**
+ * The file is owned by the current user, who is running `sudo`.
+ */
+ GIT_FS_PATH_OWNER_RUNNING_SUDO = (1 << 3),
+
/** The file may be owned by another user. */
- GIT_FS_PATH_OWNER_OTHER = (1 << 3)
+ GIT_FS_PATH_OWNER_OTHER = (1 << 4)
} git_fs_path_owner_t;
/**
diff --git a/src/repository.c b/src/repository.c
index 60357f3da..1af407df9 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -531,7 +531,8 @@ static int validate_ownership_path(bool *is_safe, const char *path)
{
git_fs_path_owner_t owner_level =
GIT_FS_PATH_OWNER_CURRENT_USER |
- GIT_FS_PATH_USER_IS_ADMINISTRATOR;
+ GIT_FS_PATH_USER_IS_ADMINISTRATOR |
+ GIT_FS_PATH_OWNER_RUNNING_SUDO;
int error = 0;
if (path)