summaryrefslogtreecommitdiff
path: root/src/index.c
diff options
context:
space:
mode:
authorVicent Marti <tanoku@gmail.com>2014-11-25 00:58:03 +0100
committerEdward Thomson <ethomson@microsoft.com>2014-12-16 10:08:49 -0600
commit0d388adc86946f3c8cddc2493b470d47a653c4a5 (patch)
treede6f47185316bf6c003d886b2bd4fdec3475b7e7 /src/index.c
parent62155257d2d30d8f8d7108539df0681dce27ff61 (diff)
downloadlibgit2-0d388adc86946f3c8cddc2493b470d47a653c4a5.tar.gz
index: Check for valid paths before creating an index entry
Diffstat (limited to 'src/index.c')
-rw-r--r--src/index.c110
1 files changed, 95 insertions, 15 deletions
diff --git a/src/index.c b/src/index.c
index d3bc081a5..644f0c8a7 100644
--- a/src/index.c
+++ b/src/index.c
@@ -762,19 +762,96 @@ void git_index_entry__init_from_stat(
entry->file_size = st->st_size;
}
-static git_index_entry *index_entry_alloc(const char *path)
+/*
+ * We fundamentally don't like some paths: we don't want
+ * dot or dot-dot anywhere, and for obvious reasons don't
+ * want to recurse into ".git" either.
+ *
+ * Also, we don't want double slashes or slashes at the
+ * end that can make pathnames ambiguous.
+ */
+static int verify_dotfile(const char *rest)
+{
+ /*
+ * The first character was '.', but that
+ * has already been discarded, we now test
+ * the rest.
+ */
+
+ /* "." is not allowed */
+ if (*rest == '\0' || *rest == '/')
+ return -1;
+
+ switch (*rest) {
+ /*
+ * ".git" followed by NUL or slash is bad. This
+ * shares the path end test with the ".." case.
+ */
+ case 'g':
+ case 'G':
+ if (rest[1] != 'i' && rest[1] != 'I')
+ break;
+ if (rest[2] != 't' && rest[2] != 'T')
+ break;
+ rest += 2;
+ /* fallthrough */
+ case '.':
+ if (rest[1] == '\0' || rest[1] == '/')
+ return -1;
+ }
+ return 0;
+}
+
+static int verify_component(char c, const char *rest)
+{
+ if ((c == '.' && verify_dotfile(rest)) < 0 || c == '/' || c == '\0') {
+ giterr_set(GITERR_INDEX, "Invalid path component in index: '%c%s'", c, rest);
+ return -1;
+ }
+ return 0;
+}
+
+static int verify_path(const char *path)
+{
+ char c;
+
+ /* TODO: should we check this? */
+ /*
+ if (has_dos_drive_prefix(path))
+ return -1;
+ */
+
+ c = *path++;
+ if (verify_component(c, path) < 0)
+ return -1;
+
+ while ((c = *path++) != '\0') {
+ if (c == '/') {
+ c = *path++;
+ if (verify_component(c, path) < 0)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int index_entry_create(git_index_entry **out, const char *path)
{
size_t pathlen = strlen(path);
- struct entry_internal *entry =
- git__calloc(sizeof(struct entry_internal) + pathlen + 1, 1);
- if (!entry)
- return NULL;
+ struct entry_internal *entry;
+
+ if (verify_path(path) < 0)
+ return -1;
+
+ entry = git__calloc(sizeof(struct entry_internal) + pathlen + 1, 1);
+ GITERR_CHECK_ALLOC(entry);
entry->pathlen = pathlen;
memcpy(entry->path, path, pathlen);
entry->entry.path = entry->path;
- return (git_index_entry *)entry;
+ *out = (git_index_entry *)entry;
+ return 0;
}
static int index_entry_init(
@@ -790,14 +867,17 @@ static int index_entry_init(
"Could not initialize index entry. "
"Index is not backed up by an existing repository.");
+ if (index_entry_create(&entry, rel_path) < 0)
+ return -1;
+
/* write the blob to disk and get the oid and stat info */
error = git_blob__create_from_paths(
&oid, &st, INDEX_OWNER(index), NULL, rel_path, 0, true);
- if (error < 0)
- return error;
- entry = index_entry_alloc(rel_path);
- GITERR_CHECK_ALLOC(entry);
+ if (error < 0) {
+ index_entry_free(entry);
+ return error;
+ }
entry->id = oid;
git_index_entry__init_from_stat(entry, &st, !index->distrust_filemode);
@@ -862,11 +942,11 @@ static int index_entry_dup(git_index_entry **out, const git_index_entry *src)
return 0;
}
- *out = entry = index_entry_alloc(src->path);
- GITERR_CHECK_ALLOC(entry);
+ if (index_entry_create(&entry, src->path) < 0)
+ return -1;
index_entry_cpy(entry, src);
-
+ *out = entry;
return 0;
}
@@ -2316,8 +2396,8 @@ static int read_tree_cb(
if (git_buf_joinpath(&path, root, tentry->filename) < 0)
return -1;
- entry = index_entry_alloc(path.ptr);
- GITERR_CHECK_ALLOC(entry);
+ if (index_entry_create(&entry, path.ptr) < 0)
+ return -1;
entry->mode = tentry->attr;
entry->id = tentry->oid;