[Nasm-bugs] [Bug 3392760] New: Stack use-after-scope in expand_mmac_params for indirect macro expansion

noreply-nasm at dev.nasm.us noreply-nasm at dev.nasm.us
Wed Jun 2 13:06:12 PDT 2021


https://bugzilla.nasm.us/show_bug.cgi?id=3392760

            Bug ID: 3392760
           Summary: Stack use-after-scope in expand_mmac_params for
                    indirect macro expansion
           Product: NASM
           Version: 2.16 (development)
          Hardware: PC
                OS: Linux
            Status: OPEN
          Severity: normal
          Priority: Medium
         Component: Assembler
          Assignee: nobody at nasm.us
          Reporter: mvanotti at protonmail.com
                CC: chang.seok.bae at intel.com, gorcunov at gmail.com,
                    hpa at zytor.com, nasm-bugs at nasm.us
     Obtained from: Built from git using configure

There's a stack use-after-scope issue in the `expand_mmac_params` function,
when it tries to expand an indirect macro expansion.

The following minimized test case reproduces the issue:


```asm
%[
```

Run with:

```shell
$ nasm -f elf64 -g -FDWARF -o test.o file.asm
```

You can reproduce this crash by compiling with Address Sanitizer:

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

Here's the Address Sanitizer output:

```
src/ce37e0123:1: error: label or instruction expected at start of line
src/ce37e0123:4: warning: unterminated %[ construct [-w+other]
=================================================================
==757284==ERROR: AddressSanitizer: stack-use-after-scope on address
0x7fff4dad6140 at pc 0x000000566e6f bp 0x7fff4dad6110 sp 0x7fff4dad6108
WRITE of size 8 at 0x7fff4dad6140 thread T0
    #0 0x566e6e in expand_mmac_params /home/markov/nasm/asm/preproc.c:5373:11
    #1 0x532fba in pp_tokline /home/markov/nasm/asm/preproc.c:7258:21
    #2 0x530674 in pp_getline /home/markov/nasm/asm/preproc.c:7328:17
    #3 0x4c05d9 in assemble_file /home/markov/nasm/asm/nasm.c:1722:24
    #4 0x4c05d9 in main /home/markov/nasm/asm/nasm.c:717:9
    #5 0x7f369a9a90b2 in __libc_start_main
/build/glibc-eX1tMB/glibc-2.31/csu/../csu/libc-start.c:308:16
    #6 0x41c64d in _start (/home/markov/nasm/nasm+0x41c64d)

Address 0x7fff4dad6140 is located in stack of thread T0 at offset 32 in frame
    #0 0x5623bf in expand_mmac_params /home/markov/nasm/asm/preproc.c:5188

  This frame has 9 object(s):
    [32, 40) 'newlist.i488' (line 892) <== Memory access at offset 32 is inside
this variable
    [64, 72) 'newlist.i' (line 915)
    [96, 104) 'newlist.i.i' (line 915)
    [128, 132) 'fst.i' (line 5136)
    [144, 148) 'lst.i' (line 5136)
    [160, 168) 'thead' (line 5189)
    [192, 200) 'ep' (line 5254)
    [224, 232) 'ep104' (line 5272)
    [256, 272) 't260' (line 5376)
HINT: this may be a false positive if your program uses some custom stack
unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-scope
/home/markov/nasm/asm/preproc.c:5373:11 in expand_mmac_params
Shadow bytes around the buggy address:
  0x100069b52bd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100069b52be0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100069b52bf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100069b52c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100069b52c10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x100069b52c20: 00 00 00 00 f1 f1 f1 f1[f8]f2 f2 f2 f8 f2 f2 f2
  0x100069b52c30: f8 f2 f2 f2 f8 f2 f8 f2 00 f2 f2 f2 f8 f2 f2 f2
  0x100069b52c40: f8 f2 f2 f2 f8 f8 f3 f3 00 00 00 00 00 00 00 00
  0x100069b52c50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100069b52c60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100069b52c70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
==757284==ABORTING

```

My understanding of the issue is as follows:

For this test file, when expand_mmac_params is called, it will enter the
TOKEN_INDIRECT case[0]

The call to tokenize will return a NULL pointer, as the macro is incomplete
(missing indirection and right bracket ])

Then, there's a call to dup_tlist(tt, &tail) right after (there's a comment
asking why it is there, I don't know if it is safe to remove, but the problem
arises then in that function)

The dup_tlist function[1] sets the tailpp pointer to the address of the newlist
variable, which has an automatic duration tied to the scope of that function.
In the normal case, for a non-empty list, this should be fine, as it will be
modified while iterating the list.

But in this case, given that the token is NULL, the list is considered empty,
so tailpp is never modified, and then, tailp is set with the value of tailpp,
which still holds the address of the newlist variable.

Thus, when the function returns, the tail variable points to the newlist
variable, which is out of scope.


[0]:
https://github.com/netwide-assembler/nasm/blob/5368e45/asm/preproc.c#L5332-L5344
[1]:
https://github.com/netwide-assembler/nasm/blob/5368e45/asm/preproc.c#L887-L908

-- 
You are receiving this mail because:
You are watching all bug changes.
You are on the CC list for the bug.


More information about the Nasm-bugs mailing list