Skip to content

RFC: Rename visible libmagic symbols#21472

Open
orlitzky wants to merge 3 commits intophp:masterfrom
orlitzky:rename-libmagic-symbols
Open

RFC: Rename visible libmagic symbols#21472
orlitzky wants to merge 3 commits intophp:masterfrom
orlitzky:rename-libmagic-symbols

Conversation

@orlitzky
Copy link
Contributor

Trying my hand at a very old problem (PHP bug 66095, Gentoo bug 471682, FreeBSD bug 195562)

The bundled libmagic for the fileinfo extension has some visible symbols:

$ objdump -TC /usr/lib/php8.5/apache2/libphp8.so | grep '\smagic_'
00000000002b3f34 g    DF .text	0000000000000034  Base        magic_compile
00000000002b3dde g    DF .text	0000000000000024  Base        magic_open
00000000002b3fd0 g    DF .text	0000000000000034  Base        magic_descriptor
00000000002b3f00 g    DF .text	0000000000000034  Base        magic_load
00000000002b43fa g    DF .text	0000000000000032  Base        magic_setflags
00000000002b3f9c g    DF .text	0000000000000034  Base        magic_list
00000000002b4442 g    DF .text	0000000000000206  Base        magic_setparam
00000000002b43d4 g    DF .text	0000000000000026  Base        magic_getflags
00000000002b439e g    DF .text	0000000000000036  Base        magic_errno
00000000002b4648 g    DF .text	00000000000001f4  Base        magic_getparam
00000000002b42f4 g    DF .text	000000000000006e  Base        magic_buffer
00000000002b4362 g    DF .text	000000000000003c  Base        magic_error
00000000002b3f68 g    DF .text	0000000000000034  Base        magic_check
00000000002b442c g    DF .text	0000000000000016  Base        magic_version
00000000002b3eda g    DF .text	0000000000000026  Base        magic_close
00000000002b4038 g    DF .text	0000000000000034  Base        magic_stream
00000000002b4004 g    DF .text	0000000000000034  Base        magic_file

This works fine until you load that shared library into a process that links against the system libmagic, providing (in many cases, different versions of) the same symbols. I hit this myself several years ago when using another apache module that linked against libmagic. I can't cite any bug reports for the embed SAPI, but there is every reason to suspect that it suffers from the same issue.

A fix was proposed on PHP bug 66095, but given how few problematic symbols there are, I think that it's easier to just rename them. I used find/sed and then checked the diff -- it was actually quite short. We can see the new names (the embed SAPI, in this case):

$ objdump -TC ./libs/libphp.so | grep php_magic
0000000000183aee g    DF .text	0000000000000036 php_magic_errno
0000000000183a44 g    DF .text	000000000000006e php_magic_buffer
0000000000183ab2 g    DF .text	000000000000003c php_magic_error
00000000001836b8 g    DF .text	0000000000000034 php_magic_check
0000000000183b7c g    DF .text	0000000000000016 php_magic_version
000000000018362a g    DF .text	0000000000000026 php_magic_close
0000000000183754 g    DF .text	0000000000000034 php_magic_file
0000000000183684 g    DF .text	0000000000000034 php_magic_compile
0000000000183788 g    DF .text	0000000000000034 php_magic_stream
0000000000183b4a g    DF .text	0000000000000032 php_magic_setflags
0000000000183720 g    DF .text	0000000000000034 php_magic_descriptor
0000000000183b92 g    DF .text	0000000000000206 php_magic_setparam
0000000000183b24 g    DF .text	0000000000000026 php_magic_getflags
000000000018352e g    DF .text	0000000000000024 php_magic_open
0000000000183d98 g    DF .text	00000000000001f4 php_magic_getparam
0000000000183650 g    DF .text	0000000000000034 php_magic_load
00000000001836ec g    DF .text	0000000000000034 php_magic_list

The strcasestr() commit is unrelated to an extent. I noticed (grep) that the only use of strcasestr() in libmagic is patched out by PHP, so there is no need for it on any platform. The -DHAVE_STRCASESTR=1 simply ensures that libmagic does not try to prototype it.

It remains to construct a failing example, and check that the PR actually fixes it.

