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

Commit ace81e9b authored by Maciej Żenczykowski's avatar Maciej Żenczykowski Committed by Gerrit Code Review
Browse files

Merge "Simplify ULOG parsing code now that all kernels are 64-bit." into main

parents 88d79e02 589c992e
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);