mirror of
https://github.com/corda/corda.git
synced 2024-12-27 08:22:35 +00:00
Support for creating and joining Java threads within SGX Avian. (#123)
* Add threading support to SGX Avian. * Handle contract verification exceptions using uncaught exception handler. * Indent uniformly to 4 spaces. * Add comments for some of the uses of SGX synchronisation primitives.
This commit is contained in:
parent
ad4bed779d
commit
2652dfce3f
@ -39,13 +39,13 @@ public class SystemClassLoader extends ClassLoader {
|
|||||||
|
|
||||||
private native VMClass findLoadedVMClass(String name);
|
private native VMClass findLoadedVMClass(String name);
|
||||||
|
|
||||||
private static native void startBlacklisting0();
|
private static native void startBlacklisting0(Thread t);
|
||||||
|
|
||||||
public void startBlacklisting() {
|
public void startBlacklisting(Thread t) {
|
||||||
if (isForbidden("java/util/regex/Pattern$Test")) {
|
if (isForbidden("java/util/regex/Pattern$Test")) {
|
||||||
throw new IllegalStateException("Impossible!");
|
throw new IllegalStateException("Impossible!");
|
||||||
}
|
}
|
||||||
startBlacklisting0();
|
startBlacklisting0(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Set<Pattern> BLACKLIST = Collections.unmodifiableSet(setOf(
|
private static final Set<Pattern> BLACKLIST = Collections.unmodifiableSet(setOf(
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
# proguard include file (http://proguard.sourceforge.net)
|
# proguard include file (http://proguard.sourceforge.net)
|
||||||
|
|
||||||
|
-keep class avian.SystemClassLoader {
|
||||||
|
public void startBlacklisting(java.lang.Thread);
|
||||||
|
}
|
||||||
|
|
||||||
# We need these for Corda deserialisation:
|
# We need these for Corda deserialisation:
|
||||||
-keep class sun.security.ec.ECPublicKeyImpl
|
-keep class sun.security.ec.ECPublicKeyImpl
|
||||||
-keep class sun.security.ec.ECPrivateKeyImpl
|
-keep class sun.security.ec.ECPrivateKeyImpl
|
||||||
|
@ -533,7 +533,8 @@ system = posix
|
|||||||
asm = x86
|
asm = x86
|
||||||
|
|
||||||
ifeq ($(system),sgx)
|
ifeq ($(system),sgx)
|
||||||
cflags += -DSGX
|
cflags += -DSGX -I../linux-sgx/common/inc -I../jvm-enclave/common
|
||||||
|
lflags += $(shared)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
pointer-size = 8
|
pointer-size = 8
|
||||||
|
@ -158,7 +158,12 @@ const unsigned FixedFootprintThresholdInBytes = ThreadHeapPoolSize
|
|||||||
|
|
||||||
// number of zombie threads which may accumulate before we force a GC
|
// number of zombie threads which may accumulate before we force a GC
|
||||||
// to clean them up:
|
// to clean them up:
|
||||||
const unsigned ZombieCollectionThreshold = 16;
|
#ifdef SGX
|
||||||
|
# define ZOMBIE_THRESHOLD 0
|
||||||
|
#else
|
||||||
|
# define ZOMBIE_THRESHOLD 16
|
||||||
|
#endif
|
||||||
|
const unsigned ZombieCollectionThreshold = ZOMBIE_THRESHOLD;
|
||||||
|
|
||||||
enum FieldCode {
|
enum FieldCode {
|
||||||
VoidField,
|
VoidField,
|
||||||
@ -1342,7 +1347,6 @@ class Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isBlacklisting();
|
bool isBlacklisting();
|
||||||
void startBlacklisting();
|
|
||||||
|
|
||||||
JNIEnvVTable* vtable;
|
JNIEnvVTable* vtable;
|
||||||
Machine* m;
|
Machine* m;
|
||||||
@ -1834,15 +1838,6 @@ inline uint64_t runThread(Thread* t, uintptr_t*)
|
|||||||
inline bool startThread(Thread* t, Thread* p)
|
inline bool startThread(Thread* t, Thread* p)
|
||||||
{
|
{
|
||||||
p->setFlag(Thread::JoinFlag);
|
p->setFlag(Thread::JoinFlag);
|
||||||
#ifdef SGX
|
|
||||||
static const char16_t *nameToSkip = u"Reference Handler";
|
|
||||||
if (p->javaThread->name()->length(t) == 17) {
|
|
||||||
if (!memcmp(nameToSkip, cast<GcCharArray>(t, p->javaThread->name()->data())->body().begin(), 17 * 2)) {
|
|
||||||
printf("Skipping start of reference handler thread\n");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return t->m->system->success(t->m->system->start(&(p->runnable)));
|
return t->m->system->success(t->m->system->start(&(p->runnable)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,9 +184,15 @@ extern "C" AVIAN_EXPORT int64_t JNICALL
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" AVIAN_EXPORT void JNICALL
|
extern "C" AVIAN_EXPORT void JNICALL
|
||||||
Avian_avian_SystemClassLoader_startBlacklisting0(Thread* t, object, uintptr_t*)
|
Avian_avian_SystemClassLoader_startBlacklisting0(Thread *t,
|
||||||
|
object,
|
||||||
|
uintptr_t* arguments)
|
||||||
{
|
{
|
||||||
t->startBlacklisting();
|
GcThread *jt = cast<GcThread>(t, reinterpret_cast<object>(arguments[0]));
|
||||||
|
if (jt == NULL) {
|
||||||
|
throwNew(t, GcNullPointerException::Type);
|
||||||
|
}
|
||||||
|
jt->setBlacklisting(t, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" AVIAN_EXPORT int64_t JNICALL
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
||||||
|
@ -70,7 +70,6 @@ jint JNICALL DetachCurrentThread(Machine* m)
|
|||||||
|
|
||||||
uint64_t destroyJavaVM(Thread* t, uintptr_t*)
|
uint64_t destroyJavaVM(Thread* t, uintptr_t*)
|
||||||
{
|
{
|
||||||
#ifndef SGX
|
|
||||||
// wait for other non-daemon threads to exit
|
// wait for other non-daemon threads to exit
|
||||||
{
|
{
|
||||||
ACQUIRE(t, t->m->stateLock);
|
ACQUIRE(t, t->m->stateLock);
|
||||||
@ -78,13 +77,11 @@ uint64_t destroyJavaVM(Thread* t, uintptr_t*)
|
|||||||
t->m->stateLock->wait(t->systemThread, 0);
|
t->m->stateLock->wait(t->systemThread, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
t->m->classpath->shutDown(t);
|
t->m->classpath->shutDown(t);
|
||||||
}
|
}
|
||||||
#ifndef SGX
|
|
||||||
// wait again in case the Classpath::shutDown process started new
|
// wait again in case the Classpath::shutDown process started new
|
||||||
// threads:
|
// threads:
|
||||||
{
|
{
|
||||||
@ -95,7 +92,6 @@ uint64_t destroyJavaVM(Thread* t, uintptr_t*)
|
|||||||
|
|
||||||
enter(t, Thread::ExclusiveState);
|
enter(t, Thread::ExclusiveState);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
shutDown(t);
|
shutDown(t);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -3969,13 +3969,6 @@ bool Thread::isBlacklisting()
|
|||||||
return (javaThread != NULL) && javaThread->blacklisting();
|
return (javaThread != NULL) && javaThread->blacklisting();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::startBlacklisting()
|
|
||||||
{
|
|
||||||
if (javaThread != NULL) {
|
|
||||||
javaThread->setBlacklisting(this, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void shutDown(Thread* t)
|
void shutDown(Thread* t)
|
||||||
{
|
{
|
||||||
ACQUIRE(t, t->m->shutdownLock);
|
ACQUIRE(t, t->m->shutdownLock);
|
||||||
|
@ -14,7 +14,10 @@
|
|||||||
#include <avian/system/memory.h>
|
#include <avian/system/memory.h>
|
||||||
#include <avian/util/math.h>
|
#include <avian/util/math.h>
|
||||||
|
|
||||||
|
#include <sgx_thread_completion.h>
|
||||||
|
|
||||||
#define PATH_MAX 256
|
#define PATH_MAX 256
|
||||||
|
#define ACQUIRE(x) MutexResource MAKE_NAME(mutexResource_)(x)
|
||||||
|
|
||||||
using namespace vm;
|
using namespace vm;
|
||||||
using namespace avian::util;
|
using namespace avian::util;
|
||||||
@ -26,7 +29,32 @@ extern "C" __attribute__((weak)) const uint8_t* embedded_file_app_jar(size_t* si
|
|||||||
|
|
||||||
extern "C" const uint8_t* javahomeJar(size_t* size);
|
extern "C" const uint8_t* javahomeJar(size_t* size);
|
||||||
|
|
||||||
|
typedef struct _thread_data_t thread_data_t;
|
||||||
|
extern "C" __attribute__((weak)) thread_data_t* start_thread(void (*routine)(void *), void *param, sgx_thread_completion *completion);
|
||||||
|
extern "C" __attribute__((weak)) thread_data_t* get_thread_data();
|
||||||
|
|
||||||
|
static void run(void* r)
|
||||||
|
{
|
||||||
|
static_cast<System::Runnable*>(r)->run();
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
class MutexResource {
|
||||||
|
public:
|
||||||
|
MutexResource(sgx_thread_mutex_t& m) noexcept : _m(&m)
|
||||||
|
{
|
||||||
|
sgx_thread_mutex_lock(_m);
|
||||||
|
}
|
||||||
|
|
||||||
|
~MutexResource() noexcept
|
||||||
|
{
|
||||||
|
sgx_thread_mutex_unlock(_m);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
sgx_thread_mutex_t* _m;
|
||||||
|
};
|
||||||
|
|
||||||
void abort_with(const char *msg) {
|
void abort_with(const char *msg) {
|
||||||
printf("%s\n", msg);
|
printf("%s\n", msg);
|
||||||
while(true);
|
while(true);
|
||||||
@ -35,81 +63,149 @@ namespace {
|
|||||||
class MySystem;
|
class MySystem;
|
||||||
MySystem* globalSystem;
|
MySystem* globalSystem;
|
||||||
const bool Verbose = false;
|
const bool Verbose = false;
|
||||||
|
const unsigned Notified = 1 << 0;
|
||||||
|
|
||||||
class MySystem : public System {
|
class MySystem : public System {
|
||||||
public:
|
public:
|
||||||
class Thread : public System::Thread {
|
class Thread : public System::Thread {
|
||||||
public:
|
public:
|
||||||
Thread* next;
|
Thread(System* s, System::Runnable* r) : s(s), r(r), next(0), flags(0)
|
||||||
|
|
||||||
Thread(System* s UNUSED, System::Runnable* r UNUSED) : next(0)
|
|
||||||
{
|
{
|
||||||
|
sgx_thread_mutex_init(&mutex, 0);
|
||||||
|
sgx_thread_cond_init(&condition, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void interrupt()
|
virtual void interrupt()
|
||||||
{
|
{
|
||||||
printf("Thread::Interrupt()\n");
|
ACQUIRE(mutex);
|
||||||
|
|
||||||
|
r->setInterrupted(true);
|
||||||
|
|
||||||
|
int rv UNUSED = sgx_thread_cond_signal(&condition);
|
||||||
|
expect(s, rv == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool getAndClearInterrupted()
|
virtual bool getAndClearInterrupted()
|
||||||
{
|
{
|
||||||
printf("Thread::getAndClearInterrupted()\n");
|
ACQUIRE(mutex);
|
||||||
return false;
|
|
||||||
|
bool interrupted = r->interrupted();
|
||||||
|
|
||||||
|
r->setInterrupted(false);
|
||||||
|
|
||||||
|
return interrupted;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void join()
|
virtual void join()
|
||||||
{
|
{
|
||||||
printf("Thread::Join()\n");
|
completion.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose()
|
virtual void dispose()
|
||||||
{
|
{
|
||||||
|
sgx_thread_mutex_destroy(&mutex);
|
||||||
|
sgx_thread_cond_destroy(&condition);
|
||||||
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
thread_data_t* thread;
|
||||||
|
sgx_thread_completion completion;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The mutex protects this thread object's internal
|
||||||
|
* "state", and the condition wakes the thread when
|
||||||
|
* it is waiting on a monitor lock.
|
||||||
|
*/
|
||||||
|
sgx_thread_mutex_t mutex;
|
||||||
|
sgx_thread_cond_t condition;
|
||||||
|
|
||||||
|
System* s;
|
||||||
|
System::Runnable* r;
|
||||||
|
Thread* next;
|
||||||
|
unsigned flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Mutex : public System::Mutex {
|
class Mutex : public System::Mutex {
|
||||||
public:
|
public:
|
||||||
Mutex(System* s) : s(s)
|
Mutex(System* s) : s(s)
|
||||||
{
|
{
|
||||||
|
sgx_thread_mutex_init(&mutex, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void acquire()
|
virtual void acquire()
|
||||||
{
|
{
|
||||||
|
sgx_thread_mutex_lock(&mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void release()
|
virtual void release()
|
||||||
{
|
{
|
||||||
|
sgx_thread_mutex_unlock(&mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose()
|
virtual void dispose()
|
||||||
{
|
{
|
||||||
|
sgx_thread_mutex_destroy(&mutex);
|
||||||
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
System* s;
|
System* s;
|
||||||
|
sgx_thread_mutex_t mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Monitor : public System::Monitor {
|
class Monitor : public System::Monitor {
|
||||||
public:
|
public:
|
||||||
Monitor(System* s) : s(s), owner_(0), first(0), last(0), depth(0)
|
Monitor(System* s) : s(s), owner_(0), first(0), last(0), depth(0)
|
||||||
{
|
{
|
||||||
|
sgx_thread_mutex_init(&mutex, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool tryAcquire(System::Thread* context UNUSED)
|
virtual bool tryAcquire(System::Thread* context)
|
||||||
{
|
{
|
||||||
return true;
|
Thread* t = static_cast<Thread*>(context);
|
||||||
|
|
||||||
|
if (owner_ == t) {
|
||||||
|
++depth;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
switch (sgx_thread_mutex_trylock(&mutex)) {
|
||||||
|
case EBUSY:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
owner_ = t;
|
||||||
|
++depth;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
sysAbort(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void acquire(System::Thread* context UNUSED)
|
virtual void acquire(System::Thread* context)
|
||||||
{
|
{
|
||||||
|
Thread* t = static_cast<Thread*>(context);
|
||||||
|
|
||||||
|
if (owner_ != t) {
|
||||||
|
sgx_thread_mutex_lock(&mutex);
|
||||||
|
owner_ = t;
|
||||||
|
}
|
||||||
|
++depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void release(System::Thread* context UNUSED)
|
virtual void release(System::Thread* context)
|
||||||
{
|
{
|
||||||
|
Thread* t = static_cast<Thread*>(context);
|
||||||
|
|
||||||
|
if (owner_ == t) {
|
||||||
|
if (--depth == 0) {
|
||||||
|
owner_ = 0;
|
||||||
|
sgx_thread_mutex_unlock(&mutex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sysAbort(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void append(Thread* t)
|
void append(Thread* t)
|
||||||
@ -157,33 +253,125 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void wait(System::Thread* context UNUSED, int64_t time UNUSED)
|
virtual void wait(System::Thread* context, int64_t time)
|
||||||
{
|
{
|
||||||
wait(context, time, false);
|
wait(context, time, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool waitAndClearInterrupted(System::Thread* context UNUSED, int64_t time UNUSED)
|
virtual bool waitAndClearInterrupted(System::Thread* context, int64_t time)
|
||||||
{
|
{
|
||||||
return wait(context, time, true);
|
return wait(context, time, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wait(System::Thread* context UNUSED, int64_t time UNUSED, bool clearInterrupted UNUSED)
|
bool wait(System::Thread* context, int64_t time UNUSED, bool clearInterrupted)
|
||||||
{
|
{
|
||||||
abort_with("STUB: Thread::Wait()");
|
Thread* t = static_cast<Thread*>(context);
|
||||||
return true;
|
|
||||||
|
if (owner_ == t) {
|
||||||
|
// Initialized here to make gcc 4.2 a happy compiler
|
||||||
|
bool interrupted = false;
|
||||||
|
bool notified = false;
|
||||||
|
unsigned depth = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
ACQUIRE(t->mutex);
|
||||||
|
|
||||||
|
expect(s, (t->flags & Notified) == 0);
|
||||||
|
|
||||||
|
interrupted = t->r->interrupted();
|
||||||
|
if (interrupted and clearInterrupted) {
|
||||||
|
t->r->setInterrupted(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
append(t);
|
||||||
|
|
||||||
|
depth = this->depth;
|
||||||
|
this->depth = 0;
|
||||||
|
owner_ = 0;
|
||||||
|
sgx_thread_mutex_unlock(&mutex);
|
||||||
|
|
||||||
|
if (not interrupted) {
|
||||||
|
int rv UNUSED = sgx_thread_cond_wait(&(t->condition), &(t->mutex));
|
||||||
|
expect(s, rv == 0 or rv == EINTR);
|
||||||
|
|
||||||
|
interrupted = t->r->interrupted();
|
||||||
|
if (interrupted and clearInterrupted) {
|
||||||
|
t->r->setInterrupted(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notified = ((t->flags & Notified) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
sgx_thread_mutex_lock(&mutex);
|
||||||
|
|
||||||
|
{
|
||||||
|
ACQUIRE(t->mutex);
|
||||||
|
t->flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not notified) {
|
||||||
|
remove(t);
|
||||||
|
} else {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
for (Thread* x = first; x; x = x->next) {
|
||||||
|
expect(s, t != x);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
t->next = 0;
|
||||||
|
|
||||||
|
owner_ = t;
|
||||||
|
this->depth = depth;
|
||||||
|
|
||||||
|
return interrupted;
|
||||||
|
} else {
|
||||||
|
sysAbort(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void doNotify(Thread* t UNUSED)
|
void doNotify(Thread* t)
|
||||||
{
|
{
|
||||||
printf("STUB: Thread::Notify()\n");
|
ACQUIRE(t->mutex);
|
||||||
|
|
||||||
|
t->flags |= Notified;
|
||||||
|
int rv UNUSED = sgx_thread_cond_signal(&(t->condition));
|
||||||
|
expect(s, rv == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void notify(System::Thread* context UNUSED)
|
virtual void notify(System::Thread* context)
|
||||||
{
|
{
|
||||||
|
Thread* t = static_cast<Thread*>(context);
|
||||||
|
|
||||||
|
if (owner_ == t) {
|
||||||
|
if (first) {
|
||||||
|
Thread* t = first;
|
||||||
|
first = first->next;
|
||||||
|
if (t == last) {
|
||||||
|
expect(s, first == 0);
|
||||||
|
last = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
doNotify(t);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sysAbort(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void notifyAll(System::Thread* context UNUSED)
|
virtual void notifyAll(System::Thread* context)
|
||||||
{
|
{
|
||||||
|
Thread* t = static_cast<Thread*>(context);
|
||||||
|
|
||||||
|
if (owner_ == t) {
|
||||||
|
for (Thread* t = first; t; t = t->next) {
|
||||||
|
doNotify(t);
|
||||||
|
}
|
||||||
|
first = last = 0;
|
||||||
|
} else {
|
||||||
|
sysAbort(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual System::Thread* owner()
|
virtual System::Thread* owner()
|
||||||
@ -194,32 +382,37 @@ namespace {
|
|||||||
virtual void dispose()
|
virtual void dispose()
|
||||||
{
|
{
|
||||||
expect(s, owner_ == 0);
|
expect(s, owner_ == 0);
|
||||||
|
sgx_thread_mutex_destroy(&mutex);
|
||||||
::free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
System* s;
|
System* s;
|
||||||
|
sgx_thread_mutex_t mutex;
|
||||||
Thread* owner_;
|
Thread* owner_;
|
||||||
Thread* first;
|
Thread* first;
|
||||||
Thread* last;
|
Thread* last;
|
||||||
unsigned depth;
|
unsigned depth;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This implementation of thread-local storage
|
||||||
|
// for SGX only works because we only create
|
||||||
|
// one instance of this class.
|
||||||
class Local : public System::Local {
|
class Local : public System::Local {
|
||||||
public:
|
public:
|
||||||
void *value;
|
|
||||||
|
|
||||||
Local(System* s) : s(s)
|
Local(System* s) : s(s)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* get()
|
virtual void* get()
|
||||||
{
|
{
|
||||||
return value;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void set(void* p)
|
virtual void set(void* p)
|
||||||
{
|
{
|
||||||
value = p;
|
expect(s, data == NULL);
|
||||||
|
data = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose()
|
virtual void dispose()
|
||||||
@ -227,7 +420,10 @@ namespace {
|
|||||||
::free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
System* s;
|
System* s;
|
||||||
|
// Requires __get_tls_addr() in libsgx_trts
|
||||||
|
static thread_local void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Region : public System::Region {
|
class Region : public System::Region {
|
||||||
@ -256,6 +452,7 @@ namespace {
|
|||||||
::free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
System* s;
|
System* s;
|
||||||
uint8_t* start_;
|
uint8_t* start_;
|
||||||
size_t length_;
|
size_t length_;
|
||||||
@ -329,6 +526,7 @@ namespace {
|
|||||||
::free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
System* s;
|
System* s;
|
||||||
System::Library* next_;
|
System::Library* next_;
|
||||||
};
|
};
|
||||||
@ -371,7 +569,10 @@ namespace {
|
|||||||
|
|
||||||
virtual Status attach(Runnable* r)
|
virtual Status attach(Runnable* r)
|
||||||
{
|
{
|
||||||
|
// This system thread will never be joined because it was not
|
||||||
|
// created using startThread() and so does not have JoinFlag set.
|
||||||
Thread* t = new (allocate(this, sizeof(Thread))) Thread(this, r);
|
Thread* t = new (allocate(this, sizeof(Thread))) Thread(this, r);
|
||||||
|
t->thread = get_thread_data();
|
||||||
r->attach(t);
|
r->attach(t);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -380,10 +581,7 @@ namespace {
|
|||||||
{
|
{
|
||||||
Thread* t = new (allocate(this, sizeof(Thread))) Thread(this, r);
|
Thread* t = new (allocate(this, sizeof(Thread))) Thread(this, r);
|
||||||
r->attach(t);
|
r->attach(t);
|
||||||
printf("System::start (thread!!)\n");
|
t->thread = start_thread(&run, r, &t->completion);
|
||||||
// We implement threads as blocking calls! This is of course totally wrong, but with extra threads
|
|
||||||
// patched out in a few places, it's hopefully sufficient.
|
|
||||||
r->run();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -509,6 +707,8 @@ namespace {
|
|||||||
Thread* visitTarget;
|
Thread* visitTarget;
|
||||||
System::Monitor* visitLock;
|
System::Monitor* visitLock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
thread_local void* MySystem::Local::data;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
|
@ -30,3 +30,4 @@ libuntrusted_corda_sgx.so: jni/build/Makefile ../../verify-enclave/build/native/
|
|||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
$(RM) -r {standalone,common,enclave,jni}/build
|
$(RM) -r {standalone,common,enclave,jni}/build
|
||||||
|
../../gradlew --project-dir=../.. verify-enclave:clean
|
||||||
|
@ -5,6 +5,7 @@ set(SGX_USE_HARDWARE TRUE CACHE STRING "")
|
|||||||
set(SGX_SDK ${CMAKE_CURRENT_SOURCE_DIR}/../../linux-sgx CACHE STRING "")
|
set(SGX_SDK ${CMAKE_CURRENT_SOURCE_DIR}/../../linux-sgx CACHE STRING "")
|
||||||
set(SGX_LIBRARY_PATH ${SGX_SDK}/build/linux CACHE STRING "")
|
set(SGX_LIBRARY_PATH ${SGX_SDK}/build/linux CACHE STRING "")
|
||||||
set(SGX_SDK_INCLUDE ${SGX_SDK}/common/inc CACHE STRING "")
|
set(SGX_SDK_INCLUDE ${SGX_SDK}/common/inc CACHE STRING "")
|
||||||
|
set(COMMON_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR} CACHE STRING "")
|
||||||
set(GENERATED_RPC_DIR ${CMAKE_CURRENT_BINARY_DIR}/rpc CACHE STRING "")
|
set(GENERATED_RPC_DIR ${CMAKE_CURRENT_BINARY_DIR}/rpc CACHE STRING "")
|
||||||
set(PROGUARD_JAR_PATH /usr/share/proguard6.0beta1/lib/proguard.jar CACHE STRING "")
|
set(PROGUARD_JAR_PATH /usr/share/proguard6.0beta1/lib/proguard.jar CACHE STRING "")
|
||||||
set(DEPENDENCIES_LIBRARY_PATH /usr/lib/x86_64-linux-gnu CACHE STRING "")
|
set(DEPENDENCIES_LIBRARY_PATH /usr/lib/x86_64-linux-gnu CACHE STRING "")
|
||||||
|
22
sgx-jvm/jvm-enclave/common/sgx_thread_completion.h
Normal file
22
sgx-jvm/jvm-enclave/common/sgx_thread_completion.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sgx_thread.h>
|
||||||
|
|
||||||
|
class sgx_thread_completion {
|
||||||
|
bool completed;
|
||||||
|
sgx_thread_mutex_t mutex;
|
||||||
|
sgx_thread_cond_t thread_complete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
sgx_thread_completion() noexcept : completed(false) {
|
||||||
|
sgx_thread_mutex_init(&mutex, NULL);
|
||||||
|
sgx_thread_cond_init(&thread_complete, NULL);
|
||||||
|
}
|
||||||
|
~sgx_thread_completion() noexcept {
|
||||||
|
sgx_thread_cond_destroy(&thread_complete);
|
||||||
|
sgx_thread_mutex_destroy(&mutex);
|
||||||
|
}
|
||||||
|
void complete() noexcept;
|
||||||
|
void wait() noexcept;
|
||||||
|
};
|
||||||
|
|
15
sgx-jvm/jvm-enclave/common/sgx_thread_mutex_guard.h
Normal file
15
sgx-jvm/jvm-enclave/common/sgx_thread_mutex_guard.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sgx_thread.h>
|
||||||
|
|
||||||
|
class sgx_thread_mutex_guard {
|
||||||
|
sgx_thread_mutex_t * const mutex;
|
||||||
|
public:
|
||||||
|
sgx_thread_mutex_guard(sgx_thread_mutex_t *mutex) noexcept : mutex(mutex) {
|
||||||
|
sgx_thread_mutex_lock(mutex);
|
||||||
|
}
|
||||||
|
~sgx_thread_mutex_guard() noexcept {
|
||||||
|
sgx_thread_mutex_unlock(mutex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -98,9 +98,9 @@ target_include_directories(os_support PUBLIC ${SGX_SDK_INCLUDE} ${AVIAN_PATH}/in
|
|||||||
add_dependencies(os_support GENERATED_EDL)
|
add_dependencies(os_support GENERATED_EDL)
|
||||||
|
|
||||||
# Build the enclave into a static archive. We switch off standard headers to make sure SGX headers are used.
|
# Build the enclave into a static archive. We switch off standard headers to make sure SGX headers are used.
|
||||||
add_library(enclave_objects enclave.cpp enclave_start_thread.cpp ${GENERATED_RPC_DIR}/java_t.c ${CMAKE_CURRENT_BINARY_DIR}/boot-jar.o ${CMAKE_CURRENT_BINARY_DIR}/app-jar.o)
|
add_library(enclave_objects enclave.cpp enclave_start_thread.cpp sgx_thread_completion.cpp ${GENERATED_RPC_DIR}/java_t.c ${CMAKE_CURRENT_BINARY_DIR}/boot-jar.o ${CMAKE_CURRENT_BINARY_DIR}/app-jar.o)
|
||||||
add_dependencies(enclave_objects GENERATED_EDL)
|
add_dependencies(enclave_objects GENERATED_EDL)
|
||||||
target_include_directories(enclave_objects PUBLIC ${SGX_SDK_INCLUDE} ${SGX_SDK_INCLUDE}/tlibc ${SGX_SDK}/sdk/tlibstdcxx/stlport ${AVIAN_PATH}/include ${AVIAN_PATH}/src ${GENERATED_RPC_DIR})
|
target_include_directories(enclave_objects PUBLIC ${COMMON_INCLUDE} ${SGX_SDK_INCLUDE} ${SGX_SDK_INCLUDE}/tlibc ${SGX_SDK}/sdk/tlibstdcxx/stlport ${AVIAN_PATH}/include ${AVIAN_PATH}/src ${GENERATED_RPC_DIR})
|
||||||
target_compile_options(enclave_objects PUBLIC -nostdinc)
|
target_compile_options(enclave_objects PUBLIC -nostdinc)
|
||||||
|
|
||||||
# Linker flags:
|
# Linker flags:
|
||||||
|
@ -1,35 +1,47 @@
|
|||||||
#include "enclave_start_thread.h"
|
#include "enclave_start_thread.h"
|
||||||
|
#include <sgx_thread_mutex_guard.h>
|
||||||
|
#include <sgx_thread_completion.h>
|
||||||
|
#include <sgx_trts.h>
|
||||||
|
#include <java_t.h>
|
||||||
|
|
||||||
#include "aex_assert.h"
|
#include "aex_assert.h"
|
||||||
|
#include <cstdlib>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
struct new_thread_data {
|
struct new_thread_data {
|
||||||
void *param;
|
void *param;
|
||||||
void (*thread_routine)(void *);
|
void (*thread_routine)(void *);
|
||||||
sgx_thread_cond_t *thread_started;
|
sgx_thread_cond_t *thread_started;
|
||||||
|
sgx_thread_completion *thread_completed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef unsigned int nonce_t;
|
||||||
static sgx_thread_mutex_t new_thread_map_mutex;
|
static sgx_thread_mutex_t new_thread_map_mutex;
|
||||||
static std::map<unsigned int, new_thread_data> new_thread_map;
|
static std::map<nonce_t, new_thread_data> new_thread_map;
|
||||||
static sgx_thread_mutex_t started_thread_data_map_mutex;
|
static sgx_thread_mutex_t started_thread_data_map_mutex;
|
||||||
static std::map<unsigned int, thread_data_t *> started_thread_data_map;
|
static std::map<nonce_t, thread_data_t *> started_thread_data_map;
|
||||||
struct ThreadMutexInit {
|
struct ThreadMutexInit {
|
||||||
ThreadMutexInit() {
|
ThreadMutexInit() noexcept {
|
||||||
sgx_thread_mutex_init(&new_thread_map_mutex, NULL);
|
sgx_thread_mutex_init(&new_thread_map_mutex, NULL);
|
||||||
sgx_thread_mutex_init(&started_thread_data_map_mutex, NULL);
|
sgx_thread_mutex_init(&started_thread_data_map_mutex, NULL);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static ThreadMutexInit _thread_mutex_init;
|
static ThreadMutexInit _thread_mutex_init;
|
||||||
|
|
||||||
thread_data_t *start_thread(void (*routine)(void *), void *param) {
|
thread_data_t *start_thread(void (*routine)(void *), void *param, sgx_thread_completion *thread_completed) {
|
||||||
unsigned int nonce;
|
nonce_t nonce;
|
||||||
aex_assert(SGX_SUCCESS == sgx_read_rand((unsigned char*)&nonce, sizeof(nonce)));
|
aex_assert(SGX_SUCCESS == sgx_read_rand((unsigned char*)&nonce, sizeof(nonce)));
|
||||||
sgx_thread_cond_t thread_started;
|
sgx_thread_cond_t thread_started;
|
||||||
sgx_thread_cond_init(&thread_started, NULL);
|
sgx_thread_cond_init(&thread_started, NULL);
|
||||||
sgx_thread_mutex_t thread_started_mutex;
|
sgx_thread_mutex_t thread_started_mutex;
|
||||||
sgx_thread_mutex_init(&thread_started_mutex, NULL);
|
sgx_thread_mutex_init(&thread_started_mutex, NULL);
|
||||||
sgx_thread_mutex_guard thread_started_guard(&thread_started_mutex);
|
sgx_thread_mutex_guard thread_started_guard(&thread_started_mutex);
|
||||||
new_thread_data thread_init_data = { param, routine, &thread_started };
|
new_thread_data thread_init_data = {
|
||||||
|
.param = param,
|
||||||
|
.thread_routine = routine,
|
||||||
|
.thread_started = &thread_started,
|
||||||
|
.thread_completed = thread_completed
|
||||||
|
};
|
||||||
{
|
{
|
||||||
sgx_thread_mutex_guard new_thread_map_guard(&new_thread_map_mutex);
|
sgx_thread_mutex_guard new_thread_map_guard(&new_thread_map_mutex);
|
||||||
aex_assert(new_thread_map.find(nonce) == new_thread_map.end());
|
aex_assert(new_thread_map.find(nonce) == new_thread_map.end());
|
||||||
@ -67,4 +79,8 @@ void create_new_thread(unsigned int nonce) {
|
|||||||
}
|
}
|
||||||
sgx_thread_cond_signal(thread_init_data.thread_started);
|
sgx_thread_cond_signal(thread_init_data.thread_started);
|
||||||
thread_init_data.thread_routine(thread_init_data.param);
|
thread_init_data.thread_routine(thread_init_data.param);
|
||||||
|
if (thread_init_data.thread_completed != NULL) {
|
||||||
|
thread_init_data.thread_completed->complete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,19 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "sgx_thread.h"
|
#include "internal/thread_data.h"
|
||||||
#include "sgx_trts.h"
|
|
||||||
#include "java_t.h"
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "internal/global_data.h"
|
|
||||||
|
|
||||||
thread_data_t *start_thread(void (*routine)(void *), void *param);
|
class sgx_thread_completion;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
thread_data_t *start_thread(void (*routine)(void *), void *param, sgx_thread_completion*);
|
||||||
|
}
|
||||||
|
|
||||||
struct sgx_thread_mutex_guard {
|
|
||||||
sgx_thread_mutex_t * const mutex;
|
|
||||||
sgx_thread_mutex_guard(sgx_thread_mutex_t *mutex) : mutex(mutex) {
|
|
||||||
sgx_thread_mutex_lock(mutex);
|
|
||||||
}
|
|
||||||
~sgx_thread_mutex_guard() {
|
|
||||||
sgx_thread_mutex_unlock(mutex);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
16
sgx-jvm/jvm-enclave/enclave/sgx_thread_completion.cpp
Normal file
16
sgx-jvm/jvm-enclave/enclave/sgx_thread_completion.cpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#include <sgx_thread_completion.h>
|
||||||
|
|
||||||
|
void sgx_thread_completion::complete() noexcept {
|
||||||
|
sgx_thread_mutex_lock(&mutex);
|
||||||
|
completed = true;
|
||||||
|
sgx_thread_mutex_unlock(&mutex);
|
||||||
|
sgx_thread_cond_signal(&thread_complete);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sgx_thread_completion::wait() noexcept {
|
||||||
|
sgx_thread_mutex_lock(&mutex);
|
||||||
|
if (!completed) {
|
||||||
|
sgx_thread_cond_wait(&thread_complete, &mutex);
|
||||||
|
}
|
||||||
|
sgx_thread_mutex_unlock(&mutex);
|
||||||
|
}
|
@ -4,9 +4,7 @@ package com.r3.enclaves.txverify
|
|||||||
|
|
||||||
import com.esotericsoftware.minlog.Log
|
import com.esotericsoftware.minlog.Log
|
||||||
import net.corda.core.contracts.Attachment
|
import net.corda.core.contracts.Attachment
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.*
|
||||||
import net.corda.core.serialization.SerializedBytes
|
|
||||||
import net.corda.core.serialization.deserialize
|
|
||||||
import net.corda.core.transactions.LedgerTransaction
|
import net.corda.core.transactions.LedgerTransaction
|
||||||
import net.corda.core.transactions.WireTransaction
|
import net.corda.core.transactions.WireTransaction
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -44,18 +42,26 @@ class TransactionVerificationRequest(private val wtxToVerify: SerializedBytes<Wi
|
|||||||
*/
|
*/
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun verifyInEnclave(reqBytes: ByteArray) {
|
fun verifyInEnclave(reqBytes: ByteArray) {
|
||||||
|
var ex: Throwable? = null
|
||||||
val ltx = deserialise(reqBytes)
|
val ltx = deserialise(reqBytes)
|
||||||
// Prevent this thread from linking new classes against any
|
// Prevent this thread from linking new classes against any
|
||||||
// blacklisted classes, e.g. ones needed by Kryo or by the
|
// blacklisted classes, e.g. ones needed by Kryo or by the
|
||||||
// JVM itself. Note that java.lang.Thread is also blacklisted.
|
// JVM itself. Note that java.lang.Thread is also blacklisted.
|
||||||
startClassBlacklisting()
|
Thread {
|
||||||
ltx.verify()
|
ltx.verify()
|
||||||
|
}.apply {
|
||||||
|
startClassBlacklisting(this)
|
||||||
|
setUncaughtExceptionHandler { _, e -> ex = e }
|
||||||
|
start()
|
||||||
|
join()
|
||||||
|
}
|
||||||
|
throw ex ?: return
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startClassBlacklisting() {
|
private fun startClassBlacklisting(t: Thread) {
|
||||||
val systemClassLoader = ClassLoader.getSystemClassLoader()
|
val systemClassLoader = ClassLoader.getSystemClassLoader()
|
||||||
systemClassLoader.javaClass.getMethod("startBlacklisting").apply {
|
systemClassLoader.javaClass.getMethod("startBlacklisting", t.javaClass).apply {
|
||||||
invoke(systemClassLoader)
|
invoke(systemClassLoader, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package com.r3.enclaves
|
package com.r3.enclaves
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused", "unused_parameter")
|
||||||
class DummySystemClassLoader(parent: ClassLoader) : ClassLoader(parent) {
|
class DummySystemClassLoader(parent: ClassLoader) : ClassLoader(parent) {
|
||||||
fun startBlacklisting() {}
|
fun startBlacklisting(t: Thread) {}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user