Commit 1bc46dd2 authored by Eric Dumazet's avatar Eric Dumazet Committed by Jakub Kicinski
Browse files

ipv6: pass proto by value to ipv6_push_nfrag_opts() and ipv6_push_frag_opts()



With CONFIG_STACKPROTECTOR_STRONG=y, it is better to avoid passing
a pointer to an automatic variable.

Change these exported functions to return 'u8 proto'
instead of void.

- ipv6_push_nfrag_opts()
- ipv6_push_frag_opts()

For instance, replace
	ipv6_push_frag_opts(skb, opt, &proto);
with:
	proto = ipv6_push_frag_opts(skb, opt, proto);

Note that even after this change, ip6_xmit() has to use a stack canary
because of @first_hop variable.

Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reviewed-by: default avatarKuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260130210303.3888261-2-edumazet@google.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent e0221553
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -1151,11 +1151,11 @@ int ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);
 *	Extension header (options) processing
 */

void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
			  u8 *proto, struct in6_addr **daddr_p,
u8 ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
			u8 proto, struct in6_addr **daddr_p,
			struct in6_addr *saddr);
void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
			 u8 *proto);
u8 ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
		       u8 proto);

int ipv6_skip_exthdr(const struct sk_buff *, int start, u8 *nexthdrp,
		     __be16 *frag_offp);
+29 −26
Original line number Diff line number Diff line
@@ -1074,7 +1074,7 @@ int ipv6_parse_hopopts(struct sk_buff *skb)
 *	for headers.
 */

static void ipv6_push_rthdr0(struct sk_buff *skb, u8 *proto,
static u8 ipv6_push_rthdr0(struct sk_buff *skb, u8 proto,
			   struct ipv6_rt_hdr *opt,
			   struct in6_addr **addr_p, struct in6_addr *saddr)
{
@@ -1095,11 +1095,11 @@ static void ipv6_push_rthdr0(struct sk_buff *skb, u8 *proto,
	phdr->addr[hops - 1] = **addr_p;
	*addr_p = ihdr->addr;

	phdr->rt_hdr.nexthdr = *proto;
	*proto = NEXTHDR_ROUTING;
	phdr->rt_hdr.nexthdr = proto;
	return NEXTHDR_ROUTING;
}

static void ipv6_push_rthdr4(struct sk_buff *skb, u8 *proto,
static u8 ipv6_push_rthdr4(struct sk_buff *skb, u8 proto,
			   struct ipv6_rt_hdr *opt,
			   struct in6_addr **addr_p, struct in6_addr *saddr)
{
@@ -1144,11 +1144,11 @@ static void ipv6_push_rthdr4(struct sk_buff *skb, u8 *proto,
	}
#endif

	sr_phdr->nexthdr = *proto;
	*proto = NEXTHDR_ROUTING;
	sr_phdr->nexthdr = proto;
	return NEXTHDR_ROUTING;
}

static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
static u8 ipv6_push_rthdr(struct sk_buff *skb, u8 proto,
			  struct ipv6_rt_hdr *opt,
			  struct in6_addr **addr_p, struct in6_addr *saddr)
{
@@ -1156,46 +1156,49 @@ static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto,
	case IPV6_SRCRT_TYPE_0:
	case IPV6_SRCRT_STRICT:
	case IPV6_SRCRT_TYPE_2:
		ipv6_push_rthdr0(skb, proto, opt, addr_p, saddr);
		proto = ipv6_push_rthdr0(skb, proto, opt, addr_p, saddr);
		break;
	case IPV6_SRCRT_TYPE_4:
		ipv6_push_rthdr4(skb, proto, opt, addr_p, saddr);
		proto = ipv6_push_rthdr4(skb, proto, opt, addr_p, saddr);
		break;
	default:
		break;
	}
	return proto;
}

static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt)
static u8 ipv6_push_exthdr(struct sk_buff *skb, u8 proto, u8 type, struct ipv6_opt_hdr *opt)
{
	struct ipv6_opt_hdr *h = skb_push(skb, ipv6_optlen(opt));

	memcpy(h, opt, ipv6_optlen(opt));
	h->nexthdr = *proto;
	*proto = type;
	h->nexthdr = proto;
	return type;
}

void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
			  u8 *proto,
u8 ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt,
			u8 proto,
			struct in6_addr **daddr, struct in6_addr *saddr)
{
	if (opt->srcrt) {
		ipv6_push_rthdr(skb, proto, opt->srcrt, daddr, saddr);
		proto = ipv6_push_rthdr(skb, proto, opt->srcrt, daddr, saddr);
		/*
		 * IPV6_RTHDRDSTOPTS is ignored
		 * unless IPV6_RTHDR is set (RFC3542).
		 */
		if (opt->dst0opt)
			ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
			proto = ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt);
	}
	if (opt->hopopt)
		ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
		proto = ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt);
	return proto;
}

void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto)
u8 ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 proto)
{
	if (opt->dst1opt)
		ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
		proto = ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt);
	return proto;
}
EXPORT_SYMBOL(ipv6_push_frag_opts);

+11 −8
Original line number Diff line number Diff line
@@ -305,10 +305,11 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
		seg_len += opt->opt_nflen + opt->opt_flen;

		if (opt->opt_flen)
			ipv6_push_frag_opts(skb, opt, &proto);
			proto = ipv6_push_frag_opts(skb, opt, proto);

		if (opt->opt_nflen)
			ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop,
			proto = ipv6_push_nfrag_opts(skb, opt, proto,
						     &first_hop,
						     &fl6->saddr);
	}

@@ -1940,11 +1941,13 @@ struct sk_buff *__ip6_make_skb(struct sock *sk,
	__skb_pull(skb, skb_network_header_len(skb));

	final_dst = &fl6->daddr;
	if (opt && opt->opt_flen)
		ipv6_push_frag_opts(skb, opt, &proto);
	if (opt && opt->opt_nflen)
		ipv6_push_nfrag_opts(skb, opt, &proto, &final_dst, &fl6->saddr);

	if (opt) {
		if (opt->opt_flen)
			proto = ipv6_push_frag_opts(skb, opt, proto);
		if (opt->opt_nflen)
			proto = ipv6_push_nfrag_opts(skb, opt, proto,
						     &final_dst, &fl6->saddr);
	}
	skb_push(skb, sizeof(struct ipv6hdr));
	skb_reset_network_header(skb);
	hdr = ipv6_hdr(skb);
+1 −1
Original line number Diff line number Diff line
@@ -1265,7 +1265,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,

	if (encap_limit >= 0) {
		init_tel_txopt(&opt, encap_limit);
		ipv6_push_frag_opts(skb, &opt.ops, &proto);
		proto = ipv6_push_frag_opts(skb, &opt.ops, proto);
	}

	skb_push(skb, sizeof(struct ipv6hdr));