Skip to content

Commit

Permalink
Fix race conditions for reboot, snapshotting and restoring.
Browse files Browse the repository at this point in the history
This is necessary for running some of these tests in an onsite
scenario where the http calls are exceptionally fast.
  • Loading branch information
strazzere committed Nov 10, 2021
1 parent e53258f commit c55b6a9
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 19 deletions.
71 changes: 54 additions & 17 deletions src/instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,10 @@ class Instance extends EventEmitter {
method: "POST",
json: { name },
});

await this.waitForUserTask("snapshot");
await this.waitForUserTask(null);

return new Snapshot(this, snapshot);
}

Expand All @@ -281,7 +285,8 @@ class Instance extends EventEmitter {
return await response.text();
}

/** Return an array of recorded kernel panics.
/**
* Return an array of recorded kernel panics.
* @return {Promise<PanicInfo[]>}
* @example
* const instances = await project.instances();
Expand All @@ -292,7 +297,8 @@ class Instance extends EventEmitter {
return await this._fetch("/panics");
}

/** Clear the recorded kernel panics of this instance.
/**
* Clear the recorded kernel panics of this instance.
* @example
* const instances = await project.instances();
* const instance = instances.find(instance => instance.name == 'foo');
Expand Down Expand Up @@ -497,47 +503,55 @@ class Instance extends EventEmitter {
await this._fetch("/input", { method: "POST", json: input.points });
}

/** Start this instance.
/**
* Start this instance.
* @example
* await instance.start();
*/
async start() {
await this._fetch("/start", { method: "POST" });
}

/** Stop this instance.
/**
* Stop this instance.
* @example
* await instance.stop();
*/
async stop() {
await this._fetch("/stop", { method: "POST" });
}

/** Pause this instance
/**
* Pause this instance
* @example
* await instance.pause();
*/
async pause() {
await this._fetch("/pause", { method: "POST" });
}

/** Unpause this instance
/**
* Unpause this instance
* @example
* await instance.unpause();
*/
async unpause() {
await this._fetch("/unpause", { method: "POST" });
}

/** Reboot this instance.
/**
* Reboot this instance.
* @example
* await instance.reboot();
*/
async reboot() {
await this._fetch("/reboot", { method: "POST" });
await this.waitForTaskState("rebooting");
await this.waitForTaskState("none");
}

/** Destroy this instance.
/**
* Destroy this instance.
* @example <caption>delete all instances of the project</caption>
* let instances = await project.instances();
* instances.forEach(instance => {
Expand All @@ -548,7 +562,8 @@ class Instance extends EventEmitter {
await this._fetch("", { method: "DELETE" });
}

/** Get CoreTrace Thread List
/**
* Get CoreTrace Thread List
* @return {Promise<ThreadInfo[]>}
* @example
* let procList = await instance.getCoreTraceThreadList();
Expand All @@ -563,7 +578,8 @@ class Instance extends EventEmitter {
return await this._fetch("/strace/thread-list", { method: "GET" });
}

/** Add List of PIDs/Names/TIDs to CoreTrace filter
/**
* Add List of PIDs/Names/TIDs to CoreTrace filter
* @param {integer[]} pids - array of process IDs to filter
* @param {string[]} names - array of process names to filter
* @param {integer[]} tids - array of thread IDs to filter
Expand Down Expand Up @@ -593,31 +609,35 @@ class Instance extends EventEmitter {
await this._fetch("", { method: "PATCH", json: { straceFilter: filter } });
}

/** Clear CoreTrace filter
/**
* Clear CoreTrace filter
* @example
* await instance.clearCoreTraceFilter();
*/
async clearCoreTraceFilter() {
await this._fetch("", { method: "PATCH", json: { straceFilter: [] } });
}

/** Start CoreTrace
/**
* Start CoreTrace
* @example
* await instance.startCoreTrace();
*/
async startCoreTrace() {
await this._fetch("/strace/enable", { method: "POST" });
}

/** Stop CoreTrace
/**
* Stop CoreTrace
* @example
* await instance.stopCoreTrace();
*/
async stopCoreTrace() {
await this._fetch("/strace/disable", { method: "POST" });
}

/** Download CoreTrace Log
/**
* Download CoreTrace Log
* @example
* let trace = await instance.downloadCoreTraceLog();
* console.log(trace.toString());
Expand All @@ -632,7 +652,8 @@ class Instance extends EventEmitter {
return await response.buffer();
}

/** Clean CoreTrace log
/**
* Clean CoreTrace log
* @example
* await instance.clearCoreTraceLog();
*/
Expand Down Expand Up @@ -660,7 +681,8 @@ class Instance extends EventEmitter {
return fridaConsole;
}

/** Execute FRIDA script by name
/**
* Execute FRIDA script by name
* @param {string} filePath - path to FRIDA script
* @example
* await instance.executeFridaScript("/data/corellium/frida/scripts/script.js");
Expand Down Expand Up @@ -780,7 +802,8 @@ class Instance extends EventEmitter {
});
}

/** Wait for the instance to finish restoring and start its first boot.
/**
* Wait for the instance to finish restoring and start its first boot.
* @example <caption>Wait for VM to finish restore</caption>
* instance.finishRestore();
*/
Expand All @@ -806,6 +829,20 @@ class Instance extends EventEmitter {
await this._waitFor(() => this.taskState === taskName);
}

/**
* Wait for the instance user task name to be a given state.
* @param {string} userTaskName
*/
async waitForUserTask(userTaskName) {
await this._waitFor(() => {
if (!userTaskName) {
return !this.userTask;
} else {
return this.userTask.name === userTaskName;
}
});
}

async _fetch(endpoint = "", options = {}) {
return await fetchApi(this.project, `/instances/${this.id}${endpoint}`, options);
}
Expand Down
2 changes: 2 additions & 0 deletions src/snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ class Snapshot {
*/
async restore() {
await this._fetch(`/restore`, { method: "POST" });
await this.instance.waitForTaskState("reverting");
await this.instance.waitForTaskState("none");
}

/**
Expand Down
2 changes: 0 additions & 2 deletions test/integration-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -394,8 +394,6 @@ describe("Corellium API", function () {
it("can reboot", async function () {
const instance = instanceMap.get(instanceVersion);
await instance.reboot();
await instance.waitForTaskState("rebooting");
await instance.waitForTaskState("none");
});

it("can stop", async function () {
Expand Down

0 comments on commit c55b6a9

Please sign in to comment.