From 6b12612a52d83b98bc0e004da7bc5104bbbad13c Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Wed, 18 Oct 2017 18:33:35 -0700 Subject: [PATCH] Sanitize name index in compile phase of CFF. Fixes #8960 --- src/core/cff_parser.js | 43 ++++++++++++++-------------- test/pdfs/.gitignore | 1 + test/pdfs/issue8960_reduced.pdf | Bin 0 -> 8414 bytes test/test_manifest.json | 7 +++++ test/unit/cff_parser_spec.js | 48 ++++++++++++++++++++------------ 5 files changed, 60 insertions(+), 39 deletions(-) create mode 100644 test/pdfs/issue8960_reduced.pdf diff --git a/src/core/cff_parser.js b/src/core/cff_parser.js index 20b794305..8335b8fcc 100644 --- a/src/core/cff_parser.js +++ b/src/core/cff_parser.js @@ -413,26 +413,7 @@ var CFFParser = (function CFFParserClosure() { var names = []; for (var i = 0, ii = index.count; i < ii; ++i) { var name = index.get(i); - // OTS doesn't allow names to be over 127 characters. - var length = Math.min(name.length, 127); - var data = []; - // OTS also only permits certain characters in the name. - for (var j = 0; j < length; ++j) { - var c = name[j]; - if (j === 0 && c === 0) { - data[j] = c; - continue; - } - if ((c < 33 || c > 126) || c === 91 /* [ */ || c === 93 /* ] */ || - c === 40 /* ( */ || c === 41 /* ) */ || c === 123 /* { */ || - c === 125 /* } */ || c === 60 /* < */ || c === 62 /* > */ || - c === 47 /* / */ || c === 37 /* % */ || c === 35 /* # */) { - data[j] = 95; - continue; - } - data[j] = c; - } - names.push(bytesToString(data)); + names.push(bytesToString(name)); } return names; }, @@ -1413,7 +1394,27 @@ var CFFCompiler = (function CFFCompilerClosure() { compileNameIndex: function CFFCompiler_compileNameIndex(names) { var nameIndex = new CFFIndex(); for (var i = 0, ii = names.length; i < ii; ++i) { - nameIndex.add(stringToBytes(names[i])); + var name = names[i]; + // OTS doesn't allow names to be over 127 characters. + var length = Math.min(name.length, 127); + var sanitizedName = new Array(length); + for (var j = 0; j < length; j++) { + // OTS requires chars to be between a range and not certain other + // chars. + var char = name[j]; + if (char < '!' || char > '~' || char === '[' || char === ']' || + char === '(' || char === ')' || char === '{' || char === '}' || + char === '<' || char === '>' || char === '/' || char === '%') { + char = '_'; + } + sanitizedName[j] = char; + } + sanitizedName = sanitizedName.join(''); + + if (sanitizedName === '') { + sanitizedName = 'Bad_Font_Name'; + } + nameIndex.add(stringToBytes(sanitizedName)); } return this.compileIndex(nameIndex); }, diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index debd68f74..2dfd68e4b 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -115,6 +115,7 @@ !issue4630.pdf !issue4909.pdf !issue5084.pdf +!issue8960_reduced.pdf !issue5202.pdf !issue5280.pdf !issue5677.pdf diff --git a/test/pdfs/issue8960_reduced.pdf b/test/pdfs/issue8960_reduced.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4c1f90ac2d7c4fc52bb7b4f4962bea1a8817d2ac GIT binary patch literal 8414 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 { + return bytes; + }, + }, {}, SEAC_ANALYSIS_ENABLED); + } + it('encodes integers', function() { var c = new CFFCompiler(); // all the examples from the spec @@ -388,5 +381,24 @@ describe('CFFCompiler', function() { expect(c.encodeFloat(5e-11)).toEqual([0x1e, 0x5c, 0x11, 0xff]); }); + it('sanitizes name index', function() { + var c = new CFFCompiler(); + var nameIndexCompiled = c.compileNameIndex(['[a']); + var parser = testParser(nameIndexCompiled); + var nameIndex = parser.parseIndex(0); + var names = parser.parseNameIndex(nameIndex.obj); + expect(names).toEqual(['_a']); + + var longName = ''; + for (var i = 0; i < 129; i++) { + longName += '_'; + } + nameIndexCompiled = c.compileNameIndex([longName]); + parser = testParser(nameIndexCompiled); + nameIndex = parser.parseIndex(0); + names = parser.parseNameIndex(nameIndex.obj); + expect(names[0].length).toEqual(127); + }); + // TODO a lot more compiler tests });