New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 765824 link

Starred by 2 users

Issue metadata

Status: WontFix
Owner:
Closed: Jan 16
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux , Android , Windows , Chrome , Mac , Fuchsia
Pri: 2
Type: Bug



Sign in to add a comment

Security: Memory Corruption Vulnerability in Skia [MSAN Build]

Reported by kushal89...@gmail.com, Sep 15 2017

Issue description

VULNERABILITY DETAILS

Memory Corruption Vulnerability triggered in Skia. 

Analysis done on LINUX System, Only the reporting was done on Windows System.

PoC has been tested on latest Chrome Linux "MSAN" build (#502297) as of Sept 15 12:45PM PST. 

Build links have been shared in the Step 1 of the "Reproduction Case" section.

VERSION
Chrome Version: Latest Linux "MSAN" release build.

Operating System: Ubuntu

REPRODUCTION CASE

1. Download latest chrome "MSAN" build from https://www.googleapis.com/download/storage/v1/b/chromium-browser-msan/o/linux-release%2Fmsan-chained-origins-linux-release-502297.zip?generation=1505503057006046&alt=media

2. Unzip the downloaded "msan" builds.

3. Change directory to filter_fuzz_stub location.

4. Set environment variable MSAN_OPTIONS=allocator_may_return_null=1

5. Under gdb, run the filter_fuzz_stub binary against the New_Msan_PoC.fil testcase file.

6. Check the crash details in the terminal window.

FOR CRASHES, PLEASE INCLUDE THE FOLLOWING ADDITIONAL INFORMATION

Binary segfaults (crashes) due to trigger of an Out-Of-Bounds Write Access.

See gdb output below: -

root@kush:~/Desktop/fil_msan# printenv | grep "MSAN_OPTIONS"
MSAN_OPTIONS=allocator_may_return_null=1
root@kush:~/Desktop/fil_msan# 


root@kush:~/Desktop/fil_msan# /root/Desktop/msan-chained-origins-linux-release-502297/filter_fuzz_stub /root/Desktop/New_Msan_PoC.fil 
[0915/144902.523473:INFO:filter_fuzz_stub.cc(60)] Test case: /root/Desktop/New_Msan_PoC.fil
Segmentation fault
root@kush:~/Desktop/fil_msan# gdb --args /root/Desktop/msan-chained-origins-linux-release-502297/filter_fuzz_stub /root/Desktop/New_Msan_PoC.fil 
GNU gdb (Debian 7.12-6) 7.12.0.20161007-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /root/Desktop/msan-chained-origins-linux-release-502297/filter_fuzz_stub...done.
(gdb) r
Starting program: /root/Desktop/msan-chained-origins-linux-release-502297/filter_fuzz_stub /root/Desktop/New_Msan_PoC.fil
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[0915/144912.108117:INFO:filter_fuzz_stub.cc(60)] Test case: /root/Desktop/New_Msan_PoC.fil

Program received signal SIGSEGV, Segmentation fault.
0x0000000000440085 in __msan::MsanAllocate(__sanitizer::StackTrace*, unsigned long, unsigned long, bool) ()
(gdb) bt
#0  0x0000000000440085 in __msan::MsanAllocate(__sanitizer::StackTrace*, unsigned long, unsigned long, bool) ()
#1  0x0000000000440186 in __msan::msan_malloc(unsigned long, __sanitizer::StackTrace*) ()
#2  0x0000000000448f4f in malloc ()
#3  0x00000000005547fd in sk_malloc_throw () at ../../skia/ext/SkMemory_new_handler.cpp:64
#4  0x000000000065685f in reset () at ../../third_party/skia/include/gpu/../private/SkTemplates.h:183
#5  0x0000000000656c8b in allocInputs () at ../../third_party/skia/src/core/SkImageFilter.cpp:113
#6  unflatten () at ../../third_party/skia/src/core/SkImageFilter.cpp:126
#7  0x0000000000fe39ff in CreateProc ()
    at ../../third_party/skia/src/effects/SkMergeImageFilter.cpp:114
#8  0x000000000083bf61 in readFlattenable ()
    at ../../third_party/skia/src/core/SkValidatingReadBuffer.cpp:301
#9  0x000000000064d90c in SkValidatingDeserializeFlattenable ()
    at ../../third_party/skia/src/core/SkFlattenableSerialization.cpp:26
#10 SkValidatingDeserializeImageFilter ()
    at ../../third_party/skia/src/core/SkFlattenableSerialization.cpp:30
#11 0x000000000049341f in RunTestCase () at ../../skia/tools/filter_fuzz_stub/filter_fuzz_stub.cc:32
#12 ReadAndRunTestCase () at ../../skia/tools/filter_fuzz_stub/filter_fuzz_stub.cc:66
#13 main () at ../../skia/tools/filter_fuzz_stub/filter_fuzz_stub.cc:85
(gdb) exploitable
__main__:99: UserWarning: GDB v7.12 may not support required Python API
Description: Access violation on destination operand
Short description: DestAv (8/22)
Hash: bd99e13b64ec52861190c6ec972adbd6.79560eba448cc95d8a97949d1631d37f
Exploitability Classification: EXPLOITABLE
Explanation: The target crashed on an access violation at an address matching the destination operand of the instruction. This likely indicates a write access violation, which means the attacker may control the write address and/or value.
Other tags: AccessViolation (21/22)
(gdb) 

 

Comment 1 by mea...@chromium.org, Sep 15 2017

Components: Internals>Skia
Labels: OS-Linux
Owner: reed@chromium.org
Status: Assigned (was: Unconfirmed)
Thanks for the report.

reed: Can you please take a look?
Hello @meacer, @reed, Google Product Security Team [skia],

Good Afternoon.

I noticed that there was a more recent version of chrome msan build available around the same time as my report.

I would like to confirm that the crash consistently occurs in the most recent version also i.e. build #502326 available at https://www.googleapis.com/download/storage/v1/b/chromium-browser-msan/o/linux-release%2Fmsan-chained-origins-linux-release-502326.zip?generation=1505510729205749&alt=media 

Thanks,
Kushal.

PS: @meacer, That was one of the fastest (if not the fastest) responses I have seen from Google PSIRT Team!!! Truly commendable!!:) 

