Skip to content

Commit 08cfa43

Browse files
authored
Merge pull request libgit2#5202 from libgit2/users/ethomson/security_updates
Security updates from 0.28.3
2 parents 5774b2b + df3f18a commit 08cfa43

File tree

5 files changed

+113
-3
lines changed

5 files changed

+113
-3
lines changed

docs/changelog.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ v0.28 + 1
2222
* libgit2 can now correctly cope with URLs where the host contains a colon
2323
but a port is not specified. (eg `http://example.com:/repo.git`).
2424

25+
* A carefully constructed commit object with a very large number
26+
of parents may lead to potential out-of-bounds writes or
27+
potential denial of service.
28+
29+
* The ProgramData configuration file is always read for compatibility
30+
with Git for Windows and Portable Git installations. The ProgramData
31+
location is not necessarily writable only by administrators, so we
32+
now ensure that the configuration file is owned by the administrator
33+
or the current user.
34+
2535
v0.28
2636
-----
2737

src/commit_list.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,15 @@ static int commit_error(git_commit_list_node *commit, const char *msg)
6969
static git_commit_list_node **alloc_parents(
7070
git_revwalk *walk, git_commit_list_node *commit, size_t n_parents)
7171
{
72+
size_t bytes;
73+
7274
if (n_parents <= PARENTS_PER_COMMIT)
7375
return (git_commit_list_node **)((char *)commit + sizeof(git_commit_list_node));
7476

75-
return (git_commit_list_node **)git_pool_malloc(
76-
&walk->commit_pool, (n_parents * sizeof(git_commit_list_node *)));
77+
if (git__multiply_sizet_overflow(&bytes, n_parents, sizeof(git_commit_list_node *)))
78+
return NULL;
79+
80+
return (git_commit_list_node **)git_pool_malloc(&walk->commit_pool, bytes);
7781
}
7882

7983

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)