mirror of
https://git.proxmox.com/git/libgit2
synced 2025-06-21 04:40:38 +00:00
Introduce core.protectHFS and core.protectNTFS
Validate HFS ignored char ".git" paths when `core.protectHFS` is specified. Validate NTFS invalid ".git" paths when `core.protectNTFS` is specified.
This commit is contained in:
parent
8e35527de2
commit
ec74b40cee
@ -76,6 +76,8 @@ static struct map_data _cvar_maps[] = {
|
|||||||
{"core.precomposeunicode", NULL, 0, GIT_PRECOMPOSE_DEFAULT },
|
{"core.precomposeunicode", NULL, 0, GIT_PRECOMPOSE_DEFAULT },
|
||||||
{"core.safecrlf", _cvar_map_safecrlf, ARRAY_SIZE(_cvar_map_safecrlf), GIT_SAFE_CRLF_DEFAULT},
|
{"core.safecrlf", _cvar_map_safecrlf, ARRAY_SIZE(_cvar_map_safecrlf), GIT_SAFE_CRLF_DEFAULT},
|
||||||
{"core.logallrefupdates", NULL, 0, GIT_LOGALLREFUPDATES_DEFAULT },
|
{"core.logallrefupdates", NULL, 0, GIT_LOGALLREFUPDATES_DEFAULT },
|
||||||
|
{"core.protecthfs", NULL, 0, GIT_PROTECTHFS_DEFAULT },
|
||||||
|
{"core.protectntfs", NULL, 0, GIT_PROTECTNTFS_DEFAULT },
|
||||||
};
|
};
|
||||||
|
|
||||||
int git_config__cvar(int *out, git_config *config, git_cvar_cached cvar)
|
int git_config__cvar(int *out, git_config *config, git_cvar_cached cvar)
|
||||||
|
113
src/path.c
113
src/path.c
@ -1240,26 +1240,6 @@ int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or_path)
|
|||||||
return git_buf_sets(local_path_out, url_or_path);
|
return git_buf_sets(local_path_out, url_or_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
GIT_INLINE(bool) verify_shortname(
|
|
||||||
git_repository *repo,
|
|
||||||
const char *component,
|
|
||||||
size_t len)
|
|
||||||
{
|
|
||||||
const char *shortname_repo;
|
|
||||||
|
|
||||||
if (len == git_repository__8dot3_default_len &&
|
|
||||||
strncasecmp(git_repository__8dot3_default, component, len) == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (repo &&
|
|
||||||
(shortname_repo = git_repository__8dot3_name(repo)) &&
|
|
||||||
shortname_repo != git_repository__8dot3_default &&
|
|
||||||
git__prefixncmp_icase(component, len, shortname_repo) == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reject paths like AUX or COM1, or those versions that end in a dot or
|
/* Reject paths like AUX or COM1, or those versions that end in a dot or
|
||||||
* colon. ("AUX." or "AUX:")
|
* colon. ("AUX." or "AUX:")
|
||||||
*/
|
*/
|
||||||
@ -1335,11 +1315,48 @@ static bool verify_dotgit_hfs(const char *path, size_t len)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GIT_INLINE(bool) verify_dotgit_ntfs(git_repository *repo, const char *path, size_t len)
|
||||||
|
{
|
||||||
|
const char *shortname = NULL;
|
||||||
|
size_t i, start, shortname_len = 0;
|
||||||
|
|
||||||
|
/* See if the repo has a custom shortname (not "GIT~1") */
|
||||||
|
if (repo &&
|
||||||
|
(shortname = git_repository__8dot3_name(repo)) &&
|
||||||
|
shortname != git_repository__8dot3_default)
|
||||||
|
shortname_len = strlen(shortname);
|
||||||
|
|
||||||
|
if (len >= 4 && strncasecmp(path, ".git", 4) == 0)
|
||||||
|
start = 4;
|
||||||
|
else if (len >= git_repository__8dot3_default_len &&
|
||||||
|
strncasecmp(path, git_repository__8dot3_default, git_repository__8dot3_default_len) == 0)
|
||||||
|
start = git_repository__8dot3_default_len;
|
||||||
|
else if (shortname_len && len >= shortname_len &&
|
||||||
|
strncasecmp(path, shortname, shortname_len) == 0)
|
||||||
|
start = shortname_len;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* Reject paths beginning with ".git\" */
|
||||||
|
if (path[start] == '\\')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (i = start; i < len; i++) {
|
||||||
|
if (path[i] != ' ' && path[i] != '.')
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
GIT_INLINE(bool) verify_char(unsigned char c, unsigned int flags)
|
GIT_INLINE(bool) verify_char(unsigned char c, unsigned int flags)
|
||||||
{
|
{
|
||||||
if ((flags & GIT_PATH_REJECT_BACKSLASH) && c == '\\')
|
if ((flags & GIT_PATH_REJECT_BACKSLASH) && c == '\\')
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if ((flags & GIT_PATH_REJECT_SLASH) && c == '/')
|
||||||
|
return false;
|
||||||
|
|
||||||
if (flags & GIT_PATH_REJECT_NT_CHARS) {
|
if (flags & GIT_PATH_REJECT_NT_CHARS) {
|
||||||
if (c < 32)
|
if (c < 32)
|
||||||
return false;
|
return false;
|
||||||
@ -1385,13 +1402,6 @@ static bool verify_component(
|
|||||||
len == 2 && component[0] == '.' && component[1] == '.')
|
len == 2 && component[0] == '.' && component[1] == '.')
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ((flags & GIT_PATH_REJECT_DOT_GIT) && len == 4 &&
|
|
||||||
component[0] == '.' &&
|
|
||||||
(component[1] == 'g' || component[1] == 'G') &&
|
|
||||||
(component[2] == 'i' || component[2] == 'I') &&
|
|
||||||
(component[3] == 't' || component[3] == 'T'))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if ((flags & GIT_PATH_REJECT_TRAILING_DOT) && component[len-1] == '.')
|
if ((flags & GIT_PATH_REJECT_TRAILING_DOT) && component[len-1] == '.')
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -1401,10 +1411,6 @@ static bool verify_component(
|
|||||||
if ((flags & GIT_PATH_REJECT_TRAILING_COLON) && component[len-1] == ':')
|
if ((flags & GIT_PATH_REJECT_TRAILING_COLON) && component[len-1] == ':')
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ((flags & GIT_PATH_REJECT_DOS_GIT_SHORTNAME) &&
|
|
||||||
!verify_shortname(repo, component, len))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (flags & GIT_PATH_REJECT_DOS_PATHS) {
|
if (flags & GIT_PATH_REJECT_DOS_PATHS) {
|
||||||
if (!verify_dospath(component, len, "CON", false) ||
|
if (!verify_dospath(component, len, "CON", false) ||
|
||||||
!verify_dospath(component, len, "PRN", false) ||
|
!verify_dospath(component, len, "PRN", false) ||
|
||||||
@ -1419,9 +1425,50 @@ static bool verify_component(
|
|||||||
!verify_dotgit_hfs(component, len))
|
!verify_dotgit_hfs(component, len))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (flags & GIT_PATH_REJECT_DOT_GIT_NTFS &&
|
||||||
|
!verify_dotgit_ntfs(repo, component, len))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((flags & GIT_PATH_REJECT_DOT_GIT_HFS) == 0 &&
|
||||||
|
(flags & GIT_PATH_REJECT_DOT_GIT_NTFS) == 0 &&
|
||||||
|
(flags & GIT_PATH_REJECT_DOT_GIT) &&
|
||||||
|
len == 4 &&
|
||||||
|
component[0] == '.' &&
|
||||||
|
(component[1] == 'g' || component[1] == 'G') &&
|
||||||
|
(component[2] == 'i' || component[2] == 'I') &&
|
||||||
|
(component[3] == 't' || component[3] == 'T'))
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GIT_INLINE(unsigned int) dotgit_flags(
|
||||||
|
git_repository *repo,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
int protectHFS = 0, protectNTFS = 0;
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
protectHFS = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GIT_WIN32
|
||||||
|
protectNTFS = 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (repo && !protectHFS)
|
||||||
|
git_repository__cvar(&protectHFS, repo, GIT_CVAR_PROTECTHFS);
|
||||||
|
if (protectHFS)
|
||||||
|
flags |= GIT_PATH_REJECT_DOT_GIT_HFS;
|
||||||
|
|
||||||
|
if (repo && !protectNTFS)
|
||||||
|
git_repository__cvar(&protectNTFS, repo, GIT_CVAR_PROTECTNTFS);
|
||||||
|
if (protectNTFS)
|
||||||
|
flags |= GIT_PATH_REJECT_DOT_GIT_NTFS;
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
bool git_path_isvalid(
|
bool git_path_isvalid(
|
||||||
git_repository *repo,
|
git_repository *repo,
|
||||||
const char *path,
|
const char *path,
|
||||||
@ -1429,6 +1476,10 @@ bool git_path_isvalid(
|
|||||||
{
|
{
|
||||||
const char *start, *c;
|
const char *start, *c;
|
||||||
|
|
||||||
|
/* Upgrade the ".git" checks based on platform */
|
||||||
|
if ((flags & GIT_PATH_REJECT_DOT_GIT))
|
||||||
|
flags = dotgit_flags(repo, flags);
|
||||||
|
|
||||||
for (start = c = path; *c; c++) {
|
for (start = c = path; *c; c++) {
|
||||||
if (!verify_char(*c, flags))
|
if (!verify_char(*c, flags))
|
||||||
return false;
|
return false;
|
||||||
|
20
src/path.h
20
src/path.h
@ -465,15 +465,20 @@ extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or
|
|||||||
/* Flags to determine path validity in `git_path_isvalid` */
|
/* Flags to determine path validity in `git_path_isvalid` */
|
||||||
#define GIT_PATH_REJECT_TRAVERSAL (1 << 0)
|
#define GIT_PATH_REJECT_TRAVERSAL (1 << 0)
|
||||||
#define GIT_PATH_REJECT_DOT_GIT (1 << 1)
|
#define GIT_PATH_REJECT_DOT_GIT (1 << 1)
|
||||||
#define GIT_PATH_REJECT_BACKSLASH (1 << 2)
|
#define GIT_PATH_REJECT_SLASH (1 << 2)
|
||||||
#define GIT_PATH_REJECT_TRAILING_DOT (1 << 3)
|
#define GIT_PATH_REJECT_BACKSLASH (1 << 3)
|
||||||
#define GIT_PATH_REJECT_TRAILING_SPACE (1 << 4)
|
#define GIT_PATH_REJECT_TRAILING_DOT (1 << 4)
|
||||||
#define GIT_PATH_REJECT_TRAILING_COLON (1 << 5)
|
#define GIT_PATH_REJECT_TRAILING_SPACE (1 << 5)
|
||||||
#define GIT_PATH_REJECT_DOS_GIT_SHORTNAME (1 << 6)
|
#define GIT_PATH_REJECT_TRAILING_COLON (1 << 6)
|
||||||
#define GIT_PATH_REJECT_DOS_PATHS (1 << 7)
|
#define GIT_PATH_REJECT_DOS_PATHS (1 << 7)
|
||||||
#define GIT_PATH_REJECT_NT_CHARS (1 << 8)
|
#define GIT_PATH_REJECT_NT_CHARS (1 << 8)
|
||||||
#define GIT_PATH_REJECT_DOT_GIT_HFS (1 << 9)
|
#define GIT_PATH_REJECT_DOT_GIT_HFS (1 << 9)
|
||||||
|
#define GIT_PATH_REJECT_DOT_GIT_NTFS (1 << 10)
|
||||||
|
|
||||||
|
/* Default path safety for writing files to disk: since we use the
|
||||||
|
* Win32 "File Namespace" APIs ("\\?\") we need to protect from
|
||||||
|
* paths that the normal Win32 APIs would not write.
|
||||||
|
*/
|
||||||
#ifdef GIT_WIN32
|
#ifdef GIT_WIN32
|
||||||
# define GIT_PATH_REJECT_DEFAULTS \
|
# define GIT_PATH_REJECT_DEFAULTS \
|
||||||
GIT_PATH_REJECT_TRAVERSAL | \
|
GIT_PATH_REJECT_TRAVERSAL | \
|
||||||
@ -481,13 +486,8 @@ extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or
|
|||||||
GIT_PATH_REJECT_TRAILING_DOT | \
|
GIT_PATH_REJECT_TRAILING_DOT | \
|
||||||
GIT_PATH_REJECT_TRAILING_SPACE | \
|
GIT_PATH_REJECT_TRAILING_SPACE | \
|
||||||
GIT_PATH_REJECT_TRAILING_COLON | \
|
GIT_PATH_REJECT_TRAILING_COLON | \
|
||||||
GIT_PATH_REJECT_DOS_GIT_SHORTNAME | \
|
|
||||||
GIT_PATH_REJECT_DOS_PATHS | \
|
GIT_PATH_REJECT_DOS_PATHS | \
|
||||||
GIT_PATH_REJECT_NT_CHARS
|
GIT_PATH_REJECT_NT_CHARS
|
||||||
#elif __APPLE__
|
|
||||||
# define GIT_PATH_REJECT_DEFAULTS \
|
|
||||||
GIT_PATH_REJECT_TRAVERSAL | \
|
|
||||||
GIT_PATH_REJECT_DOT_GIT_HFS
|
|
||||||
#else
|
#else
|
||||||
# define GIT_PATH_REJECT_DEFAULTS GIT_PATH_REJECT_TRAVERSAL
|
# define GIT_PATH_REJECT_DEFAULTS GIT_PATH_REJECT_TRAVERSAL
|
||||||
#endif
|
#endif
|
||||||
|
@ -40,6 +40,8 @@ typedef enum {
|
|||||||
GIT_CVAR_PRECOMPOSE, /* core.precomposeunicode */
|
GIT_CVAR_PRECOMPOSE, /* core.precomposeunicode */
|
||||||
GIT_CVAR_SAFE_CRLF, /* core.safecrlf */
|
GIT_CVAR_SAFE_CRLF, /* core.safecrlf */
|
||||||
GIT_CVAR_LOGALLREFUPDATES, /* core.logallrefupdates */
|
GIT_CVAR_LOGALLREFUPDATES, /* core.logallrefupdates */
|
||||||
|
GIT_CVAR_PROTECTHFS, /* core.protectHFS */
|
||||||
|
GIT_CVAR_PROTECTNTFS, /* core.protectNTFS */
|
||||||
GIT_CVAR_CACHE_MAX
|
GIT_CVAR_CACHE_MAX
|
||||||
} git_cvar_cached;
|
} git_cvar_cached;
|
||||||
|
|
||||||
@ -96,6 +98,10 @@ typedef enum {
|
|||||||
/* core.logallrefupdates */
|
/* core.logallrefupdates */
|
||||||
GIT_LOGALLREFUPDATES_UNSET = 2,
|
GIT_LOGALLREFUPDATES_UNSET = 2,
|
||||||
GIT_LOGALLREFUPDATES_DEFAULT = GIT_LOGALLREFUPDATES_UNSET,
|
GIT_LOGALLREFUPDATES_DEFAULT = GIT_LOGALLREFUPDATES_UNSET,
|
||||||
|
/* core.protectHFS */
|
||||||
|
GIT_PROTECTHFS_DEFAULT = GIT_CVAR_FALSE,
|
||||||
|
/* core.protectNTFS */
|
||||||
|
GIT_PROTECTNTFS_DEFAULT = GIT_CVAR_FALSE,
|
||||||
} git_cvar_value;
|
} git_cvar_value;
|
||||||
|
|
||||||
/* internal repository init flags */
|
/* internal repository init flags */
|
||||||
|
@ -291,3 +291,35 @@ void test_checkout_nasty__dot_git_hfs_ignorable(void)
|
|||||||
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_16", ".git/foobar");
|
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_16", ".git/foobar");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_checkout_nasty__honors_core_protecthfs(void)
|
||||||
|
{
|
||||||
|
cl_repo_set_bool(repo, "core.protectHFS", true);
|
||||||
|
|
||||||
|
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_1", ".git/foobar");
|
||||||
|
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_2", ".git/foobar");
|
||||||
|
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_3", ".git/foobar");
|
||||||
|
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_4", ".git/foobar");
|
||||||
|
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_5", ".git/foobar");
|
||||||
|
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_6", ".git/foobar");
|
||||||
|
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_7", ".git/foobar");
|
||||||
|
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_8", ".git/foobar");
|
||||||
|
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_9", ".git/foobar");
|
||||||
|
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_10", ".git/foobar");
|
||||||
|
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_11", ".git/foobar");
|
||||||
|
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_12", ".git/foobar");
|
||||||
|
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_13", ".git/foobar");
|
||||||
|
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_14", ".git/foobar");
|
||||||
|
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_15", ".git/foobar");
|
||||||
|
test_checkout_fails("refs/heads/dotgit_hfs_ignorable_16", ".git/foobar");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_checkout_nasty__honors_core_protectntfs(void)
|
||||||
|
{
|
||||||
|
cl_repo_set_bool(repo, "core.protectNTFS", true);
|
||||||
|
|
||||||
|
test_checkout_fails("refs/heads/dotgit_backslash_path", ".git/foobar");
|
||||||
|
test_checkout_fails("refs/heads/dotcapitalgit_backslash_path", ".GIT/foobar");
|
||||||
|
test_checkout_fails("refs/heads/dot_git_dot", ".git/foobar");
|
||||||
|
test_checkout_fails("refs/heads/git_tilde1", ".git/foobar");
|
||||||
|
}
|
||||||
|
@ -172,11 +172,27 @@ void test_path_core__isvalid_trailing_colon(void)
|
|||||||
cl_assert_equal_b(false, git_path_isvalid(NULL, "foo:/bar", GIT_PATH_REJECT_TRAILING_COLON));
|
cl_assert_equal_b(false, git_path_isvalid(NULL, "foo:/bar", GIT_PATH_REJECT_TRAILING_COLON));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_path_core__isvalid_dos_git_shortname(void)
|
void test_path_core__isvalid_dotgit_ntfs(void)
|
||||||
{
|
{
|
||||||
cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1", 0));
|
cl_assert_equal_b(true, git_path_isvalid(NULL, ".git", 0));
|
||||||
|
cl_assert_equal_b(true, git_path_isvalid(NULL, ".git ", 0));
|
||||||
|
cl_assert_equal_b(true, git_path_isvalid(NULL, ".git.", 0));
|
||||||
|
cl_assert_equal_b(true, git_path_isvalid(NULL, ".git.. .", 0));
|
||||||
|
|
||||||
cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1", GIT_PATH_REJECT_DOS_GIT_SHORTNAME));
|
cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1", 0));
|
||||||
|
cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1 ", 0));
|
||||||
|
cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1.", 0));
|
||||||
|
cl_assert_equal_b(true, git_path_isvalid(NULL, "git~1.. .", 0));
|
||||||
|
|
||||||
|
cl_assert_equal_b(false, git_path_isvalid(NULL, ".git", GIT_PATH_REJECT_DOT_GIT_NTFS));
|
||||||
|
cl_assert_equal_b(false, git_path_isvalid(NULL, ".git ", GIT_PATH_REJECT_DOT_GIT_NTFS));
|
||||||
|
cl_assert_equal_b(false, git_path_isvalid(NULL, ".git.", GIT_PATH_REJECT_DOT_GIT_NTFS));
|
||||||
|
cl_assert_equal_b(false, git_path_isvalid(NULL, ".git.. .", GIT_PATH_REJECT_DOT_GIT_NTFS));
|
||||||
|
|
||||||
|
cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1", GIT_PATH_REJECT_DOT_GIT_NTFS));
|
||||||
|
cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1 ", GIT_PATH_REJECT_DOT_GIT_NTFS));
|
||||||
|
cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1.", GIT_PATH_REJECT_DOT_GIT_NTFS));
|
||||||
|
cl_assert_equal_b(false, git_path_isvalid(NULL, "git~1.. .", GIT_PATH_REJECT_DOT_GIT_NTFS));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_path_core__isvalid_dos_paths(void)
|
void test_path_core__isvalid_dos_paths(void)
|
||||||
|
Loading…
Reference in New Issue
Block a user