Mercurial > illumos > illumos-gate
changeset 10934:e209937a4f19
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
line wrap: on
line diff
--- a/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/Makefile Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/Makefile Mon Nov 02 15:39:20 2009 -0800 @@ -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:
--- a/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ikeadm.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ikeadm.c Mon Nov 02 15:39:20 2009 -0800 @@ -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);
--- a/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipseckey.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/cmd/cmd-inet/usr.sbin/ipsecutils/ipseckey.c Mon Nov 02 15:39:20 2009 -0800 @@ -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); }
--- a/usr/src/cmd/ptools/pfiles/pfiles.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/cmd/ptools/pfiles/pfiles.c Mon Nov 02 15:39:20 2009 -0800 @@ -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," }, };
--- a/usr/src/cmd/truss/print.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/cmd/truss/print.c Mon Nov 02 15:39:20 2009 -0800 @@ -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");
--- a/usr/src/cmd/tsol/tnctl/tnzonecfg Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/cmd/tsol/tnctl/tnzonecfg Mon Nov 02 15:39:20 2009 -0800 @@ -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
--- a/usr/src/lib/libipsecutil/Makefile.com Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/lib/libipsecutil/Makefile.com Mon Nov 02 15:39:20 2009 -0800 @@ -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)
--- a/usr/src/lib/libipsecutil/common/ikedoor.h Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/lib/libipsecutil/common/ikedoor.h Mon Nov 02 15:39:20 2009 -0800 @@ -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.
--- a/usr/src/lib/libipsecutil/common/ipsec_util.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/lib/libipsecutil/common/ipsec_util.c Mon Nov 02 15:39:20 2009 -0800 @@ -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;
--- a/usr/src/lib/libipsecutil/common/ipsec_util.h Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/lib/libipsecutil/common/ipsec_util.h Mon Nov 02 15:39:20 2009 -0800 @@ -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
--- a/usr/src/lib/libipsecutil/common/mapfile-vers Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/lib/libipsecutil/common/mapfile-vers Mon Nov 02 15:39:20 2009 -0800 @@ -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;
--- a/usr/src/tools/scripts/nightly.sh Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/tools/scripts/nightly.sh Mon Nov 02 15:39:20 2009 -0800 @@ -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 }
--- a/usr/src/uts/common/inet/ip/icmp.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/ip/icmp.c Mon Nov 02 15:39:20 2009 -0800 @@ -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;
--- a/usr/src/uts/common/inet/ip/icmp_opt_data.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/ip/icmp_opt_data.c Mon Nov 02 15:39:20 2009 -0800 @@ -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 },
--- a/usr/src/uts/common/inet/ip/ip.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/ip/ip.c Mon Nov 02 15:39:20 2009 -0800 @@ -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; + /* + * Both of these functions expect b_rptr to be + * where the IP header starts, so advance past the + * link layer header if present. + */ + mp->b_rptr += hlen; szone = ip_get_zoneid_v4(ipha->ipha_src, mp, ipst, ALL_ZONES); - /* - * The IP observability hook expects b_rptr to be - * where the IP header starts, so advance past the - * link layer header. - */ - mp->b_rptr += hlen; 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; }
--- a/usr/src/uts/common/inet/ip/ip6.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/ip/ip6.c Mon Nov 02 15:39:20 2009 -0800 @@ -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)
--- a/usr/src/uts/common/inet/ip/ip_opt_data.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/ip/ip_opt_data.c Mon Nov 02 15:39:20 2009 -0800 @@ -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 },
--- a/usr/src/uts/common/inet/ip/ip_sadb.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/ip/ip_sadb.c Mon Nov 02 15:39:20 2009 -0800 @@ -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)
--- a/usr/src/uts/common/inet/ip/ipclassifier.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/ip/ipclassifier.c Mon Nov 02 15:39:20 2009 -0800 @@ -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; } /*
--- a/usr/src/uts/common/inet/ip/ipsecah.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/ip/ipsecah.c Mon Nov 02 15:39:20 2009 -0800 @@ -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); - } - - inbound = INBOUND_BUCKET(sp, assoc->sadb_sa_spi); - outbound = &sp->sdb_of[outhash]; + 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); + /* * 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.
--- a/usr/src/uts/common/inet/ip/ipsecesp.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/ip/ipsecesp.c Mon Nov 02 15:39:20 2009 -0800 @@ -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.. */
--- a/usr/src/uts/common/inet/ip/sadb.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/ip/sadb.c Mon Nov 02 15:39:20 2009 -0800 @@ -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_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; +sadb_purge_sa(mblk_t *mp, keysock_in_t *ksi, sadb_t *sp, + int *diagnostic, queue_t *pfkey_q, queue_t *ip_q) +{ struct sadb_purge_state ps; - - /* - * 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 + 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); + 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) { - 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; + 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); + } + + 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); - } - - 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); + 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); } - 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) -{ - 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; - +static int +get_ipsa_pair(ipsa_query_t *sq, ipsap_t *ipsapp, int *diagnostic) +{ 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); - - if (assoc->sadb_sa_flags & IPSA_F_INBOUND) { - ipsapp->ipsap_sa_ptr = ipsec_getassocbyspi(inbound_bucket, - assoc->sadb_sa_spi, srcaddr, dstaddr, af); + mutex_enter(&sq->outbound->isaf_lock); + mutex_enter(&sq->inbound->isaf_lock); + + 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; - } - 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++; - } - } - -#endif + + if (effective_cred != NULL) { + crfree(cred); + cred = effective_cred; + } + + 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); + } + } + 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(); - - /* 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 (kmcext != NULL) { - kmp = kmcext->sadb_x_kmc_proto; - kmc = kmcext->sadb_x_kmc_cookie; - } - - 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) { + 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); + + if (error != 0) + return (error); + + error = get_ipsa_pair(&sq, &ipsapp, diagnostic); + if (error != 0) + return (error); + + 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); - } - - if (oipsapp->ipsap_psa_ptr == NULL) { + return (error); /* XXX EINVAL instead of ESRCH? */ + } + + 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); - } - - destroy_ipsa_pair(oipsapp); + 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); 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? */ - - (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) { - 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; + sens = sadb_make_sens_ext(cr, &sens_len); + + if (sens == NULL) { + freeb(extended); + goto punt_extended; + } + } + + extended->b_cont = sadb_extended_acquire(&sel, pp, ap, tunnel_mode, + seq, 0, sens, ns); + + if (sens != NULL) + kmem_free(sens, sens_len); + + if (extended->b_cont == NULL) { + freeb(extended); + goto punt_extended; + } /* * Send an ACQUIRE message (and possible an extended ACQUIRE) based on @@ -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); } - - kmem_free(ipsapp, sizeof (*ipsapp)); + init_ipsa_pair(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; } /*
--- a/usr/src/uts/common/inet/ip/spd.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/ip/spd.c Mon Nov 02 15:39:20 2009 -0800 @@ -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; - - check_proto = IPPROTO_ICMPV6; + outer_hdr_len = prepended_length(mp, (uintptr_t)ip6h); + + 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]; - } - - if (nexthdr == check_proto) { - typecode = (uint8_t *)ports; - sel->ips_icmp_type = *typecode++; - sel->ips_icmp_code = *typecode; + transportp = &spare_mp->b_rptr[hdr_len + outer_hdr_len]; + } + + 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) {
--- a/usr/src/uts/common/inet/ip/tn_ipopt.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/ip/tn_ipopt.c Mon Nov 02 15:39:20 2009 -0800 @@ -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 */
--- a/usr/src/uts/common/inet/ip/tnet.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/ip/tnet.c Mon Nov 02 15:39:20 2009 -0800 @@ -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) { + /* + * If peer is label-aware, mark as "implicit" rather than + * "unlabeled" to cause appropriate mac-exempt processing + * to happen. + */ + if (src_rhtp->tpc_tp.host_type == SUN_CIPSO) + label_flags = TSLF_IMPLICIT_IN; + else if (src_rhtp->tpc_tp.host_type == UNLABELED) + label_flags = TSLF_UNLABELED; + else { + DTRACE_PROBE2(tx__get__pkt__label, char *, + "template(1) has unknown hosttype", + tsol_tpc_t *, src_rhtp); + } + + + if (!tsol_find_unlabeled_label(src_rhtp, &sl, &doi)) { TPC_RELE(src_rhtp); - pr_addr_dbg("unlabeled packet forged from %s\n", - version == IPV4_VERSION ? AF_INET : AF_INET6, src); return (B_FALSE); } - - sl = src_rhtp->tpc_tp.tp_def_label; - setbltype(&sl, SUN_SL_ID); - doi = src_rhtp->tpc_tp.tp_doi; TPC_RELE(src_rhtp); break; @@ -805,23 +862,12 @@ } 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; }
--- a/usr/src/uts/common/inet/ipclassifier.h Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/ipclassifier.h Mon Nov 02 15:39:20 2009 -0800 @@ -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)))
--- a/usr/src/uts/common/inet/ipsec_impl.h Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/ipsec_impl.h Mon Nov 02 15:39:20 2009 -0800 @@ -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.
--- a/usr/src/uts/common/inet/iptun/iptun.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/iptun/iptun.c Mon Nov 02 15:39:20 2009 -0800 @@ -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; }
--- a/usr/src/uts/common/inet/mib2.h Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/mib2.h Mon Nov 02 15:39:20 2009 -0800 @@ -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 */
--- a/usr/src/uts/common/inet/sadb.h Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/sadb.h Mon Nov 02 15:39:20 2009 -0800 @@ -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; + netstack_t *ipsa_netstack; /* Does not have a netstack_hold */ - /* 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. */
--- a/usr/src/uts/common/inet/sctp/sctp.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/sctp/sctp.c Mon Nov 02 15:39:20 2009 -0800 @@ -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,
--- a/usr/src/uts/common/inet/sctp/sctp_bind.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/sctp/sctp_bind.c Mon Nov 02 15:39:20 2009 -0800 @@ -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);
--- a/usr/src/uts/common/inet/sctp/sctp_common.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/sctp/sctp_common.c Mon Nov 02 15:39:20 2009 -0800 @@ -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)
--- a/usr/src/uts/common/inet/sctp/sctp_cookie.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/sctp/sctp_cookie.c Mon Nov 02 15:39:20 2009 -0800 @@ -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),
--- a/usr/src/uts/common/inet/sctp/sctp_error.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/sctp/sctp_error.c Mon Nov 02 15:39:20 2009 -0800 @@ -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;
--- a/usr/src/uts/common/inet/sctp/sctp_impl.h Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/sctp/sctp_impl.h Mon Nov 02 15:39:20 2009 -0800 @@ -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
--- a/usr/src/uts/common/inet/sctp/sctp_opt_data.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/sctp/sctp_opt_data.c Mon Nov 02 15:39:20 2009 -0800 @@ -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;
--- a/usr/src/uts/common/inet/sctp/sctp_snmp.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/sctp/sctp_snmp.c Mon Nov 02 15:39:20 2009 -0800 @@ -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) {
--- a/usr/src/uts/common/inet/tcp/tcp.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/tcp/tcp.c Mon Nov 02 15:39:20 2009 -0800 @@ -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; + /* + * Both of these functions expect b_rptr to be + * where the IP header starts, so advance past the + * link layer header if present. + */ + mp->b_rptr += ire_fp_mp_len; szone = ip_get_zoneid_v4(ipha->ipha_src, mp, ipst, ALL_ZONES); - - /* - * The IP observability hook expects b_rptr to be - * where the IP header starts, so advance past the - * link layer header. - */ - mp->b_rptr += ire_fp_mp_len; 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; + 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); - if (ire_fp_mp_len != 0) - mp->b_rptr += ire_fp_mp_len; 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; } }
--- a/usr/src/uts/common/inet/tcp/tcp_opt_data.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/tcp/tcp_opt_data.c Mon Nov 02 15:39:20 2009 -0800 @@ -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 },
--- a/usr/src/uts/common/inet/udp/udp.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/udp/udp.c Mon Nov 02 15:39:20 2009 -0800 @@ -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; + /* + * Both of these functions expect b_rptr to be + * where the IP header starts, so advance past the + * link layer header if present. + */ + mp->b_rptr += ire_fp_mp_len; szone = ip_get_zoneid_v4(ipha->ipha_src, mp, ipst, ALL_ZONES); - - /* - * The IP observability hook expects b_rptr to be - * where the IP header starts, so advance past the - * link layer header. - */ - mp->b_rptr += ire_fp_mp_len; 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 ||
--- a/usr/src/uts/common/inet/udp/udp_opt_data.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/inet/udp/udp_opt_data.c Mon Nov 02 15:39:20 2009 -0800 @@ -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 },
--- a/usr/src/uts/common/net/pfkeyv2.h Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/net/pfkeyv2.h Mon Nov 02 15:39:20 2009 -0800 @@ -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... */
--- a/usr/src/uts/common/os/policy.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/os/policy.c Mon Nov 02 15:39:20 2009 -0800 @@ -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
--- a/usr/src/uts/common/os/priv_defs Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/os/priv_defs Mon Nov 02 15:39:20 2009 -0800 @@ -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/
--- a/usr/src/uts/common/os/putnext.c Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/os/putnext.c Mon Nov 02 15:39:20 2009 -0800 @@ -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;
--- a/usr/src/uts/common/sys/policy.h Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/sys/policy.h Mon Nov 02 15:39:20 2009 -0800 @@ -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 *);
--- a/usr/src/uts/common/sys/socket.h Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/sys/socket.h Mon Nov 02 15:39:20 2009 -0800 @@ -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 */
--- a/usr/src/uts/common/sys/tsol/label.h Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/sys/tsol/label.h Mon Nov 02 15:39:20 2009 -0800 @@ -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)))
--- a/usr/src/uts/common/sys/tsol/tnet.h Mon Nov 02 15:57:35 2009 -0700 +++ b/usr/src/uts/common/sys/tsol/tnet.h Mon Nov 02 15:39:20 2009 -0800 @@ -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);