--- zzzz-none-000/linux-4.4.271/net/xfrm/xfrm_state.c 2021-06-03 06:22:09.000000000 +0000 +++ hawkeye-5590-750/linux-4.4.271/net/xfrm/xfrm_state.c 2023-04-19 10:22:30.000000000 +0000 @@ -528,6 +528,8 @@ net->xfrm.state_num--; spin_unlock(&net->xfrm.xfrm_state_lock); + xfrm_state_change_notify(x, XFRM_EVENT_STATE_DEL); + /* All xfrm_state objects are created by xfrm_state_alloc. * The xfrm_state_alloc call gives a reference, and that * is what we are dropping here. @@ -611,6 +613,7 @@ } } } + if (cnt) err = 0; @@ -778,6 +781,7 @@ int error = 0; struct xfrm_state *best = NULL; u32 mark = pol->mark.v & pol->mark.m; + u32 if_id = fl->flowi_xfrm.if_id; unsigned short encap_family = tmpl->encap_family; struct km_event c; @@ -789,6 +793,7 @@ if (x->props.family == encap_family && x->props.reqid == tmpl->reqid && (mark & x->mark.m) == x->mark.v && + x->if_id == if_id && !(x->props.flags & XFRM_STATE_WILDRECV) && xfrm_state_addr_check(x, daddr, saddr, encap_family) && tmpl->mode == x->props.mode && @@ -805,6 +810,7 @@ if (x->props.family == encap_family && x->props.reqid == tmpl->reqid && (mark & x->mark.m) == x->mark.v && + x->if_id == if_id && !(x->props.flags & XFRM_STATE_WILDRECV) && xfrm_addr_equal(&x->id.daddr, daddr, encap_family) && tmpl->mode == x->props.mode && @@ -844,6 +850,7 @@ * to current session. */ xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family); memcpy(&x->mark, &pol->mark, sizeof(x->mark)); + x->if_id = if_id; error = security_xfrm_state_alloc_acquire(x, pol->security, fl->flowi_secid); if (error) { @@ -886,7 +893,7 @@ } struct xfrm_state * -xfrm_stateonly_find(struct net *net, u32 mark, +xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id, xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, u8 mode, u8 proto, u32 reqid) { @@ -899,6 +906,7 @@ if (x->props.family == family && x->props.reqid == reqid && (mark & x->mark.m) == x->mark.v && + x->if_id == if_id && !(x->props.flags & XFRM_STATE_WILDRECV) && xfrm_state_addr_check(x, daddr, saddr, family) && mode == x->props.mode && @@ -979,11 +987,13 @@ struct xfrm_state *x; unsigned int h; u32 mark = xnew->mark.v & xnew->mark.m; + u32 if_id = xnew->if_id; h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { if (x->props.family == family && x->props.reqid == reqid && + x->if_id == if_id && (mark & x->mark.m) == x->mark.v && xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) && xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, family)) @@ -1006,7 +1016,7 @@ static struct xfrm_state *__find_acq_core(struct net *net, const struct xfrm_mark *m, unsigned short family, u8 mode, - u32 reqid, u8 proto, + u32 reqid, u32 if_id, u8 proto, const xfrm_address_t *daddr, const xfrm_address_t *saddr, int create) @@ -1061,6 +1071,7 @@ x->props.family = family; x->props.mode = mode; x->props.reqid = reqid; + x->if_id = if_id; x->mark.v = m->v; x->mark.m = m->m; x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; @@ -1115,7 +1126,7 @@ if (use_spi && !x1) x1 = __find_acq_core(net, &x->mark, family, x->props.mode, - x->props.reqid, x->id.proto, + x->props.reqid, x->if_id, x->id.proto, &x->id.daddr, &x->props.saddr, 0); __xfrm_state_bump_genids(x); @@ -1207,6 +1218,7 @@ x->props.flags = orig->props.flags; x->props.extra_flags = orig->props.extra_flags; + x->if_id = orig->if_id; x->tfcpad = orig->tfcpad; x->replay_maxdiff = orig->replay_maxdiff; x->replay_maxage = orig->replay_maxage; @@ -1424,13 +1436,13 @@ struct xfrm_state * xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid, - u8 proto, const xfrm_address_t *daddr, + u32 if_id, u8 proto, const xfrm_address_t *daddr, const xfrm_address_t *saddr, int create, unsigned short family) { struct xfrm_state *x; spin_lock_bh(&net->xfrm.xfrm_state_lock); - x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, saddr, create); + x = __find_acq_core(net, mark, family, mode, reqid, if_id, proto, daddr, saddr, create); spin_unlock_bh(&net->xfrm.xfrm_state_lock); return x; @@ -1970,6 +1982,20 @@ return afinfo; } +struct xfrm_state_afinfo *xfrm_state_update_afinfo(unsigned int family, struct xfrm_state_afinfo *new) +{ + struct xfrm_state_afinfo *afinfo; + + spin_lock_bh(&xfrm_state_afinfo_lock); + afinfo = rcu_dereference_protected(xfrm_state_afinfo[family], lockdep_is_held(&xfrm_state_afinfo_lock)); + rcu_assign_pointer(xfrm_state_afinfo[afinfo->family], new); + spin_unlock_bh(&xfrm_state_afinfo_lock); + + synchronize_rcu(); + return afinfo; +} +EXPORT_SYMBOL(xfrm_state_update_afinfo); + void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) { rcu_read_unlock(); @@ -2314,3 +2340,39 @@ } EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail); #endif /* CONFIG_AUDITSYSCALL */ + +void xfrm_state_change_notify(struct xfrm_state *x, enum xfrm_event_type type) +{ + struct xfrm_event_notifier *event; + struct net *net = xs_net(x); + + rcu_read_lock(); + list_for_each_entry_rcu(event, &net->xfrm.event_notifier_list, list) { + if (event->state_notify) { + event->state_notify(x, type); + } + + BUG_ON(atomic_read(&x->refcnt) <= 0); + } + + rcu_read_unlock(); +} +EXPORT_SYMBOL(xfrm_state_change_notify); + +int xfrm_event_register_notifier(struct net *net, struct xfrm_event_notifier *event) +{ + spin_lock_bh(&net->xfrm.xfrm_event_lock); + list_add_tail_rcu(&event->list, &net->xfrm.event_notifier_list); + spin_unlock_bh(&net->xfrm.xfrm_event_lock); + return 0; +} +EXPORT_SYMBOL(xfrm_event_register_notifier); + +void xfrm_event_unregister_notifier(struct net *net, struct xfrm_event_notifier *event) +{ + spin_lock_bh(&net->xfrm.xfrm_event_lock); + list_del_rcu(&event->list); + spin_unlock_bh(&net->xfrm.xfrm_event_lock); + synchronize_rcu(); +} +EXPORT_SYMBOL(xfrm_event_unregister_notifier);