sandsifter: Compiling on macOS fails

On macOS make yeilds:

/usr/include/ucontext.h:43:2: error: The deprecated ucontext routines require _XOPEN_SOURCE to be defined
#error The deprecated ucontext routines require _XOPEN_SOURCE to be defined
 ^
...

Using

cc -D_XOPEN_SOURCE -c injector.c -o injector.o -Wall

or

diff --git a/injector.c b/injector.c
index 75848b5..280ae4e 100644
--- a/injector.c
+++ b/injector.c
@@ -13,7 +13,7 @@
 #include <time.h>
 #include <execinfo.h>
 #include <limits.h>
-#include <ucontext.h>
+#include <sys/ucontext.h>
 #include <sys/types.h>
 #include <stdint.h>
 #include <stdbool.h>

fixes the first issue. But, it looks like there is still an issue with the portability of ucontext structures:

cc  -c injector.c -o injector.o -Wall
injector.c:321:93: warning: excess elements in array initializer
        .start={.bytes={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, .len=0},
                                                                                                   ^~~~
injector.c:322:91: warning: excess elements in array initializer
        .end={.bytes={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}, .len=0},
                                                                                                 ^~~~
injector.c:853:31: error: member reference type 'struct __darwin_mcontext64 *' is a pointer; did you mean to use '->'?
        ((ucontext_t*)p)->uc_mcontext.gregs[IP]+=UD2_SIZE;
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
                                     ->
injector.c:853:32: error: no member named 'gregs' in 'struct __darwin_mcontext64'
        ((ucontext_t*)p)->uc_mcontext.gregs[IP]+=UD2_SIZE;
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
injector.c:853:38: error: use of undeclared identifier 'REG_RIP'
        ((ucontext_t*)p)->uc_mcontext.gregs[IP]+=UD2_SIZE;
                                            ^
injector.c:81:13: note: expanded from macro 'IP'
        #define IP REG_RIP
                   ^
injector.c:866:29: error: member reference type 'struct __darwin_mcontext64 *' is a pointer; did you mean to use '->'?
                (uintptr_t)uc->uc_mcontext.gregs[IP]-(uintptr_t)packet-preamble_length;
                           ~~~~~~~~~~~~~~~^
                                          ->
injector.c:866:30: error: no member named 'gregs' in 'struct __darwin_mcontext64'
                (uintptr_t)uc->uc_mcontext.gregs[IP]-(uintptr_t)packet-preamble_length;
                           ~~~~~~~~~~~~~~~ ^
injector.c:866:36: error: use of undeclared identifier 'REG_RIP'
                (uintptr_t)uc->uc_mcontext.gregs[IP]-(uintptr_t)packet-preamble_length;
                                                 ^
injector.c:81:13: note: expanded from macro 'IP'
        #define IP REG_RIP
                   ^
injector.c:883:24: error: member reference type 'struct __darwin_mcontext64 *' is a pointer; did you mean to use '->'?
        memcpy(uc->uc_mcontext.gregs, fault_context.gregs, sizeof(fault_context.gregs));
               ~~~~~~~~~~~~~~~^
                              ->
/usr/include/secure/_string.h:65:27: note: expanded from macro 'memcpy'
  __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))
                          ^~~~
injector.c:883:25: error: no member named 'gregs' in 'struct __darwin_mcontext64'
        memcpy(uc->uc_mcontext.gregs, fault_context.gregs, sizeof(fault_context.gregs));
               ~~~~~~~~~~~~~~~ ^
/usr/include/secure/_string.h:65:27: note: expanded from macro 'memcpy'
  __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))
                          ^~~~
injector.c:883:45: error: member reference type 'mcontext_t' (aka 'struct __darwin_mcontext64 *') is a pointer; did you mean to use
      '->'?
        memcpy(uc->uc_mcontext.gregs, fault_context.gregs, sizeof(fault_context.gregs));
                                      ~~~~~~~~~~~~~^
                                                   ->
/usr/include/secure/_string.h:65:33: note: expanded from macro 'memcpy'
  __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))
                                ^~~
injector.c:883:46: error: no member named 'gregs' in 'struct __darwin_mcontext64'
        memcpy(uc->uc_mcontext.gregs, fault_context.gregs, sizeof(fault_context.gregs));
                                      ~~~~~~~~~~~~~ ^
/usr/include/secure/_string.h:65:33: note: expanded from macro 'memcpy'
  __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))
                                ^~~
