Skip to content

Commit cb1439c

Browse files
dschoethomson
authored andcommitted
config: validate ownership of C:\ProgramData\Git\config before using it
When the VirtualStore feature is in effect, it is safe to let random users write into C:\ProgramData because other users won't see those files. This seemed to be the case when we introduced support for C:\ProgramData\Git\config. However, when that feature is not in effect (which seems to be the case in newer Windows 10 versions), we'd rather not use those files unless they come from a trusted source, such as an administrator. This change imitates the strategy chosen by PowerShell's native OpenSSH port to Windows regarding host key files: if a system file is owned neither by an administrator, a system account, or the current user, it is ignored.
1 parent 5774b2b commit cb1439c

File tree

3 files changed

+97
-1
lines changed

3 files changed

+97
-1
lines changed

src/config.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1111,8 +1111,15 @@ int git_config_find_system(git_buf *path)
11111111

11121112
int git_config_find_programdata(git_buf *path)
11131113
{
1114+
int ret;
1115+
11141116
git_buf_sanitize(path);
1115-
return git_sysdir_find_programdata_file(path, GIT_CONFIG_FILENAME_PROGRAMDATA);
1117+
ret = git_sysdir_find_programdata_file(path,
1118+
GIT_CONFIG_FILENAME_PROGRAMDATA);
1119+
if (ret != GIT_OK)
1120+
return ret;
1121+
1122+
return git_path_validate_system_file_ownership(path->ptr);
11161123
}
11171124

11181125
int git_config__global_location(git_buf *buf)

src/path.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "win32/w32_buffer.h"
1515
#include "win32/w32_util.h"
1616
#include "win32/version.h"
17+
#include <AclAPI.h>
1718
#else
1819
#include <dirent.h>
1920
#endif
@@ -1946,3 +1947,79 @@ bool git_path_supports_symlinks(const char *dir)
19461947
git_buf_dispose(&path);
19471948
return supported;
19481949
}
1950+
1951+
int git_path_validate_system_file_ownership(const char *path)
1952+
{
1953+
#ifndef GIT_WIN32
1954+
GIT_UNUSED(path);
1955+
return GIT_OK;
1956+
#else
1957+
git_win32_path buf;
1958+
PSID owner_sid;
1959+
PSECURITY_DESCRIPTOR descriptor = NULL;
1960+
HANDLE token;
1961+
TOKEN_USER *info = NULL;
1962+
DWORD err, len;
1963+
int ret;
1964+
1965+
if (git_win32_path_from_utf8(buf, path) < 0)
1966+
return -1;
1967+
1968+
err = GetNamedSecurityInfoW(buf, SE_FILE_OBJECT,
1969+
OWNER_SECURITY_INFORMATION |
1970+
DACL_SECURITY_INFORMATION,
1971+
&owner_sid, NULL, NULL, NULL, &descriptor);
1972+
1973+
if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND) {
1974+
ret = GIT_ENOTFOUND;
1975+
goto cleanup;
1976+
}
1977+
1978+
if (err != ERROR_SUCCESS) {
1979+
git_error_set(GIT_ERROR_OS, "failed to get security information");
1980+
ret = GIT_ERROR;
1981+
goto cleanup;
1982+
}
1983+
1984+
if (!IsValidSid(owner_sid)) {
1985+
git_error_set(GIT_ERROR_INVALID, "programdata configuration file owner is unknown");
1986+
ret = GIT_ERROR;
1987+
goto cleanup;
1988+
}
1989+
1990+
if (IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) ||
1991+
IsWellKnownSid(owner_sid, WinLocalSystemSid)) {
1992+
ret = GIT_OK;
1993+
goto cleanup;
1994+
}
1995+
1996+
/* Obtain current user's SID */
1997+
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token) &&
1998+
!GetTokenInformation(token, TokenUser, NULL, 0, &len)) {
1999+
info = git__malloc(len);
2000+
GIT_ERROR_CHECK_ALLOC(info);
2001+
if (!GetTokenInformation(token, TokenUser, info, len, &len)) {
2002+
git__free(info);
2003+
info = NULL;
2004+
}
2005+
}
2006+
2007+
/*
2008+
* If the file is owned by the same account that is running the current
2009+
* process, it's okay to read from that file.
2010+
*/
2011+
if (info && EqualSid(owner_sid, info->User.Sid))
2012+
ret = GIT_OK;
2013+
else {
2014+
git_error_set(GIT_ERROR_INVALID, "programdata configuration file owner is not valid");
2015+
ret = GIT_ERROR;
2016+
}
2017+
free(info);
2018+
2019+
cleanup:
2020+
if (descriptor)
2021+
LocalFree(descriptor);
2022+
2023+
return ret;
2024+
#endif
2025+
}

src/path.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,4 +649,16 @@ int git_path_normalize_slashes(git_buf *out, const char *path);
649649

650650
bool git_path_supports_symlinks(const char *dir);
651651

652+
/**
653+
* Validate a system file's ownership
654+
*
655+
* Verify that the file in question is owned by an administrator or system
656+
* account, or at least by the current user.
657+
*
658+
* This function returns 0 if successful. If the file is not owned by any of
659+
* these, or any other if there have been problems determining the file
660+
* ownership, it returns -1.
661+
*/
662+
int git_path_validate_system_file_ownership(const char *path);
663+
652664
#endif

0 commit comments

Comments
 (0)