Skip to content

Commit d1001fd

Browse files
authored
Merge pull request libgit2#6341 from libgit2/ethomson/ownership2
Fix erroneously lax configuration ownership checks
2 parents 92ffdd2 + 56aaaf5 commit d1001fd

File tree

5 files changed

+174
-109
lines changed

5 files changed

+174
-109
lines changed

src/libgit2/config.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1170,10 +1170,13 @@ int git_config_find_programdata(git_buf *path)
11701170

11711171
int git_config__find_programdata(git_str *path)
11721172
{
1173+
git_fs_path_owner_t owner_level =
1174+
GIT_FS_PATH_OWNER_CURRENT_USER |
1175+
GIT_FS_PATH_OWNER_ADMINISTRATOR;
11731176
bool is_safe;
11741177

11751178
if (git_sysdir_find_programdata_file(path, GIT_CONFIG_FILENAME_PROGRAMDATA) < 0 ||
1176-
git_fs_path_owner_is_system_or_current_user(&is_safe, path->ptr) < 0)
1179+
git_fs_path_owner_is(&is_safe, path->ptr, owner_level) < 0)
11771180
return -1;
11781181

11791182
if (!is_safe) {

src/libgit2/repository.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,10 +509,13 @@ static int validate_ownership(const char *repo_path)
509509
{
510510
git_config *config = NULL;
511511
validate_ownership_data data = { repo_path, GIT_STR_INIT, false };
512+
git_fs_path_owner_t owner_level =
513+
GIT_FS_PATH_OWNER_CURRENT_USER |
514+
GIT_FS_PATH_USER_IS_ADMINISTRATOR;
512515
bool is_safe;
513516
int error;
514517

515-
if ((error = git_fs_path_owner_is_system_or_current_user(&is_safe, repo_path)) < 0) {
518+
if ((error = git_fs_path_owner_is(&is_safe, repo_path, owner_level)) < 0) {
516519
if (error == GIT_ENOTFOUND)
517520
error = 0;
518521

src/util/fs_path.c

Lines changed: 52 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,9 +1785,9 @@ bool git_fs_path_supports_symlinks(const char *dir)
17851785
return supported;
17861786
}
17871787

1788-
static git_fs_path__mock_owner_t mock_owner = GIT_FS_PATH_MOCK_OWNER_NONE;
1788+
static git_fs_path_owner_t mock_owner = GIT_FS_PATH_OWNER_NONE;
17891789

1790-
void git_fs_path__set_owner(git_fs_path__mock_owner_t owner)
1790+
void git_fs_path__set_owner(git_fs_path_owner_t owner)
17911791
{
17921792
mock_owner = owner;
17931793
}
@@ -1879,74 +1879,52 @@ static int file_owner_sid(PSID *out, const char *path)
18791879
return error;
18801880
}
18811881

1882-
int git_fs_path_owner_is_current_user(bool *out, const char *path)
1882+
int git_fs_path_owner_is(
1883+
bool *out,
1884+
const char *path,
1885+
git_fs_path_owner_t owner_type)
18831886
{
18841887
PSID owner_sid = NULL, user_sid = NULL;
1885-
int error = -1;
1888+
BOOL is_admin, admin_owned;
1889+
int error;
18861890

18871891
if (mock_owner) {
1888-
*out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_CURRENT_USER);
1892+
*out = ((mock_owner & owner_type) != 0);
18891893
return 0;
18901894
}
18911895

1892-
if ((error = file_owner_sid(&owner_sid, path)) < 0 ||
1893-
(error = current_user_sid(&user_sid)) < 0)
1896+
if ((error = file_owner_sid(&owner_sid, path)) < 0)
18941897
goto done;
18951898

1896-
*out = EqualSid(owner_sid, user_sid);
1897-
error = 0;
1899+
if ((owner_type & GIT_FS_PATH_OWNER_CURRENT_USER) != 0) {
1900+
if ((error = current_user_sid(&user_sid)) < 0)
1901+
goto done;
18981902

1899-
done:
1900-
git__free(owner_sid);
1901-
git__free(user_sid);
1902-
return error;
1903-
}
1904-
1905-
int git_fs_path_owner_is_system(bool *out, const char *path)
1906-
{
1907-
PSID owner_sid;
1908-
1909-
if (mock_owner) {
1910-
*out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_SYSTEM);
1911-
return 0;
1912-
}
1913-
1914-
if (file_owner_sid(&owner_sid, path) < 0)
1915-
return -1;
1916-
1917-
*out = IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) ||
1918-
IsWellKnownSid(owner_sid, WinLocalSystemSid);
1919-
1920-
git__free(owner_sid);
1921-
return 0;
1922-
}
1923-
1924-
int git_fs_path_owner_is_system_or_current_user(bool *out, const char *path)
1925-
{
1926-
PSID owner_sid = NULL, user_sid = NULL;
1927-
int error = -1;
1928-
1929-
if (mock_owner) {
1930-
*out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_SYSTEM ||
1931-
mock_owner == GIT_FS_PATH_MOCK_OWNER_CURRENT_USER);
1932-
return 0;
1903+
if (EqualSid(owner_sid, user_sid)) {
1904+
*out = true;
1905+
goto done;
1906+
}
19331907
}
19341908

