toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.cc

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 // Copyright (c) 2006, Google Inc.
     2 // All rights reserved.
     3 //
     4 // Redistribution and use in source and binary forms, with or without
     5 // modification, are permitted provided that the following conditions are
     6 // met:
     7 //
     8 //     * Redistributions of source code must retain the above copyright
     9 // notice, this list of conditions and the following disclaimer.
    10 //     * Redistributions in binary form must reproduce the above
    11 // copyright notice, this list of conditions and the following disclaimer
    12 // in the documentation and/or other materials provided with the
    13 // distribution.
    14 //     * Neither the name of Google Inc. nor the names of its
    15 // contributors may be used to endorse or promote products derived from
    16 // this software without specific prior written permission.
    17 //
    18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    30 // macho_id.cc: Functions to gather identifying information from a macho file
    31 //
    32 // See macho_id.h for documentation
    33 //
    34 // Author: Dan Waylonis
    36 extern "C" {  // necessary for Leopard
    37   #include <fcntl.h>
    38   #include <mach-o/loader.h>
    39   #include <mach-o/swap.h>
    40   #include <stdio.h>
    41   #include <stdlib.h>
    42   #include <string.h>
    43   #include <sys/time.h>
    44   #include <sys/types.h>
    45   #include <unistd.h>
    46 }
    48 #include "common/mac/macho_id.h"
    49 #include "common/mac/macho_walker.h"
    50 #include "common/mac/macho_utilities.h"
    52 namespace MacFileUtilities {
    54 using google_breakpad::MD5Init;
    55 using google_breakpad::MD5Update;
    56 using google_breakpad::MD5Final;
    58 MachoID::MachoID(const char *path)
    59    : memory_(0),
    60      memory_size_(0),
    61      crc_(0), 
    62      md5_context_(), 
    63      update_function_(NULL) {
    64   strlcpy(path_, path, sizeof(path_));
    65 }
    67 MachoID::MachoID(const char *path, void *memory, size_t size)
    68    : memory_(memory),
    69      memory_size_(size),
    70      crc_(0), 
    71      md5_context_(), 
    72      update_function_(NULL) {
    73   strlcpy(path_, path, sizeof(path_));
    74 }
    76 MachoID::~MachoID() {
    77 }
    79 // The CRC info is from http://en.wikipedia.org/wiki/Adler-32
    80 // With optimizations from http://www.zlib.net/
    82 // The largest prime smaller than 65536
    83 #define MOD_ADLER 65521
    84 // MAX_BLOCK is the largest n such that 255n(n+1)/2 + (n+1)(MAX_BLOCK-1) <= 2^32-1
    85 #define MAX_BLOCK 5552
    87 void MachoID::UpdateCRC(unsigned char *bytes, size_t size) {
    88 // Unrolled loops for summing
    89 #define DO1(buf,i)  {sum1 += (buf)[i]; sum2 += sum1;}
    90 #define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
    91 #define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
    92 #define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
    93 #define DO16(buf)   DO8(buf,0); DO8(buf,8);
    94   // Split up the crc
    95   uint32_t sum1 = crc_ & 0xFFFF;
    96   uint32_t sum2 = (crc_ >> 16) & 0xFFFF;
    98   // Do large blocks
    99   while (size >= MAX_BLOCK) {
   100     size -= MAX_BLOCK;
   101     int block_count = MAX_BLOCK / 16;
   102     do {
   103       DO16(bytes);
   104       bytes += 16;
   105     } while (--block_count);
   106     sum1 %= MOD_ADLER;
   107     sum2 %= MOD_ADLER;
   108   }
   110   // Do remaining bytes
   111   if (size) {
   112     while (size >= 16) {
   113       size -= 16;
   114       DO16(bytes);
   115       bytes += 16;
   116     }
   117     while (size--) {
   118       sum1 += *bytes++;
   119       sum2 += sum1;
   120     }
   121     sum1 %= MOD_ADLER;
   122     sum2 %= MOD_ADLER;
   123     crc_ = (sum2 << 16) | sum1;
   124   }
   125 }
   127 void MachoID::UpdateMD5(unsigned char *bytes, size_t size) {
   128   MD5Update(&md5_context_, bytes, size);
   129 }
   131 void MachoID::Update(MachoWalker *walker, off_t offset, size_t size) {
   132   if (!update_function_ || !size)
   133     return;
   135   // Read up to 4k bytes at a time
   136   unsigned char buffer[4096];
   137   size_t buffer_size;
   138   off_t file_offset = offset;
   139   while (size > 0) {
   140     if (size > sizeof(buffer)) {
   141       buffer_size = sizeof(buffer);
   142       size -= buffer_size;
   143     } else {
   144       buffer_size = size;
   145       size = 0;
   146     }
   148     if (!walker->ReadBytes(buffer, buffer_size, file_offset))
   149       return;
   151     (this->*update_function_)(buffer, buffer_size);
   152     file_offset += buffer_size;
   153   }
   154 }
   156 bool MachoID::UUIDCommand(cpu_type_t cpu_type,
   157                           cpu_subtype_t cpu_subtype,
   158                           unsigned char bytes[16]) {
   159   struct breakpad_uuid_command uuid_cmd;
   160   uuid_cmd.cmd = 0;
   161   if (!WalkHeader(cpu_type, cpu_subtype, UUIDWalkerCB, &uuid_cmd))
   162     return false;
   164   // If we found the command, we'll have initialized the uuid_command
   165   // structure
   166   if (uuid_cmd.cmd == LC_UUID) {
   167     memcpy(bytes, uuid_cmd.uuid, sizeof(uuid_cmd.uuid));
   168     return true;
   169   }
   171   return false;
   172 }
   174 bool MachoID::IDCommand(cpu_type_t cpu_type,
   175                         cpu_subtype_t cpu_subtype,
   176                         unsigned char identifier[16]) {
   177   struct dylib_command dylib_cmd;
   178   dylib_cmd.cmd = 0;
   179   if (!WalkHeader(cpu_type, cpu_subtype, IDWalkerCB, &dylib_cmd))
   180     return false;
   182   // If we found the command, we'll have initialized the dylib_command
   183   // structure
   184   if (dylib_cmd.cmd == LC_ID_DYLIB) {
   185     // Take the hashed filename, version, and compatability version bytes
   186     // to form the first 12 bytes, pad the rest with zeros
   188     // create a crude hash of the filename to generate the first 4 bytes
   189     identifier[0] = 0;
   190     identifier[1] = 0;
   191     identifier[2] = 0;
   192     identifier[3] = 0;
   194     for (int j = 0, i = (int)strlen(path_)-1; i>=0 && path_[i]!='/'; ++j, --i) {
   195       identifier[j%4] += path_[i];
   196     }
   198     identifier[4] = (dylib_cmd.dylib.current_version >> 24) & 0xFF;
   199     identifier[5] = (dylib_cmd.dylib.current_version >> 16) & 0xFF;
   200     identifier[6] = (dylib_cmd.dylib.current_version >> 8) & 0xFF;
   201     identifier[7] = dylib_cmd.dylib.current_version & 0xFF;
   202     identifier[8] = (dylib_cmd.dylib.compatibility_version >> 24) & 0xFF;
   203     identifier[9] = (dylib_cmd.dylib.compatibility_version >> 16) & 0xFF;
   204     identifier[10] = (dylib_cmd.dylib.compatibility_version >> 8) & 0xFF;
   205     identifier[11] = dylib_cmd.dylib.compatibility_version & 0xFF;
   206     identifier[12] = (cpu_type >> 24) & 0xFF;
   207     identifier[13] = (cpu_type >> 16) & 0xFF;
   208     identifier[14] = (cpu_type >> 8) & 0xFF;
   209     identifier[15] = cpu_type & 0xFF;
   211     return true;
   212   }
   214   return false;
   215 }
   217 uint32_t MachoID::Adler32(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
   218   update_function_ = &MachoID::UpdateCRC;
   219   crc_ = 0;
   221   if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this))
   222     return 0;
   224   return crc_;
   225 }
   227 bool MachoID::MD5(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, unsigned char identifier[16]) {
   228   update_function_ = &MachoID::UpdateMD5;
   230   MD5Init(&md5_context_);
   232   if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this))
   233     return false;
   235   MD5Final(identifier, &md5_context_);
   236   return true;
   237 }
   239 bool MachoID::WalkHeader(cpu_type_t cpu_type,
   240                          cpu_subtype_t cpu_subtype,
   241                          MachoWalker::LoadCommandCallback callback,
   242                          void *context) {
   243   if (memory_) {
   244     MachoWalker walker(memory_, memory_size_, callback, context);
   245     return walker.WalkHeader(cpu_type, cpu_subtype);
   246   } else {
   247     MachoWalker walker(path_, callback, context);
   248     return walker.WalkHeader(cpu_type, cpu_subtype);
   249   }
   250 }
   252 // static
   253 bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
   254                        bool swap, void *context) {
   255   MachoID *macho_id = (MachoID *)context;
   257   if (cmd->cmd == LC_SEGMENT) {
   258     struct segment_command seg;
   260     if (!walker->ReadBytes(&seg, sizeof(seg), offset))
   261       return false;
   263     if (swap)
   264       swap_segment_command(&seg, NXHostByteOrder());
   266     struct mach_header_64 header;
   267     off_t header_offset;
   269     if (!walker->CurrentHeader(&header, &header_offset))
   270       return false;
   272     // Process segments that have sections:
   273     // (e.g., __TEXT, __DATA, __IMPORT, __OBJC)
   274     offset += sizeof(struct segment_command);
   275     struct section sec;
   276     for (unsigned long i = 0; i < seg.nsects; ++i) {
   277       if (!walker->ReadBytes(&sec, sizeof(sec), offset))
   278         return false;
   280       if (swap)
   281         swap_section(&sec, 1, NXHostByteOrder());
   283       // sections of type S_ZEROFILL are "virtual" and contain no data
   284       // in the file itself
   285       if ((sec.flags & SECTION_TYPE) != S_ZEROFILL && sec.offset != 0)
   286         macho_id->Update(walker, header_offset + sec.offset, sec.size);
   288       offset += sizeof(struct section);
   289     }
   290   } else if (cmd->cmd == LC_SEGMENT_64) {
   291     struct segment_command_64 seg64;
   293     if (!walker->ReadBytes(&seg64, sizeof(seg64), offset))
   294       return false;
   296     if (swap)
   297       breakpad_swap_segment_command_64(&seg64, NXHostByteOrder());
   299     struct mach_header_64 header;
   300     off_t header_offset;
   302     if (!walker->CurrentHeader(&header, &header_offset))
   303       return false;
   305     // Process segments that have sections:
   306     // (e.g., __TEXT, __DATA, __IMPORT, __OBJC)
   307     offset += sizeof(struct segment_command_64);
   308     struct section_64 sec64;
   309     for (unsigned long i = 0; i < seg64.nsects; ++i) {
   310       if (!walker->ReadBytes(&sec64, sizeof(sec64), offset))
   311         return false;
   313       if (swap)
   314         breakpad_swap_section_64(&sec64, 1, NXHostByteOrder());
   316       // sections of type S_ZEROFILL are "virtual" and contain no data
   317       // in the file itself
   318       if ((sec64.flags & SECTION_TYPE) != S_ZEROFILL && sec64.offset != 0)
   319         macho_id->Update(walker, 
   320                          header_offset + sec64.offset, 
   321                          (size_t)sec64.size);
   323       offset += sizeof(struct section_64);
   324     }
   325   }
   327   // Continue processing
   328   return true;
   329 }
   331 // static
   332 bool MachoID::UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
   333                            bool swap, void *context) {
   334   if (cmd->cmd == LC_UUID) {
   335     struct breakpad_uuid_command *uuid_cmd =
   336       (struct breakpad_uuid_command *)context;
   338     if (!walker->ReadBytes(uuid_cmd, sizeof(struct breakpad_uuid_command),
   339                            offset))
   340       return false;
   342     if (swap)
   343       breakpad_swap_uuid_command(uuid_cmd, NXHostByteOrder());
   345     return false;
   346   }
   348   // Continue processing
   349   return true;
   350 }
   352 // static
   353 bool MachoID::IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
   354                          bool swap, void *context) {
   355   if (cmd->cmd == LC_ID_DYLIB) {
   356     struct dylib_command *dylib_cmd = (struct dylib_command *)context;
   358     if (!walker->ReadBytes(dylib_cmd, sizeof(struct dylib_command), offset))
   359       return false;
   361     if (swap)
   362       swap_dylib_command(dylib_cmd, NXHostByteOrder());
   364     return false;
   365   }
   367   // Continue processing
   368   return true;
   369 }
   371 }  // namespace MacFileUtilities

mercurial