Module Name:    src
Committed By:   riastradh
Date:           Tue Oct  8 02:28:43 UTC 2024

Modified Files:
        src/tests/net/if_wg: t_basic.sh

Log Message:
wg(4): Test truncated UDP input from the network.

This triggers double-free in the IPv6 udp6_input path -- but,
confusingly, not the IPv4 udp_input path, even though the overudp_cb
interface ought to be the same:

/* udp_input -- no further use of m if return is -1 */
        if ((n = udp4_realinput(&src, &dst, &m, iphlen)) == -1) {
                UDP_STATINC(UDP_STAT_HDROPS);
                return;
        }

/* udp6_input -- m_freem if return is not 0 */
        if (udp6_realinput(AF_INET6, &src, &dst, &m, off) == 0) {
...
        }

bad:
        m_freem(m);
        return IPPROTO_DONE;

The subroutines udp4_realinput and udp6_realinput pass through the
return value of overudp_cb in essentially the same way:

/* udp4_realinput */
                if (inp->inp_overudp_cb != NULL) {
                        int ret;
                        ret = inp->inp_overudp_cb(mp, off, inp->inp_socket,
                            sintosa(src), inp->inp_overudp_arg);
                        switch (ret) {
                        case -1: /* Error, m was freed */
                                rcvcnt = -1;
                                goto bad;
...
bad:
        return rcvcnt;

/* udp6_realinput */
                if (inp->inp_overudp_cb != NULL) {
                        int ret;
                        ret = inp->inp_overudp_cb(mp, off, inp->inp_socket,
                            sin6tosa(src), inp->inp_overudp_arg);
                        switch (ret) {
                        case -1: /* Error, m was freed */
                                rcvcnt = -1;
                                goto bad;
...
bad:
        return rcvcnt;

PR kern/58688: userland panic of kernel via wg(4)


To generate a diff of this commit:
cvs rdiff -u -r1.4 -r1.5 src/tests/net/if_wg/t_basic.sh

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/tests/net/if_wg/t_basic.sh
diff -u src/tests/net/if_wg/t_basic.sh:1.4 src/tests/net/if_wg/t_basic.sh:1.5
--- src/tests/net/if_wg/t_basic.sh:1.4	Tue Mar  2 07:16:24 2021
+++ src/tests/net/if_wg/t_basic.sh	Tue Oct  8 02:28:43 2024
@@ -1,4 +1,4 @@
-#	$NetBSD: t_basic.sh,v 1.4 2021/03/02 07:16:24 simonb Exp $
+#	$NetBSD: t_basic.sh,v 1.5 2024/10/08 02:28:43 riastradh Exp $
 #
 # Copyright (c) 2018 Ryota Ozaki <ozaki.ry...@gmail.com>
 # All rights reserved.
@@ -48,6 +48,23 @@ check_ping_payload()
 	done
 }
 
+check_badudp()
+{
+	local proto=$1
+	local ip=$2
+	local port=51820        # XXX parametrize more clearly
+
+	if [ $proto = inet ]; then
+		atf_check -o ignore -e ignore \
+		    $HIJACKING nc -4uv -w1 $ip $port </dev/null
+	else
+		atf_check -o ignore -e ignore \
+		    $HIJACKING nc -6uv -w1 $ip $port </dev/null
+		atf_expect_fail "PR kern/58688:" \
+		    " userland panic of kernel via wg(4)"
+	fi
+}
+
 test_common()
 {
 	local type=$1
@@ -107,6 +124,9 @@ test_common()
 	elif [ $type = payload ]; then
 		export RUMP_SERVER=$SOCK_LOCAL
 		check_ping_payload $inner_proto $ip_wg_peer
+	elif [ $type = badudp ]; then
+		export RUMP_SERVER=$SOCK_LOCAL
+		check_badudp $outer_proto $ip_peer
 	fi
 
 	destroy_wg_interfaces
@@ -282,6 +302,36 @@ add_payload_sizes_test()
 	atf_add_test_case ${name}
 }
 
+add_badudp_test()
+{
+	local inner=$1
+	local outer=$2
+	local ipv4=inet
+	local ipv6=inet6
+
+	name="wg_badudp_${inner}_over_${outer}"
+	fulldesc="Test wg(4) with ${inner} over ${outer} with bad UDP packets"
+
+	eval inner=\$$inner
+	eval outer=\$$outer
+
+	atf_test_case ${name} cleanup
+	eval "
+		${name}_head() {
+			atf_set descr \"${fulldesc}\"
+			atf_set require.progs rump_server wgconfig wg-keygen nc
+		}
+		${name}_body() {
+			test_common badudp $outer $inner
+			rump_server_destroy_ifaces
+		}
+		${name}_cleanup() {
+			\$DEBUG && dump
+			cleanup
+		}"
+	atf_add_test_case ${name}
+}
+
 atf_test_case wg_multiple_interfaces cleanup
 wg_multiple_interfaces_head()
 {
@@ -459,6 +509,11 @@ wg_multiple_peers_cleanup()
 atf_init_test_cases()
 {
 
+	add_badudp_test ipv4 ipv4
+	add_badudp_test ipv4 ipv6
+	add_badudp_test ipv6 ipv4
+	add_badudp_test ipv6 ipv6
+
 	add_basic_test ipv4 ipv4
 	add_basic_test ipv4 ipv6
 	add_basic_test ipv6 ipv4

Reply via email to