From dfc2c713433b3a932e4d8b648738e3b63086baec Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 7 Oct 2016 09:18:55 +0200 Subject: [PATCH 1/7] tree: validate filename and OID length when parsing object When parsing tree entries from raw object data, we do not verify that the tree entry actually has a filename as well as a valid object ID. Fix this by asserting that the filename length is non-zero as well as asserting that there are at least `GIT_OID_RAWSZ` bytes left when parsing the OID. --- src/tree.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tree.c b/src/tree.c index 3874e45f4..7cc415a09 100644 --- a/src/tree.c +++ b/src/tree.c @@ -447,7 +447,12 @@ int git_tree__parse(void *_tree, git_odb_object *odb_obj) if ((nul = memchr(buffer, 0, buffer_end - buffer)) == NULL) return tree_error("Failed to parse tree. Object is corrupted", NULL); - filename_len = nul - buffer; + if ((filename_len = nul - buffer) == 0) + return tree_error("Failed to parse tree. Can't parse filename", NULL); + + if ((buffer_end - (nul + 1)) < GIT_OID_RAWSZ) + return tree_error("Failed to parse tree. Can't parse OID", NULL); + /* Allocate the entry */ { entry = git_array_alloc(tree->entries); From 821042b673675546a265827ea184c6fa14e0623d Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Fri, 7 Oct 2016 09:31:41 +0200 Subject: [PATCH 2/7] commit: always initialize commit message When parsing a commit, we will treat all bytes left after parsing the headers as the commit message. When no bytes are left, we leave the commit's message uninitialized. While uncommon to have a commit without message, this is the right behavior as Git unfortunately allows for empty commit messages. Given that this scenario is so uncommon, most programs acting on the commit message will never check if the message is actually set, which may lead to errors. To work around the error and not lay the burden of checking for empty commit messages to the developer, initialize the commit message with an empty string when no commit message is given. --- src/commit.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/commit.c b/src/commit.c index 5ed9c474d..ade4e10b5 100644 --- a/src/commit.c +++ b/src/commit.c @@ -410,10 +410,11 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj) buffer = buffer_start + header_len + 1; /* extract commit message */ - if (buffer <= buffer_end) { + if (buffer <= buffer_end) commit->raw_message = git__strndup(buffer, buffer_end - buffer); - GITERR_CHECK_ALLOC(commit->raw_message); - } + else + commit->raw_message = git__strdup(""); + GITERR_CHECK_ALLOC(commit->raw_message); return 0; From f061aa85d5feb32d7e07c3fd554391976cfb3c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 5 Oct 2016 20:17:06 +0200 Subject: [PATCH 3/7] travis: take the newer ssh-keygen format into account The Mac machines have updated their SSH version and so the ssh-keygen format has changed. Ask it for MD5, which is the one that is output as hex. --- script/cibuild.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/script/cibuild.sh b/script/cibuild.sh index 5707f01cb..6709b38f9 100755 --- a/script/cibuild.sh +++ b/script/cibuild.sh @@ -44,8 +44,13 @@ ssh-keygen -t rsa -f ~/.ssh/id_rsa -N "" -q cat ~/.ssh/id_rsa.pub >>~/.ssh/authorized_keys ssh-keyscan -t rsa localhost >>~/.ssh/known_hosts -# Get the fingerprint for localhost and remove the colons so we can parse it as a hex number -export GITTEST_REMOTE_SSH_FINGERPRINT=$(ssh-keygen -F localhost -l | tail -n 1 | cut -d ' ' -f 2 | tr -d ':') +# Get the fingerprint for localhost and remove the colons so we can parse it as +# a hex number. The Mac version is newer so it has a different output format. +if [ "$TRAVIS_OS_NAME" = "osx" ]; then + export GITTEST_REMOTE_SSH_FINGERPRINT=$(ssh-keygen -E md5 -F localhost -l | tail -n 1 | cut -d ' ' -f 3 | cut -d : -f2- | tr -d :) +else + export GITTEST_REMOTE_SSH_FINGERPRINT=$(ssh-keygen -F localhost -l | tail -n 1 | cut -d ' ' -f 2 | tr -d ':') +fi export GITTEST_REMOTE_URL="ssh://localhost/$HOME/_temp/test.git" export GITTEST_REMOTE_USER=$USER From 4cf1ec7cff28da8838a2f0a9fb330e312ea3f963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 3 Nov 2016 11:53:23 +0100 Subject: [PATCH 4/7] Bump version to 0.24.3 --- include/git2/version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/git2/version.h b/include/git2/version.h index 93b369462..bde80fe9a 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -7,10 +7,10 @@ #ifndef INCLUDE_git_version_h__ #define INCLUDE_git_version_h__ -#define LIBGIT2_VERSION "0.24.2" +#define LIBGIT2_VERSION "0.24.3" #define LIBGIT2_VER_MAJOR 0 #define LIBGIT2_VER_MINOR 24 -#define LIBGIT2_VER_REVISION 2 +#define LIBGIT2_VER_REVISION 3 #define LIBGIT2_VER_PATCH 0 #define LIBGIT2_SOVERSION 24 From 65d24fd7dd4f881d60ef39a80999d53797626470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 2 Nov 2016 14:50:59 +0100 Subject: [PATCH 5/7] Add support for OpenSSL 1.1.0 for BIO filter --- src/openssl_stream.c | 69 ++++++++++++++++++---------- src/openssl_stream.h | 106 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 25 deletions(-) diff --git a/src/openssl_stream.c b/src/openssl_stream.c index 9d97bae00..64187a8a2 100644 --- a/src/openssl_stream.c +++ b/src/openssl_stream.c @@ -13,6 +13,7 @@ #include "posix.h" #include "stream.h" #include "socket_stream.h" +#include "openssl_stream.h" #include "netops.h" #include "git2/transport.h" #include "git2/sys/openssl.h" @@ -71,12 +72,20 @@ static void shutdown_ssl_locking(void) #endif /* GIT_THREADS */ +static BIO_METHOD *git_stream_bio_method; +static int init_bio_method(void); + /** * This function aims to clean-up the SSL context which * we allocated. */ static void shutdown_ssl(void) { + if (git_stream_bio_method) { + BIO_meth_free(git_stream_bio_method); + git_stream_bio_method = NULL; + } + if (git__ssl_ctx) { SSL_CTX_free(git__ssl_ctx); git__ssl_ctx = NULL; @@ -121,6 +130,13 @@ int git_openssl_stream_global_init(void) git__ssl_ctx = NULL; return -1; } + + if (init_bio_method() < 0) { + SSL_CTX_free(git__ssl_ctx); + git__ssl_ctx = NULL; + return -1; + } + #endif git__on_shutdown(shutdown_ssl); @@ -156,10 +172,8 @@ int git_openssl_set_locking(void) static int bio_create(BIO *b) { - b->init = 1; - b->num = 0; - b->ptr = NULL; - b->flags = 0; + BIO_set_init(b, 1); + BIO_set_data(b, NULL); return 1; } @@ -169,23 +183,22 @@ static int bio_destroy(BIO *b) if (!b) return 0; - b->init = 0; - b->num = 0; - b->ptr = NULL; - b->flags = 0; + BIO_set_data(b, NULL); return 1; } static int bio_read(BIO *b, char *buf, int len) { - git_stream *io = (git_stream *) b->ptr; + git_stream *io = (git_stream *) BIO_get_data(b); + return (int) git_stream_read(io, buf, len); } static int bio_write(BIO *b, const char *buf, int len) { - git_stream *io = (git_stream *) b->ptr; + git_stream *io = (git_stream *) BIO_get_data(b); + return (int) git_stream_write(io, buf, len, 0); } @@ -214,17 +227,22 @@ static int bio_puts(BIO *b, const char *str) return bio_write(b, str, strlen(str)); } -static BIO_METHOD git_stream_bio_method = { - BIO_TYPE_SOURCE_SINK, - "git_stream", - bio_write, - bio_read, - bio_puts, - bio_gets, - bio_ctrl, - bio_create, - bio_destroy -}; +static int init_bio_method(void) +{ + /* Set up the BIO_METHOD we use for wrapping our own stream implementations */ + git_stream_bio_method = BIO_meth_new(BIO_TYPE_SOURCE_SINK | BIO_get_new_index(), "git_stream"); + GITERR_CHECK_ALLOC(git_stream_bio_method); + + BIO_meth_set_write(git_stream_bio_method, bio_write); + BIO_meth_set_read(git_stream_bio_method, bio_read); + BIO_meth_set_puts(git_stream_bio_method, bio_puts); + BIO_meth_set_gets(git_stream_bio_method, bio_gets); + BIO_meth_set_ctrl(git_stream_bio_method, bio_ctrl); + BIO_meth_set_create(git_stream_bio_method, bio_create); + BIO_meth_set_destroy(git_stream_bio_method, bio_destroy); + + return 0; +} static int ssl_set_error(SSL *ssl, int error) { @@ -339,7 +357,7 @@ static int verify_server_cert(SSL *ssl, const char *host) num = sk_GENERAL_NAME_num(alts); for (i = 0; i < num && matched != 1; i++) { const GENERAL_NAME *gn = sk_GENERAL_NAME_value(alts, i); - const char *name = (char *) ASN1_STRING_data(gn->d.ia5); + const char *name = (char *) ASN1_STRING_get0_data(gn->d.ia5); size_t namelen = (size_t) ASN1_STRING_length(gn->d.ia5); /* Skip any names of a type we're not looking for */ @@ -394,7 +412,7 @@ static int verify_server_cert(SSL *ssl, const char *host) if (size > 0) { peer_cn = OPENSSL_malloc(size + 1); GITERR_CHECK_ALLOC(peer_cn); - memcpy(peer_cn, ASN1_STRING_data(str), size); + memcpy(peer_cn, ASN1_STRING_get0_data(str), size); peer_cn[size] = '\0'; } else { goto cert_fail_name; @@ -445,11 +463,12 @@ int openssl_connect(git_stream *stream) st->connected = true; - bio = BIO_new(&git_stream_bio_method); + bio = BIO_new(git_stream_bio_method); GITERR_CHECK_ALLOC(bio); - bio->ptr = st->io; + BIO_set_data(bio, st->io); SSL_set_bio(st->ssl, bio, bio); + /* specify the host in case SNI is needed */ #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME SSL_set_tlsext_host_name(st->ssl, st->host); diff --git a/src/openssl_stream.h b/src/openssl_stream.h index 82b5110c4..b769437ae 100644 --- a/src/openssl_stream.h +++ b/src/openssl_stream.h @@ -13,4 +13,110 @@ extern int git_openssl_stream_global_init(void); extern int git_openssl_stream_new(git_stream **out, const char *host, const char *port); +/* + * OpenSSL 1.1 made BIO opaque so we have to use functions to interact with it + * which do not exist in previous versions. We define these inline functions so + * we can program against the interface instead of littering the implementation + * with ifdefs. + */ +#ifdef GIT_OPENSSL +# include +# include +# include +# include + + + +# if OPENSSL_VERSION_NUMBER < 0x10100000L + +GIT_INLINE(BIO_METHOD*) BIO_meth_new(int type, const char *name) +{ + BIO_METHOD *meth = git__calloc(1, sizeof(BIO_METHOD)); + if (!meth) { + return NULL; + } + + meth->type = type; + meth->name = name; + + return meth; +} + +GIT_INLINE(void) BIO_meth_free(BIO_METHOD *biom) +{ + git__free(biom); +} + +GIT_INLINE(int) BIO_meth_set_write(BIO_METHOD *biom, int (*write) (BIO *, const char *, int)) +{ + biom->bwrite = write; + return 1; +} + +GIT_INLINE(int) BIO_meth_set_read(BIO_METHOD *biom, int (*read) (BIO *, char *, int)) +{ + biom->bread = read; + return 1; +} + +GIT_INLINE(int) BIO_meth_set_puts(BIO_METHOD *biom, int (*puts) (BIO *, const char *)) +{ + biom->bputs = puts; + return 1; +} + +GIT_INLINE(int) BIO_meth_set_gets(BIO_METHOD *biom, int (*gets) (BIO *, char *, int)) + +{ + biom->bgets = gets; + return 1; +} + +GIT_INLINE(int) BIO_meth_set_ctrl(BIO_METHOD *biom, long (*ctrl) (BIO *, int, long, void *)) +{ + biom->ctrl = ctrl; + return 1; +} + +GIT_INLINE(int) BIO_meth_set_create(BIO_METHOD *biom, int (*create) (BIO *)) +{ + biom->create = create; + return 1; +} + +GIT_INLINE(int) BIO_meth_set_destroy(BIO_METHOD *biom, int (*destroy) (BIO *)) +{ + biom->destroy = destroy; + return 1; +} + +GIT_INLINE(int) BIO_get_new_index(void) +{ + /* This exists as of 1.1 so before we'd just have 0 */ + return 0; +} + +GIT_INLINE(void) BIO_set_init(BIO *b, int init) +{ + b->init = init; +} + +GIT_INLINE(void) BIO_set_data(BIO *a, void *ptr) +{ + a->ptr = ptr; +} + +GIT_INLINE(void*) BIO_get_data(BIO *a) +{ + return a->ptr; +} + +GIT_INLINE(const unsigned char *) ASN1_STRING_get0_data(const ASN1_STRING *x) +{ + return ASN1_STRING_data((ASN1_STRING *)x); +} + +# endif // OpenSSL < 1.1 +#endif // GIT_OPENSSL + #endif From 302aff9695d2c77371f2bd1ca8daa9c0b1ec1407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 16 Dec 2016 23:55:06 +0000 Subject: [PATCH 6/7] Bump version to 0.24.4 --- include/git2/version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/git2/version.h b/include/git2/version.h index bde80fe9a..d7079c73c 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -7,10 +7,10 @@ #ifndef INCLUDE_git_version_h__ #define INCLUDE_git_version_h__ -#define LIBGIT2_VERSION "0.24.3" +#define LIBGIT2_VERSION "0.24.4" #define LIBGIT2_VER_MAJOR 0 #define LIBGIT2_VER_MINOR 24 -#define LIBGIT2_VER_REVISION 3 +#define LIBGIT2_VER_REVISION 4 #define LIBGIT2_VER_PATCH 0 #define LIBGIT2_SOVERSION 24 From 428e18f8d4765b8ad6cf4022080a81ab16f6fdc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Sat, 17 Dec 2016 10:47:29 +0000 Subject: [PATCH 7/7] Bump version to 0.24.5 --- include/git2/version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/git2/version.h b/include/git2/version.h index d7079c73c..5e060325c 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -7,10 +7,10 @@ #ifndef INCLUDE_git_version_h__ #define INCLUDE_git_version_h__ -#define LIBGIT2_VERSION "0.24.4" +#define LIBGIT2_VERSION "0.24.5" #define LIBGIT2_VER_MAJOR 0 #define LIBGIT2_VER_MINOR 24 -#define LIBGIT2_VER_REVISION 4 +#define LIBGIT2_VER_REVISION 5 #define LIBGIT2_VER_PATCH 0 #define LIBGIT2_SOVERSION 24