Repository: bitcoin/bitcoin
File: contrib/tracing/log_raw_p2p_msgs.py (Python)

Code before:
};

// We can't store the p2p_message struct on the eBPF stack as it is limited to
// 512 bytes and P2P message can be bigger than 512 bytes. However, we can use
// an BPF-array with a length of 1 to allocate up to 32768 bytes (this is
// defined by PCPU_MIN_UNIT_SIZE in include/linux/percpu.h in the Linux kernel).
// Also see https://github.com/iovisor/bcc/issues/2306
BPF_ARRAY(msg_arr, struct p2p_message, 1);

// Two BPF perf buffers for pushing data (here P2P messages) to user-space.
BPF_PERF_OUTPUT(inbound_messages);
BPF_PERF_OUTPUT(outbound_messages);

int trace_inbound_message(struct pt_regs *ctx) {
    int idx = 0;
    struct p2p_message *msg = msg_arr.lookup(&idx);

    // lookup() does not return a NULL pointer. However, the BPF verifier
    // requires an explicit check that that the `msg` pointer isn't a NULL
    // pointer. See https://github.com/iovisor/bcc/issues/2595
    if (msg == NULL) return 1;

    bpf_usdt_readarg(1, ctx, &msg->peer_id);
    bpf_usdt_readarg_p(2, ctx, &msg->peer_addr, MAX_PEER_ADDR_LENGTH);
    bpf_usdt_readarg_p(3, ctx, &msg->peer_conn_type, MAX_PEER_CONN_TYPE_LENGTH);
    bpf_usdt_readarg_p(4, ctx, &msg->msg_type, MAX_MSG_TYPE_LENGTH);
    bpf_usdt_readarg(5, ctx, &msg->msg_size);
    bpf_usdt_readarg_p(6, ctx, &msg->msg, _TRACEPOINT_TEST_MIN(msg->msg_size, MAX_MSG_DATA_LENGTH));

    inbound_messages.perf_submit(ctx, msg, sizeof(*msg));
    return 0;
};

int trace_outbound_message(struct pt_regs *ctx) {
    int idx = 0;
    struct p2p_message *msg = msg_arr.lookup(&idx);

    // lookup() does not return a NULL pointer. However, the BPF verifier
    // requires an explicit check that that the `msg` pointer isn't a NULL
    // pointer. See https://github.com/iovisor/bcc/issues/2595
    if (msg == NULL) return 1;

    bpf_usdt_readarg(1, ctx, &msg->peer_id);
    bpf_usdt_readarg_p(2, ctx, &msg->peer_addr, MAX_PEER_ADDR_LENGTH);
    bpf_usdt_readarg_p(3, ctx, &msg->peer_conn_type, MAX_PEER_CONN_TYPE_LENGTH);
    bpf_usdt_readarg_p(4, ctx, &msg->msg_type, MAX_MSG_TYPE_LENGTH);
    bpf_usdt_readarg(5, ctx, &msg->msg_size);
    bpf_usdt_readarg_p(6, ctx, &msg->msg,  _TRACEPOINT_TEST_MIN(msg->msg_size, MAX_MSG_DATA_LENGTH));

    outbound_messages.perf_submit(ctx, msg, sizeof(*msg));
    return 0;

Review comment (suggestion):
Using `bpf_probe_read_user_str` here at least makes sure that only until the zero-terminator is read and not the entire buffer. That's a clear improvement.

Code after:
};

// We can't store the p2p_message struct on the eBPF stack as it is limited to
// 512 bytes and P2P message can be bigger than 512 bytes. However, we can use
// an BPF-array with a length of 1 to allocate up to 32768 bytes (this is
// defined by PCPU_MIN_UNIT_SIZE in include/linux/percpu.h in the Linux kernel).
// Also see https://github.com/iovisor/bcc/issues/2306
BPF_ARRAY(msg_arr, struct p2p_message, 1);

// Two BPF perf buffers for pushing data (here P2P messages) to user-space.
BPF_PERF_OUTPUT(inbound_messages);
BPF_PERF_OUTPUT(outbound_messages);

int trace_inbound_message(struct pt_regs *ctx) {
    int idx = 0;
    struct p2p_message *msg = msg_arr.lookup(&idx);
    void *paddr = NULL, *pconn_type = NULL, *pmsg_type = NULL, *pmsg = NULL;

    // lookup() does not return a NULL pointer. However, the BPF verifier
    // requires an explicit check that that the `msg` pointer isn't a NULL
    // pointer. See https://github.com/iovisor/bcc/issues/2595
    if (msg == NULL) return 1;

    bpf_usdt_readarg(1, ctx, &msg->peer_id);
    bpf_usdt_readarg(2, ctx, &paddr);
    bpf_probe_read_user_str(&msg->peer_addr, sizeof(msg->peer_addr), paddr);
    bpf_usdt_readarg(3, ctx, &pconn_type);
    bpf_probe_read_user_str(&msg->peer_conn_type, sizeof(msg->peer_conn_type), pconn_type);
    bpf_usdt_readarg(4, ctx, &pmsg_type);
    bpf_probe_read_user_str(&msg->msg_type, sizeof(msg->msg_type), pmsg_type);
    bpf_usdt_readarg(5, ctx, &msg->msg_size);
    bpf_usdt_readarg(6, ctx, &pmsg);
    bpf_probe_read_user(&msg->msg, _TRACEPOINT_TEST_MIN(msg->msg_size, MAX_MSG_DATA_LENGTH), pmsg);

    inbound_messages.perf_submit(ctx, msg, sizeof(*msg));
    return 0;
};

int trace_outbound_message(struct pt_regs *ctx) {
    int idx = 0;
    struct p2p_message *msg = msg_arr.lookup(&idx);

    void *paddr = NULL, *pconn_type = NULL, *pmsg_type = NULL, *pmsg = NULL;

    // lookup() does not return a NULL pointer. However, the BPF verifier
    // requires an explicit check that that the `msg` pointer isn't a NULL
    // pointer. See https://github.com/iovisor/bcc/issues/2595
    if (msg == NULL) return 1;

    bpf_usdt_readarg(1, ctx, &msg->peer_id);
    bpf_usdt_readarg(2, ctx, &paddr);