Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
b45219f
Implement custom thread local storage for user of library
implausible Mar 29, 2021
7a76a33
checkout: cleanup duplication in checkout_create_the_new
implausible Aug 12, 2020
07493cc
thread checkout: move checkout buffers to tls
implausible Mar 29, 2021
e1a1eaa
thread checkout: add locks around shared state
implausible Aug 12, 2020
dc4e588
thread checkout: add locks around non thread-safe actions
implausible Apr 9, 2021
0739689
thread checkout: stub indirection for threading
implausible Aug 12, 2020
27f3c80
thread checkout: add threading to checkout_create_the_new
implausible Mar 29, 2021
37caa8d
meta: show build status for v1.3 branch
ethomson Feb 26, 2022
6b12762
online: test with https instead of git protocol
ethomson Jan 11, 2022
670415a
clone: update bitbucket tests
ethomson Mar 23, 2022
973d959
path: refactor ownership checks into current user and system
ethomson Apr 10, 2022
62d492d
repo: ensure that repo dir is owned by current user
ethomson Apr 11, 2022
e4eabb0
fs_path: mock ownership checks
ethomson Apr 12, 2022
caee92e
repo: test configuration ownership validation
ethomson Apr 11, 2022
f683806
repo: refactor global config loader function
ethomson Apr 11, 2022
eb8c3e5
repo: honor safe.directory during ownership checks
ethomson Apr 11, 2022
b58e905
repo: make ownership checks optional
ethomson Apr 12, 2022
a9eac6a
Merge pull request #6268 from libgit2/ethomson/ownership_13
ethomson Apr 12, 2022
1f39aac
meta: update version numbers for v1.3.1
ethomson Apr 12, 2022
23c24f8
meta: changelog for v1.3.1
ethomson Apr 12, 2022
1f5e7f9
Merge pull request #6271 from libgit2/ethomson/v1.3.1
ethomson Apr 12, 2022
6da6a10
Merge remote-tracking branch 'zawata/feature/custom-tls-for-external-…
zawata Apr 13, 2022
30d5c08
Merge remote-tracking branch 'zawata/multithread/checkout_create_the_…
zawata Apr 13, 2022
4b193b1
New checkout option: disabled_filters
julianmesa-gitkraken May 6, 2022
fe44f25
Merge branch 'disabled-filters-checkout' into libgit-next
ianhattendorf May 7, 2022
e78ee33
Fix degraded performance using GIT_USE_NSEC on repos cloned with GIT_…
julianmesa-gitkraken May 18, 2022
013d416
Merge pull request #7 from julianmesa-gitkraken/fix-nanoseconds-on-no…
ianhattendorf May 18, 2022
3ad710a
Fix the GIT_USE_NSEC performance fix
julianmesa-gitkraken May 26, 2022
4c98283
Merge pull request #8 from julianmesa-gitkraken/fix-nsecs-fix
ianhattendorf May 26, 2022
d6554d0
stash: introduce `build_stash_commit_from_index`
gitkraken-jacobw Jul 14, 2022
8280bb0
stash: implement partial stashing by path
gitkraken-jacobw Jul 14, 2022
65210e9
stash: implement CI testing
gitkraken-jacobw Jun 17, 2022
ec67f95
stash: better option validation for stash save
gitkraken-jacobw Jul 14, 2022
f2befe8
stash: add `const` to arguments
gitkraken-jacobw Jul 13, 2022
98faa3e
stash: test save options init
gitkraken-jacobw Jul 13, 2022
0ac7af7
Merge pull request #1 from gitkraken-jacobw/partialstashing
zawata Jul 28, 2022
e6b6ed0
Fix leak in git_tag_create_from_buffer
julianmesa-gitkraken Nov 3, 2022
d4b247d
Missing disposes
julianmesa-gitkraken Nov 3, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
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.
  • Loading branch information
ethomson committed Apr 12, 2022
commit 973d959abaa5faaddec6a4c27889ff5b980d2550
16 changes: 10 additions & 6 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
git_error_set(GIT_ERROR_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)
Expand Down
231 changes: 174 additions & 57 deletions src/path.c
Original file line number Diff line number Diff line change
Expand Up @@ -2024,78 +2024,195 @@ bool git_path_supports_symlinks(const char *dir)
return supported;
}

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)) {
git_error_set(GIT_ERROR_OS, "could not duplicate sid");
git__free(dup);
return NULL;
}

if (err != ERROR_SUCCESS) {
git_error_set(GIT_ERROR_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 (!IsValidSid(owner_sid)) {
git_error_set(GIT_ERROR_INVALID, "programdata configuration file owner is unknown");
ret = GIT_ERROR;
goto cleanup;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
git_error_set(GIT_ERROR_OS, "could not lookup process information");
goto done;
}

if (IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) ||
IsWellKnownSid(owner_sid, WinLocalSystemSid)) {
ret = GIT_OK;
goto cleanup;
}

/* 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 (GetTokenInformation(token, TokenUser, NULL, 0, &len) ||
GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
git_error_set(GIT_ERROR_OS, "could not lookup token metadata");
goto done;
}

/*
* 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 {
git_error_set(GIT_ERROR_INVALID, "programdata configuration file owner is not valid");
ret = GIT_ERROR;
info = git__malloc(len);
GIT_ERROR_CHECK_ALLOC(info);

if (!GetTokenInformation(token, TokenUser, info, len, &len)) {
git_error_set(GIT_ERROR_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)
git_error_set(GIT_ERROR_OS, "failed to get security information");
else if (!IsValidSid(owner_sid))
git_error_set(GIT_ERROR_OS, "file owner is not valid");
else if ((*out = sid_dup(owner_sid)))
error = 0;

cleanup:
if (descriptor)
LocalFree(descriptor);

return ret;
#endif
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)) {
*out = 1;
error = 0;
goto done;
}

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;

git_error_set(GIT_ERROR_OS, "could not stat '%s'", path);
return -1;
}

for (i = 0; i < uids_len; i++) {
if (uids[i] == st.st_uid) {
*out = true;
break;
}
}

return 0;
}

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
22 changes: 14 additions & 8 deletions src/path.h
Original file line number Diff line number Diff line change
Expand Up @@ -723,15 +723,21 @@ int git_path_normalize_slashes(git_buf *out, const char *path);
bool git_path_supports_symlinks(const char *dir);

/**
* 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
25 changes: 25 additions & 0 deletions tests/core/path.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

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
}