Launchpad has imported 13 comments from the remote bug at
https://bugs.freedesktop.org/show_bug.cgi?id=98165.

If you reply to an imported comment from within Launchpad, your comment
will be sent to the remote bug automatically. Read more about
Launchpad's inter-bugtracker facilities at
https://help.launchpad.net/InterBugTracking.

------------------------------------------------------------------------
On 2016-10-08T17:16:15+00:00 Jbowler wrote:

This is in cairo-1.14.6

This has already been reported on oss-security, although there is no
analysis there and as yet there is no CVE:

http://www.openwall.com/lists/oss-security/2016/10/06/1

The repro uses:

rsvg-convert -o crash.png crash.svg

The crash happens because write_png passes invalid (off by 4GByte)
pointers to libpng.  The bug is in the declaration of
_cairo_image_surface which obviously won't work on a machine with a
64-bit address space and 32-bit (int) values.

The crash is 'just' a read from the invalid pointer inside libpng,
however there is at least one other case of the loop in read_png where
the crash would be a memory overwrite with data from the PNG; that
version has been semi-fixed.

I'm not posting a detailed analysis because I'm not sure how many places
the bug is exposed and it is pretty clear given the fact that the loop
in read_png is different that you already know about one instance of
this bug.

The libpng maintainer has a copy of my complete analysis and the
original SVG, I suggest not posting it at the moment because it took me
about 4 minutes to find the problem given the SVG.

I also suspect it isn't specific to SVG; I assume the read_png change
came from test jockeys hitting Cairo with various obvious PNG files,
they tend to not test SVG anywhere near as much.

The fix is to change 'stride' in the surface to (size_t), and preferably
width/height to (uint32_t) and depth to (unsigned).  Doing that will
reveal all cases of the bug given a sufficiently high warning level.

Reply at:
https://bugs.launchpad.net/ubuntu/+source/cairo/+bug/1639372/comments/0

------------------------------------------------------------------------
On 2016-10-11T07:30:52+00:00 Jbowler wrote:

This bug is also reported here:

https://bugzilla.redhat.com/show_bug.cgi?id=1382656

The referenced bug:

http://seclists.org/oss-sec/2016/q4/44

isn't up to date but is, unfortunately, publicly readable.

Reply at:
https://bugs.launchpad.net/ubuntu/+source/cairo/+bug/1639372/comments/1

------------------------------------------------------------------------
On 2016-10-11T12:38:11+00:00 Adrian Johnson wrote:

Created attachment 127211
fix integer overflow

Reply at:
https://bugs.launchpad.net/ubuntu/+source/cairo/+bug/1639372/comments/2

------------------------------------------------------------------------
On 2016-10-11T16:43:50+00:00 Jbowler wrote:

Well, yes, stride should be (size_t), but there may be other instances
of this.

If you change the type of stride in the struct to (unsigned int), from
(int) and run with the correct compiler warning options it will warn
about:

    (int) * (unsigned int)

because the (int) gets converted silently to (unsigned int).  GCC
probably ignores this by default, but the -Wconversion stuff is meant to
detect it.  Coverity certainly can.

Doing the above temporarily will tell you if any other code in libcairo
does this.  It doesn't catch all the potential problems; for example
read_png already has 'i' as (unsigned int) and does (IRC):

    i * stride

That still overflows on a 64-bit system, it just requires a bigger SVG
and it is a 'safe' overflow because all the pointers are still inside
the image buffer.

This is why I suggested changing the struct member; it is difficult to
detect potential 32-bit overflow.  I don't think even Coverity warns
about 32-bit arithmetic being used inside a 64-bit address calculation
and it is extremely common and normally safe.

The other approach you could use is to check when the cairo surface is
created to make sure it doesn't require more than a 31, or 32-bit sized
buffer.  However there are some devices out there which can exceed a
4GByte image; think of a 72" poster printer running at 1200dpi.  That
has 86400 dots (bytes) per row so a 42" high printout would exceed the
limit.

Reply at:
https://bugs.launchpad.net/ubuntu/+source/cairo/+bug/1639372/comments/3

------------------------------------------------------------------------
On 2016-10-13T11:36:08+00:00 Adrian Johnson wrote:

I don't like the idea of making stride unsigned. Maybe ptrdiff_t would
be a better type for stride.

Reply at:
https://bugs.launchpad.net/ubuntu/+source/cairo/+bug/1639372/comments/4

------------------------------------------------------------------------
On 2016-10-13T14:54:46+00:00 Jbowler wrote:

If cairo does support bottom-up surfaces, as are typically used in
engineering analysis (where 'z' comes out of the page) then that is the
correct solution.  Indeed, the change made to write_png (the cast to
(size_t)) does not work because the surface is not made inside cairo-
png.c (as in read_png).

