summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Salyzyn2017-01-03 16:00:19 -0600
committerMark Salyzyn2017-01-04 16:46:58 -0600
commit247d682fe1b0dd4c8f149b7f5c89c546df17873a (patch)
treed11ddcf98311274cb4612f41b506ebbc9c0b4a3b /logd/LogAudit.cpp
parentfe05f1cde4fd812bbb20a39d37ee7be6b95402c3 (diff)
downloadplatform-system-core-247d682fe1b0dd4c8f149b7f5c89c546df17873a.tar.gz
platform-system-core-247d682fe1b0dd4c8f149b7f5c89c546df17873a.tar.xz
platform-system-core-247d682fe1b0dd4c8f149b7f5c89c546df17873a.zip
logd: sepolicy dynamic rate limiting
Processing overhead for selinux violation messages is costly. We want to deal with bursts of violations, but we have no intent of allowing that sustained burst to go unabated as there is a cost of processing and battery usage. Tunables in libaudit.h are: AUDIT_RATE_LIMIT_DEFAULT 20 /* acceptable burst rate */ AUDIT_RATE_LIMIT_BURST_DURATION 10 /* number of seconds of burst */ AUDIT_RATE_LIMIT_MAX 5 /* acceptable sustained rate */ Since we can only asymptotically handle DEFAULT rate, we set an upper threshold of half way between the MAX and DEFAULT rate. Default kernel audit subsystem message rate is set to 20 a second. If sepolicy exceeds 125 violation messages over up to ten seconds (>=~12/s), tell kernel audit subsystem to drop the rate to 5 messages a second. If rate drops below 50 messages over the past ten seconds (<5/s), tell kernel it is ok to increase the burst rate back to 20 messages a second. Test: gTest logd-unit-tests --gtest_filter=logd.sepolicy_rate_limiter_* Bug: 27878170 Change-Id: I843f8dcfbb3ecfbbe94a4865ea332c858e3be7f2
Diffstat (limited to 'logd/LogAudit.cpp')
-rw-r--r--logd/LogAudit.cpp51
1 files changed, 47 insertions, 4 deletions
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 11ffcb785..92d957fb1 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -43,7 +43,7 @@
43 '>' 43 '>'
44 44
45LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg) : 45LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg) :
46 SocketListener(getLogSocket(), false), 46 SocketListener(mSock = getLogSocket(), false),
47 logbuf(buf), 47 logbuf(buf),
48 reader(reader), 48 reader(reader),
49 fdDmesg(fdDmesg), 49 fdDmesg(fdDmesg),
@@ -51,19 +51,62 @@ LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg) :
51 BOOL_DEFAULT_TRUE)), 51 BOOL_DEFAULT_TRUE)),
52 events(__android_logger_property_get_bool("ro.logd.auditd.events", 52 events(__android_logger_property_get_bool("ro.logd.auditd.events",
53 BOOL_DEFAULT_TRUE)), 53 BOOL_DEFAULT_TRUE)),
54 initialized(false) { 54 initialized(false),
55 tooFast(false) {
55 static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO), 56 static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
56 'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':', 57 'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':',
57 ' ', 's', 't', 'a', 'r', 't', '\n' }; 58 ' ', 's', 't', 'a', 'r', 't', '\n' };
58 write(fdDmesg, auditd_message, sizeof(auditd_message)); 59 write(fdDmesg, auditd_message, sizeof(auditd_message));
59} 60}
60 61
62void LogAudit::checkRateLimit() {
63
64 // trim list for AUDIT_RATE_LIMIT_BURST_DURATION of history
65 log_time oldest(AUDIT_RATE_LIMIT_BURST_DURATION, 0);
66 bucket.emplace(android_log_clockid());
67 oldest = bucket.back() - oldest;
68 while (bucket.front() < oldest) bucket.pop();
69
70 static const size_t upperThreshold =
71 ((AUDIT_RATE_LIMIT_BURST_DURATION *
72 (AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) + 1) /
73 2;
74 if (bucket.size() >= upperThreshold) {
75 // Hit peak, slow down source
76 if (!tooFast) {
77 tooFast = true;
78 audit_rate_limit(mSock, AUDIT_RATE_LIMIT_MAX);
79 }
80
81 // We do not need to hold on to the full set of timing data history,
82 // let's ensure it does not grow without bounds. This also ensures
83 // that std::dequeue underneath behaves almost like a ring buffer.
84 do {
85 bucket.pop();
86 } while (bucket.size() >= upperThreshold);
87 return;
88 }
89
90 if (!tooFast) return;
91
92 static const size_t lowerThreshold = AUDIT_RATE_LIMIT_BURST_DURATION *
93 AUDIT_RATE_LIMIT_MAX;
94
95 if (bucket.size() >= lowerThreshold) return;
96
97 tooFast = false;
98 // Went below max sustained rate, allow source to speed up
99 audit_rate_limit(mSock, AUDIT_RATE_LIMIT_DEFAULT);
100}
101
61bool LogAudit::onDataAvailable(SocketClient *cli) { 102bool LogAudit::onDataAvailable(SocketClient *cli) {
62 if (!initialized) { 103 if (!initialized) {
63 prctl(PR_SET_NAME, "logd.auditd"); 104 prctl(PR_SET_NAME, "logd.auditd");
64 initialized = true; 105 initialized = true;
65 } 106 }
66 107
108 checkRateLimit();
109
67 struct audit_message rep; 110 struct audit_message rep;
68 111
69 rep.nlh.nlmsg_type = 0; 112 rep.nlh.nlmsg_type = 0;
@@ -75,8 +118,7 @@ bool LogAudit::onDataAvailable(SocketClient *cli) {
75 return false; 118 return false;
76 } 119 }
77 120
78 logPrint("type=%d %.*s", 121 logPrint("type=%d %.*s", rep.nlh.nlmsg_type, rep.nlh.nlmsg_len, rep.data);
79 rep.nlh.nlmsg_type, rep.nlh.nlmsg_len, rep.data);
80 122
81 return true; 123 return true;
82} 124}
@@ -351,5 +393,6 @@ int LogAudit::getLogSocket() {
351 audit_close(fd); 393 audit_close(fd);
352 fd = -1; 394 fd = -1;
353 } 395 }
396 (void)audit_rate_limit(fd, AUDIT_RATE_LIMIT_DEFAULT);
354 return fd; 397 return fd;
355} 398}