Loading logd/LogAudit.cpp +2 −46 Original line number Original line Diff line number Diff line Loading @@ -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), Loading @@ -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', Loading @@ -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; Loading Loading @@ -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; } } logd/LogAudit.h +0 −6 Original line number Original line Diff line number Diff line Loading @@ -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> Loading @@ -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); Loading logd/libaudit.c +2 −21 Original line number Original line Diff line number Diff line Loading @@ -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)); Loading @@ -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); } } Loading logd/libaudit.h +2 −16 Original line number Original line Diff line number Diff line Loading @@ -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 Loading logd/tests/logd_test.cpp +8 −45 Original line number Original line Diff line number Diff line Loading @@ -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 Loading
logd/LogAudit.cpp +2 −46 Original line number Original line Diff line number Diff line Loading @@ -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), Loading @@ -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', Loading @@ -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; Loading Loading @@ -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; } }
logd/LogAudit.h +0 −6 Original line number Original line Diff line number Diff line Loading @@ -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> Loading @@ -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); Loading
logd/libaudit.c +2 −21 Original line number Original line Diff line number Diff line Loading @@ -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)); Loading @@ -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); } } Loading
logd/libaudit.h +2 −16 Original line number Original line Diff line number Diff line Loading @@ -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 Loading
logd/tests/logd_test.cpp +8 −45 Original line number Original line Diff line number Diff line Loading @@ -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