diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2022-07-05 23:47:15 -0400 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2022-07-06 14:34:06 -0400 |
commit | a0c5275c7942bccbc2c5d686a21f989792b2bc82 (patch) | |
tree | 1b3c5f823c19da28b8ecb217e60bdb8f5a337284 | |
parent | af50c16f1214334470d2599ab0a4b0f01032a655 (diff) | |
download | libgit2-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.c | 51 | ||||
-rw-r--r-- | src/fs_path.h | 7 | ||||
-rw-r--r-- | src/repository.c | 3 |
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) |