Skip to content

Commit

Permalink
[VM, Precompiler] Support obfuscation of the symbolic information in …
Browse files Browse the repository at this point in the history
…precompiler

Obfuscation is controlled by obfuscate flag in Dart_IsolateFlags.

Obfuscation of identifiers is performed during script tokenization - when TokenStream is generated from the source. All kIDENT and kINTERPOL_VAR tokens are renamed consistently using a persistent obfuscation map stored in ObjectStore::obfuscation_map.

Some identifiers (pseudo-keywords, arithmetic operators, builtin recognized methods and entry-points) are not renamed to keep name based lookups from breaking. All other identifiers are renamed.

Constant instances of Symbol-s (both created via literal syntax #ident and using constant constructor const Symbol("ident")) are renamed consistently with corresponding identifiers.

Script urls and Library urls and names are also obfuscated.

Obfuscation map can be dumped as a JSON array at the end of precompilation using Dart_GetObfuscationMap API.

BUG=#30524
R=rmacnak@google.com

Review-Url: https://codereview.chromium.org/3003583002 .
  • Loading branch information
mraleph committed Aug 25, 2017
1 parent 2c3e487 commit 7d52317
Show file tree
Hide file tree
Showing 24 changed files with 1,371 additions and 413 deletions.
427 changes: 188 additions & 239 deletions runtime/bin/gen_snapshot.cc

Large diffs are not rendered by default.

136 changes: 95 additions & 41 deletions runtime/bin/main.cc
Expand Up @@ -123,6 +123,12 @@ static bool parse_all = false;
// of assembly/shared libraries for precompilation.
static bool use_blobs = false;

// Global flag is used to indicate that we want to obfuscate identifiers.
static bool obfuscate = false;

// Value of the --save-obfuscation-map= flag.
static const char* obfuscation_map_filename = NULL;

// Global flag that is used to indicate that we want to trace resolution of
// URIs and the loading of libraries, parts and scripts.
static bool trace_loading = false;
Expand Down Expand Up @@ -378,6 +384,23 @@ static bool ProcessUseBlobsOption(const char* arg,
return true;
}

static bool ProcessObfuscateOption(const char* arg,
CommandLineOptions* vm_options) {
ASSERT(arg != NULL);
if (*arg != '\0') {
return false;
}
obfuscate = true;
return true;
}

static bool ProcessObfuscationMapFilenameOption(
const char* filename,
CommandLineOptions* vm_options) {
obfuscation_map_filename = filename;
return true;
}

static bool ProcessSnapshotFilenameOption(const char* filename,
CommandLineOptions* vm_options) {
snapshot_filename = filename;
Expand Down Expand Up @@ -587,6 +610,8 @@ static struct {
{"--snapshot-kind=", ProcessSnapshotKindOption},
{"--snapshot-depfile=", ProcessSnapshotDepsFilenameOption},
{"--use-blobs", ProcessUseBlobsOption},
{"--obfuscate", ProcessObfuscateOption},
{"--save-obfuscation-map=", ProcessObfuscationMapFilenameOption},
{"--save-compilation-trace=", ProcessSaveCompilationTraceOption},
{"--load-compilation-trace=", ProcessLoadCompilationTraceOption},
{"--save-feedback=", ProcessSaveFeedbackOption},
Expand Down Expand Up @@ -1414,16 +1439,77 @@ static void ReadFile(const char* filename, uint8_t** buffer, intptr_t* size) {
file->Release();
}

static Dart_QualifiedFunctionName standalone_entry_points[] = {
// Functions.
{"dart:_builtin", "::", "_getPrintClosure"},
{"dart:_builtin", "::", "_libraryFilePath"},
{"dart:_builtin", "::", "_resolveInWorkingDirectory"},
{"dart:_builtin", "::", "_setPackageRoot"},
{"dart:_builtin", "::", "_setPackagesMap"},
{"dart:_builtin", "::", "_setWorkingDirectory"},
{"dart:async", "::", "_setScheduleImmediateClosure"},
{"dart:io", "::", "_getWatchSignalInternal"},
{"dart:io", "::", "_getUriBaseClosure"},
{"dart:io", "::", "_makeDatagram"},
{"dart:io", "::", "_makeUint8ListView"},
{"dart:io", "::", "_setupHooks"},
{"dart:io", "CertificateException", "CertificateException."},
{"dart:io", "Directory", "Directory."},
{"dart:io", "File", "File."},
{"dart:io", "FileSystemException", "FileSystemException."},
{"dart:io", "HandshakeException", "HandshakeException."},
{"dart:io", "Link", "Link."},
{"dart:io", "OSError", "OSError."},
{"dart:io", "TlsException", "TlsException."},
{"dart:io", "X509Certificate", "X509Certificate._"},
{"dart:io", "_ExternalBuffer", "get:end"},
{"dart:io", "_ExternalBuffer", "get:start"},
{"dart:io", "_ExternalBuffer", "set:data"},
{"dart:io", "_ExternalBuffer", "set:end"},
{"dart:io", "_ExternalBuffer", "set:start"},
{"dart:io", "_Platform", "set:_nativeScript"},
{"dart:io", "_ProcessStartStatus", "set:_errorCode"},
{"dart:io", "_ProcessStartStatus", "set:_errorMessage"},
{"dart:io", "_SecureFilterImpl", "get:ENCRYPTED_SIZE"},
{"dart:io", "_SecureFilterImpl", "get:SIZE"},
{"dart:io", "_SecureFilterImpl", "get:buffers"},
{"dart:isolate", "::", "_getIsolateScheduleImmediateClosure"},
{"dart:isolate", "::", "_setupHooks"},
{"dart:isolate", "::", "_startMainIsolate"},
{"dart:vmservice_io", "::", "main"},
// Fields
{"dart:_builtin", "::", "_isolateId"},
{"dart:_builtin", "::", "_loadPort"},
{"dart:_internal", "::", "_printClosure"},
{"dart:vmservice_io", "::", "_autoStart"},
{"dart:vmservice_io", "::", "_ip"},
{"dart:vmservice_io", "::", "_isFuchsia"},
{"dart:vmservice_io", "::", "_isWindows"},
{"dart:vmservice_io", "::", "_originCheckDisabled"},
{"dart:vmservice_io", "::", "_port"},
{"dart:vmservice_io", "::", "_signalWatch"},
{"dart:vmservice_io", "::", "_traceLoading"},
{NULL, NULL, NULL} // Must be terminated with NULL entries.
};

bool RunMainIsolate(const char* script_name, CommandLineOptions* dart_options) {
// Call CreateIsolateAndSetup which creates an isolate and loads up
// the specified application script.
char* error = NULL;
bool is_main_isolate = true;
int exit_code = 0;
char* isolate_name = BuildIsolateName(script_name, "main");
Dart_IsolateFlags flags;
Dart_IsolateFlagsInitialize(&flags);

if (gen_snapshot_kind == kAppAOT) {
flags.obfuscate = obfuscate;
flags.entry_points = standalone_entry_points;
}

Dart_Isolate isolate = CreateIsolateAndSetupHelper(
is_main_isolate, script_name, "main", commandline_package_root,
commandline_packages_file, NULL, &error, &exit_code);
commandline_packages_file, &flags, &error, &exit_code);
if (isolate == NULL) {
delete[] isolate_name;
Log::PrintErr("%s\n", error);
Expand Down Expand Up @@ -1497,46 +1583,6 @@ bool RunMainIsolate(const char* script_name, CommandLineOptions* dart_options) {
}

if (gen_snapshot_kind == kAppAOT) {
Dart_QualifiedFunctionName standalone_entry_points[] = {
{"dart:_builtin", "::", "_getPrintClosure"},
{"dart:_builtin", "::", "_libraryFilePath"},
{"dart:_builtin", "::", "_resolveInWorkingDirectory"},
{"dart:_builtin", "::", "_setPackageRoot"},
{"dart:_builtin", "::", "_setPackagesMap"},
{"dart:_builtin", "::", "_setWorkingDirectory"},
{"dart:async", "::", "_setScheduleImmediateClosure"},
{"dart:io", "::", "_getWatchSignalInternal"},
{"dart:io", "::", "_getUriBaseClosure"},
{"dart:io", "::", "_makeDatagram"},
{"dart:io", "::", "_makeUint8ListView"},
{"dart:io", "::", "_setupHooks"},
{"dart:io", "CertificateException", "CertificateException."},
{"dart:io", "Directory", "Directory."},
{"dart:io", "File", "File."},
{"dart:io", "FileSystemException", "FileSystemException."},
{"dart:io", "HandshakeException", "HandshakeException."},
{"dart:io", "Link", "Link."},
{"dart:io", "OSError", "OSError."},
{"dart:io", "TlsException", "TlsException."},
{"dart:io", "X509Certificate", "X509Certificate._"},
{"dart:io", "_ExternalBuffer", "get:end"},
{"dart:io", "_ExternalBuffer", "get:start"},
{"dart:io", "_ExternalBuffer", "set:data"},
{"dart:io", "_ExternalBuffer", "set:end"},
{"dart:io", "_ExternalBuffer", "set:start"},
{"dart:io", "_Platform", "set:_nativeScript"},
{"dart:io", "_ProcessStartStatus", "set:_errorCode"},
{"dart:io", "_ProcessStartStatus", "set:_errorMessage"},
{"dart:io", "_SecureFilterImpl", "get:ENCRYPTED_SIZE"},
{"dart:io", "_SecureFilterImpl", "get:SIZE"},
{"dart:io", "_SecureFilterImpl", "get:buffers"},
{"dart:isolate", "::", "_getIsolateScheduleImmediateClosure"},
{"dart:isolate", "::", "_setupHooks"},
{"dart:isolate", "::", "_startMainIsolate"},
{"dart:vmservice_io", "::", "main"},
{NULL, NULL, NULL} // Must be terminated with NULL entries.
};

uint8_t* feedback_buffer = NULL;
intptr_t feedback_length = 0;
if (load_feedback_filename != NULL) {
Expand All @@ -1558,6 +1604,14 @@ bool RunMainIsolate(const char* script_name, CommandLineOptions* dart_options) {
free(feedback_buffer);
}
CHECK_RESULT(result);

if (obfuscate && obfuscation_map_filename != NULL) {
uint8_t* buffer = NULL;
intptr_t size = 0;
result = Dart_GetObfuscationMap(&buffer, &size);
CHECK_RESULT(result);
WriteFile(obfuscation_map_filename, buffer, size);
}
}

if (gen_snapshot_kind == kAppAOT) {
Expand Down
33 changes: 26 additions & 7 deletions runtime/include/dart_api.h
Expand Up @@ -532,6 +532,12 @@ DART_EXPORT void Dart_DeleteWeakPersistentHandle(
*/
DART_EXPORT const char* Dart_VersionString();

typedef struct {
const char* library_uri;
const char* class_name;
const char* function_name;
} Dart_QualifiedFunctionName;

/**
* Isolate specific flags are set when creating a new isolate using the
* Dart_IsolateFlags structure.
Expand All @@ -540,7 +546,7 @@ DART_EXPORT const char* Dart_VersionString();
* for each part.
*/

#define DART_FLAGS_CURRENT_VERSION (0x00000003)
#define DART_FLAGS_CURRENT_VERSION (0x00000004)

typedef struct {
int32_t version;
Expand All @@ -551,8 +557,15 @@ typedef struct {
bool use_field_guards;
bool use_osr;
bool use_dart_frontend;
bool obfuscate;
Dart_QualifiedFunctionName* entry_points;
} Dart_IsolateFlags;

/**
* Initialize Dart_IsolateFlags with correct version and default values.
*/
DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags);

/**
* An isolate creation and initialization callback function.
*
Expand Down Expand Up @@ -3149,12 +3162,6 @@ DART_EXPORT Dart_Handle Dart_LoadCompilationTrace(uint8_t* buffer,
DART_EXPORT Dart_Handle Dart_SaveJITFeedback(uint8_t** buffer,
intptr_t* buffer_length);

typedef struct {
const char* library_uri;
const char* class_name;
const char* function_name;
} Dart_QualifiedFunctionName;

/**
* Compiles all functions reachable from the provided entry points and marks
* the isolate to disallow future compilation.
Expand Down Expand Up @@ -3280,6 +3287,18 @@ DART_EXPORT Dart_Handle Dart_CreateCoreJITSnapshotAsBlobs(
uint8_t** isolate_snapshot_instructions_buffer,
intptr_t* isolate_snapshot_instructions_size);

/**
* Get obfuscation map for precompiled code.
*
* Obfuscation map is encoded as a JSON array of pairs (original name,
* obfuscated name).
*
* \return Returns an error handler if the VM was built in a mode that does not
* support obfuscation.
*/
DART_EXPORT Dart_Handle Dart_GetObfuscationMap(uint8_t** buffer,
intptr_t* buffer_length);

/**
* Returns whether the VM only supports running from precompiled snapshots and
* not from any other kind of snapshot or from source (that is, the VM was
Expand Down
5 changes: 5 additions & 0 deletions runtime/tests/vm/vm.status
Expand Up @@ -444,3 +444,8 @@ cc/Parser_AllocateVariables_Issue7681: Crash
cc/Parser_AllocateVariables_MiddleChain: Crash
cc/Parser_AllocateVariables_NestedCapturedVar: Crash
cc/Parser_AllocateVariables_TwoChains: Crash

[ $runtime == dart_precompiled && $minified ]
dart/inline_stack_frame_test: Skip
dart/optimized_stacktrace_line_test: Skip

6 changes: 6 additions & 0 deletions runtime/vm/class_finalizer.cc
Expand Up @@ -3468,6 +3468,12 @@ void ClassFinalizer::VerifyImplicitFieldOffsets() {
#ifdef DEBUG
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();

if (isolate->obfuscate()) {
// Field names are obfuscated.
return;
}

Zone* zone = thread->zone();
const ClassTable& class_table = *(isolate->class_table());
Class& cls = Class::Handle(zone);
Expand Down
45 changes: 45 additions & 0 deletions runtime/vm/dart_api_impl.cc
Expand Up @@ -1162,6 +1162,10 @@ static Dart_Isolate CreateIsolate(const char* script_uri,
return reinterpret_cast<Dart_Isolate>(NULL);
}

DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags) {
Isolate::FlagsInitialize(flags);
}

DART_EXPORT Dart_Isolate
Dart_CreateIsolate(const char* script_uri,
const char* main,
Expand Down Expand Up @@ -6693,6 +6697,47 @@ Dart_CreateAppJITSnapshotAsBlobs(uint8_t** isolate_snapshot_data_buffer,
#endif
}

DART_EXPORT Dart_Handle Dart_GetObfuscationMap(uint8_t** buffer,
intptr_t* buffer_length) {
#if defined(DART_PRECOMPILED_RUNTIME)
return Api::NewError("No obfuscation map to save on an AOT runtime.");
#elif !defined(DART_PRECOMPILER)
return Api::NewError("Obfuscation is only supported for AOT compiler.");
#else
Thread* thread = Thread::Current();
DARTSCOPE(thread);
Isolate* isolate = thread->isolate();

if (buffer == NULL) {
RETURN_NULL_ERROR(buffer);
}
if (buffer_length == NULL) {
RETURN_NULL_ERROR(buffer_length);
}

// Note: can't use JSONStream in PRODUCT builds.
const intptr_t kInitialBufferSize = 1 * MB;
TextBuffer text_buffer(kInitialBufferSize);

text_buffer.AddChar('[');
if (isolate->obfuscation_map() != NULL) {
for (intptr_t i = 0; isolate->obfuscation_map()[i] != NULL; i++) {
if (i > 0) {
text_buffer.AddChar(',');
}
text_buffer.AddChar('"');
text_buffer.AddEscapedString(isolate->obfuscation_map()[i]);
text_buffer.AddChar('"');
}
}
text_buffer.AddChar(']');

*buffer_length = text_buffer.length();
*reinterpret_cast<char**>(buffer) = text_buffer.Steal();
return Api::Success();
#endif
}

DART_EXPORT bool Dart_IsPrecompiledRuntime() {
#if defined(DART_PRECOMPILED_RUNTIME)
return true;
Expand Down
5 changes: 4 additions & 1 deletion runtime/vm/intrinsifier.cc
Expand Up @@ -88,7 +88,10 @@ void Intrinsifier::InitializeState() {
} \
func = cls.LookupFunctionAllowPrivate(str); \
} \
ASSERT(!func.IsNull()); \
if (func.IsNull()) { \
FATAL2("Intrinsifier failed to find method %s in class %s\n", \
#function_name, #class_name); \
} \
func.set_is_intrinsic(true);

// Set up all core lib functions that can be intrinsified.
Expand Down

0 comments on commit 7d52317

Please sign in to comment.