Commit c907db8d authored by Paolo Abeni's avatar Paolo Abeni
Browse files

Merge branch 'fixes-for-seg6-and-rpl-lwtunnels-on-input'

Justin Iurman says:

====================
fixes for seg6 and rpl lwtunnels on input

As a follow up to commit 92191dd1 ("net: ipv6: fix dst ref loops in
rpl, seg6 and ioam6 lwtunnels"), we also need a conditional dst cache on
input for seg6_iptunnel and rpl_iptunnel to prevent dst ref loops (i.e.,
if the packet destination did not change, we may end up recording a
reference to the lwtunnel in its own cache, and the lwtunnel state will
never be freed). This series provides a fix to respectively prevent a
dst ref loop on input in seg6_iptunnel and rpl_iptunnel.

v2:
- https://lore.kernel.org/netdev/20250211221624.18435-1-justin.iurman@uliege.be/
v1:
- https://lore.kernel.org/netdev/20250209193840.20509-1-justin.iurman@uliege.be/
====================

Link: https://patch.msgid.link/20250225175139.25239-1-justin.iurman@uliege.be


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 1cf9631d 13e55fba
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -262,10 +262,18 @@ static int rpl_input(struct sk_buff *skb)
{
	struct dst_entry *orig_dst = skb_dst(skb);
	struct dst_entry *dst = NULL;
	struct lwtunnel_state *lwtst;
	struct rpl_lwt *rlwt;
	int err;

	rlwt = rpl_lwt_lwtunnel(orig_dst->lwtstate);
	/* We cannot dereference "orig_dst" once ip6_route_input() or
	 * skb_dst_drop() is called. However, in order to detect a dst loop, we
	 * need the address of its lwtstate. So, save the address of lwtstate
	 * now and use it later as a comparison.
	 */
	lwtst = orig_dst->lwtstate;

	rlwt = rpl_lwt_lwtunnel(lwtst);

	local_bh_disable();
	dst = dst_cache_get(&rlwt->cache);
@@ -280,7 +288,9 @@ static int rpl_input(struct sk_buff *skb)
	if (!dst) {
		ip6_route_input(skb);
		dst = skb_dst(skb);
		if (!dst->error) {

		/* cache only if we don't create a dst reference loop */
		if (!dst->error && lwtst != dst->lwtstate) {
			local_bh_disable();
			dst_cache_set_ip6(&rlwt->cache, dst,
					  &ipv6_hdr(skb)->saddr);
+12 −2
Original line number Diff line number Diff line
@@ -472,10 +472,18 @@ static int seg6_input_core(struct net *net, struct sock *sk,
{
	struct dst_entry *orig_dst = skb_dst(skb);
	struct dst_entry *dst = NULL;
	struct lwtunnel_state *lwtst;
	struct seg6_lwt *slwt;
	int err;

	slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
	/* We cannot dereference "orig_dst" once ip6_route_input() or
	 * skb_dst_drop() is called. However, in order to detect a dst loop, we
	 * need the address of its lwtstate. So, save the address of lwtstate
	 * now and use it later as a comparison.
	 */
	lwtst = orig_dst->lwtstate;

	slwt = seg6_lwt_lwtunnel(lwtst);

	local_bh_disable();
	dst = dst_cache_get(&slwt->cache);
@@ -490,7 +498,9 @@ static int seg6_input_core(struct net *net, struct sock *sk,
	if (!dst) {
		ip6_route_input(skb);
		dst = skb_dst(skb);
		if (!dst->error) {

		/* cache only if we don't create a dst reference loop */
		if (!dst->error && lwtst != dst->lwtstate) {
			local_bh_disable();
			dst_cache_set_ip6(&slwt->cache, dst,
					  &ipv6_hdr(skb)->saddr);