Comment 3 by mea...@chromium.org, Sep 15 2017

Glad to help :) Please keep the reports coming.

Comment 4 by hcm@chromium.org, Sep 18 2017

Cc: hcm@chromium.org
Owner: reed@google.com
reed@chromium --> @google

Comment 5 by reed@google.com, Sep 18 2017

Cc: herb@chromium.org fmalita@chromium.org bunge...@chromium.org mtklein@chromium.org
This looks like MSAN itself is crashing, while trying to service a malloc request. That is odd.

This option: MSAN_OPTIONS=allocator_may_return_null=1, is very dubious when embedding Skia, as skia in general does not check for null on allocations. Specifically in this case (for the ImageFilter), Skia has told the embedding client that it will NOT check for null.
Hello @reed, 

Good Evening.

I am not quite sure what you meant by calling "allocator_may_return_null=1" as dubious, but for reference, here are some crbug reports wherein the same option was previously used for several other bugs in Chrome.

https://bugs.chromium.org/p/chromium/issues/detail?id=446032
https://bugs.chromium.org/p/chromium/issues/detail?id=468519
https://bugs.chromium.org/p/chromium/issues/detail?id=431288
https://bugs.chromium.org/p/chromium/issues/detail?id=699166

Hope that helps in some way..:)

Thanks,
~ Kushal.

Hello @reed, @hcm, @meacer, @bungeman, Google Product Security Team,

I would like to confirm that the crash is consistently reproducible on the latest Chrome MSAN "Stable" and "Beta" builds available at https://www.googleapis.com/download/storage/v1/b/chromium-browser-msan/o/linux-release%2Fmsan-linux-stable-61.0.3163.91.zip?generation=1505829384001916&alt=media AND https://www.googleapis.com/download/storage/v1/b/chromium-browser-msan/o/linux-release%2Fmsan-linux-beta-62.0.3202.18.zip?generation=1505796962687871&alt=media respectively.

