summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTreehugger Robot2017-01-05 14:28:33 -0600
committerGerrit Code Review2017-01-05 14:28:34 -0600
commit8954ef987bac0d502348708a554f7420396841ea (patch)
treed11ddcf98311274cb4612f41b506ebbc9c0b4a3b
parentfe05f1cde4fd812bbb20a39d37ee7be6b95402c3 (diff)
parent247d682fe1b0dd4c8f149b7f5c89c546df17873a (diff)
downloadplatform-system-core-8954ef987bac0d502348708a554f7420396841ea.tar.gz
platform-system-core-8954ef987bac0d502348708a554f7420396841ea.tar.xz
platform-system-core-8954ef987bac0d502348708a554f7420396841ea.zip
Merge "logd: sepolicy dynamic rate limiting"
-rw-r--r--logd/LogAudit.cpp51
-rw-r--r--logd/LogAudit.h7
-rw-r--r--logd/libaudit.c26
-rw-r--r--logd/libaudit.h31
-rw-r--r--logd/tests/Android.mk5
-rw-r--r--logd/tests/logd_test.cpp163
6 files changed, 266 insertions, 17 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}
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index 844951dae..045d6314f 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -17,6 +17,8 @@
17#ifndef _LOGD_LOG_AUDIT_H__ 17#ifndef _LOGD_LOG_AUDIT_H__
18#define _LOGD_LOG_AUDIT_H__ 18#define _LOGD_LOG_AUDIT_H__
19 19
20#include <queue>
21
20#include <sysutils/SocketListener.h> 22#include <sysutils/SocketListener.h>
21 23
22#include "LogBuffer.h" 24#include "LogBuffer.h"
@@ -31,6 +33,11 @@ class LogAudit : public SocketListener {
31 bool events; 33 bool events;
32 bool initialized; 34 bool initialized;
33 35
36 bool tooFast;
37 int mSock;
38 std::queue<log_time> bucket;
39 void checkRateLimit();
40
34public: 41public:
35 LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg); 42 LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg);
36 int log(char *buf, size_t len); 43 int log(char *buf, size_t len);
diff --git a/logd/libaudit.c b/logd/libaudit.c
index d2b212ee4..216f1a18c 100644
--- a/logd/libaudit.c
+++ b/logd/libaudit.c
@@ -149,7 +149,7 @@ out:
149 return rc; 149 return rc;
150} 150}
151 151
152int audit_setup(int fd, uint32_t pid) 152int audit_setup(int fd, pid_t pid)
153{ 153{
154 int rc; 154 int rc;
155 struct audit_message rep; 155 struct audit_message rep;
@@ -163,8 +163,7 @@ int audit_setup(int fd, uint32_t pid)
163 * and the the mask set to AUDIT_STATUS_PID 163 * and the the mask set to AUDIT_STATUS_PID
164 */ 164 */
165 status.pid = pid; 165 status.pid = pid;
166 status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT; 166 status.mask = AUDIT_STATUS_PID;
167 status.rate_limit = 20; // audit entries per second
168 167
169 /* Let the kernel know this pid will be registering for audit events */ 168 /* Let the kernel know this pid will be registering for audit events */
170 rc = audit_send(fd, AUDIT_SET, &status, sizeof(status)); 169 rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
@@ -187,6 +186,27 @@ int audit_setup(int fd, uint32_t pid)
187 return 0; 186 return 0;
188} 187}
189 188
189int audit_rate_limit(int fd, unsigned rate_limit)
190{
191 int rc;
192 struct audit_message rep;
193 struct audit_status status;
194
195 memset(&status, 0, sizeof(status));
196
197 status.mask = AUDIT_STATUS_RATE_LIMIT;
198 status.rate_limit = rate_limit; /* audit entries per second */
199
200 rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
201 if (rc < 0) {
202 return rc;
203 }
204
205 audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
206
207 return 0;
208}
209
190int audit_open() 210int audit_open()
191{ 211{
192 return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT); 212 return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT);
diff --git a/logd/libaudit.h b/logd/libaudit.h
index b9e330d97..9865d4304 100644
--- a/logd/libaudit.h
+++ b/logd/libaudit.h
@@ -33,7 +33,7 @@ __BEGIN_DECLS
33#define MAX_AUDIT_MESSAGE_LENGTH 8970 33#define MAX_AUDIT_MESSAGE_LENGTH 8970
34 34
35typedef enum { 35typedef enum {
36 GET_REPLY_BLOCKING=0, 36 GET_REPLY_BLOCKING = 0,
37 GET_REPLY_NONBLOCKING 37 GET_REPLY_NONBLOCKING
38} reply_t; 38} reply_t;
39 39
@@ -55,7 +55,7 @@ struct audit_message {
55 * A valid fd on success or < 0 on error with errno set. 55 * A valid fd on success or < 0 on error with errno set.
56 * Returns the same errors as man 2 socket. 56 * Returns the same errors as man 2 socket.
57 */ 57 */
58extern int audit_open(void); 58extern int audit_open(void);
59 59
60/** 60/**
61 * Closes the fd returned from audit_open() 61 * Closes the fd returned from audit_open()
@@ -78,19 +78,36 @@ extern void audit_close(int fd);
78 * @return 78 * @return
79 * This function returns 0 on success, else -errno. 79 * This function returns 0 on success, else -errno.
80 */ 80 */
81extern int audit_get_reply(int fd, struct audit_message *rep, reply_t block, 81extern int audit_get_reply(int fd, struct audit_message *rep, reply_t block,
82 int peek); 82 int peek);
83 83
84/** 84/**
85 * Sets a pid to recieve audit netlink events from the kernel 85 * Sets a pid to receive audit netlink events from the kernel
86 * @param fd 86 * @param fd
87 * The fd returned by a call to audit_open() 87 * The fd returned by a call to audit_open()
88 * @param pid 88 * @param pid
89 * The pid whom to set as the reciever of audit messages 89 * The pid whom to set as the receiver of audit messages
90 * @return 90 * @return
91 * This function returns 0 on success, -errno on error. 91 * This function returns 0 on success, -errno on error.
92 */ 92 */
93extern int audit_setup(int fd, uint32_t pid); 93extern int audit_setup(int fd, pid_t pid);
94
95/**
96 * Sets the rate limit to receive audit netlink events from the kernel
97 * @param fd
98 * The fd returned by a call to audit_open()
99 * @param max_rate
100 * The cap of the maximum number of audit messages a second
101 * @return
102 * This function returns 0 on success, -errno on error.
103 */
104
105/* Guidelines to follow for dynamic rate_limit */
106#define AUDIT_RATE_LIMIT_DEFAULT 20 /* acceptable burst rate */
107#define AUDIT_RATE_LIMIT_BURST_DURATION 10 /* number of seconds of burst */
108#define AUDIT_RATE_LIMIT_MAX 5 /* acceptable sustained rate */
109
110extern int audit_rate_limit(int fd, unsigned rate_limit);
94 111
95__END_DECLS 112__END_DECLS
96 113
diff --git a/logd/tests/Android.mk b/logd/tests/Android.mk
index 808087a9b..c05399336 100644
--- a/logd/tests/Android.mk
+++ b/logd/tests/Android.mk
@@ -27,12 +27,15 @@ test_tags := tests
27# Unit tests. 27# Unit tests.
28# ----------------------------------------------------------------------------- 28# -----------------------------------------------------------------------------
29 29
30event_flag := -DAUDITD_LOG_TAG=1003 -DCHATTY_LOG_TAG=1004
31
30test_c_flags := \ 32test_c_flags := \
31 -fstack-protector-all \ 33 -fstack-protector-all \
32 -g \ 34 -g \
33 -Wall -Wextra \ 35 -Wall -Wextra \
34 -Werror \ 36 -Werror \
35 -fno-builtin \ 37 -fno-builtin \
38 $(event_flag)
36 39
37test_src_files := \ 40test_src_files := \
38 logd_test.cpp 41 logd_test.cpp
@@ -43,6 +46,6 @@ include $(CLEAR_VARS)
43LOCAL_MODULE := $(test_module_prefix)unit-tests 46LOCAL_MODULE := $(test_module_prefix)unit-tests
44LOCAL_MODULE_TAGS := $(test_tags) 47LOCAL_MODULE_TAGS := $(test_tags)
45LOCAL_CFLAGS += $(test_c_flags) 48LOCAL_CFLAGS += $(test_c_flags)
46LOCAL_SHARED_LIBRARIES := libbase libcutils liblog 49LOCAL_SHARED_LIBRARIES := libbase libcutils liblog libselinux
47LOCAL_SRC_FILES := $(test_src_files) 50LOCAL_SRC_FILES := $(test_src_files)
48include $(BUILD_NATIVE_TEST) 51include $(BUILD_NATIVE_TEST)
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 5cd9fc8f2..703c0fb9d 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -20,6 +20,9 @@
20#include <signal.h> 20#include <signal.h>
21#include <stdio.h> 21#include <stdio.h>
22#include <string.h> 22#include <string.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <unistd.h>
23 26
24#include <string> 27#include <string>
25 28
@@ -28,7 +31,12 @@
28#include <cutils/sockets.h> 31#include <cutils/sockets.h>
29#include <gtest/gtest.h> 32#include <gtest/gtest.h>
30#include <log/log.h> 33#include <log/log.h>
34#include <private/android_filesystem_config.h>
35#ifdef __ANDROID__
36#include <selinux/selinux.h>
37#endif
31 38
39#include "../libaudit.h" // pickup AUDIT_RATE_LIMIT_*
32#include "../LogReader.h" // pickup LOGD_SNDTIMEO 40#include "../LogReader.h" // pickup LOGD_SNDTIMEO
33 41
34/* 42/*
@@ -873,10 +881,10 @@ void __android_log_btwrite_multiple__helper(int count) {
873 ++second_count; 881 ++second_count;
874 } 882 }
875 } else if (eventData[4] == EVENT_TYPE_STRING) { 883 } else if (eventData[4] == EVENT_TYPE_STRING) {
876 // chatty 884 if (tag != CHATTY_LOG_TAG) continue;
877 if (tag != 1004) continue;
878 ++chatty_count; 885 ++chatty_count;
879 // int len = get4LE(eventData + 4 + 1); 886 // int len = get4LE(eventData + 4 + 1);
887 log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0';
880 const char *cp = strstr(eventData + 4 + 1 + 4, " expire "); 888 const char *cp = strstr(eventData + 4 + 1 + 4, " expire ");
881 if (!cp) continue; 889 if (!cp) continue;
882 unsigned val = 0; 890 unsigned val = 0;
@@ -908,3 +916,154 @@ TEST(logd, multiple_test_3) {
908TEST(logd, multiple_test_10) { 916TEST(logd, multiple_test_10) {
909 __android_log_btwrite_multiple__helper(10); 917 __android_log_btwrite_multiple__helper(10);
910} 918}
919
920#ifdef __ANDROID__
921// returns violating pid
922static pid_t sepolicy_rate(unsigned rate, unsigned num) {
923 pid_t pid = fork();
924
925 if (pid) {
926 siginfo_t info = {};
927 if (TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED))) return 0;
928 if (info.si_status) return 0;
929 return pid;
930 }
931
932 // We may have DAC, but let's not have MAC
933 if (setcon("u:object_r:shell:s0") < 0) {
934 int save_errno = errno;
935 security_context_t context;
936 getcon(&context);
937 fprintf(stderr, "setcon(\"u:r:shell:s0\") failed @\"%s\" %s\n",
938 context, strerror(save_errno));
939 freecon(context);
940 _exit(-1);
941 // NOTREACHED
942 return 0;
943 }
944
945 // Requests dac_read_search, falls back to request dac_override
946 rate /= 2;
947 useconds_t usec;
948 if (rate == 0) {
949 rate = 1;
950 usec = 2000000;
951 } else {
952 usec = (1000000 + (rate / 2)) / rate;
953 }
954 num = (num + 1) / 2;
955
956 if (usec < 2) usec = 2;
957
958 while (num > 0) {
959 if (access(android::base::StringPrintf(
960 "/data/misc/logd/cannot_access_directory_%u",
961 num).c_str(),
962 F_OK) == 0) {
963 _exit(-1);
964 // NOTREACHED
965 return 0;
966 }
967 usleep(usec);
968 --num;
969 }
970 _exit(0);
971 // NOTREACHED
972 return 0;
973}
974
975static int count_avc(pid_t pid) {
976 int count = 0;
977
978 if (pid == 0) return count;
979
980 struct logger_list *logger_list;
981 if (!(logger_list = android_logger_list_open(LOG_ID_EVENTS,
982 ANDROID_LOG_RDONLY |
983 ANDROID_LOG_NONBLOCK,
984 0,
985 pid))) return count;
986 for (;;) {
987 log_msg log_msg;
988
989 if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
990
991 if ((log_msg.entry.pid != pid) ||
992 (log_msg.entry.len < (4 + 1 + 8)) ||
993 (log_msg.id() != LOG_ID_EVENTS)) continue;
994
995 char *eventData = log_msg.msg();
996 if (!eventData) continue;
997
998 uint32_t tag = get4LE(eventData);
999 if (tag != AUDITD_LOG_TAG) continue;
1000
1001 if (eventData[4] != EVENT_TYPE_STRING) continue;
1002
1003 // int len = get4LE(eventData + 4 + 1);
1004 log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0';
1005 const char *cp = strstr(eventData + 4 + 1 + 4, "): avc: ");
1006 if (!cp) continue;
1007
1008 ++count;
1009 }
1010
1011 android_logger_list_close(logger_list);
1012
1013 return count;
1014}
1015#endif
1016
1017TEST(logd, sepolicy_rate_limiter_maximum) {
1018#ifdef __ANDROID__
1019 static const int rate = AUDIT_RATE_LIMIT_MAX;
1020 static const int duration = 2;
1021 // Two seconds of a liveable sustained rate
1022 EXPECT_EQ(rate * duration, count_avc(sepolicy_rate(rate, rate * duration)));
1023#else
1024 GTEST_LOG_(INFO) << "This test does nothing.\n";
1025#endif
1026}
1027
1028TEST(logd, sepolicy_rate_limiter_sub_burst) {
1029#ifdef __ANDROID__
1030 // maximum period below half way between sustainable and burst rate.
1031 static const int threshold = ((AUDIT_RATE_LIMIT_BURST_DURATION *
1032 (AUDIT_RATE_LIMIT_DEFAULT +
1033 AUDIT_RATE_LIMIT_MAX)) +
1034 1) / 2;
1035 static const int rate = (threshold / AUDIT_RATE_LIMIT_BURST_DURATION) - 1;
1036 static const int duration = AUDIT_RATE_LIMIT_BURST_DURATION;
1037 EXPECT_EQ(rate * duration, count_avc(sepolicy_rate(rate, rate * duration)));
1038#else
1039 GTEST_LOG_(INFO) << "This test does nothing.\n";
1040#endif
1041}
1042
1043TEST(logd, sepolicy_rate_limiter_spam) {
1044#ifdef __ANDROID__
1045 // maximum period of double the maximum burst rate
1046 static const int threshold = ((AUDIT_RATE_LIMIT_BURST_DURATION *
1047 (AUDIT_RATE_LIMIT_DEFAULT +
1048 AUDIT_RATE_LIMIT_MAX)) +
1049 1) / 2;
1050 static const int rate = AUDIT_RATE_LIMIT_DEFAULT * 2;
1051 static const int duration = threshold / AUDIT_RATE_LIMIT_DEFAULT;
1052 EXPECT_GE(((AUDIT_RATE_LIMIT_DEFAULT * duration) * 115) /
1053 100, // +15% margin
1054 count_avc(sepolicy_rate(rate, rate * duration)));
1055 // give logd another 3 seconds to react to the burst before checking
1056 sepolicy_rate(rate, rate * 3);
1057 // maximum period at double the maximum burst rate (spam filter kicked in)
1058 EXPECT_GE(((AUDIT_RATE_LIMIT_MAX * AUDIT_RATE_LIMIT_BURST_DURATION) * 130) /
1059 100, // +30% margin
1060 count_avc(sepolicy_rate(rate,
1061 rate * AUDIT_RATE_LIMIT_BURST_DURATION)));
1062 // cool down, and check unspammy rate still works
1063 sleep(2);
1064 EXPECT_LE(AUDIT_RATE_LIMIT_BURST_DURATION - 1, // allow _one_ to be lost
1065 count_avc(sepolicy_rate(1, AUDIT_RATE_LIMIT_BURST_DURATION)));
1066#else
1067 GTEST_LOG_(INFO) << "This test does nothing.\n";
1068#endif
1069}