[ 
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)

Reply via email to