[
https://issues.apache.org/jira/browse/TIKA-4830?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Tilman Hausherr resolved TIKA-4830.
-----------------------------------
Assignee: Tilman Hausherr
Resolution: Fixed
Thanks [~timschecki]! I've caught the specific exceptions because this is
cleaner IMHO. If you report it at Jackcess and they fix it, please ping us so
that we can remove these catches.
> JackcessParser.parse leaks Jackcess RuntimeExceptions
> (IndexOutOfBoundsException / IllegalStateException) on malformed MDBs while
> reading the global usage map
> --------------------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: TIKA-4830
> URL: https://issues.apache.org/jira/browse/TIKA-4830
> Project: Tika
> Issue Type: Bug
> Components: parser
> Affects Versions: 4.0.0, 2.9.4, 3.3.2
> Reporter: Tim Scheckenbach
> Assignee: Tilman Hausherr
> Priority: Major
> Fix For: 3.3.3, 4.1.0
>
> Attachments: inputs.zip
>
>
> {{JackcessParser.parse}} is declared {{{}throws IOException, SAXException,
> TikaException{}}}. Two fuzz inputs for the same open path —
> {{DatabaseBuilder.open}} → {{PageChannel.initialize}} → {{UsageMap.read}}
> (global usage map, page 1, row 0)
> — make Jackcess throw a {{RuntimeException}} that Tika does not wrap. The
> OSS-Fuzz target {{JackcessParserFuzzer}} swallows only
> {{{}IllegalArgumentException | TikaException | SAXException |
> IOException{}}}, so both are fuzzer crashes. {{AutoDetectParser}} /
> {{CompositeParser}} would wrap them as {{{}TikaException: Unexpected
> RuntimeException from JackcessParser{}}}; callers of {{JackcessParser}}
> directly do not.
> Calling
> {code:java}
> new JackcessParser().parse(TikaInputStream.get(new
> File("crash-083680cb14186e1be3e26b93946ea43c538d2e62")),
> new ToTextContentHandler(), new Metadata(), new ParseContext());
> {code}
> on the first attached file (32768-byte Jet 4 MDB) results in:
> {code:java}
> java.lang.IndexOutOfBoundsException
> at java.base/java.nio.Buffer.checkIndex(Buffer.java:743)
> at java.base/java.nio.HeapByteBuffer.get(HeapByteBuffer.java:169)
> at com.healthmarketscience.jackcess.impl.UsageMap.read(UsageMap.java:133)
> at
> com.healthmarketscience.jackcess.impl.PageChannel.initialize(PageChannel.java:117)
> at
> com.healthmarketscience.jackcess.impl.DatabaseImpl.<init>(DatabaseImpl.java:598)
> at
> com.healthmarketscience.jackcess.impl.DatabaseImpl.open(DatabaseImpl.java:458)
> at
> com.healthmarketscience.jackcess.DatabaseBuilder.open(DatabaseBuilder.java:278)
> at
> org.apache.tika.parser.microsoft.JackcessParser.parse(JackcessParser.java:101)
> {code}
> {{UsageMap.read}} is declared {{throws IOException}} but does:
> {code:java}
> short rowStart = TableImpl.findRowStart(tableBuffer, rowNum, format);
> int rowEnd = TableImpl.findRowEnd(tableBuffer, rowNum, format);
> tableBuffer.limit(rowEnd);
> byte mapType = tableBuffer.get(rowStart); // IndexOutOfBoundsException
> {code}
> Tika does not catch {{IndexOutOfBoundsException}} at all.
> Calling the same parse on the second attached file,
> {{crash-107db845b1fe3fee58a3b1da3a4646e604af329b}} (24576-byte Jet 4 MDB),
> results in:
> {code:java}
> java.lang.IllegalStateException: invalid page number 169285950
> at
> com.healthmarketscience.jackcess.impl.PageChannel.validatePageNumber(PageChannel.java:203)
> at
> com.healthmarketscience.jackcess.impl.PageChannel.readPage(PageChannel.java:219)
> at
> com.healthmarketscience.jackcess.impl.TempPageHolder.setPage(TempPageHolder.java:86)
> at
> com.healthmarketscience.jackcess.impl.UsageMap$ReferenceHandler.<init>(UsageMap.java:724)
> at
> com.healthmarketscience.jackcess.impl.UsageMap.initHandler(UsageMap.java:146)
> at com.healthmarketscience.jackcess.impl.UsageMap.read(UsageMap.java:135)
> at
> com.healthmarketscience.jackcess.impl.PageChannel.initialize(PageChannel.java:117)
> at
> com.healthmarketscience.jackcess.impl.DatabaseImpl.open(DatabaseImpl.java:458)
> at
> com.healthmarketscience.jackcess.DatabaseBuilder.open(DatabaseBuilder.java:278)
> at
> org.apache.tika.parser.microsoft.JackcessParser.parse(JackcessParser.java:101)
> {code}
> Here the global usage map is a _reference_ map ({{{}MAP_TYPE_REFERENCE{}}}).
> Its constructor walks page pointers and {{validatePageNumber}} is declared
> {{throws IOException}} but does:
> {code:java}
> if ((pageNumber <= INVALID_PAGE_NUMBER) || (pageNumber >= nextPageNumber)) {
> throw new IllegalStateException("invalid page number " + pageNumber);
> }
> {code}
> Page 169285950 is far past the end of a 6-page file. Tika already catches
> {{{}IllegalStateException{}}}, but only to map "Incorrect password"; every
> other one is rethrown:
> {code:java}
> } catch (IllegalStateException e) {
> if (e.getMessage() != null && e.getMessage().contains("Incorrect
> password")) {
> throw new EncryptedDocumentException(e);
> }
> throw e;
> }
> {code}
> Suggested Tika-side fix: catch {{RuntimeException}} from
> {{DatabaseBuilder.open}} (or at least {{IndexOutOfBoundsException}} and
> remaining {{{}IllegalStateException{}}}) and rethrow as {{TikaException}} or
> {{{}CorruptedFileException{}}}. One catch covers both inputs. The
> Jackcess-side fix is to throw {{IOException}} for a corrupt usage map,
> matching the declared contracts of {{UsageMap.read}} and
> {{{}validatePageNumber{}}}.
> I have attached both files as an archive to the issue.
> Found by the CISPA Fandango Team
--
This message was sent by Atlassian Jira
(v8.20.10#820010)