Bug #6303

dln_load and rb_w32_check_imported cause segfault in Ruby 1.9.3 for some extension

Added by Luis Lavena about 2 years ago. Updated over 1 year ago.

[ruby-core:44371]
Status:Closed
Priority:Normal
Assignee:Nobuyoshi Nakada
Category:core
Target version:1.9.3
ruby -v:1.9.3 Backport:

Description

Hello,

NOTE: Reporting this here since bugs.ruby-lang.org seems to be down.

Recently a user reported to RubyInstaller project issues when loading
a Ruby 1.9.2 compiled extension under Ruby 1.9.3:

https://groups.google.com/d/msg/rubyinstaller/aSezE2LwfQs/TDZvPG3X5mUJ

Which I was able to study a bit better:
https://groups.google.com/d/msg/rubyinstaller/aSezE2LwfQs/UGKlButpNfMJ

To add more, my last comment was:

"Is worth to mention that this do not fail against 1.9.2 (either
building or running) but dln_load mechanism on Ruby 1.9.2 differs from
Ruby 1.9.3 and highly unlikely is going to change."

I'm not convinced by my last comment and I do believe this is a bug.
db2cli.dll links to MSVCR80 and even so, it loads properly under
1.9.2.

Looking closely to what rbw32check_imported does, it is supposed to
verify that the extension being loaded it is indeed using the right
ruby dll.

But is failing to obtain Name from pii (PIMAGEIMPORTBY_NAME struct)

I can't find any reference to dbghelp (which provides
ImageDirectoryEntryToData) being included or linked in
msvcrt-libruby191.dll

For sure I'm missing something, specially why is failing to obtain
this extension information when works for others.

Thank you.
--
Luis Lavena
AREA 17
-
Perfection in design is achieved not when there is nothing more to add,
but rather when there is nothing more to take away.
Antoine de Saint-Exupéry

Associated revisions

Revision 35352
Added by Nobuyoshi Nakada about 2 years ago

  • dln.c (rbw32check_imported): skip ordinal entries. patched by phasis68 (Heesob Park) at . [Bug #6303]

Revision 35354
Added by Nobuyoshi Nakada about 2 years ago

  • dln.c (rbw32check_imported): skip ordinal entries. based on a patch by phasis68 (Heesob Park) at . [Bug #6303]

History

#1 Updated by Heesob Park about 2 years ago

The segfault is due to the invalid pointer reference in getting PIMAGEIMPORTBY_NAME pointer like this:

PIMAGEIMPORTBYNAME pii = (PIMAGEIMPORTBYNAME)((char *)ext + (size_t)pint->u1.AddressOfData);

Consider the following imports dump list of ibm_db.so

DB2CLI.dll
          63317274 Import Address Table
          63317078 Import Name Table
                 0 time date stamp
                 0 Index of first forwarder reference

                  Ordinal  1300
                  Ordinal  1301
               6C SQLDriverConnectW@32
               52 SQLConnectW@28
                  Ordinal     9
                  Ordinal  1303
                  Ordinal    58
               64 SQLDescribeColW@36
                  Ordinal     4
               4A SQLColumnPrivilegesW@36
               4E SQLColumnsW@36
               FB SQLPrimaryKeysW@28
               98 SQLForeignKeysW@52
               FF SQLProcedureColumnsW@36
              103 SQLProceduresW@28
              133 SQLSpecialColumnsW@40
              137 SQLStatisticsW@36
              13B SQLTablePrivilegesW@28
              13F SQLTablesW@36
               7A SQLExecDirectW@12
               F7 SQLPrepareW@12

...

As you can see, the name table entry has two types: ordinal type and name type.
But, the rbw32check_imported function overlooked ordinal case.

Refer to http://nienie.com/~masapico/api_ImageDirectoryEntryToData.html

Here is a patch:

diff --git a/dln.c b/dln.c.new
index e3dff9b..58042e1 100644
--- a/dln.c
+++ b/dln.c.new
@@ -1215,12 +1215,14 @@ rbw32checkimported(HMODULE ext, HMODULE mine)
PIMAGE
THUNKDATA pint = (PIMAGETHUNKDATA)((char *)ext + desc->Characteristics);
PIMAGE
THUNKDATA piat = (PIMAGETHUNKDATA)((char *)ext + desc->FirstThunk);
while (piat->u1.Function) {
- PIMAGE
IMPORTBYNAME pii = (PIMAGEIMPORTBYNAME)((char *)ext + (sizet)pint->u1.AddressOfData);
- static const char prefix[] = "rb";
- const char *name = (const char *)pii->Name;
- if (strncmp(name, prefix, sizeof(prefix) - 1) == 0) {
- FARPROC addr = GetProcAddress(mine, name);
- if (addr) return (FARPROC)piat->u1.Function == addr;
+ if(!IMAGE
SNAPBYORDINAL(pint->u1.Ordinal)) {
+ PIMAGEIMPORTBYNAME pii = (PIMAGEIMPORTBYNAME)((char *)ext + (sizet)pint->u1.AddressOfData);
+ static const char prefix[] = "rb
";
+ const char *name = (const char *)pii->Name;
+ if (strncmp(name, prefix, sizeof(prefix) - 1) == 0) {
+ FARPROC addr = GetProcAddress(mine, name);
+ if (addr) return (FARPROC)piat->u1.Function == addr;
+ }
}
piat++;
pint++;

#2 Updated by Nobuyoshi Nakada about 2 years ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r35352.
Luis, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


  • dln.c (rbw32check_imported): skip ordinal entries. patched by phasis68 (Heesob Park) at . [Bug #6303]

#3 Updated by Heesob Park about 2 years ago

The changeset r35352 is not same to my patch and the bug #6303 is not fixed.

After applying r35352,
require 'mswin32/ibm_db'
falls into infinite loop and runs forever.

The line
if (IMAGESNAPBY_ORDINAL(pint->u1.Ordinal)) continue;

should be

if (IMAGESNAPBY_ORDINAL(pint->u1.Ordinal)) {pint++;piat++;continue;}

#4 Updated by Luis Lavena about 2 years ago

  • Category set to core
  • Status changed from Closed to Assigned
  • Assignee set to Nobuyoshi Nakada
  • Target version set to 1.9.3
  • % Done changed from 100 to 80
  • ruby -v set to 1.9.3

#5 Updated by Nobuyoshi Nakada about 2 years ago

  • Status changed from Assigned to Closed
  • % Done changed from 80 to 100

This issue was solved with changeset r35354.
Luis, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


  • dln.c (rbw32check_imported): skip ordinal entries. based on a patch by phasis68 (Heesob Park) at . [Bug #6303]

Also available in: Atom PDF