From 860ccdefea2e9a9e5e88eed1d0e3ad41533dda6b Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Wed, 18 Jul 2018 20:03:18 +0000 Subject: [PATCH] net: enhance decoding of getsockopt(PACKET_STATISTICS) * net.c (print_tpacket_stats): Change decoder to match the kernel behaviour: getsockopt syscall accepts any non-negative *optlen and writes either MIN(sizeof(struct tpacket_stats), *optlen) or MIN(sizeof(struct tpacket_stats_v3), *optlen) bytes of data. --- net.c | 51 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/net.c b/net.c index cd1911ba..1c4e8ba2 100644 --- a/net.c +++ b/net.c @@ -651,18 +651,55 @@ print_get_ucred(struct tcb *const tcp, const kernel_ulong_t addr, #ifdef PACKET_STATISTICS static void print_tpacket_stats(struct tcb *const tcp, const kernel_ulong_t addr, - const int len) + unsigned int len) { - struct tpacket_stats stats; + struct tp_stats { + unsigned int tp_packets, tp_drops, tp_freeze_q_cnt; + } stats; - if (len != sizeof(stats) || - umove(tcp, addr, &stats) < 0) { - printaddr(addr); + /* + * The kernel may return len > sizeof(stats) if the kernel structure + * grew as it happened when tpacket_stats_v3 was introduced. + */ + if (len > sizeof(stats)) + len = sizeof(stats); + + if (umoven_or_printaddr(tcp, addr, len, &stats)) + return; + + if (len < sizeof(stats.tp_packets)) { + tprints("{tp_packets="); + print_quoted_string((void *) &stats.tp_packets, + len, QUOTE_FORCE_HEX); } else { PRINT_FIELD_U("{", stats, tp_packets); - PRINT_FIELD_U(", ", stats, tp_drops); - tprints("}"); + + if (len > offsetof(struct tp_stats, tp_drops)) { + len -= offsetof(struct tp_stats, tp_drops); + if (len < sizeof(stats.tp_drops)) { + tprints(", tp_drops="); + print_quoted_string((void *) &stats.tp_drops, + len, QUOTE_FORCE_HEX); + } else { + PRINT_FIELD_U(", ", stats, tp_drops); + + if (len > offsetof(struct tp_stats, tp_freeze_q_cnt) - + offsetof(struct tp_stats, tp_drops)) { + len -= offsetof(struct tp_stats, tp_freeze_q_cnt) - + offsetof(struct tp_stats, tp_drops); + if (len < sizeof(stats.tp_freeze_q_cnt)) { + tprints(", tp_freeze_q_cnt="); + print_quoted_string((void *) &stats.tp_freeze_q_cnt, + len, + QUOTE_FORCE_HEX); + } else { + PRINT_FIELD_U(", ", stats, tp_freeze_q_cnt); + } + } + } + } } + tprints("}"); } #endif /* PACKET_STATISTICS */ -- 2.50.0