Merge pull request #4996 from eaigner/master Prevent reading out of bounds memory
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
diff --git a/AUTHORS b/AUTHORS
index 458ff06..784bab3 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -23,6 +23,7 @@ Dmitry Kovega
Emeric Fermas
Emmanuel Rodriguez
Eric Myhre
+Erik Aigner
Florian Forster
Holger Weiss
Ingmar Vanhassel
diff --git a/src/apply.c b/src/apply.c
index d72aa83..0becf94 100644
--- a/src/apply.c
+++ b/src/apply.c
@@ -59,7 +59,7 @@ static int patch_image_init_fromstr(
git_pool_init(&out->pool, sizeof(git_diff_line));
for (start = in; start < in + in_len; start = end) {
- end = memchr(start, '\n', in_len);
+ end = memchr(start, '\n', in_len - (start - in));
if (end == NULL)
end = in + in_len;
diff --git a/tests/apply/fromdiff.c b/tests/apply/fromdiff.c
index 8a6d8fa..832415d 100644
--- a/tests/apply/fromdiff.c
+++ b/tests/apply/fromdiff.c
@@ -333,3 +333,36 @@ void test_apply_fromdiff__binary_delete(void)
NULL, NULL,
NULL, &binary_opts));
}
+
+void test_apply_fromdiff__patching_correctly_truncates_source(void)
+{
+ git_buf original = GIT_BUF_INIT, patched = GIT_BUF_INIT;
+ git_patch *patch;
+ unsigned int mode;
+ char *path;
+
+ cl_git_pass(git_patch_from_buffers(&patch,
+ "foo\nbar", 7, "file.txt",
+ "foo\nfoo", 7, "file.txt", NULL));
+
+ /*
+ * Previously, we would fail to correctly truncate the source buffer if
+ * the source has more than one line and ends with a non-newline
+ * character. In the following call, we thus truncate the source string
+ * in the middle of the second line. Without the bug fixed, we would
+ * successfully apply the patch to the source and return success. With
+ * the overflow being fixed, we should return an error.
+ */
+ cl_git_fail_with(GIT_EAPPLYFAIL,
+ git_apply__patch(&patched, &path, &mode,
+ "foo\nbar\n", 5, patch, NULL));
+
+ /* Verify that the patch succeeds if we do not truncate */
+ cl_git_pass(git_apply__patch(&patched, &path, &mode,
+ "foo\nbar\n", 7, patch, NULL));
+
+ git_buf_dispose(&original);
+ git_buf_dispose(&patched);
+ git_patch_free(patch);
+ git__free(path);
+}