Skip to content

[asan] With asan, dlopen is interposed, breaking RUNPATH resolution #1783

@stellaraccident

Description

@stellaraccident

Per the dlopen manpage, the RUNPATH calculation is based on the calling DSO:

       •  (ELF only) If the calling object (i.e., the shared library or executable from which dlopen() is called) contains a DT_RPATH tag, and does not contain a DT_RUNPATH tag, then the directories listed in the DT_RPATH tag are searched.
       •  If, at the time that the program was started, the environment variable LD_LIBRARY_PATH was defined to contain a colon-separated list of directories, then these are searched.  (As a security measure, this variable is ignored for set-user-ID and set-group-ID programs.)
       •  (ELF only) If the calling object contains a DT_RUNPATH tag, then the directories listed in that tag are searched.
       •  The cache file /etc/ld.so.cache (maintained by ldconfig(8)) is checked to see whether it contains an entry for filename.
       •  The directories /lib and /usr/lib are searched (in that order).

However, ASAN interposes its own implementation of dlopen, making itself the caller from the perspective of the underlying implementation. This causes all corresponding dlopen RUNPATH resolution to break. Not even the outer executable's RUNPATH is consulted -- only the system.

Several places in ROCm require the correct behavior and will fail at runtime with ASAN enabled. We will need to patch each one with some approach:

Bypass ASAN's implementation (courtesy of ChatGPT)

#include <dlfcn.h>

static void *real_dlopen_(const char *file, int mode) {
  typedef void *(*dlopen_fn)(const char *, int);
  static dlopen_fn real_dlopen;
  if (!real_dlopen) {
    real_dlopen = (dlopen_fn)dlsym(RTLD_NEXT, "dlopen"); // skip libasan
  }
  return real_dlopen(file, mode);
}

// use real_dlopen_(...) instead of dlopen(...)

Self locate

#include <dlfcn.h>
#include <libgen.h>

static void *dlopen_from_my_dir(const char *soname, int mode) {
  Dl_info di;
  if (dladdr((void*)&dlopen_from_my_dir, &di) && di.dli_fname) {
    char path[PATH_MAX];
    snprintf(path, sizeof(path), "%s/../lib/%s", dirname((char*)di.dli_fname), soname);
    return dlopen(path, mode);
  }
  return dlopen(soname, mode); // fallback
}

This will fail in all cases that ASAN is activated for the process, even if ROCm is not built with any ASAN enabled.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    TODO

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions