Bug 1260836 - Add functionality to allow CRX files to be handled as ZIP files draft
authorKirk Steuber <ksteuber@mozilla.com>
Wed, 06 Apr 2016 18:28:24 -0700
changeset 350078 d93460830c710d0f26f5c02c1441fb2b1eba1ecd
parent 348659 06678484909cc3712756f82d070548ac144d09c0
child 350090 49edc96527373a457cdfd051c4d6b68f8a9533f9
push id15240
push userksteuber@mozilla.com
push dateTue, 12 Apr 2016 19:37:25 +0000
bugs1260836
milestone48.0a1
Bug 1260836 - Add functionality to allow CRX files to be handled as ZIP files MozReview-Commit-ID: 8cMxoqJPNlk
modules/libjar/nsZipArchive.cpp
modules/libjar/nsZipArchive.h
--- a/modules/libjar/nsZipArchive.cpp
+++ b/modules/libjar/nsZipArchive.cpp
@@ -160,16 +160,18 @@ nsresult gZlibInit(z_stream *zs)
   return NS_OK;
 }
 
 nsZipHandle::nsZipHandle()
   : mFileData(nullptr)
   , mLen(0)
   , mMap(nullptr)
   , mRefCnt(0)
+  , mFileStart(nullptr)
+  , mTotalLen(0)
 {
   MOZ_COUNT_CTOR(nsZipHandle);
 }
 
 NS_IMPL_ADDREF(nsZipHandle)
 NS_IMPL_RELEASE(nsZipHandle)
 
 nsresult nsZipHandle::Init(nsIFile *file, nsZipHandle **ret,
@@ -210,18 +212,19 @@ nsresult nsZipHandle::Init(nsIFile *file
   if (aFd) {
     *aFd = fd.forget();
   }
 #else
   handle->mNSPRFileDesc = fd.forget();
 #endif
   handle->mMap = map;
   handle->mFile.Init(file);
-  handle->mLen = (uint32_t) size;
-  handle->mFileData = buf;
+  handle->mTotalLen = (uint32_t) size;
+  handle->mFileStart = buf;
+  handle->findDataStart();
   handle.forget(ret);
   return NS_OK;
 }
 
 nsresult nsZipHandle::Init(nsZipArchive *zip, const char *entry,
                            nsZipHandle **ret)
 {
   RefPtr<nsZipHandle> handle = new nsZipHandle();
@@ -232,36 +235,78 @@ nsresult nsZipHandle::Init(nsZipArchive 
   if (!handle->mBuf)
     return NS_ERROR_OUT_OF_MEMORY;
 
   if (!handle->mBuf->Buffer())
     return NS_ERROR_UNEXPECTED;
 
   handle->mMap = nullptr;
   handle->mFile.Init(zip, entry);
-  handle->mLen = handle->mBuf->Length();
-  handle->mFileData = handle->mBuf->Buffer();
+  handle->mTotalLen = handle->mBuf->Length();
+  handle->mFileStart = handle->mBuf->Buffer();
+  handle->findDataStart();
   handle.forget(ret);
   return NS_OK;
 }
 
 nsresult nsZipHandle::Init(const uint8_t* aData, uint32_t aLen,
                            nsZipHandle **aRet)
 {
   RefPtr<nsZipHandle> handle = new nsZipHandle();
 
-  handle->mFileData = aData;
-  handle->mLen = aLen;
+  handle->mFileStart = aData;
+  handle->mTotalLen = aLen;
+  handle->findDataStart();
   handle.forget(aRet);
   return NS_OK;
 }
 
+// This function finds the start of the ZIP data. If the file is a regular ZIP,
+// this is just the start of the file. If the file is a CRX file, the start of
+// the data is after the CRX header.
+// CRX header reference: (CRX version 2)
+//    Header requires little-endian byte ordering with 4-byte alignment.
+//    32 bits       : magicNumber   - Defined as a |char m[] = "Cr24"|.
+//                                    Equivalent to |uint32_t m = 0x34327243|.
+//    32 bits       : version       - Unsigned integer representing the CRX file
+//                                    format version. Currently equal to 2.
+//    32 bits       : pubKeyLength  - Unsigned integer representing the length
+//                                    of the public key in bytes.
+//    32 bits       : sigLength     - Unsigned integer representing the length
+//                                    of the signature in bytes.
+//    pubKeyLength  : publicKey     - Contents of the author's public key.
+//    sigLength     : signature     - Signature of the ZIP content.
+//                                    Signature is created using the RSA
+//                                    algorighm with the SHA-1 hash function.
+void nsZipHandle::findDataStart()
+{
+  // In the CRX header, integers are 32 bits. Our pointer to the file is of
+  // type |uint8_t|, which is guaranteed to be 8 bits.
+  const uint32_t CRXIntSize = 4;
+
+  if (mTotalLen > CRXIntSize * 4 && xtolong(mFileStart) == kCRXMagic) {
+    const uint8_t* headerData = mFileStart;
+    headerData += CRXIntSize * 2; // Skip magic number and version number
+    uint32_t pubKeyLength = xtolong(headerData);
+    headerData += CRXIntSize;
+    uint32_t sigLength = xtolong(headerData);
+    uint32_t headerSize = CRXIntSize * 4 + pubKeyLength + sigLength;
+    if (mTotalLen > headerSize) {
+      mLen = mTotalLen - headerSize;
+      mFileData = mFileStart + headerSize;
+      return;
+    }
+  }
+  mLen = mTotalLen;
+  mFileData = mFileStart;
+}
+
 int64_t nsZipHandle::SizeOfMapping()
 {
-    return mLen;
+  return mTotalLen;
 }
 
 nsresult nsZipHandle::GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc)
 {
   if (!aNSPRFileDesc) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
@@ -271,19 +316,20 @@ nsresult nsZipHandle::GetNSPRFileDesc(PR
   }
 
   return NS_OK;
 }
 
 nsZipHandle::~nsZipHandle()
 {
   if (mMap) {
-    PR_MemUnmap((void *)mFileData, mLen);
+    PR_MemUnmap((void *)mFileStart, mTotalLen);
     PR_CloseFileMap(mMap);
   }
+  mFileStart = nullptr;
   mFileData = nullptr;
   mMap = nullptr;
   mBuf = nullptr;
   MOZ_COUNT_DTOR(nsZipHandle);
 }
 
 //***********************************************************
 //      nsZipArchive  --  public methods
--- a/modules/libjar/nsZipArchive.h
+++ b/modules/libjar/nsZipArchive.h
@@ -403,26 +403,34 @@ public:
   NS_METHOD_(MozExternalRefCountType) AddRef(void);
   NS_METHOD_(MozExternalRefCountType) Release(void);
 
   int64_t SizeOfMapping();
 
   nsresult GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc);
 
 protected:
-  const uint8_t * mFileData; /* pointer to mmaped file */
-  uint32_t        mLen;      /* length of file and memory mapped area */
+  const uint8_t * mFileData; /* pointer to zip data */
+  uint32_t        mLen;      /* length of zip data */
   mozilla::FileLocation mFile; /* source file if any, for logging */
 
 private:
   nsZipHandle();
   ~nsZipHandle();
 
+  void findDataStart();
+
   PRFileMap *                       mMap;    /* nspr datastructure for mmap */
   mozilla::AutoFDClose              mNSPRFileDesc;
   nsAutoPtr<nsZipItemPtr<uint8_t> > mBuf;
   mozilla::ThreadSafeAutoRefCnt     mRefCnt; /* ref count */
   NS_DECL_OWNINGTHREAD
+
+  const uint8_t * mFileStart; /* pointer to mmaped file */
+  uint32_t        mTotalLen;  /* total length of the mmaped file */
+
+  /* Magic number for CRX type expressed in Big Endian since it is a literal */
+  static const uint32_t kCRXMagic = 0x34327243;
 };
 
 nsresult gZlibInit(z_stream *zs);
 
 #endif /* nsZipArchive_h_ */