Project: libsass (sass/libsass), language: c++
Vulnerability instance: libsass.cve-2018-19827
Sanitizer: address

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/sass/libsass/issues/2782
## Description:
Issue: sass/libsass#2782
Title: AddressSanitizer: heap-use-after-free in both libsass 3.5.5 and latest codebase
State: closed
Created by: zyingp
Created at: 2018-12-03 12:05:02+00:00
Labels: Fuzzy

Issue Body:
I found a new heap use-after-free bug with a special sass file. The file causes heap-use-after-free bug in both version 3.5.5 and the latest master branch (accessed on 2018/12/2) codebase, though with slightly different crash stacks. (And is quite different from previous issue https://github.com/sass/libsass/issues/2643 .)

Build libsass/saasc with ASan:
`CXX=clang++ CC=clang CFLAGS="-g -fsanitize=address -fno-omit-frame-pointer" CXXFLAGS=$CFLAGS  make -C sassc -j4`

Run `./sassc sass_heap_UAF`
(sass_heap_UAF is at here: https://github.com/zyingp/temp/blob/master/sass_heap_UAF)

The program crashes.

# ASan Crash stack

## Crash in the latest code (accessed on 2018/12/2) 
```
==37839==ERROR: AddressSanitizer: heap-use-after-free on address 0x611000010a90 at pc 0x0001087d1d0a bp 0x7ffee7bbbdd0 sp 0x7ffee7bbbdc8
WRITE of size 1 at 0x611000010a90 thread T0
    #0 0x1087d1d09 in Sass::SharedPtr::incRefCount() SharedPtr.hpp:140
    #1 0x1087d1c2a in Sass::SharedPtr::SharedPtr(Sass::SharedObj*) SharedPtr.hpp:90
    #2 0x108075537 in Sass::SharedImpl<Sass::Directive>::SharedImpl<Sass::Directive>(Sass::Directive*) SharedPtr.hpp:155
    #3 0x10806220c in Sass::SharedImpl<Sass::AST_Node>::SharedImpl<Sass::AST_Node>(Sass::AST_Node*) SharedPtr.hpp:155
    #4 0x1085b944b in Sass::Expand::operator()(Sass::Extension*) expand.cpp:666
    #5 0x108069076 in Sass::Extension::perform(Sass::Operation<Sass::Value*>*) ast.hpp:732
    #6 0x10859105c in Sass::Expand::append_block(Sass::Block*) expand.cpp:807
    #7 0x10858f950 in Sass::Expand::operator()(Sass::Block*) expand.cpp:72
    #8 0x108595a39 in Sass::Expand::operator()(Sass::Ruleset*) expand.cpp:144
    #9 0x108067123 in Sass::Ruleset::perform(Sass::Operation<Sass::Value*>*) ast.hpp:487
    #10 0x10859105c in Sass::Expand::append_block(Sass::Block*) expand.cpp:807
    #11 0x10858f950 in Sass::Expand::operator()(Sass::Block*) expand.cpp:72
    #12 0x1081b0193 in Sass::Context::compile() context.cpp:678
    #13 0x1081ac9bb in Sass::File_Context::parse() context.cpp:605
    #14 0x1087b7400 in Sass::sass_parse_block(Sass_Compiler*) sass_context.cpp:234
    #15 0x1087b6b8a in sass_compiler_parse sass_context.cpp:483
    #16 0x1087b62f9 in sass_compile_context(Sass_Context*, Sass::Context*) sass_context.cpp:371
    #17 0x1087b671d in sass_compile_file_context sass_context.cpp:470
    #18 0x10803e796 in compile_file sassc.c:158
    #19 0x10803f0d6 in main sassc.c:370
    #20 0x7fff701cb014 in start (libdyld.dylib:x86_64+0x1014)

0x611000010a90 is located 16 bytes inside of 208-byte region [0x611000010a80,0x611000010b50)
freed by thread T0 here:
    #0 0x108dddd32 in wrap__ZdlPv (libclang_rt.asan_osx_dynamic.dylib:x86_64+0x61d32)
    #1 0x1081577a1 in Sass::Selector_List::~Selector_List() ast_selectors.hpp:513
    #2 0x1087bc023 in Sass::SharedPtr::decRefCount() SharedPtr.hpp:135
    #3 0x1087bbd94 in Sass::SharedPtr::~SharedPtr() SharedPtr.hpp:94
    #4 0x10806f164 in Sass::SharedImpl<Sass::Media_Query_Expression>::~SharedImpl() SharedPtr.hpp:149
    #5 0x1080480c4 in Sass::SharedImpl<Sass::At_Root_Query>::~SharedImpl() SharedPtr.hpp:149
    #6 0x108562861 in Sass::Eval::operator()(Sass::Parent_Reference*) eval.cpp:1615
    #7 0x1080b3de6 in Sass::Parent_Reference::perform(Sass::Operation<Sass::Value*>*) ast_values.hpp:426
    #8 0x108552f6d in Sass::Eval::operator()(Sass::String_Schema*) eval.cpp:1288
    #9 0x1080b1846 in Sass::String_Schema::perform(Sass::Operation<Sass::Value*>*) ast_values.hpp:350
    #10 0x10855d1bf in Sass::Eval::operator()(Sass::Selector_Schema*) eval.cpp:1572
    #11 0x1085b746f in Sass::Expand::operator()(Sass::Extension*) expand.cpp:652
    #12 0x108069076 in Sass::Extension::perform(Sass::Operation<Sass::Value*>*) ast.hpp:732
    #13 0x10859105c in Sass::Expand::append_block(Sass::Block*) expand.cpp:807
    #14 0x10858f950 in Sass::Expand::operator()(Sass::Block*) expand.cpp:72
    #15 0x108595a39 in Sass::Expand::operator()(Sass::Ruleset*) expand.cpp:144
    #16 0x108067123 in Sass::Ruleset::perform(Sass::Operation<Sass::Value*>*) ast.hpp:487
    #17 0x10859105c in Sass::Expand::append_block(Sass::Block*) expand.cpp:807
    #18 0x10858f950 in Sass::Expand::operator()(Sass::Block*) expand.cpp:72
    #19 0x1081b0193 in Sass::Context::compile() context.cpp:678
    #20 0x1081ac9bb in Sass::File_Context::parse() context.cpp:605
    #21 0x1087b7400 in Sass::sass_parse_block(Sass_Compiler*) sass_context.cpp:234
    #22 0x1087b6b8a in sass_compiler_parse sass_context.cpp:483
    #23 0x1087b62f9 in sass_compile_context(Sass_Context*, Sass::Context*) sass_context.cpp:371
    #24 0x1087b671d in sass_compile_file_context sass_context.cpp:470
    #25 0x10803e796 in compile_file sassc.c:158
    #26 0x10803f0d6 in main sassc.c:370
    #27 0x7fff701cb014 in start (libdyld.dylib:x86_64+0x1014)

previously allocated by thread T0 here:
    #0 0x108ddd752 in wrap__Znwm (libclang_rt.asan_osx_dynamic.dylib:x86_64+0x61752)
    #1 0x10855a310 in Sass::Eval::operator()(Sass::Selector_List*) eval.cpp:1509
    #2 0x108562378 in Sass::Eval::operator()(Sass::Parent_Reference*) eval.cpp:1617
    #3 0x1080b3de6 in Sass::Parent_Reference::perform(Sass::Operation<Sass::Value*>*) ast_values.hpp:426
    #4 0x108552f6d in Sass::Eval::operator()(Sass::String_Schema*) eval.cpp:1288
    #5 0x1080b1846 in Sass::String_Schema::perform(Sass::Operation<Sass::Value*>*) ast_values.hpp:350
    #6 0x10855d1bf in Sass::Eval::operator()(Sass::Selector_Schema*) eval.cpp:1572
    #7 0x1085b746f in Sass::Expand::operator()(Sass::Extension*) expand.cpp:652
    #8 0x108069076 in Sass::Extension::perform(Sass::Operation<Sass::Value*>*) ast.hpp:732
    #9 0x10859105c in Sass::Expand::append_block(Sass::Block*) expand.cpp:807
    #10 0x10858f950 in Sass::Expand::operator()(Sass::Block*) expand.cpp:72
    #11 0x108595a39 in Sass::Expand::operator()(Sass::Ruleset*) expand.cpp:144
    #12 0x108067123 in Sass::Ruleset::perform(Sass::Operation<Sass::Value*>*) ast.hpp:487
    #13 0x10859105c in Sass::Expand::append_block(Sass::Block*) expand.cpp:807
    #14 0x10858f950 in Sass::Expand::operator()(Sass::Block*) expand.cpp:72
    #15 0x1081b0193 in Sass::Context::compile() context.cpp:678
    #16 0x1081ac9bb in Sass::File_Context::parse() context.cpp:605
    #17 0x1087b7400 in Sass::sass_parse_block(Sass_Compiler*) sass_context.cpp:234
    #18 0x1087b6b8a in sass_compiler_parse sass_context.cpp:483
    #19 0x1087b62f9 in sass_compile_context(Sass_Context*, Sass::Context*) sass_context.cpp:371
    #20 0x1087b671d in sass_compile_file_context sass_context.cpp:470
    #21 0x10803e796 in compile_file sassc.c:158
    #22 0x10803f0d6 in main sassc.c:370
    #23 0x7fff701cb014 in start (libdyld.dylib:x86_64+0x1014)

SUMMARY: AddressSanitizer: heap-use-after-free SharedPtr.hpp:140 in Sass::SharedPtr::incRefCount()
Shadow bytes around the buggy address:
  0x1c2200002100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1c2200002110: 00 00 00 00 00 00 00 00 00 00 fa fa fa fa fa fa
  0x1c2200002120: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x1c2200002130: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x1c2200002140: fd fd fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x1c2200002150: fd fd[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x1c2200002160: fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa
  0x1c2200002170: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x1c2200002180: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x1c2200002190: fd fd fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c22000021a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==37839==ABORTING
```

## Crash in libsass 3.5.5
```
==37843==ERROR: AddressSanitizer: heap-use-after-free on address 0x611000010a88 at pc 0x00010490fd8c bp 0x7ffeeb77f8c0 sp 0x7ffeeb77f8b8
READ of size 8 at 0x611000010a88 thread T0
    #0 0x10490fd8b in Sass::SharedPtr::SharedPtr(Sass::SharedObj*) SharedPtr.cpp:75
    #1 0x1047b7005 in Sass::Expand::operator()(Sass::Extension*) SharedPtr.hpp:141
    #2 0x10479b0d6 in Sass::Expand::append_block(Sass::Block*) expand.cpp:811
    #3 0x10479a6c8 in Sass::Expand::operator()(Sass::Block*) expand.cpp:72
    #4 0x10479cb96 in Sass::Expand::operator()(Sass::Ruleset*) expand.cpp:144
    #5 0x10479b0d6 in Sass::Expand::append_block(Sass::Block*) expand.cpp:811
    #6 0x10479a6c8 in Sass::Expand::operator()(Sass::Block*) expand.cpp:72
    #7 0x10451ace9 in Sass::Context::compile() context.cpp:670
    #8 0x104518096 in Sass::File_Context::parse() context.cpp:597
    #9 0x1048b92f1 in sass_compiler_parse sass_context.cpp:234
    #10 0x1048b8b29 in sass_compile_context(Sass_Context*, Sass::Context*) sass_context.cpp:371
    #11 0x10447f9a6 in compile_file sassc.c:158
    #12 0x1044802e6 in main sassc.c:370
    #13 0x7fff701cb014 in start (libdyld.dylib:x86_64+0x1014)

0x611000010a88 is located 8 bytes inside of 216-byte region [0x611000010a80,0x611000010b58)
freed by thread T0 here:
    #0 0x104bdb292 in wrap__ZdlPv (libclang_rt.asan_osx_dynamic.dylib:x86_64+0x62292)
    #1 0x1047923c7 in Sass::Eval::operator()(Sass::Parent_Selector*) SharedPtr.hpp:172
    #2 0x104785881 in Sass::Eval::operator()(Sass::String_Schema*) eval.cpp:1237
    #3 0x104790832 in Sass::Eval::operator()(Sass::Selector_Schema*) eval.cpp:1582
    #4 0x1047b6a9f in Sass::Expand::operator()(Sass::Extension*) expand.cpp:652
    #5 0x10479b0d6 in Sass::Expand::append_block(Sass::Block*) expand.cpp:811
    #6 0x10479a6c8 in Sass::Expand::operator()(Sass::Block*) expand.cpp:72
    #7 0x10479cb96 in Sass::Expand::operator()(Sass::Ruleset*) expand.cpp:144
    #8 0x10479b0d6 in Sass::Expand::append_block(Sass::Block*) expand.cpp:811
    #9 0x10479a6c8 in Sass::Expand::operator()(Sass::Block*) expand.cpp:72
    #10 0x10451ace9 in Sass::Context::compile() context.cpp:670
    #11 0x104518096 in Sass::File_Context::parse() context.cpp:597
    #12 0x1048b92f1 in sass_compiler_parse sass_context.cpp:234
    #13 0x1048b8b29 in sass_compile_context(Sass_Context*, Sass::Context*) sass_context.cpp:371
    #14 0x10447f9a6 in compile_file sassc.c:158
    #15 0x1044802e6 in main sassc.c:370
    #16 0x7fff701cb014 in start (libdyld.dylib:x86_64+0x1014)

previously allocated by thread T0 here:
    #0 0x104bdacb2 in wrap__Znwm (libclang_rt.asan_osx_dynamic.dylib:x86_64+0x61cb2)
    #1 0x10478e74a in Sass::Eval::operator()(Sass::Selector_List*) eval.cpp:1518
    #2 0x104792096 in Sass::Eval::operator()(Sass::Parent_Selector*) eval.cpp:1616
    #3 0x104785881 in Sass::Eval::operator()(Sass::String_Schema*) eval.cpp:1237
    #4 0x104790832 in Sass::Eval::operator()(Sass::Selector_Schema*) eval.cpp:1582
    #5 0x1047b6a9f in Sass::Expand::operator()(Sass::Extension*) expand.cpp:652
    #6 0x10479b0d6 in Sass::Expand::append_block(Sass::Block*) expand.cpp:811
    #7 0x10479a6c8 in Sass::Expand::operator()(Sass::Block*) expand.cpp:72
    #8 0x10479cb96 in Sass::Expand::operator()(Sass::Ruleset*) expand.cpp:144
    #9 0x10479b0d6 in Sass::Expand::append_block(Sass::Block*) expand.cpp:811
    #10 0x10479a6c8 in Sass::Expand::operator()(Sass::Block*) expand.cpp:72
    #11 0x10451ace9 in Sass::Context::compile() context.cpp:670
    #12 0x104518096 in Sass::File_Context::parse() context.cpp:597
    #13 0x1048b92f1 in sass_compiler_parse sass_context.cpp:234
    #14 0x1048b8b29 in sass_compile_context(Sass_Context*, Sass::Context*) sass_context.cpp:371
    #15 0x10447f9a6 in compile_file sassc.c:158
    #16 0x1044802e6 in main sassc.c:370
    #17 0x7fff701cb014 in start (libdyld.dylib:x86_64+0x1014)

SUMMARY: AddressSanitizer: heap-use-after-free SharedPtr.cpp:75 in Sass::SharedPtr::SharedPtr(Sass::SharedObj*)
Shadow bytes around the buggy address:
  0x1c2200002100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1c2200002110: 00 00 00 00 00 00 00 00 00 00 fa fa fa fa fa fa
  0x1c2200002120: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x1c2200002130: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x1c2200002140: fd fd fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x1c2200002150: fd[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x1c2200002160: fd fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa
  0x1c2200002170: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x1c2200002180: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x1c2200002190: fd fd fd fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c22000021a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==37843==ABORTING
```



Comments:
Comment by glebm on 2018-12-03 21:19:10+00:00:
A simple repro:

```scss
x {
 @extend #{&};
 @extend #{&};
}
```

Interestengly, the various versions of Sass can't agree on the right result:

With the example as above, Dart outputs nothing.

Ruby outputs:

```
Error: "x" failed to @extend "x".
       The selector "x" was not found.
```

However, if we change this to:

```scss
x {
 @extend #{&};
 @extend #{&};
 color: red;
}
```

Dart:

```css
x {
  color: red;
}
```

Ruby:

```css
x {
  color: red; }
```

/cc @nex3 

---

Comment by nex3 on 2018-12-03 23:50:06+00:00:
@glebm Dart Sass is correct here. As of https://github.com/sass/sass/issues/2250, the expected behavior for an `@extend` that matches a target selector but fails to create a new selector is to raise no error. Ruby Sass is in error here... can you file an issue against it?

I believe `x {@extend x}` is a sufficient reproduction here.

---

Comment by zyingp on 2018-12-04 03:12:47+00:00:
Assigned CVE-2018-19827

Build script:
#!/bin/bash -eu
# Minimized build script with only core build commands
set -eu
export BUILD='static'
make -j$(nproc)

Dockerfile:
FROM hwiwonlee/secb.base:latest
RUN apt-get update && apt-get install -y make autoconf automake libtool
RUN git clone https://github.com/sass/libsass libsass
RUN git -C libsass checkout 39e30874b9a5dd6a802c20e8b0470ba44eeba929
WORKDIR $SRC/libsass
COPY build.sh $SRC/

Additional files:
filename: data_context_fuzzer.cc
content: #include "sass.h"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  char* sass_data = (char*) malloc(sizeof(char) * size + 1);
  if (sass_data == NULL) return 0;

  memcpy(sass_data, data, size);
  sass_data[size] = '\0';

  struct Sass_Data_Context* ctx = sass_make_data_context(sass_data);
  if (ctx == NULL) {
    free(sass_data);
    return 0;
  }

  struct Sass_Options* options = sass_make_options();
  if (options == NULL) {
    sass_delete_data_context(ctx);
    return 0;
  }

  sass_option_set_output_style(options, SASS_STYLE_NESTED);
  sass_option_set_precision(options, 5);

  sass_data_context_set_options(ctx, options);
  sass_compile_data_context(ctx);

  sass_delete_data_context(ctx);
  sass_delete_options(options);

  return 0;
}