Thanks,
~ Kushal.
Kushal,

1) the crash is inside the *MSAN* allocator itself (not present in regular builds)

2) allocator_may_return_null=1 is an invalid Chromium configuration (regular builds perform a controlled-crash on allocation failures, and never return null)

Unless you can repro the crash without allocator_may_return_null=1, I don't think this is valid issue.

Comment 9 by palmer@chromium.org, Sep 20 2017

FWIW, I can't reproduce the bug (using that build, https://www.googleapis.com/download/storage/v1/b/chromium-browser-msan/o/linux-release%2Fmsan-chained-origins-linux-release-502297.zip?generation=1505503057006046&alt=media), with any of 

MSAN_OPTIONS=allocator_may_return_null=1
MSAN_OPTIONS=allocator_may_return_null=1
unset MSAN_OPTIONS

They all result in:

[0920/155404.646330:INFO:filter_fuzz_stub.cc(60)] Test case: /usr/local/google/home/palmer/Downloads/New_Msan_PoC.fil
[0920/155458.950323:INFO:filter_fuzz_stub.cc(52)] Invalid stream detected.
@palmer, 

#9: The bug is still consistently reproducible on the recent most msan build. Would you like a step by step video for the same?

Thanks,
~ Kushal.
Oops; this:

MSAN_OPTIONS=allocator_may_return_null=1
MSAN_OPTIONS=allocator_may_return_null=1
unset MSAN_OPTIONS

should have been:

MSAN_OPTIONS=allocator_may_return_null=1
MSAN_OPTIONS=allocator_may_return_null=0
unset MSAN_OPTIONS

I.e. none of the 3 possibilities results in a crash, just the rejection of the "invalid stream".

A video won't help; I believe you that you saw it. :) But I can't reproduce it. I wonder if the buggy behavior depends on something different in our different Linux systems (e.g. libc), or something.

What would help is if you can let us know if you can reproduce the crash on your system without `allocator_may_return_null=1`.
#11: I have tested it on 3 different machines, one ubuntu and two kali machines.

Without the 'allocator_may_return_null=1' flag, the binary crashes because the re-allocation fails and throws an error as seen below: -

/root/Desktop/msan-chained-origins-linux-release-503147/filter_fuzz_stub /root/Desktop/New_Msan_PoC.fil 
[0920/174205.911748:INFO:filter_fuzz_stub.cc(60)] Test case: /root/Desktop/New_Msan_PoC.fil
==7539==MemorySanitizer's allocator is terminating the process instead of returning 0
==7539==If you don't like this behavior set allocator_may_return_null=1
==7539==Sanitizer CHECK failed: /b/build/slave/linux_upload_clang/build/src/third_party/llvm/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc:218 ((0)) != (0) (0, 0)

Therefore, when we set the allocator_may_return_null=1 as suggested by the above crash, we get the segfault crash.

This is very much similar to  crbug.com/446032 

Therein, we see another researcher using the same run-time flag "allocator_may_return_null=1" to prove the vulnerability. Also we see the same Sanitizer Failed output when we don't use "allocator_may_return_null=1".

Several questions raised in this report and in  crbug.com/763213  have been answered 2 years back in  crbug.com/446032 . Hope it helps in assessing this issue and  crbug.com/763213 .

Thanks,
~ Kushal.
Kushal, the exception you see without allocator_may_return_null=1 is the expected behavior for production Chrome/Chromium builds - i.e. a controlled, unexploitable crash when allocations fail due to OOM.

Note that  crbug.com/446032  is different because, at the time of the report, the crashing process (pdfium) was not subject to the OOM exception - so allocations could indeed return null in production.  That's not the case here.

See

 https://crbug.com/446032#c14 
 https://crbug.com/446032#c50 


13: Fmalita, Not sure how this is an OOM since I couldn't find any mention of the same in the crashing output. At the end of this comment, you can see another reasoning for it not being an OOM.

Note that the initial crashing output in  crbug.com/446032#c0  for both with and without allocator_may_return_null=1 is identical in nature to this report.

See,  crbug.com/446032#c3  ;  crbug.com/446032 #4 ;  crbug.com/446032 #51 &  crbug.com/446032 #52.

Also I had another look at my crashing stack trace and at the skia files that it points to and I could see that this cannot be an OOM. Here's why: -

   void reset(int count) {
        T* start = fArray;
        T* iter = start + fCount;
        while (iter > start) {
            (--iter)->~T();
        }

        SkASSERT(count >= 0);
        if (fCount != count) {
            if (fCount > kCount) {
                // 'fArray' was allocated last time so free it now
                SkASSERT((T*) fStorage != fArray);
                sk_free(fArray);
            }

            if (count > kCount) {
                const uint64_t size64 = sk_64_mul(count, sizeof(T));
                const size_t size = static_cast<size_t>(size64);
                if (size != size64) {
                    sk_out_of_memory();
                }
                fArray = (T*) sk_malloc_throw(size);
            } else if (count > 0) {
                fArray = (T*) fStorage;
            } else {
                fArray = nullptr;
            }

            fCount = count;
        }

        iter = fArray;
        T* stop = fArray + count;
        while (iter < stop) {
            new (iter++) T;
        }
    }

From the crashing output in the initial report, we can see that the code jumps to reset() function line 183 and that line is executed if NOT OOM, as seen in line 180&181 of https://cs.chromium.org/chromium/src/third_party/skia/include/private/SkTemplates.h?l=162&gsn=reset. 

In other words, if this was an OOM, then the condition in line 180 would have been met and the flow would have moved to line 181 and not line 183.

Hope that helps..:)

Thanks,
~ Kushal.
MSAN itself is telling you this is an allocation failure:

==7539==MemorySanitizer's allocator is terminating the process instead of returning 0

  ^ a return of 0 from the allocator is indicative of an OOM.

The check on line 180 has nothing to do with the available memory/OOM - it is just a sanity check that we're not trying to allocate some insane amount (the allocation size should not overflow 32 bits).

The actual allocation (and OOM) occurs on line 183 (sk_malloc_throw): https://cs.chromium.org/chromium/src/third_party/skia/include/private/SkTemplates.h?rcl=db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9&l=183
c#15 & c#8: I am still not convinced why this report is not valid, since  crbug.com/446032  is almost identical to my report and it also showcases both the cases, with and without the allocator_may_return_null=1 flag, And it was accepted as valid and thereafter fixed.

BUT, if you believe this to not be a security issue, I would like to request you to label it "Type-Bug" and make it public.

Thanks,
~ Kushal.
Cc: infe...@chromium.org palmer@chromium.org
Based on  https://crbug.com/446032#c14 , it sounds like at the time when the crash was reported, pdfium was running in a process without OOM protection.  In that environment, the allocator could indeed return null (instead of crashing), so allocator_may_return_null=1 was a valid MSAN config for that process.  That is not the case here: Skia allocations are never allowed to return null in production.

It is also our recommendation to remove the security labels and make this bug public, but will leave it to the security team for review.
Labels: -Type-Bug-Security -Restrict-View-SecurityTeam OS-Android OS-Chrome OS-Fuchsia OS-Mac OS-Windows Type-Bug
#17: Yep, thanks.

(I assume we use Skia on Fuchsia, right? Un-check if not.)
Cc: kjlubick@chromium.org kjlubick@google.com
Owner: reed@chromium.org
Labels: Pri-2
Setting defect without priority to Pri-2.
Owner: reed@google.com
Status: WontFix (was: Assigned)
It's unclear to me if there's anything to follow up with here, so I'll mark it as WontFix.  Please remind me if this is still busy.

Sign in to add a comment