Skip to content

Commit

Permalink
Do not interpose functions before initialization
Browse files Browse the repository at this point in the history
Static initializers have no defined order in which they are run;
interposed functions, however, take effect at program initialization. In
some cases, our interposed functions would be called by libSystem's
constructors and prior to *our* constructors, and this would lead to
crashes in trace mode as we would be in an uninitialized state. All our
interposers now immediately delegate to their interposees until the are
sure initialization has been performed.

Closes: https://trac.macports.org/ticket/60702
  • Loading branch information
saagarjha authored and neverpanic committed Jun 28, 2020
1 parent 62e0767 commit d96e5a8
Show file tree
Hide file tree
Showing 14 changed files with 120 additions and 5 deletions.
4 changes: 4 additions & 0 deletions src/darwintracelib1.0/access.c
Expand Up @@ -39,6 +39,10 @@
#include <unistd.h>

static int _dt_access(const char *path, int amode) {
if (!__darwintrace_initialized) {
return access(path, amode);
}

__darwintrace_setup();

int result = 0;
Expand Down
4 changes: 4 additions & 0 deletions src/darwintracelib1.0/close.c
Expand Up @@ -48,6 +48,10 @@
* will be set to the FD to be closed when closing should be allowed.
*/
static int _dt_close(int fd) {
if (!__darwintrace_initialized) {
return close(fd);
}

__darwintrace_setup();

FILE *stream = __darwintrace_sock();
Expand Down
24 changes: 22 additions & 2 deletions src/darwintracelib1.0/darwintrace.c
Expand Up @@ -88,7 +88,6 @@ volatile int __darwintrace_close_sock = -1;
FILE *__darwintrace_stderr = NULL;

static inline void __darwintrace_log_op(const char *op, const char *path);
static void __darwintrace_setup_tls() __attribute__((constructor));
static char *__send(const char *buf, uint32_t len, int answer);

/**
Expand Down Expand Up @@ -121,6 +120,27 @@ static _Atomic(char *) filemap;
static char *filemap;
#endif


volatile bool __darwintrace_initialized = false;

/**
* "Constructors" we'd like to run before we do anything. As using
* __attribute__((constructor)) for these would be unsafe here (as our
* interposed functions might end up being called first) we'll run them manually
* before we interpose anything.
*/
static void (*constructors[])() = {
__darwintrace_setup_tls,
__darwintrace_store_env,
};

void __darwintrace_run_constructors() {
for (size_t i = 0; i < sizeof(constructors) / sizeof(*constructors); ++i) {
constructors[i]();
}
__darwintrace_initialized = true;
}

static void __darwintrace_sock_destructor(FILE *dtsock) {
__darwintrace_close_sock = fileno(dtsock);
fclose(dtsock);
Expand All @@ -132,7 +152,7 @@ static void __darwintrace_sock_destructor(FILE *dtsock) {
* Setup method called as constructor to set up thread-local storage for the
* thread id and the darwintrace socket.
*/
static void __darwintrace_setup_tls() {
void __darwintrace_setup_tls() {
if (0 != (errno = pthread_key_create(&tid_key, NULL))) {
perror("darwintrace: pthread_key_create");
abort();
Expand Down
24 changes: 24 additions & 0 deletions src/darwintracelib1.0/darwintrace.h
Expand Up @@ -130,6 +130,12 @@ void __darwintrace_close();
*/
bool __darwintrace_is_in_sandbox(const char *path, int flags);

/**
* Whether darwintrace has been fully initialized or not. Do not interpose if
* this has not been set to true.
*/
volatile bool __darwintrace_initialized;

#ifdef DARWINTRACE_USE_PRIVATE_API
#include <errno.h>
#include <stdlib.h>
Expand Down Expand Up @@ -182,4 +188,22 @@ static inline void __darwintrace_sock_set(FILE *stream) {
abort();
}
}

/**
* Initialize TLS variables.
*/
void __darwintrace_setup_tls();

/**
* Grab environment variables at startup.
*/
void __darwintrace_store_env();

/**
* Runs our "constructors". By this point all of the system libraries we link
* against should be fully initialized, so we can call their functions safely.
* Once our initialization is complete we may begin interposing.
*/
void __darwintrace_run_constructors() __attribute__((constructor));

#endif /* defined(DARWINTRACE_USE_PRIVATE_API) */
4 changes: 4 additions & 0 deletions src/darwintracelib1.0/dup2.c
Expand Up @@ -46,6 +46,10 @@
* FDs are numbered in ascending order.
*/
static int _dt_dup2(int filedes, int filedes2) {
if (!__darwintrace_initialized) {
return dup2(filedes, filedes2);
}

__darwintrace_setup();

FILE *stream = __darwintrace_sock();
Expand Down
4 changes: 4 additions & 0 deletions src/darwintracelib1.0/mkdir.c
Expand Up @@ -51,6 +51,10 @@
* outside the sandbox that already exist.
*/
static int _dt_mkdir(const char *path, mode_t mode) {
if (!__darwintrace_initialized) {
return mkdir(path, mode);
}

__darwintrace_setup();

int result = 0;
Expand Down
9 changes: 9 additions & 0 deletions src/darwintracelib1.0/open.c
Expand Up @@ -46,6 +46,15 @@
* when attempting to create a file, i.e., when \c O_CREAT is set.
*/
static int _dt_open(const char *path, int flags, ...) {
if (!__darwintrace_initialized) {
va_list args;
va_start(args, flags);
mode_t mode = va_arg(args, int);
va_end(args);

return open(path, flags, mode);
}

__darwintrace_setup();
int result = 0;

Expand Down
12 changes: 9 additions & 3 deletions src/darwintracelib1.0/proc.c
Expand Up @@ -52,8 +52,6 @@
#include <spawn.h>
#endif

static void store_env() __attribute__((constructor));

/**
* Copy of the DYLD_INSERT_LIBRARIES environment variable to restore it in
* execve(2). DYLD_INSERT_LIBRARIES is needed to preload this library into any
Expand Down Expand Up @@ -83,7 +81,7 @@ static char *__env_full_darwintrace_log;
* Copy the environment variables, if they're defined. This is run as
* a constructor at startup.
*/
static void store_env() {
void __darwintrace_store_env() {
#define COPYENV(name, variable, valuevar) do {\
char *val;\
if (NULL != (val = getenv(#name))) {\
Expand Down Expand Up @@ -249,6 +247,10 @@ static inline int check_interpreter(const char *restrict path) {
* using \c check_interpreter.
*/
static int _dt_execve(const char *path, char *const argv[], char *const envp[]) {
if (!__darwintrace_initialized) {
return execve(path, argv, envp);
}

__darwintrace_setup();

int result = 0;
Expand Down Expand Up @@ -291,6 +293,10 @@ DARWINTRACE_INTERPOSE(_dt_execve, execve);
*/
static int _dt_posix_spawn(pid_t *restrict pid, const char *restrict path, const posix_spawn_file_actions_t *file_actions,
const posix_spawnattr_t *restrict attrp, char *const argv[restrict], char *const envp[restrict]) {
if (!__darwintrace_initialized) {
return posix_spawn(pid, path, file_actions, attrp, argv, envp);
}

__darwintrace_setup();

int result = 0;
Expand Down
8 changes: 8 additions & 0 deletions src/darwintracelib1.0/readdir.c
Expand Up @@ -67,6 +67,10 @@ struct dirent64 {
size_t __getdirentries64(int fd, void *buf, size_t bufsize, __darwin_off_t *basep);

static size_t _dt_getdirentries64(int fd, void *buf, size_t bufsize, __darwin_off_t *basep) {
if (!__darwintrace_initialized) {
return __getdirentries64(fd, buf, bufsize, basep);
}

__darwintrace_setup();

size_t sz = __getdirentries64(fd, buf, bufsize, basep);
Expand Down Expand Up @@ -123,6 +127,10 @@ struct dirent32 {
int getdirentries(int fd, char *buf, int nbytes, long *basep);

static int _dt_getdirentries(int fd, char *buf, int nbytes, long *basep) {
if (!__darwintrace_initialized) {
return getdirentries(fd, buf, nbytes, basep);
}

__darwintrace_setup();

size_t sz = getdirentries(fd, buf, nbytes, basep);
Expand Down
4 changes: 4 additions & 0 deletions src/darwintracelib1.0/readlink.c
Expand Up @@ -43,6 +43,10 @@
* Deny \c readlink(2) if the file is not within the sandbox bounds.
*/
static ssize_t _dt_readlink(const char *path, char *buf, size_t bufsiz) {
if (!__darwintrace_initialized) {
return readlink(path, buf, bufsiz);
}

__darwintrace_setup();

int result = 0;
Expand Down
4 changes: 4 additions & 0 deletions src/darwintracelib1.0/rename.c
Expand Up @@ -44,6 +44,10 @@
* sandbox.
*/
static int _dt_rename(const char *from, const char *to) {
if (!__darwintrace_initialized) {
return rename(from, to);
}

__darwintrace_setup();

int result = 0;
Expand Down
4 changes: 4 additions & 0 deletions src/darwintracelib1.0/rmdir.c
Expand Up @@ -44,6 +44,10 @@
* sandbox.
*/
static int _dt_rmdir(const char *path) {
if (!__darwintrace_initialized) {
return rmdir(path);
}

__darwintrace_setup();

int result = 0;
Expand Down
16 changes: 16 additions & 0 deletions src/darwintracelib1.0/stat.c
Expand Up @@ -50,6 +50,10 @@ int stat(const char *path, void *sb);
* sandbox.
*/
static int _dt_stat(const char *path, void *sb) {
if (!__darwintrace_initialized) {
return stat(path, sb);
}

__darwintrace_setup();

int result = 0;
Expand All @@ -75,6 +79,10 @@ int stat64(const char *path, void *sb);
int stat$INODE64(const char *path, void *sb);

static int _dt_stat64(const char *path, void *sb) {
if (!__darwintrace_initialized) {
return stat64(path, sb);
}

__darwintrace_setup();

int result = 0;
Expand All @@ -99,6 +107,10 @@ DARWINTRACE_INTERPOSE(_dt_stat64, stat$INODE64);
int lstat(const char *path, void *sb);

static int _dt_lstat(const char *path, void *sb) {
if (!__darwintrace_initialized) {
return lstat(path, sb);
}

__darwintrace_setup();

int result = 0;
Expand All @@ -125,6 +137,10 @@ int lstat64(const char *path, void *sb);
int lstat$INODE64(const char *path, void *sb);

static int _dt_lstat64(const char *path, void *sb) {
if (!__darwintrace_initialized) {
return lstat64(path, sb);
}

__darwintrace_setup();

int result = 0;
Expand Down
4 changes: 4 additions & 0 deletions src/darwintracelib1.0/unlink.c
Expand Up @@ -44,6 +44,10 @@
* of the sandbox and simulate non-existence of the file instead.
*/
static int _dt_unlink(const char *path) {
if (!__darwintrace_initialized) {
return unlink(path);
}

__darwintrace_setup();

int result = 0;
Expand Down

0 comments on commit d96e5a8

Please sign in to comment.