main: Correct the pointer value of strtab on riscv/mips architectures
Glibc defines `d_ptr`/`d_val` to be a relocated address on most architectures, except for riscv and mips where it is just an offset from the binary load address. So we need to convert `strtab` from an offset into a pointer for riscv and mips. Internally within glibc there is the `D_PTR` macro for doing this, which relies on private data hidden in an ABI-unstable part of `link_map`. So we can't use the same conditional logic as glibc does internally. Our solution is to detect when `strtab` is unreasonably low (below the address of our binary) and so it must be an unrelocated offset. In that case we just do the relocation manually. Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/6528 Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2718>
This commit is contained in:
parent
a95addd772
commit
65cde18786
20
src/main.c
20
src/main.c
@ -1,5 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (HAVE_MALLINFO) || defined (HAVE_MALLINFO2)
|
||||
@ -20,6 +22,7 @@
|
||||
#include <link.h>
|
||||
|
||||
#ifdef HAVE_EXE_INTROSPECTION
|
||||
#include <dlfcn.h>
|
||||
#include <elf.h>
|
||||
#endif
|
||||
|
||||
@ -140,6 +143,8 @@ maybe_add_rpath_introspection_paths (void)
|
||||
g_auto (GStrv) paths = NULL;
|
||||
g_autofree char *exe_dir = NULL;
|
||||
GStrv str;
|
||||
Dl_info dl_info;
|
||||
struct link_map *link_map = NULL;
|
||||
|
||||
for (dyn = _DYNAMIC; dyn->d_tag != DT_NULL; dyn++)
|
||||
{
|
||||
@ -154,6 +159,21 @@ maybe_add_rpath_introspection_paths (void)
|
||||
if ((!rpath && !runpath) || !strtab)
|
||||
return;
|
||||
|
||||
if (dladdr1 (_DYNAMIC, &dl_info, (void **) &link_map, RTLD_DL_LINKMAP))
|
||||
{
|
||||
/* Sanity check */
|
||||
g_return_if_fail ((void *) _DYNAMIC == (void *) link_map->l_ld);
|
||||
|
||||
/* strtab should be at an offset above our load address. If it's not
|
||||
* then this is a special architecture (riscv, mips) that has a
|
||||
* readonly _DYNAMIC section that's not relocated. So in that case
|
||||
* strtab is currently an offset rather than an address. Let's make it
|
||||
* an address...
|
||||
*/
|
||||
if (strtab < (const char *) link_map->l_addr)
|
||||
strtab += link_map->l_addr;
|
||||
}
|
||||
|
||||
if (rpath)
|
||||
paths = g_strsplit (strtab + rpath->d_un.d_val, ":", -1);
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user