Netdev List
 help / color / mirror / Atom feed
From: Stephen Hemminger <stephen@networkplumber.org>
To: netdev@vger.kernel.org
Cc: Stephen Hemminger <stephen@networkplumber.org>,
	Claude <noreply@anthropic.com>
Subject: [PATCH iproute] iptunnel: use worst case buffer for tunnel ioctls
Date: Tue, 20 Oct 2026 08:46:35 -0700	[thread overview]
Message-ID: <20261020154636.1097849-1-stephen@networkplumber.org> (raw)

The tunnel ioctls are device private, so the kernel fills in
whatever parameter structure the device uses, and that can be
the larger IPv6 struct ip6_tnl_parm2 when an IPv4 tunnel was expected.
Ust a worst case union similar to commit 8cc2eac6 ("iptunnel: detect
protocol mismatch on tunnel change") already uses on the change
path for add, del and show as well.

Reported-by: Anthropic OSS scanner
Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 ip/iptunnel.c | 50 +++++++++++++++++++++++++++++++-------------------
 1 file changed, 31 insertions(+), 19 deletions(-)

diff --git a/ip/iptunnel.c b/ip/iptunnel.c
index b6da1459..8d590704 100644
--- a/ip/iptunnel.c
+++ b/ip/iptunnel.c
@@ -24,6 +24,18 @@
 #include "ip_common.h"
 #include "tunnel.h"
 
+/*
+ * The tunnel ioctls are device private: the driver of whatever device
+ * owns the name decides how many bytes it copies to ifru_data.  The
+ * name may belong to an IPv6 tunnel (user error, or a rename between
+ * the link dump and the ioctl), so always give the kernel a buffer
+ * large enough for any tunnel parameter block.
+ */
+union ip_tnl_parm {
+	struct ip_tunnel_parm ip_tnl;
+	struct ip6_tnl_parm2 ip6_tnl;
+};
+
 static void usage(void) __attribute__((noreturn));
 
 static void usage(void)
@@ -173,10 +185,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
 			if (get_ifname(p->name, *argv))
 				invarg("\"name\" not a valid ifname", *argv);
 			if (cmd == SIOCCHGTUNNEL && count == 0) {
-				union {
-					struct ip_tunnel_parm ip_tnl;
-					struct ip6_tnl_parm2 ip6_tnl;
-				} old_p = {};
+				union ip_tnl_parm old_p = {};
 
 				if (tnl_get_ioctl(*argv, &old_p))
 					return -1;
@@ -260,35 +269,37 @@ static const char *tnl_defname(const struct ip_tunnel_parm *p)
 
 static int do_add(int cmd, int argc, char **argv)
 {
-	struct ip_tunnel_parm p;
+	union ip_tnl_parm u = {};
+	struct ip_tunnel_parm *p = &u.ip_tnl;
 	const char *basedev;
 
-	if (parse_args(argc, argv, cmd, &p) < 0)
+	if (parse_args(argc, argv, cmd, p) < 0)
 		return -1;
 
-	if (p.iph.ttl && p.iph.frag_off == 0) {
+	if (p->iph.ttl && p->iph.frag_off == 0) {
 		fprintf(stderr, "ttl != 0 and nopmtudisc are incompatible\n");
 		return -1;
 	}
 
-	basedev = tnl_defname(&p);
+	basedev = tnl_defname(p);
 	if (!basedev) {
 		fprintf(stderr,
 			"cannot determine tunnel mode (ipip, gre, vti or sit)\n");
 		return -1;
 	}
 
-	return tnl_add_ioctl(cmd, basedev, p.name, &p);
+	return tnl_add_ioctl(cmd, basedev, p->name, &u);
 }
 
 static int do_del(int argc, char **argv)
 {
-	struct ip_tunnel_parm p;
+	union ip_tnl_parm u = {};
+	struct ip_tunnel_parm *p = &u.ip_tnl;
 
-	if (parse_args(argc, argv, SIOCDELTUNNEL, &p) < 0)
+	if (parse_args(argc, argv, SIOCDELTUNNEL, p) < 0)
 		return -1;
 
-	return tnl_del_ioctl(tnl_defname(&p) ? : p.name, p.name, &p);
+	return tnl_del_ioctl(tnl_defname(p) ? : p->name, p->name, &u);
 }
 
 static void print_tunnel(const void *t)
@@ -410,17 +421,18 @@ static bool ip_tunnel_parm_match(const struct tnl_print_nlmsg_info *info)
 
 static int do_show(int argc, char **argv)
 {
-	struct ip_tunnel_parm p, p1;
+	union ip_tnl_parm u = {}, u1 = {};
+	struct ip_tunnel_parm *p = &u.ip_tnl;
 	const char *basedev;
 
-	if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0)
+	if (parse_args(argc, argv, SIOCGETTUNNEL, p) < 0)
 		return -1;
 
-	basedev = tnl_defname(&p);
+	basedev = tnl_defname(p);
 	if (!basedev) {
 		struct tnl_print_nlmsg_info info = {
-			.p1    = &p,
-			.p2    = &p1,
+			.p1    = p,
+			.p2    = &u1,
 			.init  = ip_tunnel_parm_initialize,
 			.match = ip_tunnel_parm_match,
 			.print = print_tunnel,
@@ -429,10 +441,10 @@ static int do_show(int argc, char **argv)
 		return do_tunnels_list(&info);
 	}
 
-	if (tnl_get_ioctl(p.name[0] ? p.name : basedev, &p))
+	if (tnl_get_ioctl(p->name[0] ? p->name : basedev, &u))
 		return -1;
 
-	print_tunnel(&p);
+	print_tunnel(p);
 	fputc('\n', stdout);
 	return 0;
 }
-- 
2.53.0


             reply	other threads:[~2026-10-20 15:46 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-20 15:46 Stephen Hemminger [this message]
2026-10-20 19:05 ` [PATCH iproute] iptunnel: use worst case buffer for tunnel ioctls Jakub Kicinski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261020154636.1097849-1-stephen@networkplumber.org \
    --to=stephen@networkplumber.org \
    --cc=netdev@vger.kernel.org \
    --cc=noreply@anthropic.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox