Print this page
C. Fraire's code review fixes
8529 Extended and regular SADB_ACQUIREs should share address extension code
Portions contributed by: Bayard Bell <buffer.g.overflow@gmail.com>

*** 20,29 **** --- 20,30 ---- */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright (c) 2012 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2017 Joyent, Inc. */ #include <sys/types.h> #include <sys/stream.h> #include <sys/stropts.h>
*** 72,91 **** * This source file contains Security Association Database (SADB) common * routines. They are linked in with the AH module. Since AH has no chance * of falling under export control, it was safe to link it in there. */ ! static mblk_t *sadb_extended_acquire(ipsec_selector_t *, ipsec_policy_t *, ! ipsec_action_t *, boolean_t, uint32_t, uint32_t, sadb_sens_t *, netstack_t *); static ipsa_t *sadb_torch_assoc(isaf_t *, ipsa_t *); static void sadb_destroy_acqlist(iacqf_t **, uint_t, boolean_t, netstack_t *); static void sadb_destroy(sadb_t *, netstack_t *); static mblk_t *sadb_sa2msg(ipsa_t *, sadb_msg_t *); static ts_label_t *sadb_label_from_sens(sadb_sens_t *, uint64_t *); - static sadb_sens_t *sadb_make_sens_ext(ts_label_t *tsl, int *len); static time_t sadb_add_time(time_t, uint64_t); static void lifetime_fuzz(ipsa_t *); static void age_pair_peer_list(templist_t *, sadb_t *, boolean_t); static int get_ipsa_pair(ipsa_query_t *, ipsap_t *, int *); --- 73,90 ---- * This source file contains Security Association Database (SADB) common * routines. They are linked in with the AH module. Since AH has no chance * of falling under export control, it was safe to link it in there. */ ! static uint8_t *sadb_action_to_ecomb(uint8_t *, uint8_t *, ipsec_action_t *, netstack_t *); static ipsa_t *sadb_torch_assoc(isaf_t *, ipsa_t *); static void sadb_destroy_acqlist(iacqf_t **, uint_t, boolean_t, netstack_t *); static void sadb_destroy(sadb_t *, netstack_t *); static mblk_t *sadb_sa2msg(ipsa_t *, sadb_msg_t *); static ts_label_t *sadb_label_from_sens(sadb_sens_t *, uint64_t *); static time_t sadb_add_time(time_t, uint64_t); static void lifetime_fuzz(ipsa_t *); static void age_pair_peer_list(templist_t *, sadb_t *, boolean_t); static int get_ipsa_pair(ipsa_query_t *, ipsap_t *, int *);
*** 4842,4851 **** --- 4841,5399 ---- return (walker); } /* + * Generate an SADB_ACQUIRE base message mblk, including KEYSOCK_OUT metadata. + * In other words, this will return, upon success, a two-mblk chain. + */ + static inline mblk_t * + sadb_acquire_msg_base(minor_t serial, uint8_t satype, uint32_t seq, pid_t pid) + { + mblk_t *mp; + sadb_msg_t *samsg; + + mp = sadb_keysock_out(serial); + if (mp == NULL) + return (NULL); + mp->b_cont = allocb(sizeof (sadb_msg_t), BPRI_HI); + if (mp->b_cont == NULL) { + freeb(mp); + return (NULL); + } + + samsg = (sadb_msg_t *)mp->b_cont->b_rptr; + mp->b_cont->b_wptr += sizeof (*samsg); + samsg->sadb_msg_version = PF_KEY_V2; + samsg->sadb_msg_type = SADB_ACQUIRE; + samsg->sadb_msg_errno = 0; + samsg->sadb_msg_reserved = 0; + samsg->sadb_msg_satype = satype; + samsg->sadb_msg_seq = seq; + samsg->sadb_msg_pid = pid; + + return (mp); + } + + /* + * Generate address and TX/MLS sensitivity label PF_KEY extensions that are + * common to both regular and extended ACQUIREs. + */ + static mblk_t * + sadb_acquire_msg_common(ipsec_selector_t *sel, ipsec_policy_t *pp, + ipsec_action_t *ap, boolean_t tunnel_mode, ts_label_t *tsl, + sadb_sens_t *sens) + { + size_t len; + mblk_t *mp; + uint8_t *start, *cur, *end; + uint32_t *saddrptr, *daddrptr; + sa_family_t af; + ipsec_action_t *oldap; + ipsec_selkey_t *ipsl; + uint8_t proto, pfxlen; + uint16_t lport, rport; + int senslen = 0; + + /* + * Get action pointer set if it isn't already. + */ + oldap = ap; + if (pp != NULL) { + ap = pp->ipsp_act; + if (ap == NULL) + ap = oldap; + } + + /* + * Biggest-case scenario: + * 4x (sadb_address_t + struct sockaddr_in6) + * (src, dst, isrc, idst) + * (COMING SOON, 6x, because of triggering-packet contents.) + * sadb_x_kmc_t + * sadb_sens_t + * And wiggle room for label bitvectors. Luckily there are + * programmatic ways to find it. + */ + len = 4 * (sizeof (sadb_address_t) + sizeof (struct sockaddr_in6)); + + /* Figure out full and proper length of sensitivity labels. */ + if (sens != NULL) { + ASSERT(tsl == NULL); + senslen = SADB_64TO8(sens->sadb_sens_len); + } else if (tsl != NULL) { + senslen = sadb_sens_len_from_label(tsl); + } + #ifdef DEBUG + else { + ASSERT(senslen == 0); + } + #endif /* DEBUG */ + len += senslen; + + mp = allocb(len, BPRI_HI); + if (mp == NULL) + return (NULL); + + start = mp->b_rptr; + end = start + len; + cur = start; + + /* + * Address extensions first, from most-recently-defined to least. + * (This should immediately trigger surprise or verify robustness on + * older apps, like in.iked.) + */ + if (tunnel_mode) { + /* + * Form inner address extensions based NOT on the inner + * selectors (i.e. the packet data), but on the policy's + * selector key (i.e. the policy's selector information). + * + * NOTE: The position of IPv4 and IPv6 addresses is the + * same in ipsec_selkey_t (unless the compiler does very + * strange things with unions, consult your local C language + * lawyer for details). + */ + ASSERT(pp != NULL); + + ipsl = &(pp->ipsp_sel->ipsl_key); + if (ipsl->ipsl_valid & IPSL_IPV4) { + af = AF_INET; + ASSERT(sel->ips_protocol == IPPROTO_ENCAP); + ASSERT(!(ipsl->ipsl_valid & IPSL_IPV6)); + } else { + af = AF_INET6; + ASSERT(sel->ips_protocol == IPPROTO_IPV6); + ASSERT(ipsl->ipsl_valid & IPSL_IPV6); + } + + if (ipsl->ipsl_valid & IPSL_LOCAL_ADDR) { + saddrptr = (uint32_t *)(&ipsl->ipsl_local); + pfxlen = ipsl->ipsl_local_pfxlen; + } else { + saddrptr = (uint32_t *)(&ipv6_all_zeros); + pfxlen = 0; + } + /* XXX What about ICMP type/code? */ + lport = (ipsl->ipsl_valid & IPSL_LOCAL_PORT) ? + ipsl->ipsl_lport : 0; + proto = (ipsl->ipsl_valid & IPSL_PROTOCOL) ? + ipsl->ipsl_proto : 0; + + cur = sadb_make_addr_ext(cur, end, SADB_X_EXT_ADDRESS_INNER_SRC, + af, saddrptr, lport, proto, pfxlen); + if (cur == NULL) { + freeb(mp); + return (NULL); + } + + if (ipsl->ipsl_valid & IPSL_REMOTE_ADDR) { + daddrptr = (uint32_t *)(&ipsl->ipsl_remote); + pfxlen = ipsl->ipsl_remote_pfxlen; + } else { + daddrptr = (uint32_t *)(&ipv6_all_zeros); + pfxlen = 0; + } + /* XXX What about ICMP type/code? */ + rport = (ipsl->ipsl_valid & IPSL_REMOTE_PORT) ? + ipsl->ipsl_rport : 0; + + cur = sadb_make_addr_ext(cur, end, SADB_X_EXT_ADDRESS_INNER_DST, + af, daddrptr, rport, proto, pfxlen); + if (cur == NULL) { + freeb(mp); + return (NULL); + } + /* + * TODO - if we go to 3884's dream of transport mode IP-in-IP + * _with_ inner-packet address selectors, we'll need to further + * distinguish tunnel mode here. For now, having inner + * addresses and/or ports is sufficient. + * + * Meanwhile, whack proto/ports to reflect IP-in-IP for the + * outer addresses. + */ + proto = sel->ips_protocol; /* Either _ENCAP or _IPV6 */ + lport = rport = 0; + } else if ((ap != NULL) && (!ap->ipa_want_unique)) { + /* + * For cases when the policy calls out specific ports (or not). + */ + proto = 0; + lport = 0; + rport = 0; + if (pp != NULL) { + ipsl = &(pp->ipsp_sel->ipsl_key); + if (ipsl->ipsl_valid & IPSL_PROTOCOL) + proto = ipsl->ipsl_proto; + if (ipsl->ipsl_valid & IPSL_REMOTE_PORT) + rport = ipsl->ipsl_rport; + if (ipsl->ipsl_valid & IPSL_LOCAL_PORT) + lport = ipsl->ipsl_lport; + } + } else { + /* + * For require-unique-SA policies. + */ + proto = sel->ips_protocol; + lport = sel->ips_local_port; + rport = sel->ips_remote_port; + } + + /* + * Regular addresses. These are outer-packet ones for tunnel mode. + * Or for transport mode, the regulard address & port information. + */ + af = sel->ips_isv4 ? AF_INET : AF_INET6; + + /* + * NOTE: The position of IPv4 and IPv6 addresses is the same in + * ipsec_selector_t. + */ + cur = sadb_make_addr_ext(cur, end, SADB_EXT_ADDRESS_SRC, af, + (uint32_t *)(&sel->ips_local_addr_v6), lport, proto, 0); + if (cur == NULL) { + freeb(mp); + return (NULL); + } + + cur = sadb_make_addr_ext(cur, end, SADB_EXT_ADDRESS_DST, af, + (uint32_t *)(&sel->ips_remote_addr_v6), rport, proto, 0); + if (cur == NULL) { + freeb(mp); + return (NULL); + } + + /* + * If present, generate a sensitivity label. + */ + if (cur + senslen > end) { + freeb(mp); + return (NULL); + } + if (sens != NULL) { + /* Explicit sadb_sens_t, usually from inverse-ACQUIRE. */ + bcopy(sens, cur, senslen); + } else if (tsl != NULL) { + /* Generate sadb_sens_t from ACQUIRE source. */ + sadb_sens_from_label((sadb_sens_t *)cur, SADB_EXT_SENSITIVITY, + tsl, senslen); + } + #ifdef DEBUG + else { + ASSERT(senslen == 0); + } + #endif /* DEBUG */ + cur += senslen; + mp->b_wptr = cur; + + return (mp); + } + + /* + * Generate a regular ACQUIRE's proposal extension and KMC information.. + */ + static mblk_t * + sadb_acquire_prop(ipsec_action_t *ap, netstack_t *ns, boolean_t do_esp) + { + ipsec_stack_t *ipss = ns->netstack_ipsec; + ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; + ipsecah_stack_t *ahstack = ns->netstack_ipsecah; + mblk_t *mp = NULL; + sadb_prop_t *prop; + sadb_comb_t *comb; + ipsec_action_t *walker; + int ncombs, allocsize, ealgid, aalgid, aminbits, amaxbits, eminbits, + emaxbits, replay; + uint64_t softbytes, hardbytes, softaddtime, hardaddtime, softusetime, + hardusetime; + uint32_t kmc = 0, kmp = 0; + + /* + * Since it's an rwlock read, AND writing to the IPsec algorithms is + * rare, just acquire it once up top, and drop it upon return. + */ + rw_enter(&ipss->ipsec_alg_lock, RW_READER); + if (do_esp) { + uint64_t num_aalgs, num_ealgs; + + if (espstack->esp_kstats == NULL) + goto bail; + + num_aalgs = ipss->ipsec_nalgs[IPSEC_ALG_AUTH]; + num_ealgs = ipss->ipsec_nalgs[IPSEC_ALG_ENCR]; + if (num_ealgs == 0) + goto bail; /* IPsec not loaded yet, apparently. */ + num_aalgs++; /* No-auth or self-auth-crypto ESP. */ + + /* Use netstack's maximum loaded algorithms... */ + ncombs = num_ealgs * num_aalgs; + replay = espstack->ipsecesp_replay_size; + } else { + if (ahstack->ah_kstats == NULL) + goto bail; + + ncombs = ipss->ipsec_nalgs[IPSEC_ALG_AUTH]; + + if (ncombs == 0) + goto bail; /* IPsec not loaded yet, apparently. */ + replay = ahstack->ipsecah_replay_size; + } + + allocsize = sizeof (*prop) + ncombs * sizeof (*comb) + + sizeof (sadb_x_kmc_t); + mp = allocb(allocsize, BPRI_HI); + if (mp == NULL) + goto bail; + prop = (sadb_prop_t *)mp->b_rptr; + mp->b_wptr += sizeof (*prop); + comb = (sadb_comb_t *)mp->b_wptr; + /* Decrement allocsize, if it goes to or below 0, stop. */ + allocsize -= sizeof (*prop); + prop->sadb_prop_exttype = SADB_EXT_PROPOSAL; + prop->sadb_prop_len = SADB_8TO64(sizeof (*prop)); + *(uint32_t *)(&prop->sadb_prop_replay) = 0; /* Quick zero-out! */ + prop->sadb_prop_replay = replay; + + /* + * Based upon algorithm properties, and what-not, prioritize a + * proposal, based on the ordering of the ESP algorithms in the + * alternatives in the policy rule or socket that was placed + * in the acquire record. + * + * For each action in policy list + * Add combination. + * I should not hit it, but if I've hit limit, return. + */ + + for (walker = ap; walker != NULL; walker = walker->ipa_next) { + ipsec_alginfo_t *ealg, *aalg; + ipsec_prot_t *prot; + + if (walker->ipa_act.ipa_type != IPSEC_POLICY_APPLY) + continue; + + prot = &walker->ipa_act.ipa_apply; + if (walker->ipa_act.ipa_apply.ipp_km_proto != 0) + kmp = walker->ipa_act.ipa_apply.ipp_km_proto; + if (walker->ipa_act.ipa_apply.ipp_km_cookie != 0) + kmc = walker->ipa_act.ipa_apply.ipp_km_cookie; + if (walker->ipa_act.ipa_apply.ipp_replay_depth) { + prop->sadb_prop_replay = + walker->ipa_act.ipa_apply.ipp_replay_depth; + } + + if (do_esp) { + if (!prot->ipp_use_esp) + continue; + + if (prot->ipp_esp_auth_alg != 0) { + aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH] + [prot->ipp_esp_auth_alg]; + if (aalg == NULL || !ALG_VALID(aalg)) + continue; + } else + aalg = NULL; + + ASSERT(prot->ipp_encr_alg > 0); + ealg = ipss->ipsec_alglists[IPSEC_ALG_ENCR] + [prot->ipp_encr_alg]; + if (ealg == NULL || !ALG_VALID(ealg)) + continue; + + /* + * These may want to come from policy rule.. + */ + softbytes = espstack->ipsecesp_default_soft_bytes; + hardbytes = espstack->ipsecesp_default_hard_bytes; + softaddtime = espstack->ipsecesp_default_soft_addtime; + hardaddtime = espstack->ipsecesp_default_hard_addtime; + softusetime = espstack->ipsecesp_default_soft_usetime; + hardusetime = espstack->ipsecesp_default_hard_usetime; + } else { + if (!prot->ipp_use_ah) + continue; + ealg = NULL; + aalg = ipss->ipsec_alglists[IPSEC_ALG_AUTH] + [prot->ipp_auth_alg]; + if (aalg == NULL || !ALG_VALID(aalg)) + continue; + + /* + * These may want to come from policy rule.. + */ + softbytes = ahstack->ipsecah_default_soft_bytes; + hardbytes = ahstack->ipsecah_default_hard_bytes; + softaddtime = ahstack->ipsecah_default_soft_addtime; + hardaddtime = ahstack->ipsecah_default_hard_addtime; + softusetime = ahstack->ipsecah_default_soft_usetime; + hardusetime = ahstack->ipsecah_default_hard_usetime; + } + + if (ealg == NULL) { + ealgid = eminbits = emaxbits = 0; + } else { + ealgid = ealg->alg_id; + eminbits = + MAX(prot->ipp_espe_minbits, ealg->alg_ef_minbits); + emaxbits = + MIN(prot->ipp_espe_maxbits, ealg->alg_ef_maxbits); + } + + if (aalg == NULL) { + aalgid = aminbits = amaxbits = 0; + } else { + aalgid = aalg->alg_id; + aminbits = MAX(prot->ipp_espa_minbits, + aalg->alg_ef_minbits); + amaxbits = MIN(prot->ipp_espa_maxbits, + aalg->alg_ef_maxbits); + } + + comb->sadb_comb_flags = 0; + comb->sadb_comb_reserved = 0; + comb->sadb_comb_encrypt = ealgid; + comb->sadb_comb_encrypt_minbits = eminbits; + comb->sadb_comb_encrypt_maxbits = emaxbits; + comb->sadb_comb_auth = aalgid; + comb->sadb_comb_auth_minbits = aminbits; + comb->sadb_comb_auth_maxbits = amaxbits; + comb->sadb_comb_soft_allocations = 0; + comb->sadb_comb_hard_allocations = 0; + comb->sadb_comb_soft_bytes = softbytes; + comb->sadb_comb_hard_bytes = hardbytes; + comb->sadb_comb_soft_addtime = softaddtime; + comb->sadb_comb_hard_addtime = hardaddtime; + comb->sadb_comb_soft_usetime = softusetime; + comb->sadb_comb_hard_usetime = hardusetime; + + prop->sadb_prop_len += SADB_8TO64(sizeof (*comb)); + mp->b_wptr += sizeof (*comb); + allocsize -= sizeof (*comb); + /* Should never dip BELOW sizeof (KM cookie extension). */ + ASSERT3S(allocsize, >=, sizeof (sadb_x_kmc_t)); + if (allocsize <= sizeof (sadb_x_kmc_t)) + break; /* out of space.. */ + comb++; + } + + /* Don't include KMC extension if there's no room. */ + if (((kmp != 0) || (kmc != 0)) && allocsize >= sizeof (sadb_x_kmc_t)) { + if (sadb_make_kmc_ext(mp->b_wptr, + mp->b_wptr + sizeof (sadb_x_kmc_t), kmp, kmc) == NULL) { + freeb(mp); + mp = NULL; + goto bail; + } + mp->b_wptr += sizeof (sadb_x_kmc_t); + prop->sadb_prop_len += SADB_8TO64(sizeof (sadb_x_kmc_t)); + } + + bail: + rw_exit(&ipss->ipsec_alg_lock); + return (mp); + } + + /* + * Generate an extended ACQUIRE's extended-proposal extension. + */ + /* ARGSUSED */ + static mblk_t * + sadb_acquire_extended_prop(ipsec_action_t *ap, netstack_t *ns) + { + sadb_prop_t *eprop; + uint8_t *cur, *end; + mblk_t *mp; + int allocsize, numecombs = 0, numalgdescs = 0; + uint32_t kmc = 0, kmp = 0, replay = 0; + ipsec_action_t *walker; + + allocsize = sizeof (*eprop); + + /* + * Going to walk through the action list twice. Once for allocation + * measurement, and once for actual construction. + */ + for (walker = ap; walker != NULL; walker = walker->ipa_next) { + ipsec_prot_t *ipp; + + /* + * Skip non-IPsec policies + */ + if (walker->ipa_act.ipa_type != IPSEC_ACT_APPLY) + continue; + + ipp = &walker->ipa_act.ipa_apply; + + if (walker->ipa_act.ipa_apply.ipp_km_proto) + kmp = ipp->ipp_km_proto; + if (walker->ipa_act.ipa_apply.ipp_km_cookie) + kmc = ipp->ipp_km_cookie; + if (walker->ipa_act.ipa_apply.ipp_replay_depth) + replay = ipp->ipp_replay_depth; + + if (ipp->ipp_use_ah) + numalgdescs++; + if (ipp->ipp_use_esp) { + numalgdescs++; + if (ipp->ipp_use_espa) + numalgdescs++; + } + + numecombs++; + } + ASSERT(numecombs > 0); + + allocsize += numecombs * sizeof (sadb_x_ecomb_t) + + numalgdescs * sizeof (sadb_x_algdesc_t) + sizeof (sadb_x_kmc_t); + mp = allocb(allocsize, BPRI_HI); + if (mp == NULL) + return (NULL); + eprop = (sadb_prop_t *)mp->b_rptr; + end = mp->b_rptr + allocsize; + cur = mp->b_rptr + sizeof (*eprop); + + eprop->sadb_prop_exttype = SADB_X_EXT_EPROP; + eprop->sadb_x_prop_ereserved = 0; + eprop->sadb_x_prop_numecombs = 0; + *(uint32_t *)(&eprop->sadb_prop_replay) = 0; /* Quick zero-out! */ + /* Pick ESP's replay default if need be. */ + eprop->sadb_prop_replay = (replay == 0) ? + ns->netstack_ipsecesp->ipsecesp_replay_size : replay; + + /* This time, walk through and actually allocate. */ + for (walker = ap; walker != NULL; walker = walker->ipa_next) { + /* + * Skip non-IPsec policies + */ + if (walker->ipa_act.ipa_type != IPSEC_ACT_APPLY) + continue; + cur = sadb_action_to_ecomb(cur, end, walker, ns); + if (cur == NULL) { + /* NOTE: inverse-ACQUIRE should note this as ENOMEM. */ + freeb(mp); + return (NULL); + } + eprop->sadb_x_prop_numecombs++; + } + + ASSERT(end - cur >= sizeof (sadb_x_kmc_t)); + if ((kmp != 0) || (kmc != 0)) { + cur = sadb_make_kmc_ext(cur, end, kmp, kmc); + if (cur == NULL) { + freeb(mp); + return (NULL); + } + } + mp->b_wptr = cur; + eprop->sadb_prop_len = SADB_8TO64(cur - mp->b_rptr); + + return (mp); + } + + /* * For this mblk, insert a new acquire record. Assume bucket contains addrs * of all of the same length. Give up (and drop) if memory * cannot be allocated for a new one; otherwise, invoke callback to * send the acquire up.. *
*** 4855,4909 **** */ void sadb_acquire(mblk_t *datamp, ip_xmit_attr_t *ixa, boolean_t need_ah, boolean_t need_esp) { ! mblk_t *asyncmp; sadbp_t *spp; sadb_t *sp; ipsacq_t *newbie; iacqf_t *bucket; - mblk_t *extended; ipha_t *ipha = (ipha_t *)datamp->b_rptr; ip6_t *ip6h = (ip6_t *)datamp->b_rptr; uint32_t *src, *dst, *isrc, *idst; ipsec_policy_t *pp = ixa->ixa_ipsec_policy; ipsec_action_t *ap = ixa->ixa_ipsec_action; sa_family_t af; int hashoffset; uint32_t seq; uint64_t unique_id = 0; - ipsec_selector_t sel; boolean_t tunnel_mode = (ixa->ixa_flags & IXAF_IPSEC_TUNNEL) != 0; ! ts_label_t *tsl = NULL; netstack_t *ns = ixa->ixa_ipst->ips_netstack; ipsec_stack_t *ipss = ns->netstack_ipsec; ! sadb_sens_t *sens = NULL; ! int sens_len; ASSERT((pp != NULL) || (ap != NULL)); ! ASSERT(need_ah != NULL || need_esp != NULL); /* Assign sadb pointers */ ! if (need_esp) { /* ESP for AH+ESP */ ! ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; ! spp = &espstack->esp_sadb; } else { - ipsecah_stack_t *ahstack = ns->netstack_ipsecah; - spp = &ahstack->ah_sadb; } sp = (ixa->ixa_flags & IXAF_IS_IPV4) ? &spp->s_v4 : &spp->s_v6; if (is_system_labeled()) tsl = ixa->ixa_tsl; if (ap == NULL) ap = pp->ipsp_act; - ASSERT(ap != NULL); if (ap->ipa_act.ipa_apply.ipp_use_unique || tunnel_mode) unique_id = SA_FORM_UNIQUE_ID(ixa); --- 5403,5457 ---- */ void sadb_acquire(mblk_t *datamp, ip_xmit_attr_t *ixa, boolean_t need_ah, boolean_t need_esp) { ! mblk_t *asyncmp, *regular, *extended, *common, *prop, *eprop; sadbp_t *spp; sadb_t *sp; ipsacq_t *newbie; iacqf_t *bucket; ipha_t *ipha = (ipha_t *)datamp->b_rptr; ip6_t *ip6h = (ip6_t *)datamp->b_rptr; uint32_t *src, *dst, *isrc, *idst; ipsec_policy_t *pp = ixa->ixa_ipsec_policy; ipsec_action_t *ap = ixa->ixa_ipsec_action; sa_family_t af; int hashoffset; uint32_t seq; uint64_t unique_id = 0; boolean_t tunnel_mode = (ixa->ixa_flags & IXAF_IPSEC_TUNNEL) != 0; ! ts_label_t *tsl; netstack_t *ns = ixa->ixa_ipst->ips_netstack; ipsec_stack_t *ipss = ns->netstack_ipsec; ! ipsecesp_stack_t *espstack = ns->netstack_ipsecesp; ! ipsecah_stack_t *ahstack = ns->netstack_ipsecah; ! ipsec_selector_t sel; ! queue_t *q; ASSERT((pp != NULL) || (ap != NULL)); ! ASSERT(need_ah || need_esp); /* Assign sadb pointers */ ! if (need_esp) { ! /* ! * ESP happens first if we need both AH and ESP. ! */ spp = &espstack->esp_sadb; } else { spp = &ahstack->ah_sadb; } sp = (ixa->ixa_flags & IXAF_IS_IPV4) ? &spp->s_v4 : &spp->s_v6; if (is_system_labeled()) tsl = ixa->ixa_tsl; + else + tsl = NULL; if (ap == NULL) ap = pp->ipsp_act; ASSERT(ap != NULL); if (ap->ipa_act.ipa_apply.ipp_use_unique || tunnel_mode) unique_id = SA_FORM_UNIQUE_ID(ixa);
*** 5029,5038 **** --- 5577,5593 ---- BUMP_MIB(&ixa->ixa_ipst->ips_ip6_mib, ipIfStatsOutDiscards); } ip_drop_output("No memory for asyncmp", datamp, NULL); freemsg(datamp); + /* + * The acquire record will be freed quickly if it's new + * (ipsacq_expire == 0), and will proceed as if no packet + * showed up if not. + */ + mutex_exit(&newbie->ipsacq_lock); + return; } else if (newbie->ipsacq_numpackets == 0) { /* First one. */ newbie->ipsacq_mp = asyncmp; newbie->ipsacq_numpackets = 1; newbie->ipsacq_expire = gethrestime_sec();
*** 5061,5073 **** } else { newbie->ipsacq_proto = ixa->ixa_ipsec_proto; } newbie->ipsacq_unique_id = unique_id; ! if (ixa->ixa_tsl != NULL) { ! label_hold(ixa->ixa_tsl); ! newbie->ipsacq_tsl = ixa->ixa_tsl; } } else { /* Scan to the end of the list & insert. */ mblk_t *lastone = newbie->ipsacq_mp; --- 5616,5628 ---- } else { newbie->ipsacq_proto = ixa->ixa_ipsec_proto; } newbie->ipsacq_unique_id = unique_id; ! if (tsl != NULL) { ! label_hold(tsl); ! newbie->ipsacq_tsl = tsl; } } else { /* Scan to the end of the list & insert. */ mblk_t *lastone = newbie->ipsacq_mp;
*** 5108,5123 **** /* I have an acquire outstanding already! */ mutex_exit(&newbie->ipsacq_lock); return; } ! if (!keysock_extended_reg(ns)) ! goto punt_extended; /* ! * Construct an extended ACQUIRE. There are logging ! * opportunities here in failure cases. */ bzero(&sel, sizeof (sel)); sel.ips_isv4 = (ixa->ixa_flags & IXAF_IS_IPV4) != 0; if (tunnel_mode) { sel.ips_protocol = (ixa->ixa_ipsec_inaf == AF_INET) ? IPPROTO_ENCAP : IPPROTO_IPV6; --- 5663,5692 ---- /* I have an acquire outstanding already! */ mutex_exit(&newbie->ipsacq_lock); return; } ! if (need_esp) { ! ESP_BUMP_STAT(espstack, acquire_requests); ! q = espstack->esp_pfkey_q; ! } else { /* ! * Two cases get us here: ! * 1.) AH-only policy. ! * ! * 2.) A continuation of an AH+ESP policy, and this is the ! * post-ESP, AH-needs-to-send-a-regular-ACQUIRE case. ! * (i.e. called from esp_do_outbound_ah().) */ + AH_BUMP_STAT(ahstack, acquire_requests); + q = ahstack->ah_pfkey_q; + } + + /* + * Get selectors and other policy-expression bits needed for an + * ACQUIRE. + */ bzero(&sel, sizeof (sel)); sel.ips_isv4 = (ixa->ixa_flags & IXAF_IS_IPV4) != 0; if (tunnel_mode) { sel.ips_protocol = (ixa->ixa_ipsec_inaf == AF_INET) ? IPPROTO_ENCAP : IPPROTO_IPV6;
*** 5135,5183 **** } else { sel.ips_local_addr_v6 = ip6h->ip6_src; sel.ips_remote_addr_v6 = ip6h->ip6_dst; } - extended = sadb_keysock_out(0); - if (extended == NULL) - goto punt_extended; - if (ixa->ixa_tsl != NULL) { /* ! * XXX MLS correct condition here? ! * XXX MLS other credential attributes in acquire? ! * XXX malloc failure? don't fall back to original? */ - sens = sadb_make_sens_ext(ixa->ixa_tsl, &sens_len); ! if (sens == NULL) { ! freeb(extended); ! goto punt_extended; ! } ! } ! extended->b_cont = sadb_extended_acquire(&sel, pp, ap, tunnel_mode, ! seq, 0, sens, ns); ! if (sens != NULL) ! kmem_free(sens, sens_len); ! if (extended->b_cont == NULL) { ! freeb(extended); ! goto punt_extended; ! } /* ! * Send an ACQUIRE message (and possible an extended ACQUIRE) based on ! * this new record. The send-acquire callback assumes that acqrec is ! * already locked. */ ! (*spp->s_acqfn)(newbie, extended, ns); return; ! punt_extended: ! (*spp->s_acqfn)(newbie, NULL, ns); } /* * Unlink and free an acquire record. */ --- 5704,5806 ---- } else { sel.ips_local_addr_v6 = ip6h->ip6_src; sel.ips_remote_addr_v6 = ip6h->ip6_dst; } /* ! * 1. Generate addresses, kmc, and sensitivity. These are "common" ! * and should be an mblk pointed to by common. TBD -- eventually it ! * will include triggering packet contents as more address extensions. ! * ! * 2. Generate ACQUIRE & KEYSOCK_OUT and single-protocol proposal. ! * These are "regular" and "prop". String regular->b_cont->b_cont = ! * common, common->b_cont = prop. ! * ! * 3. If extended register got turned on, generate EXT_ACQUIRE & ! * KEYSOCK_OUT and multi-protocol eprop. These are "extended" and ! * "eprop". String extended->b_cont->b_cont = dupb(common) and ! * extended->b_cont->b_cont->b_cont = prop. ! * ! * 4. Deliver: putnext(q, regular) and if there, putnext(q, extended). */ ! regular = extended = prop = eprop = NULL; ! common = sadb_acquire_msg_common(&sel, pp, ap, tunnel_mode, tsl, NULL); ! if (common == NULL) ! goto bail; ! regular = sadb_acquire_msg_base(0, (need_esp ? ! SADB_SATYPE_ESP : SADB_SATYPE_AH), newbie->ipsacq_seq, 0); ! if (regular == NULL) ! goto bail; ! /* ! * Pardon the boolean cleverness. At least one of need_* must be true. ! * If they are equal, it's an AH & ESP policy and ESP needs to go ! * first. If they aren't, just check the contents of need_esp. ! */ ! prop = sadb_acquire_prop(ap, ns, need_esp); ! if (prop == NULL) ! goto bail; + /* Link the parts together. */ + regular->b_cont->b_cont = common; + common->b_cont = prop; /* ! * Prop is now linked, so don't freemsg() it if the extended ! * construction goes off the rails. */ ! prop = NULL; ! ! ((sadb_msg_t *)(regular->b_cont->b_rptr))->sadb_msg_len = ! SADB_8TO64(msgsize(regular->b_cont)); ! ! /* ! * If we need an extended ACQUIRE, build it here. ! */ ! if (keysock_extended_reg(ns)) { ! /* NOTE: "common" still points to what we need. */ ! extended = sadb_acquire_msg_base(0, 0, newbie->ipsacq_seq, 0); ! if (extended == NULL) { ! common = NULL; ! goto bail; ! } ! ! extended->b_cont->b_cont = dupb(common); ! common = NULL; ! if (extended->b_cont->b_cont == NULL) ! goto bail; ! ! eprop = sadb_acquire_extended_prop(ap, ns); ! if (eprop == NULL) ! goto bail; ! extended->b_cont->b_cont->b_cont = eprop; ! ! ((sadb_msg_t *)(extended->b_cont->b_rptr))->sadb_msg_len = ! SADB_8TO64(msgsize(extended->b_cont)); ! } ! ! /* So we don't hold a lock across putnext()... */ ! mutex_exit(&newbie->ipsacq_lock); ! ! if (extended != NULL) ! putnext(q, extended); ! ASSERT(regular != NULL); ! putnext(q, regular); return; ! bail: ! /* Make this acquire record go away quickly... */ ! newbie->ipsacq_expire = 0; ! /* Exploit freemsg(NULL) being legal for fun & profit. */ ! freemsg(common); ! freemsg(prop); ! freemsg(extended); ! freemsg(regular); ! mutex_exit(&newbie->ipsacq_lock); } /* * Unlink and free an acquire record. */
*** 5427,5451 **** bitmap = (uint8_t *)(sens + 1); bcopy(&(((_bslabel_impl_t *)sl)->compartments), bitmap, _C_LEN * 4); } - static sadb_sens_t * - sadb_make_sens_ext(ts_label_t *tsl, int *len) - { - /* XXX allocation failure? */ - int sens_len = sadb_sens_len_from_label(tsl); - - sadb_sens_t *sens = kmem_alloc(sens_len, KM_SLEEP); - - sadb_sens_from_label(sens, SADB_EXT_SENSITIVITY, tsl, sens_len); - - *len = sens_len; - - return (sens); - } - /* * Okay, how do we report errors/invalid labels from this? * With a special designated "not a label" cred_t ? */ /* ARGSUSED */ --- 6050,6059 ----
*** 5478,5873 **** } /* End XXX label-library-leakage */ /* - * Construct an extended ACQUIRE message based on a selector and the resulting - * IPsec action. - * - * NOTE: This is used by both inverse ACQUIRE and actual ACQUIRE - * generation. As a consequence, expect this function to evolve - * rapidly. - */ - static mblk_t * - sadb_extended_acquire(ipsec_selector_t *sel, ipsec_policy_t *pol, - ipsec_action_t *act, boolean_t tunnel_mode, uint32_t seq, uint32_t pid, - sadb_sens_t *sens, netstack_t *ns) - { - mblk_t *mp; - sadb_msg_t *samsg; - uint8_t *start, *cur, *end; - uint32_t *saddrptr, *daddrptr; - sa_family_t af; - sadb_prop_t *eprop; - ipsec_action_t *ap, *an; - ipsec_selkey_t *ipsl; - uint8_t proto, pfxlen; - uint16_t lport, rport; - uint32_t kmp, kmc; - - /* - * Find the action we want sooner rather than later.. - */ - an = NULL; - if (pol == NULL) { - ap = act; - } else { - ap = pol->ipsp_act; - - if (ap != NULL) - an = ap->ipa_next; - } - - /* - * Just take a swag for the allocation for now. We can always - * alter it later. - */ - #define SADB_EXTENDED_ACQUIRE_SIZE 4096 - mp = allocb(SADB_EXTENDED_ACQUIRE_SIZE, BPRI_HI); - if (mp == NULL) - return (NULL); - - start = mp->b_rptr; - end = start + SADB_EXTENDED_ACQUIRE_SIZE; - - cur = start; - - samsg = (sadb_msg_t *)cur; - cur += sizeof (*samsg); - - samsg->sadb_msg_version = PF_KEY_V2; - samsg->sadb_msg_type = SADB_ACQUIRE; - samsg->sadb_msg_errno = 0; - samsg->sadb_msg_reserved = 0; - samsg->sadb_msg_satype = 0; - samsg->sadb_msg_seq = seq; - samsg->sadb_msg_pid = pid; - - if (tunnel_mode) { - /* - * Form inner address extensions based NOT on the inner - * selectors (i.e. the packet data), but on the policy's - * selector key (i.e. the policy's selector information). - * - * NOTE: The position of IPv4 and IPv6 addresses is the - * same in ipsec_selkey_t (unless the compiler does very - * strange things with unions, consult your local C language - * lawyer for details). - */ - ASSERT(pol != NULL); - - ipsl = &(pol->ipsp_sel->ipsl_key); - if (ipsl->ipsl_valid & IPSL_IPV4) { - af = AF_INET; - ASSERT(sel->ips_protocol == IPPROTO_ENCAP); - ASSERT(!(ipsl->ipsl_valid & IPSL_IPV6)); - } else { - af = AF_INET6; - ASSERT(sel->ips_protocol == IPPROTO_IPV6); - ASSERT(ipsl->ipsl_valid & IPSL_IPV6); - } - - if (ipsl->ipsl_valid & IPSL_LOCAL_ADDR) { - saddrptr = (uint32_t *)(&ipsl->ipsl_local); - pfxlen = ipsl->ipsl_local_pfxlen; - } else { - saddrptr = (uint32_t *)(&ipv6_all_zeros); - pfxlen = 0; - } - /* XXX What about ICMP type/code? */ - lport = (ipsl->ipsl_valid & IPSL_LOCAL_PORT) ? - ipsl->ipsl_lport : 0; - proto = (ipsl->ipsl_valid & IPSL_PROTOCOL) ? - ipsl->ipsl_proto : 0; - - cur = sadb_make_addr_ext(cur, end, SADB_X_EXT_ADDRESS_INNER_SRC, - af, saddrptr, lport, proto, pfxlen); - if (cur == NULL) { - freeb(mp); - return (NULL); - } - - if (ipsl->ipsl_valid & IPSL_REMOTE_ADDR) { - daddrptr = (uint32_t *)(&ipsl->ipsl_remote); - pfxlen = ipsl->ipsl_remote_pfxlen; - } else { - daddrptr = (uint32_t *)(&ipv6_all_zeros); - pfxlen = 0; - } - /* XXX What about ICMP type/code? */ - rport = (ipsl->ipsl_valid & IPSL_REMOTE_PORT) ? - ipsl->ipsl_rport : 0; - - cur = sadb_make_addr_ext(cur, end, SADB_X_EXT_ADDRESS_INNER_DST, - af, daddrptr, rport, proto, pfxlen); - if (cur == NULL) { - freeb(mp); - return (NULL); - } - /* - * TODO - if we go to 3408's dream of transport mode IP-in-IP - * _with_ inner-packet address selectors, we'll need to further - * distinguish tunnel mode here. For now, having inner - * addresses and/or ports is sufficient. - * - * Meanwhile, whack proto/ports to reflect IP-in-IP for the - * outer addresses. - */ - proto = sel->ips_protocol; /* Either _ENCAP or _IPV6 */ - lport = rport = 0; - } else if ((ap != NULL) && (!ap->ipa_want_unique)) { - proto = 0; - lport = 0; - rport = 0; - if (pol != NULL) { - ipsl = &(pol->ipsp_sel->ipsl_key); - if (ipsl->ipsl_valid & IPSL_PROTOCOL) - proto = ipsl->ipsl_proto; - if (ipsl->ipsl_valid & IPSL_REMOTE_PORT) - rport = ipsl->ipsl_rport; - if (ipsl->ipsl_valid & IPSL_LOCAL_PORT) - lport = ipsl->ipsl_lport; - } - } else { - proto = sel->ips_protocol; - lport = sel->ips_local_port; - rport = sel->ips_remote_port; - } - - af = sel->ips_isv4 ? AF_INET : AF_INET6; - - /* - * NOTE: The position of IPv4 and IPv6 addresses is the same in - * ipsec_selector_t. - */ - cur = sadb_make_addr_ext(cur, end, SADB_EXT_ADDRESS_SRC, af, - (uint32_t *)(&sel->ips_local_addr_v6), lport, proto, 0); - - if (cur == NULL) { - freeb(mp); - return (NULL); - } - - cur = sadb_make_addr_ext(cur, end, SADB_EXT_ADDRESS_DST, af, - (uint32_t *)(&sel->ips_remote_addr_v6), rport, proto, 0); - - if (cur == NULL) { - freeb(mp); - return (NULL); - } - - if (sens != NULL) { - uint8_t *sensext = cur; - int senslen = SADB_64TO8(sens->sadb_sens_len); - - cur += senslen; - if (cur > end) { - freeb(mp); - return (NULL); - } - bcopy(sens, sensext, senslen); - } - - /* - * This section will change a lot as policy evolves. - * For now, it'll be relatively simple. - */ - eprop = (sadb_prop_t *)cur; - cur += sizeof (*eprop); - if (cur > end) { - /* no space left */ - freeb(mp); - return (NULL); - } - - eprop->sadb_prop_exttype = SADB_X_EXT_EPROP; - eprop->sadb_x_prop_ereserved = 0; - eprop->sadb_x_prop_numecombs = 0; - eprop->sadb_prop_replay = 32; /* default */ - - kmc = kmp = 0; - - for (; ap != NULL; ap = an) { - an = (pol != NULL) ? ap->ipa_next : NULL; - - /* - * Skip non-IPsec policies - */ - if (ap->ipa_act.ipa_type != IPSEC_ACT_APPLY) - continue; - - if (ap->ipa_act.ipa_apply.ipp_km_proto) - kmp = ap->ipa_act.ipa_apply.ipp_km_proto; - if (ap->ipa_act.ipa_apply.ipp_km_cookie) - kmc = ap->ipa_act.ipa_apply.ipp_km_cookie; - if (ap->ipa_act.ipa_apply.ipp_replay_depth) { - eprop->sadb_prop_replay = - ap->ipa_act.ipa_apply.ipp_replay_depth; - } - - cur = sadb_action_to_ecomb(cur, end, ap, ns); - if (cur == NULL) { /* no space */ - freeb(mp); - return (NULL); - } - eprop->sadb_x_prop_numecombs++; - } - - if (eprop->sadb_x_prop_numecombs == 0) { - /* - * This will happen if we fail to find a policy - * allowing for IPsec processing. - * Construct an error message. - */ - samsg->sadb_msg_len = SADB_8TO64(sizeof (*samsg)); - samsg->sadb_msg_errno = ENOENT; - samsg->sadb_x_msg_diagnostic = 0; - return (mp); - } - - if ((kmp != 0) || (kmc != 0)) { - cur = sadb_make_kmc_ext(cur, end, kmp, kmc); - if (cur == NULL) { - freeb(mp); - return (NULL); - } - } - - eprop->sadb_prop_len = SADB_8TO64(cur - (uint8_t *)eprop); - samsg->sadb_msg_len = SADB_8TO64(cur - start); - mp->b_wptr = cur; - - return (mp); - } - - /* - * Generic setup of an RFC 2367 ACQUIRE message. Caller sets satype. - * - * NOTE: This function acquires alg_lock as a side-effect if-and-only-if we - * succeed (i.e. return non-NULL). Caller MUST release it. This is to - * maximize code consolidation while preventing algorithm changes from messing - * with the callers finishing touches on the ACQUIRE itself. - */ - mblk_t * - sadb_setup_acquire(ipsacq_t *acqrec, uint8_t satype, ipsec_stack_t *ipss) - { - uint_t allocsize; - mblk_t *pfkeymp, *msgmp; - sa_family_t af; - uint8_t *cur, *end; - sadb_msg_t *samsg; - uint16_t sport_typecode; - uint16_t dport_typecode; - uint8_t check_proto; - boolean_t tunnel_mode = (acqrec->ipsacq_inneraddrfam != 0); - - ASSERT(MUTEX_HELD(&acqrec->ipsacq_lock)); - - pfkeymp = sadb_keysock_out(0); - if (pfkeymp == NULL) - return (NULL); - - /* - * First, allocate a basic ACQUIRE message - */ - allocsize = sizeof (sadb_msg_t) + sizeof (sadb_address_t) + - sizeof (sadb_address_t) + sizeof (sadb_prop_t); - - /* Make sure there's enough to cover both AF_INET and AF_INET6. */ - allocsize += 2 * sizeof (struct sockaddr_in6); - - rw_enter(&ipss->ipsec_alg_lock, RW_READER); - /* NOTE: The lock is now held through to this function's return. */ - allocsize += ipss->ipsec_nalgs[IPSEC_ALG_AUTH] * - ipss->ipsec_nalgs[IPSEC_ALG_ENCR] * sizeof (sadb_comb_t); - - if (tunnel_mode) { - /* Tunnel mode! */ - allocsize += 2 * sizeof (sadb_address_t); - /* Enough to cover both AF_INET and AF_INET6. */ - allocsize += 2 * sizeof (struct sockaddr_in6); - } - - msgmp = allocb(allocsize, BPRI_HI); - if (msgmp == NULL) { - freeb(pfkeymp); - rw_exit(&ipss->ipsec_alg_lock); - return (NULL); - } - - pfkeymp->b_cont = msgmp; - cur = msgmp->b_rptr; - end = cur + allocsize; - samsg = (sadb_msg_t *)cur; - cur += sizeof (sadb_msg_t); - - af = acqrec->ipsacq_addrfam; - switch (af) { - case AF_INET: - check_proto = IPPROTO_ICMP; - break; - case AF_INET6: - check_proto = IPPROTO_ICMPV6; - break; - default: - /* This should never happen unless we have kernel bugs. */ - cmn_err(CE_WARN, - "sadb_setup_acquire: corrupt ACQUIRE record.\n"); - ASSERT(0); - rw_exit(&ipss->ipsec_alg_lock); - return (NULL); - } - - samsg->sadb_msg_version = PF_KEY_V2; - samsg->sadb_msg_type = SADB_ACQUIRE; - samsg->sadb_msg_satype = satype; - samsg->sadb_msg_errno = 0; - samsg->sadb_msg_pid = 0; - samsg->sadb_msg_reserved = 0; - samsg->sadb_msg_seq = acqrec->ipsacq_seq; - - ASSERT(MUTEX_HELD(&acqrec->ipsacq_lock)); - - if ((acqrec->ipsacq_proto == check_proto) || tunnel_mode) { - sport_typecode = dport_typecode = 0; - } else { - sport_typecode = acqrec->ipsacq_srcport; - dport_typecode = acqrec->ipsacq_dstport; - } - - cur = sadb_make_addr_ext(cur, end, SADB_EXT_ADDRESS_SRC, af, - acqrec->ipsacq_srcaddr, sport_typecode, acqrec->ipsacq_proto, 0); - - cur = sadb_make_addr_ext(cur, end, SADB_EXT_ADDRESS_DST, af, - acqrec->ipsacq_dstaddr, dport_typecode, acqrec->ipsacq_proto, 0); - - if (tunnel_mode) { - sport_typecode = acqrec->ipsacq_srcport; - dport_typecode = acqrec->ipsacq_dstport; - cur = sadb_make_addr_ext(cur, end, SADB_X_EXT_ADDRESS_INNER_SRC, - acqrec->ipsacq_inneraddrfam, acqrec->ipsacq_innersrc, - sport_typecode, acqrec->ipsacq_inner_proto, - acqrec->ipsacq_innersrcpfx); - cur = sadb_make_addr_ext(cur, end, SADB_X_EXT_ADDRESS_INNER_DST, - acqrec->ipsacq_inneraddrfam, acqrec->ipsacq_innerdst, - dport_typecode, acqrec->ipsacq_inner_proto, - acqrec->ipsacq_innerdstpfx); - } - - /* XXX Insert identity information here. */ - - /* XXXMLS Insert sensitivity information here. */ - - if (cur != NULL) - samsg->sadb_msg_len = SADB_8TO64(cur - msgmp->b_rptr); - else - rw_exit(&ipss->ipsec_alg_lock); - - return (pfkeymp); - } - - /* * Given an SADB_GETSPI message, find an appropriately ranged SA and * allocate an SA. If there are message improprieties, return (ipsa_t *)-1. * If there was a memory allocation error, return NULL. (Assume NULL != * (ipsa_t *)-1). * --- 6086,6095 ----
*** 6854,6871 **** diagnostic = 0; goto bail; } } ! /* ! * Now that we have a policy entry/widget, construct an ACQUIRE ! * message based on that, fix fields where appropriate, ! * and return the message. ! */ ! retmp = sadb_extended_acquire(&sel, pp, NULL, ! (itp != NULL && (itp->itp_flags & ITPF_P_TUNNEL)), ! samsg->sadb_msg_seq, samsg->sadb_msg_pid, sens, ns); if (pp != NULL) { IPPOL_REFRELE(pp); } ASSERT(err == 0 && diagnostic == 0); if (retmp == NULL) --- 7076,7113 ---- diagnostic = 0; goto bail; } } ! ASSERT(pp != NULL); ! retmp = sadb_acquire_msg_base(0, 0, samsg->sadb_msg_seq, ! samsg->sadb_msg_pid); ! if (retmp != NULL) { ! /* Remove KEYSOCK_OUT, because caller constructs it instead. */ ! mblk_t *kso = retmp; ! ! retmp = retmp->b_cont; ! freeb(kso); ! /* Append addresses... */ ! retmp->b_cont = sadb_acquire_msg_common(&sel, pp, NULL, ! (itp != NULL && (itp->itp_flags & ITPF_P_TUNNEL)), NULL, ! sens); ! if (retmp->b_cont == NULL) { ! freemsg(retmp); ! retmp = NULL; ! } ! /* And the policy result. */ ! retmp->b_cont->b_cont = ! sadb_acquire_extended_prop(pp->ipsp_act, ns); ! if (retmp->b_cont->b_cont == NULL) { ! freemsg(retmp); ! retmp = NULL; ! } ! ((sadb_msg_t *)retmp->b_rptr)->sadb_msg_len = ! SADB_8TO64(msgsize(retmp)); ! } ! if (pp != NULL) { IPPOL_REFRELE(pp); } ASSERT(err == 0 && diagnostic == 0); if (retmp == NULL)