Add inpcb pointer to struct ipsec_ctx_data and pass it to the pfil hook

from enc_hhook().

This should solve the problem when pf is used with if_enc(4) interface,
and outbound packet with existing PCB checked by pf, and this leads to
deadlock due to pf does its own PCB lookup and tries to take rlock when
wlock is already held.

Now we pass PCB pointer if it is known to the pfil hook, this helps to
avoid extra PCB lookup and thus rlock acquiring is not needed.
For inbound packets it is safe to pass NULL, because we do not held any
PCB locks yet.

PR:		220217
MFC after:	3 weeks
Sponsored by:	Yandex LLC
This commit is contained in:
Andrey V. Elsukov 2017-07-31 11:04:35 +00:00
parent 1336f0f4ae
commit 1a01e0e7ac
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=321779
5 changed files with 22 additions and 16 deletions

View File

@ -284,7 +284,7 @@ enc_hhook(int32_t hhook_type, int32_t hhook_id, void *udata, void *ctx_data,
/* Make a packet looks like it was received on enc(4) */
rcvif = (*ctx->mp)->m_pkthdr.rcvif;
(*ctx->mp)->m_pkthdr.rcvif = ifp;
if (pfil_run_hooks(ph, ctx->mp, ifp, pdir, NULL) != 0 ||
if (pfil_run_hooks(ph, ctx->mp, ifp, pdir, ctx->inp) != 0 ||
*ctx->mp == NULL) {
*ctx->mp = NULL; /* consumed by filter */
return (EACCES);

View File

@ -33,6 +33,7 @@
struct ipsec_ctx_data {
struct mbuf **mp;
struct secasvar *sav;
struct inpcb *inp;
uint8_t af;
#define IPSEC_ENC_BEFORE 0x01
#define IPSEC_ENC_AFTER 0x02

View File

@ -253,8 +253,9 @@ struct ipsecstat {
#include <sys/counter.h>
struct ipsec_ctx_data;
#define IPSEC_INIT_CTX(_ctx, _mp, _sav, _af, _enc) do { \
#define IPSEC_INIT_CTX(_ctx, _mp, _inp, _sav, _af, _enc) do { \
(_ctx)->mp = (_mp); \
(_ctx)->inp = (_inp); \
(_ctx)->sav = (_sav); \
(_ctx)->af = (_af); \
(_ctx)->enc = (_enc); \

View File

@ -325,7 +325,7 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
(prot == IPPROTO_UDP || prot == IPPROTO_TCP))
udp_ipsec_adjust_cksum(m, sav, prot, skip);
IPSEC_INIT_CTX(&ctx, &m, sav, AF_INET, IPSEC_ENC_BEFORE);
IPSEC_INIT_CTX(&ctx, &m, NULL, sav, AF_INET, IPSEC_ENC_BEFORE);
if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_IN)) != 0)
goto bad;
ip = mtod(m, struct ip *); /* update pointer */
@ -416,7 +416,7 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
goto bad;
}
IPSEC_INIT_CTX(&ctx, &m, sav, af, IPSEC_ENC_AFTER);
IPSEC_INIT_CTX(&ctx, &m, NULL, sav, af, IPSEC_ENC_AFTER);
if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_IN)) != 0)
goto bad;
@ -522,7 +522,7 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
goto bad;
}
IPSEC_INIT_CTX(&ctx, &m, sav, af, IPSEC_ENC_BEFORE);
IPSEC_INIT_CTX(&ctx, &m, NULL, sav, af, IPSEC_ENC_BEFORE);
if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_IN)) != 0)
goto bad;
@ -593,7 +593,7 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
else
#endif
af = AF_INET6;
IPSEC_INIT_CTX(&ctx, &m, sav, af, IPSEC_ENC_AFTER);
IPSEC_INIT_CTX(&ctx, &m, NULL, sav, af, IPSEC_ENC_AFTER);
if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_IN)) != 0)
goto bad;
if (skip == 0) {

View File

@ -181,7 +181,8 @@ ipsec4_allocsa(struct mbuf *m, struct secpolicy *sp, u_int *pidx, int *error)
* IPsec output logic for IPv4.
*/
static int
ipsec4_perform_request(struct mbuf *m, struct secpolicy *sp, u_int idx)
ipsec4_perform_request(struct mbuf *m, struct secpolicy *sp,
struct inpcb *inp, u_int idx)
{
struct ipsec_ctx_data ctx;
union sockaddr_union *dst;
@ -211,7 +212,7 @@ ipsec4_perform_request(struct mbuf *m, struct secpolicy *sp, u_int idx)
/*
* XXXAE: most likely ip_sum at this point is wrong.
*/
IPSEC_INIT_CTX(&ctx, &m, sav, AF_INET, IPSEC_ENC_BEFORE);
IPSEC_INIT_CTX(&ctx, &m, inp, sav, AF_INET, IPSEC_ENC_BEFORE);
if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0)
goto bad;
@ -235,9 +236,10 @@ ipsec4_perform_request(struct mbuf *m, struct secpolicy *sp, u_int idx)
/* XXXAE: IPSEC_OSTAT_INC(tunnel); */
goto bad;
}
inp = NULL;
}
IPSEC_INIT_CTX(&ctx, &m, sav, dst->sa.sa_family, IPSEC_ENC_AFTER);
IPSEC_INIT_CTX(&ctx, &m, inp, sav, dst->sa.sa_family, IPSEC_ENC_AFTER);
if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0)
goto bad;
@ -285,7 +287,7 @@ ipsec4_process_packet(struct mbuf *m, struct secpolicy *sp,
struct inpcb *inp)
{
return (ipsec4_perform_request(m, sp, 0));
return (ipsec4_perform_request(m, sp, inp, 0));
}
static int
@ -491,7 +493,8 @@ ipsec6_allocsa(struct mbuf *m, struct secpolicy *sp, u_int *pidx, int *error)
* IPsec output logic for IPv6.
*/
static int
ipsec6_perform_request(struct mbuf *m, struct secpolicy *sp, u_int idx)
ipsec6_perform_request(struct mbuf *m, struct secpolicy *sp,
struct inpcb *inp, u_int idx)
{
struct ipsec_ctx_data ctx;
union sockaddr_union *dst;
@ -514,7 +517,7 @@ ipsec6_perform_request(struct mbuf *m, struct secpolicy *sp, u_int idx)
ip6 = mtod(m, struct ip6_hdr *);
ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
IPSEC_INIT_CTX(&ctx, &m, sav, AF_INET6, IPSEC_ENC_BEFORE);
IPSEC_INIT_CTX(&ctx, &m, inp, sav, AF_INET6, IPSEC_ENC_BEFORE);
if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0)
goto bad;
@ -540,9 +543,10 @@ ipsec6_perform_request(struct mbuf *m, struct secpolicy *sp, u_int idx)
/* XXXAE: IPSEC_OSTAT_INC(tunnel); */
goto bad;
}
inp = NULL;
}
IPSEC_INIT_CTX(&ctx, &m, sav, dst->sa.sa_family, IPSEC_ENC_AFTER);
IPSEC_INIT_CTX(&ctx, &m, inp, sav, dst->sa.sa_family, IPSEC_ENC_AFTER);
if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0)
goto bad;
@ -585,7 +589,7 @@ ipsec6_process_packet(struct mbuf *m, struct secpolicy *sp,
struct inpcb *inp)
{
return (ipsec6_perform_request(m, sp, 0));
return (ipsec6_perform_request(m, sp, inp, 0));
}
static int
@ -750,14 +754,14 @@ ipsec_process_done(struct mbuf *m, struct secpolicy *sp, struct secasvar *sav,
case AF_INET:
key_freesav(&sav);
IPSECSTAT_INC(ips_out_bundlesa);
return (ipsec4_perform_request(m, sp, idx));
return (ipsec4_perform_request(m, sp, NULL, idx));
/* NOTREACHED */
#endif
#ifdef INET6
case AF_INET6:
key_freesav(&sav);
IPSEC6STAT_INC(ips_out_bundlesa);
return (ipsec6_perform_request(m, sp, idx));
return (ipsec6_perform_request(m, sp, NULL, idx));
/* NOTREACHED */
#endif /* INET6 */
default: