From 09291283528f889031d7309079c41c78eb7ed8de Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Tue, 2 Jun 2026 08:10:00 +0200 Subject: [PATCH] Extend Win32 safe.directory admin-owner check to also cover non-elevated processes The current implementation which checks whether the current user is in the administrators group only works if the process runs elevated. Another check using a so-called "linked token" is necessary which exists when administrators run in non-elevated mode. Based on Git commit 03a4e46d122d5f24b6e1cd872eb996851c1563da. Signed-off-by: Sven Strickroth --- src/util/fs_path.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/util/fs_path.c b/src/util/fs_path.c index 5be2da35b..3fe478c27 100644 --- a/src/util/fs_path.c +++ b/src/util/fs_path.c @@ -1862,8 +1862,6 @@ static int current_user_sid(PSID *sid, HANDLE *linked_token) TOKEN_ELEVATION_TYPE elevation_type; DWORD size; - *linked_token = NULL; - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) { git_error_set(GIT_ERROR_OS, "could not lookup process information"); goto done; @@ -1883,19 +1881,21 @@ static int current_user_sid(PSID *sid, HANDLE *linked_token) goto done; } - if ((*sid = sid_dup(info->User.Sid))) - error = 0; - if (GetTokenInformation(token, TokenElevationType, &elevation_type, sizeof(elevation_type), &size) && elevation_type == TokenElevationTypeLimited) { /* * The current process is run by a member of the Administrators group * but is not running elevated. */ - if (!GetTokenInformation(token, TokenLinkedToken, linked_token, sizeof(HANDLE), &size)) { - linked_token = NULL; + if (!GetTokenInformation(token, TokenLinkedToken, linked_token, sizeof(HANDLE), &size)) { + CloseHandle(*linked_token); + *linked_token = NULL; } } + + if ((*sid = sid_dup(info->User.Sid))) + error = 0; + done: if (token) CloseHandle(token); @@ -1940,7 +1940,7 @@ int git_fs_path_owner_is( git_fs_path_owner_t owner_type) { PSID owner_sid = NULL, user_sid = NULL; - static HANDLE linked_token; + HANDLE linked_token = NULL; BOOL is_admin, admin_owned; int error; @@ -1949,17 +1949,14 @@ int git_fs_path_owner_is( return 0; } - if ((error = file_owner_sid(&owner_sid, path)) < 0) + if ((error = file_owner_sid(&owner_sid, path)) < 0 || + (error = current_user_sid(&user_sid, &linked_token)) < 0) goto done; - if ((owner_type & GIT_FS_PATH_OWNER_CURRENT_USER) != 0) { - if ((error = current_user_sid(&user_sid, &linked_token)) < 0) - goto done; - - if (EqualSid(owner_sid, user_sid)) { - *out = true; - goto done; - } + if ((owner_type & GIT_FS_PATH_OWNER_CURRENT_USER) != 0 && + EqualSid(owner_sid, user_sid)) { + *out = true; + goto done; } admin_owned = @@ -1974,8 +1971,8 @@ int git_fs_path_owner_is( if (admin_owned && (owner_type & GIT_FS_PATH_USER_IS_ADMINISTRATOR) != 0 && - (CheckTokenMembership(NULL, owner_sid, &is_admin) && - CheckTokenMembership(linked_token, owner_sid, &is_admin)) && + CheckTokenMembership(NULL, owner_sid, &is_admin) && + CheckTokenMembership(linked_token, owner_sid, &is_admin) && is_admin) { *out = true; goto done; @@ -1984,6 +1981,9 @@ int git_fs_path_owner_is( *out = false; done: + if (linked_token) + CloseHandle(linked_token); + git__free(owner_sid); git__free(user_sid); return error;