这是indexloc提供的服务,不要输入任何密码
Self-registration is disabled due to spam issue (mail gorcunov@gmail.com or hpa@zytor.com to create an account)
Bug 3392762 - Heap use-after-free while using %clear inside a macro.
Summary: Heap use-after-free while using %clear inside a macro.
Status: OPEN
Alias: None
Product: NASM
Classification: Unclassified
Component: Assembler (show other bugs)
Version: 2.16.xx
Hardware: PC Linux
: Medium normal
Assignee: nobody
URL:
Depends on:
Blocks:
 
Reported: 2021-06-03 10:47 PDT by Marco
Modified: 2021-06-13 23:14 PDT (History)
5 users (show)

Obtained from: Built from git using configure
Generated by: ---
Bug category:
Breaks existing code: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Marco 2021-06-03 10:47:28 PDT
It looks like if you put a %clear directive inside a macro, it will trigger a heap use-after-free. I am not sure what should happen when you do a %clear inside a macro, but probably not a use-after-free.

See the following reproducer:

```
%macro baz 0
  %clear
%endmacro
baz
```

Run with:

```shell
$ nasm --pragma 'preproc sane_empty_expansion' -f elf64 -g -FDWARF -werror -o tmp.o file.asm
```

Compile nasm with address sanitizer:

```shell
./configure --enable-sanitizer
```

Address Sanitizer crash report (lines are based on commit e2ed7b7e125e03646d3be537b11d1b46b9c3f506):

```text
==721371==ERROR: AddressSanitizer: heap-use-after-free on address 0x610000001e48 at pc 0x5619f54196ed bp 0x7ffc966f4de0 sp 0x7ffc966f4dd0
READ of size 8 at 0x610000001e48 thread T0
    #0 0x5619f54196ec in pp_tokline asm/preproc.c:7075
    #1 0x5619f54196ec in pp_getline asm/preproc.c:7328
    #2 0x5619f539363c in assemble_file asm/nasm.c:1722
    #3 0x5619f5389d87 in main asm/nasm.c:717
    #4 0x7fef1f8ae0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
    #5 0x5619f538c57d in _start (/home/markov/nasm-fix-heap-overflow/nasm+0x2af57d)

0x610000001e48 is located 8 bytes inside of 192-byte region [0x610000001e40,0x610000001f00)
freed by thread T0 here:
    #0 0x7fef204f37cf in __interceptor_free (/lib/x86_64-linux-gnu/libasan.so.5+0x10d7cf)
    #1 0x5619f53eefa3 in free_mmacro_table asm/preproc.c:1054
    #2 0x5619f54024de in do_directive asm/preproc.c:3938
    #3 0x5619f541319e in pp_tokline asm/preproc.c:7264
    #4 0x5619f541319e in pp_getline asm/preproc.c:7328
    #5 0x5619f539363c in assemble_file asm/nasm.c:1722
    #6 0x5619f5389d87 in main asm/nasm.c:717
    #7 0x7fef1f8ae0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)

previously allocated by thread T0 here:
    #0 0x7fef204f3dc6 in calloc (/lib/x86_64-linux-gnu/libasan.so.5+0x10ddc6)
    #1 0x5619f5395a3b in nasm_calloc nasmlib/alloc.c:72
    #2 0x5619f5395a95 in nasm_zalloc nasmlib/alloc.c:87
    #3 0x5619f5402c7b in do_directive asm/preproc.c:4246
    #4 0x5619f541319e in pp_tokline asm/preproc.c:7264
    #5 0x5619f541319e in pp_getline asm/preproc.c:7328
    #6 0x5619f539363c in assemble_file asm/nasm.c:1722
    #7 0x5619f5389d87 in main asm/nasm.c:717
    #8 0x7fef1f8ae0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)

SUMMARY: AddressSanitizer: heap-use-after-free asm/preproc.c:7075 in pp_tokline
Shadow bytes around the buggy address:
  0x0c207fff8370: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c207fff8380: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x0c207fff8390: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c207fff83a0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x0c207fff83b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x0c207fff83c0: fa fa fa fa fa fa fa fa fd[fd]fd fd fd fd fd fd
  0x0c207fff83d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c207fff83e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c207fff83f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c207fff8400: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c207fff8410: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
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
  Shadow gap:              cc
==721371==ABORTING
```
Comment 1 H. Peter Anvin 2021-06-03 12:11:19 PDT
This is an error for the same reason %unmacro in a running macro is. This obviously applies specifically to macros; clearing other things like defaliases are totally ok.
Comment 2 Marco 2021-06-03 13:50:02 PDT
Thanks for the reply, Peter.

So a reasonable fix would be to disallow usage of %clear inside multi-line macros?

Something like:

* Disable %clear
* Disable %clear all
* Disable %clear macro

I have never used context-local macros, so I am probably missing something there.
Comment 3 H. Peter Anvin 2021-06-03 15:36:33 PDT
I'm wondering if we shouldn't simply use the same teardown code as for %unmacro. There is already an invocation counter in the macro structure, so it isn't like we don't need to search the macro stack.
Comment 4 Marco 2021-06-06 03:09:06 PDT
Hi Peter,

I have some time to give this a go. Here is a patch fixing this issue, and a few related smaller issues (for example, the %clear all never ever worked. It just loops endlessly on my computer). It still needs tests, but I have a couple of test cases that I can add, once I figure out how nasm tests work :)

Please take a look when you have some time: https://github.com/netwide-assembler/nasm/commit/54b579b04b2a8c1dbf6a7acf1e26037a78e7a509

While looking at it, I noticed that there is some room for improvement in the handling of the %clear arguments. In particular, it seems to be possible to do something like %clear all all all all all all all all (etc), and something like %clear local defines global defines

The documentation mentions that the context should be at the start (if present).

With that in mind, the code can be simplified a bit. Like parsing first the context, then the rest of the parameters, and finally, making a single call to do_clear, checking for the mmacros expansion beforehand.
Comment 5 Marco 2021-06-13 23:14:00 PDT
Hi,

I was wondering if there were any updates on this issue. Does the patch need any more work?