[scudo] Soft and hard RSS limit checks
ClosedPublic

Authored by cryptoad on Tue, Nov 14, 9:54 AM.

Details

Summary

This implements an opportunistic check for the RSS limit.

For ASan, this was implemented thanks to a background thread checking the
current RSS vs the set limit every 100ms. This was deemed problematic for Scudo
due to potential Android concerns (Zygote as pointed out by Aleksey) as well as
the general inconvenience of having a permanent background thread.

If a limit (soft or hard) is specified, we will attempt to update the RSS limit
status (exceeded or not) every 100ms. This is done in an opportunistic way: if
we can update it, we do it, if not we return the current status, mostly because
we don't need it to be fully consistent (it's done every 100ms anyway). If the
limit is exceeded allocate will act as if OOM for a soft limit, or just die
for a hard limit.

We use the common_flags()'s hard_rss_limit_mb & soft_rss_limit_mb for
configuration of the limits.

cryptoad created this revision.Tue, Nov 14, 9:54 AM
cryptoad updated this revision to Diff 122885.Tue, Nov 14, 11:17 AM

Make HardRssLimitMb & SoftRssLimitMb allocator globals. This will allow
later to set those at runtime rather than go through common_flags() every
time.

alekseyshl added inline comments.Tue, Nov 14, 1:34 PM
lib/scudo/scudo_allocator.cpp
313

How about

if (LIKELY(CurrentCheck < LastCheck + (100ULL * 1000000ULL)))

318

How fast is it? It might read a file, right?

333

I find this structure to be easier to grasp, but it's up to you, just a suggestion (and maybe yours yield a better code):

if (atomic_load_relaxed(&RssLimitExceeded)) {
  if (CurrentRssMb <= SoftRssLimitMb)
    atomic_store_relaxed(&RssLimitExceeded, false);
} else {
  if (CurrentRssMb > SoftRssLimitMb) {
    atomic_store_relaxed(&RssLimitExceeded, true);
    Report("%s: soft RSS limit exhausted (%zdMb vs %zdMb)\n",
           SanitizerToolName, SoftRssLimitMb, CurrentRssMb);
  }
}
362

It needs UNLIKELY

test/scudo/rss.c
46

What's this for?

cryptoad updated this revision to Diff 122908.Tue, Nov 14, 1:45 PM
cryptoad marked 3 inline comments as done.

Addressing review comments.

cryptoad added inline comments.Tue, Nov 14, 1:46 PM
lib/scudo/scudo_allocator.cpp
318

It either reads /proc/self/statm, or falls back to getrusage if statm is not allowed.
So yes, not the fastest of code paths.
I am not sure I see a way around it though.

test/scudo/rss.c
46

I added it because it seems that if there is nothing on stdout or stderr, FileCheck complains and fails, which is the case for the "nolimit" tests.

cryptoad added inline comments.Tue, Nov 14, 1:50 PM
lib/scudo/scudo_allocator.cpp
318

Also the common flag is called can_use_proc_maps_statm, which is misdirecting, I think it really should be can_use_proc_self_statm.

alekseyshl added inline comments.Tue, Nov 14, 2:13 PM
lib/scudo/scudo_allocator.cpp
318

Do not fall back to reading proc/self/statm, for example? Reading a file might cause unpredictable delays, right? Not too great for the allocator. Maybe increase the interval to 1s?

Also the general idea does not feel right, the allocator is one of the moving parts affecting RSS, not the only part, why should it be burdened with RSS check?

But yeah, I have questions, but not answers, no good solution either.

cryptoad added inline comments.Tue, Nov 14, 2:43 PM
lib/scudo/scudo_allocator.cpp
318

I agree that it's not an ideal solution.

For some context, I am trying to address a problem that we are bringing to ourselves: due to the memory reservation made by the Primary, we can't enforce a sensible RLIMIT_AS for a process. Which some processes need (see limitProcessMemory in Android). The solution that comes to mind is to be able to constrain our RSS since we are the most likely consumer of memory. While not ideal, I don't think it's too unreasonable either.

Now for potential improvements I could code my own getMaxRSS that would be only getrusage based. That way, we skip the filesystem interaction. It would require a Fuchsia equivalent but that should be straightforward.

alekseyshl accepted this revision.Tue, Nov 14, 3:09 PM

Ok, add a TODO with the required improvements and let's get it in.

test/scudo/rss.c
46

There's --allow-empty flag, but this way is fine too.

This revision is now accepted and ready to land.Tue, Nov 14, 3:09 PM
cryptoad updated this revision to Diff 122929.Tue, Nov 14, 3:20 PM
cryptoad marked 3 inline comments as done.

Updating the test.

cryptoad updated this revision to Diff 122932.Tue, Nov 14, 3:44 PM

Adding a TODO with regard to GetRSS & /proc/self/statm.
Updating the tests to include can_use_proc_maps_statm again.

cryptoad marked 5 inline comments as done.Tue, Nov 14, 3:44 PM
cryptoad updated this revision to Diff 122933.Tue, Nov 14, 3:47 PM

Adding a couple of additional restrictions to the output of the tests.

cryptoad closed this revision.Wed, Nov 15, 8:40 AM