[Bug translator/30395] Regex code has invalid memory reads caught by KASAN

agentzh at gmail dot com sourceware-bugzilla@sourceware.org
Wed May 3 00:42:17 GMT 2023


https://sourceware.org/bugzilla/show_bug.cgi?id=30395

--- Comment #3 from agentzh <agentzh at gmail dot com> ---
OK, I dug this up and found that the DFA generated by re2c used by the stap
translator indeed emits the wrong C code that will read beyond the \0 byte of
the constant C string.

Below is the bloody detail.

To make debugging easier, I minimized the original reproducer to the following
much simpler stap script:

```
probe oneshot {
    if ("3" =~ "^([0-9])$") {
        println("matched: ", matched(1));
    }
}
```

By inspecting the code location (like __stp_dfa0+0x356) given in the KASAN
report in the disassembly of the corresponding .ko file, I found that it should
be this machine instruction at fault:

```
/home/agentzh/git/systemtap-plus/test-regex/stap_1714_src.c:940
    switch (*YYCURSOR) {
    beed:   44 0f b6 65 02          movzx  r12d,BYTE PTR [rbp+0x2]
```

The YYCURSOR is a pointer pointing to the input string (in this case, the
literal C string "3"). Here, rbp points to the rsi, the 2nd argument of the
__stp_dfa0 function, i.e., the `str` parameter. And we already know that the
literal string "3" has only 2 bytes. So reading the 3rd byte via `[rbp+0x2]`
definitely leads to an invalid memory read.

The actual address given in the KASAN report might be off 1, but it is easy to
confirm by adding custom reading code around that location (this also confused
me at the beginning. alas).

Then I tried adding printk calls to the beginning of every state in the DFA of
the __stp_dfa0 function to confirm this further. (yes, I directly patched up
the generated stap_XXXX_src.c file generated by the stap translator and rebuild
the .ko to keep things easy.)

And the resulting dmesg output looks like this:

```
May 02 17:19:40 fed32-dev kernel: enter yystate0 pos=0 c=51
May 02 17:19:40 fed32-dev kernel: enter yystate3 pos=1 (c=0)
May 02 17:19:40 fed32-dev kernel: enter yystate5 pos=2
May 02 17:19:40 fed32-dev kernel:
==================================================================
May 02 17:19:40 fed32-dev kernel: BUG: KASAN: global-out-of-bounds in
__stp_dfa0+0x689/0x8ea [stap_1714]
...
```

We can see that the yystate5 moves YYCURSOR beyond the \0 byte and tries to
read it afterwards. And the KASAN report comes after yystate5 is entered.

One may wonder STAPSTRINGLEN is way larger than 2 bytes, but here it is a
constant C string that is allocated differently, i.e., inside the global data
section of the .ko (note the "global-out-of-bounds" word in the KASAN report).

One interesting thing is that we need special KASAN configuration options to
catch this issue. Unfortunately, the default KASAN options used by Fedora
kernels fail to do the job. Below are the KASAN options I used in the
reproducer:

```
CONFIG_KASAN_SHADOW_OFFSET=0xdffffc0000000000
CONFIG_HAVE_ARCH_KASAN=y
CONFIG_HAVE_ARCH_KASAN_VMALLOC=y
CONFIG_CC_HAS_KASAN_GENERIC=y
CONFIG_KASAN=y
CONFIG_KASAN_GENERIC=y
# CONFIG_KASAN_OUTLINE is not set
CONFIG_KASAN_INLINE=y
CONFIG_KASAN_STACK=y
CONFIG_KASAN_VMALLOC=y
# CONFIG_KASAN_MODULE_TEST is not set
```

Now that we know for sure it is a bug in the generated C code by stap's re2c
code emitter. But I still have no idea how to fix it in re2c. Maybe it's time
to upgrade to the latest version of the upstream re2c project. Thoughts?

-- 
You are receiving this mail because:
You are the assignee for the bug.


More information about the Systemtap mailing list