config_entries: fix possible segfault when duplicating entries When duplicating a configuration entry, we allocate a new entry but do not verify that we get a valid pointer back. As we're dereferencing the pointer afterwards, we might thus run into a segfault in out-of-memory situations. Extract a new function `git_config_entries_dup_entry` that handles the complete entry duplication. Fix the error by using `GIT_ERROR_CHECK_ALLOC`.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
diff --git a/src/config_entries.c b/src/config_entries.c
index 18f8b21..2eb9e66 100644
--- a/src/config_entries.c
+++ b/src/config_entries.c
@@ -67,6 +67,36 @@ int git_config_entries_new(git_config_entries **out)
return error;
}
+int git_config_entries_dup_entry(git_config_entries *entries, const git_config_entry *entry)
+{
+ git_config_entry *duplicated;
+ int error;
+
+ duplicated = git__calloc(1, sizeof(git_config_entry));
+ GIT_ERROR_CHECK_ALLOC(duplicated);
+
+ duplicated->name = git__strdup(entry->name);
+ GIT_ERROR_CHECK_ALLOC(duplicated->name);
+
+ if (entry->value) {
+ duplicated->value = git__strdup(entry->value);
+ GIT_ERROR_CHECK_ALLOC(duplicated->value);
+ }
+ duplicated->level = entry->level;
+ duplicated->include_depth = entry->include_depth;
+
+ if ((error = git_config_entries_append(entries, duplicated)) < 0)
+ goto out;
+
+out:
+ if (error && duplicated) {
+ git__free((char *) duplicated->name);
+ git__free((char *) duplicated->value);
+ git__free(duplicated);
+ }
+ return error;
+}
+
int git_config_entries_dup(git_config_entries **out, git_config_entries *entries)
{
git_config_entries *result = NULL;
@@ -76,22 +106,9 @@ int git_config_entries_dup(git_config_entries **out, git_config_entries *entries
if ((error = git_config_entries_new(&result)) < 0)
goto out;
- for (head = entries->list; head; head = head->next) {
- git_config_entry *dup;
-
- dup = git__calloc(1, sizeof(git_config_entry));
- dup->name = git__strdup(head->entry->name);
- GIT_ERROR_CHECK_ALLOC(dup->name);
- if (head->entry->value) {
- dup->value = git__strdup(head->entry->value);
- GIT_ERROR_CHECK_ALLOC(dup->value);
- }
- dup->level = head->entry->level;
- dup->include_depth = head->entry->include_depth;
-
- if ((error = git_config_entries_append(result, dup)) < 0)
+ for (head = entries->list; head; head = head->next)
+ if ((git_config_entries_dup_entry(result, head->entry)) < 0)
goto out;
- }
*out = result;
result = NULL;
diff --git a/src/config_entries.h b/src/config_entries.h
index 6fdbc41..832379e 100644
--- a/src/config_entries.h
+++ b/src/config_entries.h
@@ -14,6 +14,7 @@ typedef struct git_config_entries git_config_entries;
int git_config_entries_new(git_config_entries **out);
int git_config_entries_dup(git_config_entries **out, git_config_entries *entries);
+int git_config_entries_dup_entry(git_config_entries *entries, const git_config_entry *entry);
void git_config_entries_incref(git_config_entries *entries);
void git_config_entries_free(git_config_entries *entries);
/* Add or append the new config option */