Skip to content

Commit 76182e8

Browse files
committed
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 parent e3adc99 commit 76182e8

File tree

2 files changed

+33
-15
lines changed

2 files changed

+33
-15
lines changed

src/config_entries.c

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,36 @@ int git_config_entries_new(git_config_entries **out)
6767
return error;
6868
}
6969

70+
int git_config_entries_dup_entry(git_config_entries *entries, const git_config_entry *entry)
71+
{
72+
git_config_entry *duplicated;
73+
int error;
74+
75+
duplicated = git__calloc(1, sizeof(git_config_entry));
76+
GIT_ERROR_CHECK_ALLOC(duplicated);
77+
78+
duplicated->name = git__strdup(entry->name);
79+
GIT_ERROR_CHECK_ALLOC(duplicated->name);
80+
81+
if (entry->value) {
82+
duplicated->value = git__strdup(entry->value);
83+
GIT_ERROR_CHECK_ALLOC(duplicated->value);
84+
}
85+
duplicated->level = entry->level;
86+
duplicated->include_depth = entry->include_depth;
87+
88+
if ((error = git_config_entries_append(entries, duplicated)) < 0)
89+
goto out;
90+
91+
out:
92+
if (error && duplicated) {
93+
git__free((char *) duplicated->name);
94+
git__free((char *) duplicated->value);
95+
git__free(duplicated);
96+
}
97+
return error;
98+
}
99+
70100
int git_config_entries_dup(git_config_entries **out, git_config_entries *entries)
71101
{
72102
git_config_entries *result = NULL;
@@ -76,22 +106,9 @@ int git_config_entries_dup(git_config_entries **out, git_config_entries *entries
76106
if ((error = git_config_entries_new(&result)) < 0)
77107
goto out;
78108

79-
for (head = entries->list; head; head = head->next) {
80-
git_config_entry *dup;
81-
82-
dup = git__calloc(1, sizeof(git_config_entry));
83-
dup->name = git__strdup(head->entry->name);
84-
GIT_ERROR_CHECK_ALLOC(dup->name);
85-
if (head->entry->value) {
86-
dup->value = git__strdup(head->entry->value);
87-
GIT_ERROR_CHECK_ALLOC(dup->value);
88-
}
89-
dup->level = head->entry->level;
90-
dup->include_depth = head->entry->include_depth;
91-
92-
if ((error = git_config_entries_append(result, dup)) < 0)
109+
for (head = entries->list; head; head = head->next)
110+
if ((git_config_entries_dup_entry(result, head->entry)) < 0)
93111
goto out;
94-
}
95112

96113
*out = result;
97114
result = NULL;

src/config_entries.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ typedef struct git_config_entries git_config_entries;
1414

1515
int git_config_entries_new(git_config_entries **out);
1616
int git_config_entries_dup(git_config_entries **out, git_config_entries *entries);
17+
int git_config_entries_dup_entry(git_config_entries *entries, const git_config_entry *entry);
1718
void git_config_entries_incref(git_config_entries *entries);
1819
void git_config_entries_free(git_config_entries *entries);
1920
/* Add or append the new config option */

0 commit comments

Comments
 (0)