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 ```