From 9a20e67fa62c1e0e0080910deec4be82ebecc922 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 30 Oct 2014 14:51:59 -0700 Subject: [PATCH] Extend to receive NFLOG packets. Packets captured and logged by the NFLOG target are unicast, so extend to catch and decode them. To avoid escaping issues, the raw contents are passed around as hex strings. Bug: 18335678 Change-Id: Ib7299500baa00080a1f000f9da843eb527363353 --- CleanSpec.mk | 1 + include/cutils/uevent.h | 1 + include/sysutils/NetlinkEvent.h | 1 + include/sysutils/NetlinkListener.h | 1 + libcutils/uevent.c | 26 ++++++++----- libsysutils/Android.mk | 7 ++-- libsysutils/src/NetlinkEvent.cpp | 59 ++++++++++++++++++++++++++--- libsysutils/src/NetlinkListener.cpp | 9 ++++- 8 files changed, 86 insertions(+), 19 deletions(-) diff --git a/CleanSpec.mk b/CleanSpec.mk index e78fc88d6..7f9536ee9 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -54,3 +54,4 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/reboot) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/default.prop) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/default.prop) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/lmkd_intermediates/import_includes) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libsysutils_intermediates/import_includes) diff --git a/include/cutils/uevent.h b/include/cutils/uevent.h index 4cca7e536..da1c2aae6 100644 --- a/include/cutils/uevent.h +++ b/include/cutils/uevent.h @@ -27,6 +27,7 @@ extern "C" { int uevent_open_socket(int buf_sz, bool passcred); ssize_t uevent_kernel_multicast_recv(int socket, void *buffer, size_t length); ssize_t uevent_kernel_multicast_uid_recv(int socket, void *buffer, size_t length, uid_t *uid); +ssize_t uevent_kernel_recv(int socket, void *buffer, size_t length, bool require_group, uid_t *uid); #ifdef __cplusplus } diff --git a/include/sysutils/NetlinkEvent.h b/include/sysutils/NetlinkEvent.h index c345cdb54..4fa49c52a 100644 --- a/include/sysutils/NetlinkEvent.h +++ b/include/sysutils/NetlinkEvent.h @@ -57,6 +57,7 @@ public: bool parseIfInfoMessage(const struct nlmsghdr *nh); bool parseIfAddrMessage(const struct nlmsghdr *nh); bool parseUlogPacketMessage(const struct nlmsghdr *nh); + bool parseNfPacketMessage(struct nlmsghdr *nh); bool parseRtMessage(const struct nlmsghdr *nh); bool parseNdUserOptMessage(const struct nlmsghdr *nh); }; diff --git a/include/sysutils/NetlinkListener.h b/include/sysutils/NetlinkListener.h index 6e52c3b1e..82465d697 100644 --- a/include/sysutils/NetlinkListener.h +++ b/include/sysutils/NetlinkListener.h @@ -27,6 +27,7 @@ class NetlinkListener : public SocketListener { public: static const int NETLINK_FORMAT_ASCII = 0; static const int NETLINK_FORMAT_BINARY = 1; + static const int NETLINK_FORMAT_BINARY_UNICAST = 2; #if 1 /* temporary version until we can get Motorola to update their diff --git a/libcutils/uevent.c b/libcutils/uevent.c index 97a81e309..827170a14 100644 --- a/libcutils/uevent.c +++ b/libcutils/uevent.c @@ -31,12 +31,12 @@ */ ssize_t uevent_kernel_multicast_recv(int socket, void *buffer, size_t length) { - uid_t user = -1; - return uevent_kernel_multicast_uid_recv(socket, buffer, length, &user); + uid_t uid = -1; + return uevent_kernel_multicast_uid_recv(socket, buffer, length, &uid); } /** - * Like the above, but passes a uid_t in by reference. In the event that this + * Like the above, but passes a uid_t in by pointer. In the event that this * fails due to a bad uid check, the uid_t will be set to the uid of the * socket's peer. * @@ -44,8 +44,12 @@ ssize_t uevent_kernel_multicast_recv(int socket, void *buffer, size_t length) * returns -1, sets errno to EIO, and sets "user" to the UID associated with the * message. If the peer UID cannot be determined, "user" is set to -1." */ -ssize_t uevent_kernel_multicast_uid_recv(int socket, void *buffer, - size_t length, uid_t *user) +ssize_t uevent_kernel_multicast_uid_recv(int socket, void *buffer, size_t length, uid_t *uid) +{ + return uevent_kernel_recv(socket, buffer, length, true, uid); +} + +ssize_t uevent_kernel_recv(int socket, void *buffer, size_t length, bool require_group, uid_t *uid) { struct iovec iov = { buffer, length }; struct sockaddr_nl addr; @@ -60,7 +64,7 @@ ssize_t uevent_kernel_multicast_uid_recv(int socket, void *buffer, 0, }; - *user = -1; + *uid = -1; ssize_t n = recvmsg(socket, &hdr, 0); if (n <= 0) { return n; @@ -73,14 +77,18 @@ ssize_t uevent_kernel_multicast_uid_recv(int socket, void *buffer, } struct ucred *cred = (struct ucred *)CMSG_DATA(cmsg); - *user = cred->uid; + *uid = cred->uid; if (cred->uid != 0) { /* ignoring netlink message from non-root user */ goto out; } - if (addr.nl_groups == 0 || addr.nl_pid != 0) { - /* ignoring non-kernel or unicast netlink message */ + if (addr.nl_pid != 0) { + /* ignore non-kernel */ + goto out; + } + if (require_group && addr.nl_groups == 0) { + /* ignore unicast messages when requested */ goto out; } diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk index 246f954cb..b902a8191 100644 --- a/libsysutils/Android.mk +++ b/libsysutils/Android.mk @@ -16,11 +16,12 @@ LOCAL_SRC_FILES:= \ LOCAL_MODULE:= libsysutils -LOCAL_C_INCLUDES := - LOCAL_CFLAGS := -Werror -LOCAL_SHARED_LIBRARIES := libcutils liblog +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + liblog \ + libnl include $(BUILD_SHARED_LIBRARY) diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp index 9d596ef55..909df8647 100644 --- a/libsysutils/src/NetlinkEvent.cpp +++ b/libsysutils/src/NetlinkEvent.cpp @@ -32,13 +32,21 @@ #include #include #include +#include #include + /* From kernel's net/netfilter/xt_quota2.c */ -const int QLOG_NL_EVENT = 112; +const int LOCAL_QLOG_NL_EVENT = 112; +const int LOCAL_NFLOG_PACKET = NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET; #include #include +#include +#include +#include +#include + const int NetlinkEvent::NlActionUnknown = 0; const int NetlinkEvent::NlActionAdd = 1; const int NetlinkEvent::NlActionRemove = 2; @@ -95,7 +103,8 @@ static const char *rtMessageName(int type) { NL_EVENT_RTM_NAME(RTM_NEWROUTE); NL_EVENT_RTM_NAME(RTM_DELROUTE); NL_EVENT_RTM_NAME(RTM_NEWNDUSEROPT); - NL_EVENT_RTM_NAME(QLOG_NL_EVENT); + NL_EVENT_RTM_NAME(LOCAL_QLOG_NL_EVENT); + NL_EVENT_RTM_NAME(LOCAL_NFLOG_PACKET); default: return NULL; } @@ -271,6 +280,41 @@ bool NetlinkEvent::parseUlogPacketMessage(const struct nlmsghdr *nh) { return true; } +/* + * Parse a LOCAL_NFLOG_PACKET message. + */ +bool NetlinkEvent::parseNfPacketMessage(struct nlmsghdr *nh) { + int uid = -1; + int len = 0; + char* raw = NULL; + + struct nlattr *uid_attr = nlmsg_find_attr(nh, sizeof(struct genlmsghdr), NFULA_UID); + if (uid_attr) { + uid = ntohl(nla_get_u32(uid_attr)); + } + + struct nlattr *payload = nlmsg_find_attr(nh, sizeof(struct genlmsghdr), NFULA_PAYLOAD); + if (payload) { + /* First 256 bytes is plenty */ + len = nla_len(payload); + if (len > 256) len = 256; + raw = (char*) nla_data(payload); + } + + char* hex = (char*) calloc(1, 5 + (len * 2)); + strcpy(hex, "HEX="); + for (int i = 0; i < len; i++) { + hex[4 + (i * 2)] = "0123456789abcdef"[(raw[i] >> 4) & 0xf]; + hex[5 + (i * 2)] = "0123456789abcdef"[raw[i] & 0xf]; + } + + asprintf(&mParams[0], "UID=%d", uid); + mParams[1] = hex; + mSubsystem = strdup("strict"); + mAction = NlActionChange; + return true; +} + /* * Parse a RTM_NEWROUTE or RTM_DELROUTE message. */ @@ -478,7 +522,7 @@ bool NetlinkEvent::parseNdUserOptMessage(const struct nlmsghdr *nh) { * TODO: consider only ever looking at the first message. */ bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) { - const struct nlmsghdr *nh; + struct nlmsghdr *nh; for (nh = (struct nlmsghdr *) buffer; NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE); @@ -493,7 +537,7 @@ bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) { if (parseIfInfoMessage(nh)) return true; - } else if (nh->nlmsg_type == QLOG_NL_EVENT) { + } else if (nh->nlmsg_type == LOCAL_QLOG_NL_EVENT) { if (parseUlogPacketMessage(nh)) return true; @@ -511,6 +555,10 @@ bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) { if (parseNdUserOptMessage(nh)) return true; + } else if (nh->nlmsg_type == LOCAL_NFLOG_PACKET) { + if (parseNfPacketMessage(nh)) + return true; + } } @@ -588,7 +636,8 @@ bool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) { } bool NetlinkEvent::decode(char *buffer, int size, int format) { - if (format == NetlinkListener::NETLINK_FORMAT_BINARY) { + if (format == NetlinkListener::NETLINK_FORMAT_BINARY + || format == NetlinkListener::NETLINK_FORMAT_BINARY_UNICAST) { return parseBinaryNetlinkMessage(buffer, size); } else { return parseAsciiNetlinkMessage(buffer, size); diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp index 81c5cc239..637aa1ea3 100644 --- a/libsysutils/src/NetlinkListener.cpp +++ b/libsysutils/src/NetlinkListener.cpp @@ -47,8 +47,13 @@ bool NetlinkListener::onDataAvailable(SocketClient *cli) ssize_t count; uid_t uid = -1; - count = TEMP_FAILURE_RETRY(uevent_kernel_multicast_uid_recv( - socket, mBuffer, sizeof(mBuffer), &uid)); + bool require_group = true; + if (mFormat == NETLINK_FORMAT_BINARY_UNICAST) { + require_group = false; + } + + count = TEMP_FAILURE_RETRY(uevent_kernel_recv(socket, + mBuffer, sizeof(mBuffer), require_group, &uid)); if (count < 0) { if (uid > 0) LOG_EVENT_INT(65537, uid);