Internally libpng uses ptrdiff_t because the libpng "simplified API"
accepts an image buffer with a negative stride; stride is 31-bit signed
in the API but the local variables initialized using it are ptrdiff_t.

With hindsight it would have been better to use ptrdiff_t in the API,
but the CVEs only started rolling in after the API had been in use for a
while.

Reply at:
https://bugs.launchpad.net/ubuntu/+source/cairo/+bug/1639372/comments/5

------------------------------------------------------------------------
On 2016-10-20T11:06:45+00:00 Adrian Johnson wrote:

Created attachment 127421
prevent invalid ptr access

Reply at:
https://bugs.launchpad.net/ubuntu/+source/cairo/+bug/1639372/comments/6

------------------------------------------------------------------------
On 2016-11-10T00:35:26+00:00 Seth Arnold wrote:

Is this patch sufficient? There's more cases of 'int stride', including
e.g.:

static cairo_surface_t *
_cairo_boilerplate_image_create_similar (cairo_surface_t *other,
                                         cairo_content_t content,
                                         int width, int height)
{
    cairo_format_t format;
    cairo_surface_t *surface;
    int stride;
    void *ptr;

    switch (content) {
    case CAIRO_CONTENT_ALPHA:
        format = CAIRO_FORMAT_A8;
        break;
    case CAIRO_CONTENT_COLOR:
        format = CAIRO_FORMAT_RGB24;
        break;
    case CAIRO_CONTENT_COLOR_ALPHA:
    default:
        format = CAIRO_FORMAT_ARGB32;
        break;
    }
    
    stride = cairo_format_stride_for_width(format, width);
    ptr = malloc (stride* height);

    surface = cairo_image_surface_create_for_data (ptr, format,
                                                   width, height, stride);
    cairo_surface_set_user_data (surface, &key, ptr, free);

    return surface;
}   

I know the malloc (stride * height) looks unsafe, but I think
cairo_format_stride_for_width() will return -1 in cases that might cause
the stride*height parameter to overflow, which causes the malloc() to
fail, and the subsequent functions fail 'safely' in that case.

In any event, this code looks fairly closely tied to stride being an
'int' rather than ptrdiff_t.


Here's another example:

