diff options
author | Kostya Kortchinsky <kostyak@google.com> | 2017-07-24 15:29:38 +0000 |
---|---|---|
committer | Kostya Kortchinsky <kostyak@google.com> | 2017-07-24 15:29:38 +0000 |
commit | 5884a6648ad229cc07706b32bfc3734e3313f231 (patch) | |
tree | a9e3d3ed33bfa78c00d09b2f465947d26b34fd60 /lib/scudo/scudo_flags.cpp | |
parent | 614a50c1049b7616fe968def766b79713c12f64e (diff) | |
download | compiler-rt-5884a6648ad229cc07706b32bfc3734e3313f231.tar.gz |
[scudo] Quarantine overhaul
Summary:
First, some context.
The main feedback we get about the quarantine is that it's too memory hungry.
A single MB of quarantine will have an impact of 3 to 4MB of PSS/RSS, and
things quickly get out of hand in terms of memory usage, and the quarantine
ends up disabled.
The main objective of the quarantine is to protect from use-after-free
exploitation by making it harder for an attacker to reallocate a controlled
chunk in place of the targeted freed chunk. This is achieved by not making it
available to the backend right away for reuse, but holding it a little while.
Historically, what has usually been the target of such attacks was objects,
where vtable pointers or other function pointers could constitute a valuable
targeti to replace. Those are usually on the smaller side. There is barely any
advantage in putting the quarantine several megabytes of RGB data or the like.
Now for the patch.
This patch introduces a new way the Quarantine behaves in Scudo. First of all,
the size of the Quarantine will be defined in KB instead of MB, then we
introduce a new option: the size up to which (lower than or equal to) a chunk
will be quarantined. This way, we only quarantine smaller chunks, and the size
of the quarantine remains manageable. It also prevents someone from triggering
a recycle by allocating something huge. We default to 512 bytes on 32-bit and
2048 bytes on 64-bit platforms.
In details, the patches includes the following:
- introduce `QuarantineSizeKb`, but honor `QuarantineSizeMb` if set to fall
back to the old behavior (meaning no threshold in that case);
`QuarantineSizeMb` is described as deprecated in the options descriptios;
documentation update will follow;
- introduce `QuarantineChunksUpToSize`, the new threshold value;
- update the `quarantine.cpp` test, and other tests using `QuarantineSizeMb`;
- remove `AllocatorOptions::copyTo`, it wasn't used;
- slightly change the logic around `quarantineOrDeallocateChunk` to accomodate
for the new logic; rename a couple of variables there as well;
Rewriting the tests, I found a somewhat annoying bug where non-default aligned
chunks would account for more than needed when placed in the quarantine due to
`<< MinAlignment` instead of `<< MinAlignmentLog`. This is fixed and tested for
now.
Reviewers: alekseyshl, kcc
Reviewed By: alekseyshl
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D35694
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@308884 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/scudo/scudo_flags.cpp')
-rw-r--r-- | lib/scudo/scudo_flags.cpp | 49 |
1 files changed, 37 insertions, 12 deletions
diff --git a/lib/scudo/scudo_flags.cpp b/lib/scudo/scudo_flags.cpp index 90f0cbf4b..ab94afac9 100644 --- a/lib/scudo/scudo_flags.cpp +++ b/lib/scudo/scudo_flags.cpp @@ -67,27 +67,52 @@ void initFlags() { // Sanity checks and default settings for the Quarantine parameters. - if (f->QuarantineSizeMb < 0) { - const int DefaultQuarantineSizeMb = FIRST_32_SECOND_64(4, 16); - f->QuarantineSizeMb = DefaultQuarantineSizeMb; + if (f->QuarantineSizeMb >= 0) { + // Backward compatible logic if QuarantineSizeMb is set. + if (f->QuarantineSizeKb >= 0) { + dieWithMessage("ERROR: please use either QuarantineSizeMb (deprecated) " + "or QuarantineSizeKb, but not both\n"); + } + if (f->QuarantineChunksUpToSize >= 0) { + dieWithMessage("ERROR: QuarantineChunksUpToSize cannot be used in " + " conjunction with the deprecated QuarantineSizeMb option\n"); + } + // If everything is in order, update QuarantineSizeKb accordingly. + f->QuarantineSizeKb = f->QuarantineSizeMb * 1024; + } else { + // Otherwise proceed with the new options. + if (f->QuarantineSizeKb < 0) { + const int DefaultQuarantineSizeKb = FIRST_32_SECOND_64(64, 256); + f->QuarantineSizeKb = DefaultQuarantineSizeKb; + } + if (f->QuarantineChunksUpToSize < 0) { + const int DefaultQuarantineChunksUpToSize = FIRST_32_SECOND_64(512, 2048); + f->QuarantineChunksUpToSize = DefaultQuarantineChunksUpToSize; + } } - // We enforce an upper limit for the quarantine size of 4Gb. - if (f->QuarantineSizeMb > (4 * 1024)) { + + // We enforce an upper limit for the chunk quarantine threshold of 4Mb. + if (f->QuarantineChunksUpToSize > (4 * 1024 * 1024)) { + dieWithMessage("ERROR: the chunk quarantine threshold is too large\n"); + } + + // We enforce an upper limit for the quarantine size of 32Mb. + if (f->QuarantineSizeKb > (32 * 1024)) { dieWithMessage("ERROR: the quarantine size is too large\n"); } + if (f->ThreadLocalQuarantineSizeKb < 0) { - const int DefaultThreadLocalQuarantineSizeKb = - FIRST_32_SECOND_64(64, 256); + const int DefaultThreadLocalQuarantineSizeKb = FIRST_32_SECOND_64(16, 64); f->ThreadLocalQuarantineSizeKb = DefaultThreadLocalQuarantineSizeKb; } - // And an upper limit of 128Mb for the thread quarantine cache. - if (f->ThreadLocalQuarantineSizeKb > (128 * 1024)) { + // And an upper limit of 8Mb for the thread quarantine cache. + if (f->ThreadLocalQuarantineSizeKb > (8 * 1024)) { dieWithMessage("ERROR: the per thread quarantine cache size is too " - "large\n"); + "large\n"); } - if (f->ThreadLocalQuarantineSizeKb == 0 && f->QuarantineSizeMb > 0) { + if (f->ThreadLocalQuarantineSizeKb == 0 && f->QuarantineSizeKb > 0) { dieWithMessage("ERROR: ThreadLocalQuarantineSizeKb can be set to 0 only " - "when QuarantineSizeMb is set to 0\n"); + "when QuarantineSizeKb is set to 0\n"); } } |