Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libredirect: fix on darwin #144653

Merged
merged 2 commits into from
Nov 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkgs/build-support/libredirect/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ stdenv.mkDerivation rec {

install -vD "$libName" "$out/lib/$libName"

# Provide a setup hook that injects our library into every process.
mkdir -p "$hook/nix-support"
cat <<SETUP_HOOK > "$hook/nix-support/setup-hook"
${if stdenv.isDarwin then ''
export DYLD_INSERT_LIBRARIES="$out/lib/$libName"
export DYLD_FORCE_FLAT_NAMESPACE=1
'' else ''
export LD_PRELOAD="$out/lib/$libName"
''}
Expand Down
143 changes: 101 additions & 42 deletions pkgs/build-support/libredirect/libredirect.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/stat.h>
Expand All @@ -13,6 +14,22 @@

#define MAX_REDIRECTS 128

#ifdef __APPLE__
struct dyld_interpose {
const void * replacement;
const void * replacee;
};
#define WRAPPER(ret, name) static ret _libredirect_wrapper_##name
#define LOOKUP_REAL(name) &name
#define WRAPPER_DEF(name) \
__attribute__((used)) static struct dyld_interpose _libredirect_interpose_##name \
__attribute__((section("__DATA,__interpose"))) = { &_libredirect_wrapper_##name, &name };
#else
#define WRAPPER(ret, name) ret name
#define LOOKUP_REAL(name) dlsym(RTLD_NEXT, #name)
#define WRAPPER_DEF(name)
#endif

static int nrRedirects = 0;
static char * from[MAX_REDIRECTS];
static char * to[MAX_REDIRECTS];
Expand Down Expand Up @@ -80,9 +97,9 @@ static int open_needs_mode(int flags)
it contains only what we needed for programs in Nixpkgs. Just add
more functions as needed. */

int open(const char * path, int flags, ...)
WRAPPER(int, open)(const char * path, int flags, ...)
{
int (*open_real) (const char *, int, mode_t) = dlsym(RTLD_NEXT, "open");
int (*open_real) (const char *, int, mode_t) = LOOKUP_REAL(open);
mode_t mode = 0;
if (open_needs_mode(flags)) {
va_list ap;
Expand All @@ -93,10 +110,12 @@ int open(const char * path, int flags, ...)
char buf[PATH_MAX];
return open_real(rewrite(path, buf), flags, mode);
}
WRAPPER_DEF(open)

int open64(const char * path, int flags, ...)
#ifndef __APPLE__
WRAPPER(int, open64)(const char * path, int flags, ...)
{
int (*open64_real) (const char *, int, mode_t) = dlsym(RTLD_NEXT, "open64");
int (*open64_real) (const char *, int, mode_t) = LOOKUP_REAL(open64);
mode_t mode = 0;
if (open_needs_mode(flags)) {
va_list ap;
Expand All @@ -107,10 +126,12 @@ int open64(const char * path, int flags, ...)
char buf[PATH_MAX];
return open64_real(rewrite(path, buf), flags, mode);
}
WRAPPER_DEF(open64)
#endif

int openat(int dirfd, const char * path, int flags, ...)
WRAPPER(int, openat)(int dirfd, const char * path, int flags, ...)
{
int (*openat_real) (int, const char *, int, mode_t) = dlsym(RTLD_NEXT, "openat");
int (*openat_real) (int, const char *, int, mode_t) = LOOKUP_REAL(openat);
mode_t mode = 0;
if (open_needs_mode(flags)) {
va_list ap;
Expand All @@ -121,114 +142,136 @@ int openat(int dirfd, const char * path, int flags, ...)
char buf[PATH_MAX];
return openat_real(dirfd, rewrite(path, buf), flags, mode);
}
WRAPPER_DEF(openat)

FILE * fopen(const char * path, const char * mode)
WRAPPER(FILE *, fopen)(const char * path, const char * mode)
{
FILE * (*fopen_real) (const char *, const char *) = dlsym(RTLD_NEXT, "fopen");
FILE * (*fopen_real) (const char *, const char *) = LOOKUP_REAL(fopen);
char buf[PATH_MAX];
return fopen_real(rewrite(path, buf), mode);
}
WRAPPER_DEF(fopen)

FILE * __nss_files_fopen(const char * path)
#ifndef __APPLE__
WRAPPER(FILE *, __nss_files_fopen)(const char * path)
{
FILE * (*__nss_files_fopen_real) (const char *) = dlsym(RTLD_NEXT, "__nss_files_fopen");
FILE * (*__nss_files_fopen_real) (const char *) = LOOKUP_REAL(__nss_files_fopen);
char buf[PATH_MAX];
return __nss_files_fopen_real(rewrite(path, buf));
}
WRAPPER_DEF(__nss_files_fopen)
#endif

FILE * fopen64(const char * path, const char * mode)
#ifndef __APPLE__
WRAPPER(FILE *, fopen64)(const char * path, const char * mode)
{
FILE * (*fopen64_real) (const char *, const char *) = dlsym(RTLD_NEXT, "fopen64");
FILE * (*fopen64_real) (const char *, const char *) = LOOKUP_REAL(fopen64);
char buf[PATH_MAX];
return fopen64_real(rewrite(path, buf), mode);
}
WRAPPER_DEF(fopen64)
#endif

int __xstat(int ver, const char * path, struct stat * st)
#ifndef __APPLE__
WRAPPER(int, __xstat)(int ver, const char * path, struct stat * st)
{
int (*__xstat_real) (int ver, const char *, struct stat *) = dlsym(RTLD_NEXT, "__xstat");
int (*__xstat_real) (int ver, const char *, struct stat *) = LOOKUP_REAL(__xstat);
char buf[PATH_MAX];
return __xstat_real(ver, rewrite(path, buf), st);
}
WRAPPER_DEF(__xstat)
#endif

int __xstat64(int ver, const char * path, struct stat64 * st)
#ifndef __APPLE__
WRAPPER(int, __xstat64)(int ver, const char * path, struct stat64 * st)
{
int (*__xstat64_real) (int ver, const char *, struct stat64 *) = dlsym(RTLD_NEXT, "__xstat64");
int (*__xstat64_real) (int ver, const char *, struct stat64 *) = LOOKUP_REAL(__xstat64);
char buf[PATH_MAX];
return __xstat64_real(ver, rewrite(path, buf), st);
}
WRAPPER_DEF(__xstat64)
#endif

int stat(const char * path, struct stat * st)
WRAPPER(int, stat)(const char * path, struct stat * st)
{
int (*__stat_real) (const char *, struct stat *) = dlsym(RTLD_NEXT, "stat");
int (*__stat_real) (const char *, struct stat *) = LOOKUP_REAL(stat);
char buf[PATH_MAX];
return __stat_real(rewrite(path, buf), st);
}
WRAPPER_DEF(stat)

int access(const char * path, int mode)
WRAPPER(int, access)(const char * path, int mode)
{
int (*access_real) (const char *, int mode) = dlsym(RTLD_NEXT, "access");
int (*access_real) (const char *, int mode) = LOOKUP_REAL(access);
char buf[PATH_MAX];
return access_real(rewrite(path, buf), mode);
}
WRAPPER_DEF(access)

int posix_spawn(pid_t * pid, const char * path,
WRAPPER(int, posix_spawn)(pid_t * pid, const char * path,
const posix_spawn_file_actions_t * file_actions,
const posix_spawnattr_t * attrp,
char * const argv[], char * const envp[])
{
int (*posix_spawn_real) (pid_t *, const char *,
const posix_spawn_file_actions_t *,
const posix_spawnattr_t *,
char * const argv[], char * const envp[]) = dlsym(RTLD_NEXT, "posix_spawn");
char * const argv[], char * const envp[]) = LOOKUP_REAL(posix_spawn);
char buf[PATH_MAX];
return posix_spawn_real(pid, rewrite(path, buf), file_actions, attrp, argv, envp);
}
WRAPPER_DEF(posix_spawn)

int posix_spawnp(pid_t * pid, const char * file,
WRAPPER(int, posix_spawnp)(pid_t * pid, const char * file,
const posix_spawn_file_actions_t * file_actions,
const posix_spawnattr_t * attrp,
char * const argv[], char * const envp[])
{
int (*posix_spawnp_real) (pid_t *, const char *,
const posix_spawn_file_actions_t *,
const posix_spawnattr_t *,
char * const argv[], char * const envp[]) = dlsym(RTLD_NEXT, "posix_spawnp");
char * const argv[], char * const envp[]) = LOOKUP_REAL(posix_spawnp);
char buf[PATH_MAX];
return posix_spawnp_real(pid, rewrite(file, buf), file_actions, attrp, argv, envp);
}
WRAPPER_DEF(posix_spawnp)

int execv(const char * path, char * const argv[])
WRAPPER(int, execv)(const char * path, char * const argv[])
{
int (*execv_real) (const char * path, char * const argv[]) = dlsym(RTLD_NEXT, "execv");
int (*execv_real) (const char * path, char * const argv[]) = LOOKUP_REAL(execv);
char buf[PATH_MAX];
return execv_real(rewrite(path, buf), argv);
}
WRAPPER_DEF(execv)

int execvp(const char * path, char * const argv[])
WRAPPER(int, execvp)(const char * path, char * const argv[])
{
int (*_execvp) (const char *, char * const argv[]) = dlsym(RTLD_NEXT, "execvp");
int (*_execvp) (const char *, char * const argv[]) = LOOKUP_REAL(execvp);
char buf[PATH_MAX];
return _execvp(rewrite(path, buf), argv);
}
WRAPPER_DEF(execvp)

int execve(const char * path, char * const argv[], char * const envp[])
WRAPPER(int, execve)(const char * path, char * const argv[], char * const envp[])
{
int (*_execve) (const char *, char * const argv[], char * const envp[]) = dlsym(RTLD_NEXT, "execve");
int (*_execve) (const char *, char * const argv[], char * const envp[]) = LOOKUP_REAL(execve);
char buf[PATH_MAX];
return _execve(rewrite(path, buf), argv, envp);
}
WRAPPER_DEF(execve)

DIR * opendir(const char * path)
WRAPPER(DIR *, opendir)(const char * path)
{
char buf[PATH_MAX];
DIR * (*_opendir) (const char*) = dlsym(RTLD_NEXT, "opendir");
DIR * (*_opendir) (const char*) = LOOKUP_REAL(opendir);

return _opendir(rewrite(path, buf));
}
WRAPPER_DEF(opendir)

#define SYSTEM_CMD_MAX 512

char *replace_substring(char * source, char * buf, char * replace_string, char * start_ptr, char * suffix_ptr) {
static char * replace_substring(char * source, char * buf, char * replace_string, char * start_ptr, char * suffix_ptr) {
char head[SYSTEM_CMD_MAX] = {0};
strncpy(head, source, start_ptr - source);

Expand All @@ -241,7 +284,7 @@ char *replace_substring(char * source, char * buf, char * replace_string, char *
return buf;
}

char *replace_string(char * buf, char * from, char * to) {
static char * replace_string(char * buf, char * from, char * to) {
int num_matches = 0;
char * matches[SYSTEM_CMD_MAX];
int from_len = strlen(from);
Expand All @@ -264,32 +307,48 @@ char *replace_string(char * buf, char * from, char * to) {
return buf;
}

void rewriteSystemCall(const char * command, char * buf) {
strcpy(buf, command);
static void rewriteSystemCall(const char * command, char * buf) {
char * p = buf;

#ifdef __APPLE__
// The dyld environment variable is not inherited by the subprocess spawned
// by system(), so this hack redefines it.
Dl_info info;
dladdr(&rewriteSystemCall, &info);
p = stpcpy(p, "export DYLD_INSERT_LIBRARIES=");
p = stpcpy(p, info.dli_fname);
p = stpcpy(p, ";");
#endif

stpcpy(p, command);

for (int n = 0; n < nrRedirects; ++n) {
replace_string(buf, from[n], to[n]);
}
}

int system(const char *command)
WRAPPER(int, system)(const char *command)
{
int (*_system) (const char*) = dlsym(RTLD_NEXT, "system");
int (*_system) (const char*) = LOOKUP_REAL(system);

char newCommand[SYSTEM_CMD_MAX];
rewriteSystemCall(command, newCommand);
return _system(newCommand);
}
WRAPPER_DEF(system)

int mkdir(const char *path, mode_t mode)
WRAPPER(int, mkdir)(const char *path, mode_t mode)
{
int (*mkdir_real) (const char *path, mode_t mode) = dlsym(RTLD_NEXT, "mkdir");
int (*mkdir_real) (const char *path, mode_t mode) = LOOKUP_REAL(mkdir);
char buf[PATH_MAX];
return mkdir_real(rewrite(path, buf), mode);
}
WRAPPER_DEF(mkdir)

int mkdirat(int dirfd, const char *path, mode_t mode)
WRAPPER(int, mkdirat)(int dirfd, const char *path, mode_t mode)
{
int (*mkdirat_real) (int dirfd, const char *path, mode_t mode) = dlsym(RTLD_NEXT, "mkdirat");
int (*mkdirat_real) (int dirfd, const char *path, mode_t mode) = LOOKUP_REAL(mkdirat);
char buf[PATH_MAX];
return mkdirat_real(dirfd, rewrite(path, buf), mode);
}
WRAPPER_DEF(mkdirat)