Mercurial > illumos > illumos-gate
changeset 4971:b721af044177
6560317 TX NFS server needs to support NFSv3 clients
6596123 TX NFSv4 should not allow a read-up mount via WebNFS
author | jarrett |
---|---|
date | Fri, 31 Aug 2007 10:09:18 -0700 |
parents | 1cbc767b641b |
children | b6da5df14183 |
files | usr/src/cmd/fs.d/nfs/mountd/Makefile usr/src/cmd/fs.d/nfs/mountd/mountd.c usr/src/uts/common/fs/nfs/nfs3_srv.c usr/src/uts/common/fs/nfs/nfs4_srv.c usr/src/uts/common/fs/nfs/nfs_srv.c usr/src/uts/common/fs/nfs/nfs_subr.c usr/src/uts/common/inet/udp/udp.c usr/src/uts/common/os/tlabel.c usr/src/uts/common/sys/tsol/label.h |
diffstat | 9 files changed, 626 insertions(+), 66 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/cmd/fs.d/nfs/mountd/Makefile Fri Aug 31 09:25:38 2007 -0700 +++ b/usr/src/cmd/fs.d/nfs/mountd/Makefile Fri Aug 31 10:09:18 2007 -0700 @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -36,7 +36,7 @@ nfsauth_xdr.o exportlist.o hashset.o OBJS = $(LOCAL) $(COMMON) SRCS = $(LOCAL:%.o=%.c) $(FSLIBSRC) ../lib/nfs_sec.c ../lib/sharetab.c -LDLIBS += -lrpcsvc -lnsl -lbsm -lsocket -ldoor +LDLIBS += -lrpcsvc -lnsl -lbsm -lsocket -ldoor -ltsnet -ltsol CPPFLAGS += -D_REENTRANT $(TYPEPROG): $(OBJS)
--- a/usr/src/cmd/fs.d/nfs/mountd/mountd.c Fri Aug 31 09:25:38 2007 -0700 +++ b/usr/src/cmd/fs.d/nfs/mountd/mountd.c Fri Aug 31 10:09:18 2007 -0700 @@ -74,6 +74,9 @@ #include <sharefs/sharetab.h> #include "../lib/sharetab.h" #include "mountd.h" +#include <tsol/label.h> +#include <sys/tsol/label_macro.h> +#include <libtsnet.h> struct sh_list *share_list; @@ -101,6 +104,7 @@ static int netmatch(struct netbuf *, char *); static void sigexit(int); static int newopts(char *); +static tsol_tpent_t *get_client_template(struct sockaddr *); static int verbose; static int rejecting; @@ -826,6 +830,7 @@ int flavor_list[MAX_FLAVORS]; int flavor_count; struct netbuf *nb; + ucred_t *uc = NULL; transp = rqstp->rq_xprt; version = rqstp->rq_vers; @@ -862,16 +867,19 @@ } /* - * Trusted Extension doesn't support older versions of nfs(v2, v3). - * To prevent circumventing TX label policy via using an older - * version of nfs client, reject the mount request and log an - * error. + * Trusted Extension doesn't support nfsv2. nfsv2 client + * uses MOUNT protocol v1 and v2. To prevent circumventing + * TX label policy via using nfsv2 client, reject a mount + * request with version less than 3 and log an error. */ if (is_system_labeled()) { - syslog(LOG_ERR, - "mount rejected: Solaris TX only supports nfs4 clients"); - error = EACCES; - goto reply; + if (version < 3) { + if (verbose) + syslog(LOG_ERR, + "Rejected mount: TX doesn't support NFSv2"); + error = EACCES; + goto reply; + } } /* @@ -916,6 +924,74 @@ } /* + * Check MAC policy here. The server side policy should be + * consistent with client side mount policy, i.e. + * - we disallow an admin_low unlabeled client to mount + * - we disallow mount from a lower labeled client. + */ + if (is_system_labeled()) { + m_label_t *clabel = NULL; + m_label_t *slabel = NULL; + m_label_t admin_low; + + if (svc_getcallerucred(rqstp->rq_xprt, &uc) != 0) { + syslog(LOG_ERR, + "mount request: Failed to get caller's ucred : %m"); + error = EACCES; + goto reply; + } + if ((clabel = ucred_getlabel(uc)) == NULL) { + syslog(LOG_ERR, + "mount request: can't get client label from ucred"); + error = EACCES; + goto reply; + } + + bsllow(&admin_low); + if (blequal(&admin_low, clabel)) { + struct sockaddr *ca; + tsol_tpent_t *tp; + + ca = (struct sockaddr *)(void *)svc_getrpccaller( + rqstp->rq_xprt)->buf; + if (ca == NULL) { + error = EACCES; + goto reply; + } + /* + * get trusted network template associated + * with the client. + */ + tp = get_client_template(ca); + if (tp == NULL || tp->host_type != SUN_CIPSO) { + if (tp != NULL) + tsol_freetpent(tp); + error = EACCES; + goto reply; + } + tsol_freetpent(tp); + } else { + if ((slabel = m_label_alloc(MAC_LABEL)) == NULL) { + error = EACCES; + goto reply; + } + + if (getlabel(rpath, slabel) != 0) { + m_label_free(slabel); + error = EACCES; + goto reply; + } + + if (!bldominates(clabel, slabel)) { + m_label_free(slabel); + error = EACCES; + goto reply; + } + m_label_free(slabel); + } + } + + /* * Now get the filehandle. * * NFS V2 clients get a 32 byte filehandle. @@ -945,6 +1021,8 @@ } reply: + if (uc != NULL) + ucred_free(uc); switch (version) { case MOUNTVERS: case MOUNTVERS_POSIX: @@ -2139,3 +2217,44 @@ _exit(0); _exit(1); } + +static tsol_tpent_t * +get_client_template(struct sockaddr *sock) +{ + in_addr_t v4client; + in6_addr_t v6client; + char v4_addr[INET_ADDRSTRLEN]; + char v6_addr[INET6_ADDRSTRLEN]; + tsol_rhent_t *rh; + tsol_tpent_t *tp; + + switch (sock->sa_family) { + case AF_INET: + v4client = ((struct sockaddr_in *)(void *)sock)-> + sin_addr.s_addr; + if (inet_ntop(AF_INET, &v4client, v4_addr, INET_ADDRSTRLEN) == + NULL) + return (NULL); + rh = tsol_getrhbyaddr(v4_addr, sizeof (v4_addr), AF_INET); + if (rh == NULL) + return (NULL); + tp = tsol_gettpbyname(rh->rh_template); + tsol_freerhent(rh); + return (tp); + break; + case AF_INET6: + v6client = ((struct sockaddr_in6 *)(void *)sock)->sin6_addr; + if (inet_ntop(AF_INET6, &v6client, v6_addr, INET6_ADDRSTRLEN) == + NULL) + return (NULL); + rh = tsol_getrhbyaddr(v6_addr, sizeof (v6_addr), AF_INET6); + if (rh == NULL) + return (NULL); + tp = tsol_gettpbyname(rh->rh_template); + tsol_freerhent(rh); + return (tp); + break; + default: + return (NULL); + } +}
--- a/usr/src/uts/common/fs/nfs/nfs3_srv.c Fri Aug 31 09:25:38 2007 -0700 +++ b/usr/src/uts/common/fs/nfs/nfs3_srv.c Fri Aug 31 10:09:18 2007 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -47,6 +47,7 @@ #include <sys/flock.h> #include <sys/nbmlock.h> #include <sys/policy.h> +#include <sys/sdt.h> #include <rpc/types.h> #include <rpc/auth.h> @@ -57,6 +58,12 @@ #include <sys/strsubr.h> +#include <sys/tsol/label.h> +#include <sys/tsol/tndb.h> + +#include <inet/ip.h> +#include <inet/ip6.h> + /* * These are the interface routines for the server side of the * Network File System. See the NFS version 3 protocol specification @@ -148,6 +155,21 @@ if (error) goto out; + if (is_system_labeled()) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + /* * We need to specially handle size changes because of * possible conflicting NBMAND locks. Get into critical @@ -380,12 +402,64 @@ error = rfs_publicfh_mclookup(args->what.name, dvp, cr, &vp, &exi, &sec); if (error && exi != NULL) - exi_rele(exi); /* See the comment below */ + exi_rele(exi); /* See comment below Re: publicfh_flag */ + /* + * Since WebNFS may bypass MOUNT, we need to ensure this + * request didn't come from an unlabeled admin_low client. + */ + if (is_system_labeled() && error == 0) { + struct sockaddr *ca; + int addr_type; + void *ipaddr; + tsol_tpc_t *tp; + + ca = (struct sockaddr *)svc_getrpccaller( + req->rq_xprt)->buf; + if (ca->sa_family == AF_INET) { + addr_type = IPV4_VERSION; + ipaddr = &((struct sockaddr_in *)ca)->sin_addr; + } else if (ca->sa_family == AF_INET6) { + addr_type = IPV6_VERSION; + ipaddr = &((struct sockaddr_in6 *) + ca)->sin6_addr; + } + tp = find_tpc(ipaddr, addr_type, B_FALSE); + if (tp == NULL || tp->tpc_tp.tp_doi != + l_admin_low->tsl_doi || tp->tpc_tp.host_type != + SUN_CIPSO) { + if (exi != NULL) + exi_rele(exi); + VN_RELE(vp); + resp->status = NFS3ERR_ACCES; + error = 1; + } + if (tp != NULL) + TPC_RELE(tp); + } } else { error = VOP_LOOKUP(dvp, args->what.name, &vp, NULL, 0, NULL, cr); } + if (is_system_labeled() && error == 0) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, dvp, + DOMINANCE_CHECK)) { + if (publicfh_flag && exi != NULL) + exi_rele(exi); + VN_RELE(vp); + resp->status = NFS3ERR_ACCES; + error = 1; + } + } + } + #ifdef DEBUG if (rfs3_do_post_op_attr) { dva.va_mask = AT_ALL; @@ -481,6 +555,9 @@ struct vattr *vap; struct vattr va; int checkwriteperm; + boolean_t dominant_label = B_FALSE; + boolean_t equal_label = B_FALSE; + boolean_t admin_low_client; vap = NULL; @@ -521,12 +598,33 @@ resp->resok.access = 0; + if (is_system_labeled()) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__opaccess__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if ((equal_label = do_rfs_label_check(clabel, vp, + EQUALITY_CHECK)) == B_FALSE) { + dominant_label = do_rfs_label_check(clabel, + vp, DOMINANCE_CHECK); + } else + dominant_label = B_TRUE; + admin_low_client = B_FALSE; + } else + admin_low_client = B_TRUE; + } + if (args->access & ACCESS3_READ) { error = VOP_ACCESS(vp, VREAD, 0, cr); if (error) { if (curthread->t_flag & T_WOULDBLOCK) goto out; - } else if (!MANDLOCK(vp, va.va_mode)) + } else if (!MANDLOCK(vp, va.va_mode) && + (!is_system_labeled() || admin_low_client || + dominant_label)) resp->resok.access |= ACCESS3_READ; } if ((args->access & ACCESS3_LOOKUP) && vp->v_type == VDIR) { @@ -534,7 +632,8 @@ if (error) { if (curthread->t_flag & T_WOULDBLOCK) goto out; - } else + } else if (!is_system_labeled() || admin_low_client || + dominant_label) resp->resok.access |= ACCESS3_LOOKUP; } if (checkwriteperm && @@ -543,7 +642,8 @@ if (error) { if (curthread->t_flag & T_WOULDBLOCK) goto out; - } else if (!MANDLOCK(vp, va.va_mode)) { + } else if (!MANDLOCK(vp, va.va_mode) && + (!is_system_labeled() || admin_low_client || equal_label)) { resp->resok.access |= (args->access & (ACCESS3_MODIFY|ACCESS3_EXTEND)); } @@ -554,7 +654,8 @@ if (error) { if (curthread->t_flag & T_WOULDBLOCK) goto out; - } else + } else if (!is_system_labeled() || admin_low_client || + equal_label) resp->resok.access |= ACCESS3_DELETE; } if (args->access & ACCESS3_EXECUTE) { @@ -562,7 +663,9 @@ if (error) { if (curthread->t_flag & T_WOULDBLOCK) goto out; - } else if (!MANDLOCK(vp, va.va_mode)) + } else if (!MANDLOCK(vp, va.va_mode) && + (!is_system_labeled() || admin_low_client || + dominant_label)) resp->resok.access |= ACCESS3_EXECUTE; } @@ -644,6 +747,21 @@ goto out1; } + if (is_system_labeled()) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP); iov.iov_base = data; @@ -745,6 +863,21 @@ goto out; } + if (is_system_labeled()) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__opread__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + /* * Check to see if the v4 side of the server has delegated * this file. If so, then we return JUKEBOX to allow the @@ -995,6 +1128,21 @@ goto out; } + if (is_system_labeled()) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + /* * Check to see if the v4 side of the server has delegated * this file. If so, then we return JUKEBOX to allow the @@ -1251,6 +1399,21 @@ goto out1; } + if (is_system_labeled()) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + if (args->how.mode == EXCLUSIVE) { va.va_mask = AT_TYPE | AT_MODE | AT_MTIME; va.va_type = VREG; @@ -1591,6 +1754,21 @@ goto out1; } + if (is_system_labeled()) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + error = sattr3_to_vattr(&args->attributes, &va); if (error) goto out; @@ -1732,6 +1910,21 @@ goto out1; } + if (is_system_labeled()) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va); if (error) goto out; @@ -1890,6 +2083,21 @@ goto out1; } + if (is_system_labeled()) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + switch (args->what.type) { case NF3CHR: case NF3BLK: @@ -2077,6 +2285,21 @@ goto out1; } + if (is_system_labeled()) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__opremove__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + /* * Check for a conflict with a non-blocking mandatory share * reservation and V4 delegations @@ -2201,6 +2424,21 @@ goto out1; } + if (is_system_labeled()) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__opremovedir__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + error = VOP_RMDIR(vp, args->object.name, rootdir, cr); #ifdef DEBUG @@ -2275,6 +2513,7 @@ nfs_fh3 *fh3; struct exportinfo *to_exi; vnode_t *srcvp = NULL; + bslabel_t *clabel; fbvap = NULL; favap = NULL; @@ -2288,6 +2527,20 @@ goto out; } + if (is_system_labeled()) { + clabel = req->rq_label; + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + #ifdef DEBUG if (rfs3_do_pre_op_attr) { fbva.va_mask = AT_ALL; @@ -2352,6 +2605,15 @@ goto out1; } + if (is_system_labeled()) { + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + /* * Check for a conflict with a non-blocking mandatory share * reservation or V4 delegations. @@ -2486,6 +2748,7 @@ struct vattr ava; nfs_fh3 *fh3; struct exportinfo *to_exi; + bslabel_t *clabel; vap = NULL; bvap = NULL; @@ -2522,6 +2785,21 @@ goto out1; } + if (is_system_labeled()) { + clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + dvp = nfs3_fhtovp(&args->link.dir, exi); if (dvp == NULL) { error = ESTALE; @@ -2559,6 +2837,18 @@ goto out1; } + if (is_system_labeled()) { + DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + error = VOP_LINK(dvp, vp, args->link.name, cr); #ifdef DEBUG @@ -2671,6 +2961,21 @@ goto out; } + if (is_system_labeled()) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); #ifdef DEBUG @@ -2915,6 +3220,22 @@ goto out; } + if (is_system_labeled()) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel, + char *, "got client label from request(1)", + struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); #ifdef DEBUG @@ -3236,6 +3557,21 @@ goto out; } + if (is_system_labeled()) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + error = VFS_STATVFS(vp->v_vfsp, &sb); #ifdef DEBUG @@ -3250,6 +3586,7 @@ #endif VN_RELE(vp); + vp = NULL; if (error) goto out; @@ -3280,6 +3617,9 @@ resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); +out1: + if (vp != NULL) + VN_RELE(vp); vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); } @@ -3313,6 +3653,23 @@ return; } + if (is_system_labeled()) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) { + resp->status = NFS3ERR_STALE; + vattr_to_post_op_attr(NULL, + &resp->resfail.obj_attributes); + return; + } + } + } + #ifdef DEBUG if (rfs3_do_post_op_attr) { va.va_mask = AT_ALL; @@ -3380,6 +3737,21 @@ goto out; } + if (is_system_labeled()) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + #ifdef DEBUG if (rfs3_do_post_op_attr) { va.va_mask = AT_ALL; @@ -3431,6 +3803,7 @@ resp->status = NFS3ERR_JUKEBOX; } else resp->status = puterrno3(error); +out1: if (vp != NULL) VN_RELE(vp); vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes); @@ -3492,6 +3865,21 @@ goto out1; } + if (is_system_labeled()) { + bslabel_t *clabel = req->rq_label; + + ASSERT(clabel != NULL); + DTRACE_PROBE2(tx__rfs3__log__info__opcommit__clabel, char *, + "got client label from request(1)", struct svc_req *, req); + + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) { + resp->status = NFS3ERR_ACCES; + goto out1; + } + } + } + if (crgetuid(cr) != bva.va_uid && (error = VOP_ACCESS(vp, VWRITE, 0, cr))) goto out;
--- a/usr/src/uts/common/fs/nfs/nfs4_srv.c Fri Aug 31 09:25:38 2007 -0700 +++ b/usr/src/uts/common/fs/nfs/nfs4_srv.c Fri Aug 31 10:09:18 2007 -0700 @@ -140,12 +140,6 @@ #define DIRENT64_TO_DIRCOUNT(dp) \ (3 * BYTES_PER_XDR_UNIT + DIRENT64_NAMELEN((dp)->d_reclen)) -/* - * types of label comparison - */ -#define EQUALITY_CHECK 0 -#define DOMINANCE_CHECK 1 - time_t rfs4_start_time; /* Initialized in rfs4_srvrinit */ static sysid_t lockt_sysid; /* dummy sysid for all LOCKT calls */ @@ -1202,32 +1196,6 @@ resp->SECINFO4resok_val = NULL; } -/* - * do label check on client label and server's file lable. - */ -static boolean_t -do_rfs4_label_check(bslabel_t *clabel, vnode_t *vp, int flag) -{ - bslabel_t *slabel; - ts_label_t *tslabel; - boolean_t result; - - if ((tslabel = nfs4_getflabel(vp)) == NULL) { - return (B_FALSE); - } - slabel = label2bslabel(tslabel); - DTRACE_PROBE4(tx__rfs4__log__info__labelcheck, char *, - "comparing server's file label(1) with client label(2) (vp(3))", - bslabel_t *, slabel, bslabel_t *, clabel, vnode_t *, vp); - - if (flag == EQUALITY_CHECK) - result = blequal(clabel, slabel); - else - result = bldominates(clabel, slabel); - label_rele(tslabel); - return (result); -} - /* ARGSUSED */ static void rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req, @@ -1294,7 +1262,7 @@ "got client label from request(1)", struct svc_req *, req); if (!blequal(&l_admin_low->tsl_label, clabel)) { - if ((tslabel = nfs4_getflabel(vp)) == NULL) { + if ((tslabel = nfs_getflabel(vp)) == NULL) { *cs->statusp = resp->status = puterrno4(EACCES); return; } @@ -2657,7 +2625,7 @@ "got client label from request(1)", struct svc_req *, req); if (!blequal(&l_admin_low->tsl_label, clabel)) { - if (!do_rfs4_label_check(clabel, vp, DOMINANCE_CHECK)) { + if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) { error = EACCES; goto err_out; } @@ -2686,9 +2654,12 @@ if (tp == NULL || tp->tpc_tp.tp_doi != l_admin_low->tsl_doi || tp->tpc_tp.host_type != SUN_CIPSO) { + if (tp != NULL) + TPC_RELE(tp); error = EACCES; goto err_out; } + TPC_RELE(tp); } } @@ -3159,6 +3130,23 @@ return; } + if (is_system_labeled()) { + bslabel_t *clabel; + + ASSERT(req->rq_label != NULL); + clabel = req->rq_label; + DTRACE_PROBE2(tx__rfs4__log__info__opputpubfh__clabel, char *, + "got client label from request(1)", + struct svc_req *, req); + if (!blequal(&l_admin_low->tsl_label, clabel)) { + if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK)) { + *cs->statusp = resp->status = + NFS4ERR_SERVERFAULT; + return; + } + } + } + error = makefh4(&cs->fh, vp, exi_public); if (error != 0) { *cs->statusp = resp->status = puterrno4(error); @@ -3830,7 +3818,7 @@ "got client label from request(1)", struct svc_req *, req); if (!blequal(&l_admin_low->tsl_label, clabel)) { - if (!do_rfs4_label_check(clabel, vp, EQUALITY_CHECK)) { + if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) { *cs->statusp = resp->status = NFS4ERR_ACCESS; kmem_free(nm, len); if (in_crit) @@ -4085,7 +4073,7 @@ "got client label from request(1)", struct svc_req *, req); if (!blequal(&l_admin_low->tsl_label, clabel)) { - if (!do_rfs4_label_check(clabel, ndvp, + if (!do_rfs_label_check(clabel, ndvp, EQUALITY_CHECK)) { *cs->statusp = resp->status = NFS4ERR_ACCESS; return; @@ -4936,7 +4924,7 @@ "got client label from request(1)", struct svc_req *, req); if (!blequal(&l_admin_low->tsl_label, clabel)) { - if (!do_rfs4_label_check(clabel, cs->vp, + if (!do_rfs_label_check(clabel, cs->vp, EQUALITY_CHECK)) { *cs->statusp = resp->status = NFS4ERR_ACCESS; return; @@ -5813,7 +5801,7 @@ "got client label from request(1)", struct svc_req *, req); if (!blequal(&l_admin_low->tsl_label, clabel)) { - if (!do_rfs4_label_check(clabel, dvp, EQUALITY_CHECK)) { + if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK)) { return (NFS4ERR_ACCESS); } }
--- a/usr/src/uts/common/fs/nfs/nfs_srv.c Fri Aug 31 09:25:38 2007 -0700 +++ b/usr/src/uts/common/fs/nfs/nfs_srv.c Fri Aug 31 10:09:18 2007 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -370,6 +370,18 @@ "rfs_lookup_start:"); /* + * Trusted Extension doesn't support NFSv2. MOUNT + * will reject v2 clients. Need to prevent v2 client + * access via WebNFS here. + */ + if (is_system_labeled() && req->rq_vers == 2) { + dr->dr_status = NFSERR_ACCES; + TRACE_1(TR_FAC_NFS, TR_RFS_LOOKUP_END, + "rfs_lookup_end:(%S)", "access"); + return; + } + + /* * Disallow NULL paths */ if (da->da_name == NULL || *da->da_name == '\0') {
--- a/usr/src/uts/common/fs/nfs/nfs_subr.c Fri Aug 31 09:25:38 2007 -0700 +++ b/usr/src/uts/common/fs/nfs/nfs_subr.c Fri Aug 31 10:09:18 2007 -0700 @@ -62,6 +62,7 @@ #include <sys/list.h> #include <sys/tsol/tnet.h> #include <sys/priv.h> +#include <sys/sdt.h> #include <inet/ip6.h> @@ -76,6 +77,8 @@ #include <nfs/rnode.h> #include <nfs/nfs_acl.h> +#include <sys/tsol/label.h> + /* * The hash queues for the access to active and cached rnodes * are organized as doubly linked lists. A reader/writer lock @@ -5128,3 +5131,30 @@ mutex_exit(&curproc->p_splock); return (rv); } + +/* + * TX NFS routine used by NFSv3 and NFSv4 to do label check + * on client label and server's file object lable. + */ +boolean_t +do_rfs_label_check(bslabel_t *clabel, vnode_t *vp, int flag) +{ + bslabel_t *slabel; + ts_label_t *tslabel; + boolean_t result; + + if ((tslabel = nfs_getflabel(vp)) == NULL) { + return (B_FALSE); + } + slabel = label2bslabel(tslabel); + DTRACE_PROBE4(tx__rfs__log__info__labelcheck, char *, + "comparing server's file label(1) with client label(2) (vp(3))", + bslabel_t *, slabel, bslabel_t *, clabel, vnode_t *, vp); + + if (flag == EQUALITY_CHECK) + result = blequal(clabel, slabel); + else + result = bldominates(clabel, slabel); + label_rele(tslabel); + return (result); +}
--- a/usr/src/uts/common/inet/udp/udp.c Fri Aug 31 09:25:38 2007 -0700 +++ b/usr/src/uts/common/inet/udp/udp.c Fri Aug 31 10:09:18 2007 -0700 @@ -6422,9 +6422,11 @@ ASSERT(mp1 != NULL && DB_TYPE(mp1) == M_DATA); /* - * Check if our saved options are valid; update if not + * Check if our saved options are valid; update if not. * TSOL Note: Since we are not in WRITER mode, UDP packets - * to different destination may require different labels. + * to different destination may require different labels, + * or worse, UDP packets to same IP address may require + * different labels due to use of shared all-zones address. * We use conn_lock to ensure that lastdst, ip_snd_options, * and ip_snd_options_len are consistent for the current * destination and are updated atomically. @@ -6442,8 +6444,14 @@ *error = ECONNREFUSED; goto done; } + /* + * update label option for this UDP socket if + * - the destination has changed, or + * - the UDP socket is MLP + */ if ((!IN6_IS_ADDR_V4MAPPED(&udp->udp_v6lastdst) || - V4_PART_OF_V6(udp->udp_v6lastdst) != v4dst) && + V4_PART_OF_V6(udp->udp_v6lastdst) != v4dst || + connp->conn_mlp_type != mlptSingle) && (*error = udp_update_label(q, mp, v4dst)) != 0) { mutex_exit(&connp->conn_lock); goto done; @@ -7350,7 +7358,9 @@ * avoid blowing up our stack here. * * TSOL Note: Since we are not in WRITER mode, UDP packets - * to different destination may require different labels. + * to different destination may require different labels, + * or worse, UDP packets to same IP address may require + * different labels due to use of shared all-zones address. * We use conn_lock to ensure that lastdst, sticky ipp_hopopts, * and sticky ipp_hopoptslen are consistent for the current * destination and are updated atomically. @@ -7368,8 +7378,14 @@ mutex_exit(&connp->conn_lock); goto done; } + /* + * update label option for this UDP socket if + * - the destination has changed, or + * - the UDP socket is MLP + */ if ((opt_present || - !IN6_ARE_ADDR_EQUAL(&udp->udp_v6lastdst, &ip6_dst)) && + !IN6_ARE_ADDR_EQUAL(&udp->udp_v6lastdst, &ip6_dst) || + connp->conn_mlp_type != mlptSingle) && (*error = udp_update_label_v6(q, mp, &ip6_dst)) != 0) { mutex_exit(&connp->conn_lock); goto done;
--- a/usr/src/uts/common/os/tlabel.c Fri Aug 31 09:25:38 2007 -0700 +++ b/usr/src/uts/common/os/tlabel.c Fri Aug 31 10:09:18 2007 -0700 @@ -528,11 +528,11 @@ } /* - * Used by NFSv4 to query label of a pathname - * component during lookup/access ops. + * Used by NFSv3 and NFSv4 server to query label of + * a pathname component during lookup/access ops. */ ts_label_t * -nfs4_getflabel(vnode_t *vp) +nfs_getflabel(vnode_t *vp) { zone_t *zone; ts_label_t *zone_label;
--- a/usr/src/uts/common/sys/tsol/label.h Fri Aug 31 09:25:38 2007 -0700 +++ b/usr/src/uts/common/sys/tsol/label.h Fri Aug 31 10:09:18 2007 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -39,6 +39,12 @@ extern "C" { #endif +/* + * types of label comparison + */ +#define EQUALITY_CHECK 0 +#define DOMINANCE_CHECK 1 + /* Binary Label Structure Definitions */ typedef struct _mac_label_impl m_label_t; @@ -123,7 +129,8 @@ extern int fgetlabel(int, m_label_t *); extern int _blinrange(const m_label_t *, const brange_t *); extern int blinlset(const m_label_t *, const blset_t); -extern ts_label_t *nfs4_getflabel(vnode_t *); +extern ts_label_t *nfs_getflabel(vnode_t *); +extern boolean_t do_rfs_label_check(bslabel_t *, vnode_t *, int); /* * The use of '!!' here prevents users from referencing this function-like