Skip to content

Latest commit

 

History

History
160 lines (129 loc) · 11.1 KB

File metadata and controls

160 lines (129 loc) · 11.1 KB

Mitigation Strategies Analysis for google/leveldb

Mitigation Strategy: Application-Level Checksumming

  • Description:

    1. Choose Checksum Algorithm: Select a strong cryptographic hash function (e.g., SHA-256, SHA-512).
    2. Implement Checksum Calculation (LevelDB Interaction): Before calling leveldb::DB::Put():
      • Concatenate the key and value (consider a consistent separator if needed).
      • Calculate the checksum of the concatenated data.
      • Store the checksum along with the key-value pair. This can be done in a few ways:
        • Append to Value: Append the checksum to the value itself (e.g., value + separator + checksum). This is the simplest approach but requires careful handling when reading.
        • Separate Key: Store the checksum in a separate LevelDB entry with a derived key (e.g., original_key + "_checksum"). This keeps the original value clean but adds complexity.
        • Separate Database: Use a separate LevelDB instance solely for storing checksums. This provides the cleanest separation but adds overhead.
    3. Implement Checksum Verification (LevelDB Interaction): After calling leveldb::DB::Get():
      • Retrieve the stored checksum (using the same method as in step 2).
      • Recalculate the checksum of the retrieved key-value pair.
      • Compare the calculated checksum with the stored checksum.
      • If they do not match, the data is considered corrupted.
  • Threats Mitigated:

    • Data Corruption (Subtle Hardware Errors): Severity: Medium. Undetected data corruption.
    • Data Corruption (Software Bugs in LevelDB): Severity: Medium. Undetected data corruption.
    • Bit Rot (Data Degradation over Time): Severity: Low. Slow data degradation on storage media.
  • Impact:

    • Data Corruption (Subtle Hardware Errors): Risk reduced from Medium to Low.
    • Data Corruption (Software Bugs in LevelDB): Risk reduced from Medium to Low.
    • Bit Rot: Risk reduced from Low to Very Low.
  • Currently Implemented: Not Implemented.

  • Missing Implementation: Entirely missing. Requires modification of all LevelDB Put and Get operations.

  • Description:

    1. Locate leveldb::Options: Find the code where the leveldb::Options object is created (usually when opening the database with leveldb::DB::Open).
    2. Enable Paranoid Checks: Set the paranoid_checks option to true:
      leveldb::Options options;
      options.paranoid_checks = true;
      leveldb::DB* db;
      leveldb::Status status = leveldb::DB::Open(options, "/path/to/db", &db);
    3. Handle Errors: Ensure that your code properly handles any errors reported by LevelDB due to failed paranoid checks (see "Proper Error Handling" below).
  • Threats Mitigated:

    • Data Corruption (Software Bugs in LevelDB): Severity: Medium. Undetected data corruption.
    • Data Corruption (Hardware Issues): Severity: Medium. Undetected data corruption.
  • Impact:

    • Data Corruption (Software Bugs in LevelDB): Risk reduced from Medium to Low/Medium (earlier detection, but performance impact).
    • Data Corruption (Hardware Issues): Risk reduced from Medium to Low/Medium (earlier detection, but performance impact).
  • Currently Implemented: Not Implemented.

  • Missing Implementation: The options.paranoid_checks = true; line needs to be added when opening the LevelDB database.

  • Description:

    1. Understand Compaction: Familiarize yourself with LevelDB's compaction process (how it merges and reorganizes data). Read the LevelDB documentation.
    2. Monitor Compaction: Use monitoring tools (if available) or add logging to your application to track LevelDB's compaction activity (number of compactions, duration, I/O).
    3. Adjust Options: Modify the following leveldb::Options (when opening the database) based on your workload and monitoring:
      • options.max_background_compactions: Limits the number of concurrent background compaction threads. Too many can overload the system; too few can lead to excessive SSTable files.
      • options.max_background_flushes: Limits the number of concurrent background flushes (writing memtables to SSTables).
      • options.write_buffer_size: The size of the in-memory memtable. Larger memtables can improve write performance but increase memory usage.
      • options.max_file_size: The maximum size of an SSTable file. Smaller files can improve read performance for point lookups but increase the number of files.
      • options.level0_file_num_compaction_trigger: The number of level-0 files that trigger a compaction.
      • options.level0_slowdown_writes_trigger: The number of level-0 files that trigger write slowdowns.
      • options.level0_stop_writes_trigger: The number of level-0 files that stop writes completely.
    4. Iterative Tuning: Adjust these options iteratively, monitoring the impact on performance and resource usage. There is no one-size-fits-all configuration; it depends heavily on the application's workload.
  • Threats Mitigated:

    • Denial of Service (Resource Exhaustion): Severity: Medium. Poorly tuned compaction can lead to excessive resource usage.
    • Performance Degradation: Severity: Medium. Inefficient compaction can slow down read and write operations.
  • Impact:

    • Denial of Service (Resource Exhaustion): Risk reduced from Medium to Low (with proper tuning).
    • Performance Degradation: Risk reduced from Medium to Low (with proper tuning).
  • Currently Implemented: Not Implemented. Default LevelDB options are used.

  • Missing Implementation: Requires analysis of the application's workload and iterative tuning of the LevelDB options.

  • Description:

    1. Identify LevelDB Calls: Locate all calls to LevelDB API functions (e.g., Put, Get, Delete, Open, iterators).
    2. Check leveldb::Status: Immediately after every LevelDB API call, check the returned leveldb::Status object:
      leveldb::Status s = db->Put(leveldb::WriteOptions(), key, value);
      if (!s.ok()) {
          // Handle the error
          std::cerr << "LevelDB Put error: " << s.ToString() << std::endl;
          // ... take appropriate action ...
      }
    3. Handle Specific Errors: Implement specific error handling for different status codes:
      • s.ok(): Success.
      • s.IsNotFound(): Key not found (for Get).
      • s.IsCorruption(): Data corruption detected. This is critical to handle.
      • s.IsIOError(): I/O error.
      • s.IsNotSupportedError(): Operation not supported.
      • s.IsInvalidArgument(): Invalid argument passed to the function.
    4. Logging: Log all errors, including the output of s.ToString().
    5. Recovery/Retry: For transient errors (like some I/O errors), implement retry logic (with appropriate backoff).
    6. Graceful Degradation/Shutdown: For critical errors (like corruption), either attempt to recover (from a backup) or shut down the application gracefully to prevent further damage.
  • Threats Mitigated:

    • Data Corruption (Unhandled Errors): Severity: Medium. Unhandled errors can lead to inconsistencies.
    • Application Crashes (Unhandled Exceptions): Severity: Medium. Unhandled errors can crash the application.
    • Denial of Service (Resource Leaks): Severity: Low. Unhandled errors can lead to resource leaks.
  • Impact:

    • Data Corruption (Unhandled Errors): Risk reduced from Medium to Low.
    • Application Crashes (Unhandled Exceptions): Risk reduced from Medium to Low.
    • Denial of Service (Resource Leaks): Risk reduced from Low to Very Low.
  • Currently Implemented: Partially. Some LevelDB calls check the status, but not all. Error handling is inconsistent.

  • Missing Implementation:

    • Consistent checking of leveldb::Status after every LevelDB API call.
    • Comprehensive and specific error handling for all possible error codes.
    • Consistent and informative error logging.
    • Robust recovery/retry mechanisms where appropriate.
    • Graceful shutdown on unrecoverable errors.
  • Description:

    1. Understand leveldb::WriteOptions::sync: This option controls whether a write operation waits for the data to be written to the underlying storage device before returning.
      • sync = false (default): The write returns immediately after the data is written to the operating system's buffer cache. This is faster but less durable (data can be lost on a power outage).
      • sync = true: The write waits for the data to be flushed to the physical storage device. This is slower but provides stronger durability guarantees.
    2. Use Asynchronously (Default): Use asynchronous writes (sync = false) for most operations where eventual consistency is acceptable. This provides better performance.
    3. Use Synchronously (Sparingly): Use synchronous writes (sync = true) only when absolutely necessary for data durability, such as:
      • Writing critical metadata.
      • Writing transaction logs (if you're implementing transactions on top of LevelDB).
      • Situations where data loss is unacceptable, even in the event of a power failure.
    4. Set the option:
      leveldb::WriteOptions write_options;
      write_options.sync = true; // Or false, as appropriate
      leveldb::Status s = db->Put(write_options, key, value);
  • Threats Mitigated:

    • Data Loss (Power Outage/System Crash): Severity: Medium/High (depending on the data). Data loss since the last successful sync.
    • Denial of Service (Excessive Sync Writes): Severity: Medium. Too many synchronous writes can significantly slow down the system.
  • Impact:

    • Data Loss: Risk reduced from Medium/High to Low (for data written with sync = true).
    • Denial of Service: Risk increased if sync = true is used excessively. Careful consideration is needed.
  • Currently Implemented: Not explicitly managed. The default (sync = false) is likely being used in most cases.

  • Missing Implementation:

    • A conscious decision about when to use sync = true needs to be made for each write operation.
    • Code needs to be modified to explicitly set write_options.sync appropriately.