]> granicus.if.org Git - strace/commitdiff
Fix corner cases of ICMP_FILTER decoding
authorDmitry V. Levin <ldv@altlinux.org>
Fri, 6 May 2016 00:06:15 +0000 (00:06 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Fri, 6 May 2016 00:22:52 +0000 (00:22 +0000)
* net.c (print_icmp_filter): Print icmp_filter for any positive length.
* tests/net-icmp_filter.c: New file.
* tests/net-icmp_filter.test: New test.
* tests/.gitignore: Add net-icmp_filter.
* tests/Makefile.am (check_PROGRAMS): Likewise.
(DECODER_TESTS): Add net-icmp_filter.test.

net.c
tests/.gitignore
tests/Makefile.am
tests/net-icmp_filter.c [new file with mode: 0644]
tests/net-icmp_filter.test [new file with mode: 0755]

diff --git a/net.c b/net.c
index f6d8c7df35c401f6978eb61e53654edb790b6070..c34b6aafce9059c6a2543b33f59d9cf8b1179f08 100644 (file)
--- a/net.c
+++ b/net.c
@@ -1249,16 +1249,20 @@ print_tpacket_stats(struct tcb *tcp, long addr, int len)
 # include "xlat/icmpfilterflags.h"
 
 static void
-print_icmp_filter(struct tcb *tcp, long addr, int len)
+print_icmp_filter(struct tcb *tcp, const long addr, int len)
 {
-       struct icmp_filter      filter;
+       struct icmp_filter filter = {};
 
-       if (len != sizeof(filter) ||
-           umove(tcp, addr, &filter) < 0) {
+       if (len > (int) sizeof(filter))
+               len = sizeof(filter);
+       else if (len <= 0) {
                printaddr(addr);
                return;
        }
 
+       if (umoven_or_printaddr(tcp, addr, len, &filter))
+               return;
+
        tprints("~(");
        printflags(icmpfilterflags, ~filter.data, "ICMP_???");
        tprints(")");
index b90ea4b4bff41ea4def5a6854ef8c66589c9e3b8..102d8edd88216fdef6c2365340a9ea4fabf93002 100644 (file)
@@ -125,6 +125,7 @@ move_pages
 mq
 nanosleep
 net-accept-connect
+net-icmp_filter
 net-y-unix
 net-yy-inet
 net-yy-unix
index 48bf517061c5c974f31ac2bf0460338d4e9deb77..c09701dcb2639ee428966ca73a7975259de95a54 100644 (file)
@@ -178,6 +178,7 @@ check_PROGRAMS = \
        mq \
        nanosleep \
        net-accept-connect \
+       net-icmp_filter \
        net-y-unix \
        net-yy-inet \
        net-yy-unix \
@@ -455,6 +456,7 @@ DECODER_TESTS = \
        move_pages.test \
        mq.test \
        nanosleep.test \
+       net-icmp_filter.test \
        net-y-unix.test \
        net-yy-inet.test \
        net-yy-unix.test \
diff --git a/tests/net-icmp_filter.c b/tests/net-icmp_filter.c
new file mode 100644 (file)
index 0000000..c710906
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Check decoding of ICMP_FILTER.
+ *
+ * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tests.h"
+#include <stdio.h>
+#include <sys/socket.h>
+#include <linux/icmp.h>
+
+int
+main(void)
+{
+       getsockopt(-1, SOL_RAW, ICMP_FILTER, 0, 0);
+       printf("getsockopt(-1, SOL_RAW, ICMP_FILTER, 0, 0) = -1 %s (%m)\n",
+              errno2name());
+
+       setsockopt(-1, SOL_RAW, ICMP_FILTER, NULL, 0);
+       printf("setsockopt(-1, SOL_RAW, ICMP_FILTER, NULL, 0) = -1 %s (%m)\n",
+              errno2name());
+
+       (void) tail_alloc(1);
+       socklen_t *const plen = tail_alloc(sizeof(*plen));
+       void *const efault = plen + 1;
+       struct icmp_filter *const f = tail_alloc(sizeof(*f));
+
+       getsockopt(-1, SOL_RAW, ICMP_FILTER, f, plen);
+       printf("getsockopt(-1, SOL_RAW, ICMP_FILTER, %p, %p) = -1 %s (%m)\n",
+              f, plen, errno2name());
+
+       setsockopt(-1, SOL_RAW, ICMP_FILTER, efault, sizeof(*f));
+       printf("setsockopt(-1, SOL_RAW, ICMP_FILTER, %p, %u) = -1 %s (%m)\n",
+              efault, (unsigned) sizeof(*f), errno2name());
+
+       f->data = ~(
+               1<<ICMP_ECHOREPLY |
+               1<<ICMP_DEST_UNREACH |
+               1<<ICMP_SOURCE_QUENCH |
+               1<<ICMP_REDIRECT |
+               1<<ICMP_TIME_EXCEEDED |
+               1<<ICMP_PARAMETERPROB);
+
+       setsockopt(-1, SOL_RAW, ICMP_FILTER, f, -2);
+       printf("setsockopt(-1, SOL_RAW, ICMP_FILTER, %p, -2) = -1 %s (%m)\n",
+              f, errno2name());
+
+       setsockopt(-1, SOL_RAW, ICMP_FILTER, f, sizeof(*f));
+       printf("setsockopt(-1, SOL_RAW, ICMP_FILTER, %s, %u) = -1 %s (%m)\n",
+              "~(1<<ICMP_ECHOREPLY|1<<ICMP_DEST_UNREACH|1<<ICMP_SOURCE_QUENCH"
+              "|1<<ICMP_REDIRECT|1<<ICMP_TIME_EXCEEDED|1<<ICMP_PARAMETERPROB)",
+              (unsigned) sizeof(*f), errno2name());
+
+       setsockopt(-1, SOL_RAW, ICMP_FILTER, f, sizeof(*f) * 2);
+       printf("setsockopt(-1, SOL_RAW, ICMP_FILTER, %s, %u) = -1 %s (%m)\n",
+              "~(1<<ICMP_ECHOREPLY|1<<ICMP_DEST_UNREACH|1<<ICMP_SOURCE_QUENCH"
+              "|1<<ICMP_REDIRECT|1<<ICMP_TIME_EXCEEDED|1<<ICMP_PARAMETERPROB)",
+              (unsigned) sizeof(*f) * 2, errno2name());
+
+       puts("+++ exited with 0 +++");
+       return 0;
+}
diff --git a/tests/net-icmp_filter.test b/tests/net-icmp_filter.test
new file mode 100755 (executable)
index 0000000..c05a5e6
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# Check decoding of ICMP_FILTER.
+
+. "${srcdir=.}/init.sh"
+run_strace_match_diff -e trace=getsockopt,setsockopt