Code

get_sha1_hex(): do not read past a NUL character
authorMichael Haggerty <mhagger@alum.mit.edu>
Fri, 23 Sep 2011 13:38:36 +0000 (15:38 +0200)
committerJunio C Hamano <gitster@pobox.com>
Wed, 5 Oct 2011 20:45:16 +0000 (13:45 -0700)
Previously, get_sha1_hex() would read one character past the end of a
null-terminated string whose strlen was an even number less than 40.
Although the function correctly returned -1 in these cases, the extra
memory access might have been to uninitialized (or even, conceivably,
unallocated) memory.

Add a check to avoid reading past the end of a string.

This problem was discovered by Thomas Rast <trast@student.ethz.ch>
using valgrind.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
cache.h
hex.c

diff --git a/cache.h b/cache.h
index 607c2ea612889c46e81ae375b6985db18e529a8e..e7bbc0debd2ec331b93cadbca05470da5d253a1c 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -819,7 +819,16 @@ static inline int get_sha1_with_context(const char *str, unsigned char *sha1, st
 {
        return get_sha1_with_context_1(str, sha1, orc, 0, NULL);
 }
+
+/*
+ * Try to read a SHA1 in hexadecimal format from the 40 characters
+ * starting at hex.  Write the 20-byte result to sha1 in binary form.
+ * Return 0 on success.  Reading stops if a NUL is encountered in the
+ * input, so it is safe to pass this function an arbitrary
+ * null-terminated string.
+ */
 extern int get_sha1_hex(const char *hex, unsigned char *sha1);
+
 extern char *sha1_to_hex(const unsigned char *sha1);   /* static buffer result! */
 extern int read_ref(const char *filename, unsigned char *sha1);
 extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
diff --git a/hex.c b/hex.c
index bb402fbaa2a04ef0849789fdd814dcbb8773fff5..9ebc050637532765b775cbd8e3b92951a67ea333 100644 (file)
--- a/hex.c
+++ b/hex.c
@@ -39,7 +39,15 @@ int get_sha1_hex(const char *hex, unsigned char *sha1)
 {
        int i;
        for (i = 0; i < 20; i++) {
-               unsigned int val = (hexval(hex[0]) << 4) | hexval(hex[1]);
+               unsigned int val;
+               /*
+                * hex[1]=='\0' is caught when val is checked below,
+                * but if hex[0] is NUL we have to avoid reading
+                * past the end of the string:
+                */
+               if (!hex[0])
+                       return -1;
+               val = (hexval(hex[0]) << 4) | hexval(hex[1]);
                if (val & ~0xff)
                        return -1;
                *sha1++ = val;