injector.c:883:73: error: member reference type 'mcontext_t' (aka 'struct __darwin_mcontext64 *') is a pointer; did you mean to use
      '->'?
        memcpy(uc->uc_mcontext.gregs, fault_context.gregs, sizeof(fault_context.gregs));
                                                                  ~~~~~~~~~~~~~^
                                                                               ->
/usr/include/secure/_string.h:65:38: note: expanded from macro 'memcpy'
  __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))
                                     ^~~
injector.c:883:74: error: no member named 'gregs' in 'struct __darwin_mcontext64'
        memcpy(uc->uc_mcontext.gregs, fault_context.gregs, sizeof(fault_context.gregs));
                                                                  ~~~~~~~~~~~~~ ^
/usr/include/secure/_string.h:65:38: note: expanded from macro 'memcpy'
  __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))
                                     ^~~
injector.c:883:24: error: member reference type 'struct __darwin_mcontext64 *' is a pointer; did you mean to use '->'?
        memcpy(uc->uc_mcontext.gregs, fault_context.gregs, sizeof(fault_context.gregs));
               ~~~~~~~~~~~~~~~^
                              ->
/usr/include/secure/_string.h:65:59: note: expanded from macro 'memcpy'
  __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))
                                                          ^~~~
/usr/include/secure/_common.h:38:55: note: expanded from macro '__darwin_obsz0'
#define __darwin_obsz0(object) __builtin_object_size (object, 0)
                                                      ^~~~~~
injector.c:883:25: error: no member named 'gregs' in 'struct __darwin_mcontext64'
        memcpy(uc->uc_mcontext.gregs, fault_context.gregs, sizeof(fault_context.gregs));
               ~~~~~~~~~~~~~~~ ^
/usr/include/secure/_string.h:65:59: note: expanded from macro 'memcpy'
  __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))
                                                          ^~~~
/usr/include/secure/_common.h:38:55: note: expanded from macro '__darwin_obsz0'
#define __darwin_obsz0(object) __builtin_object_size (object, 0)
                                                      ^~~~~~
injector.c:884:17: error: member reference type 'struct __darwin_mcontext64 *' is a pointer; did you mean to use '->'?
        uc->uc_mcontext.gregs[IP]=(uintptr_t)&resume;
        ~~~~~~~~~~~~~~~^
                       ->
injector.c:884:18: error: no member named 'gregs' in 'struct __darwin_mcontext64'
        uc->uc_mcontext.gregs[IP]=(uintptr_t)&resume;
        ~~~~~~~~~~~~~~~ ^
injector.c:884:24: error: use of undeclared identifier 'REG_RIP'
        uc->uc_mcontext.gregs[IP]=(uintptr_t)&resume;
                              ^
injector.c:81:13: note: expanded from macro 'IP'
        #define IP REG_RIP
                   ^
injector.c:885:17: error: member reference type 'struct __darwin_mcontext64 *' is a pointer; did you mean to use '->'?
        uc->uc_mcontext.gregs[REG_EFL]&=~TF;
        ~~~~~~~~~~~~~~~^
                       ->
injector.c:885:18: error: no member named 'gregs' in 'struct __darwin_mcontext64'
        uc->uc_mcontext.gregs[REG_EFL]&=~TF;
        ~~~~~~~~~~~~~~~ ^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
2 warnings and 20 errors generated.
make: *** [injector.o] Error 1

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Reactions: 13
  • Comments: 15

Most upvoted comments

-       ((ucontext_t*)p)->uc_mcontext.gregs[IP]+=UD2_SIZE;
+       ((ucontext_t*)p)->uc_mcontext->__ss.__rip+=UD2_SIZE;

Variations of this seem to, at the very least, remove more warnings. Still doesn’t compile and I’d be surprised if a straight swap out here worked.

I got this to compile, but I’m not sure if the executable still works as intended. This is ONLY for 64-bit – I didn’t take the time to convert these changes for 32-bit, but I imagine it wouldn’t be too difficult.


Change 1: Dummy Struct

Modify the following snippet: https://github.com/xoreaxeaxeax/sandsifter/blob/8375e6123d093629e3e4437d7903839fd0742c2a/injector.c#L174-L177 Delete the entire dummy_stack definition. Then, copy the following (to anywhere before the inject_state typedef struct definition on line 90!):

typedef struct {
	uint64_t dummy_stack_hi[256];
	uint64_t dummy_stack_lo[256];
} dumb_stack;
static dumb_stack dummy_stack __attribute__ ((aligned(PAGE_SIZE)));

Then, in the __x86_64__ inject_state definition, modify the struct:

...
	uint64_t rsp;
	dumb_stack dumb;
} state_t;
...

