Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

add support for passing context

  • Loading branch information...
commit 62b81355a1f283a3ef60dbabad8ff5df9ecb48f0 1 parent 4225f18
@tjanczuk authored
View
18 README.md
@@ -31,6 +31,24 @@ while(true);
tripwire.clearTripwire();
```
+When the event loop is blocked for longer than the time specified in the call to `resetTripwire`, tripwire will terminate execution of the script. Node.js will subsequently execute the `uncaughtException` handler if one is registered. The exception passed to `uncaughtException` handler will be `null` in that case. In order to determine whether the exception was indeed caused by tripwire, an optional context can be established during a call to `resetTripwire` and retrtieved with a call to `getContext`. The `getContext` will return `undefined` if the tripwire had not been triggered.
+
+```javascript
+var tripwire = require('tripwire');
+
+process.on('uncaughtException', function (e) {
+ if (undefined === tripwire.getContext())
+ console.log('The exception was not caused by tripwire.');
+ else
+ console.log('The event loop was blocked for longer than 2000 milliseconds');
+ process.exit(1);
+});
+
+// set the limit of execution time to 2000 milliseconds
+var context = { someData: "foobar" };
+tripwire.resetTripwire(2000, context);
+```
+
For more samples, see [here](https://github.com/tjanczuk/tripwire/tree/master/samples).
#### Running tests
View
BIN  lib/native/windows/x86/tripwire.node
Binary file not shown
View
12 samples/sample_sandboxing.js
@@ -10,12 +10,20 @@ var untrustedCode = function () {
process.on('uncaughtException', function (e) {
// This code will execute so you can do some logging.
// Note that untrusted code should be prevented from registring to this event.
- console.log('[Albert] Sorry Malcolm, but you overstayed your welcome.');
+
+ // If tripwire caused this exception, tripwire.getContext() will return the
+ // context object passed to tripwire.resetTripwire.
+
+ var context = tripwire.getContext();
+ if (context)
+ console.log('[Albert] Sorry ' + context.codeOwner + ', but you overstayed your welcome.');
+
process.exit(1);
});
// Terminate the process if the even loop is not responding within 2-4 seconds
-tripwire.resetTripwire(2000);
+var context = { codeOwner: 'Malcolm' };
+tripwire.resetTripwire(2000, context);
// Now execute some untusted code
untrustedCode();
View
50 src/tripwire.cc
@@ -8,6 +8,8 @@ HANDLE scriptThread;
DWORD tripwireThreshold;
HANDLE tripwireThread;
HANDLE event;
+Persistent<Value> context;
+BOOL terminated;
void tripwireWorker(void* data)
{
@@ -68,19 +70,41 @@ void tripwireWorker(void* data)
// (tripwireThreshold, 2 * tripwireThreshold) range of CPU utilization.
if (elapsedMs >= tripwireThreshold)
+ {
+ terminated = TRUE;
V8::TerminateExecution();
+ }
else
+ {
skipTimeCapture = TRUE;
+ }
}
}
}
}
+Handle<Value> clearTripwire(const Arguments& args)
+{
+ HandleScope scope;
+
+ // Seting tripwireThreshold to 0 indicates to the worker process that
+ // there is no threshold to enforce. The worker process will make this determination
+ // next time it is signalled, there is no need to force an extra context switch here
+ // by explicit signalling.
+
+ tripwireThreshold = 0;
+ terminated = FALSE;
+ context.Dispose();
+ context.Clear();
+
+ return Undefined();
+}
+
Handle<Value> resetTripwire(const Arguments& args)
{
HandleScope scope;
- if (1 != args.Length() || !args[0]->IsUint32())
+ if (0 == args.Length() || !args[0]->IsUint32())
return ThrowException(Exception::Error(String::New(
"First agument must be an integer time threshold in milliseconds.")));
@@ -88,7 +112,13 @@ Handle<Value> resetTripwire(const Arguments& args)
return ThrowException(Exception::Error(String::New(
"The time threshold for blocking operations must be greater than 0.")));
+ clearTripwire(args);
+
tripwireThreshold = args[0]->ToUint32()->Value();
+ if (args.Length() > 1)
+ {
+ context = Persistent<Value>::New(args[1]);
+ }
if (NULL == tripwireThread)
{
@@ -141,25 +171,27 @@ Handle<Value> resetTripwire(const Arguments& args)
return Undefined();
}
-Handle<Value> clearTripwire(const Arguments& args)
+Handle<Value> getContext(const Arguments& args)
{
HandleScope scope;
- // Seting tripwireThreshold to 0 indicates to the worker process that
- // there is no threshold to enforce. The worker process will make this determination
- // next time it is signalled, there is no need to force an extra context switch here
- // by explicit signalling.
-
- tripwireThreshold = 0;
+ // If the script had been terminated by tripwire, returns the context passed to resetTripwire;
+ // otherwise undefined. This can be used from within the uncaughtException handler to determine
+ // whether the exception condition was caused by script termination.
- return Undefined();
+ if (terminated)
+ return context;
+ else
+ return Undefined();
}
void init(Handle<Object> target)
{
tripwireThread = scriptThread = event = NULL;
+ terminated = FALSE;
NODE_SET_METHOD(target, "resetTripwire", resetTripwire);
NODE_SET_METHOD(target, "clearTripwire", clearTripwire);
+ NODE_SET_METHOD(target, "getContext", getContext);
}
NODE_MODULE(tripwire, init);
View
43 test/tests.js
@@ -11,7 +11,6 @@ process.on('uncaughtException', function (e) {
}
else {
console.log('Unexpected uncaughtException event.');
- process.exit(1);
}
});
@@ -25,6 +24,7 @@ describe('tripwire', function () {
it('can be cleared', function (done) {
validator = function () {
+ validator = undefined;
assert.ok(false, 'tripire unexpectedly went off');
};
@@ -40,4 +40,45 @@ describe('tripwire', function () {
while(true);
});
+ it('propagates context after termination', function (done) {
+ var context = { foo: "bar" };
+ validator = function () {
+ validator = undefined;
+ assert.ok(context === tripwire.getContext(), 'the context matches');
+ done();
+ };
+ tripwire.resetTripwire(100, context);
+ while(true);
+ });
+
+ it('does not propagate context if cleared', function () {
+ tripwire.resetTripwire(50, {});
+ tripwire.clearTripwire();
+ assert.ok(undefined === tripwire.getContext(), 'no context returned from tripwire');
+ });
+
+ it('requires threshold to be positive integer', function (done) {
+ assert.throws(
+ function () { tripwire.resetTripwire(); },
+ /First agument must be an integer time threshold in milliseconds/
+ );
+
+ assert.throws(
+ function () { tripwire.resetTripwire({}); },
+ /First agument must be an integer time threshold in milliseconds/
+ );
+
+ assert.throws(
+ function () { tripwire.resetTripwire(0); },
+ /The time threshold for blocking operations must be greater than 0/
+ );
+
+ assert.throws(
+ function () { tripwire.resetTripwire(-100); },
+ /First agument must be an integer time threshold in milliseconds/
+ );
+
+ done();
+ });
+
});
Please sign in to comment.
Something went wrong with that request. Please try again.