|
8 | 8 | #include "seccomp/action/ActionTrace.h"
|
9 | 9 | #include "seccomp/filter/LibSeccompFilter.h"
|
10 | 10 |
|
| 11 | +#include <sys/mman.h> |
11 | 12 | #include <sys/resource.h>
|
12 | 13 | #include <sys/time.h>
|
13 | 14 |
|
| 15 | +#ifndef MREMAP_DONTUNMAP |
| 16 | +// Due to this flag being introduced in Linux 5.7 there are many system which do |
| 17 | +// not define it |
| 18 | +#define MREMAP_DONTUNMAP 4 |
| 19 | +#endif |
| 20 | + |
14 | 21 | #include <csignal>
|
15 | 22 | #include <cstdint>
|
16 | 23 | #include <fstream>
|
@@ -40,33 +47,57 @@ MemoryLimitListener::MemoryLimitListener(uint64_t memoryLimitKb)
|
40 | 47 | if (!vmPeakValid_) {
|
41 | 48 | return tracer::TraceAction::CONTINUE;
|
42 | 49 | }
|
43 |
| - |
44 |
| - uint64_t memoryUsage = getMemoryUsageKb() + |
45 |
| - tracee.getSyscallArgument(1) / 1024; |
46 |
| - memoryPeakKb_ = std::max(memoryPeakKb_, memoryUsage); |
47 |
| - outputBuilder_->setMemoryPeak(memoryPeakKb_); |
48 |
| - logger::debug( |
49 |
| - "Memory usage after mmap ", |
50 |
| - VAR(memoryUsage), |
51 |
| - ", ", |
52 |
| - VAR(memoryPeakKb_)); |
53 |
| - |
54 |
| - if (memoryUsage > memoryLimitKb_) { |
55 |
| - outputBuilder_->setKillReason( |
56 |
| - printer::OutputBuilder::KillReason::MLE, |
57 |
| - "memory limit exceeded"); |
58 |
| - logger::debug( |
59 |
| - "Limit ", |
60 |
| - VAR(memoryLimitKb_), |
61 |
| - " exceeded, killing tracee"); |
62 |
| - return tracer::TraceAction::KILL; |
63 |
| - } |
64 |
| - return tracer::TraceAction::CONTINUE; |
| 50 | + return handleMemoryAllocation( |
| 51 | + tracee.getSyscallArgument(1) / 1024); |
65 | 52 | }),
|
66 | 53 | Arg(0) == 0 && Arg(1) > MEMORY_LIMIT_MARGIN / 2));
|
67 | 54 | }
|
| 55 | + syscallRules_.emplace_back(seccomp::SeccompRule( |
| 56 | + "mremap", |
| 57 | + seccomp::action::ActionTrace([this](tracer::Tracee& tracee) { |
| 58 | + TRACE(); |
| 59 | + uint64_t old_size = tracee.getSyscallArgument(1); |
| 60 | + uint64_t new_size = tracee.getSyscallArgument(2); |
| 61 | + uint64_t flags = tracee.getSyscallArgument(3); |
| 62 | + if (!vmPeakValid_) { |
| 63 | + return tracer::TraceAction::CONTINUE; |
| 64 | + } |
| 65 | + bool doesntUnmap = |
| 66 | + (flags & MREMAP_DONTUNMAP) == MREMAP_DONTUNMAP; |
| 67 | + // Allow user to shrink its memory |
| 68 | + if (!doesntUnmap && old_size >= new_size) { |
| 69 | + return tracer::TraceAction::CONTINUE; |
| 70 | + } |
| 71 | + uint64_t newMemoryAllocated = new_size; |
| 72 | + // Do not count already allocated memory |
| 73 | + if (!doesntUnmap) |
| 74 | + newMemoryAllocated -= old_size; |
| 75 | + newMemoryAllocated /= 1024; |
| 76 | + return handleMemoryAllocation(newMemoryAllocated); |
| 77 | + }), |
| 78 | + Arg(2) > MEMORY_LIMIT_MARGIN / 2)); |
68 | 79 | }
|
| 80 | +tracer::TraceAction MemoryLimitListener::handleMemoryAllocation( |
| 81 | + uint64_t allocatedMemoryKb) { |
| 82 | + uint64_t memoryUsage = getMemoryUsageKb() + allocatedMemoryKb; |
| 83 | + memoryPeakKb_ = std::max(memoryPeakKb_, memoryUsage); |
| 84 | + outputBuilder_->setMemoryPeak(memoryPeakKb_); |
| 85 | + logger::debug( |
| 86 | + "Memory usage after allocation ", |
| 87 | + VAR(memoryUsage), |
| 88 | + ", ", |
| 89 | + VAR(memoryPeakKb_)); |
69 | 90 |
|
| 91 | + if (memoryLimitKb_ > 0 && memoryUsage > memoryLimitKb_) { |
| 92 | + outputBuilder_->setKillReason( |
| 93 | + printer::OutputBuilder::KillReason::MLE, |
| 94 | + "memory limit exceeded"); |
| 95 | + logger::debug( |
| 96 | + "Limit ", VAR(memoryLimitKb_), " exceeded, killing tracee"); |
| 97 | + return tracer::TraceAction::KILL; |
| 98 | + } |
| 99 | + return tracer::TraceAction::CONTINUE; |
| 100 | +} |
70 | 101 | void MemoryLimitListener::onPostForkChild() {
|
71 | 102 | TRACE();
|
72 | 103 |
|
|
0 commit comments