static cairo_status_t
_cairo_image_spans_and_zero (void *abstract_renderer,
                             int y, int height,
                             const cairo_half_open_span_t *spans,
                             unsigned num_spans)
{
    cairo_image_span_renderer_t *r = abstract_renderer;
    uint8_t *mask;
    int len;

    mask = r->u.mask.data;
    if (y > r->u.mask.extents.y) {
        len = (y - r->u.mask.extents.y) * r->u.mask.stride;
        memset (mask, 0, len);
        mask += len;
    }


The u.mask.stride would be a ptrdiff_t after this patch, but 'len' is still 
only an 'int'.

Any advice appreciated.

Thanks

Reply at:
https://bugs.launchpad.net/ubuntu/+source/cairo/+bug/1639372/comments/11

------------------------------------------------------------------------
On 2016-11-10T01:33:33+00:00 Jbowler wrote:

(In reply to Seth Arnold from comment #7)
>     stride = cairo_format_stride_for_width(format, width);

I think that function should return a ptrdiff_t.  If it does so the
compiler will start issuing warnings on 64-bit builds where the result
is truncated to 32 bits, as in the above assignment.

I believe that in general it is ok for 'width' and 'height' to be (int),
assuming you don't support 16-bit systems, but any multiplication has to
be done with care:

>     ptr = malloc (stride* height);

That strikes me as bogus.  Images with rows as long as 2^31 bytes are
rare; pretty much limited to people trying to break libpng!  However
images with 2^31 or more bytes in total can happen and it is perfectly
possible on a modern desktop/laptop/tablet to end up with one in memory.
(Maybe it's a little dumb, but it is possible.)

In any case if cairo_format_stride_for_width uses (-1) as an error
return (I'm not that was what you are saying) the callers need to check
for it.

>     surface = cairo_image_surface_create_for_data (ptr, format,
>                                                    width, height, stride);

The last (stride) parameter should have type ptrdiff_t.  I think the
point I was trying to make before is that if the change is done in the
struct and places that use the 'stride' member it will force a lot of
other changes (int to ptrdiff_t) but a GNU 64-bit compiler with -Wall
-Wextra should show the vast majority of the issues.

> Here's another example:
> 
> static cairo_status_t
> _cairo_image_spans_and_zero (void *abstract_renderer,
>                              int y, int height,
>                              const cairo_half_open_span_t *spans,
>                              unsigned num_spans)
> {
>     cairo_image_span_renderer_t *r = abstract_renderer;
>     uint8_t *mask;
>     int len;
> 
>     mask = r->u.mask.data;
>     if (y > r->u.mask.extents.y) {
>         len = (y - r->u.mask.extents.y) * r->u.mask.stride;
>         memset (mask, 0, len);
>         mask += len;
>     }
> 
> 
> The u.mask.stride would be a ptrdiff_t after this patch, but 'len' is still
> only an 'int'.

Right; that should result in a compiler warning for the assignment to
'len', so then the next step is to change 'len' to ptrdiff_t.  Fixing
the warnings forces the change through to all the required places.  The
only way to stop the warning without fixing the problem is to use an
explicit cast; a static_cast in C++ terms.  casts are evil ;-)

Reply at:
https://bugs.launchpad.net/ubuntu/+source/cairo/+bug/1639372/comments/12

------------------------------------------------------------------------
On 2017-01-05T14:49:28+00:00 zhouzhen1 wrote:

It's been a while since this thread was last updated. Is there any plan
to fix this and make a new release?

Reply at:
https://bugs.launchpad.net/ubuntu/+source/cairo/+bug/1639372/comments/14

------------------------------------------------------------------------
On 2017-11-08T01:09:59+00:00 Bryce Harrington wrote:

Yes agreed, this fix looks ok, and this is already being carried by
Debian Sid.  Carrying this in the devel tree seems like the next logical
step, and if no issues arise from the extra testing and review, it looks
suitable for landing in 1.14 stable too.

Landed:
To ssh://git.freedesktop.org/git/cairo
   35fccff..38fbe62  master -> master

Given the feedback in comments 7 & 8 I'm going to leave this report open
for now as reminder to investigate further, although it might be
worthwhile to break those out as a separate bug report or two so this
one can be closed.

Reply at:
https://bugs.launchpad.net/ubuntu/+source/cairo/+bug/1639372/comments/17

------------------------------------------------------------------------
On 2018-08-25T13:35:06+00:00 Gitlab-migration wrote:

-- GitLab Migration Automatic Message --

This bug has been migrated to freedesktop.org's GitLab instance and has
been closed from further activity.

You can subscribe and participate further through the new bug through
this link to our GitLab instance:
https://gitlab.freedesktop.org/cairo/cairo/issues/81.

Reply at:
https://bugs.launchpad.net/ubuntu/+source/cairo/+bug/1639372/comments/18

------------------------------------------------------------------------
On 2019-07-20T00:47:28+00:00 Emadyassen1998 wrote:

great post.
http://www.winmilliongame.com
http://www.gtagame100.com
http://www.subway-game.com
http://www.zumagame100.com

Reply at:
https://bugs.launchpad.net/ubuntu/+source/cairo/+bug/1639372/comments/19


** Changed in: cairo
       Status: In Progress => Unknown

** Bug watch added: Red Hat Bugzilla #1382656
   https://bugzilla.redhat.com/show_bug.cgi?id=1382656

** Bug watch added: gitlab.freedesktop.org/cairo/cairo/issues #81
   https://gitlab.freedesktop.org/cairo/cairo/issues/81

-- 
You received this bug notification because you are a member of Ubuntu
Touch seeded packages, which is subscribed to cairo in Ubuntu.
https://bugs.launchpad.net/bugs/1639372

Title:
  CVE-2016-9082: DOS attack in converting SVG to PNG

Status in cairo:
  Unknown
Status in cairo package in Ubuntu:
  Fix Released
Status in cairo source package in Precise:
  Confirmed
Status in cairo source package in Trusty:
  Confirmed
Status in cairo source package in Xenial:
  Confirmed
Status in cairo source package in Yakkety:
  Confirmed
Status in cairo package in Debian:
  Fix Released

Bug description:
  I'm attaching debdiffs for trusty, xenial and yakkety. Zesty is
  already fixed by syncing cairo 1.14.6-1.1 from Debian. Maybe someone
  else can work on the precise update.

  Proof of Concept at
  http://seclists.org/oss-sec/2016/q4/44

  I didn't get gdb to work, but when I tried to convert the file, I got
  a crash report named /var/crash/_usr_bin_rsvg-convert.1000.crash .
  After the update, no crash happened.

  I reproduced the crash and verified that the new package doesn't crash
  on yakkety. In xenial I wasn't able to reproduce the crash. I did not
  test on trusty.

To manage notifications about this bug go to:
https://bugs.launchpad.net/cairo/+bug/1639372/+subscriptions

-- 
Mailing list: https://launchpad.net/~touch-packages
Post to     : touch-packages@lists.launchpad.net
Unsubscribe : https://launchpad.net/~touch-packages
More help   : https://help.launchpad.net/ListHelp

Reply via email to