Commit 5b855194 by Carlos Martín Nieto Committed by Patrick Steinhardt

path: reject .gitmodules as a symlink

Any part of the library which asks the question can pass in the mode to have it
checked against `.gitmodules` being a symlink.

This is particularly relevant for adding entries to the index from the worktree
and for checking out files.
parent 17df18ae
...@@ -1272,14 +1272,14 @@ static int checkout_verify_paths( ...@@ -1272,14 +1272,14 @@ static int checkout_verify_paths(
unsigned int flags = GIT_PATH_REJECT_WORKDIR_DEFAULTS; unsigned int flags = GIT_PATH_REJECT_WORKDIR_DEFAULTS;
if (action & CHECKOUT_ACTION__REMOVE) { if (action & CHECKOUT_ACTION__REMOVE) {
if (!git_path_isvalid(repo, delta->old_file.path, flags)) { if (!git_path_isvalid(repo, delta->old_file.path, delta->old_file.mode, flags)) {
giterr_set(GITERR_CHECKOUT, "cannot remove invalid path '%s'", delta->old_file.path); giterr_set(GITERR_CHECKOUT, "cannot remove invalid path '%s'", delta->old_file.path);
return -1; return -1;
} }
} }
if (action & ~CHECKOUT_ACTION__REMOVE) { if (action & ~CHECKOUT_ACTION__REMOVE) {
if (!git_path_isvalid(repo, delta->new_file.path, flags)) { if (!git_path_isvalid(repo, delta->new_file.path, delta->new_file.mode, flags)) {
giterr_set(GITERR_CHECKOUT, "cannot checkout to invalid path '%s'", delta->new_file.path); giterr_set(GITERR_CHECKOUT, "cannot checkout to invalid path '%s'", delta->new_file.path);
return -1; return -1;
} }
......
...@@ -890,8 +890,7 @@ static int index_entry_create( ...@@ -890,8 +890,7 @@ static int index_entry_create(
size_t pathlen = strlen(path), alloclen; size_t pathlen = strlen(path), alloclen;
struct entry_internal *entry; struct entry_internal *entry;
unsigned int path_valid_flags = GIT_PATH_REJECT_INDEX_DEFAULTS; unsigned int path_valid_flags = GIT_PATH_REJECT_INDEX_DEFAULTS;
uint16_t mode = 0;
GIT_UNUSED(st);
/* always reject placing `.git` in the index and directory traversal. /* always reject placing `.git` in the index and directory traversal.
* when requested, disallow platform-specific filenames and upgrade to * when requested, disallow platform-specific filenames and upgrade to
...@@ -899,8 +898,10 @@ static int index_entry_create( ...@@ -899,8 +898,10 @@ static int index_entry_create(
*/ */
if (from_workdir) if (from_workdir)
path_valid_flags |= GIT_PATH_REJECT_WORKDIR_DEFAULTS; path_valid_flags |= GIT_PATH_REJECT_WORKDIR_DEFAULTS;
if (st)
mode = st->st_mode;
if (!git_path_isvalid(repo, path, path_valid_flags)) { if (!git_path_isvalid(repo, path, mode, path_valid_flags)) {
giterr_set(GITERR_INDEX, "invalid path: '%s'", path); giterr_set(GITERR_INDEX, "invalid path: '%s'", path);
return -1; return -1;
} }
...@@ -925,7 +926,7 @@ static int index_entry_init( ...@@ -925,7 +926,7 @@ static int index_entry_init(
{ {
int error = 0; int error = 0;
git_index_entry *entry = NULL; git_index_entry *entry = NULL;
git_buf path; git_buf path = GIT_BUF_INIT;
struct stat st; struct stat st;
git_oid oid; git_oid oid;
git_repository *repo; git_repository *repo;
......
...@@ -1711,6 +1711,7 @@ static bool verify_component( ...@@ -1711,6 +1711,7 @@ static bool verify_component(
git_repository *repo, git_repository *repo,
const char *component, const char *component,
size_t len, size_t len,
uint16_t mode,
unsigned int flags) unsigned int flags)
{ {
if (len == 0) if (len == 0)
...@@ -1743,13 +1744,19 @@ static bool verify_component( ...@@ -1743,13 +1744,19 @@ static bool verify_component(
return false; return false;
} }
if (flags & GIT_PATH_REJECT_DOT_GIT_HFS && if (flags & GIT_PATH_REJECT_DOT_GIT_HFS) {
!verify_dotgit_hfs(component, len)) if (!verify_dotgit_hfs(component, len))
return false; return false;
if (S_ISLNK(mode) && git_path_is_hfs_dotgit_modules(component, len))
return false;
}
if (flags & GIT_PATH_REJECT_DOT_GIT_NTFS && if (flags & GIT_PATH_REJECT_DOT_GIT_NTFS) {
!verify_dotgit_ntfs(repo, component, len)) if (!verify_dotgit_ntfs(repo, component, len))
return false; return false;
if (S_ISLNK(mode) && git_path_is_ntfs_dotgit_modules(component, len))
return false;
}
/* don't bother rerunning the `.git` test if we ran the HFS or NTFS /* don't bother rerunning the `.git` test if we ran the HFS or NTFS
* specific tests, they would have already rejected `.git`. * specific tests, they would have already rejected `.git`.
...@@ -1800,6 +1807,7 @@ GIT_INLINE(unsigned int) dotgit_flags( ...@@ -1800,6 +1807,7 @@ GIT_INLINE(unsigned int) dotgit_flags(
bool git_path_isvalid( bool git_path_isvalid(
git_repository *repo, git_repository *repo,
const char *path, const char *path,
uint16_t mode,
unsigned int flags) unsigned int flags)
{ {
const char *start, *c; const char *start, *c;
...@@ -1813,14 +1821,14 @@ bool git_path_isvalid( ...@@ -1813,14 +1821,14 @@ bool git_path_isvalid(
return false; return false;
if (*c == '/') { if (*c == '/') {
if (!verify_component(repo, start, (c - start), flags)) if (!verify_component(repo, start, (c - start), mode, flags))
return false; return false;
start = c+1; start = c+1;
} }
} }
return verify_component(repo, start, (c - start), flags); return verify_component(repo, start, (c - start), mode, flags);
} }
int git_path_normalize_slashes(git_buf *out, const char *path) int git_path_normalize_slashes(git_buf *out, const char *path)
......
...@@ -623,6 +623,7 @@ extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or ...@@ -623,6 +623,7 @@ extern int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or
extern bool git_path_isvalid( extern bool git_path_isvalid(
git_repository *repo, git_repository *repo,
const char *path, const char *path,
uint16_t mode,
unsigned int flags); unsigned int flags);
/** /**
......
...@@ -743,7 +743,7 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char * ...@@ -743,7 +743,7 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char *
assert(file && backend && name); assert(file && backend && name);
if (!git_path_isvalid(backend->repo, name, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) { if (!git_path_isvalid(backend->repo, name, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
giterr_set(GITERR_INVALID, "invalid reference name '%s'", name); giterr_set(GITERR_INVALID, "invalid reference name '%s'", name);
return GIT_EINVALIDSPEC; return GIT_EINVALIDSPEC;
} }
...@@ -1739,7 +1739,7 @@ static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char ...@@ -1739,7 +1739,7 @@ static int lock_reflog(git_filebuf *file, refdb_fs_backend *backend, const char
repo = backend->repo; repo = backend->repo;
if (!git_path_isvalid(backend->repo, refname, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) { if (!git_path_isvalid(backend->repo, refname, 0, GIT_PATH_REJECT_FILESYSTEM_DEFAULTS)) {
giterr_set(GITERR_INVALID, "invalid reference name '%s'", refname); giterr_set(GITERR_INVALID, "invalid reference name '%s'", refname);
return GIT_EINVALIDSPEC; return GIT_EINVALIDSPEC;
} }
......
...@@ -332,7 +332,7 @@ int git_submodule_name_is_valid(const git_repository *repo, const char *name, in ...@@ -332,7 +332,7 @@ int git_submodule_name_is_valid(const git_repository *repo, const char *name, in
} }
/* FIXME: Un-consting it to reduce the amount of diff */ /* FIXME: Un-consting it to reduce the amount of diff */
isvalid = git_path_isvalid((git_repository *)repo, buf.ptr, flags); isvalid = git_path_isvalid((git_repository *)repo, buf.ptr, 0, flags);
git_buf_free(&buf); git_buf_free(&buf);
return isvalid; return isvalid;
......
...@@ -54,7 +54,7 @@ GIT_INLINE(git_filemode_t) normalize_filemode(git_filemode_t filemode) ...@@ -54,7 +54,7 @@ GIT_INLINE(git_filemode_t) normalize_filemode(git_filemode_t filemode)
static int valid_entry_name(git_repository *repo, const char *filename) static int valid_entry_name(git_repository *repo, const char *filename)
{ {
return *filename != '\0' && return *filename != '\0' &&
git_path_isvalid(repo, filename, git_path_isvalid(repo, filename, 0,
GIT_PATH_REJECT_TRAVERSAL | GIT_PATH_REJECT_DOT_GIT | GIT_PATH_REJECT_SLASH); GIT_PATH_REJECT_TRAVERSAL | GIT_PATH_REJECT_DOT_GIT | GIT_PATH_REJECT_SLASH);
} }
......
...@@ -106,3 +106,10 @@ void test_path_dotgit__dotgit_modules(void) ...@@ -106,3 +106,10 @@ void test_path_dotgit__dotgit_modules(void)
} }
} }
void test_path_dotgit__dotgit_modules_symlink(void)
{
cl_assert_equal_b(true, git_path_isvalid(NULL, ".gitmodules", 0, GIT_PATH_REJECT_DOT_GIT_HFS|GIT_PATH_REJECT_DOT_GIT_NTFS));
cl_assert_equal_b(false, git_path_isvalid(NULL, ".gitmodules", S_IFLNK, GIT_PATH_REJECT_DOT_GIT_HFS));
cl_assert_equal_b(false, git_path_isvalid(NULL, ".gitmodules", S_IFLNK, GIT_PATH_REJECT_DOT_GIT_NTFS));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment