PSARC/2008/252 Labeled IPsec phase 1
6886771 Labeled IPsec phase 1
6808727 Alignment error panic in tsol_can_accept_raw()
6894979 nightly -0 + -p builds then destroys SUNW0on
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/Makefile
index 4769f27..e82bfdf 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/Makefile
@@ -25,6 +25,7 @@
PROG= ikeadm ipsecalgs ipsecconf ipseckey ikecert
SOCKETPROG= ipsecalgs ipsecconf ipseckey
+TSOLPROG= ipseckey
SRCS= ikeadm.c ipsecalgs.c ipsecconf.c ipseckey.c
include ../../../Makefile.cmd
@@ -57,6 +58,11 @@
CFLAGS += $(XSTRCONST)
LDLIBS += -lipsecutil -lnsl
+
+LAZYLIBS = $(ZLAZYLOAD) -ltsol $(ZNOLAZYLOAD)
+lint := LAZYLIBS = -ltsol
+
+$(TSOLPROG) := LDLIBS += $(LAZYLIBS)
$(SOCKETPROG) := LDLIBS += -lsocket
.KEEP_STATE:
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ikeadm.c b/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ikeadm.c
index 8f334db..1a7e30f 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ikeadm.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ikeadm.c
@@ -1284,6 +1284,8 @@
return (gettext("Door interface"));
case D_CONFIG:
return (gettext("Config file processing"));
+ case D_LABEL:
+ return (gettext("MAC label processing"));
default:
(void) snprintf(rtn, MAXLINESIZE,
gettext("<unknown flag 0x%x>"), bit);
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipseckey.c b/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipseckey.c
index 79506a6..24f3410 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipseckey.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipseckey.c
@@ -399,6 +399,7 @@
#define NEXTIDENT 7
#define NEXTADDR4 8
#define NEXTADDR6 9
+#define NEXTLABEL 10
#define TOK_EOF 0
#define TOK_UNKNOWN 1
@@ -455,6 +456,10 @@
#define TOK_IDLE_ADDTIME 52
#define TOK_IDLE_USETIME 53
#define TOK_RESERVED 54
+#define TOK_LABEL 55
+#define TOK_OLABEL 56
+#define TOK_IMPLABEL 57
+
static struct toktable {
char *string;
@@ -543,6 +548,11 @@
{"replay_value", TOK_REPLAY_VALUE, NEXTNUM},
{"idle_addtime", TOK_IDLE_ADDTIME, NEXTNUM},
{"idle_usetime", TOK_IDLE_USETIME, NEXTNUM},
+
+ {"label", TOK_LABEL, NEXTLABEL},
+ {"outer-label", TOK_OLABEL, NEXTLABEL},
+ {"implicit-label", TOK_IMPLABEL, NEXTLABEL},
+
{NULL, TOK_UNKNOWN, NEXTEOF}
};
@@ -909,6 +919,58 @@
return (retval);
}
+#include <tsol/label.h>
+
+#define PARSELABEL_BAD_TOKEN ((struct sadb_sens *)-1)
+
+static struct sadb_sens *
+parselabel(int token, char *label)
+{
+ bslabel_t *sl = NULL;
+ int err, len;
+ sadb_sens_t *sens;
+ int doi = 1; /* XXX XXX DEFAULT_DOI XXX XXX */
+
+ err = str_to_label(label, &sl, MAC_LABEL, L_DEFAULT, NULL);
+ if (err < 0)
+ return (NULL);
+
+ len = ipsec_convert_sl_to_sens(doi, sl, NULL);
+
+ sens = malloc(len);
+ if (sens == NULL) {
+ Bail("malloc parsed label");
+ /* Should exit before reaching here... */
+ return (NULL);
+ }
+
+ (void) ipsec_convert_sl_to_sens(doi, sl, sens);
+
+ switch (token) {
+ case TOK_LABEL:
+ break;
+
+ case TOK_OLABEL:
+ sens->sadb_sens_exttype = SADB_X_EXT_OUTER_SENS;
+ break;
+
+ case TOK_IMPLABEL:
+ sens->sadb_sens_exttype = SADB_X_EXT_OUTER_SENS;
+ sens->sadb_x_sens_flags = SADB_X_SENS_IMPLICIT;
+ break;
+
+ default:
+ free(sens);
+ /*
+ * Return a different return code for a bad label, but really,
+ * this would be a caller error.
+ */
+ return (PARSELABEL_BAD_TOKEN);
+ }
+
+ return (sens);
+}
+
/*
* Write a message to the PF_KEY socket. If verbose, print the message
* heading into the kernel.
@@ -1590,6 +1652,7 @@
struct sadb_lifetime *hard = NULL, *soft = NULL; /* Current? */
struct sadb_lifetime *idle = NULL;
struct sadb_x_replay_ctr *replay_ctr = NULL;
+ struct sadb_sens *label = NULL, *olabel = NULL;
struct sockaddr_in6 *sin6;
/* MLS TODO: Need sensitivity eventually. */
int next, token, sa_len, alloclen, totallen = sizeof (msg), prefix;
@@ -2530,6 +2593,32 @@
B_TRUE, ebuf);
argv++;
break;
+ case TOK_LABEL:
+ label = parselabel(token, *argv);
+ argv++;
+ if (label == NULL) {
+ ERROR(ep, ebuf,
+ gettext("Malformed security label\n"));
+ break;
+ } else if (label == PARSELABEL_BAD_TOKEN) {
+ Bail("Internal token value error");
+ }
+ totallen += SADB_64TO8(label->sadb_sens_len);
+ break;
+
+ case TOK_OLABEL:
+ case TOK_IMPLABEL:
+ olabel = parselabel(token, *argv);
+ argv++;
+ if (label == NULL) {
+ ERROR(ep, ebuf,
+ gettext("Malformed security label\n"));
+ break;
+ } else if (label == PARSELABEL_BAD_TOKEN) {
+ Bail("Internal token value error");
+ }
+ totallen += SADB_64TO8(olabel->sadb_sens_len);
+ break;
default:
ERROR1(ep, ebuf, gettext(
"Don't use extension %s for add/update.\n"),
@@ -2830,6 +2919,20 @@
free(replay_ctr);
}
+ if (label != NULL) {
+ bcopy(label, nexthdr, SADB_64TO8(label->sadb_sens_len));
+ nexthdr += label->sadb_sens_len;
+ free(label);
+ label = NULL;
+ }
+
+ if (olabel != NULL) {
+ bcopy(olabel, nexthdr, SADB_64TO8(olabel->sadb_sens_len));
+ nexthdr += olabel->sadb_sens_len;
+ free(olabel);
+ olabel = NULL;
+ }
+
if (cflag) {
/*
* Assume the checked cmd would have worked if it was actually
@@ -2855,7 +2958,6 @@
freehostent(natt_lhp);
if (natt_rhp != NULL && natt_rhp != &dummy.he)
freehostent(natt_rhp);
-
free(ebuf);
free(buffer);
}
diff --git a/usr/src/cmd/ptools/pfiles/pfiles.c b/usr/src/cmd/ptools/pfiles/pfiles.c
index e23c9fd..dc08771 100644
--- a/usr/src/cmd/ptools/pfiles/pfiles.c
+++ b/usr/src/cmd/ptools/pfiles/pfiles.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2008 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -591,6 +589,8 @@
{ SOL_SOCKET, SO_OOBINLINE, "SO_OOBINLINE," },
{ SOL_SOCKET, SO_DGRAM_ERRIND, "SO_DGRAM_ERRIND,"},
{ SOL_SOCKET, SO_ALLZONES, "SO_ALLZONES," },
+ { SOL_SOCKET, SO_MAC_EXEMPT, "SO_MAC_EXEMPT," },
+ { SOL_SOCKET, SO_MAC_IMPLICIT, "SO_MAC_IMPLICIT," },
{ SOL_SOCKET, SO_EXCLBIND, "SO_EXCLBIND," },
{ IPPROTO_UDP, UDP_NAT_T_ENDPOINT, "UDP_NAT_T_ENDPOINT," },
};
diff --git a/usr/src/cmd/truss/print.c b/usr/src/cmd/truss/print.c
index bbcff25..c3c4918 100644
--- a/usr/src/cmd/truss/print.c
+++ b/usr/src/cmd/truss/print.c
@@ -1764,6 +1764,7 @@
case SO_ANON_MLP: return ("SO_ANON_MLP");
case SO_MAC_EXEMPT: return ("SO_MAC_EXEMPT");
case SO_ALLZONES: return ("SO_ALLZONES");
+ case SO_MAC_IMPLICIT: return ("SO_MAC_IMPLICIT");
case SO_EXCLBIND: return ("SO_EXCLBIND");
case SO_DOMAIN: return ("SO_DOMAIN");
diff --git a/usr/src/cmd/tsol/tnctl/tnzonecfg b/usr/src/cmd/tsol/tnctl/tnzonecfg
index 4ebd99b..51c0383 100644
--- a/usr/src/cmd/tsol/tnctl/tnzonecfg
+++ b/usr/src/cmd/tsol/tnctl/tnzonecfg
@@ -19,12 +19,9 @@
# 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.
#
-#ident "%Z%%M% %I% %E% SMI"
-#
-#
#There are five fields separated by colon in this configuration file:
#First Field: Name for the corresponding zone.
# It is used when zone is configured.
@@ -52,9 +49,11 @@
# MLP PURPOSE
# --- -------
# 111 Port Mapper
+# 500 IKE (IPsec key management)
# 515 BSD Multilevel Printing
# 631 IPP Multilevel Printing
# 2049 NFSv4 server
+# 4500 IKE NAT-T (IPsec/IKE nat traversal)
# 6000-6003 Multilevel Desktop
#
-global:ADMIN_LOW:1:111/tcp;111/udp;515/tcp;631/tcp;2049/tcp;6000-6003/tcp:6000-6003/tcp
+global:ADMIN_LOW:1:111/tcp;111/udp;500/udp;4500/udp;515/tcp;631/tcp;2049/tcp;6000-6003/tcp:6000-6003/tcp;500/udp;4500/udp
diff --git a/usr/src/lib/libipsecutil/Makefile.com b/usr/src/lib/libipsecutil/Makefile.com
index 5d53d28..b0d4f6a 100644
--- a/usr/src/lib/libipsecutil/Makefile.com
+++ b/usr/src/lib/libipsecutil/Makefile.com
@@ -34,6 +34,9 @@
$(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC)
LDLIBS += -ltecla -lsocket -lnsl -lc
+LAZYLIBS = $(ZLAZYLOAD) -ltsol $(ZNOLAZYLOAD)
+lint := LAZYLIBS = -ltsol
+LDLIBS += $(LAZYLIBS)
CFLAGS += $(CCVERBOSE)
CPPFLAGS += -I$(SRCDIR)
diff --git a/usr/src/lib/libipsecutil/common/ikedoor.h b/usr/src/lib/libipsecutil/common/ikedoor.h
index c05b30c..c0799e9 100644
--- a/usr/src/lib/libipsecutil/common/ikedoor.h
+++ b/usr/src/lib/libipsecutil/common/ikedoor.h
@@ -131,9 +131,10 @@
#define D_PROP 0x00000080 /* proposal construction */
#define D_DOOR 0x00000100 /* door server */
#define D_CONFIG 0x00000200 /* config file processing */
+#define D_LABEL 0x00000400 /* MAC labels */
-#define D_HIGHBIT 0x00000200
-#define D_ALL 0x000003ff
+#define D_HIGHBIT 0x00000400
+#define D_ALL 0x000007ff
/*
* Access privilege levels: define level of access to keying information.
diff --git a/usr/src/lib/libipsecutil/common/ipsec_util.c b/usr/src/lib/libipsecutil/common/ipsec_util.c
index d3f78a4..7d6aa56 100644
--- a/usr/src/lib/libipsecutil/common/ipsec_util.c
+++ b/usr/src/lib/libipsecutil/common/ipsec_util.c
@@ -839,6 +839,7 @@
{ D_PROP, "prop" },
{ D_DOOR, "door" },
{ D_CONFIG, "config" },
+ { D_LABEL, "label" },
{ D_ALL, "all" },
{ 0, "0" },
};
@@ -2040,24 +2041,126 @@
}
/*
+ * Convert sadb_sens extension into binary security label.
+ */
+
+#include <tsol/label.h>
+#include <sys/tsol/tndb.h>
+#include <sys/tsol/label_macro.h>
+
+void
+ipsec_convert_sens_to_bslabel(const struct sadb_sens *sens, bslabel_t *sl)
+{
+ uint64_t *bitmap = (uint64_t *)(sens + 1);
+ int bitmap_len = SADB_64TO8(sens->sadb_sens_sens_len);
+
+ bsllow(sl);
+ LCLASS_SET((_bslabel_impl_t *)sl, sens->sadb_sens_sens_level);
+ bcopy(bitmap, &((_bslabel_impl_t *)sl)->compartments,
+ bitmap_len);
+}
+
+void
+ipsec_convert_bslabel_to_string(bslabel_t *sl, char **plabel)
+{
+ if (label_to_str(sl, plabel, M_LABEL, DEF_NAMES) != 0) {
+ *plabel = strdup(dgettext(TEXT_DOMAIN,
+ "** Label conversion failed **"));
+ }
+}
+
+void
+ipsec_convert_bslabel_to_hex(bslabel_t *sl, char **plabel)
+{
+ if (label_to_str(sl, plabel, M_INTERNAL, DEF_NAMES) != 0) {
+ *plabel = strdup(dgettext(TEXT_DOMAIN,
+ "** Label conversion failed **"));
+ }
+}
+
+int
+ipsec_convert_sl_to_sens(int doi, bslabel_t *sl, sadb_sens_t *sens)
+{
+ uint8_t *bitmap;
+ int sens_len = sizeof (sadb_sens_t) + _C_LEN * 4;
+
+
+ if (sens == NULL)
+ return (sens_len);
+
+
+ (void) memset(sens, 0, sens_len);
+
+ sens->sadb_sens_exttype = SADB_EXT_SENSITIVITY;
+ sens->sadb_sens_len = SADB_8TO64(sens_len);
+ sens->sadb_sens_dpd = doi;
+
+ sens->sadb_sens_sens_level = LCLASS(sl);
+ sens->sadb_sens_integ_level = 0;
+ sens->sadb_sens_sens_len = _C_LEN >> 1;
+ sens->sadb_sens_integ_len = 0;
+
+ sens->sadb_x_sens_flags = 0;
+
+ bitmap = (uint8_t *)(sens + 1);
+ bcopy(&(((_bslabel_impl_t *)sl)->compartments), bitmap, _C_LEN * 4);
+
+ return (sens_len);
+}
+
+
+/*
* Print an SADB_SENSITIVITY extension.
*/
void
-print_sens(FILE *file, char *prefix, struct sadb_sens *sens)
+print_sens(FILE *file, char *prefix, const struct sadb_sens *sens,
+ boolean_t ignore_nss)
{
+ char *plabel;
+ char *hlabel;
uint64_t *bitmap = (uint64_t *)(sens + 1);
+ bslabel_t sl;
int i;
+ int sens_len = sens->sadb_sens_sens_len;
+ int integ_len = sens->sadb_sens_integ_len;
+ boolean_t inner = (sens->sadb_sens_exttype == SADB_EXT_SENSITIVITY);
+ const char *sensname = inner ?
+ dgettext(TEXT_DOMAIN, "Plaintext Sensitivity") :
+ dgettext(TEXT_DOMAIN, "Ciphertext Sensitivity");
+
+ ipsec_convert_sens_to_bslabel(sens, &sl);
(void) fprintf(file, dgettext(TEXT_DOMAIN,
- "%sSensitivity DPD %d, sens level=%d, integ level=%d\n"),
- prefix, sens->sadb_sens_dpd, sens->sadb_sens_sens_level,
- sens->sadb_sens_integ_level);
- for (i = 0; sens->sadb_sens_sens_len-- > 0; i++, bitmap++)
+ "%s%s DPD %d, sens level=%d, integ level=%d, flags=%x\n"),
+ prefix, sensname, sens->sadb_sens_dpd, sens->sadb_sens_sens_level,
+ sens->sadb_sens_integ_level, sens->sadb_x_sens_flags);
+
+ ipsec_convert_bslabel_to_hex(&sl, &hlabel);
+
+ if (ignore_nss) {
(void) fprintf(file, dgettext(TEXT_DOMAIN,
- "%s Sensitivity BM extended word %d 0x%" PRIx64 "\n"),
- prefix, i, *bitmap);
- for (i = 0; sens->sadb_sens_integ_len-- > 0; i++, bitmap++)
- (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+ "%s %s Label: %s\n"), prefix, sensname, hlabel);
+
+ for (i = 0; i < sens_len; i++, bitmap++)
+ (void) fprintf(file, dgettext(TEXT_DOMAIN,
+ "%s %s BM extended word %d 0x%" PRIx64 "\n"),
+ prefix, sensname, i, *bitmap);
+
+ } else {
+ ipsec_convert_bslabel_to_string(&sl, &plabel);
+
+ (void) fprintf(file, dgettext(TEXT_DOMAIN,
+ "%s %s Label: %s (%s)\n"),
+ prefix, sensname, plabel, hlabel);
+ free(plabel);
+
+ }
+ free(hlabel);
+
+ bitmap = (uint64_t *)(sens + 1 + sens_len);
+
+ for (i = 0; i < integ_len; i++, bitmap++)
+ (void) fprintf(file, dgettext(TEXT_DOMAIN,
"%s Integrity BM extended word %d 0x%" PRIx64 "\n"),
prefix, i, *bitmap);
}
@@ -2429,7 +2532,7 @@
break;
case SADB_EXT_SENSITIVITY:
print_sens(file, dgettext(TEXT_DOMAIN, "SNS: "),
- (struct sadb_sens *)current);
+ (struct sadb_sens *)current, ignore_nss);
break;
case SADB_EXT_PROPOSAL:
print_prop(file, dgettext(TEXT_DOMAIN, "PRP: "),
@@ -2467,6 +2570,10 @@
print_pair(file, dgettext(TEXT_DOMAIN, "OTH: "),
(struct sadb_x_pair *)current);
break;
+ case SADB_X_EXT_OUTER_SENS:
+ print_sens(file, dgettext(TEXT_DOMAIN, "OSN: "),
+ (struct sadb_sens *)current, ignore_nss);
+ break;
case SADB_X_EXT_REPLAY_VALUE:
(void) print_replay(file, dgettext(TEXT_DOMAIN,
"RPL: "), (sadb_x_replay_ctr_t *)current);
@@ -2685,6 +2792,35 @@
return (B_TRUE);
}
+boolean_t
+save_sens(struct sadb_sens *sens, FILE *ofile)
+{
+ char *prefix;
+ char *hlabel;
+ bslabel_t sl;
+
+ if (putc('\t', ofile) == EOF)
+ return (B_FALSE);
+
+ if (sens->sadb_sens_exttype == SADB_EXT_SENSITIVITY)
+ prefix = "label";
+ else if ((sens->sadb_x_sens_flags & SADB_X_SENS_IMPLICIT) == 0)
+ prefix = "outer-label";
+ else
+ prefix = "implicit-label";
+
+ ipsec_convert_sens_to_bslabel(sens, &sl);
+ ipsec_convert_bslabel_to_hex(&sl, &hlabel);
+
+ if (fprintf(ofile, "%s %s ", prefix, hlabel) < 0) {
+ free(hlabel);
+ return (B_FALSE);
+ }
+ free(hlabel);
+
+ return (B_TRUE);
+}
+
/*
* "Save" a security association to an output file.
*
@@ -2846,6 +2982,13 @@
savenl();
break;
case SADB_EXT_SENSITIVITY:
+ case SADB_X_EXT_OUTER_SENS:
+ if (!save_sens((struct sadb_sens *)ext, ofile)) {
+ tidyup();
+ bail(dgettext(TEXT_DOMAIN, "save_sens"));
+ }
+ savenl();
+ break;
default:
/* Skip over irrelevant extensions. */
break;
diff --git a/usr/src/lib/libipsecutil/common/ipsec_util.h b/usr/src/lib/libipsecutil/common/ipsec_util.h
index 023f88e..d7eedce 100644
--- a/usr/src/lib/libipsecutil/common/ipsec_util.h
+++ b/usr/src/lib/libipsecutil/common/ipsec_util.h
@@ -365,7 +365,7 @@
extern void print_asn1_name(FILE *, const unsigned char *, long);
extern void print_key(FILE *, char *, struct sadb_key *);
extern void print_ident(FILE *, char *, struct sadb_ident *);
-extern void print_sens(FILE *, char *, struct sadb_sens *);
+extern void print_sens(FILE *, char *, const struct sadb_sens *, boolean_t);
extern void print_prop(FILE *, char *, struct sadb_prop *);
extern void print_eprop(FILE *, char *, struct sadb_prop *);
extern void print_supp(FILE *, char *, struct sadb_supported *);
@@ -384,6 +384,18 @@
extern const char *do_inet_ntop(const void *, char *, size_t);
/*
+ * Label conversion convenience functions.
+ */
+
+#include <tsol/label.h>
+
+extern void ipsec_convert_sens_to_bslabel(const struct sadb_sens *,
+ bslabel_t *);
+extern int ipsec_convert_sl_to_sens(int doi, bslabel_t *, struct sadb_sens *);
+extern void ipsec_convert_bslabel_to_string(bslabel_t *, char **);
+extern void ipsec_convert_bslabel_to_hex(bslabel_t *, char **);
+
+/*
* These exit macros give a consistent exit behaviour for all
* programs that use libipsecutil. These wll work in usr/src/cmd
* and usr/src/lib, but because macros in usr/src/lib don't get
diff --git a/usr/src/lib/libipsecutil/common/mapfile-vers b/usr/src/lib/libipsecutil/common/mapfile-vers
index c5899c1..4d124b9 100644
--- a/usr/src/lib/libipsecutil/common/mapfile-vers
+++ b/usr/src/lib/libipsecutil/common/mapfile-vers
@@ -66,6 +66,10 @@
ipsecproto_get_exec_mode;
ipsecproto_set_exec_mode;
ipsecutil_exit;
+ ipsec_convert_sens_to_bslabel;
+ ipsec_convert_bslabel_to_string;
+ ipsec_convert_bslabel_to_hex;
+ ipsec_convert_sl_to_sens;
keysock_diag;
kmc_insert_mapping;
kmc_lookup_by_cookie;
diff --git a/usr/src/tools/scripts/nightly.sh b/usr/src/tools/scripts/nightly.sh
index 90b8b50..572cf44 100644
--- a/usr/src/tools/scripts/nightly.sh
+++ b/usr/src/tools/scripts/nightly.sh
@@ -575,22 +575,6 @@
/bin/time $MAKE -e install 2>&1 | \
tee -a $SRC/${INSTALLOG}.out >> $LOGFILE
- if [[ "$zero_FLAG" = "y" ]]; then
- if [[ -d "${G11N_PKGDIR}" ]]; then
- echo "\n==== Building globalization package" \
- "$(basename ${G11N_PKGDIR}) ($LABEL) ====\n" \
- >> $LOGFILE
- cd $G11N_PKGDIR
- /bin/time $MAKE -e install 2>&1 | \
- tee -a $SRC/${INSTALLOG}.out >> $LOGFILE
- cd $SRC
- else
- echo "\n==== Skipping nonexistent globalization" \
- "package $(basename ${G11N_PKGDIR})" \
- "($LABEL) ====\n" >> $LOGFILE
- fi
- fi
-
if [[ "$SCM_TYPE" = teamware ]]; then
echo "\n==== SCCS Noise ($LABEL) ====\n" >> $mail_msg_file
egrep 'sccs(check:| *get)' $SRC/${INSTALLOG}.out >> \
@@ -773,6 +757,22 @@
echo "\n==== Not creating $LABEL packages ====\n" >> $LOGFILE
fi
+ if [[ "$zero_FLAG" = "y" ]]; then
+ if [[ -d "${G11N_PKGDIR}" ]]; then
+ echo "\n==== Building globalization package" \
+ "$(basename ${G11N_PKGDIR}) ($LABEL) ====\n" \
+ >> $LOGFILE
+ cd $G11N_PKGDIR
+ /bin/time $MAKE -e install 2>&1 | \
+ tee -a $SRC/${INSTALLOG}.out >> $LOGFILE
+ cd $SRC
+ else
+ echo "\n==== Skipping nonexistent globalization" \
+ "package $(basename ${G11N_PKGDIR})" \
+ "($LABEL) ====\n" >> $LOGFILE
+ fi
+ fi
+
ROOT=$ORIGROOT
}
diff --git a/usr/src/uts/common/inet/ip/icmp.c b/usr/src/uts/common/inet/ip/icmp.c
index f1c5f92..7f6d4b6 100644
--- a/usr/src/uts/common/inet/ip/icmp.c
+++ b/usr/src/uts/common/inet/ip/icmp.c
@@ -1683,7 +1683,7 @@
* exempt mode. This allows read-down to unlabeled hosts.
*/
if (getpflags(NET_MAC_AWARE, credp) != 0)
- connp->conn_mac_exempt = B_TRUE;
+ connp->conn_mac_mode = CONN_MAC_AWARE;
connp->conn_ulp_labeled = is_system_labeled();
@@ -1816,7 +1816,10 @@
*i1 = icmp->icmp_timestamp;
break;
case SO_MAC_EXEMPT:
- *i1 = connp->conn_mac_exempt;
+ *i1 = (connp->conn_mac_mode == CONN_MAC_AWARE);
+ break;
+ case SO_MAC_IMPLICIT:
+ *i1 = (connp->conn_mac_mode == CONN_MAC_IMPLICIT);
break;
case SO_DOMAIN:
*i1 = icmp->icmp_family;
@@ -4447,7 +4450,7 @@
* with a modified label or label flags.
*/
if ((err = tsol_check_dest(cred, &dst, IPV4_VERSION,
- connp->conn_mac_exempt, &effective_cred)) != 0)
+ connp->conn_mac_mode, &effective_cred)) != 0)
goto done;
if (effective_cred != NULL)
cred = effective_cred;
@@ -4890,7 +4893,7 @@
* with a modified label or label flags.
*/
if ((err = tsol_check_dest(cred, dst, IPV6_VERSION,
- connp->conn_mac_exempt, &effective_cred)) != 0)
+ connp->conn_mac_mode, &effective_cred)) != 0)
goto done;
if (effective_cred != NULL)
cred = effective_cred;
diff --git a/usr/src/uts/common/inet/ip/icmp_opt_data.c b/usr/src/uts/common/inet/ip/icmp_opt_data.c
index 2c7f37d..8bee982 100644
--- a/usr/src/uts/common/inet/ip/icmp_opt_data.c
+++ b/usr/src/uts/common/inet/ip/icmp_opt_data.c
@@ -91,6 +91,8 @@
},
{ SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int),
0 },
+{ SO_MAC_IMPLICIT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int),
+ 0 },
{ SO_ALLZONES, SOL_SOCKET, OA_R, OA_RW, OP_CONFIG, OP_PASSNEXT, sizeof (int),
0 },
diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c
index 69382ec..b72218e 100644
--- a/usr/src/uts/common/inet/ip/ip.c
+++ b/usr/src/uts/common/inet/ip/ip.c
@@ -2056,9 +2056,7 @@
ii = (ipsec_in_t *)first_mp->b_rptr;
ii->ipsec_in_ns = ipst->ips_netstack; /* No netstack_hold */
}
- ii->ipsec_in_zoneid = zoneid;
- ASSERT(zoneid != ALL_ZONES);
- if (!ipsec_in_to_out(first_mp, ipha, NULL)) {
+ if (!ipsec_in_to_out(first_mp, ipha, NULL, zoneid)) {
BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
return;
}
@@ -3262,7 +3260,7 @@
/*
* Convert the IPSEC_IN to IPSEC_OUT.
*/
- if (!ipsec_in_to_out(ipsec_mp, ipha, NULL)) {
+ if (!ipsec_in_to_out(ipsec_mp, ipha, NULL, zoneid)) {
BUMP_MIB(&ipst->ips_ip_mib,
ipIfStatsOutDiscards);
return;
@@ -3304,20 +3302,12 @@
/* This is not a secure packet */
ii->ipsec_in_secure = B_FALSE;
- /*
- * For trusted extensions using a shared IP address we can
- * send using any zoneid.
- */
- if (zoneid == ALL_ZONES)
- ii->ipsec_in_zoneid = GLOBAL_ZONEID;
- else
- ii->ipsec_in_zoneid = zoneid;
ipsec_mp->b_cont = mp;
ipha = (ipha_t *)mp->b_rptr;
/*
* Convert the IPSEC_IN to IPSEC_OUT.
*/
- if (!ipsec_in_to_out(ipsec_mp, ipha, NULL)) {
+ if (!ipsec_in_to_out(ipsec_mp, ipha, NULL, zoneid)) {
BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutDiscards);
return;
}
@@ -4427,7 +4417,7 @@
if (is_system_labeled() && protocol == IPPROTO_UDP)
goto bad_addr;
- if (connp->conn_mac_exempt)
+ if (connp->conn_mac_mode != CONN_MAC_DEFAULT)
goto bad_addr;
/* No hash here really. The table is big enough. */
@@ -4778,7 +4768,7 @@
*/
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) {
+ connp->conn_mac_mode, &effective_cred)) != 0) {
if (ip_debug > 2) {
pr_addr_dbg(
"ip_bind_connected_v4:"
@@ -7244,7 +7234,8 @@
while ((connp != NULL) &&
(!IPCL_UDP_MATCH(connp, dstport, dst, srcport, src) ||
(!IPCL_ZONE_MATCH(connp, zoneid) &&
- !(unlabeled && connp->conn_mac_exempt && shared_addr)))) {
+ !(unlabeled && (connp->conn_mac_mode != CONN_MAC_DEFAULT) &&
+ shared_addr)))) {
/*
* We keep searching since the conn did not match,
* or its zone did not match and it is not either
@@ -9827,7 +9818,7 @@
* exempt mode. This allows read-down to unlabeled hosts.
*/
if (getpflags(NET_MAC_AWARE, credp) != 0)
- connp->conn_mac_exempt = B_TRUE;
+ connp->conn_mac_mode = CONN_MAC_AWARE;
connp->conn_rq = q;
connp->conn_wq = WR(q);
@@ -10628,7 +10619,18 @@
return (EACCES);
if (!checkonly) {
mutex_enter(&connp->conn_lock);
- connp->conn_mac_exempt = *i1 != 0 ? 1 : 0;
+ connp->conn_mac_mode = *i1 != 0 ?
+ CONN_MAC_AWARE : CONN_MAC_DEFAULT;
+ mutex_exit(&connp->conn_lock);
+ }
+ break; /* goto sizeof (int) option return */
+ case SO_MAC_IMPLICIT:
+ if (secpolicy_net_mac_implicit(cr) != 0)
+ return (EACCES);
+ if (!checkonly) {
+ mutex_enter(&connp->conn_lock);
+ connp->conn_mac_mode = *i1 != 0 ?
+ CONN_MAC_IMPLICIT : CONN_MAC_DEFAULT;
mutex_exit(&connp->conn_lock);
}
break; /* goto sizeof (int) option return */
@@ -13957,14 +13959,14 @@
if (ipst->ips_ip4_observe.he_interested) {
zoneid_t szone;
- szone = ip_get_zoneid_v4(ipha->ipha_src, mp,
- ipst, ALL_ZONES);
/*
- * The IP observability hook expects b_rptr to be
+ * Both of these functions expect b_rptr to be
* where the IP header starts, so advance past the
- * link layer header.
+ * link layer header if present.
*/
mp->b_rptr += hlen;
+ szone = ip_get_zoneid_v4(ipha->ipha_src, mp,
+ ipst, ALL_ZONES);
ipobs_hook(mp, IPOBS_HOOK_OUTBOUND, szone,
ALL_ZONES, ill, ipst);
mp->b_rptr -= hlen;
@@ -20373,7 +20375,7 @@
credp = BEST_CRED(mp, connp, &pid);
err = tsol_check_label(credp, &mp,
- connp->conn_mac_exempt, ipst, pid);
+ connp->conn_mac_mode, ipst, pid);
ipha = (ipha_t *)mp->b_rptr;
if (err != 0) {
first_mp = mp;
@@ -20436,12 +20438,11 @@
if (need_decref)
CONN_DEC_REF(connp);
return;
- } else {
- ASSERT(mp->b_datap->db_type == M_CTL);
- first_mp = mp;
- mp = mp->b_cont;
- mctl_present = B_TRUE;
}
+ ASSERT(mp->b_datap->db_type == M_CTL);
+ first_mp = mp;
+ mp = mp->b_cont;
+ mctl_present = B_TRUE;
} else {
first_mp = mp;
mctl_present = B_FALSE;
@@ -20866,10 +20867,10 @@
if (connp != NULL) {
credp = BEST_CRED(mp, connp, &pid);
err = tsol_check_label(credp, &mp,
- connp->conn_mac_exempt, ipst, pid);
+ connp->conn_mac_mode, ipst, pid);
} else if ((credp = msg_getcred(mp, &pid)) != NULL) {
err = tsol_check_label(credp, &mp,
- B_FALSE, ipst, pid);
+ CONN_MAC_DEFAULT, ipst, pid);
}
ipha = (ipha_t *)mp->b_rptr;
if (mctl_present)
@@ -22166,9 +22167,10 @@
mp = first_mp->b_cont;
ipsec_len = ipsec_out_extra_length(first_mp);
ASSERT(ipsec_len >= 0);
+ if (zoneid == ALL_ZONES)
+ zoneid = GLOBAL_ZONEID;
/* We already picked up the zoneid from the M_CTL above */
ASSERT(zoneid == io->ipsec_out_zoneid);
- ASSERT(zoneid != ALL_ZONES);
/*
* Drop M_CTL here if IPsec processing is not needed.
@@ -25472,6 +25474,7 @@
hwaccel = io->ipsec_out_accelerated;
zoneid = io->ipsec_out_zoneid;
ASSERT(zoneid != ALL_ZONES);
+ ASSERT(IPH_HDR_VERSION(ip6h) == IPV6_VERSION);
match_flags = MATCH_IRE_ILL | MATCH_IRE_SECATTR;
/* Multicast addresses should have non-zero ill_index. */
v6dstp = &ip6h->ip6_dst;
@@ -25532,6 +25535,7 @@
if (ill_need_rele)
ill_refrele(ill);
freemsg(ipsec_mp);
+ ipif_refrele(ipif);
return;
}
diff --git a/usr/src/uts/common/inet/ip/ip6.c b/usr/src/uts/common/inet/ip/ip6.c
index b9e3e15..6fca667 100644
--- a/usr/src/uts/common/inet/ip/ip6.c
+++ b/usr/src/uts/common/inet/ip/ip6.c
@@ -442,9 +442,7 @@
ii->ipsec_in_secure = B_FALSE;
first_mp->b_cont = mp;
}
- ii->ipsec_in_zoneid = zoneid;
- ASSERT(zoneid != ALL_ZONES);
- if (!ipsec_in_to_out(first_mp, NULL, ip6h)) {
+ if (!ipsec_in_to_out(first_mp, NULL, ip6h, zoneid)) {
BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
return;
}
@@ -1517,7 +1515,7 @@
/*
* Convert the IPSEC_IN to IPSEC_OUT.
*/
- if (!ipsec_in_to_out(ipsec_mp, NULL, ip6h)) {
+ if (!ipsec_in_to_out(ipsec_mp, NULL, ip6h, zoneid)) {
BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
ill_refrele(ill);
return;
@@ -1549,20 +1547,12 @@
/* This is not a secure packet */
ii->ipsec_in_secure = B_FALSE;
- /*
- * For trusted extensions using a shared IP address we can
- * send using any zoneid.
- */
- if (zoneid == ALL_ZONES)
- ii->ipsec_in_zoneid = GLOBAL_ZONEID;
- else
- ii->ipsec_in_zoneid = zoneid;
ipsec_mp->b_cont = mp;
ip6h = (ip6_t *)mp->b_rptr;
/*
* Convert the IPSEC_IN to IPSEC_OUT.
*/
- if (!ipsec_in_to_out(ipsec_mp, NULL, ip6h)) {
+ if (!ipsec_in_to_out(ipsec_mp, NULL, ip6h, zoneid)) {
BUMP_MIB(ill->ill_ip_mib, ipIfStatsInDiscards);
ill_refrele(ill);
return;
@@ -2077,8 +2067,8 @@
goto bad_addr;
/* Allow ipsec plumbing */
- if (connp->conn_mac_exempt && protocol != IPPROTO_AH &&
- protocol != IPPROTO_ESP)
+ if ((connp->conn_mac_mode != CONN_MAC_DEFAULT) &&
+ (protocol != IPPROTO_AH) && (protocol != IPPROTO_ESP))
goto bad_addr;
connp->conn_srcv6 = ipv6_all_zeros;
@@ -2477,7 +2467,7 @@
*/
if (is_system_labeled() && !IPCL_IS_TCP(connp)) {
if ((error = tsol_check_dest(cr, v6dst, IPV6_VERSION,
- connp->conn_mac_exempt, &effective_cred)) != 0) {
+ connp->conn_mac_mode, &effective_cred)) != 0) {
if (ip_debug > 2) {
pr_addr_dbg(
"ip_bind_connected: no label for dst %s\n",
@@ -9117,9 +9107,10 @@
ASSERT(CONN_CRED(connp) != NULL);
cr = BEST_CRED(mp, connp, &pid);
err = tsol_check_label_v6(cr, &mp,
- connp->conn_mac_exempt, ipst, pid);
+ connp->conn_mac_mode, ipst, pid);
} else if ((cr = msg_getcred(mp, &pid)) != NULL) {
- err = tsol_check_label_v6(cr, &mp, B_FALSE, ipst, pid);
+ err = tsol_check_label_v6(cr, &mp, CONN_MAC_DEFAULT,
+ ipst, pid);
}
if (mctl_present)
first_mp->b_cont = mp;
@@ -11891,16 +11882,15 @@
if (ipst->ips_ip6_observe.he_interested) {
zoneid_t szone;
- szone = ip_get_zoneid_v6(&ip6h->ip6_src,
- mp_ip6h, out_ill, ipst, ALL_ZONES);
-
/*
- * The IP observability hook expects b_rptr to
+ * Both of these functions expect b_rptr to
* be where the IPv6 header starts, so advance
* past the link layer header.
*/
if (fp_prepend)
mp_ip6h->b_rptr += hlen;
+ szone = ip_get_zoneid_v6(&ip6h->ip6_src,
+ mp_ip6h, out_ill, ipst, ALL_ZONES);
ipobs_hook(mp_ip6h, IPOBS_HOOK_OUTBOUND, szone,
ALL_ZONES, out_ill, ipst);
if (fp_prepend)
diff --git a/usr/src/uts/common/inet/ip/ip_opt_data.c b/usr/src/uts/common/inet/ip/ip_opt_data.c
index 1c91ea6..e86e59f 100644
--- a/usr/src/uts/common/inet/ip/ip_opt_data.c
+++ b/usr/src/uts/common/inet/ip/ip_opt_data.c
@@ -61,8 +61,8 @@
{ SO_REUSEADDR, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
{ SO_PROTOTYPE, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
{ SO_ANON_MLP, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
-{ SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0
- },
+{ SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
+{ SO_MAC_IMPLICIT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
{ SO_ALLZONES, SOL_SOCKET, OA_R, OA_RW, OP_CONFIG, 0, sizeof (int),
0 },
diff --git a/usr/src/uts/common/inet/ip/ip_sadb.c b/usr/src/uts/common/inet/ip/ip_sadb.c
index 402ab3a..35b8229 100644
--- a/usr/src/uts/common/inet/ip/ip_sadb.c
+++ b/usr/src/uts/common/inet/ip/ip_sadb.c
@@ -25,6 +25,7 @@
#include <sys/types.h>
#include <sys/stream.h>
+#include <sys/strsubr.h>
#include <sys/sunddi.h>
#include <sys/ddi.h>
#include <sys/strlog.h>
@@ -56,6 +57,48 @@
ipsid_equal(ipl->ipl_remote_cid, sa->ipsa_dst_cid);
}
+/* cr1 is packet cred; cr2 is SA credential */
+boolean_t
+ipsec_label_match(cred_t *cr1, cred_t *cr2)
+{
+ ts_label_t *l1, *l2;
+
+ if (!is_system_labeled())
+ return (B_TRUE);
+
+ /*
+ * Check for NULL creds. Unlabeled SA always matches;
+ * unlabeled user with labeled SA always fails
+ */
+ if (cr2 == NULL)
+ return (B_TRUE);
+
+ if (cr1 == NULL)
+ return (B_FALSE);
+
+ /* If we reach here, we have two passed-in creds. */
+ ASSERT(cr2 != NULL && cr1 != NULL);
+
+ /* Check for NULL labels. Two is good, one is bad, zero is good. */
+ l1 = crgetlabel(cr1);
+ l2 = crgetlabel(cr2);
+ if (l1 == NULL)
+ return (l2 == NULL);
+
+ if (l2 == NULL)
+ return (B_FALSE);
+
+ /* Simple IPsec MLS policy: labels must be equal */
+ /* In future will need bit in policy saying whether this is the case */
+
+ /*
+ * label_equal() checks DOI and label contents. We should be
+ * good to go with this check.
+ */
+ return (label_equal(l1, l2));
+}
+
+
/*
* Look up a security association based on the unique ID generated by IP and
* transport or tunnel information, such as ports and upper-layer protocol,
@@ -67,7 +110,7 @@
*/
ipsa_t *
ipsec_getassocbyconn(isaf_t *bucket, ipsec_out_t *io, uint32_t *src,
- uint32_t *dst, sa_family_t af, uint8_t protocol)
+ uint32_t *dst, sa_family_t af, uint8_t protocol, cred_t *cr)
{
ipsa_t *retval, *candidate;
ipsec_action_t *candact;
@@ -287,6 +330,12 @@
goto next_ipsa;
/*
+ * Do labels match?
+ */
+ if (!ipsec_label_match(cr, retval->ipsa_cred))
+ goto next_ipsa;
+
+ /*
* At this point, we know that we have at least a match on:
*
* - dest
@@ -546,6 +595,7 @@
sadbp_t *sadbp;
sadb_t *sp;
sa_family_t af;
+ cred_t *cr;
netstack_t *ns;
data_mp = mp->b_cont;
@@ -601,8 +651,11 @@
dst_ptr = (uint32_t *)&dst6;
}
+ cr = msg_getcred(data_mp, NULL);
+
mutex_enter(&bucket->isaf_lock);
- assoc = ipsec_getassocbyconn(bucket, io, src_ptr, dst_ptr, af, proto);
+ assoc = ipsec_getassocbyconn(bucket, io, src_ptr, dst_ptr, af,
+ proto, cr);
mutex_exit(&bucket->isaf_lock);
if (assoc == NULL)
diff --git a/usr/src/uts/common/inet/ip/ipclassifier.c b/usr/src/uts/common/inet/ip/ipclassifier.c
index 20bf8b6..45683ec 100644
--- a/usr/src/uts/common/inet/ip/ipclassifier.c
+++ b/usr/src/uts/common/inet/ip/ipclassifier.c
@@ -1019,8 +1019,8 @@
ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
ASSERT(connp != NULL);
- ASSERT(!connp->conn_mac_exempt || protocol == IPPROTO_AH ||
- protocol == IPPROTO_ESP);
+ ASSERT((connp->conn_mac_mode == CONN_MAC_DEFAULT) ||
+ protocol == IPPROTO_AH || protocol == IPPROTO_ESP);
connp->conn_ulp = protocol;
@@ -1036,8 +1036,8 @@
ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
ASSERT(connp != NULL);
- ASSERT(!connp->conn_mac_exempt || protocol == IPPROTO_AH ||
- protocol == IPPROTO_ESP);
+ ASSERT((connp->conn_mac_mode == CONN_MAC_DEFAULT) ||
+ protocol == IPPROTO_AH || protocol == IPPROTO_ESP);
connp->conn_ulp = protocol;
@@ -1221,7 +1221,8 @@
if (connp->conn_af_isv6 != tconn->conn_af_isv6)
continue;
/* If neither is exempt, then there's no conflict */
- if (!connp->conn_mac_exempt && !tconn->conn_mac_exempt)
+ if ((connp->conn_mac_mode == CONN_MAC_DEFAULT) &&
+ (tconn->conn_mac_mode == CONN_MAC_DEFAULT))
continue;
/* We are only concerned about sockets for a different zone */
if (connp->conn_zoneid == tconn->conn_zoneid)
@@ -1252,7 +1253,8 @@
if (connp->conn_af_isv6 != tconn->conn_af_isv6)
continue;
/* If neither is exempt, then there's no conflict */
- if (!connp->conn_mac_exempt && !tconn->conn_mac_exempt)
+ if ((connp->conn_mac_mode == CONN_MAC_DEFAULT) &&
+ (tconn->conn_mac_mode == CONN_MAC_DEFAULT))
continue;
/* We are only concerned about sockets for a different zone */
if (connp->conn_zoneid == tconn->conn_zoneid)
@@ -1751,8 +1753,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 &&
- shared_addr)))
+ (unlabeled && shared_addr &&
+ (connp->conn_mac_mode != CONN_MAC_DEFAULT))))
break;
}
@@ -1828,8 +1830,8 @@
if (IPCL_UDP_MATCH(connp, lport, ipha->ipha_dst,
fport, ipha->ipha_src) &&
(IPCL_ZONE_MATCH(connp, zoneid) ||
- (unlabeled && connp->conn_mac_exempt &&
- shared_addr)))
+ (unlabeled && shared_addr &&
+ (connp->conn_mac_mode != CONN_MAC_DEFAULT))))
break;
}
@@ -1957,8 +1959,8 @@
if (IPCL_BIND_MATCH_V6(connp, protocol,
ip6h->ip6_dst, lport) &&
(IPCL_ZONE_MATCH(connp, zoneid) ||
- (unlabeled && connp->conn_mac_exempt &&
- shared_addr)))
+ (unlabeled && shared_addr &&
+ (connp->conn_mac_mode != CONN_MAC_DEFAULT))))
break;
}
@@ -2033,8 +2035,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 &&
- shared_addr)))
+ (unlabeled && shared_addr &&
+ (connp->conn_mac_mode != CONN_MAC_DEFAULT))))
break;
}
@@ -2180,7 +2182,9 @@
}
if (IPCL_ZONE_MATCH(connp, zoneid) ||
- (unlabeled && connp->conn_mac_exempt && shared_addr))
+ (unlabeled &&
+ (connp->conn_mac_mode != CONN_MAC_DEFAULT) &&
+ shared_addr))
break;
}
/*
diff --git a/usr/src/uts/common/inet/ip/ipsecah.c b/usr/src/uts/common/inet/ip/ipsecah.c
index 8476f2e..c130dac 100644
--- a/usr/src/uts/common/inet/ip/ipsecah.c
+++ b/usr/src/uts/common/inet/ip/ipsecah.c
@@ -70,6 +70,8 @@
#include <sys/kstat.h>
#include <sys/strsubr.h>
+#include <sys/tsol/tnet.h>
+
/*
* Table of ND variables supported by ipsecah. These are loaded into
* ipsecah_g_nd in ipsecah_init_nd.
@@ -148,7 +150,8 @@
static void ipsecah_rput(queue_t *, mblk_t *);
static void ipsecah_wput(queue_t *, mblk_t *);
static void ah_send_acquire(ipsacq_t *, mblk_t *, netstack_t *);
-static boolean_t ah_register_out(uint32_t, uint32_t, uint_t, ipsecah_stack_t *);
+static boolean_t ah_register_out(uint32_t, uint32_t, uint_t, ipsecah_stack_t *,
+ mblk_t *);
static void *ipsecah_stack_init(netstackid_t stackid, netstack_t *ns);
static void ipsecah_stack_fini(netstackid_t stackid, void *arg);
@@ -673,7 +676,7 @@
*/
static boolean_t
ah_register_out(uint32_t sequence, uint32_t pid, uint_t serial,
- ipsecah_stack_t *ahstack)
+ ipsecah_stack_t *ahstack, mblk_t *in_mp)
{
mblk_t *mp;
boolean_t rc = B_TRUE;
@@ -685,6 +688,10 @@
ipsec_alginfo_t **authalgs;
uint_t num_aalgs;
ipsec_stack_t *ipss = ahstack->ipsecah_netstack->netstack_ipsec;
+ sadb_sens_t *sens;
+ size_t sens_len = 0;
+ sadb_ext_t *nextext;
+ cred_t *sens_cr = NULL;
/* Allocate the KEYSOCK_OUT. */
mp = sadb_keysock_out(serial);
@@ -693,6 +700,15 @@
return (B_FALSE);
}
+ if (is_system_labeled() && (in_mp != NULL)) {
+ sens_cr = msg_getcred(in_mp, NULL);
+
+ if (sens_cr != NULL) {
+ sens_len = sadb_sens_len_from_cred(sens_cr);
+ allocsize += sens_len;
+ }
+ }
+
/*
* Allocate the PF_KEY message that follows KEYSOCK_OUT.
* The alg reader lock needs to be held while allocating
@@ -727,10 +743,11 @@
}
mp->b_cont->b_wptr += allocsize;
+ nextext = (sadb_ext_t *)(mp->b_cont->b_rptr + sizeof (*samsg));
+
if (num_aalgs != 0) {
- saalg = (sadb_alg_t *)(mp->b_cont->b_rptr + sizeof (*samsg) +
- sizeof (*sasupp));
+ saalg = (sadb_alg_t *)(((uint8_t *)nextext) + sizeof (*sasupp));
ASSERT(((ulong_t)saalg & 0x7) == 0);
numalgs_snap = 0;
@@ -764,10 +781,19 @@
cmn_err(CE_PANIC,
"ah_register_out()! Missed #%d.\n", i);
#endif /* DEBUG */
+ nextext = (sadb_ext_t *)saalg;
}
mutex_exit(&ipss->ipsec_alg_lock);
+ if (sens_cr != NULL) {
+ sens = (sadb_sens_t *)nextext;
+ sadb_sens_from_cred(sens, SADB_EXT_SENSITIVITY,
+ sens_cr, sens_len);
+
+ nextext = (sadb_ext_t *)(((uint8_t *)sens) + sens_len);
+ }
+
/* Now fill the restof the SADB_REGISTER message. */
samsg = (sadb_msg_t *)mp->b_cont->b_rptr;
@@ -784,10 +810,10 @@
samsg->sadb_msg_seq = sequence;
samsg->sadb_msg_pid = pid;
- if (allocsize > sizeof (*samsg)) {
+ if (num_aalgs != 0) {
sasupp = (sadb_supported_t *)(samsg + 1);
- sasupp->sadb_supported_len =
- SADB_8TO64(allocsize - sizeof (sadb_msg_t));
+ sasupp->sadb_supported_len = SADB_8TO64(
+ sizeof (*sasupp) + sizeof (*saalg) * num_aalgs);
sasupp->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH;
sasupp->sadb_supported_reserved = 0;
}
@@ -816,7 +842,7 @@
* Time to send a PF_KEY SADB_REGISTER message to AH listeners
* everywhere. (The function itself checks for NULL ah_pfkey_q.)
*/
- (void) ah_register_out(0, 0, 0, ahstack);
+ (void) ah_register_out(0, 0, 0, ahstack, NULL);
}
/*
@@ -865,22 +891,17 @@
ah_add_sa_finish(mblk_t *mp, sadb_msg_t *samsg, keysock_in_t *ksi,
int *diagnostic, ipsecah_stack_t *ahstack)
{
- isaf_t *primary = NULL, *secondary, *inbound, *outbound;
+ isaf_t *primary = NULL, *secondary;
+ boolean_t clone = B_FALSE, is_inbound = B_FALSE;
sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
- sadb_address_t *dstext =
- (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
- struct sockaddr_in *dst;
- struct sockaddr_in6 *dst6;
- boolean_t is_ipv4, clone = B_FALSE, is_inbound = B_FALSE;
- uint32_t *dstaddr;
ipsa_t *larval;
ipsacq_t *acqrec;
iacqf_t *acq_bucket;
mblk_t *acq_msgs = NULL;
mblk_t *lpkt;
int rc;
- sadb_t *sp;
- int outhash;
+ ipsa_query_t sq;
+ int error;
netstack_t *ns = ahstack->ipsecah_netstack;
ipsec_stack_t *ipss = ns->netstack_ipsec;
@@ -888,22 +909,13 @@
* Locate the appropriate table(s).
*/
- dst = (struct sockaddr_in *)(dstext + 1);
- dst6 = (struct sockaddr_in6 *)dst;
- is_ipv4 = (dst->sin_family == AF_INET);
- if (is_ipv4) {
- sp = &ahstack->ah_sadb.s_v4;
- dstaddr = (uint32_t *)(&dst->sin_addr);
- outhash = OUTBOUND_HASH_V4(sp, *(ipaddr_t *)dstaddr);
- } else {
- ASSERT(dst->sin_family == AF_INET6);
- sp = &ahstack->ah_sadb.s_v6;
- dstaddr = (uint32_t *)(&dst6->sin6_addr);
- outhash = OUTBOUND_HASH_V6(sp, *(in6_addr_t *)dstaddr);
- }
+ sq.spp = &ahstack->ah_sadb;
+ error = sadb_form_query(ksi, IPSA_Q_SA|IPSA_Q_DST,
+ IPSA_Q_SA|IPSA_Q_DST|IPSA_Q_INBOUND|IPSA_Q_OUTBOUND,
+ &sq, diagnostic);
+ if (error)
+ return (error);
- inbound = INBOUND_BUCKET(sp, assoc->sadb_sa_spi);
- outbound = &sp->sdb_of[outhash];
/*
* Use the direction flags provided by the KMD to determine
* if the inbound or outbound table should be the primary
@@ -911,18 +923,17 @@
* decision based on the addresses.
*/
if (assoc->sadb_sa_flags & IPSA_F_INBOUND) {
- primary = inbound;
- secondary = outbound;
+ primary = sq.inbound;
+ secondary = sq.outbound;
is_inbound = B_TRUE;
if (assoc->sadb_sa_flags & IPSA_F_OUTBOUND)
clone = B_TRUE;
} else {
if (assoc->sadb_sa_flags & IPSA_F_OUTBOUND) {
- primary = outbound;
- secondary = inbound;
+ primary = sq.outbound;
+ secondary = sq.inbound;
}
}
-
if (primary == NULL) {
/*
* The KMD did not set a direction flag, determine which
@@ -943,12 +954,13 @@
*/
case KS_IN_ADDR_ME:
assoc->sadb_sa_flags |= IPSA_F_INBOUND;
- primary = inbound;
- secondary = outbound;
+ primary = sq.inbound;
+ secondary = sq.outbound;
if (ksi->ks_in_srctype != KS_IN_ADDR_NOTME)
clone = B_TRUE;
is_inbound = B_TRUE;
break;
+
/*
* If the source address literally not mine (either
* unspecified or not mine), then this SA may have an
@@ -958,8 +970,8 @@
*/
case KS_IN_ADDR_NOTME:
assoc->sadb_sa_flags |= IPSA_F_OUTBOUND;
- primary = outbound;
- secondary = inbound;
+ primary = sq.outbound;
+ secondary = sq.inbound;
if (ksi->ks_in_srctype != KS_IN_ADDR_ME) {
assoc->sadb_sa_flags |= IPSA_F_INBOUND;
clone = B_TRUE;
@@ -980,7 +992,7 @@
*/
if (samsg->sadb_msg_seq & IACQF_LOWEST_SEQ) {
- acq_bucket = &sp->sdb_acq[outhash];
+ acq_bucket = &(sq.sp->sdb_acq[sq.outhash]);
mutex_enter(&acq_bucket->iacqf_lock);
for (acqrec = acq_bucket->iacqf_ipsacq; acqrec != NULL;
acqrec = acqrec->ipsacq_next) {
@@ -991,7 +1003,7 @@
* that are queued up.
*/
if (acqrec->ipsacq_seq == samsg->sadb_msg_seq &&
- IPSA_ARE_ADDR_EQUAL(dstaddr,
+ IPSA_ARE_ADDR_EQUAL(sq.dstaddr,
acqrec->ipsacq_dstaddr, acqrec->ipsacq_addrfam))
break;
mutex_exit(&acqrec->ipsacq_lock);
@@ -1019,10 +1031,10 @@
larval = NULL;
if (samsg->sadb_msg_type == SADB_UPDATE) {
- mutex_enter(&inbound->isaf_lock);
- larval = ipsec_getassocbyspi(inbound, assoc->sadb_sa_spi,
- ALL_ZEROES_PTR, dstaddr, dst->sin_family);
- mutex_exit(&inbound->isaf_lock);
+ mutex_enter(&sq.inbound->isaf_lock);
+ larval = ipsec_getassocbyspi(sq.inbound, sq.assoc->sadb_sa_spi,
+ ALL_ZEROES_PTR, sq.dstaddr, sq.dst->sin_family);
+ mutex_exit(&sq.inbound->isaf_lock);
if ((larval == NULL) ||
(larval->ipsa_state != IPSA_STATE_LARVAL)) {
@@ -1071,11 +1083,14 @@
if (ah_outbound(mp) == IPSEC_STATUS_SUCCESS) {
ipha_t *ipha = (ipha_t *)
mp->b_cont->b_rptr;
- if (is_ipv4) {
+ if (sq.af == AF_INET) {
ip_wput_ipsec_out(NULL, mp,
ipha, NULL, NULL);
} else {
ip6_t *ip6h = (ip6_t *)ipha;
+
+ ASSERT(sq.af == AF_INET6);
+
ip_wput_ipsec_out_v6(NULL,
mp, ip6h, NULL, NULL);
}
@@ -1172,14 +1187,22 @@
ASSERT(src->sin_family == dst->sin_family);
/* Stuff I don't support, for now. XXX Diagnostic? */
- if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL ||
- ksi->ks_in_extv[SADB_EXT_SENSITIVITY] != NULL)
+ if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL)
return (EOPNOTSUPP);
+ if (ksi->ks_in_extv[SADB_EXT_SENSITIVITY] != NULL) {
+ if (!is_system_labeled())
+ return (EOPNOTSUPP);
+ }
+
+ if (ksi->ks_in_extv[SADB_X_EXT_OUTER_SENS] != NULL) {
+ if (!is_system_labeled())
+ return (EOPNOTSUPP);
+ }
/*
- * XXX Policy : I'm not checking identities or sensitivity
- * labels at this time, but if I did, I'd do them here, before I sent
- * the weak key check up to the algorithm.
+ * XXX Policy : I'm not checking identities at this time, but
+ * if I did, I'd do them here, before I sent the weak key
+ * check up to the algorithm.
*/
/* verify that there is a mapping for the specified algorithm */
@@ -1214,6 +1237,7 @@
diagnostic, ahstack));
}
+/* Refactor me */
/*
* Update a security association. Updates come in two varieties. The first
* is an update of lifetimes on a non-larval SA. The second is an update of
@@ -1249,6 +1273,7 @@
return (rcode);
}
+/* Refactor me */
/*
* Delete a security association. This is REALLY likely to be code common to
* both AH and ESP. Find the association, then unlink it.
@@ -1275,14 +1300,15 @@
}
return (sadb_purge_sa(mp, ksi,
(sin->sin_family == AF_INET6) ? &ahstack->ah_sadb.s_v6 :
- &ahstack->ah_sadb.s_v4,
- ahstack->ah_pfkey_q, ahstack->ah_sadb.s_ip_q));
+ &ahstack->ah_sadb.s_v4, diagnostic, ahstack->ah_pfkey_q,
+ ahstack->ah_sadb.s_ip_q));
}
return (sadb_delget_sa(mp, ksi, &ahstack->ah_sadb, diagnostic,
ahstack->ah_pfkey_q, sadb_msg_type));
}
+/* Refactor me */
/*
* Convert the entire contents of all of AH's SA tables into PF_KEY SADB_DUMP
* messages.
@@ -1423,7 +1449,7 @@
* Keysock takes care of the PF_KEY bookkeeping for this.
*/
if (ah_register_out(samsg->sadb_msg_seq, samsg->sadb_msg_pid,
- ksi->ks_in_serial, ahstack)) {
+ ksi->ks_in_serial, ahstack, mp)) {
freemsg(mp);
} else {
/*
@@ -1595,6 +1621,7 @@
}
}
+/* Refactor me */
/*
* Updating use times can be tricky business if the ipsa_haspeer flag is
* set. This function is called once in an SA's lifetime.
@@ -1693,6 +1720,7 @@
}
}
+/* Refactor me */
/*
* Add a number of bytes to what the SA has protected so far. Return
* B_TRUE if the SA can still protect that many bytes.
@@ -1953,6 +1981,7 @@
putnext(ahstack->ah_pfkey_q, pfkeymp);
}
+/* Refactor me */
/*
* Handle the SADB_GETSPI message. Create a larval SA.
*/
@@ -3386,6 +3415,27 @@
assoc = oi->ipsec_out_ah_sa;
ASSERT(assoc != NULL);
+
+ /*
+ * Get the outer IP header in shape to escape this system..
+ */
+ if (is_system_labeled() && (assoc->ipsa_ocred != NULL)) {
+ int whack;
+
+ mblk_setcred(mp, assoc->ipsa_ocred, NOPID);
+ if (oi->ipsec_out_v4)
+ whack = sadb_whack_label(&mp, assoc);
+ else
+ whack = sadb_whack_label_v6(&mp, assoc);
+ if (whack != 0) {
+ ip_drop_packet(ipsec_out, B_FALSE, NULL,
+ NULL, DROPPER(ipss, ipds_ah_nomem),
+ &ahstack->ah_dropper);
+ return (IPSEC_STATUS_FAILED);
+ }
+ ipsec_out->b_cont = mp;
+ }
+
/*
* Age SA according to number of bytes that will be sent after
* adding the AH header, ICV, and padding to the packet.
@@ -3415,6 +3465,11 @@
return (IPSEC_STATUS_FAILED);
}
+ /*
+ * XXX We need to have fixed up the outer label before we get here.
+ * (AH is computing the checksum over the outer label).
+ */
+
if (oi->ipsec_out_is_capab_ill) {
ah3dbg(ahstack, ("ah_outbound: pkt can be accelerated\n"));
if (oi->ipsec_out_v4)
@@ -4237,14 +4292,22 @@
while (--dest >= mp->b_rptr)
*dest = *(dest - newpos);
}
+ ipsec_in->b_cont = mp;
+ phdr_mp->b_cont = NULL;
/*
* If a db_credp exists in phdr_mp, it must also exist in mp.
*/
ASSERT(DB_CRED(phdr_mp) == NULL ||
msg_getcred(mp, NULL) != NULL);
-
freeb(phdr_mp);
- ipsec_in->b_cont = mp;
+
+ /*
+ * If SA is labelled, use its label, else inherit the label
+ */
+ if (is_system_labeled() && (assoc->ipsa_cred != NULL)) {
+ mblk_setcred(mp, assoc->ipsa_cred, NOPID);
+ }
+
if (assoc->ipsa_state == IPSA_STATE_IDLE) {
/*
* Cluster buffering case. Tell caller that we're
@@ -4253,6 +4316,7 @@
sadb_buf_pkt(assoc, ipsec_in, ns);
return (IPSEC_STATUS_PENDING);
}
+
return (IPSEC_STATUS_SUCCESS);
ah_in_discard:
@@ -4393,6 +4457,7 @@
return (IPSEC_STATUS_SUCCESS);
}
+/* Refactor me */
/*
* Wrapper to allow IP to trigger an AH association failure message
* during SA inbound selection.
diff --git a/usr/src/uts/common/inet/ip/ipsecesp.c b/usr/src/uts/common/inet/ip/ipsecesp.c
index e05f172..089e23e 100644
--- a/usr/src/uts/common/inet/ip/ipsecesp.c
+++ b/usr/src/uts/common/inet/ip/ipsecesp.c
@@ -62,12 +62,15 @@
#include <sys/kstat.h>
#include <sys/policy.h>
#include <sys/strsun.h>
+#include <sys/strsubr.h>
#include <inet/udp_impl.h>
#include <sys/taskq.h>
#include <sys/note.h>
#include <sys/iphada.h>
+#include <sys/tsol/tnet.h>
+
/*
* Table of ND variables supported by ipsecesp. These are loaded into
* ipsecesp_g_nd in ipsecesp_init_nd.
@@ -139,7 +142,7 @@
boolean_t, ipsa_t *);
static boolean_t esp_register_out(uint32_t, uint32_t, uint_t,
- ipsecesp_stack_t *);
+ ipsecesp_stack_t *, mblk_t *);
static boolean_t esp_strip_header(mblk_t *, boolean_t, uint32_t,
kstat_named_t **, ipsecesp_stack_t *);
static ipsec_status_t esp_submit_req_inbound(mblk_t *, ipsa_t *, uint_t);
@@ -1473,6 +1476,7 @@
putnext(espstack->esp_pfkey_q, pfkeymp);
}
+/* XXX refactor me */
/*
* Handle the SADB_GETSPI message. Create a larval SA.
*/
@@ -1861,9 +1865,20 @@
if (esp_strip_header(data_mp, ii->ipsec_in_v4, ivlen, &counter,
espstack)) {
+
+ if (is_system_labeled()) {
+ cred_t *cr = assoc->ipsa_cred;
+
+ if (cr != NULL) {
+ mblk_setcred(data_mp, cr, NOPID);
+ }
+
+ }
if (is_natt)
return (esp_fix_natt_checksums(data_mp, assoc));
+ ASSERT(!is_system_labeled() || (DB_CRED(data_mp) != NULL));
+
if (assoc->ipsa_state == IPSA_STATE_IDLE) {
/*
* Cluster buffering case. Tell caller that we're
@@ -2665,10 +2680,33 @@
data_mp = ipsec_out_mp->b_cont;
}
+ assoc = io->ipsec_out_esp_sa;
+ ASSERT(assoc != NULL);
+
+ /*
+ * Get the outer IP header in shape to escape this system..
+ */
+ if (is_system_labeled() && (assoc->ipsa_ocred != NULL)) {
+ int whack;
+
+ mblk_setcred(data_mp, assoc->ipsa_ocred, NOPID);
+ if (io->ipsec_out_v4)
+ whack = sadb_whack_label(&data_mp, assoc);
+ else
+ whack = sadb_whack_label_v6(&data_mp, assoc);
+ if (whack != 0) {
+ ip_drop_packet(ipsec_out_mp, B_FALSE, NULL,
+ NULL, DROPPER(ipss, ipds_esp_nomem),
+ &espstack->esp_dropper);
+ return (IPSEC_STATUS_FAILED);
+ }
+ ipsec_out_mp->b_cont = data_mp;
+ }
+
+
/*
* Reality check....
*/
-
ipha = (ipha_t *)data_mp->b_rptr; /* So we can call esp_acquire(). */
if (io->ipsec_out_v4) {
@@ -2710,13 +2748,11 @@
nhp = &ip6h->ip6_nxt;
}
}
- assoc = io->ipsec_out_esp_sa;
- ASSERT(assoc != NULL);
mac_len = assoc->ipsa_mac_len;
if (assoc->ipsa_flags & IPSA_F_NATT) {
- /* wedge in fake UDP */
+ /* wedge in UDP header */
is_natt = B_TRUE;
esplen += UDPH_SIZE;
}
@@ -3066,7 +3102,7 @@
*/
static boolean_t
esp_register_out(uint32_t sequence, uint32_t pid, uint_t serial,
- ipsecesp_stack_t *espstack)
+ ipsecesp_stack_t *espstack, mblk_t *in_mp)
{
mblk_t *pfkey_msg_mp, *keysock_out_mp;
sadb_msg_t *samsg;
@@ -3082,6 +3118,10 @@
ipsec_alginfo_t **encralgs;
uint_t num_ealgs;
ipsec_stack_t *ipss = espstack->ipsecesp_netstack->netstack_ipsec;
+ sadb_sens_t *sens;
+ size_t sens_len = 0;
+ sadb_ext_t *nextext;
+ cred_t *sens_cr = NULL;
/* Allocate the KEYSOCK_OUT. */
keysock_out_mp = sadb_keysock_out(serial);
@@ -3090,12 +3130,20 @@
return (B_FALSE);
}
+ if (is_system_labeled() && (in_mp != NULL)) {
+ sens_cr = msg_getcred(in_mp, NULL);
+
+ if (sens_cr != NULL) {
+ sens_len = sadb_sens_len_from_cred(sens_cr);
+ allocsize += sens_len;
+ }
+ }
+
/*
* Allocate the PF_KEY message that follows KEYSOCK_OUT.
*/
mutex_enter(&ipss->ipsec_alg_lock);
-
/*
* Fill SADB_REGISTER message's algorithm descriptors. Hold
* down the lock while filling it.
@@ -3128,12 +3176,13 @@
freemsg(keysock_out_mp);
return (B_FALSE);
}
-
pfkey_msg_mp = keysock_out_mp->b_cont;
pfkey_msg_mp->b_wptr += allocsize;
+
+ nextext = (sadb_ext_t *)(pfkey_msg_mp->b_rptr + sizeof (*samsg));
+
if (num_aalgs != 0) {
- sasupp_auth = (sadb_supported_t *)
- (pfkey_msg_mp->b_rptr + sizeof (*samsg));
+ sasupp_auth = (sadb_supported_t *)nextext;
saalg = (sadb_alg_t *)(sasupp_auth + 1);
ASSERT(((ulong_t)saalg & 0x7) == 0);
@@ -3169,12 +3218,11 @@
}
}
#endif /* DEBUG */
- } else {
- saalg = (sadb_alg_t *)(pfkey_msg_mp->b_rptr + sizeof (*samsg));
+ nextext = (sadb_ext_t *)saalg;
}
if (num_ealgs != 0) {
- sasupp_encr = (sadb_supported_t *)saalg;
+ sasupp_encr = (sadb_supported_t *)nextext;
saalg = (sadb_alg_t *)(sasupp_encr + 1);
numalgs_snap = 0;
@@ -3212,6 +3260,7 @@
}
}
#endif /* DEBUG */
+ nextext = (sadb_ext_t *)saalg;
}
current_aalgs = num_aalgs;
@@ -3219,6 +3268,14 @@
mutex_exit(&ipss->ipsec_alg_lock);
+ if (sens_cr != NULL) {
+ sens = (sadb_sens_t *)nextext;
+ sadb_sens_from_cred(sens, SADB_EXT_SENSITIVITY,
+ sens_cr, sens_len);
+
+ nextext = (sadb_ext_t *)(((uint8_t *)sens) + sens_len);
+ }
+
/* Now fill the rest of the SADB_REGISTER message. */
samsg = (sadb_msg_t *)pfkey_msg_mp->b_rptr;
@@ -3274,7 +3331,7 @@
* Time to send a PF_KEY SADB_REGISTER message to ESP listeners
* everywhere. (The function itself checks for NULL esp_pfkey_q.)
*/
- (void) esp_register_out(0, 0, 0, espstack);
+ (void) esp_register_out(0, 0, 0, espstack, NULL);
}
/*
@@ -3323,43 +3380,27 @@
esp_add_sa_finish(mblk_t *mp, sadb_msg_t *samsg, keysock_in_t *ksi,
int *diagnostic, ipsecesp_stack_t *espstack)
{
- isaf_t *primary = NULL, *secondary, *inbound, *outbound;
- sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
- sadb_address_t *dstext =
- (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
- struct sockaddr_in *dst;
- struct sockaddr_in6 *dst6;
- boolean_t is_ipv4, clone = B_FALSE, is_inbound = B_FALSE;
- uint32_t *dstaddr;
+ isaf_t *primary = NULL, *secondary;
+ boolean_t clone = B_FALSE, is_inbound = B_FALSE;
ipsa_t *larval = NULL;
ipsacq_t *acqrec;
iacqf_t *acq_bucket;
mblk_t *acq_msgs = NULL;
int rc;
- sadb_t *sp;
- int outhash;
mblk_t *lpkt;
+ int error;
+ ipsa_query_t sq;
ipsec_stack_t *ipss = espstack->ipsecesp_netstack->netstack_ipsec;
/*
* Locate the appropriate table(s).
*/
-
- dst = (struct sockaddr_in *)(dstext + 1);
- dst6 = (struct sockaddr_in6 *)dst;
- is_ipv4 = (dst->sin_family == AF_INET);
- if (is_ipv4) {
- sp = &espstack->esp_sadb.s_v4;
- dstaddr = (uint32_t *)(&dst->sin_addr);
- outhash = OUTBOUND_HASH_V4(sp, *(ipaddr_t *)dstaddr);
- } else {
- sp = &espstack->esp_sadb.s_v6;
- dstaddr = (uint32_t *)(&dst6->sin6_addr);
- outhash = OUTBOUND_HASH_V6(sp, *(in6_addr_t *)dstaddr);
- }
-
- inbound = INBOUND_BUCKET(sp, assoc->sadb_sa_spi);
- outbound = &sp->sdb_of[outhash];
+ sq.spp = &espstack->esp_sadb; /* XXX */
+ error = sadb_form_query(ksi, IPSA_Q_SA|IPSA_Q_DST,
+ IPSA_Q_SA|IPSA_Q_DST|IPSA_Q_INBOUND|IPSA_Q_OUTBOUND,
+ &sq, diagnostic);
+ if (error)
+ return (error);
/*
* Use the direction flags provided by the KMD to determine
@@ -3367,17 +3408,15 @@
* for this SA. If these flags were absent then make this
* decision based on the addresses.
*/
- if (assoc->sadb_sa_flags & IPSA_F_INBOUND) {
- primary = inbound;
- secondary = outbound;
+ if (sq.assoc->sadb_sa_flags & IPSA_F_INBOUND) {
+ primary = sq.inbound;
+ secondary = sq.outbound;
is_inbound = B_TRUE;
- if (assoc->sadb_sa_flags & IPSA_F_OUTBOUND)
+ if (sq.assoc->sadb_sa_flags & IPSA_F_OUTBOUND)
clone = B_TRUE;
- } else {
- if (assoc->sadb_sa_flags & IPSA_F_OUTBOUND) {
- primary = outbound;
- secondary = inbound;
- }
+ } else if (sq.assoc->sadb_sa_flags & IPSA_F_OUTBOUND) {
+ primary = sq.outbound;
+ secondary = sq.inbound;
}
if (primary == NULL) {
@@ -3388,7 +3427,7 @@
switch (ksi->ks_in_dsttype) {
case KS_IN_ADDR_MBCAST:
clone = B_TRUE; /* All mcast SAs can be bidirectional */
- assoc->sadb_sa_flags |= IPSA_F_OUTBOUND;
+ sq.assoc->sadb_sa_flags |= IPSA_F_OUTBOUND;
/* FALLTHRU */
/*
* If the source address is either one of mine, or unspecified
@@ -3399,9 +3438,9 @@
* SA (which allows me to receive the outbound traffic).
*/
case KS_IN_ADDR_ME:
- assoc->sadb_sa_flags |= IPSA_F_INBOUND;
- primary = inbound;
- secondary = outbound;
+ sq.assoc->sadb_sa_flags |= IPSA_F_INBOUND;
+ primary = sq.inbound;
+ secondary = sq.outbound;
if (ksi->ks_in_srctype != KS_IN_ADDR_NOTME)
clone = B_TRUE;
is_inbound = B_TRUE;
@@ -3414,11 +3453,11 @@
* SA.
*/
case KS_IN_ADDR_NOTME:
- assoc->sadb_sa_flags |= IPSA_F_OUTBOUND;
- primary = outbound;
- secondary = inbound;
+ sq.assoc->sadb_sa_flags |= IPSA_F_OUTBOUND;
+ primary = sq.outbound;
+ secondary = sq.inbound;
if (ksi->ks_in_srctype != KS_IN_ADDR_ME) {
- assoc->sadb_sa_flags |= IPSA_F_INBOUND;
+ sq.assoc->sadb_sa_flags |= IPSA_F_INBOUND;
clone = B_TRUE;
}
break;
@@ -3437,7 +3476,7 @@
*/
if (samsg->sadb_msg_seq & IACQF_LOWEST_SEQ) {
- acq_bucket = &sp->sdb_acq[outhash];
+ acq_bucket = &(sq.sp->sdb_acq[sq.outhash]);
mutex_enter(&acq_bucket->iacqf_lock);
for (acqrec = acq_bucket->iacqf_ipsacq; acqrec != NULL;
acqrec = acqrec->ipsacq_next) {
@@ -3448,7 +3487,7 @@
* that are queued up.
*/
if (acqrec->ipsacq_seq == samsg->sadb_msg_seq &&
- IPSA_ARE_ADDR_EQUAL(dstaddr,
+ IPSA_ARE_ADDR_EQUAL(sq.dstaddr,
acqrec->ipsacq_dstaddr, acqrec->ipsacq_addrfam))
break;
mutex_exit(&acqrec->ipsacq_lock);
@@ -3473,12 +3512,11 @@
* Find PF_KEY message, and see if I'm an update. If so, find entry
* in larval list (if there).
*/
-
if (samsg->sadb_msg_type == SADB_UPDATE) {
- mutex_enter(&inbound->isaf_lock);
- larval = ipsec_getassocbyspi(inbound, assoc->sadb_sa_spi,
- ALL_ZEROES_PTR, dstaddr, dst->sin_family);
- mutex_exit(&inbound->isaf_lock);
+ mutex_enter(&sq.inbound->isaf_lock);
+ larval = ipsec_getassocbyspi(sq.inbound, sq.assoc->sadb_sa_spi,
+ ALL_ZEROES_PTR, sq.dstaddr, sq.dst->sin_family);
+ mutex_exit(&sq.inbound->isaf_lock);
if ((larval == NULL) ||
(larval->ipsa_state != IPSA_STATE_LARVAL)) {
@@ -3532,7 +3570,8 @@
ipha = (ipha_t *)mp->b_cont->b_rptr;
/* finish IPsec processing */
- if (is_ipv4) {
+ if (IPH_HDR_VERSION(ipha) ==
+ IP_VERSION) {
ip_wput_ipsec_out(NULL, mp,
ipha, NULL, NULL);
} else {
@@ -3587,6 +3626,8 @@
ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
ipsec_stack_t *ipss = ns->netstack_ipsec;
+
+
/* I need certain extensions present for an ADD message. */
if (srcext == NULL) {
*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
@@ -3676,13 +3717,15 @@
/* Stuff I don't support, for now. XXX Diagnostic? */
- if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL ||
- ksi->ks_in_extv[SADB_EXT_SENSITIVITY] != NULL)
+ if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL)
return (EOPNOTSUPP);
+ if ((*diagnostic = sadb_labelchk(ksi)) != 0)
+ return (EINVAL);
+
/*
- * XXX Policy : I'm not checking identities or sensitivity
- * labels at this time, but if I did, I'd do them here, before I sent
+ * XXX Policy : I'm not checking identities at this time,
+ * but if I did, I'd do them here, before I sent
* the weak key check up to the algorithm.
*/
@@ -3812,6 +3855,7 @@
return (rcode);
}
+/* XXX refactor me */
/*
* Delete a security association. This is REALLY likely to be code common to
* both AH and ESP. Find the association, then unlink it.
@@ -3838,14 +3882,15 @@
}
return (sadb_purge_sa(mp, ksi,
(sin->sin_family == AF_INET6) ? &espstack->esp_sadb.s_v6 :
- &espstack->esp_sadb.s_v4, espstack->esp_pfkey_q,
- espstack->esp_sadb.s_ip_q));
+ &espstack->esp_sadb.s_v4, diagnostic,
+ espstack->esp_pfkey_q, espstack->esp_sadb.s_ip_q));
}
return (sadb_delget_sa(mp, ksi, &espstack->esp_sadb, diagnostic,
espstack->esp_pfkey_q, sadb_msg_type));
}
+/* XXX refactor me */
/*
* Convert the entire contents of all of ESP's SA tables into PF_KEY SADB_DUMP
* messages.
@@ -3979,7 +4024,7 @@
* Keysock takes care of the PF_KEY bookkeeping for this.
*/
if (esp_register_out(samsg->sadb_msg_seq, samsg->sadb_msg_pid,
- ksi->ks_in_serial, espstack)) {
+ ksi->ks_in_serial, espstack, mp)) {
freemsg(mp);
} else {
/*
@@ -4332,6 +4377,9 @@
freeb(hada_mp);
+ if (is_system_labeled() && (assoc->ipsa_cred != NULL))
+ mblk_setcred(data_mp, assoc->ipsa_cred, NOPID);
+
/*
* Account for usage..
*/
diff --git a/usr/src/uts/common/inet/ip/sadb.c b/usr/src/uts/common/inet/ip/sadb.c
index e590b5c..314e5b8 100644
--- a/usr/src/uts/common/inet/ip/sadb.c
+++ b/usr/src/uts/common/inet/ip/sadb.c
@@ -60,10 +60,13 @@
#include <sys/random.h>
#include <sys/dlpi.h>
#include <sys/iphada.h>
+#include <sys/strsun.h>
+#include <sys/strsubr.h>
#include <inet/ip_if.h>
#include <inet/ipdrop.h>
#include <inet/ipclassifier.h>
#include <inet/sctp_ip.h>
+#include <sys/tsol/tnet.h>
/*
* This source file contains Security Association Database (SADB) common
@@ -72,7 +75,8 @@
*/
static mblk_t *sadb_extended_acquire(ipsec_selector_t *, ipsec_policy_t *,
- ipsec_action_t *, boolean_t, uint32_t, uint32_t, netstack_t *);
+ ipsec_action_t *, boolean_t, uint32_t, uint32_t, sadb_sens_t *,
+ netstack_t *);
static void sadb_ill_df(ill_t *, mblk_t *, isaf_t *, int, boolean_t);
static ipsa_t *sadb_torch_assoc(isaf_t *, ipsa_t *, boolean_t, mblk_t **);
static void sadb_drain_torchq(queue_t *, mblk_t *);
@@ -80,10 +84,16 @@
netstack_t *);
static void sadb_destroy(sadb_t *, netstack_t *);
static mblk_t *sadb_sa2msg(ipsa_t *, sadb_msg_t *);
+static cred_t *sadb_cred_from_sens(sadb_sens_t *, uint64_t *);
+static sadb_sens_t *sadb_make_sens_ext(cred_t *cr, int *len);
static time_t sadb_add_time(time_t, uint64_t);
static void lifetime_fuzz(ipsa_t *);
static void age_pair_peer_list(templist_t *, sadb_t *, boolean_t);
+static int get_ipsa_pair(ipsa_query_t *, ipsap_t *, int *);
+static void init_ipsa_pair(ipsap_t *);
+static void destroy_ipsa_pair(ipsap_t *);
+static int update_pairing(ipsap_t *, ipsa_query_t *, keysock_in_t *, int *);
static void ipsa_set_replay(ipsa_t *ipsa, uint32_t offset);
extern void (*cl_inet_getspi)(netstackid_t stack_id, uint8_t protocol,
@@ -271,6 +281,17 @@
ip_drop_packet(ipsa->ipsa_lpkt, B_TRUE, NULL, NULL,
DROPPER(ipss, ipds_sadb_inlarval_timeout),
&ipss->ipsec_sadb_dropper);
+
+ if (ipsa->ipsa_cred != NULL) {
+ crfree(ipsa->ipsa_cred);
+ ipsa->ipsa_cred = NULL;
+ }
+
+ if (ipsa->ipsa_ocred != NULL) {
+ crfree(ipsa->ipsa_ocred);
+ ipsa->ipsa_ocred = NULL;
+ }
+
ipsec_destroy_ctx_tmpl(ipsa, IPSEC_ALG_AUTH);
ipsec_destroy_ctx_tmpl(ipsa, IPSEC_ALG_ENCR);
mutex_exit(&ipsa->ipsa_lock);
@@ -294,10 +315,6 @@
if (ipsa->ipsa_dst_cid != NULL) {
IPSID_REFRELE(ipsa->ipsa_dst_cid);
}
- if (ipsa->ipsa_integ != NULL)
- kmem_free(ipsa->ipsa_integ, ipsa->ipsa_integlen);
- if (ipsa->ipsa_sens != NULL)
- kmem_free(ipsa->ipsa_sens, ipsa->ipsa_senslen);
if (ipsa->ipsa_emech.cm_param != NULL)
kmem_free(ipsa->ipsa_emech.cm_param,
ipsa->ipsa_emech.cm_param_len);
@@ -1201,6 +1218,25 @@
}
/*
+ * Sanity check sensitivity labels.
+ *
+ * For now, just reject labels on unlabeled systems.
+ */
+int
+sadb_labelchk(keysock_in_t *ksi)
+{
+ if (!is_system_labeled()) {
+ if (ksi->ks_in_extv[SADB_EXT_SENSITIVITY] != NULL)
+ return (SADB_X_DIAGNOSTIC_BAD_LABEL);
+
+ if (ksi->ks_in_extv[SADB_X_EXT_OUTER_SENS] != NULL)
+ return (SADB_X_DIAGNOSTIC_BAD_LABEL);
+ }
+
+ return (0);
+}
+
+/*
* Clone a security association for the purposes of inserting a single SA
* into inbound and outbound tables respectively. This function should only
* be called from sadb_common_add().
@@ -1223,6 +1259,12 @@
/* bzero and initialize locks, in case *_init() allocates... */
mutex_init(&newbie->ipsa_lock, NULL, MUTEX_DEFAULT, NULL);
+ if (newbie->ipsa_cred != NULL)
+ crhold(newbie->ipsa_cred);
+
+ if (newbie->ipsa_ocred != NULL)
+ crhold(newbie->ipsa_ocred);
+
/*
* While somewhat dain-bramaged, the most graceful way to
* recover from errors is to keep plowing through the
@@ -1268,28 +1310,6 @@
newbie->ipsa_encrtmpl = NULL;
newbie->ipsa_haspeer = B_TRUE;
- if (ipsa->ipsa_integ != NULL) {
- newbie->ipsa_integ = kmem_alloc(newbie->ipsa_integlen,
- KM_NOSLEEP);
- if (newbie->ipsa_integ == NULL) {
- error = B_TRUE;
- } else {
- bcopy(ipsa->ipsa_integ, newbie->ipsa_integ,
- newbie->ipsa_integlen);
- }
- }
-
- if (ipsa->ipsa_sens != NULL) {
- newbie->ipsa_sens = kmem_alloc(newbie->ipsa_senslen,
- KM_NOSLEEP);
- if (newbie->ipsa_sens == NULL) {
- error = B_TRUE;
- } else {
- bcopy(ipsa->ipsa_sens, newbie->ipsa_sens,
- newbie->ipsa_senslen);
- }
- }
-
if (ipsa->ipsa_src_cid != NULL) {
newbie->ipsa_src_cid = ipsa->ipsa_src_cid;
IPSID_REFHOLD(ipsa->ipsa_src_cid);
@@ -1407,7 +1427,7 @@
sadb_sa2msg(ipsa_t *ipsa, sadb_msg_t *samsg)
{
int alloclen, addrsize, paddrsize, authsize, encrsize;
- int srcidsize, dstidsize;
+ int srcidsize, dstidsize, senslen, osenslen;
sa_family_t fam, pfam; /* Address family for SADB_EXT_ADDRESS */
/* src/dst and proxy sockaddrs. */
/*
@@ -1425,16 +1445,18 @@
sadb_x_pair_t *pair_ext;
mblk_t *mp;
- uint64_t *bitmap;
uint8_t *cur, *end;
/* These indicate the presence of the above extension fields. */
- boolean_t soft, hard, isrc, idst, auth, encr, sensinteg, srcid, dstid;
+ boolean_t soft = B_FALSE, hard = B_FALSE;
+ boolean_t isrc = B_FALSE, idst = B_FALSE;
+ boolean_t auth = B_FALSE, encr = B_FALSE;
+ boolean_t sensinteg = B_FALSE, osensinteg = B_FALSE;
+ boolean_t srcid = B_FALSE, dstid = B_FALSE;
boolean_t idle;
boolean_t paired;
uint32_t otherspi;
/* First off, figure out the allocation length for this message. */
-
/*
* Constant stuff. This includes base, SA, address (src, dst),
* and lifetime (current).
@@ -1478,16 +1500,12 @@
ipsa->ipsa_softbyteslt != 0 || ipsa->ipsa_softalloc != 0) {
alloclen += sizeof (sadb_lifetime_t);
soft = B_TRUE;
- } else {
- soft = B_FALSE;
}
if (ipsa->ipsa_hardaddlt != 0 || ipsa->ipsa_harduselt != 0 ||
ipsa->ipsa_hardbyteslt != 0 || ipsa->ipsa_hardalloc != 0) {
alloclen += sizeof (sadb_lifetime_t);
hard = B_TRUE;
- } else {
- hard = B_FALSE;
}
if (ipsa->ipsa_idleaddlt != 0 || ipsa->ipsa_idleuselt != 0) {
@@ -1498,10 +1516,7 @@
}
/* Inner addresses. */
- if (ipsa->ipsa_innerfam == 0) {
- isrc = B_FALSE;
- idst = B_FALSE;
- } else {
+ if (ipsa->ipsa_innerfam != 0) {
pfam = ipsa->ipsa_innerfam;
switch (pfam) {
case AF_INET6:
@@ -1528,8 +1543,6 @@
sizeof (uint64_t));
alloclen += authsize;
auth = B_TRUE;
- } else {
- auth = B_FALSE;
}
if (ipsa->ipsa_encrkeylen != 0) {
@@ -1541,13 +1554,16 @@
encr = B_FALSE;
}
- /* No need for roundup on sens and integ. */
- if (ipsa->ipsa_integlen != 0 || ipsa->ipsa_senslen != 0) {
- alloclen += sizeof (sadb_key_t) + ipsa->ipsa_integlen +
- ipsa->ipsa_senslen;
+ if (ipsa->ipsa_cred != NULL) {
+ senslen = sadb_sens_len_from_cred(ipsa->ipsa_cred);
+ alloclen += senslen;
sensinteg = B_TRUE;
- } else {
- sensinteg = B_FALSE;
+ }
+
+ if (ipsa->ipsa_ocred != NULL) {
+ osenslen = sadb_sens_len_from_cred(ipsa->ipsa_ocred);
+ alloclen += osenslen;
+ osensinteg = B_TRUE;
}
/*
@@ -1560,8 +1576,6 @@
sizeof (uint64_t));
alloclen += srcidsize;
srcid = B_TRUE;
- } else {
- srcid = B_FALSE;
}
if (ipsa->ipsa_dst_cid != NULL) {
@@ -1570,8 +1584,6 @@
sizeof (uint64_t));
alloclen += dstidsize;
dstid = B_TRUE;
- } else {
- dstid = B_FALSE;
}
if ((ipsa->ipsa_kmp != 0) || (ipsa->ipsa_kmc != 0))
@@ -1588,6 +1600,7 @@
mp = allocb(alloclen, BPRI_HI);
if (mp == NULL)
return (NULL);
+ bzero(mp->b_rptr, alloclen);
mp->b_wptr += alloclen;
end = mp->b_wptr;
@@ -1779,21 +1792,21 @@
if (sensinteg) {
sens = (sadb_sens_t *)walker;
- sens->sadb_sens_len = SADB_8TO64(sizeof (sadb_sens_t *) +
- ipsa->ipsa_senslen + ipsa->ipsa_integlen);
- sens->sadb_sens_dpd = ipsa->ipsa_dpd;
- sens->sadb_sens_sens_level = ipsa->ipsa_senslevel;
- sens->sadb_sens_integ_level = ipsa->ipsa_integlevel;
- sens->sadb_sens_sens_len = SADB_8TO64(ipsa->ipsa_senslen);
- sens->sadb_sens_integ_len = SADB_8TO64(ipsa->ipsa_integlen);
- sens->sadb_sens_reserved = 0;
- bitmap = (uint64_t *)(sens + 1);
- if (ipsa->ipsa_sens != NULL) {
- bcopy(ipsa->ipsa_sens, bitmap, ipsa->ipsa_senslen);
- bitmap += sens->sadb_sens_sens_len;
- }
- if (ipsa->ipsa_integ != NULL)
- bcopy(ipsa->ipsa_integ, bitmap, ipsa->ipsa_integlen);
+ sadb_sens_from_cred(sens, SADB_EXT_SENSITIVITY,
+ ipsa->ipsa_cred, senslen);
+
+ walker = (sadb_ext_t *)((uint64_t *)walker +
+ walker->sadb_ext_len);
+ }
+
+ if (osensinteg) {
+ sens = (sadb_sens_t *)walker;
+
+ sadb_sens_from_cred(sens, SADB_X_EXT_OUTER_SENS,
+ ipsa->ipsa_ocred, osenslen);
+ if (ipsa->ipsa_mac_exempt)
+ sens->sadb_x_sens_flags = SADB_X_SENS_IMPLICIT;
+
walker = (sadb_ext_t *)((uint64_t *)walker +
walker->sadb_ext_len);
}
@@ -2493,6 +2506,251 @@
return (KS_IN_ADDR_NOTME);
}
+/*
+ * Match primitives..
+ * !!! TODO: short term: inner selectors
+ * ipv6 scope id (ifindex)
+ * longer term: zone id. sensitivity label. uid.
+ */
+boolean_t
+sadb_match_spi(ipsa_query_t *sq, ipsa_t *sa)
+{
+ return (sq->spi == sa->ipsa_spi);
+}
+
+boolean_t
+sadb_match_dst_v6(ipsa_query_t *sq, ipsa_t *sa)
+{
+ return (IPSA_ARE_ADDR_EQUAL(sa->ipsa_dstaddr, sq->dstaddr, AF_INET6));
+}
+
+boolean_t
+sadb_match_src_v6(ipsa_query_t *sq, ipsa_t *sa)
+{
+ return (IPSA_ARE_ADDR_EQUAL(sa->ipsa_srcaddr, sq->srcaddr, AF_INET6));
+}
+
+boolean_t
+sadb_match_dst_v4(ipsa_query_t *sq, ipsa_t *sa)
+{
+ return (sq->dstaddr[0] == sa->ipsa_dstaddr[0]);
+}
+
+boolean_t
+sadb_match_src_v4(ipsa_query_t *sq, ipsa_t *sa)
+{
+ return (sq->srcaddr[0] == sa->ipsa_srcaddr[0]);
+}
+
+boolean_t
+sadb_match_dstid(ipsa_query_t *sq, ipsa_t *sa)
+{
+ return ((sa->ipsa_dst_cid != NULL) &&
+ (sq->didtype == sa->ipsa_dst_cid->ipsid_type) &&
+ (strcmp(sq->didstr, sa->ipsa_dst_cid->ipsid_cid) == 0));
+
+}
+boolean_t
+sadb_match_srcid(ipsa_query_t *sq, ipsa_t *sa)
+{
+ return ((sa->ipsa_src_cid != NULL) &&
+ (sq->sidtype == sa->ipsa_src_cid->ipsid_type) &&
+ (strcmp(sq->sidstr, sa->ipsa_src_cid->ipsid_cid) == 0));
+}
+
+boolean_t
+sadb_match_kmc(ipsa_query_t *sq, ipsa_t *sa)
+{
+#define M(a, b) (((a) == 0) || ((b) == 0) || ((a) == (b)))
+
+ return (M(sq->kmc, sa->ipsa_kmc) && M(sq->kmp, sa->ipsa_kmp));
+
+#undef M
+}
+
+/*
+ * Common function which extracts several PF_KEY extensions for ease of
+ * SADB matching.
+ *
+ * XXX TODO: weed out ipsa_query_t fields not used during matching
+ * or afterwards?
+ */
+int
+sadb_form_query(keysock_in_t *ksi, uint32_t req, uint32_t match,
+ ipsa_query_t *sq, int *diagnostic)
+{
+ int i;
+ ipsa_match_fn_t *mfpp = &(sq->matchers[0]);
+
+ for (i = 0; i < IPSA_NMATCH; i++)
+ sq->matchers[i] = NULL;
+
+ ASSERT((req & ~match) == 0);
+
+ sq->req = req;
+ sq->dstext = (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
+ sq->srcext = (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
+ sq->assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
+
+ if ((req & IPSA_Q_DST) && (sq->dstext == NULL)) {
+ *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
+ return (EINVAL);
+ }
+ if ((req & IPSA_Q_SRC) && (sq->srcext == NULL)) {
+ *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
+ return (EINVAL);
+ }
+ if ((req & IPSA_Q_SA) && (sq->assoc == NULL)) {
+ *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA;
+ return (EINVAL);
+ }
+
+ if (match & IPSA_Q_SA) {
+ *mfpp++ = sadb_match_spi;
+ sq->spi = sq->assoc->sadb_sa_spi;
+ }
+
+ if (sq->dstext != NULL)
+ sq->dst = (struct sockaddr_in *)(sq->dstext + 1);
+ else {
+ sq->dst = NULL;
+ sq->dst6 = NULL;
+ sq->dstaddr = NULL;
+ }
+
+ if (sq->srcext != NULL)
+ sq->src = (struct sockaddr_in *)(sq->srcext + 1);
+ else {
+ sq->src = NULL;
+ sq->src6 = NULL;
+ sq->srcaddr = NULL;
+ }
+
+ if (sq->dst != NULL)
+ sq->af = sq->dst->sin_family;
+ else if (sq->src != NULL)
+ sq->af = sq->src->sin_family;
+ else
+ sq->af = AF_INET;
+
+ if (sq->af == AF_INET6) {
+ if ((match & IPSA_Q_DST) && (sq->dstext != NULL)) {
+ *mfpp++ = sadb_match_dst_v6;
+ sq->dst6 = (struct sockaddr_in6 *)sq->dst;
+ sq->dstaddr = (uint32_t *)&(sq->dst6->sin6_addr);
+ } else {
+ match &= ~IPSA_Q_DST;
+ sq->dstaddr = ALL_ZEROES_PTR;
+ }
+
+ if ((match & IPSA_Q_SRC) && (sq->srcext != NULL)) {
+ sq->src6 = (struct sockaddr_in6 *)(sq->srcext + 1);
+ sq->srcaddr = (uint32_t *)&sq->src6->sin6_addr;
+ if (sq->src6->sin6_family != AF_INET6) {
+ *diagnostic = SADB_X_DIAGNOSTIC_AF_MISMATCH;
+ return (EINVAL);
+ }
+ *mfpp++ = sadb_match_src_v6;
+ } else {
+ match &= ~IPSA_Q_SRC;
+ sq->srcaddr = ALL_ZEROES_PTR;
+ }
+ } else {
+ sq->src6 = sq->dst6 = NULL;
+ if ((match & IPSA_Q_DST) && (sq->dstext != NULL)) {
+ *mfpp++ = sadb_match_dst_v4;
+ sq->dstaddr = (uint32_t *)&sq->dst->sin_addr;
+ } else {
+ match &= ~IPSA_Q_DST;
+ sq->dstaddr = ALL_ZEROES_PTR;
+ }
+ if ((match & IPSA_Q_SRC) && (sq->srcext != NULL)) {
+ sq->srcaddr = (uint32_t *)&sq->src->sin_addr;
+ if (sq->src->sin_family != AF_INET) {
+ *diagnostic = SADB_X_DIAGNOSTIC_AF_MISMATCH;
+ return (EINVAL);
+ }
+ *mfpp++ = sadb_match_src_v4;
+ } else {
+ match &= ~IPSA_Q_SRC;
+ sq->srcaddr = ALL_ZEROES_PTR;
+ }
+ }
+
+ sq->dstid = (sadb_ident_t *)ksi->ks_in_extv[SADB_EXT_IDENTITY_DST];
+ if ((match & IPSA_Q_DSTID) && (sq->dstid != NULL)) {
+ sq->didstr = (char *)(sq->dstid + 1);
+ sq->didtype = sq->dstid->sadb_ident_type;
+ *mfpp++ = sadb_match_dstid;
+ }
+
+ sq->srcid = (sadb_ident_t *)ksi->ks_in_extv[SADB_EXT_IDENTITY_SRC];
+
+ if ((match & IPSA_Q_SRCID) && (sq->srcid != NULL)) {
+ sq->sidstr = (char *)(sq->srcid + 1);
+ sq->sidtype = sq->srcid->sadb_ident_type;
+ *mfpp++ = sadb_match_srcid;
+ }
+
+ sq->kmcext = (sadb_x_kmc_t *)ksi->ks_in_extv[SADB_X_EXT_KM_COOKIE];
+ sq->kmc = 0;
+ sq->kmp = 0;
+
+ if ((match & IPSA_Q_KMC) && (sq->kmcext)) {
+ sq->kmc = sq->kmcext->sadb_x_kmc_cookie;
+ sq->kmp = sq->kmcext->sadb_x_kmc_proto;
+ *mfpp++ = sadb_match_kmc;
+ }
+
+ if (match & (IPSA_Q_INBOUND|IPSA_Q_OUTBOUND)) {
+ if (sq->af == AF_INET6)
+ sq->sp = &sq->spp->s_v6;
+ else
+ sq->sp = &sq->spp->s_v4;
+ } else {
+ sq->sp = NULL;
+ }
+
+ if (match & IPSA_Q_INBOUND) {
+ sq->inhash = INBOUND_HASH(sq->sp, sq->assoc->sadb_sa_spi);
+ sq->inbound = &sq->sp->sdb_if[sq->inhash];
+ } else {
+ sq->inhash = 0;
+ sq->inbound = NULL;
+ }
+
+ if (match & IPSA_Q_OUTBOUND) {
+ if (sq->af == AF_INET6) {
+ sq->outhash = OUTBOUND_HASH_V6(sq->sp, *(sq->dstaddr));
+ } else {
+ sq->outhash = OUTBOUND_HASH_V4(sq->sp, *(sq->dstaddr));
+ }
+ sq->outbound = &sq->sp->sdb_of[sq->outhash];
+ } else {
+ sq->outhash = 0;
+ sq->outbound = NULL;
+ }
+ sq->match = match;
+ return (0);
+}
+
+/*
+ * Match an initialized query structure with a security association;
+ * return B_TRUE on a match, B_FALSE on a miss.
+ * Applies match functions set up by sadb_form_query() until one returns false.
+ */
+boolean_t
+sadb_match_query(ipsa_query_t *sq, ipsa_t *sa)
+{
+ ipsa_match_fn_t *mfpp = &(sq->matchers[0]);
+ ipsa_match_fn_t mfp;
+
+ for (mfp = *mfpp++; mfp != NULL; mfp = *mfpp++) {
+ if (!mfp(sq, sa))
+ return (B_FALSE);
+ }
+ return (B_TRUE);
+}
/*
* Walker callback function to delete sa's based on src/dst address.
@@ -2500,21 +2758,12 @@
* Conveniently, and not coincidentally, this is both what sadb_walker
* gives us and also what sadb_unlinkassoc expects.
*/
-
struct sadb_purge_state
{
- uint32_t *src;
- uint32_t *dst;
- sa_family_t af;
+ ipsa_query_t sq;
boolean_t inbnd;
- char *sidstr;
- char *didstr;
- uint16_t sidtype;
- uint16_t didtype;
- uint32_t kmproto;
uint8_t sadb_sa_state;
mblk_t *mq;
- sadb_t *sp;
};
static void
@@ -2526,18 +2775,8 @@
mutex_enter(&entry->ipsa_lock);
- if ((entry->ipsa_state == IPSA_STATE_LARVAL) ||
- (ps->src != NULL &&
- !IPSA_ARE_ADDR_EQUAL(entry->ipsa_srcaddr, ps->src, ps->af)) ||
- (ps->dst != NULL &&
- !IPSA_ARE_ADDR_EQUAL(entry->ipsa_dstaddr, ps->dst, ps->af)) ||
- (ps->didstr != NULL && (entry->ipsa_dst_cid != NULL) &&
- !(ps->didtype == entry->ipsa_dst_cid->ipsid_type &&
- strcmp(ps->didstr, entry->ipsa_dst_cid->ipsid_cid) == 0)) ||
- (ps->sidstr != NULL && (entry->ipsa_src_cid != NULL) &&
- !(ps->sidtype == entry->ipsa_src_cid->ipsid_type &&
- strcmp(ps->sidstr, entry->ipsa_src_cid->ipsid_cid) == 0)) ||
- (ps->kmproto <= SADB_X_KMP_MAX && ps->kmproto != entry->ipsa_kmp)) {
+ if (entry->ipsa_state == IPSA_STATE_LARVAL ||
+ !sadb_match_query(&ps->sq, entry)) {
mutex_exit(&entry->ipsa_lock);
return;
}
@@ -2554,88 +2793,18 @@
* Don't kill larval SA's in such a purge.
*/
int
-sadb_purge_sa(mblk_t *mp, keysock_in_t *ksi, sadb_t *sp, queue_t *pfkey_q,
- queue_t *ip_q)
+sadb_purge_sa(mblk_t *mp, keysock_in_t *ksi, sadb_t *sp,
+ int *diagnostic, queue_t *pfkey_q, queue_t *ip_q)
{
- sadb_address_t *dstext =
- (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
- sadb_address_t *srcext =
- (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
- sadb_ident_t *dstid =
- (sadb_ident_t *)ksi->ks_in_extv[SADB_EXT_IDENTITY_DST];
- sadb_ident_t *srcid =
- (sadb_ident_t *)ksi->ks_in_extv[SADB_EXT_IDENTITY_SRC];
- sadb_x_kmc_t *kmc =
- (sadb_x_kmc_t *)ksi->ks_in_extv[SADB_X_EXT_KM_COOKIE];
- struct sockaddr_in *src, *dst;
- struct sockaddr_in6 *src6, *dst6;
struct sadb_purge_state ps;
+ int error = sadb_form_query(ksi, 0,
+ IPSA_Q_SRC|IPSA_Q_DST|IPSA_Q_SRCID|IPSA_Q_DSTID|IPSA_Q_KMC,
+ &ps.sq, diagnostic);
- /*
- * Don't worry about IPv6 v4-mapped addresses, sadb_addrcheck()
- * takes care of them.
- */
-
- /* enforced by caller */
- ASSERT((dstext != NULL) || (srcext != NULL));
-
- ps.src = NULL;
- ps.dst = NULL;
-#ifdef DEBUG
- ps.af = (sa_family_t)-1;
-#endif
ps.mq = NULL;
- ps.sidstr = NULL;
- ps.didstr = NULL;
- ps.kmproto = SADB_X_KMP_MAX + 1;
- if (dstext != NULL) {
- dst = (struct sockaddr_in *)(dstext + 1);
- ps.af = dst->sin_family;
- if (dst->sin_family == AF_INET6) {
- dst6 = (struct sockaddr_in6 *)dst;
- ps.dst = (uint32_t *)&dst6->sin6_addr;
- } else {
- ps.dst = (uint32_t *)&dst->sin_addr;
- }
- }
-
- if (srcext != NULL) {
- src = (struct sockaddr_in *)(srcext + 1);
- ps.af = src->sin_family;
- if (src->sin_family == AF_INET6) {
- src6 = (struct sockaddr_in6 *)(srcext + 1);
- ps.src = (uint32_t *)&src6->sin6_addr;
- } else {
- ps.src = (uint32_t *)&src->sin_addr;
- }
- ASSERT(dstext == NULL || src->sin_family == dst->sin_family);
- }
-
- ASSERT(ps.af != (sa_family_t)-1);
-
- if (dstid != NULL) {
- /*
- * NOTE: May need to copy string in the future
- * if the inbound keysock message disappears for some strange
- * reason.
- */
- ps.didstr = (char *)(dstid + 1);
- ps.didtype = dstid->sadb_ident_type;
- }
-
- if (srcid != NULL) {
- /*
- * NOTE: May need to copy string in the future
- * if the inbound keysock message disappears for some strange
- * reason.
- */
- ps.sidstr = (char *)(srcid + 1);
- ps.sidtype = srcid->sadb_ident_type;
- }
-
- if (kmc != NULL)
- ps.kmproto = kmc->sadb_x_kmc_proto;
+ if (error != 0)
+ return (error);
/*
* This is simple, crude, and effective.
@@ -2660,19 +2829,20 @@
}
static void
-sadb_delpair_state(isaf_t *head, ipsa_t *entry, void *cookie)
+sadb_delpair_state_one(isaf_t *head, ipsa_t *entry, void *cookie)
{
struct sadb_purge_state *ps = (struct sadb_purge_state *)cookie;
isaf_t *inbound_bucket;
ipsa_t *peer_assoc;
+ ipsa_query_t *sq = &ps->sq;
ASSERT(MUTEX_HELD(&head->isaf_lock));
mutex_enter(&entry->ipsa_lock);
if ((entry->ipsa_state != ps->sadb_sa_state) ||
- ((ps->src != NULL) &&
- !IPSA_ARE_ADDR_EQUAL(entry->ipsa_srcaddr, ps->src, ps->af))) {
+ ((sq->srcaddr != NULL) &&
+ !IPSA_ARE_ADDR_EQUAL(entry->ipsa_srcaddr, sq->srcaddr, sq->af))) {
mutex_exit(&entry->ipsa_lock);
return;
}
@@ -2686,13 +2856,13 @@
*/
if (entry->ipsa_haspeer) {
- inbound_bucket = INBOUND_BUCKET(ps->sp, entry->ipsa_spi);
+ inbound_bucket = INBOUND_BUCKET(sq->sp, entry->ipsa_spi);
mutex_enter(&inbound_bucket->isaf_lock);
peer_assoc = ipsec_getassocbyspi(inbound_bucket,
entry->ipsa_spi, entry->ipsa_srcaddr,
entry->ipsa_dstaddr, entry->ipsa_addrfam);
} else {
- inbound_bucket = INBOUND_BUCKET(ps->sp, entry->ipsa_otherspi);
+ inbound_bucket = INBOUND_BUCKET(sq->sp, entry->ipsa_otherspi);
mutex_enter(&inbound_bucket->isaf_lock);
peer_assoc = ipsec_getassocbyspi(inbound_bucket,
entry->ipsa_otherspi, entry->ipsa_dstaddr,
@@ -2710,6 +2880,37 @@
mutex_exit(&inbound_bucket->isaf_lock);
}
+static int
+sadb_delpair_state(mblk_t *mp, keysock_in_t *ksi, sadbp_t *spp,
+ int *diagnostic, queue_t *pfkey_q)
+{
+ sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
+ struct sadb_purge_state ps;
+ int error;
+
+ ps.sq.spp = spp; /* XXX param */
+ ps.mq = NULL;
+
+ error = sadb_form_query(ksi, IPSA_Q_DST|IPSA_Q_SRC,
+ IPSA_Q_SRC|IPSA_Q_DST|IPSA_Q_SRCID|IPSA_Q_DSTID|IPSA_Q_KMC,
+ &ps.sq, diagnostic);
+ if (error != 0)
+ return (error);
+
+ ps.inbnd = B_FALSE;
+ ps.sadb_sa_state = assoc->sadb_sa_state;
+ sadb_walker(ps.sq.sp->sdb_of, ps.sq.sp->sdb_hashsize,
+ sadb_delpair_state_one, &ps);
+
+ if (ps.mq != NULL)
+ sadb_drain_torchq(pfkey_q, ps.mq);
+
+ ASSERT(mp->b_cont != NULL);
+ sadb_pfkey_echo(pfkey_q, mp, (sadb_msg_t *)mp->b_cont->b_rptr,
+ ksi, NULL);
+ return (0);
+}
+
/*
* Common code to delete/get an SA.
*/
@@ -2717,70 +2918,30 @@
sadb_delget_sa(mblk_t *mp, keysock_in_t *ksi, sadbp_t *spp,
int *diagnostic, queue_t *pfkey_q, uint8_t sadb_msg_type)
{
- sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
- sadb_address_t *srcext =
- (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
- sadb_address_t *dstext =
- (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
+ ipsa_query_t sq;
ipsa_t *echo_target = NULL;
- ipsap_t *ipsapp;
+ ipsap_t ipsapp;
mblk_t *torchq = NULL;
uint_t error = 0;
- if (assoc == NULL) {
- *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA;
- return (EINVAL);
+ if (sadb_msg_type == SADB_X_DELPAIR_STATE)
+ return (sadb_delpair_state(mp, ksi, spp, diagnostic, pfkey_q));
+
+ sq.spp = spp; /* XXX param */
+ error = sadb_form_query(ksi, IPSA_Q_DST|IPSA_Q_SA,
+ IPSA_Q_SRC|IPSA_Q_DST|IPSA_Q_SA|IPSA_Q_INBOUND|IPSA_Q_OUTBOUND,
+ &sq, diagnostic);
+ if (error != 0)
+ return (error);
+
+ error = get_ipsa_pair(&sq, &ipsapp, diagnostic);
+ if (error != 0) {
+ return (error);
}
- if (sadb_msg_type == SADB_X_DELPAIR_STATE) {
- struct sockaddr_in *src;
- struct sockaddr_in6 *src6;
- struct sadb_purge_state ps;
-
- if (srcext == NULL) {
- *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
- return (EINVAL);
- }
- ps.src = NULL;
- ps.mq = NULL;
- src = (struct sockaddr_in *)(srcext + 1);
- ps.af = src->sin_family;
- if (src->sin_family == AF_INET6) {
- src6 = (struct sockaddr_in6 *)(srcext + 1);
- ps.src = (uint32_t *)&src6->sin6_addr;
- ps.sp = &spp->s_v6;
- } else {
- ps.src = (uint32_t *)&src->sin_addr;
- ps.sp = &spp->s_v4;
- }
- ps.inbnd = B_FALSE;
- ps.sadb_sa_state = assoc->sadb_sa_state;
- sadb_walker(ps.sp->sdb_of, ps.sp->sdb_hashsize,
- sadb_delpair_state, &ps);
-
- if (ps.mq != NULL)
- sadb_drain_torchq(pfkey_q, ps.mq);
-
- ASSERT(mp->b_cont != NULL);
- sadb_pfkey_echo(pfkey_q, mp, (sadb_msg_t *)mp->b_cont->b_rptr,
- ksi, NULL);
- return (0);
- }
-
- if (dstext == NULL) {
- *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
- return (EINVAL);
- }
-
- ipsapp = get_ipsa_pair(assoc, srcext, dstext, spp);
- if (ipsapp == NULL) {
- *diagnostic = SADB_X_DIAGNOSTIC_SA_NOTFOUND;
- return (ESRCH);
- }
-
- echo_target = ipsapp->ipsap_sa_ptr;
+ echo_target = ipsapp.ipsap_sa_ptr;
if (echo_target == NULL)
- echo_target = ipsapp->ipsap_psa_ptr;
+ echo_target = ipsapp.ipsap_psa_ptr;
if (sadb_msg_type == SADB_DELETE || sadb_msg_type == SADB_X_DELPAIR) {
/*
@@ -2789,58 +2950,58 @@
* if it can't find a pair SA pointer. To prevent a potential
* deadlock, always lock the outbound bucket before the inbound.
*/
- if (ipsapp->in_inbound_table) {
- mutex_enter(&ipsapp->ipsap_pbucket->isaf_lock);
- mutex_enter(&ipsapp->ipsap_bucket->isaf_lock);
+ if (ipsapp.in_inbound_table) {
+ mutex_enter(&ipsapp.ipsap_pbucket->isaf_lock);
+ mutex_enter(&ipsapp.ipsap_bucket->isaf_lock);
} else {
- mutex_enter(&ipsapp->ipsap_bucket->isaf_lock);
- mutex_enter(&ipsapp->ipsap_pbucket->isaf_lock);
+ mutex_enter(&ipsapp.ipsap_bucket->isaf_lock);
+ mutex_enter(&ipsapp.ipsap_pbucket->isaf_lock);
}
- if (ipsapp->ipsap_sa_ptr != NULL) {
- mutex_enter(&ipsapp->ipsap_sa_ptr->ipsa_lock);
- if (ipsapp->ipsap_sa_ptr->ipsa_flags & IPSA_F_INBOUND) {
- sadb_delete_cluster(ipsapp->ipsap_sa_ptr);
+ if (ipsapp.ipsap_sa_ptr != NULL) {
+ mutex_enter(&ipsapp.ipsap_sa_ptr->ipsa_lock);
+ if (ipsapp.ipsap_sa_ptr->ipsa_flags & IPSA_F_INBOUND) {
+ sadb_delete_cluster(ipsapp.ipsap_sa_ptr);
}
- ipsapp->ipsap_sa_ptr->ipsa_state = IPSA_STATE_DEAD;
- (void) sadb_torch_assoc(ipsapp->ipsap_bucket,
- ipsapp->ipsap_sa_ptr, B_FALSE, &torchq);
+ ipsapp.ipsap_sa_ptr->ipsa_state = IPSA_STATE_DEAD;
+ (void) sadb_torch_assoc(ipsapp.ipsap_bucket,
+ ipsapp.ipsap_sa_ptr, B_FALSE, &torchq);
/*
* sadb_torch_assoc() releases the ipsa_lock
* and calls sadb_unlinkassoc() which does a
* IPSA_REFRELE.
*/
}
- if (ipsapp->ipsap_psa_ptr != NULL) {
- mutex_enter(&ipsapp->ipsap_psa_ptr->ipsa_lock);
+ if (ipsapp.ipsap_psa_ptr != NULL) {
+ mutex_enter(&ipsapp.ipsap_psa_ptr->ipsa_lock);
if (sadb_msg_type == SADB_X_DELPAIR ||
- ipsapp->ipsap_psa_ptr->ipsa_haspeer) {
- if (ipsapp->ipsap_psa_ptr->ipsa_flags &
+ ipsapp.ipsap_psa_ptr->ipsa_haspeer) {
+ if (ipsapp.ipsap_psa_ptr->ipsa_flags &
IPSA_F_INBOUND) {
- sadb_delete_cluster(
- ipsapp->ipsap_psa_ptr);
+ sadb_delete_cluster
+ (ipsapp.ipsap_psa_ptr);
}
- ipsapp->ipsap_psa_ptr->ipsa_state =
+ ipsapp.ipsap_psa_ptr->ipsa_state =
IPSA_STATE_DEAD;
- (void) sadb_torch_assoc(ipsapp->ipsap_pbucket,
- ipsapp->ipsap_psa_ptr, B_FALSE, &torchq);
+ (void) sadb_torch_assoc(ipsapp.ipsap_pbucket,
+ ipsapp.ipsap_psa_ptr, B_FALSE, &torchq);
} else {
/*
* Only half of the "pair" has been deleted.
* Update the remaining SA and remove references
* to its pair SA, which is now gone.
*/
- ipsapp->ipsap_psa_ptr->ipsa_otherspi = 0;
- ipsapp->ipsap_psa_ptr->ipsa_flags &=
+ ipsapp.ipsap_psa_ptr->ipsa_otherspi = 0;
+ ipsapp.ipsap_psa_ptr->ipsa_flags &=
~IPSA_F_PAIRED;
- mutex_exit(&ipsapp->ipsap_psa_ptr->ipsa_lock);
+ mutex_exit(&ipsapp.ipsap_psa_ptr->ipsa_lock);
}
} else if (sadb_msg_type == SADB_X_DELPAIR) {
*diagnostic = SADB_X_DIAGNOSTIC_PAIR_SA_NOTFOUND;
error = ESRCH;
}
- mutex_exit(&ipsapp->ipsap_bucket->isaf_lock);
- mutex_exit(&ipsapp->ipsap_pbucket->isaf_lock);
+ mutex_exit(&ipsapp.ipsap_bucket->isaf_lock);
+ mutex_exit(&ipsapp.ipsap_pbucket->isaf_lock);
}
if (torchq != NULL)
@@ -2852,7 +3013,7 @@
sadb_pfkey_echo(pfkey_q, mp, (sadb_msg_t *)
mp->b_cont->b_rptr, ksi, echo_target);
- destroy_ipsa_pair(ipsapp);
+ destroy_ipsa_pair(&ipsapp);
return (error);
}
@@ -2883,115 +3044,66 @@
* found, the pair ipsa_t will be NULL. Both isaf_t values are valid
* provided at least one ipsa_t is found.
*/
-ipsap_t *
-get_ipsa_pair(sadb_sa_t *assoc, sadb_address_t *srcext, sadb_address_t *dstext,
- sadbp_t *spp)
+static int
+get_ipsa_pair(ipsa_query_t *sq, ipsap_t *ipsapp, int *diagnostic)
{
- struct sockaddr_in *src, *dst;
- struct sockaddr_in6 *src6, *dst6;
- sadb_t *sp;
- uint32_t *srcaddr, *dstaddr;
- isaf_t *outbound_bucket, *inbound_bucket;
- ipsap_t *ipsapp;
- sa_family_t af;
-
uint32_t pair_srcaddr[IPSA_MAX_ADDRLEN];
uint32_t pair_dstaddr[IPSA_MAX_ADDRLEN];
uint32_t pair_spi;
- ipsapp = kmem_zalloc(sizeof (*ipsapp), KM_NOSLEEP);
- if (ipsapp == NULL)
- return (NULL);
+ init_ipsa_pair(ipsapp);
ipsapp->in_inbound_table = B_FALSE;
- /*
- * Don't worry about IPv6 v4-mapped addresses, sadb_addrcheck()
- * takes care of them.
- */
-
- dst = (struct sockaddr_in *)(dstext + 1);
- af = dst->sin_family;
- if (af == AF_INET6) {
- sp = &spp->s_v6;
- dst6 = (struct sockaddr_in6 *)dst;
- dstaddr = (uint32_t *)&dst6->sin6_addr;
- if (srcext != NULL) {
- src6 = (struct sockaddr_in6 *)(srcext + 1);
- srcaddr = (uint32_t *)&src6->sin6_addr;
- ASSERT(src6->sin6_family == af);
- ASSERT(src6->sin6_family == AF_INET6);
- } else {
- srcaddr = ALL_ZEROES_PTR;
- }
- outbound_bucket = OUTBOUND_BUCKET_V6(sp,
- *(uint32_t *)dstaddr);
- } else {
- sp = &spp->s_v4;
- dstaddr = (uint32_t *)&dst->sin_addr;
- if (srcext != NULL) {
- src = (struct sockaddr_in *)(srcext + 1);
- srcaddr = (uint32_t *)&src->sin_addr;
- ASSERT(src->sin_family == af);
- ASSERT(src->sin_family == AF_INET);
- } else {
- srcaddr = ALL_ZEROES_PTR;
- }
- outbound_bucket = OUTBOUND_BUCKET_V4(sp,
- *(uint32_t *)dstaddr);
- }
-
- inbound_bucket = INBOUND_BUCKET(sp, assoc->sadb_sa_spi);
-
/* Lock down both buckets. */
- mutex_enter(&outbound_bucket->isaf_lock);
- mutex_enter(&inbound_bucket->isaf_lock);
+ mutex_enter(&sq->outbound->isaf_lock);
+ mutex_enter(&sq->inbound->isaf_lock);
- if (assoc->sadb_sa_flags & IPSA_F_INBOUND) {
- ipsapp->ipsap_sa_ptr = ipsec_getassocbyspi(inbound_bucket,
- assoc->sadb_sa_spi, srcaddr, dstaddr, af);
+ if (sq->assoc->sadb_sa_flags & IPSA_F_INBOUND) {
+ ipsapp->ipsap_sa_ptr = ipsec_getassocbyspi(sq->inbound,
+ sq->assoc->sadb_sa_spi, sq->srcaddr, sq->dstaddr, sq->af);
if (ipsapp->ipsap_sa_ptr != NULL) {
- ipsapp->ipsap_bucket = inbound_bucket;
- ipsapp->ipsap_pbucket = outbound_bucket;
+ ipsapp->ipsap_bucket = sq->inbound;
+ ipsapp->ipsap_pbucket = sq->outbound;
ipsapp->in_inbound_table = B_TRUE;
} else {
- ipsapp->ipsap_sa_ptr =
- ipsec_getassocbyspi(outbound_bucket,
- assoc->sadb_sa_spi, srcaddr, dstaddr, af);
- ipsapp->ipsap_bucket = outbound_bucket;
- ipsapp->ipsap_pbucket = inbound_bucket;
+ ipsapp->ipsap_sa_ptr = ipsec_getassocbyspi(sq->outbound,
+ sq->assoc->sadb_sa_spi, sq->srcaddr, sq->dstaddr,
+ sq->af);
+ ipsapp->ipsap_bucket = sq->outbound;
+ ipsapp->ipsap_pbucket = sq->inbound;
}
} else {
/* IPSA_F_OUTBOUND is set *or* no directions flags set. */
ipsapp->ipsap_sa_ptr =
- ipsec_getassocbyspi(outbound_bucket,
- assoc->sadb_sa_spi, srcaddr, dstaddr, af);
+ ipsec_getassocbyspi(sq->outbound,
+ sq->assoc->sadb_sa_spi, sq->srcaddr, sq->dstaddr, sq->af);
if (ipsapp->ipsap_sa_ptr != NULL) {
- ipsapp->ipsap_bucket = outbound_bucket;
- ipsapp->ipsap_pbucket = inbound_bucket;
+ ipsapp->ipsap_bucket = sq->outbound;
+ ipsapp->ipsap_pbucket = sq->inbound;
} else {
- ipsapp->ipsap_sa_ptr =
- ipsec_getassocbyspi(inbound_bucket,
- assoc->sadb_sa_spi, srcaddr, dstaddr, af);
- ipsapp->ipsap_bucket = inbound_bucket;
- ipsapp->ipsap_pbucket = outbound_bucket;
+ ipsapp->ipsap_sa_ptr = ipsec_getassocbyspi(sq->inbound,
+ sq->assoc->sadb_sa_spi, sq->srcaddr, sq->dstaddr,
+ sq->af);
+ ipsapp->ipsap_bucket = sq->inbound;
+ ipsapp->ipsap_pbucket = sq->outbound;
if (ipsapp->ipsap_sa_ptr != NULL)
ipsapp->in_inbound_table = B_TRUE;
}
}
if (ipsapp->ipsap_sa_ptr == NULL) {
- mutex_exit(&outbound_bucket->isaf_lock);
- mutex_exit(&inbound_bucket->isaf_lock);
- kmem_free(ipsapp, sizeof (*ipsapp));
- return (NULL);
+ mutex_exit(&sq->outbound->isaf_lock);
+ mutex_exit(&sq->inbound->isaf_lock);
+ *diagnostic = SADB_X_DIAGNOSTIC_SA_NOTFOUND;
+ return (ESRCH);
}
if ((ipsapp->ipsap_sa_ptr->ipsa_state == IPSA_STATE_LARVAL) &&
ipsapp->in_inbound_table) {
- mutex_exit(&outbound_bucket->isaf_lock);
- mutex_exit(&inbound_bucket->isaf_lock);
- return (ipsapp);
+ mutex_exit(&sq->outbound->isaf_lock);
+ mutex_exit(&sq->inbound->isaf_lock);
+ return (0);
}
mutex_enter(&ipsapp->ipsap_sa_ptr->ipsa_lock);
@@ -3002,48 +3114,48 @@
*/
ipsapp->ipsap_psa_ptr =
ipsec_getassocbyspi(ipsapp->ipsap_pbucket,
- assoc->sadb_sa_spi, srcaddr, dstaddr, af);
+ sq->assoc->sadb_sa_spi, sq->srcaddr, sq->dstaddr, sq->af);
mutex_exit(&ipsapp->ipsap_sa_ptr->ipsa_lock);
- mutex_exit(&outbound_bucket->isaf_lock);
- mutex_exit(&inbound_bucket->isaf_lock);
- return (ipsapp);
+ mutex_exit(&sq->outbound->isaf_lock);
+ mutex_exit(&sq->inbound->isaf_lock);
+ return (0);
}
pair_spi = ipsapp->ipsap_sa_ptr->ipsa_otherspi;
IPSA_COPY_ADDR(&pair_srcaddr,
- ipsapp->ipsap_sa_ptr->ipsa_srcaddr, af);
+ ipsapp->ipsap_sa_ptr->ipsa_srcaddr, sq->af);
IPSA_COPY_ADDR(&pair_dstaddr,
- ipsapp->ipsap_sa_ptr->ipsa_dstaddr, af);
+ ipsapp->ipsap_sa_ptr->ipsa_dstaddr, sq->af);
mutex_exit(&ipsapp->ipsap_sa_ptr->ipsa_lock);
- mutex_exit(&outbound_bucket->isaf_lock);
- mutex_exit(&inbound_bucket->isaf_lock);
+ mutex_exit(&sq->inbound->isaf_lock);
+ mutex_exit(&sq->outbound->isaf_lock);
if (pair_spi == 0) {
ASSERT(ipsapp->ipsap_bucket != NULL);
ASSERT(ipsapp->ipsap_pbucket != NULL);
- return (ipsapp);
+ return (0);
}
/* found sa in outbound sadb, peer should be inbound */
if (ipsapp->in_inbound_table) {
/* Found SA in inbound table, pair will be in outbound. */
- if (af == AF_INET6) {
- ipsapp->ipsap_pbucket = OUTBOUND_BUCKET_V6(sp,
+ if (sq->af == AF_INET6) {
+ ipsapp->ipsap_pbucket = OUTBOUND_BUCKET_V6(sq->sp,
*(uint32_t *)pair_srcaddr);
} else {
- ipsapp->ipsap_pbucket = OUTBOUND_BUCKET_V4(sp,
+ ipsapp->ipsap_pbucket = OUTBOUND_BUCKET_V4(sq->sp,
*(uint32_t *)pair_srcaddr);
}
} else {
- ipsapp->ipsap_pbucket = INBOUND_BUCKET(sp, pair_spi);
+ ipsapp->ipsap_pbucket = INBOUND_BUCKET(sq->sp, pair_spi);
}
mutex_enter(&ipsapp->ipsap_pbucket->isaf_lock);
ipsapp->ipsap_psa_ptr = ipsec_getassocbyspi(ipsapp->ipsap_pbucket,
- pair_spi, pair_dstaddr, pair_srcaddr, af);
+ pair_spi, pair_dstaddr, pair_srcaddr, sq->af);
mutex_exit(&ipsapp->ipsap_pbucket->isaf_lock);
ASSERT(ipsapp->ipsap_bucket != NULL);
ASSERT(ipsapp->ipsap_pbucket != NULL);
- return (ipsapp);
+ return (0);
}
/*
@@ -3163,7 +3275,7 @@
netstack_t *ns, sadbp_t *spp)
{
ipsa_t *newbie_clone = NULL, *scratch;
- ipsap_t *ipsapp = NULL;
+ ipsap_t ipsapp;
sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
sadb_address_t *srcext =
(sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
@@ -3177,6 +3289,10 @@
(sadb_x_kmc_t *)ksi->ks_in_extv[SADB_X_EXT_KM_COOKIE];
sadb_key_t *akey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_AUTH];
sadb_key_t *ekey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT];
+ sadb_sens_t *sens =
+ (sadb_sens_t *)ksi->ks_in_extv[SADB_EXT_SENSITIVITY];
+ sadb_sens_t *osens =
+ (sadb_sens_t *)ksi->ks_in_extv[SADB_X_EXT_OUTER_SENS];
sadb_x_pair_t *pair_ext =
(sadb_x_pair_t *)ksi->ks_in_extv[SADB_X_EXT_PAIR];
sadb_x_replay_ctr_t *replayext =
@@ -3185,13 +3301,6 @@
(samsg->sadb_msg_satype == SADB_SATYPE_AH) ? IPPROTO_AH:IPPROTO_ESP;
int salt_offset;
uint8_t *buf_ptr;
-#if 0
- /*
- * XXXMLS - When Trusted Solaris or Multi-Level Secure functionality
- * comes to ON, examine these if 0'ed fragments. Look for XXXMLS.
- */
- sadb_sens_t *sens = (sadb_sens_t *);
-#endif
struct sockaddr_in *src, *dst, *isrc, *idst;
struct sockaddr_in6 *src6, *dst6, *isrc6, *idst6;
sadb_lifetime_t *soft =
@@ -3206,9 +3315,12 @@
uint32_t *src_addr_ptr, *dst_addr_ptr, *isrc_addr_ptr, *idst_addr_ptr;
mblk_t *ctl_mp = NULL;
ipsec_stack_t *ipss = ns->netstack_ipsec;
+ ip_stack_t *ipst = ns->netstack_ip;
ipsec_alginfo_t *alg;
int rcode;
+ init_ipsa_pair(&ipsapp);
+
if (srcext == NULL) {
*diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
return (EINVAL);
@@ -3692,42 +3804,59 @@
}
}
-#if 0
- /* XXXMLS SENSITIVITY handling code. */
+ /*
+ * sensitivity label handling code:
+ * Convert sens + bitmap into cred_t, and associate it
+ * with the new SA.
+ */
if (sens != NULL) {
- int i;
uint64_t *bitmap = (uint64_t *)(sens + 1);
- newbie->ipsa_dpd = sens->sadb_sens_dpd;
- newbie->ipsa_senslevel = sens->sadb_sens_sens_level;
- newbie->ipsa_integlevel = sens->sadb_sens_integ_level;
- newbie->ipsa_senslen = SADB_64TO8(sens->sadb_sens_sens_len);
- newbie->ipsa_integlen = SADB_64TO8(sens->sadb_sens_integ_len);
- newbie->ipsa_integ = kmem_alloc(newbie->ipsa_integlen,
- KM_NOSLEEP);
- if (newbie->ipsa_integ == NULL) {
- error = ENOMEM;
+ newbie->ipsa_cred = sadb_cred_from_sens(sens, bitmap);
+ }
+
+ /*
+ * Likewise for outer sensitivity.
+ */
+ if (osens != NULL) {
+ uint64_t *bitmap = (uint64_t *)(osens + 1);
+ cred_t *cred, *effective_cred;
+ uint32_t *peer_addr_ptr;
+
+ peer_addr_ptr = is_inbound ? src_addr_ptr : dst_addr_ptr;
+
+ cred = sadb_cred_from_sens(osens, bitmap);
+ newbie->ipsa_mac_exempt = CONN_MAC_DEFAULT;
+
+ if (osens->sadb_x_sens_flags & SADB_X_SENS_IMPLICIT) {
+ newbie->ipsa_mac_exempt = CONN_MAC_IMPLICIT;
+ }
+
+ error = tsol_check_dest(cred, peer_addr_ptr,
+ (af == AF_INET6)?IPV6_VERSION:IPV4_VERSION,
+ newbie->ipsa_mac_exempt, &effective_cred);
+ if (error != 0) {
+ crfree(cred);
mutex_exit(&newbie->ipsa_lock);
goto error;
}
- newbie->ipsa_sens = kmem_alloc(newbie->ipsa_senslen,
- KM_NOSLEEP);
- if (newbie->ipsa_sens == NULL) {
- error = ENOMEM;
- mutex_exit(&newbie->ipsa_lock);
- goto error;
+
+ if (effective_cred != NULL) {
+ crfree(cred);
+ cred = effective_cred;
}
- for (i = 0; i < sens->sadb_sens_sens_len; i++) {
- newbie->ipsa_sens[i] = *bitmap;
- bitmap++;
- }
- for (i = 0; i < sens->sadb_sens_integ_len; i++) {
- newbie->ipsa_integ[i] = *bitmap;
- bitmap++;
+
+ newbie->ipsa_ocred = cred;
+
+ if (af == AF_INET6) {
+ tsol_compute_label_v6(cred, (in6_addr_t *)peer_addr_ptr,
+ newbie->ipsa_opt_storage, ipst);
+ } else {
+ tsol_compute_label(cred, *peer_addr_ptr,
+ newbie->ipsa_opt_storage, ipst);
}
}
-#endif
if (replayext != NULL) {
if ((replayext->sadb_x_rc_replay32 == 0) &&
@@ -3867,16 +3996,25 @@
if (pair_ext != NULL && error == 0) {
/* update pair_spi if it exists. */
- ipsapp = get_ipsa_pair(assoc, srcext, dstext, spp);
- if (ipsapp == NULL) {
- error = ESRCH;
- *diagnostic = SADB_X_DIAGNOSTIC_PAIR_SA_NOTFOUND;
- } else if (ipsapp->ipsap_psa_ptr != NULL) {
+ ipsa_query_t sq;
+
+ sq.spp = spp; /* XXX param */
+ error = sadb_form_query(ksi, IPSA_Q_DST, IPSA_Q_SRC|IPSA_Q_DST|
+ IPSA_Q_SA|IPSA_Q_INBOUND|IPSA_Q_OUTBOUND, &sq, diagnostic);
+ if (error)
+ return (error);
+
+ error = get_ipsa_pair(&sq, &ipsapp, diagnostic);
+
+ if (error != 0)
+ goto error;
+
+ if (ipsapp.ipsap_psa_ptr != NULL) {
*diagnostic = SADB_X_DIAGNOSTIC_PAIR_ALREADY;
error = EINVAL;
} else {
/* update_pairing() sets diagnostic */
- error = update_pairing(ipsapp, ksi, diagnostic, spp);
+ error = update_pairing(&ipsapp, &sq, ksi, diagnostic);
}
}
/* Common error point for this routine. */
@@ -3909,7 +4047,7 @@
sadb_pfkey_echo(pfkey_q, mp, samsg, ksi, NULL);
}
- destroy_ipsa_pair(ipsapp);
+ destroy_ipsa_pair(&ipsapp);
return (error);
}
@@ -4710,6 +4848,49 @@
}
/*
+ * Check a proposed KMC update for sanity.
+ */
+static int
+sadb_check_kmc(ipsa_query_t *sq, ipsa_t *sa, int *diagnostic)
+{
+ uint32_t kmp = sq->kmp;
+ uint32_t kmc = sq->kmc;
+
+ if (sa == NULL)
+ return (0);
+
+ if (sa->ipsa_state == IPSA_STATE_DEAD)
+ return (ESRCH); /* DEAD == Not there, in this case. */
+
+ if ((kmp != 0) && ((sa->ipsa_kmp != 0) || (sa->ipsa_kmp != kmp))) {
+ *diagnostic = SADB_X_DIAGNOSTIC_DUPLICATE_KMP;
+ return (EINVAL);
+ }
+
+ if ((kmc != 0) && ((sa->ipsa_kmc != 0) || (sa->ipsa_kmc != kmc))) {
+ *diagnostic = SADB_X_DIAGNOSTIC_DUPLICATE_KMC;
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+/*
+ * Actually update the KMC info.
+ */
+static void
+sadb_update_kmc(ipsa_query_t *sq, ipsa_t *sa)
+{
+ uint32_t kmp = sq->kmp;
+ uint32_t kmc = sq->kmc;
+
+ if (kmp != 0)
+ sa->ipsa_kmp = kmp;
+ if (kmc != 0)
+ sa->ipsa_kmc = kmc;
+}
+
+/*
* Common code to update an SA.
*/
@@ -4719,13 +4900,6 @@
int (*add_sa_func)(mblk_t *, keysock_in_t *, int *, netstack_t *),
netstack_t *ns, uint8_t sadb_msg_type)
{
- sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
- sadb_address_t *srcext =
- (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
- sadb_address_t *dstext =
- (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
- sadb_x_kmc_t *kmcext =
- (sadb_x_kmc_t *)ksi->ks_in_extv[SADB_X_EXT_KM_COOKIE];
sadb_key_t *akey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_AUTH];
sadb_key_t *ekey = (sadb_key_t *)ksi->ks_in_extv[SADB_EXT_KEY_ENCRYPT];
sadb_x_replay_ctr_t *replext =
@@ -4739,44 +4913,29 @@
sadb_x_pair_t *pair_ext =
(sadb_x_pair_t *)ksi->ks_in_extv[SADB_X_EXT_PAIR];
ipsa_t *echo_target = NULL;
- int error = 0;
- ipsap_t *ipsapp = NULL;
- uint32_t kmp = 0, kmc = 0;
+ ipsap_t ipsapp;
+ ipsa_query_t sq;
time_t current = gethrestime_sec();
+ sq.spp = spp; /* XXX param */
+ int error = sadb_form_query(ksi, IPSA_Q_SRC|IPSA_Q_DST|IPSA_Q_SA,
+ IPSA_Q_SRC|IPSA_Q_DST|IPSA_Q_SA|IPSA_Q_INBOUND|IPSA_Q_OUTBOUND,
+ &sq, diagnostic);
- /* I need certain extensions present for either UPDATE message. */
- if (srcext == NULL) {
- *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SRC;
- return (EINVAL);
- }
- if (dstext == NULL) {
- *diagnostic = SADB_X_DIAGNOSTIC_MISSING_DST;
- return (EINVAL);
- }
- if (assoc == NULL) {
- *diagnostic = SADB_X_DIAGNOSTIC_MISSING_SA;
- return (EINVAL);
- }
+ if (error != 0)
+ return (error);
- if (kmcext != NULL) {
- kmp = kmcext->sadb_x_kmc_proto;
- kmc = kmcext->sadb_x_kmc_cookie;
- }
+ error = get_ipsa_pair(&sq, &ipsapp, diagnostic);
+ if (error != 0)
+ return (error);
- ipsapp = get_ipsa_pair(assoc, srcext, dstext, spp);
- if (ipsapp == NULL) {
- *diagnostic = SADB_X_DIAGNOSTIC_SA_NOTFOUND;
- return (ESRCH);
- }
-
- if (ipsapp->ipsap_psa_ptr == NULL && ipsapp->ipsap_sa_ptr != NULL) {
- if (ipsapp->ipsap_sa_ptr->ipsa_state == IPSA_STATE_LARVAL) {
+ if (ipsapp.ipsap_psa_ptr == NULL && ipsapp.ipsap_sa_ptr != NULL) {
+ if (ipsapp.ipsap_sa_ptr->ipsa_state == IPSA_STATE_LARVAL) {
/*
* REFRELE the target and let the add_sa_func()
* deal with updating a larval SA.
*/
- destroy_ipsa_pair(ipsapp);
+ destroy_ipsa_pair(&ipsapp);
return (add_sa_func(mp, ksi, diagnostic, ns));
}
}
@@ -4796,39 +4955,39 @@
goto bail;
}
- if (assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE_ELSEWHERE) {
- if (ipsapp->ipsap_sa_ptr != NULL &&
- ipsapp->ipsap_sa_ptr->ipsa_state == IPSA_STATE_IDLE) {
- if ((error = sadb_update_state(ipsapp->ipsap_sa_ptr,
- assoc->sadb_sa_state, NULL)) != 0) {
+ if (sq.assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE_ELSEWHERE) {
+ if (ipsapp.ipsap_sa_ptr != NULL &&
+ ipsapp.ipsap_sa_ptr->ipsa_state == IPSA_STATE_IDLE) {
+ if ((error = sadb_update_state(ipsapp.ipsap_sa_ptr,
+ sq.assoc->sadb_sa_state, NULL)) != 0) {
*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
goto bail;
}
}
- if (ipsapp->ipsap_psa_ptr != NULL &&
- ipsapp->ipsap_psa_ptr->ipsa_state == IPSA_STATE_IDLE) {
- if ((error = sadb_update_state(ipsapp->ipsap_psa_ptr,
- assoc->sadb_sa_state, NULL)) != 0) {
+ if (ipsapp.ipsap_psa_ptr != NULL &&
+ ipsapp.ipsap_psa_ptr->ipsa_state == IPSA_STATE_IDLE) {
+ if ((error = sadb_update_state(ipsapp.ipsap_psa_ptr,
+ sq.assoc->sadb_sa_state, NULL)) != 0) {
*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
goto bail;
}
}
}
- if (assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE) {
- if (ipsapp->ipsap_sa_ptr != NULL) {
- error = sadb_update_state(ipsapp->ipsap_sa_ptr,
- assoc->sadb_sa_state,
- (ipsapp->ipsap_sa_ptr->ipsa_flags &
+ if (sq.assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE) {
+ if (ipsapp.ipsap_sa_ptr != NULL) {
+ error = sadb_update_state(ipsapp.ipsap_sa_ptr,
+ sq.assoc->sadb_sa_state,
+ (ipsapp.ipsap_sa_ptr->ipsa_flags &
IPSA_F_INBOUND) ? ipkt_lst : NULL);
if (error) {
*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
goto bail;
}
}
- if (ipsapp->ipsap_psa_ptr != NULL) {
- error = sadb_update_state(ipsapp->ipsap_psa_ptr,
- assoc->sadb_sa_state,
- (ipsapp->ipsap_psa_ptr->ipsa_flags &
+ if (ipsapp.ipsap_psa_ptr != NULL) {
+ error = sadb_update_state(ipsapp.ipsap_psa_ptr,
+ sq.assoc->sadb_sa_state,
+ (ipsapp.ipsap_psa_ptr->ipsa_flags &
IPSA_F_INBOUND) ? ipkt_lst : NULL);
if (error) {
*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
@@ -4847,19 +5006,17 @@
* XXX STATS : logging/stats here?
*/
- if (!((assoc->sadb_sa_state == SADB_SASTATE_MATURE) ||
- (assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE_ELSEWHERE))) {
+ if (!((sq.assoc->sadb_sa_state == SADB_SASTATE_MATURE) ||
+ (sq.assoc->sadb_sa_state == SADB_X_SASTATE_ACTIVE_ELSEWHERE))) {
*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
error = EINVAL;
goto bail;
}
-
- if (assoc->sadb_sa_flags & ~spp->s_updateflags) {
+ if (sq.assoc->sadb_sa_flags & ~spp->s_updateflags) {
*diagnostic = SADB_X_DIAGNOSTIC_BAD_SAFLAGS;
error = EINVAL;
goto bail;
}
-
if (ksi->ks_in_extv[SADB_EXT_LIFETIME_CURRENT] != NULL) {
*diagnostic = SADB_X_DIAGNOSTIC_MISSING_LIFETIME;
error = EOPNOTSUPP;
@@ -4871,107 +5028,73 @@
goto bail;
}
- if (ipsapp->ipsap_sa_ptr != NULL) {
- if (ipsapp->ipsap_sa_ptr->ipsa_state == IPSA_STATE_DEAD) {
- error = ESRCH; /* DEAD == Not there, in this case. */
- *diagnostic = SADB_X_DIAGNOSTIC_SA_EXPIRED;
- goto bail;
- }
- if ((kmp != 0) &&
- ((ipsapp->ipsap_sa_ptr->ipsa_kmp != 0) ||
- (ipsapp->ipsap_sa_ptr->ipsa_kmp != kmp))) {
- *diagnostic = SADB_X_DIAGNOSTIC_DUPLICATE_KMP;
- error = EINVAL;
- goto bail;
- }
- if ((kmc != 0) &&
- ((ipsapp->ipsap_sa_ptr->ipsa_kmc != 0) ||
- (ipsapp->ipsap_sa_ptr->ipsa_kmc != kmc))) {
- *diagnostic = SADB_X_DIAGNOSTIC_DUPLICATE_KMC;
- error = EINVAL;
- goto bail;
- }
+ if ((*diagnostic = sadb_labelchk(ksi)) != 0)
+ return (EINVAL);
+
+ error = sadb_check_kmc(&sq, ipsapp.ipsap_sa_ptr, diagnostic);
+ if (error != 0)
+ goto bail;
+
+ error = sadb_check_kmc(&sq, ipsapp.ipsap_psa_ptr, diagnostic);
+ if (error != 0)
+ goto bail;
+
+
+ if (ipsapp.ipsap_sa_ptr != NULL) {
/*
* Do not allow replay value change for MATURE or LARVAL SA.
*/
if ((replext != NULL) &&
- ((ipsapp->ipsap_sa_ptr->ipsa_state == IPSA_STATE_LARVAL) ||
- (ipsapp->ipsap_sa_ptr->ipsa_state == IPSA_STATE_MATURE))) {
+ ((ipsapp.ipsap_sa_ptr->ipsa_state == IPSA_STATE_LARVAL) ||
+ (ipsapp.ipsap_sa_ptr->ipsa_state == IPSA_STATE_MATURE))) {
*diagnostic = SADB_X_DIAGNOSTIC_BAD_SASTATE;
error = EINVAL;
goto bail;
}
}
- if (ipsapp->ipsap_psa_ptr != NULL) {
- if (ipsapp->ipsap_psa_ptr->ipsa_state == IPSA_STATE_DEAD) {
- *diagnostic = SADB_X_DIAGNOSTIC_SA_EXPIRED;
- error = ESRCH; /* DEAD == Not there, in this case. */
- goto bail;
- }
- if ((kmp != 0) &&
- ((ipsapp->ipsap_psa_ptr->ipsa_kmp != 0) ||
- (ipsapp->ipsap_psa_ptr->ipsa_kmp != kmp))) {
- *diagnostic = SADB_X_DIAGNOSTIC_DUPLICATE_KMP;
- error = EINVAL;
- goto bail;
- }
- if ((kmc != 0) &&
- ((ipsapp->ipsap_psa_ptr->ipsa_kmc != 0) ||
- (ipsapp->ipsap_psa_ptr->ipsa_kmc != kmc))) {
- *diagnostic = SADB_X_DIAGNOSTIC_DUPLICATE_KMC;
- error = EINVAL;
- goto bail;
- }
- }
- if (ipsapp->ipsap_sa_ptr != NULL) {
- sadb_update_lifetimes(ipsapp->ipsap_sa_ptr, hard, soft,
+ if (ipsapp.ipsap_sa_ptr != NULL) {
+ sadb_update_lifetimes(ipsapp.ipsap_sa_ptr, hard, soft,
idle, B_TRUE);
- if (kmp != 0)
- ipsapp->ipsap_sa_ptr->ipsa_kmp = kmp;
- if (kmc != 0)
- ipsapp->ipsap_sa_ptr->ipsa_kmc = kmc;
+ sadb_update_kmc(&sq, ipsapp.ipsap_sa_ptr);
if ((replext != NULL) &&
- (ipsapp->ipsap_sa_ptr->ipsa_replay_wsize != 0)) {
+ (ipsapp.ipsap_sa_ptr->ipsa_replay_wsize != 0)) {
/*
* If an inbound SA, update the replay counter
* and check off all the other sequence number
*/
if (ksi->ks_in_dsttype == KS_IN_ADDR_ME) {
- if (!sadb_replay_check(ipsapp->ipsap_sa_ptr,
+ if (!sadb_replay_check(ipsapp.ipsap_sa_ptr,
replext->sadb_x_rc_replay32)) {
*diagnostic =
SADB_X_DIAGNOSTIC_INVALID_REPLAY;
error = EINVAL;
goto bail;
}
- mutex_enter(&ipsapp->ipsap_sa_ptr->ipsa_lock);
- ipsapp->ipsap_sa_ptr->ipsa_idleexpiretime =
+ mutex_enter(&ipsapp.ipsap_sa_ptr->ipsa_lock);
+ ipsapp.ipsap_sa_ptr->ipsa_idleexpiretime =
current +
- ipsapp->ipsap_sa_ptr->ipsa_idletime;
- mutex_exit(&ipsapp->ipsap_sa_ptr->ipsa_lock);
+ ipsapp.ipsap_sa_ptr->ipsa_idletime;
+ mutex_exit(&ipsapp.ipsap_sa_ptr->ipsa_lock);
} else {
- mutex_enter(&ipsapp->ipsap_sa_ptr->ipsa_lock);
- ipsapp->ipsap_sa_ptr->ipsa_replay =
+ mutex_enter(&ipsapp.ipsap_sa_ptr->ipsa_lock);
+ ipsapp.ipsap_sa_ptr->ipsa_replay =
replext->sadb_x_rc_replay32;
- ipsapp->ipsap_sa_ptr->ipsa_idleexpiretime =
+ ipsapp.ipsap_sa_ptr->ipsa_idleexpiretime =
current +
- ipsapp->ipsap_sa_ptr->ipsa_idletime;
- mutex_exit(&ipsapp->ipsap_sa_ptr->ipsa_lock);
+ ipsapp.ipsap_sa_ptr->ipsa_idletime;
+ mutex_exit(&ipsapp.ipsap_sa_ptr->ipsa_lock);
}
}
}
if (sadb_msg_type == SADB_X_UPDATEPAIR) {
- if (ipsapp->ipsap_psa_ptr != NULL) {
- sadb_update_lifetimes(ipsapp->ipsap_psa_ptr, hard, soft,
+ if (ipsapp.ipsap_psa_ptr != NULL) {
+ sadb_update_lifetimes(ipsapp.ipsap_psa_ptr, hard, soft,
idle, B_FALSE);
- if (kmp != 0)
- ipsapp->ipsap_psa_ptr->ipsa_kmp = kmp;
- if (kmc != 0)
- ipsapp->ipsap_psa_ptr->ipsa_kmc = kmc;
+ sadb_update_kmc(&sq, ipsapp.ipsap_psa_ptr);
} else {
*diagnostic = SADB_X_DIAGNOSTIC_PAIR_SA_NOTFOUND;
error = ESRCH;
@@ -4980,32 +5103,28 @@
}
if (pair_ext != NULL)
- error = update_pairing(ipsapp, ksi, diagnostic, spp);
+ error = update_pairing(&ipsapp, &sq, ksi, diagnostic);
if (error == 0)
sadb_pfkey_echo(pfkey_q, mp, (sadb_msg_t *)mp->b_cont->b_rptr,
ksi, echo_target);
bail:
- destroy_ipsa_pair(ipsapp);
+ destroy_ipsa_pair(&ipsapp);
return (error);
}
-int
-update_pairing(ipsap_t *ipsapp, keysock_in_t *ksi, int *diagnostic,
- sadbp_t *spp)
+static int
+update_pairing(ipsap_t *ipsapp, ipsa_query_t *sq, keysock_in_t *ksi,
+ int *diagnostic)
{
sadb_sa_t *assoc = (sadb_sa_t *)ksi->ks_in_extv[SADB_EXT_SA];
- sadb_address_t *srcext =
- (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_SRC];
- sadb_address_t *dstext =
- (sadb_address_t *)ksi->ks_in_extv[SADB_EXT_ADDRESS_DST];
sadb_x_pair_t *pair_ext =
(sadb_x_pair_t *)ksi->ks_in_extv[SADB_X_EXT_PAIR];
int error = 0;
- ipsap_t *oipsapp = NULL;
+ ipsap_t oipsapp;
boolean_t undo_pair = B_FALSE;
uint32_t ipsa_flags;
@@ -5035,24 +5154,23 @@
* good, complete the update. IPSA_REFRELE the first pair_pointer
* after this update to ensure its not deleted until we are done.
*/
- oipsapp = get_ipsa_pair(assoc, srcext, dstext, spp);
- if (oipsapp == NULL) {
+ error = get_ipsa_pair(sq, &oipsapp, diagnostic);
+ if (error != 0) {
/*
* This should never happen, calling function still has
* IPSA_REFHELD on the SA we just updated.
*/
- *diagnostic = SADB_X_DIAGNOSTIC_PAIR_SA_NOTFOUND;
- return (EINVAL);
+ return (error); /* XXX EINVAL instead of ESRCH? */
}
- if (oipsapp->ipsap_psa_ptr == NULL) {
+ if (oipsapp.ipsap_psa_ptr == NULL) {
*diagnostic = SADB_X_DIAGNOSTIC_PAIR_INAPPROPRIATE;
error = EINVAL;
undo_pair = B_TRUE;
} else {
- ipsa_flags = oipsapp->ipsap_psa_ptr->ipsa_flags;
- if ((oipsapp->ipsap_psa_ptr->ipsa_state == IPSA_STATE_DEAD) ||
- (oipsapp->ipsap_psa_ptr->ipsa_state == IPSA_STATE_DYING)) {
+ ipsa_flags = oipsapp.ipsap_psa_ptr->ipsa_flags;
+ if ((oipsapp.ipsap_psa_ptr->ipsa_state == IPSA_STATE_DEAD) ||
+ (oipsapp.ipsap_psa_ptr->ipsa_state == IPSA_STATE_DYING)) {
/* Its dead Jim! */
*diagnostic = SADB_X_DIAGNOSTIC_PAIR_INAPPROPRIATE;
undo_pair = B_TRUE;
@@ -5075,13 +5193,13 @@
ipsapp->ipsap_sa_ptr->ipsa_otherspi = 0;
mutex_exit(&ipsapp->ipsap_sa_ptr->ipsa_lock);
} else {
- mutex_enter(&oipsapp->ipsap_psa_ptr->ipsa_lock);
- oipsapp->ipsap_psa_ptr->ipsa_otherspi = assoc->sadb_sa_spi;
- oipsapp->ipsap_psa_ptr->ipsa_flags |= IPSA_F_PAIRED;
- mutex_exit(&oipsapp->ipsap_psa_ptr->ipsa_lock);
+ mutex_enter(&oipsapp.ipsap_psa_ptr->ipsa_lock);
+ oipsapp.ipsap_psa_ptr->ipsa_otherspi = assoc->sadb_sa_spi;
+ oipsapp.ipsap_psa_ptr->ipsa_flags |= IPSA_F_PAIRED;
+ mutex_exit(&oipsapp.ipsap_psa_ptr->ipsa_lock);
}
- destroy_ipsa_pair(oipsapp);
+ destroy_ipsa_pair(&oipsapp);
return (error);
}
@@ -5098,11 +5216,13 @@
/*
* Check the ACQUIRE lists. If there's an existing ACQUIRE record,
* grab it, lock it, and return it. Otherwise return NULL.
+ *
+ * XXX MLS number of arguments getting unwieldy here
*/
static ipsacq_t *
sadb_checkacquire(iacqf_t *bucket, ipsec_action_t *ap, ipsec_policy_t *pp,
uint32_t *src, uint32_t *dst, uint32_t *isrc, uint32_t *idst,
- uint64_t unique_id)
+ uint64_t unique_id, cred_t *cr)
{
ipsacq_t *walker;
sa_family_t fam;
@@ -5131,7 +5251,8 @@
(ap == walker->ipsacq_act) &&
(pp == walker->ipsacq_policy) &&
/* XXX do deep compares of ap/pp? */
- (unique_id == walker->ipsacq_unique_id))
+ (unique_id == walker->ipsacq_unique_id) &&
+ (ipsec_label_match(cr, walker->ipsacq_cred)))
break; /* everything matched */
mutex_exit(&walker->ipsacq_lock);
}
@@ -5169,12 +5290,16 @@
uint64_t unique_id = 0;
ipsec_selector_t sel;
boolean_t tunnel_mode = io->ipsec_out_tunnel;
+ cred_t *cr = NULL;
netstack_t *ns = io->ipsec_out_ns;
ipsec_stack_t *ipss = ns->netstack_ipsec;
+ sadb_sens_t *sens = NULL;
+ int sens_len;
ASSERT((pp != NULL) || (ap != NULL));
ASSERT(need_ah != NULL || need_esp != NULL);
+
/* Assign sadb pointers */
if (need_esp) { /* ESP for AH+ESP */
ipsecesp_stack_t *espstack = ns->netstack_ipsecesp;
@@ -5187,6 +5312,11 @@
}
sp = io->ipsec_out_v4 ? &spp->s_v4 : &spp->s_v6;
+ ASSERT(mp->b_cont != NULL);
+
+ if (is_system_labeled())
+ cr = msg_getcred(mp->b_cont, NULL);
+
if (ap == NULL)
ap = pp->ipsp_act;
@@ -5247,7 +5377,7 @@
bucket = &(sp->sdb_acq[hashoffset]);
mutex_enter(&bucket->iacqf_lock);
newbie = sadb_checkacquire(bucket, ap, pp, src, dst, isrc, idst,
- unique_id);
+ unique_id, cr);
if (newbie == NULL) {
/*
@@ -5272,11 +5402,24 @@
newbie->ipsacq_ptpn = &bucket->iacqf_ipsacq;
if (newbie->ipsacq_next != NULL)
newbie->ipsacq_next->ipsacq_ptpn = &newbie->ipsacq_next;
+
bucket->iacqf_ipsacq = newbie;
mutex_init(&newbie->ipsacq_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_enter(&newbie->ipsacq_lock);
}
+ /*
+ * XXX MLS does it actually help us to drop the bucket lock here?
+ * we have inserted a half-built, locked acquire record into the
+ * bucket. any competing thread will now be able to lock the bucket
+ * to scan it, but will immediately pile up on the new acquire
+ * record's lock; I don't think we gain anything here other than to
+ * disperse blame for lock contention.
+ *
+ * we might be able to dispense with acquire record locks entirely..
+ * just use the bucket locks..
+ */
+
mutex_exit(&bucket->iacqf_lock);
/*
@@ -5318,6 +5461,11 @@
newbie->ipsacq_proto = io->ipsec_out_proto;
}
newbie->ipsacq_unique_id = unique_id;
+
+ if (cr != NULL) {
+ crhold(cr);
+ newbie->ipsacq_cred = cr;
+ }
} else {
/* Scan to the end of the list & insert. */
mblk_t *lastone = newbie->ipsacq_mp;
@@ -5358,44 +5506,61 @@
return;
}
- if (keysock_extended_reg(ns)) {
+ if (!keysock_extended_reg(ns))
+ goto punt_extended;
+ /*
+ * Construct an extended ACQUIRE. There are logging
+ * opportunities here in failure cases.
+ */
+ (void) memset(&sel, 0, sizeof (sel));
+ sel.ips_isv4 = io->ipsec_out_v4;
+ if (tunnel_mode) {
+ sel.ips_protocol = (io->ipsec_out_inaf == AF_INET) ?
+ IPPROTO_ENCAP : IPPROTO_IPV6;
+ } else {
+ sel.ips_protocol = io->ipsec_out_proto;
+ sel.ips_local_port = io->ipsec_out_src_port;
+ sel.ips_remote_port = io->ipsec_out_dst_port;
+ }
+ sel.ips_icmp_type = io->ipsec_out_icmp_type;
+ sel.ips_icmp_code = io->ipsec_out_icmp_code;
+ sel.ips_is_icmp_inv_acq = 0;
+ if (af == AF_INET) {
+ sel.ips_local_addr_v4 = ipha->ipha_src;
+ sel.ips_remote_addr_v4 = ipha->ipha_dst;
+ } else {
+ sel.ips_local_addr_v6 = ip6h->ip6_src;
+ sel.ips_remote_addr_v6 = ip6h->ip6_dst;
+ }
+
+ extended = sadb_keysock_out(0);
+ if (extended == NULL)
+ goto punt_extended;
+
+ if (cr != NULL) {
/*
- * Construct an extended ACQUIRE. There are logging
- * opportunities here in failure cases.
+ * XXX MLS correct condition here?
+ * XXX MLS other credential attributes in acquire?
+ * XXX malloc failure? don't fall back to original?
*/
+ sens = sadb_make_sens_ext(cr, &sens_len);
- (void) memset(&sel, 0, sizeof (sel));
- sel.ips_isv4 = io->ipsec_out_v4;
- if (tunnel_mode) {
- sel.ips_protocol = (io->ipsec_out_inaf == AF_INET) ?
- IPPROTO_ENCAP : IPPROTO_IPV6;
- } else {
- sel.ips_protocol = io->ipsec_out_proto;
- sel.ips_local_port = io->ipsec_out_src_port;
- sel.ips_remote_port = io->ipsec_out_dst_port;
+ if (sens == NULL) {
+ freeb(extended);
+ goto punt_extended;
}
- sel.ips_icmp_type = io->ipsec_out_icmp_type;
- sel.ips_icmp_code = io->ipsec_out_icmp_code;
- sel.ips_is_icmp_inv_acq = 0;
- if (af == AF_INET) {
- sel.ips_local_addr_v4 = ipha->ipha_src;
- sel.ips_remote_addr_v4 = ipha->ipha_dst;
- } else {
- sel.ips_local_addr_v6 = ip6h->ip6_src;
- sel.ips_remote_addr_v6 = ip6h->ip6_dst;
- }
+ }
- extended = sadb_keysock_out(0);
- if (extended != NULL) {
- extended->b_cont = sadb_extended_acquire(&sel, pp, ap,
- tunnel_mode, seq, 0, ns);
- if (extended->b_cont == NULL) {
- freeb(extended);
- extended = NULL;
- }
- }
- } else
- extended = NULL;
+ extended->b_cont = sadb_extended_acquire(&sel, pp, ap, tunnel_mode,
+ seq, 0, sens, ns);
+
+ if (sens != NULL)
+ kmem_free(sens, sens_len);
+
+ if (extended->b_cont == NULL) {
+ freeb(extended);
+ goto punt_extended;
+ }
/*
* Send an ACQUIRE message (and possible an extended ACQUIRE) based on
@@ -5403,6 +5568,10 @@
* already locked.
*/
(*spp->s_acqfn)(newbie, extended, ns);
+ return;
+
+punt_extended:
+ (*spp->s_acqfn)(newbie, NULL, ns);
}
/*
@@ -5428,6 +5597,11 @@
if (acqrec->ipsacq_next != NULL)
acqrec->ipsacq_next->ipsacq_ptpn = acqrec->ipsacq_ptpn;
+ if (acqrec->ipsacq_cred) {
+ crfree(acqrec->ipsacq_cred);
+ acqrec->ipsacq_cred = NULL;
+ }
+
/*
* Free hanging mp's.
*
@@ -5605,6 +5779,101 @@
return (cur);
}
+#include <sys/tsol/label_macro.h> /* XXX should not need this */
+
+/*
+ * From a cred_t, construct a sensitivity label extension
+ *
+ * We send up a fixed-size sensitivity label bitmap, and are perhaps
+ * overly chummy with the underlying data structures here.
+ */
+
+/* ARGSUSED */
+int
+sadb_sens_len_from_cred(cred_t *cr)
+{
+ int baselen = sizeof (sadb_sens_t) + _C_LEN * 4;
+ return (roundup(baselen, sizeof (uint64_t)));
+}
+
+void
+sadb_sens_from_cred(sadb_sens_t *sens, int exttype, cred_t *cr, int senslen)
+{
+ uint8_t *bitmap;
+ bslabel_t *sl;
+ ts_label_t *tsl;
+
+ /* LINTED */
+ ASSERT((_C_LEN & 1) == 0);
+ ASSERT((senslen & 7) == 0);
+
+ tsl = crgetlabel(cr);
+ sl = label2bslabel(tsl);
+
+ sens->sadb_sens_exttype = exttype;
+ sens->sadb_sens_len = SADB_8TO64(senslen);
+
+ sens->sadb_sens_dpd = tsl->tsl_doi;
+ sens->sadb_sens_sens_level = LCLASS(sl);
+ sens->sadb_sens_integ_level = 0; /* TBD */
+ sens->sadb_sens_sens_len = _C_LEN >> 1;
+ sens->sadb_sens_integ_len = 0; /* TBD */
+ sens->sadb_x_sens_flags = 0;
+
+ bitmap = (uint8_t *)(sens + 1);
+ bcopy(&(((_bslabel_impl_t *)sl)->compartments), bitmap, _C_LEN * 4);
+}
+
+static sadb_sens_t *
+sadb_make_sens_ext(cred_t *cr, int *len)
+{
+ /* XXX allocation failure? */
+ int sens_len = sadb_sens_len_from_cred(cr);
+
+ sadb_sens_t *sens = kmem_alloc(sens_len, KM_SLEEP);
+
+ sadb_sens_from_cred(sens, SADB_EXT_SENSITIVITY, cr, sens_len);
+
+ *len = sens_len;
+
+ return (sens);
+}
+
+/*
+ * Okay, how do we report errors/invalid labels from this?
+ * With a special designated "not a label" cred_t ?
+ */
+/* ARGSUSED */
+cred_t *
+sadb_cred_from_sens(sadb_sens_t *sens, uint64_t *bitmap)
+{
+ int bitmap_len = SADB_64TO8(sens->sadb_sens_sens_len);
+ bslabel_t sl;
+ cred_t *cr;
+
+ if (sens->sadb_sens_integ_level != 0)
+ return (NULL);
+ if (sens->sadb_sens_integ_len != 0)
+ return (NULL);
+ if (bitmap_len > _C_LEN * 4)
+ return (NULL);
+
+ bsllow(&sl);
+ LCLASS_SET((_bslabel_impl_t *)&sl, sens->sadb_sens_sens_level);
+ bcopy(bitmap, &((_bslabel_impl_t *)&sl)->compartments,
+ bitmap_len);
+
+ cr = newcred_from_bslabel(&sl, sens->sadb_sens_dpd, KM_NOSLEEP);
+ if (cr == NULL)
+ return (cr);
+
+ if (sens->sadb_x_sens_flags & SADB_X_SENS_UNLABELED)
+ crgetlabel(cr)->tsl_flags |= TSLF_UNLABELED;
+ return (cr);
+}
+
+/* End XXX label-library-leakage */
+
/*
* Construct an extended ACQUIRE message based on a selector and the resulting
* IPsec action.
@@ -5616,7 +5885,7 @@
static mblk_t *
sadb_extended_acquire(ipsec_selector_t *sel, ipsec_policy_t *pol,
ipsec_action_t *act, boolean_t tunnel_mode, uint32_t seq, uint32_t pid,
- netstack_t *ns)
+ sadb_sens_t *sens, netstack_t *ns)
{
mblk_t *mp;
sadb_msg_t *samsg;
@@ -5781,6 +6050,18 @@
return (NULL);
}
+ if (sens != NULL) {
+ uint8_t *sensext = cur;
+ int senslen = SADB_64TO8(sens->sadb_sens_len);
+
+ cur += senslen;
+ if (cur > end) {
+ freeb(mp);
+ return (NULL);
+ }
+ bcopy(sens, sensext, senslen);
+ }
+
/*
* This section will change a lot as policy evolves.
* For now, it'll be relatively simple.
@@ -6827,6 +7108,9 @@
* in this function so the caller can extract them where appropriately.
*
* The SRC address is the local one - just like an outbound ACQUIRE message.
+ *
+ * XXX MLS: key management supplies a label which we just reflect back up
+ * again. clearly we need to involve the label in the rest of the checks.
*/
mblk_t *
ipsec_construct_inverse_acquire(sadb_msg_t *samsg, sadb_ext_t *extv[],
@@ -6838,6 +7122,7 @@
*dstext = (sadb_address_t *)extv[SADB_EXT_ADDRESS_DST],
*innsrcext = (sadb_address_t *)extv[SADB_X_EXT_ADDRESS_INNER_SRC],
*inndstext = (sadb_address_t *)extv[SADB_X_EXT_ADDRESS_INNER_DST];
+ sadb_sens_t *sens = (sadb_sens_t *)extv[SADB_EXT_SENSITIVITY];
struct sockaddr_in6 *src, *dst;
struct sockaddr_in6 *isrc, *idst;
ipsec_tun_pol_t *itp = NULL;
@@ -6846,6 +7131,7 @@
mblk_t *retmp = NULL;
ip_stack_t *ipst = ns->netstack_ip;
+
/* Normalize addresses */
if (sadb_addrcheck(NULL, (mblk_t *)samsg, (sadb_ext_t *)srcext, 0, ns)
== KS_IN_ADDR_UNKNOWN) {
@@ -6989,7 +7275,7 @@
*/
retmp = sadb_extended_acquire(&sel, pp, NULL,
(itp != NULL && (itp->itp_flags & ITPF_P_TUNNEL)),
- samsg->sadb_msg_seq, samsg->sadb_msg_pid, ns);
+ samsg->sadb_msg_seq, samsg->sadb_msg_pid, sens, ns);
if (pp != NULL) {
IPPOL_REFRELE(pp, ns);
}
@@ -7396,6 +7682,180 @@
return (-1);
}
+
+/*
+ * Whack options in the outer IP header when ipsec changes the outer label
+ *
+ * This is inelegant and really could use refactoring.
+ */
+int
+sadb_whack_label(mblk_t **mpp, ipsa_t *assoc)
+{
+ int delta;
+ int plen;
+ dblk_t *db;
+ int hlen;
+ uint8_t *opt_storage = assoc->ipsa_opt_storage;
+ mblk_t *mp = *mpp;
+ ipha_t *ipha = (ipha_t *)mp->b_rptr;
+
+ plen = ntohs(ipha->ipha_length);
+
+ delta = tsol_remove_secopt(ipha, MBLKL(mp));
+ mp->b_wptr += delta;
+ plen += delta;
+
+ /* XXX XXX code copied from tsol_check_label */
+
+ /* Make sure we have room for the worst-case addition */
+ hlen = IPH_HDR_LENGTH(ipha) + opt_storage[IPOPT_OLEN];
+ hlen = (hlen + 3) & ~3;
+ if (hlen > IP_MAX_HDR_LENGTH)
+ hlen = IP_MAX_HDR_LENGTH;
+ hlen -= IPH_HDR_LENGTH(ipha);
+
+ db = mp->b_datap;
+ if ((db->db_ref != 1) || (mp->b_wptr + hlen > db->db_lim)) {
+ int copylen;
+ mblk_t *new_mp;
+
+ /* allocate enough to be meaningful, but not *too* much */
+ copylen = MBLKL(mp);
+ if (copylen > 256)
+ copylen = 256;
+ new_mp = allocb_tmpl(hlen + copylen +
+ (mp->b_rptr - mp->b_datap->db_base), mp);
+
+ if (new_mp == NULL)
+ return (ENOMEM);
+
+ /* keep the bias */
+ new_mp->b_rptr += mp->b_rptr - mp->b_datap->db_base;
+ new_mp->b_wptr = new_mp->b_rptr + copylen;
+ bcopy(mp->b_rptr, new_mp->b_rptr, copylen);
+ new_mp->b_cont = mp;
+ if ((mp->b_rptr += copylen) >= mp->b_wptr) {
+ new_mp->b_cont = mp->b_cont;
+ freeb(mp);
+ }
+ *mpp = mp = new_mp;
+ ipha = (ipha_t *)mp->b_rptr;
+ }
+
+ delta = tsol_prepend_option(assoc->ipsa_opt_storage, ipha, MBLKL(mp));
+
+ ASSERT(delta != -1);
+
+ plen += delta;
+ mp->b_wptr += delta;
+
+ /*
+ * Paranoia
+ */
+ db = mp->b_datap;
+
+ ASSERT3P(mp->b_wptr, <=, db->db_lim);
+ ASSERT3P(mp->b_rptr, <=, db->db_lim);
+
+ ASSERT3P(mp->b_wptr, >=, db->db_base);
+ ASSERT3P(mp->b_rptr, >=, db->db_base);
+ /* End paranoia */
+
+ ipha->ipha_length = htons(plen);
+
+ return (0);
+}
+
+int
+sadb_whack_label_v6(mblk_t **mpp, ipsa_t *assoc)
+{
+ int delta;
+ int plen;
+ dblk_t *db;
+ int hlen;
+ uint8_t *opt_storage = assoc->ipsa_opt_storage;
+ uint_t sec_opt_len; /* label option length not including type, len */
+ mblk_t *mp = *mpp;
+ ip6_t *ip6h = (ip6_t *)mp->b_rptr;
+
+ plen = ntohs(ip6h->ip6_plen);
+
+ delta = tsol_remove_secopt_v6(ip6h, MBLKL(mp));
+ mp->b_wptr += delta;
+ plen += delta;
+
+ /* XXX XXX code copied from tsol_check_label_v6 */
+ /*
+ * Make sure we have room for the worst-case addition. Add 2 bytes for
+ * the hop-by-hop ext header's next header and length fields. Add
+ * another 2 bytes for the label option type, len and then round
+ * up to the next 8-byte multiple.
+ */
+ sec_opt_len = opt_storage[1];
+
+ db = mp->b_datap;
+ hlen = (4 + sec_opt_len + 7) & ~7;
+
+ if ((db->db_ref != 1) || (mp->b_wptr + hlen > db->db_lim)) {
+ int copylen;
+ mblk_t *new_mp;
+ uint16_t hdr_len;
+
+ hdr_len = ip_hdr_length_v6(mp, ip6h);
+ /*
+ * Allocate enough to be meaningful, but not *too* much.
+ * Also all the IPv6 extension headers must be in the same mblk
+ */
+ copylen = MBLKL(mp);
+ if (copylen > 256)
+ copylen = 256;
+ if (copylen < hdr_len)
+ copylen = hdr_len;
+ new_mp = allocb_tmpl(hlen + copylen +
+ (mp->b_rptr - mp->b_datap->db_base), mp);
+ if (new_mp == NULL)
+ return (ENOMEM);
+
+ /* keep the bias */
+ new_mp->b_rptr += mp->b_rptr - mp->b_datap->db_base;
+ new_mp->b_wptr = new_mp->b_rptr + copylen;
+ bcopy(mp->b_rptr, new_mp->b_rptr, copylen);
+ new_mp->b_cont = mp;
+ if ((mp->b_rptr += copylen) >= mp->b_wptr) {
+ new_mp->b_cont = mp->b_cont;
+ freeb(mp);
+ }
+ *mpp = mp = new_mp;
+ ip6h = (ip6_t *)mp->b_rptr;
+ }
+
+ delta = tsol_prepend_option_v6(assoc->ipsa_opt_storage,
+ ip6h, MBLKL(mp));
+
+ ASSERT(delta != -1);
+
+ plen += delta;
+ mp->b_wptr += delta;
+
+ /*
+ * Paranoia
+ */
+ db = mp->b_datap;
+
+ ASSERT3P(mp->b_wptr, <=, db->db_lim);
+ ASSERT3P(mp->b_rptr, <=, db->db_lim);
+
+ ASSERT3P(mp->b_wptr, >=, db->db_base);
+ ASSERT3P(mp->b_rptr, >=, db->db_base);
+ /* End paranoia */
+
+ ip6h->ip6_plen = htons(plen);
+
+ return (0);
+}
+
+
+
/*
* If this is an outgoing SA then add some fuzz to the
* SOFT EXPIRE time. The reason for this is to stop
@@ -7405,7 +7865,7 @@
* sadb_ager(), although this is only a guide as it
* selftunes.
*/
-void
+static void
lifetime_fuzz(ipsa_t *assoc)
{
uint8_t rnd;
@@ -7418,12 +7878,10 @@
assoc->ipsa_softexpiretime -= rnd;
assoc->ipsa_softaddlt -= rnd;
}
-void
+
+static void
destroy_ipsa_pair(ipsap_t *ipsapp)
{
- if (ipsapp == NULL)
- return;
-
/*
* Because of the multi-line macro nature of IPSA_REFRELE, keep
* them in { }.
@@ -7434,8 +7892,16 @@
if (ipsapp->ipsap_psa_ptr != NULL) {
IPSA_REFRELE(ipsapp->ipsap_psa_ptr);
}
+ init_ipsa_pair(ipsapp);
+}
- kmem_free(ipsapp, sizeof (*ipsapp));
+static void
+init_ipsa_pair(ipsap_t *ipsapp)
+{
+ ipsapp->ipsap_bucket = NULL;
+ ipsapp->ipsap_sa_ptr = NULL;
+ ipsapp->ipsap_pbucket = NULL;
+ ipsapp->ipsap_psa_ptr = NULL;
}
/*
diff --git a/usr/src/uts/common/inet/ip/spd.c b/usr/src/uts/common/inet/ip/spd.c
index 2767436..37a9f47 100644
--- a/usr/src/uts/common/inet/ip/spd.c
+++ b/usr/src/uts/common/inet/ip/spd.c
@@ -35,6 +35,7 @@
#include <sys/stropts.h>
#include <sys/sysmacros.h>
#include <sys/strsubr.h>
+#include <sys/strsun.h>
#include <sys/strlog.h>
#include <sys/cmn_err.h>
#include <sys/zone.h>
@@ -2221,6 +2222,27 @@
IPPOL_REFHOLD(p);
}
/*
+ * The caller may have mistakenly assigned an ip6i_t as the
+ * ip6h for this packet, so take that corner-case into
+ * account.
+ */
+ if (ip6h != NULL && ip6h->ip6_nxt == IPPROTO_RAW) {
+ ip6h++;
+ /* First check for bizarro split-mblk headers. */
+ if ((uintptr_t)ip6h > (uintptr_t)data_mp->b_wptr ||
+ ((uintptr_t)ip6h) + sizeof (ip6_t) >
+ (uintptr_t)data_mp->b_wptr) {
+ ipsec_log_policy_failure(IPSEC_POLICY_MISMATCH,
+ "ipsec_check_global_policy", ipha, ip6h,
+ B_TRUE, ns);
+ counter = DROPPER(ipss, ipds_spd_nomem);
+ goto fail;
+ }
+ /* Next, see if ip6i is at the end of an mblk. */
+ if (ip6h == (ip6_t *)data_mp->b_wptr)
+ ip6h = (ip6_t *)data_mp->b_cont->b_rptr;
+ }
+ /*
* Fudge sel for UNIQUE_ID setting below.
*/
pkt_unique = conn_to_unique(connp, data_mp, ipha, ip6h);
@@ -2233,7 +2255,7 @@
* an internal failure.
*/
ipsec_log_policy_failure(IPSEC_POLICY_MISMATCH,
- "ipsec_init_inbound_sel", ipha, ip6h, B_FALSE, ns);
+ "ipsec_init_inbound_sel", ipha, ip6h, B_TRUE, ns);
counter = DROPPER(ipss, ipds_spd_nomem);
goto fail;
}
@@ -2708,6 +2730,43 @@
}
/*
+ * Handle all sorts of cases like tunnel-mode, ICMP, and ip6i prepending.
+ */
+static int
+prepended_length(mblk_t *mp, uintptr_t hptr)
+{
+ int rc = 0;
+
+ while (mp != NULL) {
+ if (hptr >= (uintptr_t)mp->b_rptr && hptr <
+ (uintptr_t)mp->b_wptr) {
+ rc += (int)(hptr - (uintptr_t)mp->b_rptr);
+ break; /* out of while loop */
+ }
+ rc += (int)MBLKL(mp);
+ mp = mp->b_cont;
+ }
+
+ if (mp == NULL) {
+ /*
+ * IF (big IF) we make it here by naturally exiting the loop,
+ * then ip6h isn't in the mblk chain "mp" at all.
+ *
+ * The only case where this happens is with a reversed IP
+ * header that gets passed up by inbound ICMP processing.
+ * This unfortunately triggers longstanding bug 6478464. For
+ * now, just pass up 0 for the answer.
+ */
+#ifdef DEBUG_NOT_UNTIL_6478464
+ ASSERT(mp != NULL);
+#endif
+ rc = 0;
+ }
+
+ return (rc);
+}
+
+/*
* Returns:
*
* SELRET_NOMEM --> msgpullup() needed to gather things failed.
@@ -2726,13 +2785,12 @@
ip6_t *ip6h, uint8_t sel_flags)
{
uint16_t *ports;
+ int outer_hdr_len = 0; /* For ICMP, tunnel-mode, or ip6i cases... */
ushort_t hdr_len;
- int outer_hdr_len = 0; /* For ICMP tunnel-mode cases... */
mblk_t *spare_mp = NULL;
- uint8_t *nexthdrp;
+ uint8_t *nexthdrp, *transportp;
uint8_t nexthdr;
- uint8_t *typecode;
- uint8_t check_proto;
+ uint8_t icmp_proto;
ip6_pkt_t ipp;
boolean_t port_policy_present = (sel_flags & SEL_PORT_POLICY);
boolean_t is_icmp = (sel_flags & SEL_IS_ICMP);
@@ -2743,10 +2801,39 @@
(ipha != NULL && ip6h == NULL));
if (ip6h != NULL) {
- if (is_icmp || tunnel_mode)
- outer_hdr_len = ((uint8_t *)ip6h) - mp->b_rptr;
+ outer_hdr_len = prepended_length(mp, (uintptr_t)ip6h);
- check_proto = IPPROTO_ICMPV6;
+ nexthdr = ip6h->ip6_nxt;
+
+ /*
+ * The caller may have mistakenly assigned an ip6i_t as the
+ * ip6h for this packet, so take that corner-case into
+ * account.
+ */
+ if (nexthdr == IPPROTO_RAW) {
+ ip6h++;
+ /* First check for bizarro split-mblk headers. */
+ if ((uintptr_t)ip6h > (uintptr_t)mp->b_wptr ||
+ ((uintptr_t)ip6h) + sizeof (ip6_t) >
+ (uintptr_t)mp->b_wptr) {
+ return (SELRET_BADPKT);
+ }
+ /* Next, see if ip6i is at the end of an mblk. */
+ if (ip6h == (ip6_t *)mp->b_wptr)
+ ip6h = (ip6_t *)mp->b_cont->b_rptr;
+
+ nexthdr = ip6h->ip6_nxt;
+
+ /*
+ * Finally, if we haven't adjusted for ip6i, do so
+ * now. ip6i_t structs are prepended, so an ICMP
+ * or tunnel packet would just be overwritten.
+ */
+ if (outer_hdr_len == 0)
+ outer_hdr_len = sizeof (ip6i_t);
+ }
+
+ icmp_proto = IPPROTO_ICMPV6;
sel->ips_isv4 = B_FALSE;
sel->ips_local_addr_v6 = ip6h->ip6_dst;
sel->ips_remote_addr_v6 = ip6h->ip6_src;
@@ -2754,7 +2841,6 @@
bzero(&ipp, sizeof (ipp));
(void) ip_find_hdr_v6(mp, ip6h, &ipp, NULL);
- nexthdr = ip6h->ip6_nxt;
switch (nexthdr) {
case IPPROTO_HOPOPTS:
case IPPROTO_ROUTING:
@@ -2766,6 +2852,7 @@
*/
if ((spare_mp = msgpullup(mp, -1)) == NULL)
return (SELRET_NOMEM);
+
if (!ip_hdr_length_nexthdr_v6(spare_mp,
(ip6_t *)(spare_mp->b_rptr + outer_hdr_len),
&hdr_len, &nexthdrp)) {
@@ -2786,10 +2873,10 @@
ipsec_freemsg_chain(spare_mp);
return (SELRET_TUNFRAG);
}
+ transportp = (uint8_t *)ip6h + hdr_len;
} else {
- if (is_icmp || tunnel_mode)
- outer_hdr_len = ((uint8_t *)ipha) - mp->b_rptr;
- check_proto = IPPROTO_ICMP;
+ outer_hdr_len = prepended_length(mp, (uintptr_t)ipha);
+ icmp_proto = IPPROTO_ICMP;
sel->ips_isv4 = B_TRUE;
sel->ips_local_addr_v4 = ipha->ipha_dst;
sel->ips_remote_addr_v4 = ipha->ipha_src;
@@ -2803,19 +2890,19 @@
ipsec_freemsg_chain(spare_mp);
return (SELRET_TUNFRAG);
}
-
+ transportp = (uint8_t *)ipha + hdr_len;
}
sel->ips_protocol = nexthdr;
if ((nexthdr != IPPROTO_TCP && nexthdr != IPPROTO_UDP &&
- nexthdr != IPPROTO_SCTP && nexthdr != check_proto) ||
+ nexthdr != IPPROTO_SCTP && nexthdr != icmp_proto) ||
(!port_policy_present && !post_frag && tunnel_mode)) {
sel->ips_remote_port = sel->ips_local_port = 0;
ipsec_freemsg_chain(spare_mp);
return (SELRET_SUCCESS);
}
- if (&mp->b_rptr[hdr_len] + 4 > mp->b_wptr) {
+ if (transportp + 4 > mp->b_wptr) {
/* If we didn't pullup a copy already, do so now. */
/*
* XXX performance, will upper-layers frequently split TCP/UDP
@@ -2827,17 +2914,15 @@
(spare_mp = msgpullup(mp, -1)) == NULL) {
return (SELRET_NOMEM);
}
- ports = (uint16_t *)&spare_mp->b_rptr[hdr_len + outer_hdr_len];
- } else {
- ports = (uint16_t *)&mp->b_rptr[hdr_len + outer_hdr_len];
+ transportp = &spare_mp->b_rptr[hdr_len + outer_hdr_len];
}
- if (nexthdr == check_proto) {
- typecode = (uint8_t *)ports;
- sel->ips_icmp_type = *typecode++;
- sel->ips_icmp_code = *typecode;
+ if (nexthdr == icmp_proto) {
+ sel->ips_icmp_type = *transportp++;
+ sel->ips_icmp_code = *transportp;
sel->ips_remote_port = sel->ips_local_port = 0;
} else {
+ ports = (uint16_t *)transportp;
sel->ips_remote_port = *ports++;
sel->ips_local_port = *ports;
}
@@ -3983,7 +4068,7 @@
* in IP proper.
*/
boolean_t
-ipsec_in_to_out(mblk_t *ipsec_mp, ipha_t *ipha, ip6_t *ip6h)
+ipsec_in_to_out(mblk_t *ipsec_mp, ipha_t *ipha, ip6_t *ip6h, zoneid_t zoneid)
{
ipsec_in_t *ii;
ipsec_out_t *io;
@@ -3993,7 +4078,6 @@
uint_t ifindex;
ipsec_selector_t sel;
ipsec_action_t *reflect_action = NULL;
- zoneid_t zoneid;
netstack_t *ns;
ASSERT(ipsec_mp->b_datap->db_type == M_CTL);
@@ -4013,14 +4097,25 @@
reflect_action = ipsec_in_to_out_action(ii);
secure = ii->ipsec_in_secure;
ifindex = ii->ipsec_in_ill_index;
- zoneid = ii->ipsec_in_zoneid;
- ASSERT(zoneid != ALL_ZONES);
ns = ii->ipsec_in_ns;
v4 = ii->ipsec_in_v4;
ipsec_in_release_refs(ii); /* No netstack_rele/hold needed */
/*
+ * Use the global zone's id if we don't have a specific zone
+ * identified. This is likely to happen when the received packet's
+ * destination is a Trusted Extensions all-zones address. We did
+ * not copy the zoneid from ii->ipsec_in_zone id because that
+ * information represents the zoneid we started input processing
+ * with. The caller should have a better idea of which zone the
+ * received packet was destined for.
+ */
+
+ if (zoneid == ALL_ZONES)
+ zoneid = GLOBAL_ZONEID;
+
+ /*
* The caller is going to send the datagram out which might
* go on the wire or delivered locally through ip_wput_local.
*
@@ -4460,6 +4555,8 @@
ii->ipsec_in_frtn.free_func = ipsec_in_free;
ii->ipsec_in_frtn.free_arg = (char *)ii;
+ ii->ipsec_in_zoneid = ALL_ZONES; /* default for received packets */
+
ipsec_in = desballoc((uint8_t *)ii, sizeof (ipsec_info_t), BPRI_HI,
&ii->ipsec_in_frtn);
if (ipsec_in == NULL) {
diff --git a/usr/src/uts/common/inet/ip/tn_ipopt.c b/usr/src/uts/common/inet/ip/tn_ipopt.c
index dba9b8c..359b8d4 100644
--- a/usr/src/uts/common/inet/ip/tn_ipopt.c
+++ b/usr/src/uts/common/inet/ip/tn_ipopt.c
@@ -272,7 +272,7 @@
*
* 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 cred are needed due to the connection's MAC mode or
* the destination's ability to receive labels, an "effective cred"
* will be returned.
*
@@ -287,7 +287,7 @@
*/
int
tsol_check_dest(const cred_t *credp, const void *dst, uchar_t version,
- boolean_t mac_exempt, cred_t **effective_cred)
+ uint_t mac_mode, cred_t **effective_cred)
{
ts_label_t *tsl, *newtsl = NULL;
tsol_tpc_t *dst_rhtp;
@@ -307,6 +307,14 @@
return (0);
}
+ if (tsl->tsl_flags & TSLF_IMPLICIT_IN) {
+ DTRACE_PROBE3(tx__tnopt__log__info__labeling__unresolved__label,
+ char *,
+ "implicit-in packet to ip(1) reached tsol_check_dest "
+ "with implied security label sl(2)",
+ ipaddr_t, dst, ts_label_t *, tsl);
+ }
+
/* Always pass multicast */
if (version == IPV4_VERSION &&
CLASSD(*(ipaddr_t *)dst)) {
@@ -335,8 +343,10 @@
/*
* 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
+ * (2) SO_MAC_EXEMPT is on and we
+ * dominate the peer's label, or
+ * (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,
@@ -349,7 +359,7 @@
if (!blequal(&dst_rhtp->tpc_tp.tp_def_label,
&tsl->tsl_label)) {
zoneid = crgetzoneid(credp);
- if (!mac_exempt ||
+ if (mac_mode != CONN_MAC_AWARE ||
!(zoneid == GLOBAL_ZONEID ||
bldominates(&tsl->tsl_label,
&dst_rhtp->tpc_tp.tp_def_label))) {
@@ -403,16 +413,22 @@
TPC_RELE(dst_rhtp);
return (EHOSTUNREACH);
}
- if (tsl->tsl_flags & TSLF_UNLABELED) {
+ if ((tsl->tsl_flags & TSLF_UNLABELED) ||
+ (mac_mode == CONN_MAC_IMPLICIT)) {
/*
- * The security label is a match but we need to
- * clear the unlabeled flag for this remote node.
+ * Copy label so we can modify the flags
*/
if ((newtsl = labeldup(tsl, KM_NOSLEEP)) == NULL) {
TPC_RELE(dst_rhtp);
return (ENOMEM);
}
- newtsl->tsl_flags ^= TSLF_UNLABELED;
+ /*
+ * The security label is a match but we need to
+ * clear the unlabeled flag for this remote node.
+ */
+ newtsl->tsl_flags &= ~TSLF_UNLABELED;
+ if (mac_mode == CONN_MAC_IMPLICIT)
+ newtsl->tsl_flags |= TSLF_IMPLICIT_OUT;
}
break;
@@ -473,6 +489,9 @@
if (CLASSD(dst))
return (0);
+ if (tsl->tsl_flags & TSLF_IMPLICIT_OUT)
+ return (0);
+
if (tsl->tsl_flags & TSLF_UNLABELED) {
/*
@@ -807,7 +826,7 @@
* EINVAL Label cannot be computed
*/
int
-tsol_check_label(const cred_t *credp, mblk_t **mpp, boolean_t isexempt,
+tsol_check_label(const cred_t *credp, mblk_t **mpp, uint_t mac_mode,
ip_stack_t *ipst, pid_t pid)
{
mblk_t *mp = *mpp;
@@ -832,7 +851,7 @@
* for use in future routing decisions.
*/
retv = tsol_check_dest(credp, &ipha->ipha_dst, IPV4_VERSION,
- isexempt, &effective_cred);
+ mac_mode, &effective_cred);
if (retv != 0)
return (retv);
@@ -871,6 +890,10 @@
return (0);
}
+ if (msg_getcred(mp, NULL) == NULL) {
+ mblk_setcred(mp, (cred_t *)credp, NOPID);
+ }
+
/*
* If there is an option there, then it must be the wrong one; delete.
*/
@@ -983,6 +1006,9 @@
* that the maximum size of this label is reflected in sys/tsol/tnet.h
* as TSOL_MAX_IPV6_OPTION.
*/
+ if (tsl->tsl_flags & TSLF_IMPLICIT_OUT)
+ return (0);
+
if (tsl->tsl_flags & TSLF_UNLABELED) {
/*
* The destination is unlabeled. Only add a label if the
@@ -1352,7 +1378,7 @@
* ENOMEM Memory allocation failure.
*/
int
-tsol_check_label_v6(const cred_t *credp, mblk_t **mpp, boolean_t isexempt,
+tsol_check_label_v6(const cred_t *credp, mblk_t **mpp, uint_t mode,
ip_stack_t *ipst, pid_t pid)
{
mblk_t *mp = *mpp;
@@ -1382,7 +1408,7 @@
*/
ip6h = (ip6_t *)mp->b_rptr;
retv = tsol_check_dest(credp, &ip6h->ip6_dst, IPV6_VERSION,
- isexempt, &effective_cred);
+ mode, &effective_cred);
if (retv != 0)
return (retv);
@@ -1430,6 +1456,11 @@
*/
return (0);
}
+
+ if (msg_getcred(mp, NULL) == NULL) {
+ mblk_setcred(mp, (cred_t *)credp, NOPID);
+ }
+
if (secopt != NULL && sec_opt_len != 0 &&
(bcmp(opt_storage, secopt, sec_opt_len + 2) == 0)) {
/* The packet has the correct label already */
diff --git a/usr/src/uts/common/inet/ip/tnet.c b/usr/src/uts/common/inet/ip/tnet.c
index c4f4d0b..1e5c0eb 100644
--- a/usr/src/uts/common/inet/ip/tnet.c
+++ b/usr/src/uts/common/inet/ip/tnet.c
@@ -632,6 +632,34 @@
kmem_free(gcgrp, sizeof (*gcgrp));
}
+
+/*
+ * Assign a sensitivity label to inbound traffic which arrived without
+ * an explicit on-the-wire label.
+ *
+ * In the case of CIPSO-type hosts, we assume packets arriving without
+ * a label are at the most sensitive label known for the host, most
+ * likely involving out-of-band key management traffic (such as IKE,
+ * etc.,)
+ */
+static boolean_t
+tsol_find_unlabeled_label(tsol_tpc_t *rhtp, bslabel_t *sl, uint32_t *doi)
+{
+ *doi = rhtp->tpc_tp.tp_doi;
+ switch (rhtp->tpc_tp.host_type) {
+ case UNLABELED:
+ *sl = rhtp->tpc_tp.tp_def_label;
+ break;
+ case SUN_CIPSO:
+ *sl = rhtp->tpc_tp.tp_sl_range_cipso.upper_bound;
+ break;
+ default:
+ return (B_FALSE);
+ }
+ setbltype(sl, SUN_SL_ID);
+ return (B_TRUE);
+}
+
/*
* Converts CIPSO option to sensitivity label.
* Validity checks based on restrictions defined in
@@ -658,13 +686,14 @@
}
/*
- * Parse the CIPSO label in the incoming packet and construct a ts_label_t
- * that reflects the CIPSO label and attach it to the dblk cred. Later as
- * the mblk flows up through the stack any code that needs to examine the
- * packet label can inspect the label from the dblk cred. This function is
- * called right in ip_rput for all packets, i.e. locally destined and
- * to be forwarded packets. The forwarding path needs to examine the label
- * to determine how to forward the packet.
+ * If present, parse a CIPSO label in the incoming packet and
+ * construct a ts_label_t that reflects the CIPSO label and attach it
+ * to the dblk cred. Later as the mblk flows up through the stack any
+ * code that needs to examine the packet label can inspect the label
+ * from the dblk cred. This function is called right in ip_rput for
+ * all packets, i.e. locally destined and to be forwarded packets. The
+ * forwarding path needs to examine the label to determine how to
+ * forward the packet.
*
* This routine pulls all message text up into the first mblk.
* For IPv4, only the first 20 bytes of the IP header are guaranteed
@@ -673,17 +702,19 @@
boolean_t
tsol_get_pkt_label(mblk_t *mp, int version)
{
- tsol_tpc_t *src_rhtp;
+ tsol_tpc_t *src_rhtp = NULL;
uchar_t *opt_ptr = NULL;
const ipha_t *ipha;
bslabel_t sl;
uint32_t doi;
tsol_ip_label_t label_type;
+ uint32_t label_flags = 0; /* flags to set in label */
const cipso_option_t *co;
const void *src;
const ip6_t *ip6h;
cred_t *credp;
pid_t cpid;
+ int proto;
ASSERT(DB_TYPE(mp) == M_DATA);
@@ -725,21 +756,37 @@
if (!cipso_to_sl(opt_ptr, &sl))
return (B_FALSE);
setbltype(&sl, SUN_SL_ID);
+
+ /*
+ * If the source was unlabeled, then flag as such,
+ * (since CIPSO routers may add headers)
+ */
+
+ if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL)
+ return (B_FALSE);
+
+ if (src_rhtp->tpc_tp.host_type == UNLABELED)
+ label_flags = TSLF_UNLABELED;
+
+ TPC_RELE(src_rhtp);
+
break;
case OPT_NONE:
/*
- * Handle special cases that are not currently labeled, even
+ * Handle special cases that may not be labeled, even
* though the sending system may otherwise be configured as
* labeled.
* - IGMP
* - IPv4 ICMP Router Discovery
* - IPv6 Neighbor Discovery
+ * - IPsec ESP
*/
if (version == IPV4_VERSION) {
- if (ipha->ipha_protocol == IPPROTO_IGMP)
+ proto = ipha->ipha_protocol;
+ if (proto == IPPROTO_IGMP)
return (B_TRUE);
- if (ipha->ipha_protocol == IPPROTO_ICMP) {
+ if (proto == IPPROTO_ICMP) {
const struct icmp *icmp = (const struct icmp *)
(mp->b_rptr + IPH_HDR_LENGTH(ipha));
@@ -750,7 +797,8 @@
return (B_TRUE);
}
} else {
- if (ip6h->ip6_nxt == IPPROTO_ICMPV6) {
+ proto = ip6h->ip6_nxt;
+ if (proto == IPPROTO_ICMPV6) {
const icmp6_t *icmp6 = (const icmp6_t *)
(mp->b_rptr + IPV6_HDR_LEN);
@@ -765,23 +813,32 @@
/*
* Look up the tnrhtp database and get the implicit label
- * that is associated with this unlabeled host and attach
+ * that is associated with the sending host and attach
* it to the packet.
*/
if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL)
return (B_FALSE);
- /* If the sender is labeled, drop the unlabeled packet. */
- if (src_rhtp->tpc_tp.host_type != UNLABELED) {
- TPC_RELE(src_rhtp);
- pr_addr_dbg("unlabeled packet forged from %s\n",
- version == IPV4_VERSION ? AF_INET : AF_INET6, src);
- return (B_FALSE);
+ /*
+ * If peer is label-aware, mark as "implicit" rather than
+ * "unlabeled" to cause appropriate mac-exempt processing
+ * to happen.
+ */
+ if (src_rhtp->tpc_tp.host_type == SUN_CIPSO)
+ label_flags = TSLF_IMPLICIT_IN;
+ else if (src_rhtp->tpc_tp.host_type == UNLABELED)
+ label_flags = TSLF_UNLABELED;
+ else {
+ DTRACE_PROBE2(tx__get__pkt__label, char *,
+ "template(1) has unknown hosttype",
+ tsol_tpc_t *, src_rhtp);
}
- sl = src_rhtp->tpc_tp.tp_def_label;
- setbltype(&sl, SUN_SL_ID);
- doi = src_rhtp->tpc_tp.tp_doi;
+
+ if (!tsol_find_unlabeled_label(src_rhtp, &sl, &doi)) {
+ TPC_RELE(src_rhtp);
+ return (B_FALSE);
+ }
TPC_RELE(src_rhtp);
break;
@@ -805,23 +862,12 @@
}
if (credp == NULL)
return (B_FALSE);
+
+ crgetlabel(credp)->tsl_flags |= label_flags;
+
mblk_setcred(mp, credp, cpid);
crfree(credp); /* mblk has ref on cred */
- /*
- * If the source was unlabeled, then flag as such,
- * while remembering that CIPSO routers add headers.
- */
- if (label_type == OPT_NONE) {
- crgetlabel(credp)->tsl_flags |= TSLF_UNLABELED;
- } else if (label_type == OPT_CIPSO) {
- if ((src_rhtp = find_tpc(src, version, B_FALSE)) == NULL)
- return (B_FALSE);
- if (src_rhtp->tpc_tp.host_type == UNLABELED)
- crgetlabel(credp)->tsl_flags |= TSLF_UNLABELED;
- TPC_RELE(src_rhtp);
- }
-
return (B_TRUE);
}
@@ -870,6 +916,23 @@
label = label2bslabel(plabel);
conn_label = label2bslabel(crgetlabel(connp->conn_cred));
+
+ /*
+ * Implicitly labeled packets from label-aware sources
+ * go only to privileged receivers
+ */
+ if ((plabel->tsl_flags & TSLF_IMPLICIT_IN) &&
+ (connp->conn_mac_mode != CONN_MAC_IMPLICIT)) {
+ DTRACE_PROBE3(tx__ip__log__drop__receivelocal__mac_impl,
+ char *,
+ "implicitly labeled packet mp(1) for conn(2) "
+ "which isn't in implicit mac mode",
+ mblk_t *, mp, conn_t *, connp);
+
+ return (B_FALSE);
+ }
+
+
/*
* MLPs are always validated using the range and set of the local
* address, even when the remote host is unlabeled.
@@ -895,7 +958,7 @@
* conn_zoneid is global for an exclusive stack, thus we use
* conn_cred to get the zoneid
*/
- if (!connp->conn_mac_exempt ||
+ if ((connp->conn_mac_mode == CONN_MAC_DEFAULT) ||
(crgetzoneid(connp->conn_cred) != GLOBAL_ZONEID &&
(plabel->tsl_doi != conn_plabel->tsl_doi ||
!bldominates(conn_label, label)))) {
@@ -1106,6 +1169,16 @@
if (plabel == NULL)
return (B_TRUE);
+ if (plabel->tsl_flags & TSLF_IMPLICIT_IN) {
+ DTRACE_PROBE3(tx__ip__log__drop__replyerror__unresolved__label,
+ char *,
+ "cannot send error report for packet mp(1) with "
+ "unresolved security label sl(2)",
+ mblk_t *, mp, ts_label_t *, plabel);
+ return (B_FALSE);
+ }
+
+
if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION) {
ipha = (const ipha_t *)mp->b_rptr;
rhtp = find_tpc(&ipha->ipha_dst, IPV4_VERSION, B_FALSE);
@@ -1212,10 +1285,10 @@
*/
if (tsl == NULL || ire->ire_gw_secattr == NULL) {
if (tsl != NULL) {
- DTRACE_PROBE3(tx__ip__log__drop__irematch__nogwsec,
- char *,
- "ire(1) lacks ire_gw_secattr matching label(2)",
- ire_t *, ire, ts_label_t *, tsl);
+ DTRACE_PROBE3(
+ tx__ip__log__drop__irematch__nogwsec, char *,
+ "ire(1) lacks ire_gw_secattr when matching "
+ "label(2)", ire_t *, ire, ts_label_t *, tsl);
error = EACCES;
}
goto done;
@@ -1498,6 +1571,17 @@
if ((tsl = msg_getlabel(mp)) == NULL)
return (mp);
+ if (tsl->tsl_flags & TSLF_IMPLICIT_IN) {
+ DTRACE_PROBE3(tx__ip__log__drop__forward__unresolved__label,
+ char *,
+ "cannot forward packet mp(1) with unresolved "
+ "security label sl(2)",
+ mblk_t *, mp, ts_label_t *, tsl);
+
+ return (NULL);
+ }
+
+
ASSERT(psrc != NULL && pdst != NULL);
dst_rhtp = find_tpc(pdst, ire->ire_ipversion, B_FALSE);
@@ -1648,9 +1732,10 @@
credp = msg_getcred(mp, &pid);
if ((af == AF_INET &&
- tsol_check_label(credp, &mp, B_FALSE, ipst, pid) != 0) ||
+ tsol_check_label(credp, &mp, CONN_MAC_DEFAULT, ipst, pid) != 0) ||
(af == AF_INET6 &&
- tsol_check_label_v6(credp, &mp, B_FALSE, ipst, pid) != 0)) {
+ tsol_check_label_v6(credp, &mp, CONN_MAC_DEFAULT, ipst,
+ pid) != 0)) {
mp = NULL;
goto keep_label;
}
diff --git a/usr/src/uts/common/inet/ipclassifier.h b/usr/src/uts/common/inet/ipclassifier.h
index 36151fa..e24bcd9 100644
--- a/usr/src/uts/common/inet/ipclassifier.h
+++ b/usr/src/uts/common/inet/ipclassifier.h
@@ -165,6 +165,21 @@
} ip_helper_stream_info_t;
/*
+ * Mandatory Access Control mode, in conn_t's conn_mac_mode field.
+ * CONN_MAC_DEFAULT: strict enforcement of MAC.
+ * CONN_MAC_AWARE: allows communications between unlabeled systems
+ * and privileged daemons
+ * CONN_MAC_IMPLICIT: allows communications without explicit labels
+ * on the wire with privileged daemons.
+ *
+ * CONN_MAC_IMPLICIT is intended specifically for labeled IPsec key management
+ * in networks which don't pass CIPSO-labeled packets.
+ */
+#define CONN_MAC_DEFAULT 0
+#define CONN_MAC_AWARE 1
+#define CONN_MAC_IMPLICIT 2
+
+/*
* The initial fields in the conn_t are setup by the kmem_cache constructor,
* and are preserved when it is freed. Fields after that are bzero'ed when
* the conn_t is freed.
@@ -329,7 +344,7 @@
conn_anon_mlp : 1, /* user wants anon MLP */
conn_anon_port : 1, /* user bound anonymously */
- conn_mac_exempt : 1, /* unlabeled with loose MAC */
+ conn_mac_mode : 2, /* normal/loose/implicit MAC */
conn_spare : 26;
boolean_t conn_flow_cntrld;
@@ -421,6 +436,22 @@
((zoneid) == ALL_ZONES) || \
(connp)->conn_zoneid == (zoneid))
+/*
+ * On a labeled system, we must treat bindings to ports
+ * on shared IP addresses by sockets with MAC exemption
+ * privilege as being in all zones, as there's
+ * otherwise no way to identify the right receiver.
+ */
+
+#define IPCL_CONNS_MAC(conn1, conn2) \
+ (((conn1)->conn_mac_mode != CONN_MAC_DEFAULT) || \
+ ((conn2)->conn_mac_mode != CONN_MAC_DEFAULT))
+
+#define IPCL_BIND_ZONE_MATCH(conn1, conn2) \
+ (IPCL_CONNS_MAC(conn1, conn2) || \
+ IPCL_ZONE_MATCH(conn1, conn2->conn_zoneid) || \
+ IPCL_ZONE_MATCH(conn2, conn1->conn_zoneid))
+
#define _IPCL_V4_MATCH(v6addr, v4addr) \
(V4_PART_OF_V6((v6addr)) == (v4addr) && IN6_IS_ADDR_V4MAPPED(&(v6addr)))
diff --git a/usr/src/uts/common/inet/ipsec_impl.h b/usr/src/uts/common/inet/ipsec_impl.h
index e3e7d86..c5fa936 100644
--- a/usr/src/uts/common/inet/ipsec_impl.h
+++ b/usr/src/uts/common/inet/ipsec_impl.h
@@ -847,7 +847,7 @@
extern mblk_t *ipsec_check_inbound_policy(mblk_t *, conn_t *, ipha_t *, ip6_t *,
boolean_t);
-extern boolean_t ipsec_in_to_out(mblk_t *, ipha_t *, ip6_t *);
+extern boolean_t ipsec_in_to_out(mblk_t *, ipha_t *, ip6_t *, zoneid_t);
extern void ipsec_log_policy_failure(int, char *, ipha_t *, ip6_t *, boolean_t,
netstack_t *);
extern boolean_t ipsec_inbound_accept_clear(mblk_t *, ipha_t *, ip6_t *);
@@ -923,6 +923,8 @@
extern void ipsec_insert_always(avl_tree_t *tree, void *new_node);
extern int32_t ipsec_act_ovhd(const ipsec_act_t *act);
+extern int sadb_whack_label(mblk_t **, ipsa_t *);
+extern int sadb_whack_label_v6(mblk_t **, ipsa_t *);
extern boolean_t update_iv(uint8_t *, queue_t *, ipsa_t *, ipsecesp_stack_t *);
/*
@@ -1017,6 +1019,7 @@
* Common functions
*/
extern boolean_t ip_addr_match(uint8_t *, int, in6_addr_t *);
+extern boolean_t ipsec_label_match(cred_t *, cred_t *);
/*
* AH and ESP counters types.
diff --git a/usr/src/uts/common/inet/iptun/iptun.c b/usr/src/uts/common/inet/iptun/iptun.c
index 8fd6440..bc2f1d6 100644
--- a/usr/src/uts/common/inet/iptun/iptun.c
+++ b/usr/src/uts/common/inet/iptun/iptun.c
@@ -1850,6 +1850,8 @@
switch (iptun->iptun_typeinfo->iti_ipvers) {
case IPV4_VERSION:
header_size = sizeof (ipha_t);
+ if (is_system_labeled())
+ header_size += IP_MAX_OPT_LENGTH;
break;
case IPV6_VERSION:
header_size = sizeof (iptun_ipv6hdrs_t);
@@ -2650,7 +2652,7 @@
if (tsol_check_dest(msg_cred, (outer4 != NULL ?
(void *)&outer4->ipha_dst : (void *)&outer6->ip6_dst),
(outer4 != NULL ? IPV4_VERSION : IPV6_VERSION),
- B_FALSE, NULL) != 0)
+ CONN_MAC_DEFAULT, NULL) != 0)
goto drop;
}
diff --git a/usr/src/uts/common/inet/mib2.h b/usr/src/uts/common/inet/mib2.h
index 9414004..16bed4e 100644
--- a/usr/src/uts/common/inet/mib2.h
+++ b/usr/src/uts/common/inet/mib2.h
@@ -953,7 +953,7 @@
#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 */
-
+#define MIB2_TMEF_MACIMPLICIT 0x00000020 /* MAC-Implicit */
/*
* List of IPv4 source addresses being filtered per interface
*/
diff --git a/usr/src/uts/common/inet/sadb.h b/usr/src/uts/common/inet/sadb.h
index 663de77..6d3b9b5 100644
--- a/usr/src/uts/common/inet/sadb.h
+++ b/usr/src/uts/common/inet/sadb.h
@@ -125,8 +125,6 @@
struct ipsid_s *ipsa_src_cid; /* Source certificate identity */
struct ipsid_s *ipsa_dst_cid; /* Destination certificate identity */
- uint64_t *ipsa_integ; /* Integrity bitmap */
- uint64_t *ipsa_sens; /* Sensitivity bitmap */
mblk_t *ipsa_lpkt; /* Packet received while larval (CAS me) */
mblk_t *ipsa_bpkt_head; /* Packets received while idle */
mblk_t *ipsa_bpkt_tail;
@@ -221,13 +219,7 @@
uint_t ipsa_hardalloc; /* Allocations allowed (hard). */
uint_t ipsa_alloc; /* Allocations made. */
- uint_t ipsa_integlen; /* Length of the integrity bitmap (bytes). */
- uint_t ipsa_senslen; /* Length of the sensitivity bitmap (bytes). */
-
uint_t ipsa_type; /* Type of security association. (AH/etc.) */
- uint_t ipsa_dpd; /* Domain for sensitivity bit vectors. */
- uint_t ipsa_senslevel; /* Sensitivity level. */
- uint_t ipsa_integlevel; /* Integrity level. */
uint_t ipsa_state; /* State of my association. */
uint_t ipsa_replay_wsize; /* Size of replay window */
uint32_t ipsa_flags; /* Flags for security association. */
@@ -296,10 +288,12 @@
* Soft reference to paired SA
*/
uint32_t ipsa_otherspi;
-
- /* MLS boxen will probably need more fields in here. */
-
netstack_t *ipsa_netstack; /* Does not have a netstack_hold */
+
+ cred_t *ipsa_cred; /* MLS: cred_t attributes */
+ cred_t *ipsa_ocred; /* MLS: outer label */
+ uint8_t ipsa_mac_exempt; /* MLS: mac exempt flag */
+ uchar_t ipsa_opt_storage[IP_MAX_OPT_LENGTH];
} ipsa_t;
/*
@@ -508,6 +502,9 @@
/* icmp type and code of triggering packet (if applicable) */
uint8_t ipsacq_icmp_type;
uint8_t ipsacq_icmp_code;
+
+ /* credentials associated with triggering packet */
+ cred_t *ipsacq_cred;
} ipsacq_t;
/*
@@ -638,6 +635,61 @@
#define SA_SRCPORT(ipsa) ((ipsa)->ipsa_unique_id & 0xffff)
#define SA_DSTPORT(ipsa) (((ipsa)->ipsa_unique_id >> 16) & 0xffff)
+typedef struct ipsa_query_s ipsa_query_t;
+
+typedef boolean_t (*ipsa_match_fn_t)(ipsa_query_t *, ipsa_t *);
+
+#define IPSA_NMATCH 10
+
+/*
+ * SADB query structure.
+ *
+ * Provide a generalized mechanism for matching entries in the SADB;
+ * one of these structures is initialized using sadb_form_query(),
+ * and then can be used as a parameter to sadb_match_query() which returns
+ * B_TRUE if the SA matches the query.
+ *
+ * Under the covers, sadb_form_query populates the matchers[] array with
+ * functions which are called one at a time until one fails to match.
+ */
+struct ipsa_query_s {
+ uint32_t req, match;
+ sadb_address_t *srcext, *dstext;
+ sadb_ident_t *srcid, *dstid;
+ sadb_x_kmc_t *kmcext;
+ sadb_sa_t *assoc;
+ uint32_t spi;
+ struct sockaddr_in *src;
+ struct sockaddr_in6 *src6;
+ struct sockaddr_in *dst;
+ struct sockaddr_in6 *dst6;
+ sa_family_t af;
+ uint32_t *srcaddr, *dstaddr;
+ uint32_t ifindex;
+ uint32_t kmc, kmp;
+ char *didstr, *sidstr;
+ uint16_t didtype, sidtype;
+ sadbp_t *spp;
+ sadb_t *sp;
+ isaf_t *inbound, *outbound;
+ uint32_t outhash;
+ uint32_t inhash;
+ ipsa_match_fn_t matchers[IPSA_NMATCH];
+};
+
+#define IPSA_Q_SA 0x00000001
+#define IPSA_Q_DST 0x00000002
+#define IPSA_Q_SRC 0x00000004
+#define IPSA_Q_DSTID 0x00000008
+#define IPSA_Q_SRCID 0x00000010
+#define IPSA_Q_KMC 0x00000020
+#define IPSA_Q_INBOUND 0x00000040 /* fill in inbound isaf_t */
+#define IPSA_Q_OUTBOUND 0x00000080 /* fill in outbound isaf_t */
+
+int sadb_form_query(keysock_in_t *, uint32_t, uint32_t, ipsa_query_t *, int *);
+boolean_t sadb_match_query(ipsa_query_t *q, ipsa_t *sa);
+
+
/*
* All functions that return an ipsa_t will return it with IPSA_REFHOLD()
* already called.
@@ -647,11 +699,7 @@
ipsa_t *ipsec_getassocbyspi(isaf_t *, uint32_t, uint32_t *, uint32_t *,
sa_family_t);
ipsa_t *ipsec_getassocbyconn(isaf_t *, ipsec_out_t *, uint32_t *, uint32_t *,
- sa_family_t, uint8_t);
-ipsap_t *get_ipsa_pair(sadb_sa_t *, sadb_address_t *, sadb_address_t *,
- sadbp_t *);
-void destroy_ipsa_pair(ipsap_t *);
-int update_pairing(ipsap_t *, keysock_in_t *, int *, sadbp_t *);
+ sa_family_t, uint8_t, cred_t *);
/* SA insertion. */
int sadb_insertassoc(ipsa_t *, isaf_t *);
@@ -668,6 +716,7 @@
/* Support routines to interface a keysock consumer to PF_KEY. */
mblk_t *sadb_keysock_out(minor_t);
int sadb_hardsoftchk(sadb_lifetime_t *, sadb_lifetime_t *, sadb_lifetime_t *);
+int sadb_labelchk(struct keysock_in_s *);
void sadb_pfkey_echo(queue_t *, mblk_t *, sadb_msg_t *, struct keysock_in_s *,
ipsa_t *);
void sadb_pfkey_error(queue_t *, mblk_t *, int, int, uint_t);
@@ -678,8 +727,8 @@
int sadb_addrset(ire_t *);
int sadb_delget_sa(mblk_t *, keysock_in_t *, sadbp_t *, int *, queue_t *,
uint8_t);
-
-int sadb_purge_sa(mblk_t *, keysock_in_t *, sadb_t *, queue_t *, queue_t *);
+int sadb_purge_sa(mblk_t *, keysock_in_t *, sadb_t *, int *, queue_t *,
+ queue_t *);
int sadb_common_add(queue_t *, queue_t *, mblk_t *, sadb_msg_t *,
keysock_in_t *, isaf_t *, isaf_t *, ipsa_t *, boolean_t, boolean_t, int *,
netstack_t *, sadbp_t *);
@@ -840,6 +889,9 @@
extern void sadb_alg_update(ipsec_algtype_t, uint8_t, boolean_t,
netstack_t *);
+extern int sadb_sens_len_from_cred(cred_t *);
+extern void sadb_sens_from_cred(sadb_sens_t *, int, cred_t *, int);
+
/*
* Context templates management.
*/
diff --git a/usr/src/uts/common/inet/sctp/sctp.c b/usr/src/uts/common/inet/sctp/sctp.c
index 5062b18..00fc6cd 100644
--- a/usr/src/uts/common/inet/sctp/sctp.c
+++ b/usr/src/uts/common/inet/sctp/sctp.c
@@ -237,7 +237,7 @@
* MAC exempt mode. This allows read-down to unlabeled hosts.
*/
if (getpflags(NET_MAC_AWARE, credp) != 0)
- connp->conn_mac_exempt = B_TRUE;
+ connp->conn_mac_mode = CONN_MAC_AWARE;
}
connp->conn_allzones = pconnp->conn_allzones;
@@ -1521,7 +1521,7 @@
* exempt mode. This allows read-down to unlabeled hosts.
*/
if (getpflags(NET_MAC_AWARE, credp) != 0)
- sctp_connp->conn_mac_exempt = B_TRUE;
+ sctp_connp->conn_mac_mode = CONN_MAC_AWARE;
/* Initialize SCTP instance values, our verf tag must never be 0 */
(void) random_get_pseudo_bytes((uint8_t *)&sctp->sctp_lvtag,
diff --git a/usr/src/uts/common/inet/sctp/sctp_bind.c b/usr/src/uts/common/inet/sctp/sctp_bind.c
index 053bde9..c0c1c75 100644
--- a/usr/src/uts/common/inet/sctp/sctp_bind.c
+++ b/usr/src/uts/common/inet/sctp/sctp_bind.c
@@ -535,7 +535,8 @@
* otherwise no way to identify the right receiver.
*/
if (lsctp->sctp_zoneid != zoneid &&
- !lsctp->sctp_mac_exempt && !sctp->sctp_mac_exempt)
+ lsctp->sctp_mac_mode == CONN_MAC_DEFAULT &&
+ sctp->sctp_mac_mode == CONN_MAC_DEFAULT)
continue;
addrcmp = sctp_compare_saddrs(sctp, lsctp);
diff --git a/usr/src/uts/common/inet/sctp/sctp_common.c b/usr/src/uts/common/inet/sctp/sctp_common.c
index d64e318..3486ba1 100644
--- a/usr/src/uts/common/inet/sctp/sctp_common.c
+++ b/usr/src/uts/common/inet/sctp/sctp_common.c
@@ -526,11 +526,11 @@
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,
+ &dst, IPV4_VERSION, sctp->sctp_mac_mode,
&effective_cred);
} else {
err = tsol_check_dest(CONN_CRED(sctp->sctp_connp),
- addr, IPV6_VERSION, sctp->sctp_mac_exempt,
+ addr, IPV6_VERSION, sctp->sctp_mac_mode,
&effective_cred);
}
if (err != 0)
diff --git a/usr/src/uts/common/inet/sctp/sctp_cookie.c b/usr/src/uts/common/inet/sctp/sctp_cookie.c
index f15b997..601938c 100644
--- a/usr/src/uts/common/inet/sctp/sctp_cookie.c
+++ b/usr/src/uts/common/inet/sctp/sctp_cookie.c
@@ -783,11 +783,11 @@
if (isv4)
err = tsol_check_label(cr, &iackmp,
- connp->conn_mac_exempt,
+ connp->conn_mac_mode,
sctps->sctps_netstack->netstack_ip, pid);
else
err = tsol_check_label_v6(cr, &iackmp,
- connp->conn_mac_exempt,
+ connp->conn_mac_mode,
sctps->sctps_netstack->netstack_ip, pid);
if (err != 0) {
sctp_send_abort(sctp, sctp_init2vtag(ch),
diff --git a/usr/src/uts/common/inet/sctp/sctp_error.c b/usr/src/uts/common/inet/sctp/sctp_error.c
index 5efa383..02d18cf 100644
--- a/usr/src/uts/common/inet/sctp/sctp_error.c
+++ b/usr/src/uts/common/inet/sctp/sctp_error.c
@@ -276,12 +276,12 @@
if (is_system_labeled() && (cr = msg_getcred(inmp, &pid)) != NULL &&
crgetlabel(cr) != NULL) {
int err;
- boolean_t exempt = connp->conn_mac_exempt;
+ uint_t mode = connp->conn_mac_mode;
if (isv4)
- err = tsol_check_label(cr, &hmp, exempt, ipst, pid);
+ err = tsol_check_label(cr, &hmp, mode, ipst, pid);
else
- err = tsol_check_label_v6(cr, &hmp, exempt, ipst, pid);
+ err = tsol_check_label_v6(cr, &hmp, mode, ipst, pid);
if (err != 0) {
freemsg(hmp);
return;
diff --git a/usr/src/uts/common/inet/sctp/sctp_impl.h b/usr/src/uts/common/inet/sctp/sctp_impl.h
index fa4af0b..3226864 100644
--- a/usr/src/uts/common/inet/sctp/sctp_impl.h
+++ b/usr/src/uts/common/inet/sctp/sctp_impl.h
@@ -639,7 +639,7 @@
conn_t *sctp_connp; /* conn_t stuff */
#define sctp_zoneid sctp_connp->conn_zoneid
#define sctp_allzones sctp_connp->conn_allzones
-#define sctp_mac_exempt sctp_connp->conn_mac_exempt
+#define sctp_mac_mode sctp_connp->conn_mac_mode
#define sctp_credp sctp_connp->conn_cred
#define sctp_reuseaddr sctp_connp->conn_reuseaddr
diff --git a/usr/src/uts/common/inet/sctp/sctp_opt_data.c b/usr/src/uts/common/inet/sctp/sctp_opt_data.c
index f4b6a58..322e4d4 100644
--- a/usr/src/uts/common/inet/sctp/sctp_opt_data.c
+++ b/usr/src/uts/common/inet/sctp/sctp_opt_data.c
@@ -734,7 +734,10 @@
*i1 = connp->conn_allzones;
break;
case SO_MAC_EXEMPT:
- *i1 = connp->conn_mac_exempt;
+ *i1 = (connp->conn_mac_mode == CONN_MAC_AWARE);
+ break;
+ case SO_MAC_IMPLICIT:
+ *i1 = (connp->conn_mac_mode == CONN_MAC_IMPLICIT);
break;
case SO_PROTOTYPE:
*i1 = IPPROTO_SCTP;
@@ -1326,7 +1329,20 @@
retval = EINVAL;
break;
}
- connp->conn_mac_exempt = onoff;
+ connp->conn_mac_mode = onoff ?
+ CONN_MAC_AWARE : CONN_MAC_DEFAULT;
+ break;
+ case SO_MAC_IMPLICIT:
+ if (secpolicy_net_mac_implicit(sctp->sctp_credp) != 0) {
+ retval = EACCES;
+ break;
+ }
+ if (sctp->sctp_state >= SCTPS_BOUND) {
+ retval = EINVAL;
+ break;
+ }
+ connp->conn_mac_mode = onoff ?
+ CONN_MAC_AWARE : CONN_MAC_IMPLICIT;
break;
default:
retval = ENOPROTOOPT;
diff --git a/usr/src/uts/common/inet/sctp/sctp_snmp.c b/usr/src/uts/common/inet/sctp/sctp_snmp.c
index e668f4c..f859cd6 100644
--- a/usr/src/uts/common/inet/sctp/sctp_snmp.c
+++ b/usr/src/uts/common/inet/sctp/sctp_snmp.c
@@ -647,9 +647,17 @@
mlp.tme_flags |= MIB2_TMEF_ANONMLP;
needattr = B_TRUE;
}
- if (connp->conn_mac_exempt) {
+ switch (connp->conn_mac_mode) {
+ case CONN_MAC_DEFAULT:
+ break;
+ case CONN_MAC_AWARE:
mlp.tme_flags |= MIB2_TMEF_MACEXEMPT;
needattr = B_TRUE;
+ break;
+ case CONN_MAC_IMPLICIT:
+ mlp.tme_flags |= MIB2_TMEF_MACIMPLICIT;
+ needattr = B_TRUE;
+ break;
}
if (connp->conn_fully_bound &&
connp->conn_effective_cred != NULL) {
diff --git a/usr/src/uts/common/inet/tcp/tcp.c b/usr/src/uts/common/inet/tcp/tcp.c
index 5939bed..c9a941e 100644
--- a/usr/src/uts/common/inet/tcp/tcp.c
+++ b/usr/src/uts/common/inet/tcp/tcp.c
@@ -2454,7 +2454,7 @@
econnp->conn_zoneid = aconnp->conn_zoneid;
econnp->conn_allzones = aconnp->conn_allzones;
- aconnp->conn_mac_exempt = B_FALSE;
+ aconnp->conn_mac_mode = CONN_MAC_DEFAULT;
/* Do the IPC initialization */
CONN_INC_REF(econnp);
@@ -3119,7 +3119,6 @@
/* maximum number of times to run around the loop */
int loopmax;
conn_t *connp = tcp->tcp_connp;
- zoneid_t zoneid = connp->conn_zoneid;
tcp_stack_t *tcps = tcp->tcp_tcps;
/*
@@ -3192,11 +3191,7 @@
* privilege as being in all zones, as there's
* otherwise no way to identify the right receiver.
*/
- if (!(IPCL_ZONE_MATCH(ltcp->tcp_connp, zoneid) ||
- IPCL_ZONE_MATCH(connp,
- ltcp->tcp_connp->conn_zoneid)) &&
- !lconnp->conn_mac_exempt &&
- !connp->conn_mac_exempt)
+ if (!IPCL_BIND_ZONE_MATCH(ltcp->tcp_connp, connp))
continue;
/*
@@ -3250,7 +3245,8 @@
TCP_IS_SOCKET(tcp));
exclbind = ltcp->tcp_exclbind || tcp->tcp_exclbind;
- if (lconnp->conn_mac_exempt || connp->conn_mac_exempt ||
+ if ((lconnp->conn_mac_mode != CONN_MAC_DEFAULT) ||
+ (connp->conn_mac_mode != CONN_MAC_DEFAULT) ||
(exclbind && (not_socket ||
ltcp->tcp_state <= TCPS_ESTABLISHED))) {
if (V6_OR_V4_INADDR_ANY(
@@ -5452,7 +5448,7 @@
if ((cr = msg_getcred(mp, NULL)) != NULL &&
(tsl = crgetlabel(cr)) != NULL &&
(connp->conn_mlp_type != mlptSingle ||
- (connp->conn_mac_exempt == B_TRUE &&
+ (connp->conn_mac_mode != CONN_MAC_AWARE &&
(tsl->tsl_flags & TSLF_UNLABELED)))) {
if ((econnp->conn_effective_cred =
copycred_from_tslabel(econnp->conn_cred,
@@ -6191,7 +6187,7 @@
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,
+ &dstaddr, IPV4_VERSION, tcp->tcp_connp->conn_mac_mode,
&tcp->tcp_connp->conn_effective_cred)) != 0) {
if (error != EHOSTUNREACH)
error = -TSYSERR;
@@ -6392,7 +6388,7 @@
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,
+ dstaddrp, IPV6_VERSION, tcp->tcp_connp->conn_mac_mode,
&tcp->tcp_connp->conn_effective_cred)) != 0) {
if (error != EHOSTUNREACH)
error = -TSYSERR;
@@ -6535,7 +6531,7 @@
connp->conn_ulp = IPPROTO_TCP;
if (ipst->ips_ipcl_proto_fanout_v6[IPPROTO_TCP].connf_head !=
- NULL || connp->conn_mac_exempt) {
+ NULL || (connp->conn_mac_mode != CONN_MAC_DEFAULT)) {
error = -TBADADDR;
} else {
connp->conn_srcv6 = ipv6_all_zeros;
@@ -9333,7 +9329,7 @@
* exempt mode. This allows read-down to unlabeled hosts.
*/
if (getpflags(NET_MAC_AWARE, credp) != 0)
- connp->conn_mac_exempt = B_TRUE;
+ connp->conn_mac_mode = CONN_MAC_AWARE;
connp->conn_dev = NULL;
if (issocket) {
@@ -9618,7 +9614,10 @@
*i1 = connp->conn_anon_mlp;
break;
case SO_MAC_EXEMPT:
- *i1 = connp->conn_mac_exempt;
+ *i1 = (connp->conn_mac_mode == CONN_MAC_AWARE);
+ break;
+ case SO_MAC_IMPLICIT:
+ *i1 = (connp->conn_mac_mode == CONN_MAC_IMPLICIT);
break;
case SO_EXCLBIND:
*i1 = tcp->tcp_exclbind ? SO_EXCLBIND : 0;
@@ -15981,9 +15980,17 @@
mlp.tme_flags |= MIB2_TMEF_ANONMLP;
needattr = B_TRUE;
}
- if (connp->conn_mac_exempt) {
+ switch (connp->conn_mac_mode) {
+ case CONN_MAC_DEFAULT:
+ break;
+ case CONN_MAC_AWARE:
mlp.tme_flags |= MIB2_TMEF_MACEXEMPT;
needattr = B_TRUE;
+ break;
+ case CONN_MAC_IMPLICIT:
+ mlp.tme_flags |= MIB2_TMEF_MACIMPLICIT;
+ needattr = B_TRUE;
+ break;
}
if (connp->conn_fully_bound &&
connp->conn_effective_cred != NULL) {
@@ -18644,15 +18651,14 @@
if (ipst->ips_ip4_observe.he_interested) {
zoneid_t szone;
- szone = ip_get_zoneid_v4(ipha->ipha_src, mp,
- ipst, ALL_ZONES);
-
/*
- * The IP observability hook expects b_rptr to be
+ * Both of these functions expect b_rptr to be
* where the IP header starts, so advance past the
- * link layer header.
+ * link layer header if present.
*/
mp->b_rptr += ire_fp_mp_len;
+ szone = ip_get_zoneid_v4(ipha->ipha_src, mp,
+ ipst, ALL_ZONES);
ipobs_hook(mp, IPOBS_HOOK_OUTBOUND, szone,
ALL_ZONES, ill, ipst);
mp->b_rptr -= ire_fp_mp_len;
@@ -20650,10 +20656,10 @@
if (ipst->ips_ip4_observe.he_interested) {
zoneid_t szone;
- szone = ip_get_zoneid_v4(ipha->ipha_src, mp,
- ipst, ALL_ZONES);
if (ire_fp_mp_len != 0)
mp->b_rptr += ire_fp_mp_len;
+ szone = ip_get_zoneid_v4(ipha->ipha_src, mp,
+ ipst, ALL_ZONES);
ipobs_hook(mp, IPOBS_HOOK_OUTBOUND, szone,
ALL_ZONES, ill, ipst);
if (ire_fp_mp_len != 0)
@@ -22226,11 +22232,11 @@
if (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION)
err = tsol_check_label(cr, &mp,
- tcp->tcp_connp->conn_mac_exempt,
+ tcp->tcp_connp->conn_mac_mode,
tcps->tcps_netstack->netstack_ip, pid);
else
err = tsol_check_label_v6(cr, &mp,
- tcp->tcp_connp->conn_mac_exempt,
+ tcp->tcp_connp->conn_mac_mode,
tcps->tcps_netstack->netstack_ip, pid);
if (mctl_present)
ipsec_mp->b_cont = mp;
@@ -22251,7 +22257,7 @@
ipsec_in_t *ii = (ipsec_in_t *)ipsec_mp->b_rptr;
ASSERT(ii->ipsec_in_type == IPSEC_IN);
- if (!ipsec_in_to_out(ipsec_mp, ipha, ip6h)) {
+ if (!ipsec_in_to_out(ipsec_mp, ipha, ip6h, zoneid)) {
return;
}
}
diff --git a/usr/src/uts/common/inet/tcp/tcp_opt_data.c b/usr/src/uts/common/inet/tcp/tcp_opt_data.c
index 167d3cc..fa2529a 100644
--- a/usr/src/uts/common/inet/tcp/tcp_opt_data.c
+++ b/usr/src/uts/common/inet/tcp/tcp_opt_data.c
@@ -80,6 +80,8 @@
0 },
{ SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int),
0 },
+{ SO_MAC_IMPLICIT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int),
+ 0 },
{ SO_ALLZONES, SOL_SOCKET, OA_R, OA_RW, OP_CONFIG, OP_PASSNEXT, sizeof (int),
0 },
{ SO_EXCLBIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int), 0 },
diff --git a/usr/src/uts/common/inet/udp/udp.c b/usr/src/uts/common/inet/udp/udp.c
index 3903643..d0bab51 100644
--- a/usr/src/uts/common/inet/udp/udp.c
+++ b/usr/src/uts/common/inet/udp/udp.c
@@ -1849,8 +1849,11 @@
*i1 = connp->conn_anon_mlp;
break; /* goto sizeof (int) option return */
case SO_MAC_EXEMPT:
- *i1 = connp->conn_mac_exempt;
- break; /* goto sizeof (int) option return */
+ *i1 = (connp->conn_mac_mode == CONN_MAC_AWARE);
+ break;
+ case SO_MAC_IMPLICIT:
+ *i1 = (connp->conn_mac_mode == CONN_MAC_IMPLICIT);
+ break;
case SO_ALLZONES:
*i1 = connp->conn_allzones;
break; /* goto sizeof (int) option return */
@@ -2231,19 +2234,9 @@
udp->udp_timestamp = onoff;
break;
case SO_ANON_MLP:
- if (!checkonly) {
- connp->conn_anon_mlp = onoff;
- PASS_OPT_TO_IP(connp);
- }
- break;
case SO_MAC_EXEMPT:
- if (secpolicy_net_mac_aware(cr) != 0 ||
- udp->udp_state != TS_UNBND)
- return (EACCES);
- if (!checkonly) {
- connp->conn_mac_exempt = onoff;
- PASS_OPT_TO_IP(connp);
- }
+ case SO_MAC_IMPLICIT:
+ PASS_OPT_TO_IP(connp);
break;
case SCM_UCRED: {
struct ucred_s *ucr;
@@ -4381,9 +4374,17 @@
mlp.tme_flags |= MIB2_TMEF_ANONMLP;
needattr = B_TRUE;
}
- if (connp->conn_mac_exempt) {
+ switch (connp->conn_mac_mode) {
+ case CONN_MAC_DEFAULT:
+ break;
+ case CONN_MAC_AWARE:
mlp.tme_flags |= MIB2_TMEF_MACEXEMPT;
needattr = B_TRUE;
+ break;
+ case CONN_MAC_IMPLICIT:
+ mlp.tme_flags |= MIB2_TMEF_MACIMPLICIT;
+ needattr = B_TRUE;
+ break;
}
/*
@@ -4714,7 +4715,7 @@
* from the message to handle MLP
*/
if ((err = tsol_check_dest(cred, &dst, IPV4_VERSION,
- udp->udp_connp->conn_mac_exempt, &effective_cred)) != 0)
+ udp->udp_connp->conn_mac_mode, &effective_cred)) != 0)
goto done;
if (effective_cred != NULL)
cred = effective_cred;
@@ -5457,15 +5458,14 @@
if (ipst->ips_ip4_observe.he_interested && mp != NULL) {
zoneid_t szone;
- szone = ip_get_zoneid_v4(ipha->ipha_src, mp,
- ipst, ALL_ZONES);
-
/*
- * The IP observability hook expects b_rptr to be
+ * Both of these functions expect b_rptr to be
* where the IP header starts, so advance past the
- * link layer header.
+ * link layer header if present.
*/
mp->b_rptr += ire_fp_mp_len;
+ szone = ip_get_zoneid_v4(ipha->ipha_src, mp,
+ ipst, ALL_ZONES);
ipobs_hook(mp, IPOBS_HOOK_OUTBOUND, szone,
ALL_ZONES, ill, ipst);
mp->b_rptr -= ire_fp_mp_len;
@@ -5558,7 +5558,7 @@
* 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)
+ udp->udp_connp->conn_mac_mode, &effective_cred)) != 0)
goto done;
if (effective_cred != NULL)
cred = effective_cred;
@@ -7489,7 +7489,7 @@
* exempt mode. This allows read-down to unlabeled hosts.
*/
if (getpflags(NET_MAC_AWARE, credp) != 0)
- connp->conn_mac_exempt = B_TRUE;
+ connp->conn_mac_mode = CONN_MAC_AWARE;
connp->conn_ulp_labeled = is_system_labeled();
@@ -7679,7 +7679,6 @@
int loopmax;
udp_fanout_t *udpf;
in_port_t lport; /* Network byte order */
- zoneid_t zoneid;
udp_t *udp;
boolean_t is_inaddr_any;
mlp_type_t addrtype, mlptype;
@@ -7873,7 +7872,6 @@
}
is_inaddr_any = V6_OR_V4_INADDR_ANY(v6src);
- zoneid = connp->conn_zoneid;
for (;;) {
udp_t *udp1;
@@ -7898,11 +7896,7 @@
* privilege as being in all zones, as there's
* otherwise no way to identify the right receiver.
*/
- if (!(IPCL_ZONE_MATCH(udp1->udp_connp, zoneid) ||
- IPCL_ZONE_MATCH(connp,
- udp1->udp_connp->conn_zoneid)) &&
- !connp->conn_mac_exempt && \
- !udp1->udp_connp->conn_mac_exempt)
+ if (!IPCL_BIND_ZONE_MATCH(udp1->udp_connp, connp))
continue;
/*
@@ -7925,8 +7919,7 @@
* as UDP_EXCLBIND, except that zoneid is ignored.
*/
if (udp1->udp_exclbind || udp->udp_exclbind ||
- udp1->udp_connp->conn_mac_exempt ||
- connp->conn_mac_exempt) {
+ IPCL_CONNS_MAC(udp1->udp_connp, connp)) {
if (V6_OR_V4_INADDR_ANY(
udp1->udp_bound_v6src) ||
is_inaddr_any ||
diff --git a/usr/src/uts/common/inet/udp/udp_opt_data.c b/usr/src/uts/common/inet/udp/udp_opt_data.c
index 5cad013..425d258 100644
--- a/usr/src/uts/common/inet/udp/udp_opt_data.c
+++ b/usr/src/uts/common/inet/udp/udp_opt_data.c
@@ -81,6 +81,8 @@
0 },
{ SO_MAC_EXEMPT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int),
0 },
+{ SO_MAC_IMPLICIT, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int),
+ 0 },
{ SCM_UCRED, SOL_SOCKET, OA_W, OA_W, OP_NP, OP_VARLEN|OP_NODEFAULT, 512, 0 },
{ SO_EXCLBIND, SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int), 0 },
{ SO_DOMAIN, SOL_SOCKET, OA_R, OA_R, OP_NP, OP_PASSNEXT, sizeof (int), 0 },
diff --git a/usr/src/uts/common/net/pfkeyv2.h b/usr/src/uts/common/net/pfkeyv2.h
index dda81b3..e05195c 100644
--- a/usr/src/uts/common/net/pfkeyv2.h
+++ b/usr/src/uts/common/net/pfkeyv2.h
@@ -206,7 +206,7 @@
uint8_t sadb_sens_sens_len; /* 64-bit words */
uint8_t sadb_sens_integ_level;
uint8_t sadb_sens_integ_len; /* 64-bit words */
- uint32_t sadb_sens_reserved;
+ uint32_t sadb_x_sens_flags;
/*
* followed by two uint64_t arrays
* uint64_t sadb_sens_bitmap[sens_bitmap_len];
@@ -215,7 +215,16 @@
} sadb_sens_t;
/*
- * A proposal extension. This is found in an ACQUIRE message, and it
+ * We recycled the formerly reserved word for flags.
+ */
+
+#define sadb_sens_reserved sadb_x_sens_flags
+
+#define SADB_X_SENS_IMPLICIT 0x1 /* implicit labelling */
+#define SADB_X_SENS_UNLABELED 0x2 /* peer is unlabeled */
+
+/*
+ * a proposal extension. This is found in an ACQUIRE message, and it
* proposes what sort of SA the kernel would like to ACQUIRE.
*/
@@ -662,8 +671,9 @@
#define SADB_X_EXT_REPLAY_VALUE 24
#define SADB_X_EXT_EDUMP 25
#define SADB_X_EXT_LIFETIME_IDLE 26
+#define SADB_X_EXT_OUTER_SENS 27
-#define SADB_EXT_MAX 26
+#define SADB_EXT_MAX 27
/*
* Identity types.
@@ -809,7 +819,9 @@
#define SADB_X_DIAGNOSTIC_BAD_CTX 80
#define SADB_X_DIAGNOSTIC_INVALID_REPLAY 81
#define SADB_X_DIAGNOSTIC_MISSING_LIFETIME 82
-#define SADB_X_DIAGNOSTIC_MAX 82
+
+#define SADB_X_DIAGNOSTIC_BAD_LABEL 83
+#define SADB_X_DIAGNOSTIC_MAX 83
/* Algorithm type for sadb_x_algdesc above... */
diff --git a/usr/src/uts/common/os/policy.c b/usr/src/uts/common/os/policy.c
index 39edfbb..8673e49 100644
--- a/usr/src/uts/common/os/policy.c
+++ b/usr/src/uts/common/os/policy.c
@@ -602,6 +602,15 @@
}
/*
+ * Allow a privileged process to transmit traffic without explicit labels
+ */
+int
+secpolicy_net_mac_implicit(const cred_t *cr)
+{
+ return (PRIV_POLICY(cr, PRIV_NET_MAC_IMPLICIT, B_FALSE, EACCES, NULL));
+}
+
+/*
* Common routine which determines whether a given credential can
* act on a given mount.
* When called through mount, the parameter needoptcheck is a pointer
diff --git a/usr/src/uts/common/os/priv_defs b/usr/src/uts/common/os/priv_defs
index ff839d4..038ad88 100644
--- a/usr/src/uts/common/os/priv_defs
+++ b/usr/src/uts/common/os/priv_defs
@@ -223,6 +223,14 @@
This privilege is interpreted only if the system is configured
with Trusted Extensions.
+privilege PRIV_NET_MAC_IMPLICIT
+
+ Allows a process to set SO_MAC_IMPLICIT option by using
+ setsockopt(3SOCKET). This allows a privileged process to
+ transmit implicitly-labeled packets to a peer.
+ This privilege is interpreted only if the system is configured
+ with Trusted Extensions.
+
privilege PRIV_NET_OBSERVABILITY
Allows a process to access /dev/lo0 and the devices in /dev/ipnet/
diff --git a/usr/src/uts/common/os/putnext.c b/usr/src/uts/common/os/putnext.c
index caef9e9..5a6424f 100644
--- a/usr/src/uts/common/os/putnext.c
+++ b/usr/src/uts/common/os/putnext.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 1991-2003 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -28,8 +27,6 @@
/* All Rights Reserved */
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* UNIX Device Driver Interface functions
* This file contains the C-versions of putnext() and put().
@@ -61,9 +58,9 @@
*
* The redzone value is chosen dependent on the default stack size which is 8K
* on 32-bit kernels and on x86 and 16K on 64-bit kernels. The values are chosen
- * empirically. For 64-bit kernels it is 5000 and for 32-bit kernels it is 2500.
- * Experiments showed that 2500 is not enough for 64-bit kernels and 2048 is not
- * enough for 32-bit.
+ * empirically. For 64-bit kernels it is 5000 and for 32-bit kernels it is 3000.
+ * Experiments showed that 2500 is not enough for either 32-bit or 64-bit
+ * kernels.
*
* The redzone value is a tuneable rather then a constant to allow adjustments
* in the field.
@@ -83,7 +80,7 @@
#ifdef _LP64
#define PUT_STACK_NEEDED 5000
#else
-#define PUT_STACK_NEEDED 2500
+#define PUT_STACK_NEEDED 3000
#endif
int put_stack_needed = PUT_STACK_NEEDED;
@@ -160,7 +157,7 @@
ushort_t *sqcipcount = NULL;
TRACE_2(TR_FAC_STREAMS_FR, TR_PUTNEXT_START,
- "putnext_start:(%p, %p)", qp, mp);
+ "putnext_start:(%p, %p)", qp, mp);
ASSERT(mp->b_datap->db_ref != 0);
ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
@@ -198,7 +195,7 @@
queued = qp->q_sqflags & Q_SQQUEUED;
mutex_exit(sqciplock);
} else {
- slowlock:
+ slowlock:
ASSERT(sqciplock == NULL);
mutex_enter(SQLOCK(sq));
mutex_exit(sdlock);
@@ -440,7 +437,7 @@
ushort_t *sqcipcount = NULL;
TRACE_2(TR_FAC_STREAMS_FR, TR_PUT_START,
- "put:(%X, %X)", qp, mp);
+ "put:(%X, %X)", qp, mp);
ASSERT(mp->b_datap->db_ref != 0);
ASSERT(mp->b_next == NULL && mp->b_prev == NULL);
@@ -466,7 +463,7 @@
queued = qp->q_sqflags & Q_SQQUEUED;
mutex_exit(sqciplock);
} else {
- slowlock:
+ slowlock:
ASSERT(sqciplock == NULL);
mutex_enter(SQLOCK(sq));
flags = sq->sq_flags;
diff --git a/usr/src/uts/common/sys/policy.h b/usr/src/uts/common/sys/policy.h
index 4109ded..8613aa4 100644
--- a/usr/src/uts/common/sys/policy.h
+++ b/usr/src/uts/common/sys/policy.h
@@ -112,6 +112,7 @@
int secpolicy_net_config(const cred_t *, boolean_t);
int secpolicy_net_icmpaccess(const cred_t *);
int secpolicy_net_mac_aware(const cred_t *);
+int secpolicy_net_mac_implicit(const cred_t *);
int secpolicy_net_observability(const cred_t *);
int secpolicy_net_privaddr(const cred_t *, in_port_t, int proto);
int secpolicy_net_rawaccess(const cred_t *);
diff --git a/usr/src/uts/common/sys/socket.h b/usr/src/uts/common/sys/socket.h
index bdab588..435c432 100644
--- a/usr/src/uts/common/sys/socket.h
+++ b/usr/src/uts/common/sys/socket.h
@@ -176,6 +176,7 @@
#define SCM_TIMESTAMP SO_TIMESTAMP /* socket control message timestamp */
#define SO_ALLZONES 0x1014 /* bind in all zones */
#define SO_EXCLBIND 0x1015 /* exclusive binding */
+#define SO_MAC_IMPLICIT 0x1016 /* hide mac labels on wire */
#ifdef _KERNEL
#define SO_SRCADDR 0x2001 /* Internal: AF_UNIX source address */
diff --git a/usr/src/uts/common/sys/tsol/label.h b/usr/src/uts/common/sys/tsol/label.h
index d048315..5845c92 100644
--- a/usr/src/uts/common/sys/tsol/label.h
+++ b/usr/src/uts/common/sys/tsol/label.h
@@ -103,7 +103,21 @@
#define DEFAULT_DOI 1
-#define TSLF_UNLABELED 0x00000001 /* peer is unlabeled */
+/*
+ * TSLF_UNLABELED is set in tsl_flags for packets with no explicit label
+ * when the peer is unlabeled.
+ *
+ * TSLF_IMPLICIT_IN is set when a packet is received with no explicit label
+ * from a peer which is flagged in the tnrhdb as label-aware.
+ *
+ * TSLF_IMPLICIT_OUT is set when the packet should be sent without an
+ * explict label even if the peer or next-hop router is flagged in the
+ * tnrhdb as label-aware.
+ */
+
+#define TSLF_UNLABELED 0x00000001 /* peer is unlabeled */
+#define TSLF_IMPLICIT_IN 0x00000002 /* inbound implicit */
+#define TSLF_IMPLICIT_OUT 0x00000004 /* outbound implicit */
#define CR_SL(cr) (label2bslabel(crgetlabel(cr)))
diff --git a/usr/src/uts/common/sys/tsol/tnet.h b/usr/src/uts/common/sys/tsol/tnet.h
index 802b90c..221f4c7 100644
--- a/usr/src/uts/common/sys/tsol/tnet.h
+++ b/usr/src/uts/common/sys/tsol/tnet.h
@@ -46,15 +46,15 @@
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_check_dest(const cred_t *, const void *, uchar_t, boolean_t,
+extern int tsol_check_dest(const cred_t *, const void *, uchar_t, uint_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 *,
ip_stack_t *);
-extern int tsol_check_label(const cred_t *, mblk_t **, boolean_t,
+extern int tsol_check_label(const cred_t *, mblk_t **, uint_t,
ip_stack_t *, pid_t);
-extern int tsol_check_label_v6(const cred_t *, mblk_t **, boolean_t,
+extern int tsol_check_label_v6(const cred_t *, mblk_t **, uint_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);