summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/inet/ip/tnet.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/inet/ip/tnet.c')
-rw-r--r--usr/src/uts/common/inet/ip/tnet.c169
1 files changed, 127 insertions, 42 deletions
diff --git a/usr/src/uts/common/inet/ip/tnet.c b/usr/src/uts/common/inet/ip/tnet.c
index c4f4d0b18f..1e5c0eb170 100644
--- a/usr/src/uts/common/inet/ip/tnet.c
+++ b/usr/src/uts/common/inet/ip/tnet.c
@@ -632,6 +632,34 @@ gcgrp_inactive(tsol_gcgrp_t *gcgrp)
kmem_free(gcgrp, sizeof (*gcgrp));
}
+
+/*
+ * Assign a sensitivity label to inbound traffic which arrived without
+ * an explicit on-the-wire label.
+ *
+ * In the case of CIPSO-type hosts, we assume packets arriving without
+ * a label are at the most sensitive label known for the host, most
+ * likely involving out-of-band key management traffic (such as IKE,
+ * etc.,)
+ */
+static boolean_t
+tsol_find_unlabeled_label(tsol_tpc_t *rhtp, bslabel_t *sl, uint32_t *doi)
+{
+ *doi = rhtp->tpc_tp.tp_doi;
+ switch (rhtp->tpc_tp.host_type) {
+ case UNLABELED:
+ *sl = rhtp->tpc_tp.tp_def_label;
+ break;
+ case SUN_CIPSO:
+ *sl = rhtp->tpc_tp.tp_sl_range_cipso.upper_bound;
+ break;
+ default:
+ return (B_FALSE);
+ }
+ setbltype(sl, SUN_SL_ID);
+ return (B_TRUE);
+}
+
/*
* Converts CIPSO option to sensitivity label.
* Validity checks based on restrictions defined in
@@ -658,13 +686,14 @@ cipso_to_sl(const uchar_t *option, bslabel_t *sl)
}
/*
- * Parse the CIPSO label in the incoming packet and construct a ts_label_t
- * that reflects the CIPSO label and attach it to the dblk cred. Later as
- * the mblk flows up through the stack any code that needs to examine the
- * packet label can inspect the label from the dblk cred. This function is
- * called right in ip_rput for all packets, i.e. locally destined and
- * to be forwarded packets. The forwarding path needs to examine the label
- * to determine how to forward the packet.
+ * If present, parse a CIPSO label in the incoming packet and
+ * construct a ts_label_t that reflects the CIPSO label and attach it
+ * to the dblk cred. Later as the mblk flows up through the stack any
+ * code that needs to examine the packet label can inspect the label
+ * from the dblk cred. This function is called right in ip_rput for
+ * all packets, i.e. locally destined and to be forwarded packets. The
+ * forwarding path needs to examine the label to determine how to
+ * forward the packet.
*
* This routine pulls all message text up into the first mblk.
* For IPv4, only the first 20 bytes of the IP header are guaranteed
@@ -673,17 +702,19 @@ cipso_to_sl(const uchar_t *option, bslabel_t *sl)
boolean_t
tsol_get_pkt_label(mblk_t *mp, int version)
{
- tsol_tpc_t *src_rhtp;
+ tsol_tpc_t *src_rhtp = NULL;
uchar_t *opt_ptr = NULL;
const ipha_t *ipha;
bslabel_t sl;
uint32_t doi;
tsol_ip_label_t label_type;
+ uint32_t label_flags = 0; /* flags to set in label */
const cipso_option_t *co;
const void *src;
const ip6_t *ip6h;
cred_t *credp;
pid_t cpid;
+ int proto;
ASSERT(DB_TYPE(mp) == M_DATA);
@@ -725,21 +756,37 @@ tsol_get_pkt_label(mblk_t *mp, int version)
if (!cipso_to_sl(opt_ptr, &sl))
return (B_FALSE);
setbltype(&sl, SUN_SL_ID);
+
+ /*
+ * If the source was unlabeled, then flag as such,
+ * (since CIPSO routers may add headers)
+ */
+
+ if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL)
+ return (B_FALSE);
+
+ if (src_rhtp->tpc_tp.host_type == UNLABELED)
+ label_flags = TSLF_UNLABELED;
+
+ TPC_RELE(src_rhtp);
+
break;
case OPT_NONE:
/*
- * Handle special cases that are not currently labeled, even
+ * Handle special cases that may not be labeled, even
* though the sending system may otherwise be configured as
* labeled.
* - IGMP
* - IPv4 ICMP Router Discovery
* - IPv6 Neighbor Discovery
+ * - IPsec ESP
*/
if (version == IPV4_VERSION) {
- if (ipha->ipha_protocol == IPPROTO_IGMP)
+ proto = ipha->ipha_protocol;
+ if (proto == IPPROTO_IGMP)
return (B_TRUE);
- if (ipha->ipha_protocol == IPPROTO_ICMP) {
+ if (proto == IPPROTO_ICMP) {
const struct icmp *icmp = (const struct icmp *)
(mp->b_rptr + IPH_HDR_LENGTH(ipha));
@@ -750,7 +797,8 @@ tsol_get_pkt_label(mblk_t *mp, int version)
return (B_TRUE);
}
} else {
- if (ip6h->ip6_nxt == IPPROTO_ICMPV6) {
+ proto = ip6h->ip6_nxt;
+ if (proto == IPPROTO_ICMPV6) {
const icmp6_t *icmp6 = (const icmp6_t *)
(mp->b_rptr + IPV6_HDR_LEN);
@@ -765,23 +813,32 @@ tsol_get_pkt_label(mblk_t *mp, int version)
/*
* Look up the tnrhtp database and get the implicit label
- * that is associated with this unlabeled host and attach
+ * that is associated with the sending host and attach
* it to the packet.
*/
if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL)
return (B_FALSE);
- /* If the sender is labeled, drop the unlabeled packet. */
- if (src_rhtp->tpc_tp.host_type != UNLABELED) {
+ /*
+ * If peer is label-aware, mark as "implicit" rather than
+ * "unlabeled" to cause appropriate mac-exempt processing
+ * to happen.
+ */
+ if (src_rhtp->tpc_tp.host_type == SUN_CIPSO)
+ label_flags = TSLF_IMPLICIT_IN;
+ else if (src_rhtp->tpc_tp.host_type == UNLABELED)
+ label_flags = TSLF_UNLABELED;
+ else {
+ DTRACE_PROBE2(tx__get__pkt__label, char *,
+ "template(1) has unknown hosttype",
+ tsol_tpc_t *, src_rhtp);
+ }
+
+
+ if (!tsol_find_unlabeled_label(src_rhtp, &sl, &doi)) {
TPC_RELE(src_rhtp);
- pr_addr_dbg("unlabeled packet forged from %s\n",
- version == IPV4_VERSION ? AF_INET : AF_INET6, src);
return (B_FALSE);
}
-
- sl = src_rhtp->tpc_tp.tp_def_label;
- setbltype(&sl, SUN_SL_ID);
- doi = src_rhtp->tpc_tp.tp_doi;
TPC_RELE(src_rhtp);
break;
@@ -805,23 +862,12 @@ tsol_get_pkt_label(mblk_t *mp, int version)
}
if (credp == NULL)
return (B_FALSE);
+
+ crgetlabel(credp)->tsl_flags |= label_flags;
+
mblk_setcred(mp, credp, cpid);
crfree(credp); /* mblk has ref on cred */
- /*
- * If the source was unlabeled, then flag as such,
- * while remembering that CIPSO routers add headers.
- */
- if (label_type == OPT_NONE) {
- crgetlabel(credp)->tsl_flags |= TSLF_UNLABELED;
- } else if (label_type == OPT_CIPSO) {
- if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL)
- return (B_FALSE);
- if (src_rhtp->tpc_tp.host_type == UNLABELED)
- crgetlabel(credp)->tsl_flags |= TSLF_UNLABELED;
- TPC_RELE(src_rhtp);
- }
-
return (B_TRUE);
}
@@ -870,6 +916,23 @@ tsol_receive_local(const mblk_t *mp, const void *addr, uchar_t version,
label = label2bslabel(plabel);
conn_label = label2bslabel(crgetlabel(connp->conn_cred));
+
+ /*
+ * Implicitly labeled packets from label-aware sources
+ * go only to privileged receivers
+ */
+ if ((plabel->tsl_flags & TSLF_IMPLICIT_IN) &&
+ (connp->conn_mac_mode != CONN_MAC_IMPLICIT)) {
+ DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac_impl,
+ char *,
+ "implicitly labeled packet mp(1) for conn(2) "
+ "which isn't in implicit mac mode",
+ mblk_t *, mp, conn_t *, connp);
+
+ return (B_FALSE);
+ }
+
+
/*
* MLPs are always validated using the range and set of the local
* address, even when the remote host is unlabeled.
@@ -895,7 +958,7 @@ tsol_receive_local(const mblk_t *mp, const void *addr, uchar_t version,
* conn_zoneid is global for an exclusive stack, thus we use
* conn_cred to get the zoneid
*/
- if (!connp->conn_mac_exempt ||
+ if ((connp->conn_mac_mode == CONN_MAC_DEFAULT) ||
(crgetzoneid(connp->conn_cred) != GLOBAL_ZONEID &&
(plabel->tsl_doi != conn_plabel->tsl_doi ||
!bldominates(conn_label, label)))) {
@@ -1106,6 +1169,16 @@ tsol_can_reply_error(const mblk_t *mp)
if (plabel == NULL)
return (B_TRUE);
+ if (plabel->tsl_flags & TSLF_IMPLICIT_IN) {
+ DTRACE_PROBE3(tx__ip__log__drop__replyerror__unresolved__label,
+ char *,
+ "cannot send error report for packet mp(1) with "
+ "unresolved security label sl(2)",
+ mblk_t *, mp, ts_label_t *, plabel);
+ return (B_FALSE);
+ }
+
+
if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
ipha = (const ipha_t *)mp->b_rptr;
rhtp = find_tpc(&ipha->ipha_dst, IPV4_VERSION, B_FALSE);
@@ -1212,10 +1285,10 @@ tsol_ire_match_gwattr(ire_t *ire, const ts_label_t *tsl)
*/
if (tsl == NULL || ire->ire_gw_secattr == NULL) {
if (tsl != NULL) {
- DTRACE_PROBE3(tx__ip__log__drop__irematch__nogwsec,
- char *,
- "ire(1) lacks ire_gw_secattr matching label(2)",
- ire_t *, ire, ts_label_t *, tsl);
+ DTRACE_PROBE3(
+ tx__ip__log__drop__irematch__nogwsec, char *,
+ "ire(1) lacks ire_gw_secattr when matching "
+ "label(2)", ire_t *, ire, ts_label_t *, tsl);
error = EACCES;
}
goto done;
@@ -1498,6 +1571,17 @@ tsol_ip_forward(ire_t *ire, mblk_t *mp)
if ((tsl = msg_getlabel(mp)) == NULL)
return (mp);
+ if (tsl->tsl_flags & TSLF_IMPLICIT_IN) {
+ DTRACE_PROBE3(tx__ip__log__drop__forward__unresolved__label,
+ char *,
+ "cannot forward packet mp(1) with unresolved "
+ "security label sl(2)",
+ mblk_t *, mp, ts_label_t *, tsl);
+
+ return (NULL);
+ }
+
+
ASSERT(psrc != NULL && pdst != NULL);
dst_rhtp = find_tpc(pdst, ire->ire_ipversion, B_FALSE);
@@ -1648,9 +1732,10 @@ tsol_ip_forward(ire_t *ire, mblk_t *mp)
credp = msg_getcred(mp, &pid);
if ((af == AF_INET &&
- tsol_check_label(credp, &mp, B_FALSE, ipst, pid) != 0) ||
+ tsol_check_label(credp, &mp, CONN_MAC_DEFAULT, ipst, pid) != 0) ||
(af == AF_INET6 &&
- tsol_check_label_v6(credp, &mp, B_FALSE, ipst, pid) != 0)) {
+ tsol_check_label_v6(credp, &mp, CONN_MAC_DEFAULT, ipst,
+ pid) != 0)) {
mp = NULL;
goto keep_label;
}