tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

mutators.cc (8010B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "mutators.h"
      6 
      7 #include <algorithm>
      8 #include <cassert>
      9 #include <cstddef>
     10 #include <cstdint>
     11 #include <random>
     12 #include <vector>
     13 
     14 #include "tls_parser.h"
     15 
     16 // Helper class to simplify TLS record manipulation.
     17 class Record {
     18 public:
     19  static std::unique_ptr<Record> Create(const uint8_t *data, size_t size,
     20                                        size_t remaining) {
     21    return std::unique_ptr<Record>(new Record(data, size, remaining));
     22  }
     23 
     24  void insert_before(const std::unique_ptr<Record> &other) {
     25    assert(data_ && size_ > 0);
     26 
     27    // Copy data in case other == this.
     28    std::vector<uint8_t> buf(size_);
     29    memcpy(buf.data(), data_, size_);
     30 
     31    uint8_t *dest = const_cast<uint8_t *>(other->data());
     32    // Make room for the record we want to insert.
     33    memmove(dest + size_, other->data(), other->size() + other->remaining());
     34    // Insert the record.
     35    memcpy(dest, buf.data(), size_);
     36  }
     37 
     38  void truncate(size_t length) {
     39    assert(length >= 5 + EXTRA_HEADER_BYTES);
     40    uint8_t *dest = const_cast<uint8_t *>(data_);
     41    size_t l = length - (5 + EXTRA_HEADER_BYTES);
     42    dest[3] = (l >> 8) & 0xff;
     43    dest[4] = l & 0xff;
     44    memmove(dest + length, data_ + size_, remaining_);
     45  }
     46 
     47  void drop() {
     48    uint8_t *dest = const_cast<uint8_t *>(data_);
     49    memmove(dest, data_ + size_, remaining_);
     50  }
     51 
     52  const uint8_t *data() { return data_; }
     53  size_t remaining() { return remaining_; }
     54  size_t size() { return size_; }
     55 
     56 private:
     57  Record(const uint8_t *data, size_t size, size_t remaining)
     58      : data_(data), remaining_(remaining), size_(size) {}
     59 
     60  const uint8_t *data_;
     61  size_t remaining_;
     62  size_t size_;
     63 };
     64 
     65 // Parse records contained in a given TLS transcript.
     66 std::vector<std::unique_ptr<Record>> ParseRecords(const uint8_t *data,
     67                                                  size_t size) {
     68  std::vector<std::unique_ptr<Record>> records;
     69  nss_test::TlsParser parser(data, size);
     70 
     71  while (parser.remaining()) {
     72    size_t offset = parser.consumed();
     73 
     74    // Skip type, version, and DTLS seqnums.
     75    if (!parser.Skip(3 + EXTRA_HEADER_BYTES)) {
     76      break;
     77    }
     78 
     79    nss_test::DataBuffer fragment;
     80    if (!parser.ReadVariable(&fragment, 2)) {
     81      break;
     82    }
     83 
     84    records.push_back(Record::Create(data + offset,
     85                                     fragment.len() + 5 + EXTRA_HEADER_BYTES,
     86                                     parser.remaining()));
     87  }
     88 
     89  return records;
     90 }
     91 
     92 namespace TlsMutators {
     93 
     94 // Mutator that drops whole TLS records.
     95 size_t DropRecord(uint8_t *data, size_t size, size_t maxSize,
     96                  unsigned int seed) {
     97  std::mt19937 rng(seed);
     98 
     99  // Find TLS records in the corpus.
    100  auto records = ParseRecords(data, size);
    101  if (records.empty()) {
    102    return 0;
    103  }
    104 
    105  // Pick a record to drop at random.
    106  std::uniform_int_distribution<size_t> dist(0, records.size() - 1);
    107  auto &rec = records.at(dist(rng));
    108 
    109  // Drop the record.
    110  rec->drop();
    111 
    112  // Return the new final size.
    113  return size - rec->size();
    114 }
    115 
    116 // Mutator that shuffles TLS records in a transcript.
    117 size_t ShuffleRecords(uint8_t *data, size_t size, size_t maxSize,
    118                      unsigned int seed) {
    119  std::mt19937 rng(seed);
    120 
    121  // Find TLS records in the corpus.
    122  auto records = ParseRecords(data, size);
    123  if (records.empty()) {
    124    return 0;
    125  }
    126 
    127  // Store the original corpus.
    128  std::vector<uint8_t> buf(size);
    129  memcpy(buf.data(), data, size);
    130 
    131  // Find offset of first record in target buffer.
    132  uint8_t *dest = const_cast<uint8_t *>(records.at(0)->data());
    133 
    134  // Shuffle record order.
    135  std::shuffle(records.begin(), records.end(), rng);
    136 
    137  // Write records to their new positions.
    138  for (auto &rec : records) {
    139    memcpy(dest, buf.data() + (rec->data() - data), rec->size());
    140    dest += rec->size();
    141  }
    142 
    143  // Final size hasn't changed.
    144  return size;
    145 }
    146 
    147 // Mutator that duplicates a single TLS record and randomly inserts it.
    148 size_t DuplicateRecord(uint8_t *data, size_t size, size_t maxSize,
    149                       unsigned int seed) {
    150  std::mt19937 rng(seed);
    151 
    152  // Find TLS records in the corpus.
    153  const auto records = ParseRecords(data, size);
    154  if (records.empty()) {
    155    return 0;
    156  }
    157 
    158  // Pick a record to duplicate at random.
    159  std::uniform_int_distribution<size_t> dist(0, records.size() - 1);
    160  auto &rec = records.at(dist(rng));
    161  if (size + rec->size() > maxSize) {
    162    return 0;
    163  }
    164 
    165  // Insert before random record.
    166  rec->insert_before(records.at(dist(rng)));
    167 
    168  // Return the new final size.
    169  return size + rec->size();
    170 }
    171 
    172 // Mutator that truncates a TLS record.
    173 size_t TruncateRecord(uint8_t *data, size_t size, size_t maxSize,
    174                      unsigned int seed) {
    175  std::mt19937 rng(seed);
    176 
    177  // Find TLS records in the corpus.
    178  const auto records = ParseRecords(data, size);
    179  if (records.empty()) {
    180    return 0;
    181  }
    182 
    183  // Pick a record to truncate at random.
    184  std::uniform_int_distribution<size_t> dist(0, records.size() - 1);
    185  auto &rec = records.at(dist(rng));
    186 
    187  // Need a record with data.
    188  if (rec->size() <= 5 + EXTRA_HEADER_BYTES) {
    189    return 0;
    190  }
    191 
    192  // Truncate.
    193  std::uniform_int_distribution<size_t> dist2(5 + EXTRA_HEADER_BYTES,
    194                                              rec->size() - 1);
    195  size_t new_length = dist2(rng);
    196  rec->truncate(new_length);
    197 
    198  // Return the new final size.
    199  return size + new_length - rec->size();
    200 }
    201 
    202 // Mutator that splits a TLS record in two.
    203 size_t FragmentRecord(uint8_t *data, size_t size, size_t maxSize,
    204                      unsigned int seed) {
    205  std::mt19937 rng(seed);
    206 
    207  // We can't deal with DTLS yet.
    208  if (EXTRA_HEADER_BYTES > 0) {
    209    return 0;
    210  }
    211 
    212  if (size + 5 > maxSize) {
    213    return 0;
    214  }
    215 
    216  // Find TLS records in the corpus.
    217  const auto records = ParseRecords(data, size);
    218  if (records.empty()) {
    219    return 0;
    220  }
    221 
    222  // Pick a record to fragment at random.
    223  std::uniform_int_distribution<size_t> rand_record(0, records.size() - 1);
    224  auto &rec = records.at(rand_record(rng));
    225  uint8_t *rdata = const_cast<uint8_t *>(rec->data());
    226  size_t length = rec->size();
    227  size_t content_length = length - 5;
    228 
    229  if (content_length < 2) {
    230    return 0;
    231  }
    232 
    233  // Assign a new length to the first fragment.
    234  std::uniform_int_distribution<size_t> rand_size(1, content_length - 1);
    235  size_t first_length = rand_size(rng);
    236  size_t second_length = content_length - first_length;
    237  rdata[3] = (first_length >> 8) & 0xff;
    238  rdata[4] = first_length & 0xff;
    239  uint8_t *second_record = rdata + 5 + first_length;
    240 
    241  // Make room for the header of the second record.
    242  memmove(second_record + 5, second_record,
    243          rec->remaining() + content_length - first_length);
    244 
    245  // Write second header.
    246  memcpy(second_record, rdata, 3);
    247  second_record[3] = (second_length >> 8) & 0xff;
    248  second_record[4] = second_length & 0xff;
    249 
    250  return size + 5;
    251 }
    252 
    253 // Cross-over function that merges and shuffles two transcripts.
    254 size_t CrossOver(const uint8_t *data1, size_t size1, const uint8_t *data2,
    255                 size_t size2, uint8_t *out, size_t maxOutSize,
    256                 unsigned int seed) {
    257  std::mt19937 rng(seed);
    258 
    259  // Find TLS records in the corpus.
    260  auto records1 = ParseRecords(data1, size1);
    261  if (records1.empty()) {
    262    return 0;
    263  }
    264 
    265  {  // Merge the two vectors.
    266    auto records2 = ParseRecords(data2, size2);
    267    if (records2.empty()) {
    268      return 0;
    269    }
    270    std::move(records2.begin(), records2.end(), std::back_inserter(records1));
    271  }
    272 
    273  // Shuffle record order.
    274  std::shuffle(records1.begin(), records1.end(), rng);
    275 
    276  size_t total = 0;
    277  for (auto &rec : records1) {
    278    size_t length = rec->size();
    279    if (total + length > maxOutSize) {
    280      break;
    281    }
    282 
    283    // Write record to its new position.
    284    memcpy(out + total, rec->data(), length);
    285    total += length;
    286  }
    287 
    288  return total;
    289 }
    290 
    291 }  // namespace TlsMutators