Merge "LogAudit: remove dynamic rate limiter"
am: 9e7cec22e0
Change-Id: I332b64922dbe52fe0e254de7150e36fa6bc0fdb9
This commit is contained in:
commit
cf7f19f4b9
5 changed files with 14 additions and 134 deletions
|
|
@ -45,7 +45,7 @@
|
||||||
'0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, '>'
|
'0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, '>'
|
||||||
|
|
||||||
LogAudit::LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg)
|
LogAudit::LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg)
|
||||||
: SocketListener(mSock = getLogSocket(), false),
|
: SocketListener(getLogSocket(), false),
|
||||||
logbuf(buf),
|
logbuf(buf),
|
||||||
reader(reader),
|
reader(reader),
|
||||||
fdDmesg(fdDmesg),
|
fdDmesg(fdDmesg),
|
||||||
|
|
@ -53,8 +53,7 @@ LogAudit::LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg)
|
||||||
BOOL_DEFAULT_TRUE)),
|
BOOL_DEFAULT_TRUE)),
|
||||||
events(__android_logger_property_get_bool("ro.logd.auditd.events",
|
events(__android_logger_property_get_bool("ro.logd.auditd.events",
|
||||||
BOOL_DEFAULT_TRUE)),
|
BOOL_DEFAULT_TRUE)),
|
||||||
initialized(false),
|
initialized(false) {
|
||||||
tooFast(false) {
|
|
||||||
static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
|
static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
|
||||||
'l',
|
'l',
|
||||||
'o',
|
'o',
|
||||||
|
|
@ -78,54 +77,12 @@ LogAudit::LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg)
|
||||||
write(fdDmesg, auditd_message, sizeof(auditd_message));
|
write(fdDmesg, auditd_message, sizeof(auditd_message));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogAudit::checkRateLimit() {
|
|
||||||
// trim list for AUDIT_RATE_LIMIT_BURST_DURATION of history
|
|
||||||
log_time oldest(AUDIT_RATE_LIMIT_BURST_DURATION, 0);
|
|
||||||
bucket.emplace(android_log_clockid());
|
|
||||||
oldest = bucket.back() - oldest;
|
|
||||||
while (bucket.front() < oldest) bucket.pop();
|
|
||||||
|
|
||||||
static const size_t upperThreshold =
|
|
||||||
((AUDIT_RATE_LIMIT_BURST_DURATION *
|
|
||||||
(AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) +
|
|
||||||
1) /
|
|
||||||
2;
|
|
||||||
if (bucket.size() >= upperThreshold) {
|
|
||||||
// Hit peak, slow down source
|
|
||||||
if (!tooFast) {
|
|
||||||
tooFast = true;
|
|
||||||
audit_rate_limit(mSock, AUDIT_RATE_LIMIT_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We do not need to hold on to the full set of timing data history,
|
|
||||||
// let's ensure it does not grow without bounds. This also ensures
|
|
||||||
// that std::dequeue underneath behaves almost like a ring buffer.
|
|
||||||
do {
|
|
||||||
bucket.pop();
|
|
||||||
} while (bucket.size() >= upperThreshold);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tooFast) return;
|
|
||||||
|
|
||||||
static const size_t lowerThreshold =
|
|
||||||
AUDIT_RATE_LIMIT_BURST_DURATION * AUDIT_RATE_LIMIT_MAX;
|
|
||||||
|
|
||||||
if (bucket.size() >= lowerThreshold) return;
|
|
||||||
|
|
||||||
tooFast = false;
|
|
||||||
// Went below max sustained rate, allow source to speed up
|
|
||||||
audit_rate_limit(mSock, AUDIT_RATE_LIMIT_DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LogAudit::onDataAvailable(SocketClient* cli) {
|
bool LogAudit::onDataAvailable(SocketClient* cli) {
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
prctl(PR_SET_NAME, "logd.auditd");
|
prctl(PR_SET_NAME, "logd.auditd");
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
checkRateLimit();
|
|
||||||
|
|
||||||
struct audit_message rep;
|
struct audit_message rep;
|
||||||
|
|
||||||
rep.nlh.nlmsg_type = 0;
|
rep.nlh.nlmsg_type = 0;
|
||||||
|
|
@ -486,6 +443,5 @@ int LogAudit::getLogSocket() {
|
||||||
audit_close(fd);
|
audit_close(fd);
|
||||||
fd = -1;
|
fd = -1;
|
||||||
}
|
}
|
||||||
(void)audit_rate_limit(fd, AUDIT_RATE_LIMIT_DEFAULT);
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@
|
||||||
#define _LOGD_LOG_AUDIT_H__
|
#define _LOGD_LOG_AUDIT_H__
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
#include <sysutils/SocketListener.h>
|
#include <sysutils/SocketListener.h>
|
||||||
|
|
||||||
|
|
@ -34,11 +33,6 @@ class LogAudit : public SocketListener {
|
||||||
bool events;
|
bool events;
|
||||||
bool initialized;
|
bool initialized;
|
||||||
|
|
||||||
bool tooFast;
|
|
||||||
int mSock;
|
|
||||||
std::queue<log_time> bucket;
|
|
||||||
void checkRateLimit();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg);
|
LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg);
|
||||||
int log(char* buf, size_t len);
|
int log(char* buf, size_t len);
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,8 @@ int audit_setup(int fd, pid_t pid) {
|
||||||
* and the the mask set to AUDIT_STATUS_PID
|
* and the the mask set to AUDIT_STATUS_PID
|
||||||
*/
|
*/
|
||||||
status.pid = pid;
|
status.pid = pid;
|
||||||
status.mask = AUDIT_STATUS_PID;
|
status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT;
|
||||||
|
status.rate_limit = AUDIT_RATE_LIMIT; /* audit entries per second */
|
||||||
|
|
||||||
/* Let the kernel know this pid will be registering for audit events */
|
/* Let the kernel know this pid will be registering for audit events */
|
||||||
rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
|
rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
|
||||||
|
|
@ -183,26 +184,6 @@ int audit_setup(int fd, pid_t pid) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int audit_rate_limit(int fd, unsigned rate_limit) {
|
|
||||||
int rc;
|
|
||||||
struct audit_message rep;
|
|
||||||
struct audit_status status;
|
|
||||||
|
|
||||||
memset(&status, 0, sizeof(status));
|
|
||||||
|
|
||||||
status.mask = AUDIT_STATUS_RATE_LIMIT;
|
|
||||||
status.rate_limit = rate_limit; /* audit entries per second */
|
|
||||||
|
|
||||||
rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
|
|
||||||
if (rc < 0) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int audit_open() {
|
int audit_open() {
|
||||||
return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT);
|
return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,22 +89,8 @@ extern int audit_get_reply(int fd, struct audit_message* rep, reply_t block,
|
||||||
*/
|
*/
|
||||||
extern int audit_setup(int fd, pid_t pid);
|
extern int audit_setup(int fd, pid_t pid);
|
||||||
|
|
||||||
/**
|
/* Max audit messages per second */
|
||||||
* Sets the rate limit to receive audit netlink events from the kernel
|
#define AUDIT_RATE_LIMIT 5
|
||||||
* @param fd
|
|
||||||
* The fd returned by a call to audit_open()
|
|
||||||
* @param max_rate
|
|
||||||
* The cap of the maximum number of audit messages a second
|
|
||||||
* @return
|
|
||||||
* This function returns 0 on success, -errno on error.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Guidelines to follow for dynamic rate_limit */
|
|
||||||
#define AUDIT_RATE_LIMIT_DEFAULT 20 /* acceptable burst rate */
|
|
||||||
#define AUDIT_RATE_LIMIT_BURST_DURATION 10 /* number of seconds of burst */
|
|
||||||
#define AUDIT_RATE_LIMIT_MAX 5 /* acceptable sustained rate */
|
|
||||||
|
|
||||||
extern int audit_rate_limit(int fd, unsigned rate_limit);
|
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1195,51 +1195,14 @@ TEST(logd, sepolicy_rate_limiter) {
|
||||||
<< "fail as this device is in a bad state, "
|
<< "fail as this device is in a bad state, "
|
||||||
<< "but is not strictly a unit test failure.";
|
<< "but is not strictly a unit test failure.";
|
||||||
}
|
}
|
||||||
// sepolicy_rate_limiter_maximum
|
|
||||||
{ // maximum precharch test block.
|
static const int rate = AUDIT_RATE_LIMIT;
|
||||||
static constexpr int rate = AUDIT_RATE_LIMIT_MAX;
|
static const int duration = 2;
|
||||||
static constexpr int duration = 2;
|
// Two seconds of sustained denials. Depending on the overlap in the time
|
||||||
// Two seconds of a liveable sustained rate
|
// window that the kernel is considering vs what this test is considering,
|
||||||
EXPECT_EQ(rate * duration,
|
// allow some additional denials to prevent a flaky test.
|
||||||
count_avc(sepolicy_rate(rate, rate * duration)));
|
EXPECT_LE(count_avc(sepolicy_rate(rate, rate * duration)),
|
||||||
}
|
rate * duration + rate);
|
||||||
// sepolicy_rate_limiter_sub_burst
|
|
||||||
{ // maximum period below half way between sustainable and burst rate
|
|
||||||
static constexpr int threshold =
|
|
||||||
((AUDIT_RATE_LIMIT_BURST_DURATION *
|
|
||||||
(AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) +
|
|
||||||
1) /
|
|
||||||
2;
|
|
||||||
static constexpr int rate =
|
|
||||||
(threshold / AUDIT_RATE_LIMIT_BURST_DURATION) - 1;
|
|
||||||
static constexpr int duration = AUDIT_RATE_LIMIT_BURST_DURATION;
|
|
||||||
EXPECT_EQ(rate * duration,
|
|
||||||
count_avc(sepolicy_rate(rate, rate * duration)));
|
|
||||||
}
|
|
||||||
// sepolicy_rate_limiter_spam
|
|
||||||
{ // hit avc: hard beyond reason block.
|
|
||||||
// maximum period of double the maximum burst rate
|
|
||||||
static constexpr int threshold =
|
|
||||||
((AUDIT_RATE_LIMIT_BURST_DURATION *
|
|
||||||
(AUDIT_RATE_LIMIT_DEFAULT + AUDIT_RATE_LIMIT_MAX)) +
|
|
||||||
1) /
|
|
||||||
2;
|
|
||||||
static constexpr int rate = AUDIT_RATE_LIMIT_DEFAULT * 2;
|
|
||||||
static constexpr int duration = threshold / AUDIT_RATE_LIMIT_DEFAULT;
|
|
||||||
EXPECT_GE(
|
|
||||||
((AUDIT_RATE_LIMIT_DEFAULT * duration) * 115) / 100, // +15% margin
|
|
||||||
count_avc(sepolicy_rate(rate, rate * duration)));
|
|
||||||
// give logd another 3 seconds to react to the burst before checking
|
|
||||||
sepolicy_rate(rate, rate * 3);
|
|
||||||
// maximum period at double maximum burst rate (spam filter kicked in)
|
|
||||||
EXPECT_GE(threshold * 2,
|
|
||||||
count_avc(sepolicy_rate(
|
|
||||||
rate, rate * AUDIT_RATE_LIMIT_BURST_DURATION)));
|
|
||||||
// cool down, and check unspammy rate still works
|
|
||||||
sleep(2);
|
|
||||||
EXPECT_LE(AUDIT_RATE_LIMIT_BURST_DURATION - 1, // allow _one_ lost
|
|
||||||
count_avc(sepolicy_rate(1, AUDIT_RATE_LIMIT_BURST_DURATION)));
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue