https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80094

            Bug ID: 80094
           Summary: GCC plugin hash table corruption on hash table
                    expansion (>10 plugins) on GCC 4.5+
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: plugins
          Assignee: unassigned at gcc dot gnu.org
          Reporter: git at lerya dot net
  Target Milestone: ---

Hi!

While trying to compile a linux kernel patches with grsecurity (grsecurity.net)
and other options that loads gcc plugins, I was unable to compile anything, due
to a very strange error: ```cc1: error: plugin XXX should be specified before
-fplugin-arg-XXX-YYY=ZZZ in the command line```, while aquick check on the
command line pointed out that the line was correctly ordered. After a bit of
debugging and instrumentation of gcc/plugin.c, it appeared that the
```htab_hash_plugin``` hash map get corrupted when the 11th plugin is loaded.
As it is created with 10 element by default, this should have been linked to
the hash table expansion.

After some unfruitful debugging of hashtab.c, Brad Spengler from grsecurity
(alias spender) identified the issue:
- htab_hash_plugin is populated with a custom structure, ```struct
plugin_name_args```, but is indexed with the plugin name
- the hash function to htab_create, htab_hash_string, expect a strings, which
will be the case with the insertions and queries made in plugin.c
- htab_expand recreates a new table, re-inserting each element using its hash.
However, the hash is applied to the whole structure, not only the plugin name!

As a result, after the hash table expansion, the entries are indexed with the
hash of the structure, while gcc/plugin.c will try to access them via the hash
of the plugin name only.

Brad quickly wrote a patch which define a proper hash function that can be
applied to the whole structure and which replace the incorrect htab_find_slot
calls by replacing the plugin name with the whole structure:
https://grsecurity.net/~spender/plugin_hash_fix.diff

I confirmed the bug on gcc 4.9.4 and 5.4.0 on gentoo-hardened. However, looking
at git, this code has not been touch and seems to be as old as the initial GCC
support. As a result, the fix would need to be backported to previous versions
of GC (GCC4.5+?).

I've written a reproducer:
https://gist.github.com/Feandil/55c104a4e9f5e6c72ce610b152ce37c3

To trigger the bug with this reproducer:
```
% make PLUGIN_NUMBER=10
g++ -shared -I/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.4/plugin/include -fPIC
-fno-rtti -O2 -std=gnu++98 -fvisibility=hidden basic_plugin.c -o
basic_plugin.so
cp basic_plugin.so basic_plugin_1.so
cp basic_plugin.so basic_plugin_2.so
cp basic_plugin.so basic_plugin_3.so
cp basic_plugin.so basic_plugin_4.so
cp basic_plugin.so basic_plugin_5.so
cp basic_plugin.so basic_plugin_6.so
cp basic_plugin.so basic_plugin_7.so
cp basic_plugin.so basic_plugin_8.so
cp basic_plugin.so basic_plugin_9.so
cp basic_plugin.so basic_plugin_10.so
gcc -fplugin=./basic_plugin_1.so -fplugin=./basic_plugin_2.so
-fplugin=./basic_plugin_3.so -fplugin=./basic_plugin_4.so
-fplugin=./basic_plugin_5.so -fplugin=./basic_plugin_6.so
-fplugin=./basic_plugin_7.so -fplugin=./basic_plugin_8.so
-fplugin=./basic_plugin_9.so -fplugin=./basic_plugin_10.so
-fplugin-arg-basic_plugin_1-enable empty.c -o empty
%  make PLUGIN_NUMBER=11
cp basic_plugin.so basic_plugin_11.so
gcc -fplugin=./basic_plugin_1.so -fplugin=./basic_plugin_2.so
-fplugin=./basic_plugin_3.so -fplugin=./basic_plugin_4.so
-fplugin=./basic_plugin_5.so -fplugin=./basic_plugin_6.so
-fplugin=./basic_plugin_7.so -fplugin=./basic_plugin_8.so
-fplugin=./basic_plugin_9.so -fplugin=./basic_plugin_10.so
-fplugin=./basic_plugin_11.so -fplugin-arg-basic_plugin_1-enable empty.c -o
empty
cc1: error: plugin basic_plugin_1 should be specified before
-fplugin-arg-basic_plugin_1-enable in the command line
(null):0: confused by earlier errors, bailing out
make: *** [Makefile:12: test] Error 1
```

Reply via email to