Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 589c992e authored by Maciej Żenczykowski's avatar Maciej Żenczykowski
Browse files

Simplify ULOG parsing code now that all kernels are 64-bit.



Test: TreeHugger
Signed-off-by: default avatarMaciej Żenczykowski <maze@google.com>
Change-Id: Ida581e3e9eff55dfd4b9f4c91db85095818723a4
parent 79bbceb9
Loading
Loading
Loading
Loading
+24 −97
Original line number Diff line number Diff line
@@ -37,108 +37,44 @@
#include <sys/utsname.h>

#include <android-base/parseint.h>
#include <bpf/KernelUtils.h>
#include <log/log.h>
#include <sysutils/NetlinkEvent.h>

using android::base::ParseInt;
using android::bpf::isKernel64Bit;

/* From kernel's net/netfilter/xt_quota2.c */
const int LOCAL_QLOG_NL_EVENT = 112;
const int LOCAL_NFLOG_PACKET = NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET;

/******************************************************************************
 * WARNING: HERE BE DRAGONS!                                                  *
 *                                                                            *
 * This is here to provide for compatibility with both 32 and 64-bit kernels  *
 * from 32-bit userspace.                                                     *
 *                                                                            *
 * The kernel definition of this struct uses types (like long) that are not   *
 * the same across 32-bit and 64-bit builds, and there is no compatibility    *
 * layer to fix it up before it reaches userspace.                            *
 * As such we need to detect the bit-ness of the kernel and deal with it.     *
 *                                                                            *
 ******************************************************************************/

/*
 * This is the verbatim kernel declaration from net/netfilter/xt_quota2.c,
 * it is *NOT* of a well defined layout and is included here for compile
 * time assertions only.
 *
 * It got there from deprecated ipt_ULOG.h to parse QLOG_NL_EVENT.
 */
#define ULOG_MAC_LEN 80
#define ULOG_PREFIX_LEN 32
typedef struct ulog_packet_msg {
    unsigned long mark;
    long timestamp_sec;
    long timestamp_usec;
    unsigned int hook;
    char indev_name[IFNAMSIZ];
    char outdev_name[IFNAMSIZ];
    size_t data_len;
    char prefix[ULOG_PREFIX_LEN];
    unsigned char mac_len;
    unsigned char mac[ULOG_MAC_LEN];
    unsigned char payload[0];
} ulog_packet_msg_t;

// On Linux int is always 32 bits, while sizeof(long) == sizeof(void*),
// thus long on a 32-bit Linux kernel is 32-bits, like int always is
typedef int long32;
typedef unsigned int ulong32;
static_assert(sizeof(long32) == 4);
static_assert(sizeof(ulong32) == 4);

// Here's the same structure definition with the assumption the kernel
// is compiled for 32-bits.
typedef struct {
    ulong32 mark;
    long32 timestamp_sec;
    long32 timestamp_usec;
    unsigned int hook;
    char indev_name[IFNAMSIZ];
    char outdev_name[IFNAMSIZ];
    ulong32 data_len;
    char prefix[ULOG_PREFIX_LEN];
    unsigned char mac_len;
    unsigned char mac[ULOG_MAC_LEN];
    unsigned char payload[0];
} ulog_packet_msg32_t;

// long on a 64-bit kernel is 64-bits with 64-bit alignment,
// while long long is 64-bit but may have 32-bit aligment.
// 'long' on a 32-bit kernel is 32-bits with 32-bit alignment,
// and on a 64-bit kernel is 64-bits with 64-bit alignment,
// while 'long long' is always 64-bit it may have 32-bit aligment (x86 structs).
typedef long long __attribute__((__aligned__(8))) long64;
typedef unsigned long long __attribute__((__aligned__(8))) ulong64;
static_assert(sizeof(long64) == 8);
static_assert(sizeof(ulong64) == 8);

// Here's the same structure definition with the assumption the kernel
// is compiled for 64-bits.
// From kernel's net/netfilter/xt_quota2.c
// It got there from deprecated ipt_ULOG.h to parse QLOG_NL_EVENT.
constexpr int LOCAL_QLOG_NL_EVENT = 112;
constexpr int LOCAL_NFLOG_PACKET = NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET;

constexpr int ULOG_MAC_LEN = 80;
constexpr int ULOG_PREFIX_LEN = 32;

// This structure layout assumes we're running on a 64-bit kernel.
typedef struct {
    ulong64 mark;
    long64 timestamp_sec;
    long64 timestamp_usec;
    ulong64 mark;  // kernel: unsigned long
    long64 timestamp_sec;  // kernel: long
    long64 timestamp_usec;  // kernel: long
    unsigned int hook;
    char indev_name[IFNAMSIZ];
    char outdev_name[IFNAMSIZ];
    ulong64 data_len;
    ulong64 data_len;  // kernel: size_t, a.k.a. unsigned long
    char prefix[ULOG_PREFIX_LEN];
    unsigned char mac_len;
    unsigned char mac[ULOG_MAC_LEN];
    unsigned char payload[0];
} ulog_packet_msg64_t;

// One expects the 32-bit version to be smaller than the 64-bit version.
static_assert(sizeof(ulog_packet_msg32_t) < sizeof(ulog_packet_msg64_t));
// And either way the 'native' version should match either the 32 or 64 bit one.
static_assert(sizeof(ulog_packet_msg_t) == sizeof(ulog_packet_msg32_t) ||
              sizeof(ulog_packet_msg_t) == sizeof(ulog_packet_msg64_t));
} ulog_packet_msg_t;

// In practice these sizes are always simply (for both x86 and arm):
static_assert(sizeof(ulog_packet_msg32_t) == 168);
static_assert(sizeof(ulog_packet_msg64_t) == 192);
// In practice, for both x86 and arm, we have
static_assert(sizeof(ulog_packet_msg_t) == 192);

/******************************************************************************/

@@ -356,20 +292,11 @@ bool NetlinkEvent::parseIfAddrMessage(const struct nlmsghdr *nh) {
 * Parse a QLOG_NL_EVENT message.
 */
bool NetlinkEvent::parseUlogPacketMessage(const struct nlmsghdr *nh) {
    const char* alert;
    const char* devname;

    if (isKernel64Bit()) {
        ulog_packet_msg64_t* pm64 = (ulog_packet_msg64_t*)NLMSG_DATA(nh);
        if (!checkRtNetlinkLength(nh, sizeof(*pm64))) return false;
        alert = pm64->prefix;
        devname = pm64->indev_name[0] ? pm64->indev_name : pm64->outdev_name;
    } else {
        ulog_packet_msg32_t* pm32 = (ulog_packet_msg32_t*)NLMSG_DATA(nh);
        if (!checkRtNetlinkLength(nh, sizeof(*pm32))) return false;
        alert = pm32->prefix;
        devname = pm32->indev_name[0] ? pm32->indev_name : pm32->outdev_name;
    }
    ulog_packet_msg_t* pm = (ulog_packet_msg_t*)NLMSG_DATA(nh);
    if (!checkRtNetlinkLength(nh, sizeof(*pm))) return false;

    const char* alert = pm->prefix;
    const char* devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name;

    asprintf(&mParams[0], "ALERT_NAME=%s", alert);
    asprintf(&mParams[1], "INTERFACE=%s", devname);