Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15-SP1:GA
libgit2.34826
0001-path-refactor-ownership-checks-into-curren...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0001-path-refactor-ownership-checks-into-current-user-and.patch of Package libgit2.34826
From 973d959abaa5faaddec6a4c27889ff5b980d2550 Mon Sep 17 00:00:00 2001 From: Edward Thomson <ethomson@edwardthomson.com> Date: Sun, 10 Apr 2022 21:29:43 +0100 Subject: [PATCH 01/20] path: refactor ownership checks into current user and system Provide individual file ownership checks for both the current user and the system user, as well as a combined current user and system user check. --- src/config.c | 16 ++-- src/path.c | 231 ++++++++++++++++++++++++++++++++++------------ src/path.h | 22 +++-- tests/core/path.c | 25 +++++ 4 files changed, 223 insertions(+), 71 deletions(-) diff --git a/src/config.c b/src/config.c index 3251cd51f..489eee643 100644 --- a/src/config.c +++ b/src/config.c @@ -1118,16 +1118,20 @@ int git_config_find_system(git_buf *path) int git_config_find_programdata(git_buf *path) { int ret; + bool is_safe; - if ((ret = git_buf_sanitize(path)) < 0) + if ((ret = git_buf_sanitize(path)) < 0 || + (ret = git_sysdir_find_programdata_file(path, + GIT_CONFIG_FILENAME_PROGRAMDATA)) < 0 || + (ret = git_path_owner_is_system_or_current_user(&is_safe, path->ptr)) < 0) return ret; - ret = git_sysdir_find_programdata_file(path, - GIT_CONFIG_FILENAME_PROGRAMDATA); - if (ret != GIT_OK) - return ret; + if (!is_safe) { #+ giterr_set(GIT_ERROR_CONFIG, "programdata path has invalid ownership"); + giterr_set(GITERR_CONFIG, "programdata path has invalid ownership"); + return -1; + } - return git_path_validate_system_file_ownership(path->ptr); + return 0; } int git_config__global_location(git_buf *buf) diff --git a/src/path.c b/src/path.c index c444b31a7..b3bb0b408 100644 --- a/src/path.c +++ b/src/path.c @@ -1942,78 +1942,195 @@ # } return git_path_is_ntfs_dotgit_attributes(name, len); } -int git_path_validate_system_file_ownership(const char *path) +#ifdef GIT_WIN32 +static PSID *sid_dup(PSID sid) { -#ifndef GIT_WIN32 - GIT_UNUSED(path); - return GIT_OK; -#else - git_win32_path buf; - PSID owner_sid; - PSECURITY_DESCRIPTOR descriptor = NULL; - HANDLE token; - TOKEN_USER *info = NULL; - DWORD err, len; - int ret; + DWORD len; + PSID dup; - if (git_win32_path_from_utf8(buf, path) < 0) - return -1; + len = GetLengthSid(sid); - err = GetNamedSecurityInfoW(buf, SE_FILE_OBJECT, - OWNER_SECURITY_INFORMATION | - DACL_SECURITY_INFORMATION, - &owner_sid, NULL, NULL, NULL, &descriptor); + if ((dup = git__malloc(len)) == NULL) + return NULL; - if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) { - ret = GIT_ENOTFOUND; - goto cleanup; + if (!CopySid(len, dup, sid)) { + giterr_set(GITERR_OS, "could not duplicate sid"); + git__free(dup); + return NULL; } - if (err != ERROR_SUCCESS) { - giterr_set(GITERR_OS, "failed to get security information"); - ret = GIT_ERROR; - goto cleanup; + return dup; +} + +static int current_user_sid(PSID *out) +{ + TOKEN_USER *info = NULL; + HANDLE token = NULL; + DWORD len = 0; + int error = -1; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) { + giterr_set(GITERR_OS, "could not lookup process information"); + goto done; } - if (!IsValidSid(owner_sid)) { - giterr_set(GITERR_INVALID, "programdata configuration file owner is unknown"); - ret = GIT_ERROR; - goto cleanup; + if (GetTokenInformation(token, TokenUser, NULL, 0, &len) || + GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + giterr_set(GITERR_OS, "could not lookup token metadata"); + goto done; + } + + info = git__malloc(len); + GIT_ERROR_CHECK_ALLOC(info); + + if (!GetTokenInformation(token, TokenUser, info, len, &len)) { + giterr_set(GITERR_OS, "could not lookup current user"); + goto done; } + if ((*out = sid_dup(info->User.Sid))) + error = 0; + +done: + if (token) + CloseHandle(token); + + git__free(info); + return error; +} + +static int file_owner_sid(PSID *out, const char *path) +{ + git_win32_path path_w32; + PSECURITY_DESCRIPTOR descriptor = NULL; + PSID owner_sid; + DWORD ret; + int error = -1; + + if (git_win32_path_from_utf8(path_w32, path) < 0) + return -1; + + ret = GetNamedSecurityInfoW(path_w32, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + &owner_sid, NULL, NULL, NULL, &descriptor); + + if (ret == ERROR_FILE_NOT_FOUND || ret == ERROR_PATH_NOT_FOUND) + error = GIT_ENOTFOUND; + else if (ret != ERROR_SUCCESS) + giterr_set(GITERR_OS, "failed to get security information"); + else if (!IsValidSid(owner_sid)) + giterr_set(GITERR_OS, "file owner is not valid"); + else if ((*out = sid_dup(owner_sid))) + error = 0; + + if (descriptor) + LocalFree(descriptor); + + return error; +} + +int git_path_owner_is_current_user(bool *out, const char *path) +{ + PSID owner_sid = NULL, user_sid = NULL; + int error = -1; + + if ((error = file_owner_sid(&owner_sid, path)) < 0 || + (error = current_user_sid(&user_sid)) < 0) + goto done; + + *out = EqualSid(owner_sid, user_sid); + error = 0; + +done: + git__free(owner_sid); + git__free(user_sid); + return error; +} + +int git_path_owner_is_system(bool *out, const char *path) +{ + PSID owner_sid; + + if (file_owner_sid(&owner_sid, path) < 0) + return -1; + + *out = IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) || + IsWellKnownSid(owner_sid, WinLocalSystemSid); + + git__free(owner_sid); + return 0; +} + +int git_path_owner_is_system_or_current_user(bool *out, const char *path) +{ + PSID owner_sid = NULL, user_sid = NULL; + int error = -1; + + if (file_owner_sid(&owner_sid, path) < 0) + goto done; + if (IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) || IsWellKnownSid(owner_sid, WinLocalSystemSid)) { - ret = GIT_OK; - goto cleanup; + *out = 1; + error = 0; + goto done; } - /* Obtain current user's SID */ - if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token) && - !GetTokenInformation(token, TokenUser, NULL, 0, &len)) { - info = git__malloc(len); - GIT_ERROR_CHECK_ALLOC(info); - if (!GetTokenInformation(token, TokenUser, info, len, &len)) { - git__free(info); - info = NULL; - } + if (current_user_sid(&user_sid) < 0) + goto done; + + *out = EqualSid(owner_sid, user_sid); + error = 0; + +done: + git__free(owner_sid); + git__free(user_sid); + return error; +} + +#else + +static int path_owner_is(bool *out, const char *path, uid_t *uids, size_t uids_len) +{ + struct stat st; + size_t i; + + *out = false; + + if (p_lstat(path, &st) != 0) { + if (errno == ENOENT) + return GIT_ENOTFOUND; + + giterr_set(GITERR_OS, "could not stat '%s'", path); + return -1; } - /* - * If the file is owned by the same account that is running the current - * process, it's okay to read from that file. - */ - if (info && EqualSid(owner_sid, info->User.Sid)) - ret = GIT_OK; - else { - giterr_set(GITERR_INVALID, "programdata configuration file owner is not valid"); - ret = GIT_ERROR; + for (i = 0; i < uids_len; i++) { + if (uids[i] == st.st_uid) { + *out = true; + break; + } } - free(info); -cleanup: - if (descriptor) - LocalFree(descriptor); + return 0; +} - return ret; -#endif +int git_path_owner_is_current_user(bool *out, const char *path) +{ + uid_t userid = geteuid(); + return path_owner_is(out, path, &userid, 1); } + +int git_path_owner_is_system(bool *out, const char *path) +{ + uid_t userid = 0; + return path_owner_is(out, path, &userid, 1); +} + +int git_path_owner_is_system_or_current_user(bool *out, const char *path) +{ + uid_t userids[2] = { geteuid(), 0 }; + return path_owner_is(out, path, userids, 2); +} + +#endif diff --git a/src/path.h b/src/path.h index de6ec8ff2..699945bd7 100644 --- a/src/path.h +++ b/src/path.h @@ -723,15 +723,21 @@ int git_path_normalize_slashes(git_buf *out, const char *path); # bool git_path_supports_symlinks(const char *dir); # int git_path_normalize_slashes(git_buf *out, const char *path); extern int git_path_is_hfs_dotgit_attributes(const char *name, size_t len); /** - * Validate a system file's ownership - * * Verify that the file in question is owned by an administrator or system - * account, or at least by the current user. - * - * This function returns 0 if successful. If the file is not owned by any of - * these, or any other if there have been problems determining the file - * ownership, it returns -1. + * account. + */ +int git_path_owner_is_system(bool *out, const char *path); + +/** + * Verify that the file in question is owned by the current user; + */ + +int git_path_owner_is_current_user(bool *out, const char *path); + +/** + * Verify that the file in question is owned by an administrator or system + * account _or_ the current user; */ -int git_path_validate_system_file_ownership(const char *path); +int git_path_owner_is_system_or_current_user(bool *out, const char *path); #endif diff --git a/tests/core/path.c b/tests/core/path.c index eac3573fe..321b492c9 100644 --- a/tests/core/path.c +++ b/tests/core/path.c @@ -659,3 +659,28 @@ void test_core_path__git_path_is_file(void) # cl_git_pass(git_path_is_gitfile("blob", 4, GIT_PATH_GITFILE_GITATTRIBUTES, GIT_PATH_FS_HFS)); # cl_git_fail(git_path_is_gitfile("blob", 4, 3, GIT_PATH_FS_HFS)); assert_common_dirlen(6, "a/b/c/foo.txt", "a/b/c/d/e/bar.txt"); assert_common_dirlen(7, "/a/b/c/foo.txt", "/a/b/c/d/e/bar.txt"); } + +void test_core_path__validate_current_user_ownership(void) +{ + bool is_cur; + + cl_must_pass(p_mkdir("testdir", 0777)); + cl_git_pass(git_path_owner_is_current_user(&is_cur, "testdir")); + cl_assert_equal_i(is_cur, 1); + + cl_git_rewritefile("testfile", "This is a test file."); + cl_git_pass(git_path_owner_is_current_user(&is_cur, "testfile")); + cl_assert_equal_i(is_cur, 1); + +#ifdef GIT_WIN32 + cl_git_pass(git_path_owner_is_current_user(&is_cur, "C:\\")); + cl_assert_equal_i(is_cur, 0); + + cl_git_fail(git_path_owner_is_current_user(&is_cur, "c:\\path\\does\\not\\exist")); +#else + cl_git_pass(git_path_owner_is_current_user(&is_cur, "/")); + cl_assert_equal_i(is_cur, 0); + + cl_git_fail(git_path_owner_is_current_user(&is_cur, "/path/does/not/exist")); +#endif +} -- 2.37.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor