[poppler] poppler/Catalog.cc poppler/Dict.cc poppler/Dict.h poppler/Stream.cc poppler/Stream.h poppler/XRef.cc poppler/XRef.h

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Feb 20 21:23:11 UTC 2020


 poppler/Catalog.cc |    4 ++--
 poppler/Dict.cc    |   17 +++++++++++++++++
 poppler/Dict.h     |    3 +++
 poppler/Stream.cc  |    8 ++++++++
 poppler/Stream.h   |    7 +++++--
 poppler/XRef.cc    |   29 +++++++++++++++++++++++++++++
 poppler/XRef.h     |    4 ++++
 7 files changed, 68 insertions(+), 4 deletions(-)

New commits:
commit ddf97254576a88bd85fcc7b41876c90d1780504e
Author: Albert Astals Cid <aacid at kde.org>
Date:   Sat Dec 7 00:18:53 2019 +0100

    Make sure Base URI is encrypted if the document is before using it
    
    Otherwise we may be being targetted by a link content exfiltration

diff --git a/poppler/Catalog.cc b/poppler/Catalog.cc
index f1afc6e5..05498c3b 100644
--- a/poppler/Catalog.cc
+++ b/poppler/Catalog.cc
@@ -102,9 +102,9 @@ Catalog::Catalog(PDFDoc *docA) {
   acroForm = catDict.dictLookup("AcroForm");
 
   // read base URI
-  Object obj = catDict.dictLookup("URI");
+  Object obj = catDict.getDict()->lookupEnsureEncryptedIfNeeded("URI");
   if (obj.isDict()) {
-    Object obj2 = obj.dictLookup("Base");
+    Object obj2 = obj.getDict()->lookupEnsureEncryptedIfNeeded("Base");
     if (obj2.isString()) {
       baseURI = obj2.getString()->copy();
     }
diff --git a/poppler/Dict.cc b/poppler/Dict.cc
index 77b8ee18..61b89c2e 100644
--- a/poppler/Dict.cc
+++ b/poppler/Dict.cc
@@ -180,6 +180,23 @@ Object Dict::lookup(const char *key, Ref *returnRef, int recursion) const {
   return Object(objNull);
 }
 
+Object Dict::lookupEnsureEncryptedIfNeeded(const char *key) const
+{
+  const auto *entry = find(key);
+  if (!entry)
+    return Object(objNull);
+
+  if (entry->second.getType() == objRef &&
+      xref->isEncrypted() &&
+      !xref->isRefEncrypted(entry->second.getRef()))
+  {
+    error(errSyntaxError, -1, "{0:s} is not encrypted and the document is. This may be a hacking attempt", key);
+    return Object(objNull);
+  }
+
+  return entry->second.fetch(xref);
+}
+
 const Object &Dict::lookupNF(const char *key) const {
   if (const auto *entry = find(key)) {
     return entry->second;
diff --git a/poppler/Dict.h b/poppler/Dict.h
index 287d5a3c..140be8b2 100644
--- a/poppler/Dict.h
+++ b/poppler/Dict.h
@@ -78,6 +78,9 @@ public:
   Object lookup(const char *key, int recursion = 0) const;
   // Same as above but if the returned object is a fetched Ref returns such Ref in returnRef, otherwise returnRef is Ref::INVALID()
   Object lookup(const char *key, Ref *returnRef, int recursion = 0) const;
+  // Look up an entry and return the value.  Returns a null object
+  // if <key> is not in the dictionary or if it is a ref to a non encrypted object in a partially encrypted document
+  Object lookupEnsureEncryptedIfNeeded(const char *key) const;
   const Object &lookupNF(const char *key) const;
   bool lookupInt(const char *key, const char *alt_key, int *value) const;
 
diff --git a/poppler/Stream.cc b/poppler/Stream.cc
index fa89fc5c..59db9d07 100644
--- a/poppler/Stream.cc
+++ b/poppler/Stream.cc
@@ -176,6 +176,14 @@ Stream *Stream::addFilters(Dict *dict, int recursion) {
   return str;
 }
 
+bool Stream::isEncrypted() const {
+  for (const Stream *str = this; str != nullptr; str = str->getNextStream()) {
+    if (str->getKind() == strCrypt)
+      return true;
+  }
+  return false;
+}
+
 class BaseStreamStream : public Stream
 {
 public:
diff --git a/poppler/Stream.h b/poppler/Stream.h
index b675bcc6..406840e6 100644
--- a/poppler/Stream.h
+++ b/poppler/Stream.h
@@ -220,12 +220,15 @@ public:
 			      StreamColorSpaceMode * /*csMode*/) {}
 
   // Return the next stream in the "stack".
-  virtual Stream *getNextStream() { return nullptr; }
+  virtual Stream *getNextStream() const { return nullptr; }
 
   // Add filters to this stream according to the parameters in <dict>.
   // Returns the new stream.
   Stream *addFilters(Dict *dict, int recursion = 0);
 
+  // Returns true if this stream includes a crypt filter.
+  bool isEncrypted() const;
+
 private:
   friend class Object; // for incRef/decRef
 
@@ -402,7 +405,7 @@ public:
   Stream *getUndecodedStream() override { return str->getUndecodedStream(); }
   Dict *getDict() override { return str->getDict(); }
   Object *getDictObject() override { return str->getDictObject(); }
-  Stream *getNextStream() override { return str; }
+  Stream *getNextStream() const override { return str; }
 
   int getUnfilteredChar () override { return str->getUnfilteredChar(); }
   void unfilteredReset () override { str->unfilteredReset(); }
diff --git a/poppler/XRef.cc b/poppler/XRef.cc
index 8f9dd7fe..b123ad23 100644
--- a/poppler/XRef.cc
+++ b/poppler/XRef.cc
@@ -1012,6 +1012,35 @@ void XRef::getEncryptionParameters(unsigned char **fileKeyA, CryptAlgorithm *enc
   }
 }
 
+bool XRef::isRefEncrypted(Ref r)
+{
+  xrefLocker();
+
+  const XRefEntry *e = getEntry(r.num);
+  if (!e->obj.isNull()) { //check for updated object
+    return false;
+  }
+
+  switch (e->type) {
+    case xrefEntryUncompressed:
+    {
+      return encrypted && !e->getFlag(XRefEntry::Unencrypted);
+    }
+
+    case xrefEntryCompressed:
+    {
+      const Object objStr = fetch(e->offset, 0);
+      return objStr.getStream()->isEncrypted();
+    }
+
+    default:
+    {
+    }
+  }
+
+  return false;
+}
+
 bool XRef::okToPrint(bool ignoreOwnerPW) const {
   return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint);
 }
diff --git a/poppler/XRef.h b/poppler/XRef.h
index 2e72ae54..8950980b 100644
--- a/poppler/XRef.h
+++ b/poppler/XRef.h
@@ -128,6 +128,9 @@ public:
   // Is the file encrypted?
   bool isEncrypted() const { return encrypted; }
 
+  // Is the given Ref encrypted?
+  bool isRefEncrypted(Ref r);
+
   // Check various permissions.
   bool okToPrint(bool ignoreOwnerPW = false) const;
   bool okToPrintHighRes(bool ignoreOwnerPW = false) const;
@@ -163,6 +166,7 @@ public:
   // Return the catalog object reference.
   int getRootNum() const { return rootNum; }
   int getRootGen() const { return rootGen; }
+  Ref getRoot() const { return { rootNum, rootGen }; }
 
   // Get end position for a stream in a damaged file.
   // Returns false if unknown or file is not damaged.


More information about the poppler mailing list