and the inject_state definition:

...
	.rsp=0,
	.dumb.dummy_stack_lo=0,
	.dumb.dummy_stack_hi=0
};
...

We also need to modify the stack reset on line 766:

inject_state.dumb.dummy_stack_lo[0]=0;

And lastly, we need to modify the inline asm here: https://github.com/xoreaxeaxeax/sandsifter/blob/8375e6123d093629e3e4437d7903839fd0742c2a/injector.c#L777-L815 The asm on line 813 should read:

[rsp]"m"(inject_state.dumb.dummy_stack_lo),

Change 2: uc_mcontext

We need to modify uc_mcontext references for macOS. Make all of the following changes:

  • Line 853:
((ucontext_t*)p)->uc_mcontext->__ss.__rip+=UD2_SIZE;
  • Line 866:
(uintptr_t)uc->uc_mcontext->__ss.__rip-(uintptr_t)packet-preamble_length;
  • Lines 883-885:
uc->uc_mcontext->__ss = fault_context->__ss;
uc->uc_mcontext->__ss.__rip =(uintptr_t)&resume;
uc->uc_mcontext->__ss.__rflags &=~TF;

Change 3: header file

Create a new file injector.h with the following contents:

extern char debug, resume, preamble_start, preamble_end;

Then modify the extern definition on line 366. https://github.com/xoreaxeaxeax/sandsifter/blob/8375e6123d093629e3e4437d7903839fd0742c2a/injector.c#L366 Change line 366 to:

char debug, resume, preamble_start, preamble_end;

Change 4: pthread modifications

This code was borrowed from https://yyshen.github.io/2015/01/18/binding_threads_to_cores_osx.html. Copy the following block underneath the top #include section.

#define SYSCTL_CORE_COUNT   "machdep.cpu.core_count"

typedef struct cpu_set {
  uint32_t    count;
} cpu_set_t;

static inline void
CPU_ZERO(cpu_set_t *cs) { cs->count = 0; }

static inline void
CPU_SET(int num, cpu_set_t *cs) { cs->count |= (1 << num); }

static inline int
CPU_ISSET(int num, cpu_set_t *cs) { return (cs->count & (1 << num)); }

int sched_getaffinity(pid_t pid, size_t cpu_size, cpu_set_t *cpu_set)
{
  int32_t core_count = 0;
  size_t  len = sizeof(core_count);
  int ret = sysctlbyname(SYSCTL_CORE_COUNT, &core_count, &len, 0, 0);
  if (ret) {
    printf("error while get core count %d\n", ret);
    return -1;
  }
  cpu_set->count = 0;
  for (int i = 0; i < core_count; i++) {
    cpu_set->count |= (1 << i);
  }

  return 0;
}

int pthread_setaffinity_np(pthread_t thread, size_t cpu_size,
                           cpu_set_t *cpu_set)
{
  thread_port_t mach_thread;
  int core = 0;

  for (core = 0; core < 8 * cpu_size; core++) {
    if (CPU_ISSET(core, cpu_set)) break;
  }
  printf("binding to core %d\n", core);
  thread_affinity_policy_data_t policy = { core };
  mach_thread = pthread_mach_thread_np(thread);
  thread_policy_set(mach_thread, THREAD_AFFINITY_POLICY,
                    (thread_policy_t)&policy, 1);
  return 0;
}

Then, modify line 1344 to read:

if (pthread_setaffinity_np(0, sizeof(mask), &mask)) {

Lastly, append this to the #include section

#include <mach/thread_policy.h>

Change 5: Python

The sifter.py file is designed for Linux and attempts to gather CPU info via /proc/cpuinfo, which doesn’t exist on macOS. So, I made a small change to allow running on a Mac. https://github.com/xoreaxeaxeax/sandsifter/blob/8375e6123d093629e3e4437d7903839fd0742c2a/sifter.py#L681-L684 Modify the get_cpu_info() function to:

def get_cpu_info():
    p =  subprocess.Popen(['/usr/sbin/sysctl','-a'], stdout=subprocess.PIPE)
    p.wait()
    cpu = [l.strip('machdep.cpu.') for l in str(p.stdout.read()).split('\n') if 'machdep.cpu' in l]
    return cpu

Lastly, run make. If you encounter this error:

/usr/include/ucontext.h:43:2: error: The deprecated ucontext routines require _XOPEN_SOURCE to be defined

Run make with the CFLAGS variable:

CFLAGS="-D_XOPEN_SOURCE" make

Hope this helps! Also hopefully the injector binary still functions as expected. Please comment below with results or findings.