From 49f45ff291942a10f75156811e15a467fde3229c Mon Sep 17 00:00:00 2001 From: Zhibin Li <08826794brmt@gmail.com> Date: Tue, 24 Jul 2018 16:59:16 +0800 Subject: [PATCH] tests: check decoding of getsockopt(PACKET_STATISTICS) * tests/net-tpacket_stats.c: New file. * tests/net-tpacket_stats-success.c: Likewise. * tests/gen_tests.in (net-tpacket_stats): New test. * tests/net-tpacket_stats-success.test: Likewise. * tests/.gitignore: Add net-tpacket_stats and net-tpacket_stats-success. * tests/Makefile.am (check_PROGRAMS): Add net-tpacket_stats-success. (DECODER_TESTS): Add net-tpacket_stats-success.test. * tests/pure_executables.list: Add net-tpacket_stats. --- tests/.gitignore | 2 + tests/Makefile.am | 2 + tests/gen_tests.in | 1 + tests/net-tpacket_stats-success.c | 2 + tests/net-tpacket_stats-success.test | 6 ++ tests/net-tpacket_stats.c | 147 +++++++++++++++++++++++++++ tests/pure_executables.list | 1 + 7 files changed, 161 insertions(+) create mode 100644 tests/net-tpacket_stats-success.c create mode 100755 tests/net-tpacket_stats-success.test create mode 100644 tests/net-tpacket_stats.c diff --git a/tests/.gitignore b/tests/.gitignore index 011e3132..6ef4d820 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -254,6 +254,8 @@ net-icmp_filter net-packet_mreq net-sockaddr net-tpacket_req +net-tpacket_stats +net-tpacket_stats-success net-y-unix net-yy-inet net-yy-inet6 diff --git a/tests/Makefile.am b/tests/Makefile.am index 0779782e..a2f39506 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -131,6 +131,7 @@ check_PROGRAMS = $(PURE_EXECUTABLES) \ mmsg_name-v \ msg_control-v \ net-accept-connect \ + net-tpacket_stats-success \ netlink_inet_diag \ netlink_netlink_diag \ netlink_unix_diag \ @@ -252,6 +253,7 @@ DECODER_TESTS = \ llseek.test \ lseek.test \ mmap.test \ + net-tpacket_stats-success.test \ net-y-unix.test \ net-yy-inet.test \ net-yy-netlink.test \ diff --git a/tests/gen_tests.in b/tests/gen_tests.in index c3cd1a0b..6744e556 100644 --- a/tests/gen_tests.in +++ b/tests/gen_tests.in @@ -237,6 +237,7 @@ net-icmp_filter -e trace=getsockopt,setsockopt net-packet_mreq -e trace=setsockopt net-sockaddr -a24 -e trace=connect net-tpacket_req -e trace=setsockopt +net-tpacket_stats -e trace=getsockopt net-yy-inet6 +net-yy-inet.test netlink_audit +netlink_sock_diag.test netlink_crypto +netlink_sock_diag.test diff --git a/tests/net-tpacket_stats-success.c b/tests/net-tpacket_stats-success.c new file mode 100644 index 00000000..883ec048 --- /dev/null +++ b/tests/net-tpacket_stats-success.c @@ -0,0 +1,2 @@ +#define INJECT_RETVAL 42 +#include "net-tpacket_stats.c" diff --git a/tests/net-tpacket_stats-success.test b/tests/net-tpacket_stats-success.test new file mode 100755 index 00000000..c298b6c3 --- /dev/null +++ b/tests/net-tpacket_stats-success.test @@ -0,0 +1,6 @@ +#!/bin/sh -efu + + . "${srcdir=.}/scno_tampering.sh" + +run_strace -e trace=getsockopt -e inject=getsockopt:retval=42 ../net-tpacket_stats-success > "$EXP" +match_diff "$LOG" "$EXP" diff --git a/tests/net-tpacket_stats.c b/tests/net-tpacket_stats.c new file mode 100644 index 00000000..a13da5ca --- /dev/null +++ b/tests/net-tpacket_stats.c @@ -0,0 +1,147 @@ +#include "tests.h" +#include +#include +#include +#include +#include "print_fields.h" + +static const char *errstr; + +struct tp_stats { + unsigned int tp_packets, tp_drops, tp_freeze_q_cnt; +}; + +static long +get_tpacket_stats(void *optval, socklen_t *len) +{ + struct tp_stats *tpstats = optval; + socklen_t optlen = *len; + long rc = getsockopt(-1, SOL_PACKET, PACKET_STATISTICS, tpstats, len); + errstr = sprintrc(rc); +#ifdef INJECT_RETVAL + if (rc != INJECT_RETVAL) + error_msg_and_fail("Got a return value of %ld != %d", + rc, INJECT_RETVAL); + + static char inj_errstr[4096]; + + snprintf(inj_errstr, sizeof(inj_errstr), "%s (INJECTED)", errstr); + errstr = inj_errstr; +#endif + printf("getsockopt(-1, SOL_PACKET, PACKET_STATISTICS"); + if (rc < 0 || optlen <= 0) { + printf(", %p", tpstats); + } else if (optlen < sizeof(tpstats->tp_packets)) { + printf(", {tp_packets="); + print_quoted_hex(tpstats, optlen); + printf("}"); + } else { + PRINT_FIELD_U(", {", *tpstats, tp_packets); + + if (optlen > offsetof(struct tp_stats, tp_drops)) { + optlen -= offsetof(struct tp_stats, tp_drops); + if (optlen < sizeof(tpstats->tp_drops)) { + printf(", tp_drops="); + print_quoted_hex(tpstats, optlen); + } else { + PRINT_FIELD_U(", ", *tpstats, tp_drops); + + if (optlen > offsetof(struct tp_stats, tp_freeze_q_cnt) - + offsetof(struct tp_stats, tp_drops)) { + optlen -= offsetof(struct tp_stats, tp_freeze_q_cnt) - + offsetof(struct tp_stats, tp_drops); + if (optlen < sizeof(tpstats->tp_freeze_q_cnt)) { + printf(", tp_freeze_q_cnt="); + print_quoted_hex(tpstats, optlen); + } else { + PRINT_FIELD_U(", ", *tpstats, tp_freeze_q_cnt); + } + } + } + } + printf("}"); + } + printf(", [%d]) = %s\n", *len, errstr); + + return rc; +} + +int +main(void) +{ + TAIL_ALLOC_OBJECT_CONST_PTR(struct tp_stats, tp_stats); + TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len); + + /* offset of (truncated) struct tp_stats.tp_packets */ + const unsigned int offset_tp_packets = offsetofend(struct tp_stats, tp_packets); + const unsigned int tp_packets_truncated = offset_tp_packets - 1; + /* offset of (truncated) struct tp_stats.tp_drops */ + const unsigned int offset_tp_drops = offsetofend(struct tp_stats, tp_drops); + const unsigned int tp_drops_truncated = offset_tp_drops - 1; + /* offset of (truncated) struct tp_stats.tp_freeze_q_cnt */ + const unsigned int offset_tp_freeze_q_cnt = offsetofend(struct tp_stats, tp_freeze_q_cnt); + const unsigned int tp_freeze_q_cnt_truncated = offset_tp_freeze_q_cnt - 1; + + *len = sizeof(*tp_stats); + + /* classic getsockopt */ + unsigned int optlen = *len; + get_tpacket_stats(tp_stats, &optlen); + + /* getsockopt with zero optlen */ + optlen = 0; + get_tpacket_stats(tp_stats, &optlen); + + /* + * getsockopt with optlen less than offsetofend(struct tp_stats.tp_packets): + * the part of struct tp_stats.tp_packets is printed in hex. + */ + optlen = tp_packets_truncated; + get_tpacket_stats(tp_stats, &optlen); + + /* + * getsockopt with optlen equals to offsetofend(struct tp_stats.tp_packets): + * struct tp_stats.tp_drops and struct tp_stats.offset_tp_freeze_q_cnt + * are not printed. + */ + optlen = offset_tp_packets; + get_tpacket_stats(tp_stats, &optlen); + + /* + * getsockopt with optlen greater than offsetofend(struct tp_stats.tp_packets) + * but less than offsetofend(struct tp_stats, tp_drops): + * the part of struct tp_stats.tp_drops is printed in hex. + */ + optlen = tp_drops_truncated; + get_tpacket_stats(tp_stats, &optlen); + + /* + * getsockopt with optlen equals to offsetofend(struct tp_stats.tp_drops): + * struct tp_stats.tp_freeze_q_cnt is not printed. + */ + optlen = offset_tp_drops; + get_tpacket_stats(tp_stats, &optlen); + + /* + * getsockopt with optlen greater than offsetofend(struct tp_stats.tp_drops) + * but less than offsetofend(struct tp_stats, tp_freeze_q_cnt): + * the part of struct tp_stats.tp_freeze_q_cnt is printed in hex. + */ + optlen = tp_freeze_q_cnt_truncated; + get_tpacket_stats(tp_stats, &optlen); + + /* + * getsockopt with optlen equals to offsetofend(struct tp_stats.tp_freeze_q_cnt): + */ + optlen = offset_tp_freeze_q_cnt; + get_tpacket_stats(tp_stats, &optlen); + + /* + * getsockopt with optlen greater than sizeof(struct tp_stats) + */ + optlen = offset_tp_freeze_q_cnt + 1; + get_tpacket_stats(tp_stats, &optlen); + + puts("+++ exited with 0 +++"); + return 0; +} diff --git a/tests/pure_executables.list b/tests/pure_executables.list index e8345252..0d19b75e 100755 --- a/tests/pure_executables.list +++ b/tests/pure_executables.list @@ -208,6 +208,7 @@ net-icmp_filter net-packet_mreq net-sockaddr net-tpacket_req +net-tpacket_stats net-y-unix net-yy-inet net-yy-inet6 -- 2.40.0