This function isn't used, but it is declared in file.h, and that can
lead to conflicts if the system also provides it. If we define
HAVE_STRCASESTR=1, though, the declaration in file.h is skipped. We no
longer need to compile libmagic/strcasestr.c in any case.
When libphp.so (from the embed SAPI, or the apache module) is loaded
by another project that already uses libmagic, the symbols from the
two copies of libmagic can clash.

To avoid this, we prefix the public functions provided by the
bundled libmagic with "php_":

  $ objdump -TC ./libs/libphp.so | grep php_magic
  00000000002505ae g   DF .text  0000000000000036 php_magic_errno
  0000000000250504 g   DF .text  000000000000006e php_magic_buffer
  0000000000250572 g   DF .text  000000000000003c php_magic_error
  0000000000250178 g   DF .text  0000000000000034 php_magic_check
  000000000025063c g   DF .text  0000000000000016 php_magic_version
  00000000002500ea g   DF .text  0000000000000026 php_magic_close
  0000000000250214 g   DF .text  0000000000000034 php_magic_file
  0000000000250144 g   DF .text  0000000000000034 php_magic_compile
  0000000000250248 g   DF .text  0000000000000034 php_magic_stream
  000000000025060a g   DF .text  0000000000000032 php_magic_setflags
  00000000002501e0 g   DF .text  0000000000000034 php_magic_descriptor
  0000000000250652 g   DF .text  0000000000000206 php_magic_setparam
  00000000002505e4 g   DF .text  0000000000000026 php_magic_getflags
  000000000024ffee g   DF .text  0000000000000024 php_magic_open
  0000000000250858 g   DF .text  00000000000001f4 php_magic_getparam
  0000000000250110 g   DF .text  0000000000000034 php_magic_load
  00000000002501ac g   DF .text  0000000000000034 php_magic_list

This should avoid conflicts with other libraries that link against the
system copy of libmagic (taking a random example from my machine):

  $ objdump -TC /usr/lib/libmtp-ng.so.4.5 | grep magic
  0000000000000000  DF *UND*  0000000000000000  Base  magic_load
  0000000000000000  DF *UND*  0000000000000000  Base  magic_file
  0000000000000000  DF *UND*  0000000000000000  Base  magic_open
  0000000000000000  DF *UND*  0000000000000000  Base  magic_close

PHP-bug: https://bugs.php.net/bug.php?id=66095
Gentoo-bug: https://bugs.gentoo.org/471682
Run ext/fileinfo/generate_patch.sh to update PHP's patch against
file-5.46. The diff of the diff is mostly timestamps, but it does
include the recent addition of the "php_" prefix to the public
libmagic functions.
@orlitzky
Copy link
Contributor Author

Linking of the embed SAPI looks borked on master, but if I hack these patches onto the PHP-8.5 branch, pointlessly linking the embed SAPI into a small libmagic example induces the problem:

/* main.c */
#include <magic.h>
#include <stdio.h>

int main(int argc, char **argv)
{
  char *actual_file = "example.pdf";
  const char *magic_full;
  magic_t magic_cookie;

  magic_cookie = magic_open(MAGIC_MIME);
  if (magic_cookie == NULL) {
    printf("unable to initialize magic library\n");
    return 1;
  }

  printf("Loading default magic database...\n");
  if (magic_load(magic_cookie, "/usr/share/misc/magic.mgc") != 0) {
    printf("cannot load magic database - %s\n", magic_error(magic_cookie));
    magic_close(magic_cookie);
    return 1;
  }

  magic_full = magic_file(magic_cookie, actual_file);
  printf("libmagic answer: %s\n", magic_full);
  magic_close(magic_cookie);
  return 0;
}

Before the PR (my system copy of php-8.5):

$ gcc $(/usr/lib/php8.5/bin/php-config --includes) main.c -L/usr/lib/php8.5/lib -lphp -lmagic
$ LD_LIBRARY_PATH=/usr/lib/php8.5/lib ./a.out 
Segmentation fault         LD_LIBRARY_PATH=/usr/lib/php8.5/lib ./a.out

And the one I just built and installed to ~/tmp/php:

$ gcc $(/home/mjo/tmp/php/bin/php-config --includes) main.c -L/home/mjo/tmp/php/lib -lphp -lmagic
$ LD_LIBRARY_PATH=/home/mjo/tmp/php/lib ./a.out 
Loading default magic database...
libmagic answer: application/pdf; charset=binary

@orlitzky
Copy link
Contributor Author

(example.pdf is a random PDF on my machine)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant