Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1350)

Unified Diff: mojo/public/js/bindings/validator.js

Issue 468713002: JavaScript bindings for Mojo message validation (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Skip unexpected null tests" Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: mojo/public/js/bindings/validator.js
diff --git a/mojo/public/js/bindings/validator.js b/mojo/public/js/bindings/validator.js
index eac95d93d41c85fec85a2e8cd599c76123a2c0a7..837f85a37df59b15758ea8286b91c726c416c998 100644
--- a/mojo/public/js/bindings/validator.js
+++ b/mojo/public/js/bindings/validator.js
@@ -4,7 +4,7 @@
define("mojo/public/js/bindings/validator", [
"mojo/public/js/bindings/codec",
- ], function(codec) {
+], function(codec) {
var validationError = {
NONE: 'VALIDATION_ERROR_NONE',
@@ -20,15 +20,22 @@ define("mojo/public/js/bindings/validator", [
'VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID'
};
+ var NULL_MOJO_POINTER = "NULL_MOJO_POINTER";
+
function Validator(message) {
this.message = message;
this.offset = 0;
+ this.handleIndex = 0;
}
Object.defineProperty(Validator.prototype, "offsetLimit", {
get: function() { return this.message.buffer.byteLength; }
});
+ Object.defineProperty(Validator.prototype, "handleIndexLimit", {
+ get: function() { return this.message.handles.length; }
+ });
+
// True if we can safely allocate a block of bytes from start to
// to start + numBytes.
Validator.prototype.isValidRange = function(start, numBytes) {
@@ -54,6 +61,25 @@ define("mojo/public/js/bindings/validator", [
return false;
}
+ Validator.prototype.claimHandle = function(index) {
+ if (index === codec.kEncodedInvalidHandleValue)
+ return true;
+
+ if (index < this.handleIndex || index >= this.handleIndexLimit)
+ return false;
+
+ // This is safe because handle indices are uint32.
+ this.handleIndex = index + 1;
+ return true;
+ }
+
+ Validator.prototype.validateHandle = function(offset) {
+ var index = this.message.buffer.getUint32(offset);
+ if (!this.claimHandle(index))
+ return validationError.ILLEGAL_HANDLE;
+ return validationError.NONE;
+ }
+
Validator.prototype.validateStructHeader =
function(offset, minNumBytes, minNumFields) {
if (!codec.isAligned(offset))
@@ -75,6 +101,10 @@ define("mojo/public/js/bindings/validator", [
}
Validator.prototype.validateMessageHeader = function() {
+ var err = this.validateStructHeader(0, codec.kMessageHeaderSize, 2);
+ if (err != validationError.NONE)
+ return err;
+
var numBytes = this.message.getHeaderNumBytes();
var numFields = this.message.getHeaderNumFields();
@@ -99,12 +129,126 @@ define("mojo/public/js/bindings/validator", [
return validationError.NONE;
}
- Validator.prototype.validateMessage = function() {
- var err = this.validateStructHeader(0, codec.kStructHeaderSize, 2);
- if (err != validationError.NONE)
- return err;
+ // Returns the message.buffer relative offset this pointer "points to",
+ // NULL_MOJO_POINTER if the pointer represents a null, or JS null if the
+ // pointer's value is not valid.
+ Validator.prototype.decodePointer = function(offset) {
+ var pointerValue = this.message.buffer.getUint64(offset);
+ if (pointerValue === 0)
+ return NULL_MOJO_POINTER;
+ var bufferOffset = offset + pointerValue;
+ return Number.isSafeInteger(bufferOffset) ? bufferOffset : null;
+ }
+
+ Validator.prototype.validateArrayPointer =
+ function(offset, elementSize, expectedElementCount, elementType) {
+ var arrayOffset = this.decodePointer(offset);
+ if (arrayOffset === null)
+ return validationError.ILLEGAL_POINTER;
+ if (arrayOffset === NULL_MOJO_POINTER)
+ return validationError.NONE;
+ return this.validateArray(
+ arrayOffset, elementSize, expectedElementCount, elementType);
+ }
- return this.validateMessageHeader();
+ Validator.prototype.validateStructPointer = function(offset, structClass) {
+ var structOffset = this.decodePointer(offset);
+ if (structOffset === null)
+ return validationError.ILLEGAL_POINTER;
+ if (structOffset === NULL_MOJO_POINTER)
+ return validationError.NONE;
+ return structClass.validate(this, structOffset);
+ }
+
+ Validator.prototype.validateStringPointer = function(offset) {
+ return this.validateArrayPointer(
+ offset, codec.Uint8.encodedSize, 0, codec.Uint8);
+ }
+
+ // Similar to Array_Data<T>::Validate()
+ // mojo/public/cpp/bindings/lib/array_internal.h
+
+ Validator.prototype.validateArray =
+ function (offset, elementSize, expectedElementCount, elementType) {
+ if (!codec.isAligned(offset))
+ return validationError.MISALIGNED_OBJECT;
+
+ if (!this.isValidRange(offset, codec.kArrayHeaderSize))
+ return validationError.ILLEGAL_MEMORY_RANGE;
+
+ var numBytes = this.message.buffer.getUint32(offset);
+ var numElements = this.message.buffer.getUint32(offset + 4);
+
+ // Note: this computation is "safe" because elementSize <= 8 and
+ // numElements is a uint32.
+ var elementsTotalSize = (elementType === codec.PackedBool) ?
+ Math.ceil(numElements / 8) : (elementSize * numElements);
+
+ if (numBytes < codec.kArrayHeaderSize + elementsTotalSize)
+ return validationError.UNEXPECTED_ARRAY_HEADER;
+
+ if (expectedElementCount != 0 && numElements != expectedElementCount)
+ return validationError.UNEXPECTED_ARRAY_HEADER;
+
+ if (!this.claimRange(offset, numBytes))
+ return validationError.ILLEGAL_MEMORY_RANGE;
+
+ // Validate the array's elements if they are pointers or handles.
+
+ var elementsOffset = offset + codec.kArrayHeaderSize;
+ if (elementType === codec.Handle)
+ return this.validateHandleElements(elementsOffset, numElements);
+ if (elementType instanceof codec.PointerTo)
+ return this.validateStructElements(
+ elementsOffset, numElements, elementType.cls);
+ if (elementType instanceof codec.String)
+ return this.validateArrayElements(
+ elementsOffset, numElements, codec.Uint8);
+ if (elementType instanceof codec.ArrayOf)
+ return this.validateArrayElements(
+ elementsOffset, numElements, elementType.cls);
+
+ return validationError.NONE;
+ }
+
+ // Note: the |offset + i * elementSize| computation in the validateFooElements
+ // methods below is "safe" because elementSize <= 8, offset and
+ // numElements are uint32, and 0 <= i < numElements.
+
+ Validator.prototype.validateHandleElements = function(offset, numElements) {
+ var elementSize = codec.Handle.encodedSize;
+ for (var i = 0; i < numElements; i++) {
+ var index = this.message.buffer.getUint32(offset + i * elementSize);
+ if (!this.claimHandle(index))
+ return validationError.ILLEGAL_HANDLE;
+ }
+ return validationError.NONE;
+ }
+
+ // The elementClass parameter is the element type of the element arrays.
+ Validator.prototype.validateArrayElements =
+ function(offset, numElements, elementClass) {
+ var elementSize = codec.PointerTo.prototype.encodedSize;
+ for (var i = 0; i < numElements; i++) {
+ var elementOffset = offset + i * elementSize;
+ var err = this.validateArrayPointer(
+ elementOffset, elementClass.encodedSize, 0, elementClass);
+ if (err != validationError.NONE)
+ return err;
+ }
+ return validationError.NONE;
+ }
+
+ Validator.prototype.validateStructElements =
+ function(offset, numElements, structClass) {
+ var elementSize = codec.PointerTo.prototype.encodedSize;
+ for (var i = 0; i < numElements; i++) {
+ var elementOffset = offset + i * elementSize;
+ var err = this.validateStructPointer(elementOffset, structClass);
+ if (err != validationError.NONE)
+ return err;
+ }
+ return validationError.NONE;
}
var exports = {};

Powered by Google App Engine
This is Rietveld 408576698