Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Backports:SLE-12:Update
libgit2
libgit2-boo1100613-sign-fix.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File libgit2-boo1100613-sign-fix.patch of Package libgit2
From 8ab4f363141e07c306503fa5aeb989e5cd5474d8 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt <ps@pks.im> Date: Fri, 29 Jun 2018 07:45:18 +0200 Subject: [PATCH] delta: fix sign-extension of big left-shift Our delta code was originally adapted from JGit, which itself adapted it from git itself. Due to this heritage, we inherited a bug from git.git in how we compute the delta offset, which was fixed upstream in 48fb7deb5 (Fix big left-shifts of unsigned char, 2009-06-17). As explained by Linus: Shifting 'unsigned char' or 'unsigned short' left can result in sign extension errors, since the C integer promotion rules means that the unsigned char/short will get implicitly promoted to a signed 'int' due to the shift (or due to other operations). This normally doesn't matter, but if you shift things up sufficiently, it will now set the sign bit in 'int', and a subsequent cast to a bigger type (eg 'long' or 'unsigned long') will now sign-extend the value despite the original expression being unsigned. One example of this would be something like unsigned long size; unsigned char c; size += c << 24; where despite all the variables being unsigned, 'c << 24' ends up being a signed entity, and will get sign-extended when then doing the addition in an 'unsigned long' type. Since git uses 'unsigned char' pointers extensively, we actually have this bug in a couple of places. In our delta code, we inherited such a bogus shift when computing the offset at which the delta base is to be found. Due to the sign extension we can end up with an offset where all the bits are set. This can allow an arbitrary memory read, as the addition in `base_len < off + len` can now overflow if `off` has all its bits set. Fix the issue by casting the result of `*delta++ << 24UL` to an unsigned integer again. Add a test with a crafted delta that would actually succeed with an out-of-bounds read in case where the cast wouldn't exist. Reported-by: Riccardo Schirone <rschiron@redhat.com> Test-provided-by: Riccardo Schirone <rschiron@redhat.com> Backported by Mike Gorse <mgorse@suse.com> --- diff -urpN libgit2-0.24.1.orig/src/delta-apply.c libgit2-0.24.1/src/delta-apply.c --- libgit2-0.24.1.orig/src/delta-apply.c 2018-12-10 17:36:47.337138662 -0600 +++ libgit2-0.24.1/src/delta-apply.c 2018-12-10 17:37:16.525296317 -0600 @@ -60,7 +60,8 @@ int git__delta_apply( size_t base_sz, res_sz, alloc_sz; unsigned char *res_dp; - /* Check that the base size matches the data we were given; + /* + * Check that the base size matches the data we were given; * if not we would underflow while accessing data from the * base object, resulting in data corruption or segfault. */ @@ -85,19 +86,18 @@ int git__delta_apply( while (delta < delta_end) { unsigned char cmd = *delta++; if (cmd & 0x80) { - /* cmd is a copy instruction; copy from the base. - */ + /* cmd is a copy instruction; copy from the base. */ size_t off = 0, len = 0; if (cmd & 0x01) off = *delta++; if (cmd & 0x02) off |= *delta++ << 8; if (cmd & 0x04) off |= *delta++ << 16; - if (cmd & 0x08) off |= *delta++ << 24; + if (cmd & 0x08) off |= ((unsigned) *delta++ << 24UL); if (cmd & 0x10) len = *delta++; if (cmd & 0x20) len |= *delta++ << 8; if (cmd & 0x40) len |= *delta++ << 16; - if (!len) len = 0x10000; + if (!len) len = 0x10000; if (base_len < off + len || res_sz < len) goto fail; @@ -106,7 +106,8 @@ int git__delta_apply( res_sz -= len; } else if (cmd) { - /* cmd is a literal insert instruction; copy from + /* + * cmd is a literal insert instruction; copy from * the delta stream itself. */ if (delta_end - delta < cmd || res_sz < cmd) @@ -117,8 +118,7 @@ int git__delta_apply( res_sz -= cmd; } else { - /* cmd == 0 is reserved for future encodings. - */ + /* cmd == 0 is reserved for future encodings. */ goto fail; } } diff -urpN libgit2-0.24.1.orig/tests/delta/apply.c libgit2-0.24.1/tests/delta/apply.c --- libgit2-0.24.1.orig/tests/delta/apply.c 1969-12-31 18:00:00.000000000 -0600 +++ libgit2-0.24.1/tests/delta/apply.c 2018-12-10 17:38:31.085698183 -0600 @@ -0,0 +1,16 @@ +#include "clar_libgit2.h" + +#include "delta.h" +#include "delta-apply.h" + +void test_delta_apply__read_at_off(void) +{ + unsigned char base[16] = { 0 }, delta[] = { 0x10, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00 }; + git_rawobj obj; + + obj.data = NULL; + obj.len = 0; + obj.type = GIT_OBJ_BAD; + + cl_git_fail(git__delta_apply(&obj, base, sizeof(base), delta, sizeof(delta))); +} diff -urpN libgit2-0.24.1.orig/tests/diff/binary.c libgit2-0.24.1/tests/diff/binary.c --- libgit2-0.24.1.orig/tests/diff/binary.c 2018-12-10 17:36:47.341138684 -0600 +++ libgit2-0.24.1/tests/diff/binary.c 2018-12-10 17:37:16.529296338 -0600 @@ -3,6 +3,7 @@ #include "git2/sys/diff.h" #include "buffer.h" +#include "delta.h" #include "filebuf.h" #include "repository.h"
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor