6304623 Initiator checks against wrong label for Mac-exempt read-down exchanges
6400008 Binding to UDP MLP without privilege ruturning incorrect errno
6409753 tx sctp connect() returns different errno value from tcp
6410308 tx mlp server fails to accept sctp connections from unlabeled nodes
6468843 TX ipv4 ICMP messages not generated with appropriate labels
6685898 TX: server side sends incorrect cred when MLP is in use
6810083 TX: MAC-Exempt socket received packets sent to another zone's address
6810303 spurious ASSERT(msg_getcred(phdr_mp, NULL) == NULL) in ipsecah
6818663 TX: netstat -aR displays INVALID label
diff --git a/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c b/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c
index 2d115e2..21ad42a 100644
--- a/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c
+++ b/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c
@@ -292,6 +292,8 @@
"af", "outif", "dst", "flags"
};
+static m_label_t *zone_security_label = NULL;
+
/* Flags on routes */
#define FLF_A 0x00000001
#define FLF_B 0x00000002
@@ -526,6 +528,18 @@
exit(0);
}
+ /*
+ * Get this process's security label if the -R switch is set.
+ * We use this label as the current zone's security label.
+ */
+ if (RSECflag) {
+ zone_security_label = m_label_alloc(MAC_LABEL);
+ if (zone_security_label == NULL)
+ fatal(errno, "m_label_alloc() failed");
+ if (getplabel(zone_security_label) < 0)
+ fatal(errno, "getplabel() failed");
+ }
+
/* Get data structures: priming before iteration */
if (family_selected(AF_INET) || family_selected(AF_INET6)) {
sd = mibopen();
@@ -632,6 +646,8 @@
} /* 'for' loop 1 ends */
mibfree(item);
(void) close(sd);
+ if (zone_security_label != NULL)
+ m_label_free(zone_security_label);
return (0);
}
@@ -4503,12 +4519,13 @@
static void
print_transport_label(const mib2_transportMLPEntry_t *attr)
{
- if (!RSECflag || attr == NULL)
+ if (!RSECflag || attr == NULL ||
+ !(attr->tme_flags & MIB2_TMEF_IS_LABELED))
return;
if (bisinvalid(&attr->tme_label))
(void) printf(" INVALID\n");
- else
+ else if (!blequal(&attr->tme_label, zone_security_label))
(void) printf(" %s\n", sl_to_str(&attr->tme_label));
}
diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h
index d587fa7..cd6abc6 100644
--- a/usr/src/uts/common/inet/ip.h
+++ b/usr/src/uts/common/inet/ip.h
@@ -3242,7 +3242,7 @@
extern void icmp_unreachable(queue_t *, mblk_t *, uint8_t, zoneid_t,
ip_stack_t *);
extern mblk_t *ip_add_info(mblk_t *, ill_t *, uint_t, zoneid_t, ip_stack_t *);
-cred_t *ip_best_cred(mblk_t *, conn_t *);
+cred_t *ip_best_cred(mblk_t *, conn_t *, pid_t *);
extern mblk_t *ip_bind_v4(queue_t *, mblk_t *, conn_t *);
extern boolean_t ip_bind_ipsec_policy_set(conn_t *, mblk_t *);
extern int ip_bind_laddr_v4(conn_t *, mblk_t **, uint8_t, ipaddr_t,
diff --git a/usr/src/uts/common/inet/ip/icmp.c b/usr/src/uts/common/inet/ip/icmp.c
index 2cd4efc..559bca6 100644
--- a/usr/src/uts/common/inet/ip/icmp.c
+++ b/usr/src/uts/common/inet/ip/icmp.c
@@ -843,6 +843,17 @@
icmp->icmp_sticky_hdrs = NULL;
icmp->icmp_sticky_hdrs_len = 0;
}
+
+ if (icmp->icmp_last_cred != NULL) {
+ crfree(icmp->icmp_last_cred);
+ icmp->icmp_last_cred = NULL;
+ }
+
+ if (icmp->icmp_effective_cred != NULL) {
+ crfree(icmp->icmp_effective_cred);
+ icmp->icmp_effective_cred = NULL;
+ }
+
ip6_pkt_free(&icmp->icmp_sticky_ipp);
/*
@@ -4232,9 +4243,16 @@
ipha_t *ipha;
int ip_hdr_length;
int tp_hdr_len;
+ int error;
+ uchar_t ip_snd_opt[IP_MAX_OPT_LENGTH];
+ uint32_t ip_snd_opt_len = 0;
mblk_t *mp1;
uint_t pkt_len;
ip_opt_info_t optinfo;
+ pid_t cpid;
+ cred_t *cr;
+
+ rw_enter(&icmp->icmp_rwlock, RW_READER);
optinfo.ip_opt_flags = 0;
optinfo.ip_opt_ill_index = 0;
@@ -4245,6 +4263,7 @@
ASSERT(icmp != NULL);
BUMP_MIB(&is->is_rawip_mib, rawipOutErrors);
freemsg(mp);
+ rw_exit(&icmp->icmp_rwlock);
return (0);
}
ipha = (ipha_t *)mp->b_rptr;
@@ -4253,6 +4272,50 @@
(IP_VERSION<<4) | (ip_hdr_length>>2);
/*
+ * Check if our saved options are valid; update if not.
+ * TSOL Note: Since we are not in WRITER mode, ICMP packets
+ * to different destination may require different labels,
+ * or worse, ICMP packets to same IP address may require
+ * different labels due to use of shared all-zones address.
+ * We use conn_lock to ensure that lastdst, ip_snd_options,
+ * and ip_snd_options_len are consistent for the current
+ * destination and are updated atomically.
+ */
+ mutex_enter(&connp->conn_lock);
+ if (is_system_labeled()) {
+ /*
+ * Recompute the Trusted Extensions security label if
+ * we're not going to the same destination as last
+ * time or the cred attached to the received mblk
+ * changed.
+ */
+ cr = msg_getcred(mp, &cpid);
+ if (!IN6_IS_ADDR_V4MAPPED(&icmp->icmp_v6lastdst) ||
+ V4_PART_OF_V6(icmp->icmp_v6lastdst) != ipha->ipha_dst ||
+ cr != icmp->icmp_last_cred) {
+ error = icmp_update_label(icmp, mp, ipha->ipha_dst);
+ if (error != 0) {
+ mutex_exit(&connp->conn_lock);
+ rw_exit(&icmp->icmp_rwlock);
+ return (error);
+ }
+ }
+ /*
+ * Apply credentials with modified security label if they
+ * exist. icmp_update_label() may have generated these
+ * credentials for packets to unlabeled remote nodes.
+ */
+ if (icmp->icmp_effective_cred != NULL)
+ mblk_setcred(mp, icmp->icmp_effective_cred, cpid);
+ }
+
+ if (icmp->icmp_ip_snd_options_len > 0) {
+ ip_snd_opt_len = icmp->icmp_ip_snd_options_len;
+ bcopy(icmp->icmp_ip_snd_options, ip_snd_opt, ip_snd_opt_len);
+ }
+ mutex_exit(&connp->conn_lock);
+
+ /*
* For the socket of SOCK_RAW type, the checksum is provided in the
* pre-built packet. We set the ipha_ident field to IP_HDR_INCLUDED to
* tell IP that the application has sent a complete IP header and not
@@ -4290,6 +4353,7 @@
BUMP_MIB(&is->is_rawip_mib,
rawipOutErrors);
freemsg(mp);
+ rw_exit(&icmp->icmp_rwlock);
return (0);
}
ipha = (ipha_t *)mp->b_rptr;
@@ -4300,12 +4364,14 @@
* then send an error and abort the processing.
*/
pkt_len = ntohs(ipha->ipha_length)
- + icmp->icmp_ip_snd_options_len;
+ + ip_snd_opt_len;
if (pkt_len > IP_MAXPACKET) {
+ rw_exit(&icmp->icmp_rwlock);
return (EMSGSIZE);
}
if (!(mp1 = allocb(ip_hdr_length + is->is_wroff_extra +
tp_hdr_len, BPRI_LO))) {
+ rw_exit(&icmp->icmp_rwlock);
return (ENOMEM);
}
mp1->b_rptr += is->is_wroff_extra;
@@ -4320,8 +4386,7 @@
/* Add options */
ipha = (ipha_t *)mp1->b_rptr;
- bcopy(icmp->icmp_ip_snd_options, &ipha[1],
- icmp->icmp_ip_snd_options_len);
+ bcopy(ip_snd_opt, &ipha[1], ip_snd_opt_len);
/* Drop IP header and transport header from original */
(void) adjmsg(mp, IP_SIMPLE_HDR_LENGTH + tp_hdr_len);
@@ -4349,6 +4414,8 @@
}
}
+ rw_exit(&icmp->icmp_rwlock);
+
ip_output_options(connp, mp, q, IP_WPUT, &optinfo);
return (0);
}
@@ -4360,7 +4427,9 @@
uchar_t opt_storage[IP_MAX_OPT_LENGTH];
icmp_stack_t *is = icmp->icmp_is;
conn_t *connp = icmp->icmp_connp;
- cred_t *cr;
+ cred_t *cred;
+ cred_t *msg_cred;
+ cred_t *effective_cred;
/*
* All Solaris components should pass a db_credp
@@ -4368,19 +4437,63 @@
* On production kernels we return an error to be robust against
* random streams modules sitting on top of us.
*/
- cr = msg_getcred(mp, NULL);
- ASSERT(cr != NULL);
- if (cr == NULL)
+ cred = msg_cred = msg_getcred(mp, NULL);
+ ASSERT(cred != NULL);
+ if (cred == NULL)
return (EINVAL);
- err = tsol_compute_label(cr, dst,
- opt_storage, connp->conn_mac_exempt,
- is->is_netstack->netstack_ip);
- if (err == 0) {
- err = tsol_update_options(&icmp->icmp_ip_snd_options,
- &icmp->icmp_ip_snd_options_len, &icmp->icmp_label_len,
- opt_storage);
+ /*
+ * Verify the destination is allowed to receive packets at
+ * the security label of the message data. check_dest()
+ * may create a new effective cred for this message
+ * with a modified label or label flags.
+ */
+ if ((err = tsol_check_dest(cred, &dst, IPV4_VERSION,
+ connp->conn_mac_exempt, &effective_cred)) != 0)
+ goto done;
+ if (effective_cred != NULL)
+ cred = effective_cred;
+
+ /*
+ * Calculate the security label to be placed in the text
+ * of the message (if any).
+ */
+ if ((err = tsol_compute_label(cred, dst, opt_storage,
+ is->is_netstack->netstack_ip)) != 0)
+ goto done;
+
+ /*
+ * Insert the security label in the cached ip options,
+ * removing any old label that may exist.
+ */
+ if ((err = tsol_update_options(&icmp->icmp_ip_snd_options,
+ &icmp->icmp_ip_snd_options_len, &icmp->icmp_label_len,
+ opt_storage)) != 0)
+ goto done;
+
+ /*
+ * Save the destination address and cred we used to generate
+ * the security label text.
+ */
+ IN6_IPADDR_TO_V4MAPPED(dst, &icmp->icmp_v6lastdst);
+ if (cred != icmp->icmp_effective_cred) {
+ if (icmp->icmp_effective_cred != NULL)
+ crfree(icmp->icmp_effective_cred);
+ crhold(cred);
+ icmp->icmp_effective_cred = cred;
}
+
+ if (msg_cred != icmp->icmp_last_cred) {
+ if (icmp->icmp_last_cred != NULL)
+ crfree(icmp->icmp_last_cred);
+ crhold(msg_cred);
+ icmp->icmp_last_cred = msg_cred;
+ }
+
+done:
+ if (effective_cred != NULL)
+ crfree(effective_cred);
+
if (err != 0) {
BUMP_MIB(&is->is_rawip_mib, rawipOutErrors);
DTRACE_PROBE4(
@@ -4389,7 +4502,6 @@
icmp_t *, icmp, char *, opt_storage, mblk_t *, mp);
return (err);
}
- IN6_IPADDR_TO_V4MAPPED(dst, &icmp->icmp_v6lastdst);
return (0);
}
@@ -4402,7 +4514,6 @@
icmp_wput(queue_t *q, mblk_t *mp)
{
uchar_t *rptr = mp->b_rptr;
- ipha_t *ipha;
mblk_t *mp1;
#define tudr ((struct T_unitdata_req *)rptr)
size_t ip_len;
@@ -4425,32 +4536,6 @@
case M_DATA:
if (icmp->icmp_hdrincl) {
ASSERT(icmp->icmp_ipversion == IPV4_VERSION);
- ipha = (ipha_t *)mp->b_rptr;
- if (mp->b_wptr - mp->b_rptr < IP_SIMPLE_HDR_LENGTH) {
- if (!pullupmsg(mp, IP_SIMPLE_HDR_LENGTH)) {
- BUMP_MIB(&is->is_rawip_mib,
- rawipOutErrors);
- freemsg(mp);
- return;
- }
- ipha = (ipha_t *)mp->b_rptr;
- }
- /*
- * If this connection was used for v6 (inconceivable!)
- * or if we have a new destination, then it's time to
- * figure a new label.
- */
- if (is_system_labeled() &&
- (!IN6_IS_ADDR_V4MAPPED(&icmp->icmp_v6lastdst) ||
- V4_PART_OF_V6(icmp->icmp_v6lastdst) !=
- ipha->ipha_dst)) {
- error = icmp_update_label(icmp, mp,
- ipha->ipha_dst);
- if (error != 0) {
- icmp_ud_err(q, mp, error);
- return;
- }
- }
error = icmp_wput_hdrincl(q, connp, mp, icmp, NULL);
if (error != 0)
icmp_ud_err(q, mp, error);
@@ -4602,6 +4687,10 @@
icmp_stack_t *is = icmp->icmp_is;
int ip_hdr_length;
ip_opt_info_t optinfo;
+ uchar_t ip_snd_opt[IP_MAX_OPT_LENGTH];
+ uint32_t ip_snd_opt_len = 0;
+ pid_t cpid;
+ cred_t *cr;
optinfo.ip_opt_flags = 0;
optinfo.ip_opt_ill_index = 0;
@@ -4615,22 +4704,58 @@
if (v4dst == INADDR_ANY)
v4dst = htonl(INADDR_LOOPBACK);
- /* Check if our saved options are valid; update if not */
- if (is_system_labeled() &&
- (!IN6_IS_ADDR_V4MAPPED(&icmp->icmp_v6lastdst) ||
- V4_PART_OF_V6(icmp->icmp_v6lastdst) != v4dst)) {
- int error = icmp_update_label(icmp, mp, v4dst);
-
- if (error != 0)
- return (error);
- }
-
/* Protocol 255 contains full IP headers */
if (icmp->icmp_hdrincl)
return (icmp_wput_hdrincl(q, connp, mp, icmp, pktinfop));
+ rw_enter(&icmp->icmp_rwlock, RW_READER);
+
+ /*
+ * Check if our saved options are valid; update if not.
+ * TSOL Note: Since we are not in WRITER mode, ICMP packets
+ * to different destination may require different labels,
+ * or worse, ICMP packets to same IP address may require
+ * different labels due to use of shared all-zones address.
+ * We use conn_lock to ensure that lastdst, ip_snd_options,
+ * and ip_snd_options_len are consistent for the current
+ * destination and are updated atomically.
+ */
+ mutex_enter(&connp->conn_lock);
+ if (is_system_labeled()) {
+
+ /*
+ * Recompute the Trusted Extensions security label if we're not
+ * going to the same destination as last time or the cred
+ * attached to the received mblk changed.
+ */
+ cr = msg_getcred(mp, &cpid);
+ if (!IN6_IS_ADDR_V4MAPPED(&icmp->icmp_v6lastdst) ||
+ V4_PART_OF_V6(icmp->icmp_v6lastdst) != v4dst ||
+ cr != icmp->icmp_last_cred) {
+ int error = icmp_update_label(icmp, mp, v4dst);
+ if (error != 0) {
+ mutex_exit(&connp->conn_lock);
+ rw_exit(&icmp->icmp_rwlock);
+ return (error);
+ }
+ }
+ /*
+ * Apply credentials with modified security label if they
+ * exist. icmp_update_label() may have generated these
+ * credentials for packets to unlabeled remote nodes.
+ */
+ if (icmp->icmp_effective_cred != NULL)
+ mblk_setcred(mp, icmp->icmp_effective_cred, cpid);
+ }
+
+ if (icmp->icmp_ip_snd_options_len > 0) {
+ ip_snd_opt_len = icmp->icmp_ip_snd_options_len;
+ bcopy(icmp->icmp_ip_snd_options, ip_snd_opt, ip_snd_opt_len);
+ }
+ mutex_exit(&connp->conn_lock);
+
/* Add an IP header */
- ip_hdr_length = IP_SIMPLE_HDR_LENGTH + icmp->icmp_ip_snd_options_len;
+ ip_hdr_length = IP_SIMPLE_HDR_LENGTH + ip_snd_opt_len;
ipha = (ipha_t *)&mp->b_rptr[-ip_hdr_length];
if ((uchar_t *)ipha < mp->b_datap->db_base ||
mp->b_datap->db_ref != 1 ||
@@ -4639,6 +4764,7 @@
if (!(mp1 = allocb(ip_hdr_length + is->is_wroff_extra,
BPRI_LO))) {
BUMP_MIB(&is->is_rawip_mib, rawipOutErrors);
+ rw_exit(&icmp->icmp_rwlock);
return (ENOMEM);
}
mp1->b_cont = mp;
@@ -4704,6 +4830,7 @@
*/
if (ip_len > IP_MAXPACKET) {
BUMP_MIB(&is->is_rawip_mib, rawipOutErrors);
+ rw_exit(&icmp->icmp_rwlock);
return (EMSGSIZE);
}
ipha->ipha_length = htons((uint16_t)ip_len);
@@ -4720,8 +4847,8 @@
/* Copy in options if any */
if (ip_hdr_length > IP_SIMPLE_HDR_LENGTH) {
- bcopy(icmp->icmp_ip_snd_options,
- &ipha[1], icmp->icmp_ip_snd_options_len);
+ bcopy(ip_snd_opt,
+ &ipha[1], ip_snd_opt_len);
/*
* Massage source route putting first source route in ipha_dst.
* Ignore the destination in the T_unitdata_req.
@@ -4729,7 +4856,9 @@
(void) ip_massage_options(ipha, is->is_netstack);
}
+ rw_exit(&icmp->icmp_rwlock);
BUMP_MIB(&is->is_rawip_mib, rawipOutDatagrams);
+
ip_output_options(connp, mp, q, IP_WPUT, &optinfo);
return (0);
}
@@ -4741,7 +4870,9 @@
uchar_t opt_storage[TSOL_MAX_IPV6_OPTION];
icmp_stack_t *is = icmp->icmp_is;
conn_t *connp = icmp->icmp_connp;
- cred_t *cr;
+ cred_t *cred;
+ cred_t *msg_cred;
+ cred_t *effective_cred;
/*
* All Solaris components should pass a db_credp
@@ -4749,18 +4880,62 @@
* On production kernels we return an error to be robust against
* random streams modules sitting on top of us.
*/
- cr = msg_getcred(mp, NULL);
- ASSERT(cr != NULL);
- if (cr == NULL)
+ cred = msg_cred = msg_getcred(mp, NULL);
+ ASSERT(cred != NULL);
+ if (cred == NULL)
return (EINVAL);
- err = tsol_compute_label_v6(cr, dst,
- opt_storage, connp->conn_mac_exempt,
- is->is_netstack->netstack_ip);
- if (err == 0) {
- err = tsol_update_sticky(&icmp->icmp_sticky_ipp,
- &icmp->icmp_label_len_v6, opt_storage);
+ /*
+ * Verify the destination is allowed to receive packets at
+ * the security label of the message data. check_dest()
+ * may create a new effective cred for this message
+ * with a modified label or label flags.
+ */
+ if ((err = tsol_check_dest(cred, dst, IPV6_VERSION,
+ connp->conn_mac_exempt, &effective_cred)) != 0)
+ goto done;
+ if (effective_cred != NULL)
+ cred = effective_cred;
+
+ /*
+ * Calculate the security label to be placed in the text
+ * of the message (if any).
+ */
+ if ((err = tsol_compute_label_v6(cred, dst, opt_storage,
+ is->is_netstack->netstack_ip)) != 0)
+ goto done;
+
+ /*
+ * Insert the security label in the cached ip options,
+ * removing any old label that may exist.
+ */
+ if ((err = tsol_update_sticky(&icmp->icmp_sticky_ipp,
+ &icmp->icmp_label_len_v6, opt_storage)) != 0)
+ goto done;
+
+ /*
+ * Save the destination address and cred we used to generate
+ * the security label text.
+ */
+ icmp->icmp_v6lastdst = *dst;
+ if (cred != icmp->icmp_effective_cred) {
+ if (icmp->icmp_effective_cred != NULL)
+ crfree(icmp->icmp_effective_cred);
+ crhold(cred);
+ icmp->icmp_effective_cred = cred;
}
+
+ if (msg_cred != icmp->icmp_last_cred) {
+ if (icmp->icmp_last_cred != NULL)
+ crfree(icmp->icmp_last_cred);
+ crhold(msg_cred);
+ icmp->icmp_last_cred = msg_cred;
+ }
+
+done:
+ if (effective_cred != NULL)
+ crfree(effective_cred);
+
if (err != 0) {
BUMP_MIB(&is->is_rawip_mib, rawipOutErrors);
DTRACE_PROBE4(
@@ -4769,8 +4944,6 @@
icmp_t *, icmp, char *, opt_storage, mblk_t *, mp);
return (err);
}
-
- icmp->icmp_v6lastdst = *dst;
return (0);
}
@@ -4790,12 +4963,18 @@
icmp_t *icmp = connp->conn_icmp;
icmp_stack_t *is = icmp->icmp_is;
ip6_pkt_t *tipp;
+ ip6_hbh_t *hopoptsptr = NULL;
+ uint_t hopoptslen = 0;
uint32_t csum = 0;
uint_t ignore = 0;
uint_t option_exists = 0, is_sticky = 0;
uint8_t *cp;
uint8_t *nxthdr_ptr;
in6_addr_t ip6_dst;
+ pid_t cpid;
+ cred_t *cr;
+
+ rw_enter(&icmp->icmp_rwlock, RW_READER);
/*
* If the local address is a mapped address return
@@ -4806,6 +4985,7 @@
*/
if (IN6_IS_ADDR_V4MAPPED(&icmp->icmp_v6src)) {
BUMP_MIB(&is->is_rawip_mib, rawipOutErrors);
+ rw_exit(&icmp->icmp_rwlock);
return (EADDRNOTAVAIL);
}
@@ -4828,17 +5008,42 @@
ip6_dst = ipv6_loopback;
/*
- * If we're not going to the same destination as last time, then
- * recompute the label required. This is done in a separate routine to
- * avoid blowing up our stack here.
+ * Check if our saved options are valid; update if not.
+ * TSOL Note: Since we are not in WRITER mode, ICMP packets
+ * to different destination may require different labels,
+ * or worse, ICMP packets to same IP address may require
+ * different labels due to use of shared all-zones address.
+ * We use conn_lock to ensure that lastdst, sticky ipp_hopopts,
+ * and sticky ipp_hopoptslen are consistent for the current
+ * destination and are updated atomically.
*/
- if (is_system_labeled() &&
- !IN6_ARE_ADDR_EQUAL(&icmp->icmp_v6lastdst, &ip6_dst)) {
- int error = 0;
+ mutex_enter(&connp->conn_lock);
+ if (is_system_labeled()) {
+ /*
+ * Recompute the Trusted Extensions security label if we're
+ * not going to the same destination as last time or the cred
+ * attached to the received mblk changed. This is done in a
+ * separate routine to avoid blowing up our stack here.
+ */
+ cr = msg_getcred(mp, &cpid);
+ if (!IN6_ARE_ADDR_EQUAL(&icmp->icmp_v6lastdst, &ip6_dst) ||
+ cr != icmp->icmp_last_cred) {
+ int error = 0;
+ error = icmp_update_label_v6(icmp, mp, &ip6_dst);
+ if (error != 0) {
+ mutex_exit(&connp->conn_lock);
+ rw_exit(&icmp->icmp_rwlock);
+ return (error);
+ }
+ }
- error = icmp_update_label_v6(icmp, mp, &ip6_dst);
- if (error != 0)
- return (error);
+ /*
+ * Apply credentials with modified security label if they exist.
+ * icmp_update_label_v6() may have generated these credentials
+ * for MAC-Exempt connections.
+ */
+ if (icmp->icmp_effective_cred != NULL)
+ mblk_setcred(mp, icmp->icmp_effective_cred, cpid);
}
/*
@@ -4854,6 +5059,7 @@
if ((icmp->icmp_sticky_ipp.ipp_fields == 0) &&
(ipp->ipp_fields == 0)) {
/* No sticky options nor ancillary data. */
+ mutex_exit(&connp->conn_lock);
goto no_options;
}
@@ -4870,9 +5076,21 @@
} else if (icmp->icmp_sticky_ipp.ipp_fields & IPPF_HOPOPTS) {
option_exists |= IPPF_HOPOPTS;
is_sticky |= IPPF_HOPOPTS;
- ip_hdr_len += icmp->icmp_sticky_ipp.ipp_hopoptslen;
+ ASSERT(icmp->icmp_sticky_ipp.ipp_hopoptslen != 0);
+ hopoptsptr = kmem_alloc(
+ icmp->icmp_sticky_ipp.ipp_hopoptslen, KM_NOSLEEP);
+ if (hopoptsptr == NULL) {
+ mutex_exit(&connp->conn_lock);
+ rw_exit(&icmp->icmp_rwlock);
+ return (ENOMEM);
+ }
+ hopoptslen = icmp->icmp_sticky_ipp.ipp_hopoptslen;
+ bcopy(icmp->icmp_sticky_ipp.ipp_hopopts, hopoptsptr,
+ hopoptslen);
+ ip_hdr_len += hopoptslen;
}
}
+ mutex_exit(&connp->conn_lock);
if (!(ignore & IPPF_RTHDR)) {
if (ipp->ipp_fields & IPPF_RTHDR) {
@@ -5022,6 +5240,8 @@
mp1 = allocb(ip_hdr_len + is->is_wroff_extra, BPRI_LO);
if (!mp1) {
BUMP_MIB(&is->is_rawip_mib, rawipOutErrors);
+ kmem_free(hopoptsptr, hopoptslen);
+ rw_exit(&icmp->icmp_rwlock);
return (ENOMEM);
}
mp1->b_cont = mp;
@@ -5138,13 +5358,19 @@
if (option_exists & IPPF_HOPOPTS) {
/* Hop-by-hop options */
ip6_hbh_t *hbh = (ip6_hbh_t *)cp;
- tipp = ANCIL_OR_STICKY_PTR(IPPF_HOPOPTS);
*nxthdr_ptr = IPPROTO_HOPOPTS;
nxthdr_ptr = &hbh->ip6h_nxt;
- bcopy(tipp->ipp_hopopts, cp, tipp->ipp_hopoptslen);
- cp += tipp->ipp_hopoptslen;
+ if (hopoptslen == 0) {
+ tipp = ANCIL_OR_STICKY_PTR(IPPF_HOPOPTS);
+ bcopy(tipp->ipp_hopopts, cp, tipp->ipp_hopoptslen);
+ cp += tipp->ipp_hopoptslen;
+ } else {
+ bcopy(hopoptsptr, cp, hopoptslen);
+ cp += hopoptslen;
+ kmem_free(hopoptsptr, hopoptslen);
+ }
}
/*
* En-route destination options
@@ -5224,6 +5450,7 @@
*/
BUMP_MIB(&is->is_rawip_mib,
rawipOutErrors);
+ rw_exit(&icmp->icmp_rwlock);
return (EPROTO);
}
/*
@@ -5233,6 +5460,7 @@
if (rth->ip6r_len & 0x1) {
BUMP_MIB(&is->is_rawip_mib,
rawipOutErrors);
+ rw_exit(&icmp->icmp_rwlock);
return (EPROTO);
}
/*
@@ -5251,6 +5479,7 @@
if (IN6_IS_ADDR_V4MAPPED(&ip6h->ip6_dst)) {
BUMP_MIB(&is->is_rawip_mib,
rawipOutErrors);
+ rw_exit(&icmp->icmp_rwlock);
return (EADDRNOTAVAIL);
}
}
@@ -5268,6 +5497,7 @@
*/
if (ip_len > IP_MAXPACKET) {
BUMP_MIB(&is->is_rawip_mib, rawipOutErrors);
+ rw_exit(&icmp->icmp_rwlock);
return (EMSGSIZE);
}
if (icmp->icmp_proto == IPPROTO_ICMPV6 || icmp->icmp_raw_checksum) {
@@ -5292,6 +5522,7 @@
BUMP_MIB(&is->is_rawip_mib,
rawipOutErrors);
freemsg(mp);
+ rw_exit(&icmp->icmp_rwlock);
return (0);
}
ip6i = (ip6i_t *)mp->b_rptr;
@@ -5316,6 +5547,7 @@
ip6h->ip6_plen = (uint16_t)ip_len;
/* We're done. Pass the packet to IP */
+ rw_exit(&icmp->icmp_rwlock);
BUMP_MIB(&is->is_rawip_mib, rawipOutDatagrams);
ip_output_v6(icmp->icmp_connp, mp, q, IP_WPUT);
return (0);
diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c
index 799e9bb..c6f52e3 100644
--- a/usr/src/uts/common/inet/ip/ip.c
+++ b/usr/src/uts/common/inet/ip/ip.c
@@ -4309,18 +4309,19 @@
/*
* Used to determine the most accurate cred_t to use for TX.
* First priority is SCM_UCRED having set the label in the message,
- * which is used for MLP on UDP. Second priority is the peers label (aka
- * conn_peercred), which is needed for MLP on TCP/SCTP. Last priority is the
- * open credentials.
+ * which is used for MLP on UDP. Second priority is the open credentials
+ * with the peer's label (aka conn_effective_cred), which is needed for
+ * MLP on TCP/SCTP and for MAC-Exempt. Last priority is the open credentials.
*/
cred_t *
-ip_best_cred(mblk_t *mp, conn_t *connp)
+ip_best_cred(mblk_t *mp, conn_t *connp, pid_t *pidp)
{
cred_t *cr;
- cr = msg_getcred(mp, NULL);
+ cr = msg_getcred(mp, pidp);
if (cr != NULL && crgetlabel(cr) != NULL)
return (cr);
+ *pidp = NOPID;
return (CONN_CRED(connp));
}
@@ -4809,6 +4810,7 @@
boolean_t ire_requested = B_FALSE;
boolean_t ipsec_policy_set = B_FALSE;
ts_label_t *tsl = NULL;
+ cred_t *effective_cred = NULL;
if (mpp)
mp = *mpp;
@@ -4817,8 +4819,6 @@
ire_requested = (DB_TYPE(mp) == IRE_DB_REQ_TYPE);
ipsec_policy_set = (DB_TYPE(mp) == IPSEC_POLICY_SET);
}
- if (cr != NULL)
- tsl = crgetlabel(cr);
src_ire = dst_ire = NULL;
@@ -4829,6 +4829,44 @@
zoneid = IPCL_ZONEID(connp);
+ /*
+ * Check whether Trusted Solaris policy allows communication with this
+ * host, and pretend that the destination is unreachable if not.
+ *
+ * This is never a problem for TCP, since that transport is known to
+ * compute the label properly as part of the tcp_rput_other T_BIND_ACK
+ * handling. If the remote is unreachable, it will be detected at that
+ * point, so there's no reason to check it here.
+ *
+ * Note that for sendto (and other datagram-oriented friends), this
+ * check is done as part of the data path label computation instead.
+ * The check here is just to make non-TCP connect() report the right
+ * error.
+ */
+ if (is_system_labeled() && !IPCL_IS_TCP(connp)) {
+ if ((error = tsol_check_dest(cr, &dst_addr, IPV4_VERSION,
+ connp->conn_mac_exempt, &effective_cred)) != 0) {
+ if (ip_debug > 2) {
+ pr_addr_dbg(
+ "ip_bind_connected_v4:"
+ " no label for dst %s\n",
+ AF_INET, &dst_addr);
+ }
+ goto bad_addr;
+ }
+
+ /*
+ * tsol_check_dest() may have created a new cred with
+ * a modified security label. Use that cred if it exists
+ * for ire lookups.
+ */
+ if (effective_cred == NULL) {
+ tsl = crgetlabel(cr);
+ } else {
+ tsl = crgetlabel(effective_cred);
+ }
+ }
+
if (CLASSD(dst_addr)) {
/* Pick up an IRE_BROADCAST */
dst_ire = ire_route_lookup(ip_g_all_ones, 0, 0, 0, NULL,
@@ -4904,34 +4942,6 @@
}
/*
- * We now know that routing will allow us to reach the destination.
- * Check whether Trusted Solaris policy allows communication with this
- * host, and pretend that the destination is unreachable if not.
- *
- * This is never a problem for TCP, since that transport is known to
- * compute the label properly as part of the tcp_rput_other T_BIND_ACK
- * handling. If the remote is unreachable, it will be detected at that
- * point, so there's no reason to check it here.
- *
- * Note that for sendto (and other datagram-oriented friends), this
- * check is done as part of the data path label computation instead.
- * The check here is just to make non-TCP connect() report the right
- * error.
- */
- if (dst_ire != NULL && is_system_labeled() &&
- !IPCL_IS_TCP(connp) &&
- tsol_compute_label(cr, dst_addr, NULL,
- connp->conn_mac_exempt, ipst) != 0) {
- error = EHOSTUNREACH;
- if (ip_debug > 2) {
- pr_addr_dbg("ip_bind_connected_v4:"
- " no label for dst %s\n",
- AF_INET, &dst_addr);
- }
- goto bad_addr;
- }
-
- /*
* If the app does a connect(), it means that it will most likely
* send more than 1 packet to the destination. It makes sense
* to clear the temporary flag.
@@ -5265,6 +5275,8 @@
IRE_REFRELE(md_dst_ire);
if (lso_dst_ire != NULL)
IRE_REFRELE(lso_dst_ire);
+ if (effective_cred != NULL)
+ crfree(effective_cred);
return (error);
}
@@ -7337,7 +7349,7 @@
while ((connp != NULL) &&
(!IPCL_UDP_MATCH(connp, dstport, dst, srcport, src) ||
(!IPCL_ZONE_MATCH(connp, zoneid) &&
- !(unlabeled && connp->conn_mac_exempt)))) {
+ !(unlabeled && connp->conn_mac_exempt && shared_addr)))) {
/*
* We keep searching since the conn did not match,
* or its zone did not match and it is not either
@@ -20474,7 +20486,7 @@
ipif_t *dst_ipif;
boolean_t multirt_need_resolve = B_FALSE;
mblk_t *copy_mp = NULL;
- int err;
+ int err = 0;
zoneid_t zoneid;
boolean_t need_decref = B_FALSE;
boolean_t ignore_dontroute = B_FALSE;
@@ -20559,8 +20571,12 @@
if (is_system_labeled() &&
(ipha->ipha_version_and_hdr_length & 0xf0) == (IPV4_VERSION << 4) &&
!connp->conn_ulp_labeled) {
- err = tsol_check_label(BEST_CRED(mp, connp), &mp,
- connp->conn_mac_exempt, ipst);
+ cred_t *credp;
+ pid_t pid;
+
+ credp = BEST_CRED(mp, connp, &pid);
+ err = tsol_check_label(credp, &mp,
+ connp->conn_mac_exempt, ipst, pid);
ipha = (ipha_t *)mp->b_rptr;
if (err != 0) {
first_mp = mp;
@@ -21044,17 +21060,26 @@
}
/* This function assumes that mp points to an IPv4 packet. */
- if (is_system_labeled() && q->q_next == NULL &&
+ if (is_system_labeled() &&
(*mp->b_rptr & 0xf0) == (IPV4_VERSION << 4) &&
- !connp->conn_ulp_labeled) {
- err = tsol_check_label(BEST_CRED(mp, connp), &mp,
- connp->conn_mac_exempt, ipst);
+ (connp == NULL || !connp->conn_ulp_labeled)) {
+ cred_t *credp;
+ pid_t pid;
+
+ if (connp != NULL) {
+ credp = BEST_CRED(mp, connp, &pid);
+ err = tsol_check_label(credp, &mp,
+ connp->conn_mac_exempt, ipst, pid);
+ } else if ((credp = msg_getcred(mp, &pid)) != NULL) {
+ err = tsol_check_label(credp, &mp,
+ B_FALSE, ipst, pid);
+ }
ipha = (ipha_t *)mp->b_rptr;
- if (first_mp != NULL)
+ if (mctl_present)
first_mp->b_cont = mp;
+ else
+ first_mp = mp;
if (err != 0) {
- if (first_mp == NULL)
- first_mp = mp;
if (err == EINVAL)
goto icmp_parameter_problem;
ip2dbg(("ip_wput: label check failed (%d)\n",
diff --git a/usr/src/uts/common/inet/ip/ip6.c b/usr/src/uts/common/inet/ip/ip6.c
index 1f73209..d50e84d 100644
--- a/usr/src/uts/common/inet/ip/ip6.c
+++ b/usr/src/uts/common/inet/ip/ip6.c
@@ -2458,6 +2458,7 @@
boolean_t ipsec_policy_set = B_FALSE;
ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
ts_label_t *tsl = NULL;
+ cred_t *effective_cred = NULL;
if (mpp)
mp = *mpp;
@@ -2466,8 +2467,6 @@
ire_requested = (DB_TYPE(mp) == IRE_DB_REQ_TYPE);
ipsec_policy_set = (DB_TYPE(mp) == IPSEC_POLICY_SET);
}
- if (cr != NULL)
- tsl = crgetlabel(cr);
src_ire = dst_ire = NULL;
/*
@@ -2477,6 +2476,43 @@
zoneid = connp->conn_zoneid;
+ /*
+ * Check whether Trusted Solaris policy allows communication with this
+ * host, and pretend that the destination is unreachable if not.
+ *
+ * This is never a problem for TCP, since that transport is known to
+ * compute the label properly as part of the tcp_rput_other T_BIND_ACK
+ * handling. If the remote is unreachable, it will be detected at that
+ * point, so there's no reason to check it here.
+ *
+ * Note that for sendto (and other datagram-oriented friends), this
+ * check is done as part of the data path label computation instead.
+ * The check here is just to make non-TCP connect() report the right
+ * error.
+ */
+ if (is_system_labeled() && !IPCL_IS_TCP(connp)) {
+ if ((error = tsol_check_dest(cr, v6dst, IPV6_VERSION,
+ connp->conn_mac_exempt, &effective_cred)) != 0) {
+ if (ip_debug > 2) {
+ pr_addr_dbg(
+ "ip_bind_connected: no label for dst %s\n",
+ AF_INET6, v6dst);
+ }
+ goto bad_addr;
+ }
+
+ /*
+ * tsol_check_dest() may have created a new cred with
+ * a modified security label. Use that cred if it exists
+ * for ire lookups.
+ */
+ if (effective_cred == NULL) {
+ tsl = crgetlabel(cr);
+ } else {
+ tsl = crgetlabel(effective_cred);
+ }
+ }
+
if (IN6_IS_ADDR_MULTICAST(v6dst)) {
ipif_t *ipif;
@@ -2554,33 +2590,6 @@
}
/*
- * We now know that routing will allow us to reach the destination.
- * Check whether Trusted Solaris policy allows communication with this
- * host, and pretend that the destination is unreachable if not.
- *
- * This is never a problem for TCP, since that transport is known to
- * compute the label properly as part of the tcp_rput_other T_BIND_ACK
- * handling. If the remote is unreachable, it will be detected at that
- * point, so there's no reason to check it here.
- *
- * Note that for sendto (and other datagram-oriented friends), this
- * check is done as part of the data path label computation instead.
- * The check here is just to make non-TCP connect() report the right
- * error.
- */
- if (dst_ire != NULL && is_system_labeled() &&
- !IPCL_IS_TCP(connp) &&
- tsol_compute_label_v6(cr, v6dst, NULL,
- connp->conn_mac_exempt, ipst) != 0) {
- error = EHOSTUNREACH;
- if (ip_debug > 2) {
- pr_addr_dbg("ip_bind_connected: no label for dst %s\n",
- AF_INET6, v6dst);
- }
- goto bad_addr;
- }
-
- /*
* If the app does a connect(), it means that it will most likely
* send more than 1 packet to the destination. It makes sense
* to clear the temporary flag.
@@ -2890,6 +2899,8 @@
IRE_REFRELE(md_dst_ire);
if (ill_held && dst_ill != NULL)
ill_refrele(dst_ill);
+ if (effective_cred != NULL)
+ crfree(effective_cred);
return (error);
}
@@ -9243,13 +9254,15 @@
if (is_system_labeled() && DB_TYPE(mp) == M_DATA &&
(connp == NULL || !connp->conn_ulp_labeled)) {
cred_t *cr;
+ pid_t pid;
if (connp != NULL) {
ASSERT(CONN_CRED(connp) != NULL);
- err = tsol_check_label_v6(BEST_CRED(mp, connp),
- &mp, connp->conn_mac_exempt, ipst);
- } else if ((cr = msg_getcred(mp, NULL)) != NULL) {
- err = tsol_check_label_v6(cr, &mp, B_FALSE, ipst);
+ cr = BEST_CRED(mp, connp, &pid);
+ err = tsol_check_label_v6(cr, &mp,
+ connp->conn_mac_exempt, ipst, pid);
+ } else if ((cr = msg_getcred(mp, &pid)) != NULL) {
+ err = tsol_check_label_v6(cr, &mp, B_FALSE, ipst, pid);
}
if (mctl_present)
first_mp->b_cont = mp;
diff --git a/usr/src/uts/common/inet/ip/ipclassifier.c b/usr/src/uts/common/inet/ip/ipclassifier.c
index 0aafd8e..031034e 100644
--- a/usr/src/uts/common/inet/ip/ipclassifier.c
+++ b/usr/src/uts/common/inet/ip/ipclassifier.c
@@ -672,9 +672,9 @@
DTRACE_PROBE1(conn__destroy, conn_t *, connp);
- if (connp->conn_peercred != NULL) {
- crfree(connp->conn_peercred);
- connp->conn_peercred = NULL;
+ if (connp->conn_effective_cred != NULL) {
+ crfree(connp->conn_effective_cred);
+ connp->conn_effective_cred = NULL;
}
if (connp->conn_cred != NULL) {
@@ -1094,6 +1094,9 @@
/* If neither is exempt, then there's no conflict */
if (!connp->conn_mac_exempt && !tconn->conn_mac_exempt)
continue;
+ /* We are only concerned about sockets for a different zone */
+ if (connp->conn_zoneid == tconn->conn_zoneid)
+ continue;
/* If both are bound to different specific addrs, ok */
if (connp->conn_src != INADDR_ANY &&
tconn->conn_src != INADDR_ANY &&
@@ -1122,6 +1125,9 @@
/* If neither is exempt, then there's no conflict */
if (!connp->conn_mac_exempt && !tconn->conn_mac_exempt)
continue;
+ /* We are only concerned about sockets for a different zone */
+ if (connp->conn_zoneid == tconn->conn_zoneid)
+ continue;
/* If both are bound to different addrs, ok */
if (!IN6_IS_ADDR_UNSPECIFIED(&connp->conn_srcv6) &&
!IN6_IS_ADDR_UNSPECIFIED(&tconn->conn_srcv6) &&
@@ -1604,7 +1610,8 @@
connp = connp->conn_next) {
if (IPCL_BIND_MATCH(connp, protocol, ipha->ipha_dst,
lport) && (IPCL_ZONE_MATCH(connp, zoneid) ||
- (unlabeled && connp->conn_mac_exempt)))
+ (unlabeled && connp->conn_mac_exempt &&
+ shared_addr)))
break;
}
@@ -1680,7 +1687,8 @@
if (IPCL_UDP_MATCH(connp, lport, ipha->ipha_dst,
fport, ipha->ipha_src) &&
(IPCL_ZONE_MATCH(connp, zoneid) ||
- (unlabeled && connp->conn_mac_exempt)))
+ (unlabeled && connp->conn_mac_exempt &&
+ shared_addr)))
break;
}
@@ -1803,7 +1811,8 @@
if (IPCL_BIND_MATCH_V6(connp, protocol,
ip6h->ip6_dst, lport) &&
(IPCL_ZONE_MATCH(connp, zoneid) ||
- (unlabeled && connp->conn_mac_exempt)))
+ (unlabeled && connp->conn_mac_exempt &&
+ shared_addr)))
break;
}
@@ -1878,7 +1887,8 @@
if (IPCL_UDP_MATCH_V6(connp, lport, ip6h->ip6_dst,
fport, ip6h->ip6_src) &&
(IPCL_ZONE_MATCH(connp, zoneid) ||
- (unlabeled && connp->conn_mac_exempt)))
+ (unlabeled && connp->conn_mac_exempt &&
+ shared_addr)))
break;
}
@@ -2020,7 +2030,7 @@
}
if (IPCL_ZONE_MATCH(connp, zoneid) ||
- (unlabeled && connp->conn_mac_exempt))
+ (unlabeled && connp->conn_mac_exempt && shared_addr))
break;
}
/*
@@ -2342,7 +2352,7 @@
ASSERT(connp->conn_idl == NULL);
#endif
ASSERT(connp->conn_ipsec_opt_mp == NULL);
- ASSERT(connp->conn_peercred == NULL);
+ ASSERT(connp->conn_effective_cred == NULL);
ASSERT(connp->conn_netstack == NULL);
ASSERT(connp->conn_helper_info == NULL);
diff --git a/usr/src/uts/common/inet/ip/ipsecah.c b/usr/src/uts/common/inet/ip/ipsecah.c
index 7782f62..3409ab0 100644
--- a/usr/src/uts/common/inet/ip/ipsecah.c
+++ b/usr/src/uts/common/inet/ip/ipsecah.c
@@ -4235,9 +4235,10 @@
*dest = *(dest - newpos);
}
/*
- * The db_credp should be in mp (if needed) and never in phdr_mp
+ * If a db_credp exists in phdr_mp, it must also exist in mp.
*/
- ASSERT(msg_getcred(phdr_mp, NULL) == NULL);
+ ASSERT(DB_CRED(phdr_mp) == NULL ||
+ msg_getcred(mp, NULL) != NULL);
freeb(phdr_mp);
ipsec_in->b_cont = mp;
diff --git a/usr/src/uts/common/inet/ip/tn_ipopt.c b/usr/src/uts/common/inet/ip/tn_ipopt.c
index c187c8c..cf3bdbe 100644
--- a/usr/src/uts/common/inet/ip/tn_ipopt.c
+++ b/usr/src/uts/common/inet/ip/tn_ipopt.c
@@ -186,6 +186,176 @@
}
/*
+ * tsol_check_dest()
+ *
+ * This routine verifies if a destination is allowed to recieve messages
+ * based on the message cred's security label. If any adjustments to
+ * the cred are needed due to the connection's MAC-exempt status or
+ * the destination's ability to receive labels, an "effective cred"
+ * will be returned.
+ *
+ * On successful return, effective_cred will point to the new creds needed
+ * or will be NULL if new creds aren't needed. On error, effective_cred
+ * is NULL.
+ *
+ * Returns:
+ * 0 Have or constructed appropriate credentials
+ * EHOSTUNREACH The credentials failed the remote host accreditation
+ * ENOMEM Memory allocation failure
+ */
+int
+tsol_check_dest(const cred_t *credp, const void *dst, uchar_t version,
+ boolean_t mac_exempt, cred_t **effective_cred)
+{
+ ts_label_t *tsl, *newtsl = NULL;
+ tsol_tpc_t *dst_rhtp;
+ zoneid_t zoneid;
+
+ *effective_cred = NULL;
+ ASSERT(version == IPV4_VERSION ||
+ (version == IPV6_VERSION &&
+ !IN6_IS_ADDR_V4MAPPED((in6_addr_t *)dst)));
+
+ /* Always pass kernel level communication (NULL label) */
+ if ((tsl = crgetlabel(credp)) == NULL) {
+ DTRACE_PROBE2(tx__tnopt__log__info__labeling__mac__allownull,
+ char *, "destination ip(1) with null cred was passed",
+ ipaddr_t, dst);
+ return (0);
+ }
+
+ /* Always pass multicast */
+ if (version == IPV4_VERSION &&
+ CLASSD(*(ipaddr_t *)dst)) {
+ DTRACE_PROBE2(tx__tnopt__log__info__labeling__mac__allowmult,
+ char *, "destination ip(1) with multicast dest was passed",
+ ipaddr_t, dst);
+ return (0);
+ } else if (version == IPV6_VERSION &&
+ IN6_IS_ADDR_MULTICAST((in6_addr_t *)dst)) {
+ DTRACE_PROBE2(tx__tnopt__log__info__labeling__mac__allowmult_v6,
+ char *, "destination ip(1) with multicast dest was passed",
+ in6_addr_t *, dst);
+ return (0);
+ }
+
+ /* Never pass an undefined destination */
+ if ((dst_rhtp = find_tpc(dst, version, B_FALSE)) == NULL) {
+ DTRACE_PROBE2(tx__tnopt__log__info__labeling__lookupdst,
+ char *, "destination ip(1) not in tn database.",
+ void *, dst);
+ return (EHOSTUNREACH);
+ }
+
+ switch (dst_rhtp->tpc_tp.host_type) {
+ case UNLABELED:
+ /*
+ * Can talk to unlabeled hosts if
+ * (1) zone's label matches the default label, or
+ * (2) SO_MAC_EXEMPT is on and we dominate the peer's label
+ * (3) SO_MAC_EXEMPT is on and this is the global zone
+ */
+ if (dst_rhtp->tpc_tp.tp_doi != tsl->tsl_doi) {
+ DTRACE_PROBE4(tx__tnopt__log__info__labeling__doi,
+ char *, "unlabeled dest ip(1)/tpc(2) doi does "
+ "not match msg label(3) doi.", void *, dst,
+ tsol_tpc_t *, dst_rhtp, ts_label_t *, tsl);
+ TPC_RELE(dst_rhtp);
+ return (EHOSTUNREACH);
+ }
+ if (!blequal(&dst_rhtp->tpc_tp.tp_def_label,
+ &tsl->tsl_label)) {
+ zoneid = crgetzoneid(credp);
+ if (!mac_exempt ||
+ !(zoneid == GLOBAL_ZONEID ||
+ bldominates(&tsl->tsl_label,
+ &dst_rhtp->tpc_tp.tp_def_label))) {
+ DTRACE_PROBE4(
+ tx__tnopt__log__info__labeling__mac,
+ char *, "unlabeled dest ip(1)/tpc(2) does "
+ "not match msg label(3).", void *, dst,
+ tsol_tpc_t *, dst_rhtp, ts_label_t *, tsl);
+ TPC_RELE(dst_rhtp);
+ return (EHOSTUNREACH);
+ }
+ /*
+ * This is a downlabel MAC-exempt exchange.
+ * Use the remote destination's default label
+ * as the label of the message data.
+ */
+ if ((newtsl = labelalloc(&dst_rhtp->tpc_tp.tp_def_label,
+ dst_rhtp->tpc_tp.tp_doi, KM_NOSLEEP)) == NULL) {
+ TPC_RELE(dst_rhtp);
+ return (ENOMEM);
+ }
+ newtsl->tsl_flags |= TSLF_UNLABELED;
+
+ } else if (!(tsl->tsl_flags & TSLF_UNLABELED)) {
+ /*
+ * The security labels are the same but we need
+ * to flag that the remote node is unlabeled.
+ */
+ if ((newtsl = labeldup(tsl, KM_NOSLEEP)) == NULL) {
+ TPC_RELE(dst_rhtp);
+ return (ENOMEM);
+ }
+ newtsl->tsl_flags |= TSLF_UNLABELED;
+ }
+ break;
+
+ case SUN_CIPSO:
+ /*
+ * Can talk to labeled hosts if zone's label is within target's
+ * label range or set.
+ */
+ if (dst_rhtp->tpc_tp.tp_cipso_doi_cipso != tsl->tsl_doi ||
+ (!_blinrange(&tsl->tsl_label,
+ &dst_rhtp->tpc_tp.tp_sl_range_cipso) &&
+ !blinlset(&tsl->tsl_label,
+ dst_rhtp->tpc_tp.tp_sl_set_cipso))) {
+ DTRACE_PROBE4(tx__tnopt__log__info__labeling__mac,
+ char *, "labeled dest ip(1)/tpc(2) does not "
+ "match msg label(3).", void *, dst,
+ tsol_tpc_t *, dst_rhtp, ts_label_t *, tsl);
+ TPC_RELE(dst_rhtp);
+ return (EHOSTUNREACH);
+ }
+ if (tsl->tsl_flags & TSLF_UNLABELED) {
+ /*
+ * The security label is a match but we need to
+ * clear the unlabeled flag for this remote node.
+ */
+ if ((newtsl = labeldup(tsl, KM_NOSLEEP)) == NULL) {
+ TPC_RELE(dst_rhtp);
+ return (ENOMEM);
+ }
+ newtsl->tsl_flags ^= TSLF_UNLABELED;
+ }
+ break;
+
+ default:
+ TPC_RELE(dst_rhtp);
+ return (EHOSTUNREACH);
+ }
+
+ /*
+ * Generate a new cred if we modified the security label or
+ * label flags.
+ */
+ if (newtsl != NULL) {
+ *effective_cred = copycred_from_tslabel(credp,
+ newtsl, KM_NOSLEEP);
+ label_rele(newtsl);
+ if (*effective_cred == NULL) {
+ TPC_RELE(dst_rhtp);
+ return (ENOMEM);
+ }
+ }
+ TPC_RELE(dst_rhtp);
+ return (0);
+}
+
+/*
* tsol_compute_label()
*
* This routine computes the IP label that should be on a packet based on the
@@ -193,19 +363,16 @@
*
* Returns:
* 0 Fetched label
- * EACCES The packet failed the remote host accreditation
- * ENOMEM Memory allocation failure
+ * EHOSTUNREACH No route to destination
* EINVAL Label cannot be computed
*/
int
tsol_compute_label(const cred_t *credp, ipaddr_t dst, uchar_t *opt_storage,
- boolean_t isexempt, ip_stack_t *ipst)
+ ip_stack_t *ipst)
{
uint_t sec_opt_len;
ts_label_t *tsl;
- tsol_tpc_t *dst_rhtp;
ire_t *ire, *sire = NULL;
- boolean_t compute_label = B_FALSE;
tsol_ire_gw_secattr_t *attrp;
zoneid_t zoneid, ip_zoneid;
@@ -221,38 +388,29 @@
if (CLASSD(dst))
return (0);
- if ((dst_rhtp = find_tpc(&dst, IPV4_VERSION, B_FALSE)) == NULL) {
- DTRACE_PROBE3(tx__tnopt__log__info__labeling__lookupdst__v4,
- char *, "destination ip(1) not in database (with creds(2))",
- ipaddr_t, dst, cred_t *, credp);
- return (EINVAL);
- }
+ if (tsl->tsl_flags & TSLF_UNLABELED) {
- zoneid = crgetzoneid(credp);
-
- /*
- * For exclusive stacks we set the zoneid to zero
- * to operate as if in the global zone for IRE and conn_t comparisons.
- */
- if (ipst->ips_netstack->netstack_stackid != GLOBAL_NETSTACKID)
- ip_zoneid = GLOBAL_ZONEID;
- else
- ip_zoneid = zoneid;
-
- switch (dst_rhtp->tpc_tp.host_type) {
- case UNLABELED:
/*
- * Only add a label if the unlabeled destination is
- * not broadcast/local/loopback address, that it is
- * not on the same subnet, and that the next-hop
- * gateway is labeled.
+ * The destination is unlabeled. Only add a label if the
+ * destination is not a broadcast/local/loopback address,
+ * the destination is not on the same subnet, and the
+ * next-hop gateway is labeled.
+ *
+ * For exclusive stacks we set the zoneid to zero
+ * to operate as if we are in the global zone for
+ * IRE lookups.
*/
+ zoneid = crgetzoneid(credp);
+ if (ipst->ips_netstack->netstack_stackid != GLOBAL_NETSTACKID)
+ ip_zoneid = GLOBAL_ZONEID;
+ else
+ ip_zoneid = zoneid;
+
ire = ire_cache_lookup(dst, ip_zoneid, tsl, ipst);
if (ire != NULL && (ire->ire_type & (IRE_BROADCAST | IRE_LOCAL |
IRE_LOOPBACK | IRE_INTERFACE)) != 0) {
IRE_REFRELE(ire);
- TPC_RELE(dst_rhtp);
return (0);
} else if (ire == NULL) {
ire = ire_ftable_lookup(dst, 0, 0, 0, NULL, &sire,
@@ -262,13 +420,11 @@
/* no route to destination */
if (ire == NULL) {
- DTRACE_PROBE4(
+ DTRACE_PROBE3(
tx__tnopt__log__info__labeling__routedst__v4,
- char *, "No route to unlabeled dest ip(1)/tpc(2) "
- "with creds(3).", ipaddr_t, dst, tsol_tpc_t *,
- dst_rhtp, cred_t *, credp);
- TPC_RELE(dst_rhtp);
- return (EINVAL);
+ char *, "No route to unlabeled dest ip(1) with "
+ "creds(2).", ipaddr_t, dst, cred_t *, credp);
+ return (EHOSTUNREACH);
}
/*
@@ -281,78 +437,29 @@
ire = sire;
}
- attrp = ire->ire_gw_secattr;
- if (attrp != NULL && attrp->igsa_rhc != NULL &&
- attrp->igsa_rhc->rhc_tpc->tpc_tp.host_type != UNLABELED)
- compute_label = B_TRUE;
-
/*
- * Can talk to unlabeled hosts if
- * (1) zone's label matches the default label, or
- * (2) SO_MAC_EXEMPT is on and we dominate the peer's label
- * (3) SO_MAC_EXEMPT is on and this is the global zone
+ * Return now if next hop gateway is unlabeled. There is
+ * no need to generate a CIPSO option for this message.
*/
- if (dst_rhtp->tpc_tp.tp_doi != tsl->tsl_doi ||
- (!blequal(&dst_rhtp->tpc_tp.tp_def_label,
- &tsl->tsl_label) && (!isexempt ||
- (zoneid != GLOBAL_ZONEID && !bldominates(&tsl->tsl_label,
- &dst_rhtp->tpc_tp.tp_def_label))))) {
- DTRACE_PROBE4(tx__tnopt__log__info__labeling__mac__v4,
- char *, "unlabeled dest ip(1)/tpc(2) "
- "non-matching creds(3).", ipaddr_t, dst,
- tsol_tpc_t *, dst_rhtp, cred_t *, credp);
+ attrp = ire->ire_gw_secattr;
+ if (attrp == NULL || attrp->igsa_rhc == NULL ||
+ attrp->igsa_rhc->rhc_tpc->tpc_tp.host_type == UNLABELED) {
IRE_REFRELE(ire);
- TPC_RELE(dst_rhtp);
- return (EACCES);
+ return (0);
}
IRE_REFRELE(ire);
- break;
- case SUN_CIPSO:
- /*
- * Can talk to labeled hosts if zone's label is within target's
- * label range or set.
- */
- if (dst_rhtp->tpc_tp.tp_cipso_doi_cipso != tsl->tsl_doi ||
- (!_blinrange(&tsl->tsl_label,
- &dst_rhtp->tpc_tp.tp_sl_range_cipso) &&
- !blinlset(&tsl->tsl_label,
- dst_rhtp->tpc_tp.tp_sl_set_cipso))) {
- DTRACE_PROBE4(tx__tnopt__log__info__labeling__mac__v4,
- char *, "labeled dest ip(1)/tpc(2) "
- "non-matching creds(3).", ipaddr_t, dst,
- tsol_tpc_t *, dst_rhtp, cred_t *, credp);
- TPC_RELE(dst_rhtp);
- return (EACCES);
- }
- compute_label = B_TRUE;
- break;
-
- default:
- TPC_RELE(dst_rhtp);
- return (EACCES);
- }
-
- if (!compute_label) {
- TPC_RELE(dst_rhtp);
- return (0);
}
/* compute the CIPSO option */
- if (dst_rhtp->tpc_tp.host_type != UNLABELED)
- sec_opt_len = tsol2cipso_tt1(&tsl->tsl_label, opt_storage,
- tsl->tsl_doi);
- else
- sec_opt_len = tsol2cipso_tt1(&dst_rhtp->tpc_tp.tp_def_label,
- opt_storage, tsl->tsl_doi);
- TPC_RELE(dst_rhtp);
+ sec_opt_len = tsol2cipso_tt1(&tsl->tsl_label, opt_storage,
+ tsl->tsl_doi);
if (sec_opt_len == 0) {
- DTRACE_PROBE4(tx__tnopt__log__error__labeling__lostops__v4,
- char *,
- "options lack length for dest ip(1)/tpc(2) with creds(3).",
- ipaddr_t, dst, tsol_tpc_t *, dst_rhtp, cred_t *, credp);
+ DTRACE_PROBE3(tx__tnopt__log__error__labeling__lostops__v4,
+ char *, "options lack length for dest ip(1) with creds(2).",
+ ipaddr_t, dst, cred_t *, credp);
return (EINVAL);
}
@@ -616,10 +723,11 @@
*/
int
tsol_check_label(const cred_t *credp, mblk_t **mpp, boolean_t isexempt,
- ip_stack_t *ipst)
+ ip_stack_t *ipst, pid_t pid)
{
mblk_t *mp = *mpp;
ipha_t *ipha;
+ cred_t *effective_cred = NULL;
uchar_t opt_storage[IP_MAX_OPT_LENGTH];
uint_t hlen;
uint_t sec_opt_len;
@@ -631,11 +739,37 @@
ipha = (ipha_t *)mp->b_rptr;
- retv = tsol_compute_label(credp, ipha->ipha_dst, opt_storage, isexempt,
- ipst);
+ /*
+ * Verify the destination is allowed to receive packets at
+ * the security label of the message data. check_dest()
+ * may create a new effective cred with a modified label
+ * or label flags. Apply any such cred to the message block
+ * for use in future routing decisions.
+ */
+ retv = tsol_check_dest(credp, &ipha->ipha_dst, IPV4_VERSION,
+ isexempt, &effective_cred);
if (retv != 0)
return (retv);
+ /*
+ * Calculate the security label to be placed in the text
+ * of the message (if any).
+ */
+ if (effective_cred != NULL) {
+ if ((retv = tsol_compute_label(effective_cred,
+ ipha->ipha_dst, opt_storage, ipst)) != 0) {
+ crfree(effective_cred);
+ return (retv);
+ }
+ mblk_setcred(mp, effective_cred, pid);
+ crfree(effective_cred);
+ } else {
+ if ((retv = tsol_compute_label(credp,
+ ipha->ipha_dst, opt_storage, ipst)) != 0) {
+ return (retv);
+ }
+ }
+
optr = (uchar_t *)(ipha + 1);
hlen = IPH_HDR_LENGTH(ipha) - IP_SIMPLE_HDR_LENGTH;
sec_opt_len = opt_storage[IPOPT_OLEN];
@@ -733,16 +867,14 @@
*/
int
tsol_compute_label_v6(const cred_t *credp, const in6_addr_t *dst,
- uchar_t *opt_storage, boolean_t isexempt, ip_stack_t *ipst)
+ uchar_t *opt_storage, ip_stack_t *ipst)
{
- tsol_tpc_t *dst_rhtp;
ts_label_t *tsl;
uint_t sec_opt_len;
uint32_t doi;
zoneid_t zoneid, ip_zoneid;
ire_t *ire, *sire;
tsol_ire_gw_secattr_t *attrp;
- boolean_t compute_label;
ASSERT(credp != NULL);
@@ -759,45 +891,35 @@
if (IN6_IS_ADDR_MULTICAST(dst))
return (0);
- if ((dst_rhtp = find_tpc(dst, IPV6_VERSION, B_FALSE)) == NULL) {
- DTRACE_PROBE3(tx__tnopt__log__info__labeling__lookupdst__v6,
- char *, "destination ip6(1) not in database with creds(2)",
- in6_addr_t *, dst, cred_t *, credp);
- return (EINVAL);
- }
-
zoneid = crgetzoneid(credp);
/*
- * For exclusive stacks we set the zoneid to zero
- * to operate as if in the global zone for IRE and conn_t comparisons.
- */
- if (ipst->ips_netstack->netstack_stackid != GLOBAL_NETSTACKID)
- ip_zoneid = GLOBAL_ZONEID;
- else
- ip_zoneid = zoneid;
-
- /*
* Fill in a V6 label. If a new format is added here, make certain
* that the maximum size of this label is reflected in sys/tsol/tnet.h
* as TSOL_MAX_IPV6_OPTION.
*/
- compute_label = B_FALSE;
- switch (dst_rhtp->tpc_tp.host_type) {
- case UNLABELED:
+ if (tsl->tsl_flags & TSLF_UNLABELED) {
/*
- * Only add a label if the unlabeled destination is
- * not local or loopback address, that it is
- * not on the same subnet, and that the next-hop
- * gateway is labeled.
+ * The destination is unlabeled. Only add a label if the
+ * destination is not broadcast/local/loopback address,
+ * the destination is not on the same subnet, and the
+ * next-hop gateway is labeled.
+ *
+ * For exclusive stacks we set the zoneid to zero to
+ * operate as if we are in the global zone when
+ * performing IRE lookups and conn_t comparisons.
*/
+ if (ipst->ips_netstack->netstack_stackid != GLOBAL_NETSTACKID)
+ ip_zoneid = GLOBAL_ZONEID;
+ else
+ ip_zoneid = zoneid;
+
sire = NULL;
ire = ire_cache_lookup_v6(dst, ip_zoneid, tsl, ipst);
if (ire != NULL && (ire->ire_type & (IRE_LOCAL |
IRE_LOOPBACK | IRE_INTERFACE)) != 0) {
IRE_REFRELE(ire);
- TPC_RELE(dst_rhtp);
return (0);
} else if (ire == NULL) {
ire = ire_ftable_lookup_v6(dst, NULL, NULL, 0, NULL,
@@ -807,13 +929,11 @@
/* no route to destination */
if (ire == NULL) {
- DTRACE_PROBE4(
+ DTRACE_PROBE3(
tx__tnopt__log__info__labeling__routedst__v6,
- char *, "No route to unlabeled dest ip6(1)/tpc(2) "
- "with creds(3).", in6_addr_t *, dst, tsol_tpc_t *,
- dst_rhtp, cred_t *, credp);
- TPC_RELE(dst_rhtp);
- return (EINVAL);
+ char *, "No route to unlabeled dest ip6(1) with "
+ "creds(2).", in6_addr_t *, dst, cred_t *, credp);
+ return (EHOSTUNREACH);
}
/*
@@ -826,72 +946,29 @@
ire = sire;
}
+ /*
+ * Return now if next hop gateway is unlabeled. There is
+ * no need to generate a CIPSO option for this message.
+ */
attrp = ire->ire_gw_secattr;
- if (attrp != NULL && attrp->igsa_rhc != NULL &&
- attrp->igsa_rhc->rhc_tpc->tpc_tp.host_type != UNLABELED)
- compute_label = B_TRUE;
-
- if (dst_rhtp->tpc_tp.tp_doi != tsl->tsl_doi ||
- (!blequal(&dst_rhtp->tpc_tp.tp_def_label,
- &tsl->tsl_label) && (!isexempt ||
- (zoneid != GLOBAL_ZONEID && !bldominates(&tsl->tsl_label,
- &dst_rhtp->tpc_tp.tp_def_label))))) {
- DTRACE_PROBE4(tx__tnopt__log__info__labeling__mac__v6,
- char *, "unlabeled dest ip6(1)/tpc(2) "
- "non-matching creds(3)", in6_addr_t *, dst,
- tsol_tpc_t *, dst_rhtp, cred_t *, credp);
+ if (attrp == NULL || attrp->igsa_rhc == NULL ||
+ attrp->igsa_rhc->rhc_tpc->tpc_tp.host_type == UNLABELED) {
IRE_REFRELE(ire);
- TPC_RELE(dst_rhtp);
- return (EACCES);
+ return (0);
}
-
IRE_REFRELE(ire);
- break;
-
- case SUN_CIPSO:
- if (dst_rhtp->tpc_tp.tp_cipso_doi_cipso != tsl->tsl_doi ||
- (!_blinrange(&tsl->tsl_label,
- &dst_rhtp->tpc_tp.tp_sl_range_cipso) &&
- !blinlset(&tsl->tsl_label,
- dst_rhtp->tpc_tp.tp_sl_set_cipso))) {
- DTRACE_PROBE4(tx__tnopt__log__info__labeling__mac__v6,
- char *,
- "labeled dest ip6(1)/tpc(2) non-matching creds(3).",
- in6_addr_t *, dst, tsol_tpc_t *, dst_rhtp,
- cred_t *, credp);
- TPC_RELE(dst_rhtp);
- return (EACCES);
- }
- compute_label = B_TRUE;
- break;
-
- default:
- TPC_RELE(dst_rhtp);
- return (EACCES);
- }
-
- if (!compute_label) {
- TPC_RELE(dst_rhtp);
- return (0);
}
/* compute the CIPSO option */
if (opt_storage != NULL)
opt_storage += 8;
- if (dst_rhtp->tpc_tp.host_type != UNLABELED) {
- sec_opt_len = tsol2cipso_tt1(&tsl->tsl_label, opt_storage,
- tsl->tsl_doi);
- } else {
- sec_opt_len = tsol2cipso_tt1(&dst_rhtp->tpc_tp.tp_def_label,
- opt_storage, tsl->tsl_doi);
- }
- TPC_RELE(dst_rhtp);
+ sec_opt_len = tsol2cipso_tt1(&tsl->tsl_label, opt_storage,
+ tsl->tsl_doi);
if (sec_opt_len == 0) {
- DTRACE_PROBE4(tx__tnopt__log__error__labeling__lostops__v6,
- char *,
- "options lack length for dest ip6(1)/tpc(2) with creds(3).",
- in6_addr_t *, dst, tsol_tpc_t *, dst_rhtp, cred_t *, credp);
+ DTRACE_PROBE3(tx__tnopt__log__error__labeling__lostops__v6,
+ char *, "options lack length for dest ip6(1) with "
+ "creds(2).", in6_addr_t *, dst, cred_t *, credp);
return (EINVAL);
}
@@ -1169,15 +1246,16 @@
*
* Returns:
* 0 Label on packet was already correct
- * EACCESS The packet failed the remote host accreditation.
+ * EACCES The packet failed the remote host accreditation.
* ENOMEM Memory allocation failure.
*/
int
tsol_check_label_v6(const cred_t *credp, mblk_t **mpp, boolean_t isexempt,
- ip_stack_t *ipst)
+ ip_stack_t *ipst, pid_t pid)
{
mblk_t *mp = *mpp;
ip6_t *ip6h;
+ cred_t *effective_cred;
/*
* Label option length is limited to IP_MAX_OPT_LENGTH for
* symmetry with IPv4. Can be relaxed if needed
@@ -1193,12 +1271,37 @@
uint_t hbhlen;
boolean_t hbh_needed;
+ /*
+ * Verify the destination is allowed to receive packets at
+ * the security label of the message data. check_dest()
+ * may create a new effective cred with a modified label
+ * or label flags. Apply any such cred to the message block
+ * for use in future routing decisions.
+ */
ip6h = (ip6_t *)mp->b_rptr;
- retv = tsol_compute_label_v6(credp, &ip6h->ip6_dst, opt_storage,
- isexempt, ipst);
+ retv = tsol_check_dest(credp, &ip6h->ip6_dst, IPV6_VERSION,
+ isexempt, &effective_cred);
if (retv != 0)
return (retv);
+ /*
+ * Calculate the security label to be placed in the text
+ * of the message (if any).
+ */
+ if (effective_cred != NULL) {
+ if ((retv = tsol_compute_label_v6(effective_cred,
+ &ip6h->ip6_dst, opt_storage, ipst)) != 0) {
+ crfree(effective_cred);
+ return (retv);
+ }
+ mblk_setcred(mp, effective_cred, pid);
+ crfree(effective_cred);
+ } else {
+ if ((retv = tsol_compute_label_v6(credp,
+ &ip6h->ip6_dst, opt_storage, ipst)) != 0)
+ return (retv);
+ }
+
sec_opt_len = opt_storage[1];
if (ip6h->ip6_nxt == IPPROTO_HOPOPTS) {
diff --git a/usr/src/uts/common/inet/ip/tnet.c b/usr/src/uts/common/inet/ip/tnet.c
index 4664e77..7dd3da3 100644
--- a/usr/src/uts/common/inet/ip/tnet.c
+++ b/usr/src/uts/common/inet/ip/tnet.c
@@ -687,6 +687,9 @@
ASSERT(DB_TYPE(mp) == M_DATA);
+ if (mp->b_cont != NULL && !pullupmsg(mp, -1))
+ return (B_FALSE);
+
if (version == IPV4_VERSION) {
ipha = (const ipha_t *)mp->b_rptr;
src = &ipha->ipha_src;
@@ -1477,6 +1480,7 @@
ipaddr_t *gw;
ip_stack_t *ipst = ire->ire_ipst;
cred_t *credp;
+ pid_t pid;
ASSERT(ire != NULL && mp != NULL);
ASSERT(ire->ire_stq != NULL);
@@ -1676,11 +1680,11 @@
goto keep_label;
- credp = msg_getcred(mp, NULL);
+ credp = msg_getcred(mp, &pid);
if ((af == AF_INET &&
- tsol_check_label(credp, &mp, B_FALSE, ipst) != 0) ||
+ tsol_check_label(credp, &mp, B_FALSE, ipst, pid) != 0) ||
(af == AF_INET6 &&
- tsol_check_label_v6(credp, &mp, B_FALSE, ipst) != 0)) {
+ tsol_check_label_v6(credp, &mp, B_FALSE, ipst, pid) != 0)) {
mp = NULL;
goto keep_label;
}
diff --git a/usr/src/uts/common/inet/ipclassifier.h b/usr/src/uts/common/inet/ipclassifier.h
index 7166899..67d1c74 100644
--- a/usr/src/uts/common/inet/ipclassifier.h
+++ b/usr/src/uts/common/inet/ipclassifier.h
@@ -316,7 +316,7 @@
in6_addr_t conn_nexthop_v6; /* nexthop IP address */
uchar_t conn_broadcast_ttl; /* IP_BROADCAST_TTL */
#define conn_nexthop_v4 V4_PART_OF_V6(conn_nexthop_v6)
- cred_t *conn_peercred; /* Peer TX label, if any */
+ cred_t *conn_effective_cred; /* Effective TX credentials */
int conn_rtaware; /* RT_AWARE sockopt value */
kcondvar_t conn_sq_cv; /* For non-STREAMS socket IO */
kthread_t *conn_sq_caller; /* Caller of squeue sync ops */
@@ -343,15 +343,15 @@
/*
* These two macros are used by TX. First priority is SCM_UCRED having
- * set the label in the mblk. Second priority is the peers label (aka
- * conn_peercred). Last priority is the open credentials.
- * BEST_CRED takes all three into account in the above order.
+ * set the label in the mblk. Second priority is the open credentials with
+ * peer's label (aka conn_effective_cred). Last priority is the open
+ * credentials. BEST_CRED takes all three into account in the above order.
* CONN_CRED is for connection-oriented cases when we don't need to look
* at the mblk.
*/
-#define CONN_CRED(connp) ((connp)->conn_peercred == NULL ? \
- (connp)->conn_cred : (connp)->conn_peercred)
-#define BEST_CRED(mp, connp) ip_best_cred(mp, connp)
+#define CONN_CRED(connp) ((connp)->conn_effective_cred == NULL ? \
+ (connp)->conn_cred : (connp)->conn_effective_cred)
+#define BEST_CRED(mp, connp, pidp) ip_best_cred(mp, connp, pidp)
/*
* connf_t - connection fanout data.
diff --git a/usr/src/uts/common/inet/mib2.h b/usr/src/uts/common/inet/mib2.h
index a467aba..9414004 100644
--- a/usr/src/uts/common/inet/mib2.h
+++ b/usr/src/uts/common/inet/mib2.h
@@ -950,6 +950,9 @@
#define MIB2_TMEF_PRIVATE 0x00000001 /* MLP on private addresses */
#define MIB2_TMEF_SHARED 0x00000002 /* MLP on shared addresses */
+#define MIB2_TMEF_ANONMLP 0x00000004 /* Anonymous MLP port */
+#define MIB2_TMEF_MACEXEMPT 0x00000008 /* MAC-Exempt port */
+#define MIB2_TMEF_IS_LABELED 0x00000010 /* tme_doi & tme_label exists */
/*
* List of IPv4 source addresses being filtered per interface
diff --git a/usr/src/uts/common/inet/rawip_impl.h b/usr/src/uts/common/inet/rawip_impl.h
index 241132b..5635bb0 100644
--- a/usr/src/uts/common/inet/rawip_impl.h
+++ b/usr/src/uts/common/inet/rawip_impl.h
@@ -143,6 +143,8 @@
uint_t icmp_label_len; /* length of security label */
uint_t icmp_label_len_v6; /* sec. part of sticky opt */
in6_addr_t icmp_v6lastdst; /* most recent destination */
+ cred_t *icmp_last_cred; /* most recent credentials */
+ cred_t *icmp_effective_cred; /* cred with effective label */
icmp_stack_t *icmp_is; /* Stack instance */
size_t icmp_xmit_hiwat;
size_t icmp_xmit_lowat;
diff --git a/usr/src/uts/common/inet/sctp/sctp.c b/usr/src/uts/common/inet/sctp/sctp.c
index 7a64587..7a1c289 100644
--- a/usr/src/uts/common/inet/sctp/sctp.c
+++ b/usr/src/uts/common/inet/sctp/sctp.c
@@ -1489,6 +1489,7 @@
sctp->sctp_cpid = curproc->p_pid;
sctp->sctp_open_time = lbolt64;
+ ASSERT(sctp_connp->conn_cred == NULL);
sctp_connp->conn_cred = credp;
crhold(credp);
@@ -2356,6 +2357,10 @@
IPPH_REFRELE(connp->conn_policy, connp->conn_netstack);
if (connp->conn_ipsec_opt_mp != NULL)
freemsg(connp->conn_ipsec_opt_mp);
+ if (connp->conn_cred != NULL)
+ crfree(connp->conn_cred);
+ if (connp->conn_effective_cred != NULL)
+ crfree(connp->conn_effective_cred);
mutex_destroy(&connp->conn_lock);
cv_destroy(&connp->conn_cv);
netstack_rele(connp->conn_netstack);
diff --git a/usr/src/uts/common/inet/sctp/sctp_common.c b/usr/src/uts/common/inet/sctp/sctp_common.c
index 9f6b7a1..76bc2db 100644
--- a/usr/src/uts/common/inet/sctp/sctp_common.c
+++ b/usr/src/uts/common/inet/sctp/sctp_common.c
@@ -484,9 +484,12 @@
}
/*
- * Returns 0 on success, -1 on memory allocation failure. If sleep
- * is true, this function should never fail. The boolean parameter
- * first decides whether the newly created faddr structure should be
+ * Returns 0 on success, ENOMEM on memory allocation failure, EHOSTUNREACH
+ * if the connection credentials fail remote host accreditation or
+ * if the new destination does not support the previously established
+ * connection security label. If sleep is true, this function should
+ * never fail for a memory allocation failure. The boolean parameter
+ * "first" decides whether the newly created faddr structure should be
* added at the beginning of the list or at the end.
*
* Note: caller must hold conn fanout lock.
@@ -496,54 +499,48 @@
{
sctp_faddr_t *faddr;
mblk_t *timer_mp;
+ int err;
if (is_system_labeled()) {
- ts_label_t *tsl;
- tsol_tpc_t *rhtp;
- int retv;
+ cred_t *effective_cred;
- tsl = crgetlabel(CONN_CRED(sctp->sctp_connp));
- ASSERT(tsl != NULL);
-
- /* find_tpc automatically does the right thing with IPv4 */
- rhtp = find_tpc(addr, IPV6_VERSION, B_FALSE);
- if (rhtp == NULL)
- return (EACCES);
-
- retv = EACCES;
- if (tsl->tsl_doi == rhtp->tpc_tp.tp_doi) {
- switch (rhtp->tpc_tp.host_type) {
- case UNLABELED:
- /*
- * Can talk to unlabeled hosts if any of the
- * following are true:
- * 1. zone's label matches the remote host's
- * default label,
- * 2. mac_exempt is on and the zone dominates
- * the remote host's label, or
- * 3. mac_exempt is on and the socket is from
- * the global zone.
- */
- if (blequal(&rhtp->tpc_tp.tp_def_label,
- &tsl->tsl_label) ||
- (sctp->sctp_mac_exempt &&
- (sctp->sctp_zoneid == GLOBAL_ZONEID ||
- bldominates(&tsl->tsl_label,
- &rhtp->tpc_tp.tp_def_label))))
- retv = 0;
- break;
- case SUN_CIPSO:
- if (_blinrange(&tsl->tsl_label,
- &rhtp->tpc_tp.tp_sl_range_cipso) ||
- blinlset(&tsl->tsl_label,
- rhtp->tpc_tp.tp_sl_set_cipso))
- retv = 0;
- break;
- }
+ /*
+ * Verify the destination is allowed to receive packets
+ * at the security label of the connection we are initiating.
+ *
+ * tsol_check_dest() will create a new effective cred for
+ * this connection with a modified label or label flags only
+ * if there are changes from the original cred.
+ *
+ * conn_effective_cred may be non-NULL if a previous
+ * faddr was already added or if this is a server
+ * accepting a connection on a multi-label port.
+ *
+ * Accept whatever label we get if this is the first
+ * destination address for this connection. The security
+ * label and label flags must match any previuous settings
+ * for all subsequent destination addresses.
+ */
+ if (IN6_IS_ADDR_V4MAPPED(addr)) {
+ uint32_t dst;
+ IN6_V4MAPPED_TO_IPADDR(addr, dst);
+ err = tsol_check_dest(CONN_CRED(sctp->sctp_connp),
+ &dst, IPV4_VERSION, sctp->sctp_mac_exempt,
+ &effective_cred);
+ } else {
+ err = tsol_check_dest(CONN_CRED(sctp->sctp_connp),
+ addr, IPV6_VERSION, sctp->sctp_mac_exempt,
+ &effective_cred);
}
- TPC_RELE(rhtp);
- if (retv != 0)
- return (retv);
+ if (err != 0)
+ return (err);
+ if (sctp->sctp_faddrs == NULL &&
+ sctp->sctp_connp->conn_effective_cred == NULL) {
+ sctp->sctp_connp->conn_effective_cred = effective_cred;
+ } else if (effective_cred != NULL) {
+ crfree(effective_cred);
+ return (EHOSTUNREACH);
+ }
}
if ((faddr = kmem_cache_alloc(sctp_kmem_faddr_cache, sleep)) == NULL)
@@ -1084,7 +1081,6 @@
int added;
if (tsol_compute_label(cr, sctp->sctp_ipha->ipha_dst, optbuf,
- sctp->sctp_mac_exempt,
sctp->sctp_sctps->sctps_netstack->netstack_ip) != 0)
return (EACCES);
@@ -1115,7 +1111,6 @@
const cred_t *cr = CONN_CRED(sctp->sctp_connp);
if (tsol_compute_label_v6(cr, &sctp->sctp_ip6h->ip6_dst, optbuf,
- sctp->sctp_mac_exempt,
sctp->sctp_sctps->sctps_netstack->netstack_ip) != 0)
return (EACCES);
if (tsol_update_sticky(&sctp->sctp_sticky_ipp, &sctp->sctp_v6label_len,
diff --git a/usr/src/uts/common/inet/sctp/sctp_conn.c b/usr/src/uts/common/inet/sctp/sctp_conn.c
index 8340004..60c22a3 100644
--- a/usr/src/uts/common/inet/sctp/sctp_conn.c
+++ b/usr/src/uts/common/inet/sctp/sctp_conn.c
@@ -64,7 +64,8 @@
uint_t sctp_options;
conn_t *aconnp;
conn_t *lconnp;
- cred_t *cr;
+ cred_t *credp;
+ ts_label_t *tslp;
sctp_stack_t *sctps = listener->sctp_sctps;
sctph = (sctp_hdr_t *)(cr_pkt->b_rptr + ip_hdr_len);
@@ -76,6 +77,25 @@
ich = (sctp_chunk_hdr_t *)(iack + 1);
init = (sctp_init_chunk_t *)(ich + 1);
+ /*
+ * If this is an MLP connection, packets are to be
+ * exchanged using the security label of the received
+ * Cookie packet instead of the server application's label.
+ * Create an effective cred for the connection by attaching
+ * the received packet's security label to the server
+ * application's cred.
+ */
+ aconnp = acceptor->sctp_connp;
+ lconnp = listener->sctp_connp;
+ ASSERT(aconnp->conn_effective_cred == NULL);
+ if (lconnp->conn_mlp_type != mlptSingle &&
+ (credp = msg_getcred(cr_pkt, NULL)) != NULL &&
+ (tslp = crgetlabel(credp)) != NULL) {
+ if ((aconnp->conn_effective_cred = copycred_from_tslabel(
+ aconnp->conn_cred, tslp, KM_NOSLEEP)) == NULL)
+ return (ENOMEM);
+ }
+
/* acceptor isn't in any fanouts yet, so don't need to hold locks */
ASSERT(acceptor->sctp_faddrs == NULL);
err = sctp_get_addrparams(acceptor, listener, cr_pkt, ich,
@@ -83,14 +103,6 @@
if (err != 0)
return (err);
- aconnp = acceptor->sctp_connp;
- lconnp = listener->sctp_connp;
- if (lconnp->conn_mlp_type != mlptSingle) {
- cr = aconnp->conn_peercred = msg_getcred(cr_pkt, NULL);
- if (cr != NULL)
- crhold(cr);
- }
-
if ((err = sctp_set_hdraddrs(acceptor)) != 0)
return (err);
diff --git a/usr/src/uts/common/inet/sctp/sctp_cookie.c b/usr/src/uts/common/inet/sctp/sctp_cookie.c
index 5c265c3..f15b997 100644
--- a/usr/src/uts/common/inet/sctp/sctp_cookie.c
+++ b/usr/src/uts/common/inet/sctp/sctp_cookie.c
@@ -486,6 +486,7 @@
boolean_t initcollision = B_FALSE;
boolean_t linklocal = B_FALSE;
cred_t *cr;
+ pid_t pid;
ts_label_t *initlabel;
sctp_stack_t *sctps = sctp->sctp_sctps;
@@ -593,9 +594,7 @@
* added to cover this possibility.
*/
if (sctp->sctp_connp->conn_mlp_type != mlptSingle) {
- pid_t cpid;
-
- cr = msg_getcred(initmp, &cpid);
+ cr = msg_getcred(initmp, &pid);
if (cr == NULL || (initlabel = crgetlabel(cr)) == NULL) {
sctp_send_abort(sctp, sctp_init2vtag(ch),
SCTP_ERR_UNKNOWN, NULL, 0, initmp, 0, B_FALSE);
@@ -609,7 +608,7 @@
return;
}
iackmp = allocb_cred(ipsctplen + sctps->sctps_wroff_xtra,
- cr, cpid);
+ cr, pid);
crfree(cr);
} else {
iackmp = allocb_cred(ipsctplen + sctps->sctps_wroff_xtra,
@@ -777,7 +776,7 @@
iackmp->b_cont = errmp; /* OK if NULL */
- if (is_system_labeled() && (cr = msg_getcred(iackmp, NULL)) != NULL &&
+ if (is_system_labeled() && (cr = msg_getcred(iackmp, &pid)) != NULL &&
crgetlabel(cr) != NULL) {
conn_t *connp = sctp->sctp_connp;
int err;
@@ -785,11 +784,11 @@
if (isv4)
err = tsol_check_label(cr, &iackmp,
connp->conn_mac_exempt,
- sctps->sctps_netstack->netstack_ip);
+ sctps->sctps_netstack->netstack_ip, pid);
else
err = tsol_check_label_v6(cr, &iackmp,
connp->conn_mac_exempt,
- sctps->sctps_netstack->netstack_ip);
+ sctps->sctps_netstack->netstack_ip, pid);
if (err != 0) {
sctp_send_abort(sctp, sctp_init2vtag(ch),
SCTP_ERR_AUTH_ERR, NULL, 0, initmp, 0, B_FALSE);
diff --git a/usr/src/uts/common/inet/sctp/sctp_error.c b/usr/src/uts/common/inet/sctp/sctp_error.c
index 5adaa09..5efa383 100644
--- a/usr/src/uts/common/inet/sctp/sctp_error.c
+++ b/usr/src/uts/common/inet/sctp/sctp_error.c
@@ -185,6 +185,7 @@
ts_label_t *tsl;
conn_t *connp;
cred_t *cr = NULL;
+ pid_t pid;
sctp_stack_t *sctps = sctp->sctp_sctps;
ip_stack_t *ipst;
@@ -272,15 +273,15 @@
ipst = sctps->sctps_netstack->netstack_ip;
connp = sctp->sctp_connp;
- if (is_system_labeled() && (cr = msg_getcred(inmp, NULL)) != NULL &&
+ if (is_system_labeled() && (cr = msg_getcred(inmp, &pid)) != NULL &&
crgetlabel(cr) != NULL) {
int err;
boolean_t exempt = connp->conn_mac_exempt;
if (isv4)
- err = tsol_check_label(cr, &hmp, exempt, ipst);
+ err = tsol_check_label(cr, &hmp, exempt, ipst, pid);
else
- err = tsol_check_label_v6(cr, &hmp, exempt, ipst);
+ err = tsol_check_label_v6(cr, &hmp, exempt, ipst, pid);
if (err != 0) {
freemsg(hmp);
return;
diff --git a/usr/src/uts/common/inet/sctp/sctp_ioc.c b/usr/src/uts/common/inet/sctp/sctp_ioc.c
index d92be9b..7150c48 100644
--- a/usr/src/uts/common/inet/sctp/sctp_ioc.c
+++ b/usr/src/uts/common/inet/sctp/sctp_ioc.c
@@ -273,6 +273,7 @@
/*
* connp->conn_cred is crfree()ed in ipcl_conn_destroy()
*/
+ ASSERT(connp->conn_cred == NULL);
connp->conn_cred = credp;
crhold(connp->conn_cred);
diff --git a/usr/src/uts/common/inet/sctp/sctp_snmp.c b/usr/src/uts/common/inet/sctp/sctp_snmp.c
index cbb922e..e5cf071 100644
--- a/usr/src/uts/common/inet/sctp/sctp_snmp.c
+++ b/usr/src/uts/common/inet/sctp/sctp_snmp.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/stream.h>
#include <sys/cmn_err.h>
@@ -617,10 +615,20 @@
mlp.tme_flags |= MIB2_TMEF_PRIVATE;
needattr = B_TRUE;
}
- if (connp->conn_peercred != NULL) {
+ if (connp->conn_anon_mlp) {
+ mlp.tme_flags |= MIB2_TMEF_ANONMLP;
+ needattr = B_TRUE;
+ }
+ if (connp->conn_mac_exempt) {
+ mlp.tme_flags |= MIB2_TMEF_MACEXEMPT;
+ needattr = B_TRUE;
+ }
+ if (connp->conn_fully_bound &&
+ connp->conn_effective_cred != NULL) {
ts_label_t *tsl;
- tsl = crgetlabel(connp->conn_peercred);
+ tsl = crgetlabel(connp->conn_effective_cred);
+ mlp.tme_flags |= MIB2_TMEF_IS_LABELED;
mlp.tme_doi = label2doi(tsl);
mlp.tme_label = *label2bslabel(tsl);
needattr = B_TRUE;
diff --git a/usr/src/uts/common/inet/tcp/tcp.c b/usr/src/uts/common/inet/tcp/tcp.c
index 547e447..781870c 100644
--- a/usr/src/uts/common/inet/tcp/tcp.c
+++ b/usr/src/uts/common/inet/tcp/tcp.c
@@ -692,7 +692,7 @@
static void tcp_random_init(void);
int tcp_random(void);
static void tcp_tli_accept(tcp_t *tcp, mblk_t *mp);
-static void tcp_accept_swap(tcp_t *listener, tcp_t *acceptor,
+static int tcp_accept_swap(tcp_t *listener, tcp_t *acceptor,
tcp_t *eager);
static int tcp_adapt_ire(tcp_t *tcp, mblk_t *ire_mp);
static in_port_t tcp_bindi(tcp_t *tcp, in_port_t port, const in6_addr_t *laddr,
@@ -1652,9 +1652,9 @@
crfree(connp->conn_cred);
connp->conn_cred = NULL;
}
- if (connp->conn_peercred != NULL) {
- crfree(connp->conn_peercred);
- connp->conn_peercred = NULL;
+ if (connp->conn_effective_cred != NULL) {
+ crfree(connp->conn_effective_cred);
+ connp->conn_effective_cred = NULL;
}
ipcl_conn_cleanup(connp);
connp->conn_flags = IPCL_TCPCONN;
@@ -1891,6 +1891,7 @@
mblk_t *ok_mp;
mblk_t *mp1;
tcp_stack_t *tcps = listener->tcp_tcps;
+ int error;
if ((mp->b_wptr - mp->b_rptr) < sizeof (*tcr)) {
tcp_err_ack(listener, mp, TPROTO, 0);
@@ -2145,7 +2146,15 @@
* the tcp_accept_swap is done since it would be dangerous to
* let the application start using the new fd prior to the swap.
*/
- tcp_accept_swap(listener, acceptor, eager);
+ error = tcp_accept_swap(listener, acceptor, eager);
+ if (error != 0) {
+ CONN_DEC_REF(acceptor->tcp_connp);
+ CONN_DEC_REF(eager->tcp_connp);
+ freemsg(ok_mp);
+ /* Original mp has been freed by now, so use mp1 */
+ tcp_err_ack(listener, mp1, TSYSERR, error);
+ return;
+ }
/*
* tcp_accept_swap unlinks eager from listener but does not drop
@@ -2346,10 +2355,11 @@
*
* See the block comment on top of tcp_accept() and tcp_wput_accept().
*/
-static void
+static int
tcp_accept_swap(tcp_t *listener, tcp_t *acceptor, tcp_t *eager)
{
conn_t *econnp, *aconnp;
+ cred_t *effective_cred = NULL;
ASSERT(eager->tcp_rq == listener->tcp_rq);
ASSERT(eager->tcp_detached && !acceptor->tcp_detached);
@@ -2358,6 +2368,27 @@
ASSERT(!TCP_IS_SOCKET(eager));
ASSERT(!TCP_IS_SOCKET(listener));
+ econnp = eager->tcp_connp;
+ aconnp = acceptor->tcp_connp;
+
+ /*
+ * Trusted Extensions may need to use a security label that is
+ * different from the acceptor's label on MLP and MAC-Exempt
+ * sockets. If this is the case, the required security label
+ * already exists in econnp->conn_effective_cred. Use this label
+ * to generate a new effective cred for the acceptor.
+ *
+ * We allow for potential application level retry attempts by
+ * checking for transient errors before modifying eager.
+ */
+ if (is_system_labeled() &&
+ aconnp->conn_cred != NULL && econnp->conn_effective_cred != NULL) {
+ effective_cred = copycred_from_tslabel(aconnp->conn_cred,
+ crgetlabel(econnp->conn_effective_cred), KM_NOSLEEP);
+ if (effective_cred == NULL)
+ return (ENOMEM);
+ }
+
acceptor->tcp_detached = B_TRUE;
/*
* To permit stream re-use by TLI/XTI, the eager needs a copy of
@@ -2376,9 +2407,6 @@
eager->tcp_rq = acceptor->tcp_rq;
eager->tcp_wq = acceptor->tcp_wq;
- econnp = eager->tcp_connp;
- aconnp = acceptor->tcp_connp;
-
eager->tcp_rq->q_ptr = econnp;
eager->tcp_wq->q_ptr = econnp;
@@ -2397,23 +2425,25 @@
econnp->conn_dev = aconnp->conn_dev;
econnp->conn_minor_arena = aconnp->conn_minor_arena;
+
ASSERT(econnp->conn_minor_arena != NULL);
if (eager->tcp_cred != NULL)
crfree(eager->tcp_cred);
eager->tcp_cred = econnp->conn_cred = aconnp->conn_cred;
+ if (econnp->conn_effective_cred != NULL)
+ crfree(econnp->conn_effective_cred);
+ econnp->conn_effective_cred = effective_cred;
+ aconnp->conn_cred = NULL;
+ ASSERT(aconnp->conn_effective_cred == NULL);
+
ASSERT(econnp->conn_netstack == aconnp->conn_netstack);
ASSERT(eager->tcp_tcps == acceptor->tcp_tcps);
- aconnp->conn_cred = NULL;
-
econnp->conn_zoneid = aconnp->conn_zoneid;
econnp->conn_allzones = aconnp->conn_allzones;
- econnp->conn_mac_exempt = aconnp->conn_mac_exempt;
aconnp->conn_mac_exempt = B_FALSE;
- ASSERT(aconnp->conn_peercred == NULL);
-
/* Do the IPC initialization */
CONN_INC_REF(econnp);
@@ -2423,6 +2453,7 @@
/* Done with old IPC. Drop its ref on its connp */
CONN_DEC_REF(aconnp);
+ return (0);
}
@@ -5055,7 +5086,6 @@
int added;
if (tsol_compute_label(cr, tcp->tcp_remote, optbuf,
- connp->conn_mac_exempt,
tcp->tcp_tcps->tcps_netstack->netstack_ip) != 0)
return (B_FALSE);
@@ -5080,7 +5110,6 @@
uchar_t optbuf[TSOL_MAX_IPV6_OPTION];
if (tsol_compute_label_v6(cr, &tcp->tcp_remote_v6, optbuf,
- connp->conn_mac_exempt,
tcp->tcp_tcps->tcps_netstack->netstack_ip) != 0)
return (B_FALSE);
if (tsol_update_sticky(&tcp->tcp_sticky_ipp,
@@ -5396,31 +5425,71 @@
econnp->conn_cred = eager->tcp_cred = credp = connp->conn_cred;
crhold(credp);
- /*
- * If the caller has the process-wide flag set, then default to MAC
- * exempt mode. This allows read-down to unlabeled hosts.
- */
- if (getpflags(NET_MAC_AWARE, credp) != 0)
- econnp->conn_mac_exempt = B_TRUE;
-
+ ASSERT(econnp->conn_effective_cred == NULL);
if (is_system_labeled()) {
cred_t *cr;
+ ts_label_t *tsl;
- if (connp->conn_mlp_type != mlptSingle) {
- cr = econnp->conn_peercred = msg_getcred(mp, NULL);
- if (cr != NULL)
- crhold(cr);
- else
- cr = econnp->conn_cred;
- DTRACE_PROBE2(mlp_syn_accept, conn_t *,
- econnp, cred_t *, cr)
+ /*
+ * If this is an MLP connection or a MAC-Exempt connection
+ * with an unlabeled node, packets are to be
+ * exchanged using the security label of the received
+ * SYN packet instead of the server application's label.
+ */
+ if ((cr = msg_getcred(mp, NULL)) != NULL &&
+ (tsl = crgetlabel(cr)) != NULL &&
+ (connp->conn_mlp_type != mlptSingle ||
+ (connp->conn_mac_exempt == B_TRUE &&
+ (tsl->tsl_flags & TSLF_UNLABELED)))) {
+ if ((econnp->conn_effective_cred =
+ copycred_from_tslabel(econnp->conn_cred,
+ tsl, KM_NOSLEEP)) != NULL) {
+ DTRACE_PROBE2(
+ syn_accept_peerlabel,
+ conn_t *, econnp, cred_t *,
+ econnp->conn_effective_cred);
+ } else {
+ DTRACE_PROBE3(
+ tx__ip__log__error__set__eagercred__tcp,
+ char *,
+ "SYN mp(1) label on eager connp(2) failed",
+ mblk_t *, mp, conn_t *, econnp);
+ goto error3;
+ }
} else {
- cr = econnp->conn_cred;
DTRACE_PROBE2(syn_accept, conn_t *,
- econnp, cred_t *, cr)
+ econnp, cred_t *, econnp->conn_cred)
}
- if (!tcp_update_label(eager, cr)) {
+ /*
+ * Verify the destination is allowed to receive packets
+ * at the security label of the SYN-ACK we are generating.
+ * tsol_check_dest() may create a new effective cred for
+ * this connection with a modified label or label flags.
+ */
+ if (IN6_IS_ADDR_V4MAPPED(&econnp->conn_remv6)) {
+ uint32_t dst;
+ IN6_V4MAPPED_TO_IPADDR(&econnp->conn_remv6, dst);
+ err = tsol_check_dest(CONN_CRED(econnp), &dst,
+ IPV4_VERSION, B_FALSE, &cr);
+ } else {
+ err = tsol_check_dest(CONN_CRED(econnp),
+ &econnp->conn_remv6, IPV6_VERSION,
+ B_FALSE, &cr);
+ }
+ if (err != 0)
+ goto error3;
+ if (cr != NULL) {
+ if (econnp->conn_effective_cred != NULL)
+ crfree(econnp->conn_effective_cred);
+ econnp->conn_effective_cred = cr;
+ }
+
+ /*
+ * Generate the security label to be used in the text of
+ * this connection's outgoing packets.
+ */
+ if (!tcp_update_label(eager, CONN_CRED(econnp))) {
DTRACE_PROBE3(
tx__ip__log__error__connrequest__tcp,
char *, "eager connp(1) label on SYN mp(2) failed",
@@ -6098,6 +6167,23 @@
goto failed;
}
+ /*
+ * Verify the destination is allowed to receive packets
+ * at the security label of the connection we are initiating.
+ * tsol_check_dest() may create a new effective cred for this
+ * connection with a modified label or label flags.
+ */
+ if (is_system_labeled()) {
+ ASSERT(tcp->tcp_connp->conn_effective_cred == NULL);
+ if ((error = tsol_check_dest(CONN_CRED(tcp->tcp_connp),
+ &dstaddr, IPV4_VERSION, tcp->tcp_connp->conn_mac_exempt,
+ &tcp->tcp_connp->conn_effective_cred)) != 0) {
+ if (error != EHOSTUNREACH)
+ error = -TSYSERR;
+ goto failed;
+ }
+ }
+
tcp->tcp_ipha->ipha_dst = dstaddr;
IN6_IPADDR_TO_V4MAPPED(dstaddr, &tcp->tcp_remote_v6);
@@ -6282,6 +6368,23 @@
goto failed;
}
+ /*
+ * Verify the destination is allowed to receive packets
+ * at the security label of the connection we are initiating.
+ * check_dest may create a new effective cred for this
+ * connection with a modified label or label flags.
+ */
+ if (is_system_labeled()) {
+ ASSERT(tcp->tcp_connp->conn_effective_cred == NULL);
+ if ((error = tsol_check_dest(CONN_CRED(tcp->tcp_connp),
+ dstaddrp, IPV6_VERSION, tcp->tcp_connp->conn_mac_exempt,
+ &tcp->tcp_connp->conn_effective_cred)) != 0) {
+ if (error != EHOSTUNREACH)
+ error = -TSYSERR;
+ goto failed;
+ }
+ }
+
tcp->tcp_ip6h->ip6_dst = *dstaddrp;
tcp->tcp_remote_v6 = *dstaddrp;
tcp->tcp_ip6h->ip6_vcf =
@@ -7412,6 +7515,11 @@
conn_delete_ire(tcp->tcp_connp, NULL);
tcp_ipsec_cleanup(tcp);
+ if (tcp->tcp_connp->conn_effective_cred != NULL) {
+ crfree(tcp->tcp_connp->conn_effective_cred);
+ tcp->tcp_connp->conn_effective_cred = NULL;
+ }
+
if (tcp->tcp_conn_req_max != 0) {
/*
* This is the case when a TLI program uses the same
@@ -15811,10 +15919,20 @@
mlp.tme_flags |= MIB2_TMEF_PRIVATE;
needattr = B_TRUE;
}
- if (connp->conn_peercred != NULL) {
+ if (connp->conn_anon_mlp) {
+ mlp.tme_flags |= MIB2_TMEF_ANONMLP;
+ needattr = B_TRUE;
+ }
+ if (connp->conn_mac_exempt) {
+ mlp.tme_flags |= MIB2_TMEF_MACEXEMPT;
+ needattr = B_TRUE;
+ }
+ if (connp->conn_fully_bound &&
+ connp->conn_effective_cred != NULL) {
ts_label_t *tsl;
- tsl = crgetlabel(connp->conn_peercred);
+ tsl = crgetlabel(connp->conn_effective_cred);
+ mlp.tme_flags |= MIB2_TMEF_IS_LABELED;
mlp.tme_doi = label2doi(tsl);
mlp.tme_label = *label2bslabel(tsl);
needattr = B_TRUE;
@@ -16445,7 +16563,7 @@
* But we assume that SYN's are not dropped for loopback connections.
*/
if (tcp->tcp_state == TCPS_SYN_SENT) {
- mblk_setcred(mp, tcp->tcp_cred, tcp->tcp_cpid);
+ mblk_setcred(mp, CONN_CRED(tcp->tcp_connp), tcp->tcp_cpid);
}
tcp->tcp_csuna = tcp->tcp_snxt;
@@ -18364,12 +18482,12 @@
* both getpeerucred and TX.
* If this is a SYN then the caller already set db_credp so
* that getpeerucred will work. But if TX is in use we might have
- * a conn_peercred which is different, and we need to use that cred
- * to make TX use the correct label and label dependent route.
+ * a conn_effective_cred which is different, and we need to use that
+ * cred to make TX use the correct label and label dependent route.
*/
if (is_system_labeled()) {
cr = msg_getcred(mp, &cpid);
- if (cr == NULL || connp->conn_peercred != NULL)
+ if (cr == NULL || connp->conn_effective_cred != NULL)
mblk_setcred(mp, CONN_CRED(connp), cpid);
}
@@ -21922,6 +22040,7 @@
queue_t *q = tcps->tcps_g_q;
tcp_t *tcp;
cred_t *cr;
+ pid_t pid;
mblk_t *nmp;
ip_stack_t *ipst = tcps->tcps_netstack->netstack_ip;
@@ -22070,18 +22189,18 @@
}
/* IP trusts us to set up labels when required. */
- if (is_system_labeled() && (cr = msg_getcred(mp, NULL)) != NULL &&
+ if (is_system_labeled() && (cr = msg_getcred(mp, &pid)) != NULL &&
crgetlabel(cr) != NULL) {
int err;
if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION)
err = tsol_check_label(cr, &mp,
tcp->tcp_connp->conn_mac_exempt,
- tcps->tcps_netstack->netstack_ip);
+ tcps->tcps_netstack->netstack_ip, pid);
else
err = tsol_check_label_v6(cr, &mp,
tcp->tcp_connp->conn_mac_exempt,
- tcps->tcps_netstack->netstack_ip);
+ tcps->tcps_netstack->netstack_ip, pid);
if (mctl_present)
ipsec_mp->b_cont = mp;
else
@@ -25513,6 +25632,8 @@
mblk_t *lsoi;
int retval;
tcph_t *tcph;
+ cred_t *ecr;
+ ts_label_t *tsl;
uint32_t mss;
queue_t *q = tcp->tcp_rq;
conn_t *connp = tcp->tcp_connp;
@@ -25673,11 +25794,49 @@
syn_mp = tcp_xmit_mp(tcp, NULL, 0, NULL, NULL,
tcp->tcp_iss, B_FALSE, NULL, B_FALSE);
if (syn_mp) {
+ /*
+ * cr contains the cred from the thread calling
+ * connect().
+ *
+ * If no thread cred is available, use the
+ * socket creator's cred instead. If still no
+ * cred, drop the request rather than risk a
+ * panic on production systems.
+ */
if (cr == NULL) {
- cr = tcp->tcp_cred;
+ cr = CONN_CRED(connp);
pid = tcp->tcp_cpid;
+ ASSERT(cr != NULL);
+ if (cr != NULL) {
+ mblk_setcred(syn_mp, cr, pid);
+ } else {
+ error = ECONNABORTED;
+ goto ipcl_rm;
+ }
+
+ /*
+ * If an effective security label exists for
+ * the connection, create a copy of the thread's
+ * cred but with the effective label attached.
+ */
+ } else if (is_system_labeled() &&
+ connp->conn_effective_cred != NULL &&
+ (tsl = crgetlabel(connp->
+ conn_effective_cred)) != NULL) {
+ if ((ecr = copycred_from_tslabel(cr,
+ tsl, KM_NOSLEEP)) == NULL) {
+ error = ENOMEM;
+ goto ipcl_rm;
+ }
+ mblk_setcred(syn_mp, ecr, pid);
+ crfree(ecr);
+
+ /*
+ * Default to using the thread's cred unchanged.
+ */
+ } else {
+ mblk_setcred(syn_mp, cr, pid);
}
- mblk_setcred(syn_mp, cr, pid);
tcp_send_data(tcp, tcp->tcp_wq, syn_mp);
}
after_syn_sent:
diff --git a/usr/src/uts/common/inet/udp/udp.c b/usr/src/uts/common/inet/udp/udp.c
index 63cec75..bff50c9 100644
--- a/usr/src/uts/common/inet/udp/udp.c
+++ b/usr/src/uts/common/inet/udp/udp.c
@@ -878,6 +878,14 @@
udp->udp_sticky_hdrs = NULL;
udp->udp_sticky_hdrs_len = 0;
}
+ if (udp->udp_last_cred != NULL) {
+ crfree(udp->udp_last_cred);
+ udp->udp_last_cred = NULL;
+ }
+ if (udp->udp_effective_cred != NULL) {
+ crfree(udp->udp_effective_cred);
+ udp->udp_effective_cred = NULL;
+ }
ip6_pkt_free(&udp->udp_sticky_ipp);
@@ -4521,6 +4529,14 @@
mlp.tme_flags |= MIB2_TMEF_PRIVATE;
needattr = B_TRUE;
}
+ if (connp->conn_anon_mlp) {
+ mlp.tme_flags |= MIB2_TMEF_ANONMLP;
+ needattr = B_TRUE;
+ }
+ if (connp->conn_mac_exempt) {
+ mlp.tme_flags |= MIB2_TMEF_MACEXEMPT;
+ needattr = B_TRUE;
+ }
/*
* Create an IPv4 table entry for IPv4 entries and also
@@ -4821,14 +4837,15 @@
}
static int
-udp_update_label(queue_t *wq, mblk_t *mp, ipaddr_t dst,
- boolean_t *update_lastdst)
+udp_update_label(queue_t *wq, mblk_t *mp, ipaddr_t dst)
{
int err;
+ cred_t *cred;
+ cred_t *orig_cred = NULL;
+ cred_t *effective_cred = NULL;
uchar_t opt_storage[IP_MAX_OPT_LENGTH];
udp_t *udp = Q_TO_UDP(wq);
udp_stack_t *us = udp->udp_us;
- cred_t *cr;
/*
* All Solaris components should pass a db_credp
@@ -4836,27 +4853,66 @@
* On production kernels we return an error to be robust against
* random streams modules sitting on top of us.
*/
- cr = msg_getcred(mp, NULL);
- ASSERT(cr != NULL);
- if (cr == NULL)
+ cred = orig_cred = msg_getcred(mp, NULL);
+ ASSERT(cred != NULL);
+ if (cred == NULL)
return (EINVAL);
- /* Note that we use the cred/label from the message to handle MLP */
- err = tsol_compute_label(cr, dst,
- opt_storage, udp->udp_connp->conn_mac_exempt,
- us->us_netstack->netstack_ip);
- if (err == 0) {
- err = tsol_update_options(&udp->udp_ip_snd_options,
- &udp->udp_ip_snd_options_len, &udp->udp_label_len,
- opt_storage);
+ /*
+ * Verify the destination is allowed to receive packets at
+ * the security label of the message data. tsol_check_dest()
+ * may create a new effective cred for this message with a
+ * modified label or label flags. Note that we use the cred/label
+ * from the message to handle MLP
+ */
+ if ((err = tsol_check_dest(cred, &dst, IPV4_VERSION,
+ udp->udp_connp->conn_mac_exempt, &effective_cred)) != 0)
+ goto done;
+ if (effective_cred != NULL)
+ cred = effective_cred;
+
+ /*
+ * Calculate the security label to be placed in the text
+ * of the message (if any).
+ */
+ if ((err = tsol_compute_label(cred, dst, opt_storage,
+ us->us_netstack->netstack_ip)) != 0)
+ goto done;
+
+ /*
+ * Insert the security label in the cached ip options,
+ * removing any old label that may exist.
+ */
+ if ((err = tsol_update_options(&udp->udp_ip_snd_options,
+ &udp->udp_ip_snd_options_len, &udp->udp_label_len,
+ opt_storage)) != 0)
+ goto done;
+
+ /*
+ * Save the destination address and creds we used to
+ * generate the security label text.
+ */
+ if (cred != udp->udp_effective_cred) {
+ if (udp->udp_effective_cred != NULL)
+ crfree(udp->udp_effective_cred);
+ crhold(cred);
+ udp->udp_effective_cred = cred;
}
+ if (orig_cred != udp->udp_last_cred) {
+ if (udp->udp_last_cred != NULL)
+ crfree(udp->udp_last_cred);
+ crhold(orig_cred);
+ udp->udp_last_cred = orig_cred;
+ }
+done:
+ if (effective_cred != NULL)
+ crfree(effective_cred);
+
if (err != 0) {
DTRACE_PROBE4(
tx__ip__log__info__updatelabel__udp,
char *, "queue(1) failed to update options(2) on mp(3)",
queue_t *, wq, char *, opt_storage, mblk_t *, mp);
- } else {
- *update_lastdst = B_TRUE;
}
return (err);
}
@@ -4994,6 +5050,9 @@
* destination and are updated atomically.
*/
if (is_system_labeled()) {
+ cred_t *credp;
+ pid_t cpid;
+
/* Using UDP MLP requires SCM_UCRED from user */
if (connp->conn_mlp_type != mlptSingle &&
!attrs.udpattr_credset) {
@@ -5001,23 +5060,33 @@
DTRACE_PROBE4(
tx__ip__log__info__output__udp,
char *, "MLP mp(1) lacks SCM_UCRED attr(2) on q(3)",
- mblk_t *, mp1, udpattrs_t *, &attrs, queue_t *, q);
- *error = ECONNREFUSED;
+ mblk_t *, mp, udpattrs_t *, &attrs, queue_t *, q);
+ *error = EINVAL;
goto done;
}
/*
- * update label option for this UDP socket if
- * - the destination has changed, or
- * - the UDP socket is MLP
+ * Update label option for this UDP socket if
+ * - the destination has changed,
+ * - the UDP socket is MLP, or
+ * - the cred attached to the mblk changed.
*/
- if ((!IN6_IS_ADDR_V4MAPPED(&udp->udp_v6lastdst) ||
+ credp = msg_getcred(mp, &cpid);
+ if (!IN6_IS_ADDR_V4MAPPED(&udp->udp_v6lastdst) ||
V4_PART_OF_V6(udp->udp_v6lastdst) != v4dst ||
- connp->conn_mlp_type != mlptSingle) &&
- (*error = udp_update_label(q, mp, v4dst, &update_lastdst))
- != 0) {
- mutex_exit(&connp->conn_lock);
- goto done;
+ connp->conn_mlp_type != mlptSingle ||
+ credp != udp->udp_last_cred) {
+ if ((*error = udp_update_label(q, mp, v4dst)) != 0) {
+ mutex_exit(&connp->conn_lock);
+ goto done;
+ }
+ update_lastdst = B_TRUE;
}
+
+ /*
+ * Attach the effective cred to the mblk to ensure future
+ * routing decisions will be based on it's label.
+ */
+ mblk_setcred(mp, udp->udp_effective_cred, cpid);
}
if (update_lastdst) {
IN6_IPADDR_TO_V4MAPPED(v4dst, &udp->udp_v6lastdst);
@@ -5049,7 +5118,6 @@
mp->b_cont = mp1;
else
mp = mp1;
-
ipha = (ipha_t *)(mp1->b_wptr - ip_hdr_length);
}
ip_hdr_length -= (UDPH_SIZE + (insert_spi ? sizeof (uint32_t) : 0));
@@ -5605,14 +5673,15 @@
}
static boolean_t
-udp_update_label_v6(queue_t *wq, mblk_t *mp, in6_addr_t *dst,
- boolean_t *update_lastdst)
+udp_update_label_v6(queue_t *wq, mblk_t *mp, in6_addr_t *dst)
{
udp_t *udp = Q_TO_UDP(wq);
int err;
+ cred_t *cred;
+ cred_t *orig_cred;
+ cred_t *effective_cred = NULL;
uchar_t opt_storage[TSOL_MAX_IPV6_OPTION];
udp_stack_t *us = udp->udp_us;
- cred_t *cr;
/*
* All Solaris components should pass a db_credp
@@ -5620,26 +5689,66 @@
* On production kernels we return an error to be robust against
* random streams modules sitting on top of us.
*/
- cr = msg_getcred(mp, NULL);
- ASSERT(cr != NULL);
- if (cr == NULL)
+ cred = orig_cred = msg_getcred(mp, NULL);
+ ASSERT(cred != NULL);
+ if (cred == NULL)
return (EINVAL);
- /* Note that we use the cred/label from the message to handle MLP */
- err = tsol_compute_label_v6(cr,
- dst, opt_storage, udp->udp_connp->conn_mac_exempt,
- us->us_netstack->netstack_ip);
- if (err == 0) {
- err = tsol_update_sticky(&udp->udp_sticky_ipp,
- &udp->udp_label_len_v6, opt_storage);
+ /*
+ * Verify the destination is allowed to receive packets at
+ * the security label of the message data. tsol_check_dest()
+ * may create a new effective cred for this message with a
+ * modified label or label flags. Note that we use the
+ * cred/label from the message to handle MLP.
+ */
+ if ((err = tsol_check_dest(cred, dst, IPV6_VERSION,
+ udp->udp_connp->conn_mac_exempt, &effective_cred)) != 0)
+ goto done;
+ if (effective_cred != NULL)
+ cred = effective_cred;
+
+ /*
+ * Calculate the security label to be placed in the text
+ * of the message (if any).
+ */
+ if ((err = tsol_compute_label_v6(cred, dst, opt_storage,
+ us->us_netstack->netstack_ip)) != 0)
+ goto done;
+
+ /*
+ * Insert the security label in the cached ip options,
+ * removing any old label that may exist.
+ */
+ if ((err = tsol_update_sticky(&udp->udp_sticky_ipp,
+ &udp->udp_label_len_v6, opt_storage)) != 0)
+ goto done;
+
+ /*
+ * Save the destination address and cred we used to
+ * generate the security label text.
+ */
+ if (cred != udp->udp_effective_cred) {
+ if (udp->udp_effective_cred != NULL)
+ crfree(udp->udp_effective_cred);
+ crhold(cred);
+ udp->udp_effective_cred = cred;
}
+ if (orig_cred != udp->udp_last_cred) {
+ if (udp->udp_last_cred != NULL)
+ crfree(udp->udp_last_cred);
+ crhold(orig_cred);
+ udp->udp_last_cred = orig_cred;
+ }
+
+done:
+ if (effective_cred != NULL)
+ crfree(effective_cred);
+
if (err != 0) {
DTRACE_PROBE4(
tx__ip__log__drop__updatelabel__udp6,
char *, "queue(1) failed to update options(2) on mp(3)",
queue_t *, wq, char *, opt_storage, mblk_t *, mp);
- } else {
- *update_lastdst = B_TRUE;
}
return (err);
}
@@ -6097,6 +6206,9 @@
* destination and are updated atomically.
*/
if (is_system_labeled()) {
+ cred_t *credp;
+ pid_t cpid;
+
/* Using UDP MLP requires SCM_UCRED from user */
if (connp->conn_mlp_type != mlptSingle &&
!attrs.udpattr_credset) {
@@ -6104,25 +6216,35 @@
tx__ip__log__info__output__udp6,
char *, "MLP mp(1) lacks SCM_UCRED attr(2) on q(3)",
mblk_t *, mp1, udpattrs_t *, &attrs, queue_t *, q);
- *error = ECONNREFUSED;
+ *error = EINVAL;
rw_exit(&udp->udp_rwlock);
mutex_exit(&connp->conn_lock);
goto done;
}
/*
* update label option for this UDP socket if
- * - the destination has changed, or
- * - the UDP socket is MLP
+ * - the destination has changed,
+ * - the UDP socket is MLP, or
+ * - the cred attached to the mblk changed.
*/
- if ((opt_present ||
+ credp = msg_getcred(mp, &cpid);
+ if (opt_present ||
!IN6_ARE_ADDR_EQUAL(&udp->udp_v6lastdst, &ip6_dst) ||
- connp->conn_mlp_type != mlptSingle) &&
- (*error = udp_update_label_v6(q, mp, &ip6_dst,
- &update_lastdst)) != 0) {
- rw_exit(&udp->udp_rwlock);
- mutex_exit(&connp->conn_lock);
- goto done;
+ connp->conn_mlp_type != mlptSingle ||
+ credp != udp->udp_last_cred) {
+ if ((*error = udp_update_label_v6(q, mp, &ip6_dst))
+ != 0) {
+ rw_exit(&udp->udp_rwlock);
+ mutex_exit(&connp->conn_lock);
+ goto done;
+ }
+ update_lastdst = B_TRUE;
}
+ /*
+ * Attach the effective cred to the mblk to ensure future
+ * routing decisions will be based on it's label.
+ */
+ mblk_setcred(mp, udp->udp_effective_cred, cpid);
}
if (update_lastdst) {
@@ -8398,9 +8520,27 @@
mlpport = connp->conn_anon_port ? PMAPPORT : port;
mlptype = tsol_mlp_port_type(zone, IPPROTO_UDP, mlpport,
addrtype);
+
+ /*
+ * It is a coding error to attempt to bind an MLP port
+ * without first setting SOL_SOCKET/SCM_UCRED.
+ */
if (mlptype != mlptSingle &&
- (connp->conn_mlp_type == mlptSingle ||
- secpolicy_net_bindmlp(cr) != 0)) {
+ connp->conn_mlp_type == mlptSingle) {
+ rw_enter(&udp->udp_rwlock, RW_WRITER);
+ udp->udp_pending_op = -1;
+ rw_exit(&udp->udp_rwlock);
+ connp->conn_anon_port = B_FALSE;
+ connp->conn_mlp_type = mlptSingle;
+ return (EINVAL);
+ }
+
+ /*
+ * It is an access violation to attempt to bind an MLP port
+ * without NET_BINDMLP privilege.
+ */
+ if (mlptype != mlptSingle &&
+ secpolicy_net_bindmlp(cr) != 0) {
if (udp->udp_debug) {
(void) strlog(UDP_MOD_ID, 0, 1,
SL_ERROR|SL_TRACE,
diff --git a/usr/src/uts/common/inet/udp_impl.h b/usr/src/uts/common/inet/udp_impl.h
index 7d0a2ad..2827f42 100644
--- a/usr/src/uts/common/inet/udp_impl.h
+++ b/usr/src/uts/common/inet/udp_impl.h
@@ -315,6 +315,8 @@
uint_t udp_label_len_v6; /* len of v6 security label */
in6_addr_t udp_v6lastdst; /* most recent destination */
in_port_t udp_lastdstport; /* most recent dest port */
+ cred_t *udp_last_cred; /* most recent credentials */
+ cred_t *udp_effective_cred; /* cred with effective label */
uint64_t udp_open_time; /* time when this was opened */
pid_t udp_open_pid; /* process id when this was opened */
diff --git a/usr/src/uts/common/os/cred.c b/usr/src/uts/common/os/cred.c
index 59e856e..205ae32 100644
--- a/usr/src/uts/common/os/cred.c
+++ b/usr/src/uts/common/os/cred.c
@@ -131,7 +131,7 @@
return (eph_zsd);
}
-static cred_t *crdup_flags(cred_t *, int);
+static cred_t *crdup_flags(const cred_t *, int);
static cred_t *cralloc_flags(int);
/*
@@ -419,7 +419,7 @@
* The old cred is not freed.
*/
static cred_t *
-crdup_flags(cred_t *cr, int flgs)
+crdup_flags(const cred_t *cr, int flgs)
{
cred_t *newcr;
@@ -1023,19 +1023,33 @@
* by a caller without affecting other users
*/
cred_t *
-copycred_from_bslabel(cred_t *cr, bslabel_t *blabel, uint32_t doi, int flags)
+copycred_from_tslabel(const cred_t *cr, ts_label_t *label, int flags)
{
- ts_label_t *lbl = labelalloc(blabel, doi, flags);
cred_t *newcr = NULL;
+ if ((newcr = crdup_flags(cr, flags)) != NULL) {
+ if (newcr->cr_label != NULL)
+ label_rele(newcr->cr_label);
+ label_hold(label);
+ newcr->cr_label = label;
+ }
+
+ return (newcr);
+}
+
+/*
+ * Derive a new cred from the existing cred, but with a different label.
+ */
+cred_t *
+copycred_from_bslabel(const cred_t *cr, bslabel_t *blabel,
+ uint32_t doi, int flags)
+{
+ ts_label_t *lbl = labelalloc(blabel, doi, flags);
+ cred_t *newcr = NULL;
+
if (lbl != NULL) {
- if ((newcr = crdup_flags(cr, flags)) != NULL) {
- if (newcr->cr_label != NULL)
- label_rele(newcr->cr_label);
- newcr->cr_label = lbl;
- } else {
- label_rele(lbl);
- }
+ newcr = copycred_from_tslabel(cr, lbl, flags);
+ label_rele(lbl);
}
return (newcr);
diff --git a/usr/src/uts/common/os/tlabel.c b/usr/src/uts/common/os/tlabel.c
index 3a46745..78f857f 100644
--- a/usr/src/uts/common/os/tlabel.c
+++ b/usr/src/uts/common/os/tlabel.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/param.h>
#include <sys/cmn_err.h>
@@ -102,6 +100,22 @@
}
/*
+ * Duplicate an existing ts_label_t to a new one, with only
+ * the current reference.
+ */
+ts_label_t *
+labeldup(const ts_label_t *val, int flag)
+{
+ ts_label_t *lab = kmem_cache_alloc(tslabel_cache, flag);
+
+ if (lab != NULL) {
+ bcopy(val, lab, sizeof (ts_label_t));
+ lab->tsl_ref = 1;
+ }
+ return (lab);
+}
+
+/*
* Put a hold on a label structure.
*/
void
diff --git a/usr/src/uts/common/sys/tsol/label.h b/usr/src/uts/common/sys/tsol/label.h
index b496737..13fae9c 100644
--- a/usr/src/uts/common/sys/tsol/label.h
+++ b/usr/src/uts/common/sys/tsol/label.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_TSOL_LABEL_H
#define _SYS_TSOL_LABEL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#ifdef _KERNEL
#include <sys/cred.h>
@@ -105,7 +103,7 @@
#define DEFAULT_DOI 1
-#define TSLF_UNLABELED 0x00000001 /* source was unlabeled */
+#define TSLF_UNLABELED 0x00000001 /* peer is unlabeled */
#define CR_SL(cr) (label2bslabel(crgetlabel(cr)))
@@ -116,14 +114,17 @@
extern void label_init(void);
extern ts_label_t *labelalloc(const m_label_t *, uint32_t, int);
+extern ts_label_t *labeldup(const ts_label_t *, int);
extern void label_hold(ts_label_t *);
extern void label_rele(ts_label_t *);
extern m_label_t *label2bslabel(ts_label_t *);
extern uint32_t label2doi(ts_label_t *);
extern boolean_t label_equal(const ts_label_t *, const ts_label_t *);
extern cred_t *newcred_from_bslabel(m_label_t *, uint32_t, int);
-extern cred_t *copycred_from_bslabel(cred_t *, m_label_t *,
+extern cred_t *copycred_from_bslabel(const cred_t *, m_label_t *,
uint32_t, int);
+extern cred_t *copycred_from_tslabel(const cred_t *, ts_label_t *,
+ int);
extern ts_label_t *getflabel(vnode_t *);
extern int getlabel(const char *, m_label_t *);
extern int fgetlabel(int, m_label_t *);
diff --git a/usr/src/uts/common/sys/tsol/tnet.h b/usr/src/uts/common/sys/tsol/tnet.h
index 30b633b..c8fb39e 100644
--- a/usr/src/uts/common/sys/tsol/tnet.h
+++ b/usr/src/uts/common/sys/tsol/tnet.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* from "tnet.h 7.44 02/10/09 SMI; TSOL 2.x"
@@ -28,8 +28,6 @@
#ifndef _SYS_TSOL_TNET_H
#define _SYS_TSOL_TNET_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/stream.h>
#include <sys/tsol/label.h>
@@ -48,13 +46,16 @@
extern int tsol_tnrh_chk(tsol_tpent_t *, bslabel_t *, int);
extern tsol_tnrhc_t *find_rhc(const void *, uchar_t, boolean_t);
-extern int tsol_compute_label(const cred_t *, ipaddr_t, uchar_t *, boolean_t,
+extern int tsol_check_dest(const cred_t *, const void *, uchar_t, boolean_t,
+ cred_t **);
+extern int tsol_compute_label(const cred_t *, ipaddr_t, uchar_t *,
ip_stack_t *);
extern int tsol_compute_label_v6(const cred_t *, const in6_addr_t *, uchar_t *,
- boolean_t, ip_stack_t *);
-extern int tsol_check_label(const cred_t *, mblk_t **, boolean_t, ip_stack_t *);
-extern int tsol_check_label_v6(const cred_t *, mblk_t **, boolean_t,
ip_stack_t *);
+extern int tsol_check_label(const cred_t *, mblk_t **, boolean_t,
+ ip_stack_t *, pid_t);
+extern int tsol_check_label_v6(const cred_t *, mblk_t **, boolean_t,
+ ip_stack_t *, pid_t);
extern int tsol_prepend_option(uchar_t *, ipha_t *, int);
extern int tsol_prepend_option_v6(uchar_t *, ip6_t *, int);
extern int tsol_remove_secopt(ipha_t *, int);