Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
4ae8704b
Unverified
Commit
4ae8704b
authored
Jul 12, 2022
by
Edward Thomson
Committed by
GitHub
Jul 12, 2022
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #6349 from libgit2/ethomson/cve-2022-29187
Fixes for CVE 2022-29187
parents
d1001fd0
ed24b8ba
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
117 additions
and
41 deletions
+117
-41
src/libgit2/repository.c
+76
-28
src/util/fs_path.c
+35
-12
src/util/fs_path.h
+6
-1
No files found.
src/libgit2/repository.c
View file @
4ae8704b
...
@@ -488,7 +488,7 @@ static int read_gitfile(git_str *path_out, const char *file_path)
...
@@ -488,7 +488,7 @@ static int read_gitfile(git_str *path_out, const char *file_path)
typedef
struct
{
typedef
struct
{
const
char
*
repo_path
;
const
char
*
repo_path
;
git_str
tmp
;
git_str
tmp
;
bool
is_safe
;
bool
*
is_safe
;
}
validate_ownership_data
;
}
validate_ownership_data
;
static
int
validate_ownership_cb
(
const
git_config_entry
*
entry
,
void
*
payload
)
static
int
validate_ownership_cb
(
const
git_config_entry
*
entry
,
void
*
payload
)
...
@@ -496,52 +496,102 @@ static int validate_ownership_cb(const git_config_entry *entry, void *payload)
...
@@ -496,52 +496,102 @@ static int validate_ownership_cb(const git_config_entry *entry, void *payload)
validate_ownership_data
*
data
=
payload
;
validate_ownership_data
*
data
=
payload
;
if
(
strcmp
(
entry
->
value
,
""
)
==
0
)
if
(
strcmp
(
entry
->
value
,
""
)
==
0
)
data
->
is_safe
=
false
;
*
data
->
is_safe
=
false
;
if
(
git_fs_path_prettify_dir
(
&
data
->
tmp
,
entry
->
value
,
NULL
)
==
0
&&
if
(
git_fs_path_prettify_dir
(
&
data
->
tmp
,
entry
->
value
,
NULL
)
==
0
&&
strcmp
(
data
->
tmp
.
ptr
,
data
->
repo_path
)
==
0
)
strcmp
(
data
->
tmp
.
ptr
,
data
->
repo_path
)
==
0
)
data
->
is_safe
=
true
;
*
data
->
is_safe
=
true
;
return
0
;
return
0
;
}
}
static
int
validate_ownership
(
const
char
*
repo_
path
)
static
int
validate_ownership
_config
(
bool
*
is_safe
,
const
char
*
path
)
{
{
git_config
*
config
=
NULL
;
validate_ownership_data
ownership_data
=
{
validate_ownership_data
data
=
{
repo_path
,
GIT_STR_INIT
,
false
};
path
,
GIT_STR_INIT
,
is_safe
git_fs_path_owner_t
owner_level
=
};
GIT_FS_PATH_OWNER_CURRENT_USER
|
git_config
*
config
;
GIT_FS_PATH_USER_IS_ADMINISTRATOR
;
bool
is_safe
;
int
error
;
int
error
;
if
((
error
=
git_fs_path_owner_is
(
&
is_safe
,
repo_path
,
owner_level
))
<
0
)
{
if
(
load_global_config
(
&
config
)
!=
0
)
if
(
error
==
GIT_ENOTFOUND
)
return
0
;
error
=
0
;
goto
done
;
error
=
git_config_get_multivar_foreach
(
config
,
}
"safe.directory"
,
NULL
,
validate_ownership_cb
,
&
ownership_data
);
git_config_free
(
config
);
git_str_dispose
(
&
ownership_data
.
tmp
);
if
(
is_safe
)
{
return
error
;
}
static
int
validate_ownership_path
(
bool
*
is_safe
,
const
char
*
path
)
{
git_fs_path_owner_t
owner_level
=
GIT_FS_PATH_OWNER_CURRENT_USER
|
GIT_FS_PATH_USER_IS_ADMINISTRATOR
|
GIT_FS_PATH_OWNER_RUNNING_SUDO
;
int
error
=
0
;
if
(
path
)
error
=
git_fs_path_owner_is
(
is_safe
,
path
,
owner_level
);
if
(
error
==
GIT_ENOTFOUND
)
{
*
is_safe
=
true
;
error
=
0
;
error
=
0
;
goto
done
;
}
}
if
(
load_global_config
(
&
config
)
==
0
)
{
return
error
;
error
=
git_config_get_multivar_foreach
(
config
,
"safe.directory"
,
NULL
,
validate_ownership_cb
,
&
data
);
}
static
int
validate_ownership
(
git_repository
*
repo
)
{
const
char
*
validation_paths
[
3
]
=
{
NULL
},
*
path
;
size_t
validation_len
=
0
,
i
;
bool
is_safe
=
false
;
int
error
=
0
;
/*
* If there's a worktree, validate the permissions to it *and*
* the git directory, and use the worktree as the configuration
* key for allowlisting the directory. In a bare setup, only
* look at the gitdir and use that as the allowlist. So we
* examine all `validation_paths` but use only the first as
* the configuration lookup.
*/
if
(
repo
->
workdir
)
validation_paths
[
validation_len
++
]
=
repo
->
workdir
;
if
(
!
error
&&
data
.
is_safe
)
if
(
repo
->
gitlink
)
validation_paths
[
validation_len
++
]
=
repo
->
gitlink
;
validation_paths
[
validation_len
++
]
=
repo
->
gitdir
;
for
(
i
=
0
;
i
<
validation_len
;
i
++
)
{
path
=
validation_paths
[
i
];
if
((
error
=
validate_ownership_path
(
&
is_safe
,
path
))
<
0
)
goto
done
;
goto
done
;
if
(
!
is_safe
)
break
;
}
}
if
(
is_safe
||
(
error
=
validate_ownership_config
(
&
is_safe
,
validation_paths
[
0
]))
<
0
)
goto
done
;
if
(
!
is_safe
)
{
git_error_set
(
GIT_ERROR_CONFIG
,
git_error_set
(
GIT_ERROR_CONFIG
,
"repository path '%s' is not owned by current user"
,
"repository path '%s' is not owned by current user"
,
repo_
path
);
path
);
error
=
GIT_EOWNER
;
error
=
GIT_EOWNER
;
}
done:
done:
git_config_free
(
config
);
git_str_dispose
(
&
data
.
tmp
);
return
error
;
return
error
;
}
}
...
@@ -918,7 +968,6 @@ int git_repository_open_ext(
...
@@ -918,7 +968,6 @@ int git_repository_open_ext(
gitlink
=
GIT_STR_INIT
,
commondir
=
GIT_STR_INIT
;
gitlink
=
GIT_STR_INIT
,
commondir
=
GIT_STR_INIT
;
git_repository
*
repo
=
NULL
;
git_repository
*
repo
=
NULL
;
git_config
*
config
=
NULL
;
git_config
*
config
=
NULL
;
const
char
*
validation_path
;
int
version
=
0
;
int
version
=
0
;
if
(
flags
&
GIT_REPOSITORY_OPEN_FROM_ENV
)
if
(
flags
&
GIT_REPOSITORY_OPEN_FROM_ENV
)
...
@@ -977,12 +1026,11 @@ int git_repository_open_ext(
...
@@ -977,12 +1026,11 @@ int git_repository_open_ext(
}
}
/*
/*
* Ensure that the git directory is owned by the current user.
* Ensure that the git directory and worktree are
* owned by the current user.
*/
*/
validation_path
=
repo
->
is_bare
?
repo
->
gitdir
:
repo
->
workdir
;
if
(
git_repository__validate_ownership
&&
if
(
git_repository__validate_ownership
&&
(
error
=
validate_ownership
(
validation_path
))
<
0
)
(
error
=
validate_ownership
(
repo
))
<
0
)
goto
cleanup
;
goto
cleanup
;
cleanup:
cleanup:
...
...
src/util/fs_path.c
View file @
4ae8704b
...
@@ -1934,27 +1934,36 @@ done:
...
@@ -1934,27 +1934,36 @@ done:
#else
#else
static
int
sudo_uid_lookup
(
uid_t
*
out
)
{
git_str
uid_str
=
GIT_STR_INIT
;
int64_t
uid
;
int
error
;
if
((
error
=
git__getenv
(
&
uid_str
,
"SUDO_UID"
))
==
0
&&
(
error
=
git__strntol64
(
&
uid
,
uid_str
.
ptr
,
uid_str
.
size
,
NULL
,
10
))
==
0
&&
uid
==
(
int64_t
)((
uid_t
)
uid
))
{
*
out
=
(
uid_t
)
uid
;
}
git_str_dispose
(
&
uid_str
);
return
error
;
}
int
git_fs_path_owner_is
(
int
git_fs_path_owner_is
(
bool
*
out
,
bool
*
out
,
const
char
*
path
,
const
char
*
path
,
git_fs_path_owner_t
owner_type
)
git_fs_path_owner_t
owner_type
)
{
{
uid_t
uids
[
2
]
=
{
0
};
size_t
uid_count
=
0
,
i
;
struct
stat
st
;
struct
stat
st
;
uid_t
euid
,
sudo_uid
;
if
(
mock_owner
)
{
if
(
mock_owner
)
{
*
out
=
((
mock_owner
&
owner_type
)
!=
0
);
*
out
=
((
mock_owner
&
owner_type
)
!=
0
);
return
0
;
return
0
;
}
}
if
(
owner_type
&
GIT_FS_PATH_OWNER_CURRENT_USER
)
euid
=
geteuid
();
uids
[
uid_count
++
]
=
geteuid
();
if
(
owner_type
&
GIT_FS_PATH_OWNER_ADMINISTRATOR
)
uids
[
uid_count
++
]
=
0
;
*
out
=
false
;
if
(
p_lstat
(
path
,
&
st
)
!=
0
)
{
if
(
p_lstat
(
path
,
&
st
)
!=
0
)
{
if
(
errno
==
ENOENT
)
if
(
errno
==
ENOENT
)
...
@@ -1964,13 +1973,27 @@ int git_fs_path_owner_is(
...
@@ -1964,13 +1973,27 @@ int git_fs_path_owner_is(
return
-
1
;
return
-
1
;
}
}
for
(
i
=
0
;
i
<
uid_count
;
i
++
)
{
if
((
owner_type
&
GIT_FS_PATH_OWNER_CURRENT_USER
)
!=
0
&&
if
(
uids
[
i
]
==
st
.
st_
uid
)
{
st
.
st_uid
==
e
uid
)
{
*
out
=
true
;
*
out
=
true
;
break
;
return
0
;
}
if
((
owner_type
&
GIT_FS_PATH_OWNER_ADMINISTRATOR
)
!=
0
&&
st
.
st_uid
==
0
)
{
*
out
=
true
;
return
0
;
}
}
if
((
owner_type
&
GIT_FS_PATH_OWNER_RUNNING_SUDO
)
!=
0
&&
euid
==
0
&&
sudo_uid_lookup
(
&
sudo_uid
)
==
0
&&
st
.
st_uid
==
sudo_uid
)
{
*
out
=
true
;
return
0
;
}
}
*
out
=
false
;
return
0
;
return
0
;
}
}
...
...
src/util/fs_path.h
View file @
4ae8704b
...
@@ -747,8 +747,13 @@ typedef enum {
...
@@ -747,8 +747,13 @@ typedef enum {
*/
*/
GIT_FS_PATH_USER_IS_ADMINISTRATOR
=
(
1
<<
2
),
GIT_FS_PATH_USER_IS_ADMINISTRATOR
=
(
1
<<
2
),
/**
* The file is owned by the current user, who is running `sudo`.
*/
GIT_FS_PATH_OWNER_RUNNING_SUDO
=
(
1
<<
3
),
/** The file may be owned by another user. */
/** The file may be owned by another user. */
GIT_FS_PATH_OWNER_OTHER
=
(
1
<<
3
)
GIT_FS_PATH_OWNER_OTHER
=
(
1
<<
4
)
}
git_fs_path_owner_t
;
}
git_fs_path_owner_t
;
/**
/**
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment