FAILED: patch "[PATCH] netfilter: nf_queue: hold bridge skb->dev while queued" failed to apply to 5.10-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.10.y
git checkout FETCH_HEAD
git cherry-pick -x e196115ec330a18de415bdb9f5071aa9f08e53ce
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026052832-chamomile-jazz-bc30@gregkh' --subject-prefix 'PATCH 5.10.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From e196115ec330a18de415bdb9f5071aa9f08e53ce Mon Sep 17 00:00:00 2001
From: Haoze Xie <[email protected]>
Date: Fri, 15 May 2026 11:19:02 +0800
Subject: [PATCH] netfilter: nf_queue: hold bridge skb->dev while queued
br_pass_frame_up() rewrites skb->dev from the ingress port to the bridge master before queueing bridge LOCAL_IN packets. NFQUEUE only holds references on state.in/out and bridge physdevs, so a queued bridge packet can retain a freed bridge master in skb->dev until reinjection.
When the verdict is reinjected later, br_netif_receive_skb() re-enters the receive path with skb->dev still pointing at the freed bridge master, triggering a use-after-free.
Store skb->dev in the queue entry, hold a reference on it for the queue lifetime, and use the saved device when dropping queued packets during NETDEV_DOWN handling.
include/net/netfilter/nf_queue.h +1 -0
@@ -14,6 +14,7 @@ struct nf_queue_entry {struct list_head list;struct rhash_head hash_node;struct sk_buff *skb; +struct net_device *skb_dev;unsigned int id;unsigned int hook_index;/* index in hook_entries->hook[] */ #if IS_ENABLED (CONFIG_BRIDGE_NETFILTER )
net/netfilter/nf_queue.c +3 -1
@@ -61,6 +61,7 @@ static void nf_queue_entry_release_refs(struct nf_queue_entry *entry)struct nf_hook_state *state = &entry->state;/* Release those devices we held, or Alexey will kill me. */ +dev_put (entry->skb_dev);dev_put (state->in);dev_put (state->out);if (state->sk)
@@ -102,6 +103,7 @@ bool nf_queue_entry_get_refs(struct nf_queue_entry *entry)if (state->sk && !refcount_inc_not_zero (&state->sk->sk_refcnt))return false; +dev_hold (entry->skb_dev);dev_hold (state->in);dev_hold (state->out);
@@ -202,11 +204,11 @@ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state, *entry = (struct nf_queue_entry ) { .skb = skb, + .skb_dev = skb->dev, .state = *state, .hook_index = index, .size =sizeof (*entry) + route_key_size, }; -__nf_queue_entry_init_physdevs (entry);if (!nf_queue_entry_get_refs (entry)) {
net/netfilter/nfnetlink_queue.c +2 -0
@@ -1212,6 +1212,8 @@ dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex)if (physinif == ifindex || physoutif == ifindex)return 1 ;#endif +if (entry->skb_dev && entry->skb_dev->ifindex == ifindex) +return 1 ;if (entry->state.in)if (entry->state.in->ifindex == ifindex)return 1 ;
Sasha Levin
maintainerPATCH 1/2 net: Remove redundant if statements
From: Yajun Deng <[email protected]>
[ Upstream commit 1160dfa178eb848327e9dec39960a735f4dc1685 ]
The 'if (dev)' statement already move into dev_{put , hold}, so remove redundant if statements.
Stable-dep-of: e196115ec330 ("netfilter: nf_queue: hold bridge skb->dev while queued")
--- net/batman-adv/bridge_loop_avoidance.c | 6 ++---- net/batman-adv/distributed-arp-table.c | 3 +-- net/batman-adv/gateway_client.c | 3 +-- net/batman-adv/multicast.c | 9 +++------ net/batman-adv/originator.c | 12 ++++-------- net/batman-adv/translation-table.c | 9 +++------ net/can/raw.c | 8 ++------ net/core/dev.c | 6 ++---- net/core/drop_monitor.c | 6 ++---- net/core/dst.c | 6 ++---- net/core/neighbour.c | 15 +++++---------- net/ethtool/netlink.c | 6 ++---- net/ieee802154/nl-phy.c | 3 +-- net/ieee802154/nl802154.c | 3 +-- net/ieee802154/socket.c | 3 +-- net/ipv4/fib_semantics.c | 4 +--- net/ipv4/route.c | 3 +-- net/ipv6/addrconf.c | 6 ++---- net/ipv6/ip6mr.c | 3 +-- net/ipv6/route.c | 3 +-- net/netfilter/nf_queue.c | 24 ++++++++---------------- net/netlabel/netlabel_unlabeled.c | 6 ++---- net/netrom/nr_loopback.c | 3 +-- net/netrom/nr_route.c | 3 +-- net/packet/af_packet.c | 15 +++++---------- net/phonet/af_phonet.c | 3 +-- net/phonet/pn_dev.c | 6 ++---- net/phonet/socket.c | 3 +-- net/sched/act_mirred.c | 6 ++---- net/smc/smc_pnet.c | 3 +-- net/wireless/nl80211.c | 16 +++++----------- net/wireless/scan.c | 3 +-- 32 files changed, 68 insertions(+), 140 deletions(-)
net/batman-adv/bridge_loop_avoidance.c +2 -4
@@ -2352,8 +2352,7 @@ int batadv_bla_claim_dump(struct sk_buff *msg, struct netlink_callback *cb)if (primary_if)batadv_hardif_put (primary_if); -if (soft_iface) -dev_put (soft_iface); +dev_put (soft_iface);return ret; }
@@ -2590,8 +2589,7 @@ int batadv_bla_backbone_dump(struct sk_buff *msg, struct netlink_callback *cb)if (primary_if)batadv_hardif_put (primary_if); -if (soft_iface) -dev_put (soft_iface); +dev_put (soft_iface);return ret; }
net/batman-adv/distributed-arp-table.c +1 -2
@@ -1042,8 +1042,7 @@ int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb)if (primary_if)batadv_hardif_put (primary_if); -if (soft_iface) -dev_put (soft_iface); +dev_put (soft_iface);return ret; }
net/batman-adv/gateway_client.c +1 -2
@@ -586,8 +586,7 @@ int batadv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb) out:if (primary_if)batadv_hardif_put (primary_if); -if (soft_iface) -dev_put (soft_iface); +dev_put (soft_iface);return ret; }
net/batman-adv/multicast.c +3 -6
@@ -92,8 +92,7 @@ static struct net_device *batadv_mcast_get_bridge(struct net_device *soft_iface) upper =netdev_master_upper_dev_get_rcu (upper); }while (upper && !(upper->priv_flags &IFF_EBRIDGE )); -if (upper) -dev_hold (upper); +dev_hold (upper);rcu_read_unlock ();return upper;
@@ -541,8 +540,7 @@ batadv_mcast_mla_softif_get(struct net_device *dev, } out: -if (bridge) -dev_put (bridge); +dev_put (bridge);return ret4 + ret6; }
@@ -2386,8 +2384,7 @@ batadv_mcast_netlink_get_primary(struct netlink_callback *cb, } out: -if (soft_iface) -dev_put (soft_iface); +dev_put (soft_iface);if (!ret && primary_if) *primary_if = hard_iface;
net/batman-adv/originator.c +4 -8
@@ -823,12 +823,10 @@ int batadv_hardif_neigh_dump(struct sk_buff *msg, struct netlink_callback *cb) out:if (hardif)batadv_hardif_put (hardif); -if (hard_iface) -dev_put (hard_iface); +dev_put (hard_iface);if (primary_if)batadv_hardif_put (primary_if); -if (soft_iface) -dev_put (soft_iface); +dev_put (soft_iface);return ret; }
@@ -1502,12 +1500,10 @@ int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb) out:if (hardif)batadv_hardif_put (hardif); -if (hard_iface) -dev_put (hard_iface); +dev_put (hard_iface);if (primary_if)batadv_hardif_put (primary_if); -if (soft_iface) -dev_put (soft_iface); +dev_put (soft_iface);return ret; }
net/batman-adv/translation-table.c +3 -6
@@ -815,8 +815,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr, out:if (in_hardif)batadv_hardif_put (in_hardif); -if (in_dev) -dev_put (in_dev); +dev_put (in_dev);if (tt_local)batadv_tt_local_entry_put (tt_local);if (tt_global)
@@ -1310,8 +1309,7 @@ int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb) out:if (primary_if)batadv_hardif_put (primary_if); -if (soft_iface) -dev_put (soft_iface); +dev_put (soft_iface); cb->args[0 ] = bucket; cb->args[1 ] = idx;
@@ -2231,8 +2229,7 @@ int batadv_tt_global_dump(struct sk_buff *msg, struct netlink_callback *cb) out:if (primary_if)batadv_hardif_put (primary_if); -if (soft_iface) -dev_put (soft_iface); +dev_put (soft_iface); cb->args[0 ] = bucket; cb->args[1 ] = idx;
net/can/raw.c +2 -6
@@ -592,9 +592,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, ro->count = count; out_fil: -if (dev) -dev_put (dev); - +dev_put (dev);release_sock (sk);rtnl_unlock ();
@@ -638,9 +636,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname, ro->err_mask = err_mask; out_err: -if (dev) -dev_put (dev); - +dev_put (dev);release_sock (sk);rtnl_unlock ();
net/core/dev.c +2 -4
@@ -906,8 +906,7 @@ struct net_device *dev_get_by_name(struct net *net, const char *name)rcu_read_lock (); dev =dev_get_by_name_rcu (net, name); -if (dev) -dev_hold (dev); +dev_hold (dev);rcu_read_unlock ();return dev; }
@@ -980,8 +979,7 @@ struct net_device *dev_get_by_index(struct net *net, int ifindex)rcu_read_lock (); dev =dev_get_by_index_rcu (net, ifindex); -if (dev) -dev_hold (dev); +dev_hold (dev);rcu_read_unlock ();return dev; }
net/core/drop_monitor.c +2 -4
@@ -854,8 +854,7 @@ net_dm_hw_metadata_copy(const struct devlink_trap_metadata *metadata) } hw_metadata->input_dev = metadata->input_dev; -if (hw_metadata->input_dev) -dev_hold (hw_metadata->input_dev); +dev_hold (hw_metadata->input_dev);return hw_metadata;
@@ -871,8 +870,7 @@ net_dm_hw_metadata_copy(const struct devlink_trap_metadata *metadata)static void net_dm_hw_metadata_free (const struct devlink_trap_metadata *hw_metadata) { -if (hw_metadata->input_dev) -dev_put (hw_metadata->input_dev); +dev_put (hw_metadata->input_dev);kfree (hw_metadata->fa_cookie);kfree (hw_metadata->trap_name);kfree (hw_metadata->trap_group_name);
net/core/dst.c +2 -4
@@ -49,8 +49,7 @@ void dst_init(struct dst_entry *dst, struct dst_ops *ops, unsigned short flags) { dst->dev = dev; -if (dev) -dev_hold (dev); +dev_hold (dev); dst->ops = ops;dst_init_metrics (dst, dst_default_metrics.metrics, true); dst->expires =0UL ;
@@ -111,8 +110,7 @@ struct dst_entry *dst_destroy(struct dst_entry * dst)#endif if (dst->ops->destroy) dst->ops->destroy (dst); -if (dst->dev) -dev_put (dst->dev); +dev_put (dst->dev);lwtstate_put (dst->lwtstate);
net/core/neighbour.c +5 -10
@@ -743,12 +743,10 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,write_pnet (&n->net, net);memcpy (n->key, pkey, key_len); n->dev = dev; -if (dev) -dev_hold (dev); +dev_hold (dev);if (tbl->pconstructor && tbl->pconstructor (n)) { -if (dev) -dev_put (dev); +dev_put (dev);kfree (n); n =NULL ; goto out;
@@ -780,8 +778,7 @@ int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,write_unlock_bh (&tbl->lock);if (tbl->pdestructor) tbl->pdestructor (n); -if (n->dev) -dev_put (n->dev); +dev_put (n->dev);kfree (n);return 0 ; }
@@ -814,8 +811,7 @@ static int pneigh_ifdown_and_unlock(struct neigh_table *tbl, n->next =NULL ;if (tbl->pdestructor) tbl->pdestructor (n); -if (n->dev) -dev_put (n->dev); +dev_put (n->dev);kfree (n); }return -ENOENT ;
@@ -1677,8 +1673,7 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)list_del (&parms->list); parms->dead =1 ;write_unlock_bh (&tbl->lock); -if (parms->dev) -dev_put (parms->dev); +dev_put (parms->dev);call_rcu (&parms->rcu_head, neigh_rcu_free_parms); }EXPORT_SYMBOL (neigh_parms_release);
net/ethtool/netlink.c +2 -4
@@ -356,8 +356,7 @@ static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info) ops->cleanup_data (reply_data);genlmsg_end (rskb, reply_payload); -if (req_info->dev) -dev_put (req_info->dev); +dev_put (req_info->dev);kfree (reply_data);kfree (req_info);return genlmsg_reply (rskb, info);
@@ -369,8 +368,7 @@ static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info)if (ops->cleanup_data) ops->cleanup_data (reply_data); err_dev: -if (req_info->dev) -dev_put (req_info->dev); +dev_put (req_info->dev);kfree (reply_data);kfree (req_info);return ret;
net/ieee802154/nl-phy.c +1 -2
@@ -340,8 +340,7 @@ int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info) out_dev:wpan_phy_put (phy); out: -if (dev) -dev_put (dev); +dev_put (dev);return rc; }
net/ieee802154/nl802154.c +1 -2
@@ -2230,8 +2230,7 @@ static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,if (ops->internal_flags &NL802154_FLAG_NEED_WPAN_DEV ) {struct wpan_dev *wpan_dev = info->user_ptr[1 ]; -if (wpan_dev->netdev) -dev_put (wpan_dev->netdev); +dev_put (wpan_dev->netdev); }else {dev_put (info->user_ptr[1 ]); }
net/ieee802154/socket.c +1 -2
@@ -41,8 +41,7 @@ ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr)ieee802154_devaddr_to_raw (hwaddr, addr->extended_addr);rcu_read_lock (); dev =dev_getbyhwaddr_rcu (net,ARPHRD_IEEE802154 , hwaddr); -if (dev) -dev_hold (dev); +dev_hold (dev);rcu_read_unlock ();break ;case IEEE802154_ADDR_SHORT :
net/ipv4/fib_semantics.c +1 -3
@@ -210,9 +210,7 @@ static void rt_fibinfo_free_cpus(struct rtable __rcu * __percpu *rtp)void fib_nh_common_release (struct fib_nh_common *nhc) { -if (nhc->nhc_dev) -dev_put (nhc->nhc_dev); - +dev_put (nhc->nhc_dev);lwtstate_put (nhc->nhc_lwtstate);rt_fibinfo_free_cpus (nhc->nhc_pcpu_rth_output);rt_fibinfo_free (&nhc->nhc_rth_input);
net/ipv4/route.c +1 -2
@@ -2782,8 +2782,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or new->output = dst_discard_out; new->dev = net->loopback_dev; -if (new->dev) -dev_hold (new->dev); +dev_hold (new->dev); rt->rt_is_input = ort->rt_is_input; rt->rt_iif = ort->rt_iif;
net/ipv6/addrconf.c +2 -4
@@ -693,8 +693,7 @@ static int inet6_netconf_get_devconf(struct sk_buff *in_skb, errout:if (in6_dev)in6_dev_put (in6_dev); -if (dev) -dev_put (dev); +dev_put (dev);return err; }
@@ -5469,8 +5468,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh, errout_ifa:in6_ifa_put (ifa); errout: -if (dev) -dev_put (dev); +dev_put (dev);if (fillargs.netnsid >=0 )put_net (tgt_net);
net/ipv6/ip6mr.c +1 -2
@@ -561,8 +561,7 @@ static int pim6_rcv(struct sk_buff *skb)read_lock (&mrt_lock);if (reg_vif_num >=0 ) reg_dev = mrt->vif_table[reg_vif_num].dev; -if (reg_dev) -dev_hold (reg_dev); +dev_hold (reg_dev);read_unlock (&mrt_lock);if (!reg_dev)
net/ipv6/route.c +1 -2
@@ -3521,8 +3521,7 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,fib_nh_common_release (&fib6_nh->nh_common); fib6_nh->nh_common.nhc_pcpu_rth_output =NULL ; fib6_nh->fib_nh_lws =NULL ; -if (dev) -dev_put (dev); +dev_put (dev); }return err;
net/netfilter/nf_queue.c +8 -16
@@ -60,18 +60,14 @@ static void nf_queue_entry_release_refs(struct nf_queue_entry *entry)struct nf_hook_state *state = &entry->state;/* Release those devices we held, or Alexey will kill me. */ -if (state->in) -dev_put (state->in); -if (state->out) -dev_put (state->out); +dev_put (state->in); +dev_put (state->out);if (state->sk)nf_queue_sock_put (state->sk);#if IS_ENABLED (CONFIG_BRIDGE_NETFILTER ) -if (entry->physin) -dev_put (entry->physin); -if (entry->physout) -dev_put (entry->physout); +dev_put (entry->physin); +dev_put (entry->physout);#endif }
@@ -107,16 +103,12 @@ bool nf_queue_entry_get_refs(struct nf_queue_entry *entry)if (state->sk && !refcount_inc_not_zero (&state->sk->sk_refcnt))return false; -if (state->in) -dev_hold (state->in); -if (state->out) -dev_hold (state->out); +dev_hold (state->in); +dev_hold (state->out);#if IS_ENABLED (CONFIG_BRIDGE_NETFILTER ) -if (entry->physin) -dev_hold (entry->physin); -if (entry->physout) -dev_hold (entry->physout); +dev_hold (entry->physin); +dev_hold (entry->physout);#endif return true; }
net/netlabel/netlabel_unlabeled.c +2 -4
@@ -492,8 +492,7 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,netlbl_af4list_audit_addr (audit_buf,1 , (dev !=NULL ? dev->name :NULL ), addr->s_addr, mask->s_addr); -if (dev !=NULL ) -dev_put (dev); +dev_put (dev);if (entry !=NULL &&security_secid_to_secctx (entry->secid, &secctx, &secctx_len) ==0 ) {
@@ -553,8 +552,7 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,netlbl_af6list_audit_addr (audit_buf,1 , (dev !=NULL ? dev->name :NULL ), addr, mask); -if (dev !=NULL ) -dev_put (dev); +dev_put (dev);if (entry !=NULL &&security_secid_to_secctx (entry->secid, &secctx, &secctx_len) ==0 ) {
net/netrom/nr_loopback.c +1 -2
@@ -59,8 +59,7 @@ static void nr_loopback_timer(struct timer_list *unused)if (dev ==NULL ||nr_rx_frame (skb, dev) ==0 )kfree_skb (skb); -if (dev !=NULL ) -dev_put (dev); +dev_put (dev);if (!skb_queue_empty (&loopback_queue) && !nr_loopback_running ())mod_timer (&loopback_timer, jiffies +10 );
net/netrom/nr_route.c +1 -2
@@ -573,8 +573,7 @@ struct net_device *nr_dev_first(void)if (first ==NULL ||strncmp (dev->name, first->name,3 ) <0 ) first = dev; } -if (first) -dev_hold (first); +dev_hold (first);rcu_read_unlock ();return first;
net/packet/af_packet.c +5 -10
@@ -249,8 +249,7 @@ static struct net_device *packet_cached_dev_get(struct packet_sock *po)rcu_read_lock (); dev =rcu_dereference (po->cached_dev); -if (likely (dev)) -dev_hold (dev); +dev_hold (dev);rcu_read_unlock ();return dev;
@@ -3098,8 +3097,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) out_free:kfree_skb (skb); out_unlock: -if (dev) -dev_put (dev); +dev_put (dev); out:return err; }
@@ -3236,8 +3234,7 @@ static int packet_do_bind(struct sock *sk, const char *name, int ifindex, } } -if (dev) -dev_hold (dev); +dev_hold (dev); proto_curr = po->prot_hook.type; dev_curr = po->prot_hook.dev;
@@ -3274,8 +3271,7 @@ static int packet_do_bind(struct sock *sk, const char *name, int ifindex,packet_cached_dev_assign (po, dev); } } -if (dev_curr) -dev_put (dev_curr); +dev_put (dev_curr);if (proto ==0 || !need_rehook) goto out_unlock;
@@ -4211,8 +4207,7 @@ static int packet_notifier(struct notifier_block *this,if (msg ==NETDEV_UNREGISTER ) {packet_cached_dev_reset (po);WRITE_ONCE (po->ifindex,-1 ); -if (po->prot_hook.dev) -dev_put (po->prot_hook.dev); +dev_put (po->prot_hook.dev); po->prot_hook.dev =NULL ; }spin_unlock (&po->bind_lock);
net/phonet/af_phonet.c +1 -2
@@ -275,8 +275,7 @@ int pn_skb_send(struct sock *sk, struct sk_buff *skb, drop:kfree_skb (skb); -if (dev) -dev_put (dev); +dev_put (dev);return err; }EXPORT_SYMBOL (pn_skb_send);
net/phonet/pn_dev.c +2 -4
@@ -122,8 +122,7 @@ struct net_device *phonet_device_get(struct net *net)break ; dev =NULL ; } -if (dev) -dev_hold (dev); +dev_hold (dev);rcu_read_unlock ();return dev; }
@@ -411,8 +410,7 @@ struct net_device *phonet_route_output(struct net *net, u8 daddr) daddr >>=2 ;rcu_read_lock (); dev =rcu_dereference (routes->table[daddr]); -if (dev) -dev_hold (dev); +dev_hold (dev);rcu_read_unlock ();if (!dev)
net/phonet/socket.c +1 -2
@@ -379,8 +379,7 @@ static int pn_socket_ioctl(struct socket *sock, unsigned int cmd, saddr =PN_NO_ADDR ;release_sock (sk); -if (dev) -dev_put (dev); +dev_put (dev);if (saddr ==PN_NO_ADDR )return -EHOSTUNREACH ;
net/sched/act_mirred.c +2 -4
@@ -79,8 +79,7 @@ static void tcf_mirred_release(struct tc_action *a)/* last reference to action, no need to lock */ dev =rcu_dereference_protected (m->tcfm_dev,1 ); -if (dev) -dev_put (dev); +dev_put (dev); }static const struct nla_policy mirred_policy[TCA_MIRRED_MAX +1 ] = {
@@ -181,8 +180,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, mac_header_xmit =dev_is_mac_header_xmit (dev); dev =rcu_replace_pointer (m->tcfm_dev, dev,lockdep_is_held (&m->tcf_lock)); -if (dev) -dev_put (dev); +dev_put (dev); m->tcfm_mac_header_xmit = mac_header_xmit; } goto_ch =tcf_action_set_ctrlact (*a, parm->action, goto_ch);
net/smc/smc_pnet.c +1 -2
@@ -395,8 +395,7 @@ static int smc_pnet_add_eth(struct smc_pnettable *pnettable, struct net *net,return 0 ; out_put: -if (ndev) -dev_put (ndev); +dev_put (ndev);return rc; }
net/wireless/nl80211.c +5 -11
@@ -6356,8 +6356,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) err =rdev_change_station (rdev, dev, mac_addr, ¶ms); out_put_vlan: -if (params.vlan) -dev_put (params.vlan); +dev_put (params.vlan);return err; }
@@ -6592,8 +6591,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) err =rdev_add_station (rdev, dev, mac_addr, ¶ms); -if (params.vlan) -dev_put (params.vlan); +dev_put (params.vlan);return err; }
@@ -8308,8 +8306,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) goto out_free;nl80211_send_scan_start (rdev, wdev); -if (wdev->netdev) -dev_hold (wdev->netdev); +dev_hold (wdev->netdev);return 0 ;
@@ -14661,9 +14658,7 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,return -ENETDOWN ; } -if (dev) -dev_hold (dev); - +dev_hold (dev); info->user_ptr[0 ] = rdev; }
@@ -14677,8 +14672,7 @@ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,if (ops->internal_flags &NL80211_FLAG_NEED_WDEV ) {struct wireless_dev *wdev = info->user_ptr[1 ]; -if (wdev->netdev) -dev_put (wdev->netdev); +dev_put (wdev->netdev); }else {dev_put (info->user_ptr[1 ]); }
net/wireless/scan.c +1 -2
@@ -1057,8 +1057,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, }#endif -if (wdev->netdev) -dev_put (wdev->netdev); +dev_put (wdev->netdev);kfree (rdev->int_scan_req); rdev->int_scan_req =NULL ;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 netfilter: nf_queue: hold bridge skb->dev while queued
From: Haoze Xie <[email protected]>
[ Upstream commit e196115ec330a18de415bdb9f5071aa9f08e53ce ]
br_pass_frame_up() rewrites skb->dev from the ingress port to the bridge master before queueing bridge LOCAL_IN packets. NFQUEUE only holds references on state.in/out and bridge physdevs, so a queued bridge packet can retain a freed bridge master in skb->dev until reinjection.
When the verdict is reinjected later, br_netif_receive_skb() re-enters the receive path with skb->dev still pointing at the freed bridge master, triggering a use-after-free.
Store skb->dev in the queue entry, hold a reference on it for the queue lifetime, and use the saved device when dropping queued packets during NETDEV_DOWN handling.
--- include/net/netfilter/nf_queue.h | 1 + net/netfilter/nf_queue.c | 4 +++- net/netfilter/nfnetlink_queue.c | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-)
include/net/netfilter/nf_queue.h +1 -0
@@ -12,6 +12,7 @@struct nf_queue_entry {struct list_head list;struct sk_buff *skb; +struct net_device *skb_dev;unsigned int id;unsigned int hook_index;/* index in hook_entries->hook[] */ #if IS_ENABLED (CONFIG_BRIDGE_NETFILTER )
net/netfilter/nf_queue.c +3 -1
@@ -60,6 +60,7 @@ static void nf_queue_entry_release_refs(struct nf_queue_entry *entry)struct nf_hook_state *state = &entry->state;/* Release those devices we held, or Alexey will kill me. */ +dev_put (entry->skb_dev);dev_put (state->in);dev_put (state->out);if (state->sk)
@@ -103,6 +104,7 @@ bool nf_queue_entry_get_refs(struct nf_queue_entry *entry)if (state->sk && !refcount_inc_not_zero (&state->sk->sk_refcnt))return false; +dev_hold (entry->skb_dev);dev_hold (state->in);dev_hold (state->out);
@@ -204,11 +206,11 @@ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state, *entry = (struct nf_queue_entry ) { .skb = skb, + .skb_dev = skb->dev, .state = *state, .hook_index = index, .size =sizeof (*entry) + route_key_size, }; -__nf_queue_entry_init_physdevs (entry);if (!nf_queue_entry_get_refs (entry)) {
net/netfilter/nfnetlink_queue.c +2 -0
@@ -911,6 +911,8 @@ dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex)if (physinif == ifindex || physoutif == ifindex)return 1 ;#endif +if (entry->skb_dev && entry->skb_dev->ifindex == ifindex) +return 1 ;if (entry->state.in)if (entry->state.in->ifindex == ifindex)return 1 ;
Signature · 1 line
2.53.0