Skip to content

Commit 6eb3a3b

Browse files
authored
fix: Harden input handling (#2163)
1 parent 5696d2c commit 6eb3a3b

51 files changed

Lines changed: 14991 additions & 7134 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bench/data/static_pbjs.js

Lines changed: 90 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ $root.Test = (function() {
1212
function Test(properties) {
1313
if (properties)
1414
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
15-
if (properties[keys[i]] != null)
15+
if (properties[keys[i]] != null && keys[i] !== "__proto__")
1616
this[keys[i]] = properties[keys[i]];
1717
}
1818

@@ -35,27 +35,37 @@ $root.Test = (function() {
3535
return writer;
3636
};
3737

38-
Test.decode = function decode(reader, length) {
38+
Test.decode = function decode(reader, length, error, long) {
3939
if (!(reader instanceof $Reader))
4040
reader = $Reader.create(reader);
41+
if (long === undefined)
42+
long = 0;
43+
if (long > $Reader.recursionLimit)
44+
throw Error("maximum nesting depth exceeded");
4145
var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Test();
4246
while (reader.pos < end) {
4347
var tag = reader.uint32();
44-
switch (tag >>> 3) {
45-
case 1:
46-
message.string = reader.string();
47-
break;
48-
case 2:
49-
message.uint32 = reader.uint32();
50-
break;
51-
case 3:
52-
message.inner = $root.Test.Inner.decode(reader, reader.uint32());
53-
break;
54-
case 4:
55-
message.float = reader.float();
48+
if (tag === error)
5649
break;
50+
switch (tag >>> 3) {
51+
case 1: {
52+
message.string = reader.string();
53+
break;
54+
}
55+
case 2: {
56+
message.uint32 = reader.uint32();
57+
break;
58+
}
59+
case 3: {
60+
message.inner = $root.Test.Inner.decode(reader, reader.uint32(), undefined, long + 1);
61+
break;
62+
}
63+
case 4: {
64+
message.float = reader.float();
65+
break;
66+
}
5767
default:
58-
reader.skipType(tag & 7);
68+
reader.skipType(tag & 7, long);
5969
break;
6070
}
6171
}
@@ -67,7 +77,7 @@ $root.Test = (function() {
6777
function Inner(properties) {
6878
if (properties)
6979
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
70-
if (properties[keys[i]] != null)
80+
if (properties[keys[i]] != null && keys[i] !== "__proto__")
7181
this[keys[i]] = properties[keys[i]];
7282
}
7383

@@ -87,24 +97,33 @@ $root.Test = (function() {
8797
return writer;
8898
};
8999

90-
Inner.decode = function decode(reader, length) {
100+
Inner.decode = function decode(reader, length, error, long) {
91101
if (!(reader instanceof $Reader))
92102
reader = $Reader.create(reader);
103+
if (long === undefined)
104+
long = 0;
105+
if (long > $Reader.recursionLimit)
106+
throw Error("maximum nesting depth exceeded");
93107
var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Test.Inner();
94108
while (reader.pos < end) {
95109
var tag = reader.uint32();
96-
switch (tag >>> 3) {
97-
case 1:
98-
message.int32 = reader.int32();
99-
break;
100-
case 2:
101-
message.innerInner = $root.Test.Inner.InnerInner.decode(reader, reader.uint32());
102-
break;
103-
case 3:
104-
message.outer = $root.Outer.decode(reader, reader.uint32());
110+
if (tag === error)
105111
break;
112+
switch (tag >>> 3) {
113+
case 1: {
114+
message.int32 = reader.int32();
115+
break;
116+
}
117+
case 2: {
118+
message.innerInner = $root.Test.Inner.InnerInner.decode(reader, reader.uint32(), undefined, long + 1);
119+
break;
120+
}
121+
case 3: {
122+
message.outer = $root.Outer.decode(reader, reader.uint32(), undefined, long + 1);
123+
break;
124+
}
106125
default:
107-
reader.skipType(tag & 7);
126+
reader.skipType(tag & 7, long);
108127
break;
109128
}
110129
}
@@ -116,7 +135,7 @@ $root.Test = (function() {
116135
function InnerInner(properties) {
117136
if (properties)
118137
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
119-
if (properties[keys[i]] != null)
138+
if (properties[keys[i]] != null && keys[i] !== "__proto__")
120139
this[keys[i]] = properties[keys[i]];
121140
}
122141

@@ -136,24 +155,33 @@ $root.Test = (function() {
136155
return writer;
137156
};
138157

139-
InnerInner.decode = function decode(reader, length) {
158+
InnerInner.decode = function decode(reader, length, error, long) {
140159
if (!(reader instanceof $Reader))
141160
reader = $Reader.create(reader);
161+
if (long === undefined)
162+
long = 0;
163+
if (long > $Reader.recursionLimit)
164+
throw Error("maximum nesting depth exceeded");
142165
var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Test.Inner.InnerInner();
143166
while (reader.pos < end) {
144167
var tag = reader.uint32();
145-
switch (tag >>> 3) {
146-
case 1:
147-
message.long = reader.int64();
148-
break;
149-
case 2:
150-
message["enum"] = reader.int32();
151-
break;
152-
case 3:
153-
message.sint32 = reader.sint32();
168+
if (tag === error)
154169
break;
170+
switch (tag >>> 3) {
171+
case 1: {
172+
message.long = reader.int64();
173+
break;
174+
}
175+
case 2: {
176+
message["enum"] = reader.int32();
177+
break;
178+
}
179+
case 3: {
180+
message.sint32 = reader.sint32();
181+
break;
182+
}
155183
default:
156-
reader.skipType(tag & 7);
184+
reader.skipType(tag & 7, long);
157185
break;
158186
}
159187
}
@@ -185,7 +213,7 @@ $root.Outer = (function() {
185213
this.bool = [];
186214
if (properties)
187215
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
188-
if (properties[keys[i]] != null)
216+
if (properties[keys[i]] != null && keys[i] !== "__proto__")
189217
this[keys[i]] = properties[keys[i]];
190218
}
191219

@@ -206,28 +234,36 @@ $root.Outer = (function() {
206234
return writer;
207235
};
208236

209-
Outer.decode = function decode(reader, length) {
237+
Outer.decode = function decode(reader, length, error, long) {
210238
if (!(reader instanceof $Reader))
211239
reader = $Reader.create(reader);
240+
if (long === undefined)
241+
long = 0;
242+
if (long > $Reader.recursionLimit)
243+
throw Error("maximum nesting depth exceeded");
212244
var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Outer();
213245
while (reader.pos < end) {
214246
var tag = reader.uint32();
247+
if (tag === error)
248+
break;
215249
switch (tag >>> 3) {
216-
case 1:
217-
if (!(message.bool && message.bool.length))
218-
message.bool = [];
219-
if ((tag & 7) === 2) {
220-
var end2 = reader.uint32() + reader.pos;
221-
while (reader.pos < end2)
250+
case 1: {
251+
if (!(message.bool && message.bool.length))
252+
message.bool = [];
253+
if ((tag & 7) === 2) {
254+
var end2 = reader.uint32() + reader.pos;
255+
while (reader.pos < end2)
256+
message.bool.push(reader.bool());
257+
} else
222258
message.bool.push(reader.bool());
223-
} else
224-
message.bool.push(reader.bool());
225-
break;
226-
case 2:
227-
message.double = reader.double();
228-
break;
259+
break;
260+
}
261+
case 2: {
262+
message.double = reader.double();
263+
break;
264+
}
229265
default:
230-
reader.skipType(tag & 7);
266+
reader.skipType(tag & 7, long);
231267
break;
232268
}
233269
}

cli/targets/static.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,12 @@ function exportName(object, asInterface) {
9797
function escapeName(name) {
9898
if (!name)
9999
return "$root";
100-
return util.isReserved(name) ? name + "_" : name;
100+
name = name.replace(/\W/g, "");
101+
if (!name)
102+
return "_";
103+
if (/^\d/.test(name))
104+
name = "_" + name;
105+
return util.patterns.reservedRe.test(name) ? name + "_" : name;
101106
}
102107

103108
function aOrAn(name) {

ext/descriptor/index.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as $protobuf from "../..";
2+
import Long = require("long");
23
export const FileDescriptorSet: $protobuf.Type;
34

45
export const FileDescriptorProto: $protobuf.Type;
@@ -73,8 +74,11 @@ export interface IFileDescriptorProto {
7374
options?: IFileOptions;
7475
sourceCodeInfo?: any;
7576
syntax?: string;
77+
edition?: IEdition;
7678
}
7779

80+
type IEdition = number;
81+
7882
export interface IFileOptions {
7983
javaPackage?: string;
8084
javaOuterClassname?: string;

ext/descriptor/index.js

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ var Namespace = $protobuf.Namespace,
1010
MapField = $protobuf.MapField,
1111
OneOf = $protobuf.OneOf,
1212
Service = $protobuf.Service,
13-
Method = $protobuf.Method;
13+
Method = $protobuf.Method,
14+
patterns = $protobuf.util.patterns;
15+
16+
var numberRe = patterns.numberRe,
17+
typeRefRe = patterns.typeRefRe;
1418

1519
// --- Root ---
1620

@@ -393,9 +397,6 @@ Type.prototype.toDescriptor = function toDescriptor(edition) {
393397
* @property {number} JS_NUMBER=2
394398
*/
395399

396-
// copied here from parse.js
397-
var numberRe = /^(?![eE])[0-9]*(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?$/;
398-
399400
/**
400401
* Creates a field from a descriptor.
401402
*
@@ -416,10 +417,13 @@ Field.fromDescriptor = function fromDescriptor(descriptor, edition, nested) {
416417
throw Error("missing field id");
417418

418419
// Rewire field type
419-
var fieldType;
420-
if (descriptor.typeName && descriptor.typeName.length)
421-
fieldType = descriptor.typeName;
422-
else
420+
var typeName = descriptor.typeName,
421+
fieldType;
422+
if (typeName != null && typeName !== "") {
423+
if (typeof typeName !== "string" || !typeRefRe.test(typeName))
424+
throw Error("illegal type name: " + typeName);
425+
fieldType = typeName;
426+
} else
423427
fieldType = fromDescriptorType(descriptor.type);
424428

425429
// Rewire field rule
@@ -432,10 +436,12 @@ Field.fromDescriptor = function fromDescriptor(descriptor, edition, nested) {
432436
default: throw Error("illegal label: " + descriptor.label);
433437
}
434438

435-
var extendee = descriptor.extendee;
436-
if (descriptor.extendee !== undefined) {
437-
extendee = extendee.length ? extendee : undefined;
438-
}
439+
var extendee = descriptor.extendee;
440+
if (extendee != null && extendee !== "") {
441+
if (typeof extendee !== "string" || !typeRefRe.test(extendee))
442+
throw Error("illegal type name: " + extendee);
443+
} else
444+
extendee = undefined;
439445
var field = new Field(
440446
descriptor.name.length ? descriptor.name : "field" + descriptor.number,
441447
descriptor.number,
@@ -763,12 +769,24 @@ Method.fromDescriptor = function fromDescriptor(descriptor) {
763769
if (typeof descriptor.length === "number")
764770
descriptor = exports.MethodDescriptorProto.decode(descriptor);
765771

772+
var inputType = descriptor.inputType,
773+
outputType = descriptor.outputType;
774+
775+
if (inputType != null && inputType !== "") {
776+
if (typeof inputType !== "string" || !typeRefRe.test(inputType))
777+
throw Error("illegal type name: " + inputType);
778+
}
779+
if (outputType != null && outputType !== "") {
780+
if (typeof outputType !== "string" || !typeRefRe.test(outputType))
781+
throw Error("illegal type name: " + outputType);
782+
}
783+
766784
return new Method(
767785
// unnamedMethodIndex is global, not per service, because we have no ref to a service here
768786
descriptor.name && descriptor.name.length ? descriptor.name : "Method" + unnamedMethodIndex++,
769787
"rpc",
770-
descriptor.inputType,
771-
descriptor.outputType,
788+
inputType,
789+
outputType,
772790
Boolean(descriptor.clientStreaming),
773791
Boolean(descriptor.serverStreaming),
774792
fromDescriptorOptions(descriptor.options, exports.MethodOptions)

0 commit comments

Comments
 (0)