1935-
if (file_owner_sid(&owner_sid, path) < 0)
1936-
goto done;
1909+
admin_owned =
1910+
IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) ||
1911+
IsWellKnownSid(owner_sid, WinLocalSystemSid);
19371912

1938-
if (IsWellKnownSid(owner_sid, WinBuiltinAdministratorsSid) ||
1939-
IsWellKnownSid(owner_sid, WinLocalSystemSid)) {
1940-
*out = 1;
1941-
error = 0;
1913+
if (admin_owned &&
1914+
(owner_type & GIT_FS_PATH_OWNER_ADMINISTRATOR) != 0) {
1915+
*out = true;
19421916
goto done;
19431917
}
19441918

1945-
if (current_user_sid(&user_sid) < 0)
1919+
if (admin_owned &&
1920+
(owner_type & GIT_FS_PATH_USER_IS_ADMINISTRATOR) != 0 &&
1921+
CheckTokenMembership(NULL, owner_sid, &is_admin) &&
1922+
is_admin) {
1923+
*out = true;
19461924
goto done;
1925+
}
19471926

1948-
*out = EqualSid(owner_sid, user_sid);
1949-
error = 0;
1927+
*out = false;
19501928

19511929
done:
19521930
git__free(owner_sid);
@@ -1956,10 +1934,25 @@ int git_fs_path_owner_is_system_or_current_user(bool *out, const char *path)
19561934

19571935
#else
19581936

1959-
static int fs_path_owner_is(bool *out, const char *path, uid_t *uids, size_t uids_len)
1937+
int git_fs_path_owner_is(
1938+
bool *out,
1939+
const char *path,
1940+
git_fs_path_owner_t owner_type)
19601941
{
1942+
uid_t uids[2] = { 0 };
1943+
size_t uid_count = 0, i;
19611944
struct stat st;
1962-
size_t i;
1945+
1946+
if (mock_owner) {
1947+
*out = ((mock_owner & owner_type) != 0);
1948+
return 0;
1949+
}
1950+
1951+
if (owner_type & GIT_FS_PATH_OWNER_CURRENT_USER)
1952+
uids[uid_count++] = geteuid();
1953+
1954+
if (owner_type & GIT_FS_PATH_OWNER_ADMINISTRATOR)
1955+
uids[uid_count++] = 0;
19631956

19641957
*out = false;
19651958

@@ -1971,7 +1964,7 @@ static int fs_path_owner_is(bool *out, const char *path, uid_t *uids, size_t uid
19711964
return -1;
19721965
}
19731966

1974-
for (i = 0; i < uids_len; i++) {
1967+
for (i = 0; i < uid_count; i++) {
19751968
if (uids[i] == st.st_uid) {
19761969
*out = true;
19771970
break;
@@ -1981,45 +1974,18 @@ static int fs_path_owner_is(bool *out, const char *path, uid_t *uids, size_t uid
19811974
return 0;
19821975
}
19831976

1977+
#endif
1978+
19841979
int git_fs_path_owner_is_current_user(bool *out, const char *path)
19851980
{
1986-
uid_t userid = geteuid();
1987-
1988-
if (mock_owner) {
1989-
*out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_CURRENT_USER);
1990-
return 0;
1991-
}
1992-
1993-
return fs_path_owner_is(out, path, &userid, 1);
1981+
return git_fs_path_owner_is(out, path, GIT_FS_PATH_OWNER_CURRENT_USER);
19941982
}
19951983

19961984
int git_fs_path_owner_is_system(bool *out, const char *path)
19971985
{
1998-
uid_t userid = 0;
1999-
2000-
if (mock_owner) {
2001-
*out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_SYSTEM);
2002-
return 0;
2003-
}
2004-
2005-
return fs_path_owner_is(out, path, &userid, 1);
2006-
}
2007-
2008-
int git_fs_path_owner_is_system_or_current_user(bool *out, const char *path)
2009-
{
2010-
uid_t userids[2] = { geteuid(), 0 };
2011-
2012-
if (mock_owner) {
2013-
*out = (mock_owner == GIT_FS_PATH_MOCK_OWNER_SYSTEM ||
2014-
mock_owner == GIT_FS_PATH_MOCK_OWNER_CURRENT_USER);
2015-
return 0;
2016-
}
2017-
2018-
return fs_path_owner_is(out, path, userids, 2);
1986+
return git_fs_path_owner_is(out, path, GIT_FS_PATH_OWNER_ADMINISTRATOR);
20191987
}
20201988

2021-
#endif
2022-
20231989
int git_fs_path_find_executable(git_str *fullpath, const char *executable)
20241990
{
20251991
#ifdef GIT_WIN32

src/util/fs_path.h

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -732,18 +732,37 @@ int git_fs_path_normalize_slashes(git_str *out, const char *path);
732732
bool git_fs_path_supports_symlinks(const char *dir);
733733

734734
typedef enum {
735-
GIT_FS_PATH_MOCK_OWNER_NONE = 0, /* do filesystem lookups as normal */
736-
GIT_FS_PATH_MOCK_OWNER_SYSTEM = 1,
737-
GIT_FS_PATH_MOCK_OWNER_CURRENT_USER = 2,
738-
GIT_FS_PATH_MOCK_OWNER_OTHER = 3
739-
} git_fs_path__mock_owner_t;
735+
GIT_FS_PATH_OWNER_NONE = 0,
736+
737+
/** The file must be owned by the current user. */
738+
GIT_FS_PATH_OWNER_CURRENT_USER = (1 << 0),
739+
740+
/** The file must be owned by the system account. */
741+
GIT_FS_PATH_OWNER_ADMINISTRATOR = (1 << 1),
742+
743+
/**
744+
* The file may be owned by a system account if the current
745+
* user is in an administrator group. Windows only; this is
746+
* a noop on non-Windows systems.
747+
*/
748+
GIT_FS_PATH_USER_IS_ADMINISTRATOR = (1 << 2),
749+
750+
/** The file may be owned by another user. */
751+
GIT_FS_PATH_OWNER_OTHER = (1 << 3)
752+
} git_fs_path_owner_t;
740753

741754
/**
742755
* Sets the mock ownership for files; subsequent calls to
743-
* `git_fs_path_owner_is_*` functions will return this data until cleared
744-
* with `GIT_FS_PATH_MOCK_OWNER_NONE`.
756+
* `git_fs_path_owner_is_*` functions will return this data until
757+
* cleared with `GIT_FS_PATH_OWNER_NONE`.
745758
*/
746-
void git_fs_path__set_owner(git_fs_path__mock_owner_t owner);
759+
void git_fs_path__set_owner(git_fs_path_owner_t owner);
760+
761+
/** Verify that the file in question is owned by the given owner. */
762+
int git_fs_path_owner_is(
763+
bool *out,
764+
const char *path,
765+
git_fs_path_owner_t owner_type);
747766

748767
/**
749768
* Verify that the file in question is owned by an administrator or system
@@ -757,12 +776,6 @@ int git_fs_path_owner_is_system(bool *out, const char *path);
757776

758777
int git_fs_path_owner_is_current_user(bool *out, const char *path);
759778

760-
/**
761-
* Verify that the file in question is owned by an administrator or system
762-
* account _or_ the current user;
763-
*/
764-
int git_fs_path_owner_is_system_or_current_user(bool *out, const char *path);
765-
766779
/**
767780
* Search the current PATH for the given executable, returning the full
768781
* path if it is found.

0 commit comments

Comments
 (0)