From 838e4208cccf722716a5a02f03871bf07413a32c Mon Sep 17 00:00:00 2001 From: Steve Dickson Date: Tue, 4 Dec 2012 10:39:29 -0500 Subject: [PATCH] Label NFS port to Fedora 3.7.0-0.rc7.git1.2.fc19 Signed-off-by: Steve Dickson --- config-generic | 1 + config-x86_64-generic | 2 +- kernel.spec | 6 +- lnfs-3.7.0-0.rc7.git1.2.fc19.patch | 3923 ++++++++++++++++++++++ lnfs-unset-3.7.0-0.rc7.git1.2.fc19.patch | 124 + 5 files changed, 4054 insertions(+), 2 deletions(-) create mode 100644 lnfs-3.7.0-0.rc7.git1.2.fc19.patch create mode 100644 lnfs-unset-3.7.0-0.rc7.git1.2.fc19.patch diff --git a/config-generic b/config-generic index a27aedd40..8def08345 100644 --- a/config-generic +++ b/config-generic @@ -3652,6 +3652,7 @@ CONFIG_NFS_V4=y # CONFIG_NFS_SWAP is not set CONFIG_NFS_V4_1=y CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org" +NFS_V4_SECURITY_LABEL=y CONFIG_NFSD=m CONFIG_NFSD_V3=y CONFIG_NFSD_V3_ACL=y diff --git a/config-x86_64-generic b/config-x86_64-generic index 6003f11c0..4e2ba5604 100644 --- a/config-x86_64-generic +++ b/config-x86_64-generic @@ -123,4 +123,4 @@ CONFIG_BPF_JIT=y # Should be 32bit only, but lacks KConfig depends # CONFIG_XO15_EBOOK is not set - +CONFIG_NFS_V4_SECURITY_LABEL=y diff --git a/kernel.spec b/kernel.spec index 0ba866e63..65cfdef97 100644 --- a/kernel.spec +++ b/kernel.spec @@ -31,7 +31,7 @@ Summary: The Linux kernel # # (Uncomment the '#' and both spaces below to set the buildid.) # -# % define buildid .local +%define buildid .lnfs37rc2 ################################################################### # The buildid can also be specified on the rpmbuild command line @@ -719,6 +719,8 @@ Patch2901: linux-2.6-v4l-dvb-experimental.patch # fs fixes # NFSv4 +Patch3000: lnfs-3.7.0-0.rc7.git1.2.fc19.patch +Patch3001: lnfs-unset-3.7.0-0.rc7.git1.2.fc19.patch # patches headed upstream Patch10000: fs-proc-devtree-remove_proc_entry.patch @@ -1370,6 +1372,8 @@ ApplyPatch arm-tegra-sdhci-module-fix.patch # eCryptfs # NFSv4 +ApplyPatch lnfs-3.7.0-0.rc7.git1.2.fc19.patch +ApplyPatch lnfs-unset-3.7.0-0.rc7.git1.2.fc19.patch # USB diff --git a/lnfs-3.7.0-0.rc7.git1.2.fc19.patch b/lnfs-3.7.0-0.rc7.git1.2.fc19.patch new file mode 100644 index 000000000..e57c32add --- /dev/null +++ b/lnfs-3.7.0-0.rc7.git1.2.fc19.patch @@ -0,0 +1,3923 @@ +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/client.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/client.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/client.c.orig 2012-11-29 16:37:13.672901481 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/client.c 2012-12-03 10:53:55.645785378 -0500 +@@ -1080,7 +1080,7 @@ struct nfs_server *nfs_create_server(str + } + + if (!(fattr->valid & NFS_ATTR_FATTR)) { +- error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh, fattr); ++ error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh, fattr, NULL); + if (error < 0) { + dprintk("nfs_create_server: getattr error = %d\n", -error); + goto error; +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/export.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/export.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/export.c.orig 2012-09-30 19:47:46.000000000 -0400 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/export.c 2012-12-03 10:53:55.670785398 -0500 +@@ -1112,6 +1112,9 @@ static struct flags { + { NFSEXP_ASYNC, {"async", "sync"}}, + { NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}}, + { NFSEXP_NOHIDE, {"nohide", ""}}, ++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL ++ { NFSEXP_SECURITY_LABEL, {"security_label", ""}}, ++#endif + { NFSEXP_CROSSMOUNT, {"crossmnt", ""}}, + { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}}, + { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}}, +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/dir.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/dir.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/dir.c.orig 2012-11-29 16:37:13.680901489 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/dir.c 2012-12-03 10:53:55.653785381 -0500 +@@ -447,7 +447,7 @@ void nfs_prime_dcache(struct dentry *par + dentry = d_lookup(parent, &filename); + if (dentry != NULL) { + if (nfs_same_file(dentry, entry)) { +- nfs_refresh_inode(dentry->d_inode, entry->fattr); ++ nfs_refresh_inode(dentry->d_inode, entry->fattr, entry->label); + goto out; + } else { + d_drop(dentry); +@@ -459,7 +459,7 @@ void nfs_prime_dcache(struct dentry *par + if (dentry == NULL) + return; + +- inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); ++ inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr, entry->label); + if (IS_ERR(inode)) + goto out; + +@@ -581,7 +581,8 @@ int nfs_readdir_xdr_to_array(nfs_readdir + entry.fh = nfs_alloc_fhandle(); + entry.fattr = nfs_alloc_fattr(); + entry.server = NFS_SERVER(inode); +- if (entry.fh == NULL || entry.fattr == NULL) ++ entry.label = nfs4_label_alloc(GFP_NOWAIT); ++ if (entry.fh == NULL || entry.fattr == NULL || entry.label == NULL) + goto out; + + array = nfs_readdir_get_array(page); +@@ -616,6 +617,7 @@ out_release_array: + out: + nfs_free_fattr(entry.fattr); + nfs_free_fhandle(entry.fh); ++ nfs4_label_free(entry.label); + return status; + } + +@@ -1034,6 +1036,7 @@ static int nfs_lookup_revalidate(struct + struct dentry *parent; + struct nfs_fh *fhandle = NULL; + struct nfs_fattr *fattr = NULL; ++ struct nfs4_label *label = NULL; + int error; + + if (flags & LOOKUP_RCU) +@@ -1076,16 +1079,30 @@ static int nfs_lookup_revalidate(struct + if (fhandle == NULL || fattr == NULL) + goto out_error; + +- error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) { ++ label = nfs4_label_alloc(GFP_NOWAIT); ++ if (label == NULL) ++ goto out_error; ++ } ++#endif ++ ++ error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label); + if (error) + goto out_bad; + if (nfs_compare_fh(NFS_FH(inode), fhandle)) + goto out_bad; +- if ((error = nfs_refresh_inode(inode, fattr)) != 0) ++ if ((error = nfs_refresh_inode(inode, fattr, label)) != 0) + goto out_bad; + + nfs_free_fattr(fattr); + nfs_free_fhandle(fhandle); ++ ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) ++ nfs4_label_free(label); ++#endif ++ + out_set_verifier: + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); + out_valid: +@@ -1122,6 +1139,7 @@ out_zap_parent: + out_error: + nfs_free_fattr(fattr); + nfs_free_fhandle(fhandle); ++ nfs4_label_free(label); + dput(parent); + dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) lookup returned error %d\n", + __func__, dentry->d_parent->d_name.name, +@@ -1207,6 +1225,7 @@ struct dentry *nfs_lookup(struct inode * + struct inode *inode = NULL; + struct nfs_fh *fhandle = NULL; + struct nfs_fattr *fattr = NULL; ++ struct nfs4_label *label = NULL; + int error; + + dfprintk(VFS, "NFS: lookup(%s/%s)\n", +@@ -1233,17 +1252,24 @@ struct dentry *nfs_lookup(struct inode * + if (fhandle == NULL || fattr == NULL) + goto out; + ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) { ++ label = nfs4_label_alloc(GFP_NOWAIT); ++ if (label == NULL) ++ goto out; ++ } ++#endif + parent = dentry->d_parent; + /* Protect against concurrent sillydeletes */ + nfs_block_sillyrename(parent); +- error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); ++ error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label); + if (error == -ENOENT) + goto no_entry; + if (error < 0) { + res = ERR_PTR(error); + goto out_unblock_sillyrename; + } +- inode = nfs_fhget(dentry->d_sb, fhandle, fattr); ++ inode = nfs_fhget(dentry->d_sb, fhandle, fattr, label); + res = ERR_CAST(inode); + if (IS_ERR(res)) + goto out_unblock_sillyrename; +@@ -1262,6 +1288,10 @@ no_entry: + out_unblock_sillyrename: + nfs_unblock_sillyrename(parent); + out: ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) ++ nfs4_label_free(label); ++#endif + nfs_free_fattr(fattr); + nfs_free_fhandle(fhandle); + return res; +@@ -1477,7 +1507,8 @@ no_open: + * Code common to create, mkdir, and mknod. + */ + int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, +- struct nfs_fattr *fattr) ++ struct nfs_fattr *fattr, ++ struct nfs4_label *label) + { + struct dentry *parent = dget_parent(dentry); + struct inode *dir = parent->d_inode; +@@ -1490,18 +1521,18 @@ int nfs_instantiate(struct dentry *dentr + if (dentry->d_inode) + goto out; + if (fhandle->size == 0) { +- error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr); ++ error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, NULL); + if (error) + goto out_error; + } + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); + if (!(fattr->valid & NFS_ATTR_FATTR)) { + struct nfs_server *server = NFS_SB(dentry->d_sb); +- error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr); ++ error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr, NULL); + if (error < 0) + goto out_error; + } +- inode = nfs_fhget(dentry->d_sb, fhandle, fattr); ++ inode = nfs_fhget(dentry->d_sb, fhandle, fattr, label); + error = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out_error; +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/Kconfig.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/Kconfig +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/Kconfig.orig 2012-09-30 19:47:46.000000000 -0400 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/Kconfig 2012-12-03 10:53:55.669785397 -0500 +@@ -81,6 +81,19 @@ config NFSD_V4 + + If unsure, say N. + ++config NFSD_V4_SECURITY_LABEL ++ bool "Provide Security Label support for NFSv4 server" ++ depends on NFSD_V4 && SECURITY ++ help ++ ++ Say Y here if you want enable fine-grained security label attribute ++ support for NFS version 4. Security labels allow security modules like ++ SELinux and Smack to label files to facilitate enforcement of their policies. ++ Without this an NFSv4 mount will have the same label on each file. ++ ++ If you do not wish to enable fine-grained security labels SELinux or ++ Smack policies on NFSv4 files, say N. ++ + config NFSD_FAULT_INJECTION + bool "NFS server manual fault injection" + depends on NFSD_V4 && DEBUG_KERNEL +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/nfs4proc.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/nfs4proc.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/nfs4proc.c.orig 2012-11-29 16:37:14.048901772 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/nfs4proc.c 2012-12-03 10:53:55.671785399 -0500 +@@ -41,6 +41,10 @@ + #include "vfs.h" + #include "current_stateid.h" + ++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL ++#include ++#endif ++ + #define NFSDDBG_FACILITY NFSDDBG_PROC + + static u32 nfsd_attrmask[] = { +@@ -228,6 +232,18 @@ do_open_lookup(struct svc_rqst *rqstp, s + (u32 *)open->op_verf.data, + &open->op_truncate, &open->op_created); + ++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL ++ if (!status && open->op_label != NULL) { ++ struct inode *inode = resfh->fh_dentry->d_inode; ++ ++ mutex_lock(&inode->i_mutex); ++ /* Is it appropriate to just kick back an error? */ ++ status = security_inode_setsecctx(resfh->fh_dentry, ++ open->op_label->label, open->op_label->len); ++ mutex_unlock(&inode->i_mutex); ++ } ++#endif ++ + /* + * Following rfc 3530 14.2.16, use the returned bitmask + * to indicate which attributes we used to store the +@@ -588,6 +604,18 @@ nfsd4_create(struct svc_rqst *rqstp, str + status = nfserr_badtype; + } + ++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL ++ if (!status && create->cr_label != NULL) { ++ struct inode *inode = resfh.fh_dentry->d_inode; ++ ++ mutex_lock(&inode->i_mutex); ++ /* Is it appropriate to just kick back an error? */ ++ status = security_inode_setsecctx(resfh.fh_dentry, ++ create->cr_label->label, create->cr_label->len); ++ mutex_unlock(&inode->i_mutex); ++ } ++#endif ++ + if (status) + goto out; + +@@ -869,6 +897,11 @@ nfsd4_setattr(struct svc_rqst *rqstp, st + setattr->sa_acl); + if (status) + goto out; ++ if (setattr->sa_label != NULL) ++ status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh, ++ setattr->sa_label); ++ if (status) ++ goto out; + status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, + 0, (time_t)0); + out: +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/nfs4xdr.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/nfs4xdr.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/nfs4xdr.c.orig 2012-11-29 16:37:14.066901788 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/nfs4xdr.c 2012-12-03 10:53:55.672785400 -0500 +@@ -54,6 +54,11 @@ + #include "state.h" + #include "cache.h" + ++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL ++#include ++#endif ++ ++ + #define NFSDDBG_FACILITY NFSDDBG_XDR + + /* +@@ -241,7 +246,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoun + + static __be32 + nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, +- struct iattr *iattr, struct nfs4_acl **acl) ++ struct iattr *iattr, struct nfs4_acl **acl, ++ struct nfs4_label **label) + { + int expected_len, len = 0; + u32 dummy32; +@@ -385,6 +391,50 @@ nfsd4_decode_fattr(struct nfsd4_compound + goto xdr_error; + } + } ++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL ++ if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) { ++ uint32_t pi; ++ uint32_t lfs; ++ ++ READ_BUF(4); ++ len += 4; ++ READ32(lfs); ++ READ_BUF(4); ++ len += 4; ++ READ32(pi); ++ READ_BUF(4); ++ len += 4; ++ READ32(dummy32); ++ READ_BUF(dummy32); ++ len += (XDR_QUADLEN(dummy32) << 2); ++ READMEM(buf, dummy32); ++ ++ if (dummy32 > NFS4_MAXLABELLEN) ++ return nfserr_resource; ++ ++ *label = kzalloc(sizeof(struct nfs4_label), GFP_KERNEL); ++ if (*label == NULL) { ++ host_err = -ENOMEM; ++ goto out_nfserr; ++ } ++ ++ (*label)->label = kmalloc(dummy32 + 1, GFP_KERNEL); ++ if ((*label)->label == NULL) { ++ host_err = -ENOMEM; ++ kfree(*label); ++ goto out_nfserr; ++ } ++ ++ (*label)->len = dummy32; ++ memcpy((*label)->label, buf, dummy32); ++ ((char *)(*label)->label)[dummy32] = '\0'; ++ (*label)->pi = pi; ++ (*label)->lfs = lfs; ++ ++ defer_free(argp, kfree, (*label)->label); ++ defer_free(argp, kfree, *label); ++ } ++#endif + if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 + || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 + || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) +@@ -494,7 +544,7 @@ nfsd4_decode_create(struct nfsd4_compoun + return status; + + status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, +- &create->cr_acl); ++ &create->cr_acl, &create->cr_label); + if (status) + goto out; + +@@ -744,7 +794,7 @@ nfsd4_decode_open(struct nfsd4_compounda + case NFS4_CREATE_UNCHECKED: + case NFS4_CREATE_GUARDED: + status = nfsd4_decode_fattr(argp, open->op_bmval, +- &open->op_iattr, &open->op_acl); ++ &open->op_iattr, &open->op_acl, &open->op_label); + if (status) + goto out; + break; +@@ -758,7 +808,7 @@ nfsd4_decode_open(struct nfsd4_compounda + READ_BUF(NFS4_VERIFIER_SIZE); + COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); + status = nfsd4_decode_fattr(argp, open->op_bmval, +- &open->op_iattr, &open->op_acl); ++ &open->op_iattr, &open->op_acl, &open->op_label); + if (status) + goto out; + break; +@@ -981,7 +1031,7 @@ nfsd4_decode_setattr(struct nfsd4_compou + if (status) + return status; + return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, +- &setattr->sa_acl); ++ &setattr->sa_acl, &setattr->sa_label); + } + + static __be32 +@@ -1045,7 +1095,7 @@ nfsd4_decode_verify(struct nfsd4_compoun + * nfsd4_proc_verify; however we still decode here just to return + * correct error in case of bad xdr. */ + #if 0 +- status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl); ++ status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl, &ve_label); + if (status == nfserr_inval) { + status = nfserrno(status); + goto out; +@@ -1998,6 +2048,47 @@ nfsd4_encode_aclname(struct svc_rqst *rq + FATTR4_WORD0_RDATTR_ERROR) + #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID + ++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL ++ static inline __be32 ++nfsd4_encode_security_label(struct svc_rqst *rqstp, struct dentry *dentry, __be32 **pp, int *buflen) ++{ ++ void *context; ++ int err; ++ int len; ++ uint32_t pi = 0; ++ uint32_t lfs = 0; ++ __be32 *p = *pp; ++ ++ err = 0; ++ (void)security_inode_getsecctx(dentry->d_inode, &context, &len); ++ if (len < 0) ++ return nfserrno(len); ++ ++ if (*buflen < ((XDR_QUADLEN(len) << 2) + 4 + 4 + 4)) { ++ err = nfserr_resource; ++ goto out; ++ } ++ ++ /* XXX: A call to the translation code should be placed here ++ * for now send 0 until we have that to indicate the null ++ * translation */ ++ ++ if ((*buflen -= 4) < 0) ++ return nfserr_resource; ++ ++ WRITE32(lfs); ++ WRITE32(pi); ++ p = xdr_encode_opaque(p, context, len); ++ *buflen -= (XDR_QUADLEN(len) << 2) + 4; ++ BUG_ON(*buflen < 0); ++ ++ *pp = p; ++out: ++ security_release_secctx(context, len); ++ return err; ++} ++#endif ++ + static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) + { + /* As per referral draft: */ +@@ -2122,6 +2213,14 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s + + if (!aclsupport) + word0 &= ~FATTR4_WORD0_ACL; ++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL ++ if (exp->ex_flags & NFSEXP_SECURITY_LABEL) ++ word2 |= FATTR4_WORD2_SECURITY_LABEL; ++ else ++ word2 &= ~FATTR4_WORD2_SECURITY_LABEL; ++#else ++ word2 &= ~FATTR4_WORD2_SECURITY_LABEL; ++#endif + if (!word2) { + if ((buflen -= 12) < 0) + goto out_resource; +@@ -2444,6 +2543,16 @@ out_acl: + } + WRITE64(stat.ino); + } ++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL ++ if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { ++ status = nfsd4_encode_security_label(rqstp, dentry, ++ &p, &buflen); ++ if (status == nfserr_resource) ++ goto out_resource; ++ if (status) ++ goto out; ++ } ++#endif + if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { + WRITE32(3); + WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0); +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/nfsd.h.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/nfsd.h +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/nfsd.h.orig 2012-11-29 16:37:14.081901803 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/nfsd.h 2012-12-03 10:53:55.673785401 -0500 +@@ -322,10 +322,10 @@ extern time_t nfsd4_grace; + | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP | FATTR4_WORD1_RAWDEV \ + | FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL \ + | FATTR4_WORD1_SPACE_USED | FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_ACCESS_SET \ +- | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA \ +- | FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID) ++ | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY \ ++ | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID) + +-#define NFSD4_SUPPORTED_ATTRS_WORD2 0 ++#define NFSD4_SUPPORTED_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL + + #define NFSD4_1_SUPPORTED_ATTRS_WORD0 \ + NFSD4_SUPPORTED_ATTRS_WORD0 +@@ -364,7 +364,7 @@ static inline u32 nfsd_suppattrs2(u32 mi + #define NFSD_WRITEABLE_ATTRS_WORD1 \ + (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ + | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) +-#define NFSD_WRITEABLE_ATTRS_WORD2 0 ++#define NFSD_WRITEABLE_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL + + #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \ + NFSD_WRITEABLE_ATTRS_WORD0 +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/vfs.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/vfs.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/vfs.c.orig 2012-11-29 16:37:14.133901832 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/vfs.c 2012-12-03 10:53:55.674785401 -0500 +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #ifdef CONFIG_NFSD_V3 + #include "xdr3.h" +@@ -621,6 +622,36 @@ int nfsd4_is_junction(struct dentry *den + return 0; + return 1; + } ++ ++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL ++__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, ++ struct nfs4_label *label) ++{ ++ __be32 error; ++ int host_error; ++ struct dentry *dentry; ++ ++ /* Get inode */ ++ /* XXX: should we have a MAY_SSECCTX? */ ++ error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR); ++ if (error) ++ return error; ++ ++ dentry = fhp->fh_dentry; ++ ++ mutex_lock(&dentry->d_inode->i_mutex); ++ host_error = security_inode_setsecctx(dentry, label->label, label->len); ++ mutex_unlock(&dentry->d_inode->i_mutex); ++ return nfserrno(host_error); ++} ++#else ++__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, ++ struct nfs4_label *label) ++{ ++ return -EOPNOTSUPP; ++} ++#endif ++ + #endif /* defined(CONFIG_NFSD_V4) */ + + #ifdef CONFIG_NFSD_V3 +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/vfs.h.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/vfs.h +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/vfs.h.orig 2012-09-30 19:47:46.000000000 -0400 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/vfs.h 2012-12-03 10:53:55.674785401 -0500 +@@ -55,6 +55,8 @@ int nfsd_mountpoint(struct dentry *, str + __be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *, + struct nfs4_acl *); + int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **); ++__be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *, ++ struct nfs4_label *); + #endif /* CONFIG_NFSD_V4 */ + __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, + char *name, int len, struct iattr *attrs, +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/xdr4.h.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/xdr4.h +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/xdr4.h.orig 2012-09-30 19:47:46.000000000 -0400 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfsd/xdr4.h 2012-12-03 10:53:55.675785402 -0500 +@@ -118,6 +118,7 @@ struct nfsd4_create { + struct iattr cr_iattr; /* request */ + struct nfsd4_change_info cr_cinfo; /* response */ + struct nfs4_acl *cr_acl; ++ struct nfs4_label *cr_label; + }; + #define cr_linklen u.link.namelen + #define cr_linkname u.link.name +@@ -246,6 +247,7 @@ struct nfsd4_open { + struct nfs4_file *op_file; /* used during processing */ + struct nfs4_ol_stateid *op_stp; /* used during processing */ + struct nfs4_acl *op_acl; ++ struct nfs4_label *op_label; + }; + #define op_iattr iattr + +@@ -330,6 +332,7 @@ struct nfsd4_setattr { + u32 sa_bmval[3]; /* request */ + struct iattr sa_iattr; /* request */ + struct nfs4_acl *sa_acl; ++ struct nfs4_label *sa_label; + }; + + struct nfsd4_setclientid { +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/getroot.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/getroot.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/getroot.c.orig 2012-11-29 16:37:13.711901517 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/getroot.c 2012-12-03 10:53:55.653785381 -0500 +@@ -95,7 +95,7 @@ struct dentry *nfs_get_root(struct super + goto out; + } + +- inode = nfs_fhget(sb, mntfh, fsinfo.fattr); ++ inode = nfs_fhget(sb, mntfh, fsinfo.fattr, NULL); + if (IS_ERR(inode)) { + dprintk("nfs_get_root: get root inode failed\n"); + ret = ERR_CAST(inode); +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/inode.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/inode.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/inode.c.orig 2012-11-29 16:37:13.728901534 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/inode.c 2012-12-03 10:53:55.655785383 -0500 +@@ -61,7 +61,7 @@ + static bool enable_ino64 = NFS_64_BIT_INODE_NUMBERS_ENABLED; + + static void nfs_invalidate_inode(struct inode *); +-static int nfs_update_inode(struct inode *, struct nfs_fattr *); ++static int nfs_update_inode(struct inode *, struct nfs_fattr *, struct nfs4_label *); + + static struct kmem_cache * nfs_inode_cachep; + +@@ -156,9 +156,18 @@ static void nfs_zap_caches_locked(struct + + memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf)); + if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) +- nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; ++ nfsi->cache_validity |= NFS_INO_INVALID_ATTR ++ | NFS_INO_INVALID_LABEL ++ | NFS_INO_INVALID_DATA ++ | NFS_INO_INVALID_ACCESS ++ | NFS_INO_INVALID_ACL ++ | NFS_INO_REVAL_PAGECACHE; + else +- nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; ++ nfsi->cache_validity |= NFS_INO_INVALID_ATTR ++ | NFS_INO_INVALID_LABEL ++ | NFS_INO_INVALID_ACCESS ++ | NFS_INO_INVALID_ACL ++ | NFS_INO_REVAL_PAGECACHE; + } + + void nfs_zap_caches(struct inode *inode) +@@ -246,12 +255,77 @@ nfs_init_locked(struct inode *inode, voi + return 0; + } + ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, ++ struct nfs4_label *label) ++{ ++ int error; ++ ++ if ((fattr->valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL) && ++ label && inode->i_security) { ++ error = security_inode_notifysecctx(inode, label->label, ++ label->len); ++ if (error) ++ printk(KERN_ERR "%s() %s %d " ++ "security_inode_notifysecctx() %d\n", ++ __func__, ++ (char *)label->label, ++ label->len, error); ++ } ++} ++ ++struct nfs4_label *nfs4_label_alloc(gfp_t flags) ++{ ++ struct nfs4_label *label = NULL; ++ ++ label = kzalloc(sizeof(struct nfs4_label) + NFS4_MAXLABELLEN, flags); ++ if (label == NULL) ++ return NULL; ++ ++ label->label = (void *)(label + 1); ++ label->len = NFS4_MAXLABELLEN; ++ /* 0 is the null format meaning that the data is not to be translated */ ++ label->lfs = 0; ++ label->pi = 0; ++ return label; ++} ++EXPORT_SYMBOL_GPL(nfs4_label_alloc); ++ ++void nfs4_label_init(struct nfs4_label *label) ++{ ++ if (label && label->label) { ++ *(unsigned char *)label->label = 0; ++ label->len = NFS4_MAXLABELLEN; ++ /* 0 is the null format meaning that the data is not ++ to be translated */ ++ label->lfs = 0; ++ label->pi = 0; ++ } ++ return; ++} ++EXPORT_SYMBOL_GPL(nfs4_label_init); ++ ++void nfs4_label_free(struct nfs4_label *label) ++{ ++ kfree(label); ++ return; ++} ++EXPORT_SYMBOL_GPL(nfs4_label_free); ++ ++#else ++void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, ++ struct nfs4_label *label) ++{ ++} ++#endif ++EXPORT_SYMBOL_GPL(nfs_setsecurity); ++ + /* + * This is our front-end to iget that looks up inodes by file handle + * instead of inode number. + */ + struct inode * +-nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) ++nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, struct nfs4_label *label) + { + struct nfs_find_desc desc = { + .fh = fh, +@@ -373,6 +447,9 @@ nfs_fhget(struct super_block *sb, struct + */ + inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); + } ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ nfs_setsecurity(inode, fattr, label); ++#endif + nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); + nfsi->attrtimeo_timestamp = now; + nfsi->access_cache = RB_ROOT; +@@ -381,7 +458,7 @@ nfs_fhget(struct super_block *sb, struct + + unlock_new_inode(inode); + } else +- nfs_refresh_inode(inode, fattr); ++ nfs_refresh_inode(inode, fattr, label); + dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n", + inode->i_sb->s_id, + (long long)NFS_FILEID(inode), +@@ -438,7 +515,7 @@ nfs_setattr(struct dentry *dentry, struc + NFS_PROTO(inode)->return_delegation(inode); + error = NFS_PROTO(inode)->setattr(dentry, fattr, attr); + if (error == 0) +- nfs_refresh_inode(inode, fattr); ++ nfs_refresh_inode(inode, fattr, NULL); + nfs_free_fattr(fattr); + out: + return error; +@@ -735,6 +812,7 @@ struct nfs_open_context *nfs_find_open_c + spin_unlock(&inode->i_lock); + return ctx; + } ++EXPORT_SYMBOL_GPL(nfs_find_open_context); + + static void nfs_file_clear_open_context(struct file *filp) + { +@@ -780,6 +858,7 @@ int + __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) + { + int status = -ESTALE; ++ struct nfs4_label *label = NULL; + struct nfs_fattr *fattr = NULL; + struct nfs_inode *nfsi = NFS_I(inode); + +@@ -797,7 +876,16 @@ __nfs_revalidate_inode(struct nfs_server + goto out; + + nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); +- status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr); ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) { ++ label = nfs4_label_alloc(GFP_KERNEL); ++ if (label == NULL) { ++ status = -ENOMEM; ++ goto out; ++ } ++ } ++#endif ++ status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr, label); + if (status != 0) { + dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n", + inode->i_sb->s_id, +@@ -810,7 +898,7 @@ __nfs_revalidate_inode(struct nfs_server + goto out; + } + +- status = nfs_refresh_inode(inode, fattr); ++ status = nfs_refresh_inode(inode, fattr, label); + if (status) { + dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n", + inode->i_sb->s_id, +@@ -826,6 +914,10 @@ __nfs_revalidate_inode(struct nfs_server + (long long)NFS_FILEID(inode)); + + out: ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) ++ nfs4_label_free(label); ++#endif + nfs_free_fattr(fattr); + return status; + } +@@ -853,7 +945,8 @@ static int nfs_attribute_cache_expired(s + */ + int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) + { +- if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATTR) ++ if (!(NFS_I(inode)->cache_validity & ++ (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) + && !nfs_attribute_cache_expired(inode)) + return NFS_STALE(inode) ? -ESTALE : 0; + return __nfs_revalidate_inode(server, inode); +@@ -1163,10 +1256,10 @@ static int nfs_inode_attrs_need_update(c + ((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0); + } + +-static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr) ++static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label) + { + if (nfs_inode_attrs_need_update(inode, fattr)) +- return nfs_update_inode(inode, fattr); ++ return nfs_update_inode(inode, fattr, label); + return nfs_check_inode_attributes(inode, fattr); + } + +@@ -1180,21 +1273,21 @@ static int nfs_refresh_inode_locked(stru + * safe to do a full update of the inode attributes, or whether just to + * call nfs_check_inode_attributes. + */ +-int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) ++int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label) + { + int status; + + if ((fattr->valid & NFS_ATTR_FATTR) == 0) + return 0; + spin_lock(&inode->i_lock); +- status = nfs_refresh_inode_locked(inode, fattr); ++ status = nfs_refresh_inode_locked(inode, fattr, label); + spin_unlock(&inode->i_lock); + + return status; + } + EXPORT_SYMBOL_GPL(nfs_refresh_inode); + +-static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr) ++static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label) + { + struct nfs_inode *nfsi = NFS_I(inode); + +@@ -1203,7 +1296,7 @@ static int nfs_post_op_update_inode_lock + nfsi->cache_validity |= NFS_INO_INVALID_DATA; + if ((fattr->valid & NFS_ATTR_FATTR) == 0) + return 0; +- return nfs_refresh_inode_locked(inode, fattr); ++ return nfs_refresh_inode_locked(inode, fattr, label); + } + + /** +@@ -1220,12 +1313,12 @@ static int nfs_post_op_update_inode_lock + * are expected to change one or more attributes, to avoid + * unnecessary NFS requests and trips through nfs_update_inode(). + */ +-int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr) ++int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label) + { + int status; + + spin_lock(&inode->i_lock); +- status = nfs_post_op_update_inode_locked(inode, fattr); ++ status = nfs_post_op_update_inode_locked(inode, fattr, label); + spin_unlock(&inode->i_lock); + return status; + } +@@ -1277,7 +1370,7 @@ int nfs_post_op_update_inode_force_wcc(s + fattr->valid |= NFS_ATTR_FATTR_PRESIZE; + } + out_noforce: +- status = nfs_post_op_update_inode_locked(inode, fattr); ++ status = nfs_post_op_update_inode_locked(inode, fattr, NULL); + spin_unlock(&inode->i_lock); + return status; + } +@@ -1295,7 +1388,7 @@ EXPORT_SYMBOL_GPL(nfs_post_op_update_ino + * + * A very similar scenario holds for the dir cache. + */ +-static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ++static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label) + { + struct nfs_server *server; + struct nfs_inode *nfsi = NFS_I(inode); +@@ -1446,6 +1539,10 @@ static int nfs_update_inode(struct inode + | NFS_INO_INVALID_ACL + | NFS_INO_REVAL_FORCED); + ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (label) ++ nfs_setsecurity(inode, fattr, label); ++#endif + if (fattr->valid & NFS_ATTR_FATTR_NLINK) { + if (inode->i_nlink != fattr->nlink) { + invalid |= NFS_INO_INVALID_ATTR; +@@ -1467,7 +1564,7 @@ static int nfs_update_inode(struct inode + inode->i_blocks = fattr->du.nfs2.blocks; + + /* Update attrtimeo value if we're out of the unstable period */ +- if (invalid & NFS_INO_INVALID_ATTR) { ++ if (invalid & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) { + nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); + nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); + nfsi->attrtimeo_timestamp = now; +@@ -1480,6 +1577,7 @@ static int nfs_update_inode(struct inode + } + } + invalid &= ~NFS_INO_INVALID_ATTR; ++ invalid &= ~NFS_INO_INVALID_LABEL; + /* Don't invalidate the data if we were to blame */ + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) + || S_ISLNK(inode->i_mode))) +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/Kconfig.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/Kconfig +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/Kconfig.orig 2012-11-29 16:37:13.607901430 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/Kconfig 2012-12-03 10:53:55.645785378 -0500 +@@ -131,6 +131,22 @@ config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN + If the NFS client is unchanged from the upstream kernel, this + option should be set to the default "kernel.org". + ++config NFS_V4_SECURITY_LABEL ++ bool "Provide Security Label support for NFSv4 client" ++ depends on NFS_V4 && SECURITY ++ help ++ ++ Say Y here if you want enable fine-grained security label attribute ++ support for NFS version 4. Security labels allow security modules like ++ SELinux and Smack to label files to facilitate enforcement of their policies. ++ Without this an NFSv4 mount will have the same label on each file. ++ ++ If you do not wish to enable fine-grained security labels SELinux or ++ Smack policies on NFSv4 files, say N. ++ ++ ++ If unsure, say N. ++ + config ROOT_NFS + bool "Root file system on NFS" + depends on NFS_FS=y && IP_PNP +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/namespace.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/namespace.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/namespace.c.orig 2012-11-29 16:37:13.751901554 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/namespace.c 2012-12-03 10:53:55.656785384 -0500 +@@ -260,7 +260,7 @@ struct vfsmount *nfs_submount(struct nfs + struct dentry *parent = dget_parent(dentry); + + /* Look it up again to get its attributes */ +- err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &dentry->d_name, fh, fattr); ++ err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &dentry->d_name, fh, fattr, NULL); + dput(parent); + if (err != 0) + return ERR_PTR(err); +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs3acl.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs3acl.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs3acl.c.orig 2012-11-29 16:37:13.794901580 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs3acl.c 2012-12-03 10:53:55.656785384 -0500 +@@ -240,7 +240,7 @@ struct posix_acl *nfs3_proc_getacl(struc + + switch (status) { + case 0: +- status = nfs_refresh_inode(inode, res.fattr); ++ status = nfs_refresh_inode(inode, res.fattr, NULL); + break; + case -EPFNOSUPPORT: + case -EPROTONOSUPPORT: +@@ -352,7 +352,7 @@ static int nfs3_proc_setacls(struct inod + + switch (status) { + case 0: +- status = nfs_refresh_inode(inode, fattr); ++ status = nfs_refresh_inode(inode, fattr, NULL); + nfs3_cache_acls(inode, acl, dfacl); + break; + case -EPFNOSUPPORT: +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs3proc.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs3proc.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs3proc.c.orig 2012-09-30 19:47:46.000000000 -0400 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs3proc.c 2012-12-03 10:53:55.657785385 -0500 +@@ -98,7 +98,7 @@ nfs3_proc_get_root(struct nfs_server *se + */ + static int + nfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, +- struct nfs_fattr *fattr) ++ struct nfs_fattr *fattr, struct nfs4_label *label) + { + struct rpc_message msg = { + .rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR], +@@ -143,7 +143,8 @@ nfs3_proc_setattr(struct dentry *dentry, + + static int + nfs3_proc_lookup(struct inode *dir, struct qstr *name, +- struct nfs_fh *fhandle, struct nfs_fattr *fattr) ++ struct nfs_fh *fhandle, struct nfs_fattr *fattr, ++ struct nfs4_label *label) + { + struct nfs3_diropargs arg = { + .fh = NFS_FH(dir), +@@ -168,7 +169,7 @@ nfs3_proc_lookup(struct inode *dir, stru + + nfs_fattr_init(fattr); + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); +- nfs_refresh_inode(dir, res.dir_attr); ++ nfs_refresh_inode(dir, res.dir_attr, NULL); + if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) { + msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; + msg.rpc_argp = fhandle; +@@ -216,7 +217,7 @@ static int nfs3_proc_access(struct inode + goto out; + + status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); +- nfs_refresh_inode(inode, res.fattr); ++ nfs_refresh_inode(inode, res.fattr, NULL); + if (status == 0) { + entry->mask = 0; + if (res.access & NFS3_ACCESS_READ) +@@ -255,7 +256,7 @@ static int nfs3_proc_readlink(struct ino + msg.rpc_resp = fattr; + + status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); +- nfs_refresh_inode(inode, fattr); ++ nfs_refresh_inode(inode, fattr, NULL); + nfs_free_fattr(fattr); + out: + dprintk("NFS reply readlink: %d\n", status); +@@ -298,9 +299,9 @@ static int nfs3_do_create(struct inode * + int status; + + status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0); +- nfs_post_op_update_inode(dir, data->res.dir_attr); ++ nfs_post_op_update_inode(dir, data->res.dir_attr, NULL); + if (status == 0) +- status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); ++ status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL); + return status; + } + +@@ -381,7 +382,7 @@ nfs3_proc_create(struct inode *dir, stru + * not sure this buys us anything (and I'd have + * to revamp the NFSv3 XDR code) */ + status = nfs3_proc_setattr(dentry, data->res.fattr, sattr); +- nfs_post_op_update_inode(dentry->d_inode, data->res.fattr); ++ nfs_post_op_update_inode(dentry->d_inode, data->res.fattr, NULL); + dprintk("NFS reply setattr (post-create): %d\n", status); + if (status != 0) + goto out; +@@ -414,7 +415,7 @@ nfs3_proc_remove(struct inode *dir, stru + goto out; + + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); +- nfs_post_op_update_inode(dir, res.dir_attr); ++ nfs_post_op_update_inode(dir, res.dir_attr, NULL); + nfs_free_fattr(res.dir_attr); + out: + dprintk("NFS reply remove: %d\n", status); +@@ -439,7 +440,7 @@ nfs3_proc_unlink_done(struct rpc_task *t + if (nfs3_async_handle_jukebox(task, dir)) + return 0; + res = task->tk_msg.rpc_resp; +- nfs_post_op_update_inode(dir, res->dir_attr); ++ nfs_post_op_update_inode(dir, res->dir_attr, NULL); + return 1; + } + +@@ -464,8 +465,8 @@ nfs3_proc_rename_done(struct rpc_task *t + return 0; + res = task->tk_msg.rpc_resp; + +- nfs_post_op_update_inode(old_dir, res->old_fattr); +- nfs_post_op_update_inode(new_dir, res->new_fattr); ++ nfs_post_op_update_inode(old_dir, res->old_fattr, NULL); ++ nfs_post_op_update_inode(new_dir, res->new_fattr, NULL); + return 1; + } + +@@ -495,8 +496,8 @@ nfs3_proc_rename(struct inode *old_dir, + goto out; + + status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); +- nfs_post_op_update_inode(old_dir, res.old_fattr); +- nfs_post_op_update_inode(new_dir, res.new_fattr); ++ nfs_post_op_update_inode(old_dir, res.old_fattr, NULL); ++ nfs_post_op_update_inode(new_dir, res.new_fattr, NULL); + out: + nfs_free_fattr(res.old_fattr); + nfs_free_fattr(res.new_fattr); +@@ -528,8 +529,8 @@ nfs3_proc_link(struct inode *inode, stru + goto out; + + status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); +- nfs_post_op_update_inode(dir, res.dir_attr); +- nfs_post_op_update_inode(inode, res.fattr); ++ nfs_post_op_update_inode(dir, res.dir_attr, NULL); ++ nfs_post_op_update_inode(inode, res.fattr, NULL); + out: + nfs_free_fattr(res.dir_attr); + nfs_free_fattr(res.fattr); +@@ -622,7 +623,7 @@ nfs3_proc_rmdir(struct inode *dir, struc + + msg.rpc_resp = dir_attr; + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); +- nfs_post_op_update_inode(dir, dir_attr); ++ nfs_post_op_update_inode(dir, dir_attr, NULL); + nfs_free_fattr(dir_attr); + out: + dprintk("NFS reply rmdir: %d\n", status); +@@ -677,7 +678,7 @@ nfs3_proc_readdir(struct dentry *dentry, + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + + nfs_invalidate_atime(dir); +- nfs_refresh_inode(dir, res.dir_attr); ++ nfs_refresh_inode(dir, res.dir_attr, NULL); + + nfs_free_fattr(res.dir_attr); + out: +@@ -816,7 +817,7 @@ static int nfs3_read_done(struct rpc_tas + return -EAGAIN; + + nfs_invalidate_atime(inode); +- nfs_refresh_inode(inode, &data->fattr); ++ nfs_refresh_inode(inode, &data->fattr, NULL); + return 0; + } + +@@ -860,7 +861,7 @@ static int nfs3_commit_done(struct rpc_t + { + if (nfs3_async_handle_jukebox(task, data->inode)) + return -EAGAIN; +- nfs_refresh_inode(data->inode, data->res.fattr); ++ nfs_refresh_inode(data->inode, data->res.fattr, NULL); + return 0; + } + +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs4_fs.h.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs4_fs.h +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs4_fs.h.orig 2012-11-29 16:37:13.802901578 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs4_fs.h 2012-12-03 10:53:55.658785386 -0500 +@@ -230,7 +230,7 @@ extern int nfs4_server_capabilities(stru + extern int nfs4_proc_fs_locations(struct rpc_clnt *, struct inode *, const struct qstr *, + struct nfs4_fs_locations *, struct page *); + extern struct rpc_clnt *nfs4_proc_lookup_mountpoint(struct inode *, struct qstr *, +- struct nfs_fh *, struct nfs_fattr *); ++ struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *); + extern int nfs4_proc_secinfo(struct inode *, const struct qstr *, struct nfs4_secinfo_flavors *); + extern int nfs4_release_lockowner(struct nfs4_lock_state *); + extern const struct xattr_handler *nfs4_xattr_handlers[]; +@@ -304,10 +304,10 @@ is_ds_client(struct nfs_client *clp) + extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[]; + + extern const u32 nfs4_fattr_bitmap[3]; +-extern const u32 nfs4_statfs_bitmap[2]; +-extern const u32 nfs4_pathconf_bitmap[2]; ++extern const u32 nfs4_statfs_bitmap[3]; ++extern const u32 nfs4_pathconf_bitmap[3]; + extern const u32 nfs4_fsinfo_bitmap[3]; +-extern const u32 nfs4_fs_locations_bitmap[2]; ++extern const u32 nfs4_fs_locations_bitmap[3]; + + void nfs4_free_client(struct nfs_client *); + +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs4namespace.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs4namespace.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs4namespace.c.orig 2012-11-29 16:37:13.858901623 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs4namespace.c 2012-12-03 10:53:55.658785386 -0500 +@@ -368,7 +368,7 @@ struct vfsmount *nfs4_submount(struct nf + struct vfsmount *mnt; + + /* Look it up again to get its attributes and sec flavor */ +- client = nfs4_proc_lookup_mountpoint(parent->d_inode, &dentry->d_name, fh, fattr); ++ client = nfs4_proc_lookup_mountpoint(parent->d_inode, &dentry->d_name, fh, fattr, NULL); + dput(parent); + if (IS_ERR(client)) + return ERR_CAST(client); +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs4proc.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs4proc.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs4proc.c.orig 2012-11-29 16:37:13.869901632 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs4proc.c 2012-12-03 10:53:55.664785392 -0500 +@@ -78,11 +78,12 @@ static int _nfs4_recover_proc_open(struc + static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); + static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); + static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr); +-static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *); +-static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr); ++static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *label); ++static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label); + static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, + struct nfs_fattr *fattr, struct iattr *sattr, +- struct nfs4_state *state); ++ struct nfs4_state *state, struct nfs4_label *ilabel, ++ struct nfs4_label *olabel); + #ifdef CONFIG_NFS_V4_1 + static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *); + static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *); +@@ -131,7 +132,12 @@ const u32 nfs4_fattr_bitmap[3] = { + | FATTR4_WORD1_SPACE_USED + | FATTR4_WORD1_TIME_ACCESS + | FATTR4_WORD1_TIME_METADATA +- | FATTR4_WORD1_TIME_MODIFY ++ | FATTR4_WORD1_TIME_MODIFY, ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ FATTR4_WORD2_SECURITY_LABEL ++#else ++ 0 ++#endif + }; + + static const u32 nfs4_pnfs_open_bitmap[3] = { +@@ -158,18 +164,20 @@ static const u32 nfs4_open_noattr_bitmap + | FATTR4_WORD0_FILEID, + }; + +-const u32 nfs4_statfs_bitmap[2] = { ++const u32 nfs4_statfs_bitmap[3] = { + FATTR4_WORD0_FILES_AVAIL + | FATTR4_WORD0_FILES_FREE + | FATTR4_WORD0_FILES_TOTAL, + FATTR4_WORD1_SPACE_AVAIL + | FATTR4_WORD1_SPACE_FREE +- | FATTR4_WORD1_SPACE_TOTAL ++ | FATTR4_WORD1_SPACE_TOTAL, ++ 0 + }; + +-const u32 nfs4_pathconf_bitmap[2] = { ++const u32 nfs4_pathconf_bitmap[3] = { + FATTR4_WORD0_MAXLINK + | FATTR4_WORD0_MAXNAME, ++ 0, + 0 + }; + +@@ -182,7 +190,7 @@ const u32 nfs4_fsinfo_bitmap[3] = { FATT + FATTR4_WORD2_LAYOUT_BLKSIZE + }; + +-const u32 nfs4_fs_locations_bitmap[2] = { ++const u32 nfs4_fs_locations_bitmap[3] = { + FATTR4_WORD0_TYPE + | FATTR4_WORD0_CHANGE + | FATTR4_WORD0_SIZE +@@ -198,7 +206,8 @@ const u32 nfs4_fs_locations_bitmap[2] = + | FATTR4_WORD1_TIME_ACCESS + | FATTR4_WORD1_TIME_METADATA + | FATTR4_WORD1_TIME_MODIFY +- | FATTR4_WORD1_MOUNTED_ON_FILEID ++ | FATTR4_WORD1_MOUNTED_ON_FILEID, ++ 0 + }; + + static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry, +@@ -821,6 +830,7 @@ struct nfs4_opendata { + struct nfs4_string owner_name; + struct nfs4_string group_name; + struct nfs_fattr f_attr; ++ struct nfs4_label *f_label; + struct dentry *dir; + struct dentry *dentry; + struct nfs4_state_owner *owner; +@@ -836,6 +846,7 @@ struct nfs4_opendata { + static void nfs4_init_opendata_res(struct nfs4_opendata *p) + { + p->o_res.f_attr = &p->f_attr; ++ p->o_res.f_label = p->f_label; + p->o_res.seqid = p->o_arg.seqid; + p->c_res.seqid = p->c_arg.seqid; + p->o_res.server = p->o_arg.server; +@@ -846,7 +857,7 @@ static void nfs4_init_opendata_res(struc + + static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, + struct nfs4_state_owner *sp, fmode_t fmode, int flags, +- const struct iattr *attrs, ++ const struct iattr *attrs, struct nfs4_label *label, + gfp_t gfp_mask) + { + struct dentry *parent = dget_parent(dentry); +@@ -857,9 +868,16 @@ static struct nfs4_opendata *nfs4_openda + p = kzalloc(sizeof(*p), gfp_mask); + if (p == NULL) + goto err; ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (server->caps & NFS_CAP_SECURITY_LABEL) { ++ p->f_label = nfs4_label_alloc(gfp_mask); ++ if (p->f_label == NULL) ++ goto err_free_p; ++ } ++#endif + p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask); + if (p->o_arg.seqid == NULL) +- goto err_free; ++ goto err_free_label; + nfs_sb_active(dentry->d_sb); + p->dentry = dget(dentry); + p->dir = parent; +@@ -884,6 +902,7 @@ static struct nfs4_opendata *nfs4_openda + p->o_arg.bitmask = server->attr_bitmask; + p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0]; + p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; ++ p->o_arg.label = label; + if (attrs != NULL && attrs->ia_valid != 0) { + __be32 verf[2]; + +@@ -901,7 +920,13 @@ static struct nfs4_opendata *nfs4_openda + nfs4_init_opendata_res(p); + kref_init(&p->kref); + return p; +-err_free: ++ ++err_free_label: ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (server->caps & NFS_CAP_SECURITY_LABEL) ++ nfs4_label_free(p->f_label); ++#endif ++err_free_p: + kfree(p); + err: + dput(parent); +@@ -918,6 +943,10 @@ static void nfs4_opendata_free(struct kr + if (p->state != NULL) + nfs4_put_open_state(p->state); + nfs4_put_state_owner(p->owner); ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (p->o_arg.server->caps & NFS_CAP_SECURITY_LABEL) ++ nfs4_label_free(p->f_label); ++#endif + dput(p->dir); + dput(p->dentry); + nfs_sb_deactive(sb); +@@ -1185,7 +1214,7 @@ _nfs4_opendata_reclaim_to_nfs4_state(str + if (state == NULL) + goto err; + +- ret = nfs_refresh_inode(inode, &data->f_attr); ++ ret = nfs_refresh_inode(inode, &data->f_attr, data->f_label); + if (ret) + goto err; + +@@ -1215,7 +1244,7 @@ _nfs4_opendata_to_nfs4_state(struct nfs4 + ret = -EAGAIN; + if (!(data->f_attr.valid & NFS_ATTR_FATTR)) + goto err; +- inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr); ++ inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr, data->f_label); + ret = PTR_ERR(inode); + if (IS_ERR(inode)) + goto err; +@@ -1265,7 +1294,7 @@ static struct nfs4_opendata *nfs4_open_r + { + struct nfs4_opendata *opendata; + +- opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0, NULL, GFP_NOFS); ++ opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0, NULL, NULL, GFP_NOFS); + if (opendata == NULL) + return ERR_PTR(-ENOMEM); + opendata->state = state; +@@ -1785,7 +1814,7 @@ static int _nfs4_proc_open(struct nfs4_o + return status; + } + if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) +- _nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr); ++ _nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr, o_res->f_label); + return 0; + } + +@@ -1962,6 +1991,7 @@ static int _nfs4_do_open(struct inode *d + fmode_t fmode, + int flags, + struct iattr *sattr, ++ struct nfs4_label *label, + struct rpc_cred *cred, + struct nfs4_state **res, + struct nfs4_threshold **ctx_th) +@@ -1970,6 +2000,7 @@ static int _nfs4_do_open(struct inode *d + struct nfs4_state *state = NULL; + struct nfs_server *server = NFS_SERVER(dir); + struct nfs4_opendata *opendata; ++ struct nfs4_label *olabel = NULL; + int status; + + /* Protect against reboot recovery conflicts */ +@@ -1985,10 +2016,20 @@ static int _nfs4_do_open(struct inode *d + if (dentry->d_inode != NULL) + nfs4_return_incompatible_delegation(dentry->d_inode, fmode); + status = -ENOMEM; +- opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr, GFP_KERNEL); ++ opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr, label, GFP_KERNEL); + if (opendata == NULL) + goto err_put_state_owner; + ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (label && nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) { ++ olabel = nfs4_label_alloc(GFP_KERNEL); ++ if (olabel == NULL) { ++ status = -ENOMEM; ++ goto err_opendata_put; ++ } ++ } ++#endif ++ + if (ctx_th && server->attr_bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD) { + opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc(); + if (!opendata->f_attr.mdsthreshold) +@@ -2019,10 +2060,12 @@ static int _nfs4_do_open(struct inode *d + nfs_fattr_init(opendata->o_res.f_attr); + status = nfs4_do_setattr(state->inode, cred, + opendata->o_res.f_attr, sattr, +- state); +- if (status == 0) ++ state, label, olabel); ++ if (status == 0) { + nfs_setattr_update_inode(state->inode, sattr); +- nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr); ++ nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr, olabel); ++ nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel); ++ } + } + + if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server)) +@@ -2031,6 +2074,10 @@ static int _nfs4_do_open(struct inode *d + kfree(opendata->f_attr.mdsthreshold); + opendata->f_attr.mdsthreshold = NULL; + ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) ++ nfs4_label_free(olabel); ++#endif + nfs4_opendata_put(opendata); + nfs4_put_state_owner(sp); + *res = state; +@@ -2051,6 +2098,7 @@ static struct nfs4_state *nfs4_do_open(s + fmode_t fmode, + int flags, + struct iattr *sattr, ++ struct nfs4_label *label, + struct rpc_cred *cred, + struct nfs4_threshold **ctx_th) + { +@@ -2060,7 +2108,7 @@ static struct nfs4_state *nfs4_do_open(s + + fmode &= FMODE_READ|FMODE_WRITE|FMODE_EXEC; + do { +- status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, cred, ++ status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, label, cred, + &res, ctx_th); + if (status == 0) + break; +@@ -2105,7 +2153,8 @@ static struct nfs4_state *nfs4_do_open(s + + static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, + struct nfs_fattr *fattr, struct iattr *sattr, +- struct nfs4_state *state) ++ struct nfs4_state *state, struct nfs4_label *ilabel, ++ struct nfs4_label *olabel) + { + struct nfs_server *server = NFS_SERVER(inode); + struct nfs_setattrargs arg = { +@@ -2113,9 +2162,11 @@ static int _nfs4_do_setattr(struct inode + .iap = sattr, + .server = server, + .bitmask = server->attr_bitmask, ++ .label = ilabel, + }; + struct nfs_setattrres res = { + .fattr = fattr, ++ .label = olabel, + .server = server, + }; + struct rpc_message msg = { +@@ -2127,6 +2178,10 @@ static int _nfs4_do_setattr(struct inode + unsigned long timestamp = jiffies; + int status; + ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (ilabel == NULL || olabel == NULL) ++ arg.bitmask = server->attr_bitmask_nl; ++#endif + nfs_fattr_init(fattr); + + if (state != NULL) { +@@ -2150,7 +2205,8 @@ static int _nfs4_do_setattr(struct inode + + static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, + struct nfs_fattr *fattr, struct iattr *sattr, +- struct nfs4_state *state) ++ struct nfs4_state *state, struct nfs4_label *ilabel, ++ struct nfs4_label *olabel) + { + struct nfs_server *server = NFS_SERVER(inode); + struct nfs4_exception exception = { +@@ -2159,7 +2215,7 @@ static int nfs4_do_setattr(struct inode + }; + int err; + do { +- err = _nfs4_do_setattr(inode, cred, fattr, sattr, state); ++ err = _nfs4_do_setattr(inode, cred, fattr, sattr, state, ilabel, olabel); + switch (err) { + case -NFS4ERR_OPENMODE: + if (state && !(state->state & FMODE_WRITE)) { +@@ -2246,7 +2302,7 @@ static void nfs4_close_done(struct rpc_t + rpc_restart_call_prepare(task); + } + nfs_release_seqid(calldata->arg.seqid); +- nfs_refresh_inode(calldata->inode, calldata->res.fattr); ++ nfs_refresh_inode(calldata->inode, calldata->res.fattr, NULL); + dprintk("%s: done, ret = %d!\n", __func__, task->tk_status); + } + +@@ -2354,7 +2410,7 @@ int nfs4_do_close(struct nfs4_state *sta + if (calldata->arg.seqid == NULL) + goto out_free_calldata; + calldata->arg.fmode = 0; +- calldata->arg.bitmask = server->cache_consistency_bitmask; ++ calldata->arg.bitmask = server->cache_consistency_bitmask_nl; + calldata->res.fattr = &calldata->fattr; + calldata->res.seqid = calldata->arg.seqid; + calldata->res.server = server; +@@ -2384,10 +2440,26 @@ static struct inode * + nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr) + { + struct nfs4_state *state; ++ struct nfs4_label l, *label = NULL; ++ ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) { ++ struct dentry *dentry = ctx->dentry; ++ int error; ++ error = security_dentry_init_security(dentry, attr->ia_mode, ++ &dentry->d_name, &l.label, &l.len); ++ if (error == 0) ++ label = &l; ++ } ++#endif + + /* Protect against concurrent sillydeletes */ +- state = nfs4_do_open(dir, ctx->dentry, ctx->mode, open_flags, attr, ++ state = nfs4_do_open(dir, ctx->dentry, ctx->mode, open_flags, attr, label, + ctx->cred, &ctx->mdsthreshold); ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (label) ++ security_release_secctx(l.label, l.len); ++#endif + if (IS_ERR(state)) + return ERR_CAST(state); + ctx->state = state; +@@ -2447,10 +2519,26 @@ static int _nfs4_server_capabilities(str + server->caps |= NFS_CAP_CTIME; + if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY) + server->caps |= NFS_CAP_MTIME; ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL) { ++ server->caps |= NFS_CAP_SECURITY_LABEL; ++ } else ++#endif ++ server->attr_bitmask[2] &= ~FATTR4_WORD2_SECURITY_LABEL; ++ ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ memcpy(server->attr_bitmask_nl, res.attr_bitmask, sizeof(server->attr_bitmask)); ++ server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL; ++#endif + + memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask)); + server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE; +- server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; ++ server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA | ++ FATTR4_WORD1_TIME_MODIFY; ++ server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL; ++ memcpy(server->cache_consistency_bitmask_nl, server->cache_consistency_bitmask, ++ sizeof(server->cache_consistency_bitmask_nl)); ++ server->cache_consistency_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL; + server->acl_bitmask = res.acl_bitmask; + server->fh_expire_type = res.fh_expire_type; + } +@@ -2473,8 +2561,9 @@ int nfs4_server_capabilities(struct nfs_ + static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_fsinfo *info) + { ++ u32 bitmask[3]; + struct nfs4_lookup_root_arg args = { +- .bitmask = nfs4_fattr_bitmap, ++ .bitmask = bitmask, + }; + struct nfs4_lookup_res res = { + .server = server, +@@ -2487,6 +2576,10 @@ static int _nfs4_lookup_root(struct nfs_ + .rpc_resp = &res, + }; + ++ bitmask[0] = nfs4_fattr_bitmap[0]; ++ bitmask[1] = nfs4_fattr_bitmap[1]; ++ bitmask[2] = nfs4_fattr_bitmap[2] & ~FATTR4_WORD2_SECURITY_LABEL; ++ + nfs_fattr_init(info->fattr); + return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); + } +@@ -2584,6 +2677,7 @@ static int nfs4_proc_get_root(struct nfs + { + int error; + struct nfs_fattr *fattr = info->fattr; ++ struct nfs4_label *label = NULL; + + error = nfs4_server_capabilities(server, mntfh); + if (error < 0) { +@@ -2591,7 +2685,13 @@ static int nfs4_proc_get_root(struct nfs + return error; + } + +- error = nfs4_proc_getattr(server, mntfh, fattr); ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ label = nfs4_label_alloc(GFP_KERNEL); ++ if (label == NULL) ++ return -ENOMEM; ++#endif ++ ++ error = nfs4_proc_getattr(server, mntfh, fattr, label); + if (error < 0) { + dprintk("nfs4_get_root: getattr error = %d\n", -error); + return error; +@@ -2601,6 +2701,11 @@ static int nfs4_proc_get_root(struct nfs + !nfs_fsid_equal(&server->fsid, &fattr->fsid)) + memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid)); + ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (server->caps & NFS_CAP_SECURITY_LABEL) ++ nfs4_label_free(label); ++#endif ++ + return error; + } + +@@ -2647,7 +2752,8 @@ out: + return status; + } + +-static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) ++static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, ++ struct nfs_fattr *fattr, struct nfs4_label *label) + { + struct nfs4_getattr_arg args = { + .fh = fhandle, +@@ -2655,6 +2761,7 @@ static int _nfs4_proc_getattr(struct nfs + }; + struct nfs4_getattr_res res = { + .fattr = fattr, ++ .label = label, + .server = server, + }; + struct rpc_message msg = { +@@ -2662,18 +2769,24 @@ static int _nfs4_proc_getattr(struct nfs + .rpc_argp = &args, + .rpc_resp = &res, + }; +- ++ ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (!label) ++ args.bitmask = server->attr_bitmask_nl; ++#endif ++ + nfs_fattr_init(fattr); + return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); + } + +-static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) ++static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, ++ struct nfs_fattr *fattr, struct nfs4_label *label) + { + struct nfs4_exception exception = { }; + int err; + do { + err = nfs4_handle_exception(server, +- _nfs4_proc_getattr(server, fhandle, fattr), ++ _nfs4_proc_getattr(server, fhandle, fattr, label), + &exception); + } while (exception.retry); + return err; +@@ -2703,11 +2816,16 @@ nfs4_proc_setattr(struct dentry *dentry, + struct inode *inode = dentry->d_inode; + struct rpc_cred *cred = NULL; + struct nfs4_state *state = NULL; ++ struct nfs4_label *olabel = NULL; + int status; + + if (pnfs_ld_layoutret_on_setattr(inode)) + pnfs_return_layout(inode); + ++ olabel = nfs4_label_alloc(GFP_KERNEL); ++ if (olabel == NULL) ++ return -ENOMEM; ++ + nfs_fattr_init(fattr); + + /* Deal with open(O_TRUNC) */ +@@ -2729,7 +2847,7 @@ nfs4_proc_setattr(struct dentry *dentry, + } + } + +- status = nfs4_do_setattr(inode, cred, fattr, sattr, state); ++ status = nfs4_do_setattr(inode, cred, fattr, sattr, state, NULL, NULL); + if (status == 0) + nfs_setattr_update_inode(inode, sattr); + return status; +@@ -2737,7 +2855,7 @@ nfs4_proc_setattr(struct dentry *dentry, + + static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, + const struct qstr *name, struct nfs_fh *fhandle, +- struct nfs_fattr *fattr) ++ struct nfs_fattr *fattr, struct nfs4_label *label) + { + struct nfs_server *server = NFS_SERVER(dir); + int status; +@@ -2749,6 +2867,7 @@ static int _nfs4_proc_lookup(struct rpc_ + struct nfs4_lookup_res res = { + .server = server, + .fattr = fattr, ++ .label = label, + .fh = fhandle, + }; + struct rpc_message msg = { +@@ -2757,6 +2876,11 @@ static int _nfs4_proc_lookup(struct rpc_ + .rpc_resp = &res, + }; + ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (label == NULL) ++ args.bitmask = server->attr_bitmask_nl; ++#endif ++ + nfs_fattr_init(fattr); + + dprintk("NFS call lookup %s\n", name->name); +@@ -2775,13 +2899,13 @@ static void nfs_fixup_secinfo_attributes + + static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir, + struct qstr *name, struct nfs_fh *fhandle, +- struct nfs_fattr *fattr) ++ struct nfs_fattr *fattr, struct nfs4_label *label) + { + struct nfs4_exception exception = { }; + struct rpc_clnt *client = *clnt; + int err; + do { +- err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr); ++ err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr, label); + switch (err) { + case -NFS4ERR_BADNAME: + err = -ENOENT; +@@ -2815,12 +2939,13 @@ out: + } + + static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, +- struct nfs_fh *fhandle, struct nfs_fattr *fattr) ++ struct nfs_fh *fhandle, struct nfs_fattr *fattr, ++ struct nfs4_label *label) + { + int status; + struct rpc_clnt *client = NFS_CLIENT(dir); + +- status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr); ++ status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, label); + if (client != NFS_CLIENT(dir)) { + rpc_shutdown_client(client); + nfs_fixup_secinfo_attributes(fattr); +@@ -2830,12 +2955,13 @@ static int nfs4_proc_lookup(struct inode + + struct rpc_clnt * + nfs4_proc_lookup_mountpoint(struct inode *dir, struct qstr *name, +- struct nfs_fh *fhandle, struct nfs_fattr *fattr) ++ struct nfs_fh *fhandle, struct nfs_fattr *fattr, ++ struct nfs4_label *label) + { + int status; + struct rpc_clnt *client = rpc_clone_client(NFS_CLIENT(dir)); + +- status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr); ++ status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, label); + if (status < 0) { + rpc_shutdown_client(client); + return ERR_PTR(status); +@@ -2852,6 +2978,7 @@ static int _nfs4_proc_access(struct inod + }; + struct nfs4_accessres res = { + .server = server, ++ .label = NULL, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS], +@@ -2860,7 +2987,7 @@ static int _nfs4_proc_access(struct inod + .rpc_cred = entry->cred, + }; + int mode = entry->mask; +- int status; ++ int status = 0; + + /* + * Determine which access bits we want to ask for... +@@ -2882,12 +3009,27 @@ static int _nfs4_proc_access(struct inod + res.fattr = nfs_alloc_fattr(); + if (res.fattr == NULL) + return -ENOMEM; ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (server->caps & NFS_CAP_SECURITY_LABEL) { ++ res.label = nfs4_label_alloc(GFP_KERNEL); ++ if (res.label == NULL) { ++ status = -ENOMEM; ++ goto out; ++ } ++ } ++#endif + + status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); + if (!status) { + nfs_access_set_mask(entry, res.access); +- nfs_refresh_inode(inode, res.fattr); ++ nfs_refresh_inode(inode, res.fattr, res.label); + } ++ ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (server->caps & NFS_CAP_SECURITY_LABEL) ++ nfs4_label_free(res.label); ++#endif ++out: + nfs_free_fattr(res.fattr); + return status; + } +@@ -2965,6 +3107,7 @@ static int + nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, + int flags) + { ++ struct nfs4_label l, *ilabel = NULL; + struct nfs_open_context *ctx; + struct nfs4_state *state; + int status = 0; +@@ -2973,9 +3116,18 @@ nfs4_proc_create(struct inode *dir, stru + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) { ++ status = security_dentry_init_security(dentry, sattr->ia_mode, ++ &dentry->d_name, &l.label, &l.len); ++ if (status == 0) ++ ilabel = &l; ++ } ++#endif ++ + sattr->ia_mode &= ~current_umask(); + state = nfs4_do_open(dir, dentry, ctx->mode, +- flags, sattr, ctx->cred, ++ flags, sattr, ilabel, ctx->cred, + &ctx->mdsthreshold); + d_drop(dentry); + if (IS_ERR(state)) { +@@ -2986,6 +3138,10 @@ nfs4_proc_create(struct inode *dir, stru + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); + ctx->state = state; + out: ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (ilabel) ++ security_release_secctx(ilabel->label, ilabel->len); ++#endif + put_nfs_open_context(ctx); + return status; + } +@@ -3010,6 +3166,7 @@ static int _nfs4_proc_remove(struct inod + status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1); + if (status == 0) + update_changeattr(dir, &res.cinfo); ++ + return status; + } + +@@ -3034,6 +3191,8 @@ static void nfs4_proc_unlink_setup(struc + res->server = server; + msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; + nfs41_init_sequence(&args->seq_args, &res->seq_res, 1); ++ ++ nfs_fattr_init(res->dir_attr); + } + + static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data) +@@ -3055,6 +3214,7 @@ static int nfs4_proc_unlink_done(struct + if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) + return 0; + update_changeattr(dir, &res->cinfo); ++ + return 1; + } + +@@ -3103,6 +3263,8 @@ static int _nfs4_proc_rename(struct inod + .new_dir = NFS_FH(new_dir), + .old_name = old_name, + .new_name = new_name, ++ .old_label = NULL, ++ .new_label = NULL, + }; + struct nfs_renameres res = { + .server = server, +@@ -3113,12 +3275,33 @@ static int _nfs4_proc_rename(struct inod + .rpc_resp = &res, + }; + int status = -ENOMEM; ++ ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (server->caps & NFS_CAP_SECURITY_LABEL) { ++ res.old_label = nfs4_label_alloc(GFP_NOWAIT); ++ if (res.old_label == NULL) ++ goto out; ++ res.new_label = nfs4_label_alloc(GFP_NOWAIT); ++ if (res.new_label == NULL) { ++ nfs4_label_free(res.old_label); ++ goto out; ++ } ++ } ++#endif + + status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); + if (!status) { + update_changeattr(old_dir, &res.old_cinfo); + update_changeattr(new_dir, &res.new_cinfo); + } ++ ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (server->caps & NFS_CAP_SECURITY_LABEL) { ++ nfs4_label_free(res.old_label); ++ nfs4_label_free(res.new_label); ++ } ++#endif ++out: + return status; + } + +@@ -3147,6 +3330,7 @@ static int _nfs4_proc_link(struct inode + }; + struct nfs4_link_res res = { + .server = server, ++ .label = NULL, + }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK], +@@ -3159,11 +3343,25 @@ static int _nfs4_proc_link(struct inode + if (res.fattr == NULL) + goto out; + ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (server->caps & NFS_CAP_SECURITY_LABEL) { ++ res.label = nfs4_label_alloc(GFP_KERNEL); ++ if (res.label == NULL) ++ goto out; ++ } ++#endif ++ + status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1); + if (!status) { + update_changeattr(dir, &res.cinfo); +- nfs_post_op_update_inode(inode, res.fattr); ++ nfs_post_op_update_inode(inode, res.fattr, res.label); + } ++ ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (server->caps & NFS_CAP_SECURITY_LABEL) ++ nfs4_label_free(res.label); ++#endif ++ + out: + nfs_free_fattr(res.fattr); + return status; +@@ -3187,6 +3385,7 @@ struct nfs4_createdata { + struct nfs4_create_res res; + struct nfs_fh fh; + struct nfs_fattr fattr; ++ struct nfs4_label *label; + }; + + static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir, +@@ -3198,6 +3397,13 @@ static struct nfs4_createdata *nfs4_allo + if (data != NULL) { + struct nfs_server *server = NFS_SERVER(dir); + ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (server->caps & NFS_CAP_SECURITY_LABEL) { ++ data->label = nfs4_label_alloc(GFP_KERNEL); ++ if (data->label == NULL) ++ goto out_free; ++ } ++#endif + data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE]; + data->msg.rpc_argp = &data->arg; + data->msg.rpc_resp = &data->res; +@@ -3210,9 +3416,13 @@ static struct nfs4_createdata *nfs4_allo + data->res.server = server; + data->res.fh = &data->fh; + data->res.fattr = &data->fattr; ++ data->res.label = data->label; + nfs_fattr_init(data->res.fattr); + } + return data; ++out_free: ++ kfree(data); ++ return NULL; + } + + static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) +@@ -3221,18 +3431,23 @@ static int nfs4_do_create(struct inode * + &data->arg.seq_args, &data->res.seq_res, 1); + if (status == 0) { + update_changeattr(dir, &data->res.dir_cinfo); +- status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); ++ status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->res.label); + } + return status; + } + + static void nfs4_free_createdata(struct nfs4_createdata *data) + { ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (data->arg.server->caps & NFS_CAP_SECURITY_LABEL) ++ nfs4_label_free(data->label); ++#endif + kfree(data); + } + + static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, +- struct page *page, unsigned int len, struct iattr *sattr) ++ struct page *page, unsigned int len, struct iattr *sattr, ++ struct nfs4_label *label) + { + struct nfs4_createdata *data; + int status = -ENAMETOOLONG; +@@ -3248,6 +3463,7 @@ static int _nfs4_proc_symlink(struct ino + data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK]; + data->arg.u.symlink.pages = &page; + data->arg.u.symlink.len = len; ++ data->arg.label = label; + + status = nfs4_do_create(dir, dentry, data); + +@@ -3260,18 +3476,34 @@ static int nfs4_proc_symlink(struct inod + struct page *page, unsigned int len, struct iattr *sattr) + { + struct nfs4_exception exception = { }; ++ struct nfs4_label l, *label = NULL; + int err; ++ ++ ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) { ++ err = security_dentry_init_security(dentry, sattr->ia_mode, ++ &dentry->d_name, &l.label, &l.len); ++ if (err == 0) ++ label = &l; ++ } ++#endif ++ + do { + err = nfs4_handle_exception(NFS_SERVER(dir), + _nfs4_proc_symlink(dir, dentry, page, +- len, sattr), ++ len, sattr, label), + &exception); + } while (exception.retry); ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (label) ++ security_release_secctx(l.label, l.len); ++#endif + return err; + } + + static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, +- struct iattr *sattr) ++ struct iattr *sattr, struct nfs4_label *label) + { + struct nfs4_createdata *data; + int status = -ENOMEM; +@@ -3280,6 +3512,7 @@ static int _nfs4_proc_mkdir(struct inode + if (data == NULL) + goto out; + ++ data->arg.label = label; + status = nfs4_do_create(dir, dentry, data); + + nfs4_free_createdata(data); +@@ -3291,15 +3524,29 @@ static int nfs4_proc_mkdir(struct inode + struct iattr *sattr) + { + struct nfs4_exception exception = { }; ++ struct nfs4_label l, *label = NULL; + int err; + ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) { ++ err = security_dentry_init_security(dentry, sattr->ia_mode, ++ &dentry->d_name, &l.label, &l.len); ++ if (err == 0) ++ label = &l; ++ } ++#endif ++ + sattr->ia_mode &= ~current_umask(); + do { + err = nfs4_handle_exception(NFS_SERVER(dir), +- _nfs4_proc_mkdir(dir, dentry, sattr), ++ _nfs4_proc_mkdir(dir, dentry, sattr, label), + &exception); + } while (exception.retry); + return err; ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (label) ++ security_release_secctx(l.label, l.len); ++#endif + } + + static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, +@@ -3314,7 +3561,9 @@ static int _nfs4_proc_readdir(struct den + .bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask, + .plus = plus, + }; +- struct nfs4_readdir_res res; ++ struct nfs4_readdir_res res = { ++ .pgbase = 0, ++ }; + struct rpc_message msg = { + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READDIR], + .rpc_argp = &args, +@@ -3356,7 +3605,7 @@ static int nfs4_proc_readdir(struct dent + } + + static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, +- struct iattr *sattr, dev_t rdev) ++ struct iattr *sattr, struct nfs4_label *label, dev_t rdev) + { + struct nfs4_createdata *data; + int mode = sattr->ia_mode; +@@ -3381,7 +3630,8 @@ static int _nfs4_proc_mknod(struct inode + data->arg.u.device.specdata1 = MAJOR(rdev); + data->arg.u.device.specdata2 = MINOR(rdev); + } +- ++ ++ data->arg.label = label; + status = nfs4_do_create(dir, dentry, data); + + nfs4_free_createdata(data); +@@ -3393,14 +3643,28 @@ static int nfs4_proc_mknod(struct inode + struct iattr *sattr, dev_t rdev) + { + struct nfs4_exception exception = { }; ++ struct nfs4_label l, *label = NULL; + int err; + ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) { ++ err = security_dentry_init_security(dentry, sattr->ia_mode, ++ &dentry->d_name, &l.label, &l.len); ++ if (err == 0) ++ label = &l; ++ } ++#endif ++ + sattr->ia_mode &= ~current_umask(); + do { + err = nfs4_handle_exception(NFS_SERVER(dir), +- _nfs4_proc_mknod(dir, dentry, sattr, rdev), ++ _nfs4_proc_mknod(dir, dentry, sattr, label, rdev), + &exception); + } while (exception.retry); ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (label) ++ security_release_secctx(l.label, l.len); ++#endif + return err; + } + +@@ -3618,7 +3882,11 @@ static void nfs4_proc_write_setup(struct + data->args.bitmask = NULL; + data->res.fattr = NULL; + } else ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ data->args.bitmask = server->cache_consistency_bitmask_nl; ++#else + data->args.bitmask = server->cache_consistency_bitmask; ++#endif + + if (!data->write_done_cb) + data->write_done_cb = nfs4_write_done_cb; +@@ -4042,6 +4310,182 @@ static int nfs4_proc_set_acl(struct inod + return err; + } + ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++static int _nfs4_get_security_label(struct inode *inode, void *buf, ++ size_t buflen) ++{ ++ struct nfs_server *server = NFS_SERVER(inode); ++ struct nfs_fattr fattr; ++ struct nfs4_label label; ++ u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL }; ++ struct nfs4_getattr_arg args = { ++ .fh = NFS_FH(inode), ++ .bitmask = bitmask, ++ }; ++ struct nfs4_getattr_res res = { ++ .fattr = &fattr, ++ .label = &label, ++ .server = server, ++ }; ++ struct rpc_message msg = { ++ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR], ++ .rpc_argp = &args, ++ .rpc_resp = &res, ++ }; ++ int ret; ++ ++ label.label = buf; ++ label.len = buflen; ++ nfs_fattr_init(&fattr); ++ ++ ret = rpc_call_sync(server->client, &msg, 0); ++ if (ret) ++ return ret; ++ if (!(fattr.valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL)) ++ return -ENOENT; ++ if (buflen < label.len) ++ return -ERANGE; ++ return 0; ++} ++ ++static int nfs4_get_security_label(struct inode *inode, void *buf, ++ size_t buflen) ++{ ++ struct nfs4_exception exception = { }; ++ int err; ++ ++ if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) ++ return -EOPNOTSUPP; ++ ++ do { ++ err = nfs4_handle_exception(NFS_SERVER(inode), ++ _nfs4_get_security_label(inode, buf, buflen), ++ &exception); ++ } while (exception.retry); ++ return err; ++} ++ ++static int _nfs4_do_set_security_label(struct inode *inode, ++ struct nfs4_label *ilabel, ++ struct nfs_fattr *fattr, ++ struct nfs4_label *olabel, ++ struct nfs4_state *state) ++{ ++ ++ struct iattr sattr; ++ struct nfs_server *server = NFS_SERVER(inode); ++ const u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL }; ++ struct nfs_setattrargs args = { ++ .fh = NFS_FH(inode), ++ .iap = &sattr, ++ .server = server, ++ .bitmask = bitmask, ++ .label = ilabel, ++ }; ++ struct nfs_setattrres res = { ++ .fattr = fattr, ++ .label = olabel, ++ .server = server, ++ }; ++ struct rpc_message msg = { ++ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR], ++ .rpc_argp = &args, ++ .rpc_resp = &res, ++ }; ++ unsigned long timestamp = jiffies; ++ int status; ++ ++ memset(&sattr, 0, sizeof(struct iattr)); ++ ++ if (state != NULL) { ++ struct nfs_lockowner lockowner = { ++ .l_owner = current->files, ++ .l_pid = current->tgid, ++ }; ++ ++ msg.rpc_cred = state->owner->so_cred; ++ nfs4_select_rw_stateid(&args.stateid, state, FMODE_WRITE, ++ &lockowner); ++ } else if (nfs4_copy_delegation_stateid(&args.stateid, inode, ++ FMODE_WRITE)) { ++ /* Use that stateid */ ++ } else ++ nfs4_stateid_copy(&args.stateid, &zero_stateid); ++ ++ status = rpc_call_sync(server->client, &msg, 0); ++ if (status == 0 && state != NULL) ++ renew_lease(server, timestamp); ++ return status; ++} ++ ++static int nfs4_do_set_security_label(struct inode *inode, ++ struct nfs4_label *ilabel, ++ struct nfs_fattr *fattr, ++ struct nfs4_label *olabel, ++ struct nfs4_state *state) ++{ ++ struct nfs4_exception exception = { }; ++ int err; ++ ++ do { ++ err = nfs4_handle_exception(NFS_SERVER(inode), ++ _nfs4_do_set_security_label(inode, ilabel, ++ fattr, olabel, state), ++ &exception); ++ } while (exception.retry); ++ return err; ++} ++ ++ static int ++nfs4_set_security_label(struct dentry *dentry, const void *buf, size_t buflen) ++{ ++ struct nfs4_label ilabel, *olabel = NULL; ++ struct nfs_fattr fattr; ++ struct rpc_cred *cred; ++ struct nfs_open_context *ctx; ++ struct nfs4_state *state = NULL; ++ struct inode *inode = dentry->d_inode; ++ int status; ++ ++ if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) ++ return -EOPNOTSUPP; ++ ++ nfs_fattr_init(&fattr); ++ ++ ilabel.pi = 0; ++ ilabel.lfs = 0; ++ ilabel.label = (char *)buf; ++ ilabel.len = buflen; ++ ++ cred = rpc_lookup_cred(); ++ if (IS_ERR(cred)) ++ return PTR_ERR(cred); ++ ++ olabel = nfs4_label_alloc(GFP_KERNEL); ++ if (olabel == NULL) { ++ status = -ENOMEM; ++ goto out; ++ } ++ ++ /* Search for an existing open(O_WRITE) file */ ++ ctx = nfs_find_open_context(inode, cred, FMODE_WRITE); ++ if (ctx != NULL) ++ state = ctx->state; ++ ++ status = nfs4_do_set_security_label(inode, &ilabel, &fattr, olabel, ++ state); ++ if (status == 0) ++ nfs_setsecurity(inode, &fattr, olabel); ++ if (ctx != NULL) ++ put_nfs_open_context(ctx); ++ nfs4_label_free(olabel); ++out: ++ put_rpccred(cred); ++ return status; ++} ++#endif /* CONFIG_NFS_V4_SECURITY_LABEL */ ++ ++ + static int + nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) + { +@@ -4332,7 +4776,7 @@ static int _nfs4_proc_delegreturn(struct + nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1); + data->args.fhandle = &data->fh; + data->args.stateid = &data->stateid; +- data->args.bitmask = server->cache_consistency_bitmask; ++ data->args.bitmask = server->cache_consistency_bitmask_nl; + nfs_copy_fh(&data->fh, NFS_FH(inode)); + nfs4_stateid_copy(&data->stateid, stateid); + data->res.fattr = &data->fattr; +@@ -4356,7 +4800,7 @@ static int _nfs4_proc_delegreturn(struct + if (status == 0) + nfs_post_op_update_inode_force_wcc(inode, &data->fattr); + else +- nfs_refresh_inode(inode, &data->fattr); ++ nfs_refresh_inode(inode, &data->fattr, NULL); + out: + rpc_put_task(task); + return status; +@@ -5198,6 +5642,53 @@ static size_t nfs4_xattr_list_nfs4_acl(s + return len; + } + ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++static inline int nfs4_server_supports_labels(struct nfs_server *server) ++{ ++ return server->caps & NFS_CAP_SECURITY_LABEL; ++} ++ ++static int nfs4_xattr_set_nfs4_label(struct dentry *dentry, const char *key, ++ const void *buf, size_t buflen, ++ int flags, int type) ++{ ++ if (security_ismaclabel(key)) ++ return nfs4_set_security_label(dentry, buf, buflen); ++ ++ return -EOPNOTSUPP; ++} ++ ++static int nfs4_xattr_get_nfs4_label(struct dentry *dentry, const char *key, ++ void *buf, size_t buflen, int type) ++{ ++ if (security_ismaclabel(key)) ++ return nfs4_get_security_label(dentry->d_inode, buf, buflen); ++ return -EOPNOTSUPP; ++} ++ ++static size_t nfs4_xattr_list_nfs4_label(struct dentry *dentry, char *list, ++ size_t list_len, const char *name, ++ size_t name_len, int type) ++{ ++ size_t len = 0; ++ ++ if (nfs_server_capable(dentry->d_inode, NFS_CAP_SECURITY_LABEL)) { ++ len = security_inode_listsecurity(dentry->d_inode, NULL, 0); ++ if (list && len <= list_len) ++ security_inode_listsecurity(dentry->d_inode, list, len); ++ } ++ return len; ++} ++ ++static const struct xattr_handler nfs4_xattr_nfs4_label_handler = { ++ .prefix = XATTR_SECURITY_PREFIX, ++ .list = nfs4_xattr_list_nfs4_label, ++ .get = nfs4_xattr_get_nfs4_label, ++ .set = nfs4_xattr_set_nfs4_label, ++}; ++#endif ++ ++ + /* + * nfs_fhget will use either the mounted_on_fileid or the fileid + */ +@@ -5221,8 +5712,10 @@ static int _nfs4_proc_fs_locations(struc + struct page *page) + { + struct nfs_server *server = NFS_SERVER(dir); +- u32 bitmask[2] = { ++ u32 bitmask[3] = { + [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS, ++ [1] = 0, ++ [2] = 0 + }; + struct nfs4_fs_locations_arg args = { + .dir_fh = NFS_FH(dir), +@@ -7154,6 +7647,9 @@ static const struct xattr_handler nfs4_x + + const struct xattr_handler *nfs4_xattr_handlers[] = { + &nfs4_xattr_nfs4_acl_handler, ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ &nfs4_xattr_nfs4_label_handler, ++#endif + NULL + }; + +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs4xdr.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs4xdr.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs4xdr.c.orig 2012-11-29 16:37:13.923901662 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/nfs4xdr.c 2012-12-03 10:53:55.667785395 -0500 +@@ -101,12 +101,19 @@ static int nfs4_stat_to_errno(int); + #define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2)) + #define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) + #define nfs4_group_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++/* PI(4 bytes) + LFS(4 bytes) + 1(for null terminator?) + MAXLABELLEN */ ++#define nfs4_label_maxsz (4 + 4 + 1 + XDR_QUADLEN(NFS4_MAXLABELLEN)) ++#else ++#define nfs4_label_maxsz 0 ++#endif + /* We support only one layout type per file system */ + #define decode_mdsthreshold_maxsz (1 + 1 + nfs4_fattr_bitmap_maxsz + 1 + 8) + /* This is based on getfattr, which uses the most attributes: */ + #define nfs4_fattr_value_maxsz (1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \ + 3 + 3 + 3 + nfs4_owner_maxsz + \ +- nfs4_group_maxsz + decode_mdsthreshold_maxsz)) ++ nfs4_group_maxsz + nfs4_label_maxsz + \ ++ decode_mdsthreshold_maxsz)) + #define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \ + nfs4_fattr_value_maxsz) + #define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz) +@@ -114,6 +121,7 @@ static int nfs4_stat_to_errno(int); + 1 + 2 + 1 + \ + nfs4_owner_maxsz + \ + nfs4_group_maxsz + \ ++ nfs4_label_maxsz + \ + 4 + 4) + #define encode_savefh_maxsz (op_encode_hdr_maxsz) + #define decode_savefh_maxsz (op_decode_hdr_maxsz) +@@ -191,9 +199,11 @@ static int nfs4_stat_to_errno(int); + encode_stateid_maxsz + 3) + #define decode_read_maxsz (op_decode_hdr_maxsz + 2) + #define encode_readdir_maxsz (op_encode_hdr_maxsz + \ +- 2 + encode_verifier_maxsz + 5) ++ 2 + encode_verifier_maxsz + 5 + \ ++ nfs4_label_maxsz) + #define decode_readdir_maxsz (op_decode_hdr_maxsz + \ +- decode_verifier_maxsz) ++ decode_verifier_maxsz + \ ++ nfs4_label_maxsz + nfs4_fattr_maxsz) + #define encode_readlink_maxsz (op_encode_hdr_maxsz) + #define decode_readlink_maxsz (op_decode_hdr_maxsz + 1) + #define encode_write_maxsz (op_encode_hdr_maxsz + \ +@@ -969,7 +979,9 @@ static void encode_nfs4_verifier(struct + encode_opaque_fixed(xdr, verf->data, NFS4_VERIFIER_SIZE); + } + +-static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server) ++static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, ++ const struct nfs4_label *label, ++ const struct nfs_server *server) + { + char owner_name[IDMAP_NAMESZ]; + char owner_group[IDMAP_NAMESZ]; +@@ -980,15 +992,16 @@ static void encode_attrs(struct xdr_stre + int len; + uint32_t bmval0 = 0; + uint32_t bmval1 = 0; ++ uint32_t bmval2 = 0; + + /* + * We reserve enough space to write the entire attribute buffer at once. + * In the worst-case, this would be +- * 12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime) +- * = 36 bytes, plus any contribution from variable-length fields ++ * 16(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime) ++ * = 40 bytes, plus any contribution from variable-length fields + * such as owner/group. + */ +- len = 16; ++ len = 20; + + /* Sigh */ + if (iap->ia_valid & ATTR_SIZE) +@@ -1018,6 +1031,10 @@ static void encode_attrs(struct xdr_stre + } + len += 4 + (XDR_QUADLEN(owner_grouplen) << 2); + } ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (label) ++ len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2); ++#endif + if (iap->ia_valid & ATTR_ATIME_SET) + len += 16; + else if (iap->ia_valid & ATTR_ATIME) +@@ -1032,9 +1049,9 @@ static void encode_attrs(struct xdr_stre + * We write the bitmap length now, but leave the bitmap and the attribute + * buffer length to be backfilled at the end of this routine. + */ +- *p++ = cpu_to_be32(2); ++ *p++ = cpu_to_be32(3); + q = p; +- p += 3; ++ p += 4; + + if (iap->ia_valid & ATTR_SIZE) { + bmval0 |= FATTR4_WORD0_SIZE; +@@ -1074,6 +1091,15 @@ static void encode_attrs(struct xdr_stre + bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET; + *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME); + } ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (label) { ++ bmval2 |= FATTR4_WORD2_SECURITY_LABEL; ++ *p++ = cpu_to_be32(label->lfs); ++ *p++ = cpu_to_be32(label->pi); ++ *p++ = cpu_to_be32(label->len); ++ p = xdr_encode_opaque_fixed(p, label->label, label->len); ++ } ++#endif + + /* + * Now we backfill the bitmap and the attribute buffer length. +@@ -1083,9 +1109,10 @@ static void encode_attrs(struct xdr_stre + len, ((char *)p - (char *)q) + 4); + BUG(); + } +- len = (char *)p - (char *)q - 12; ++ len = (char *)p - (char *)q - 16; + *q++ = htonl(bmval0); + *q++ = htonl(bmval1); ++ *q++ = htonl(bmval2); + *q = htonl(len); + + /* out: */ +@@ -1139,7 +1166,7 @@ static void encode_create(struct xdr_str + } + + encode_string(xdr, create->name->len, create->name->name); +- encode_attrs(xdr, create->attrs, create->server); ++ encode_attrs(xdr, create->attrs, create->label, create->server); + } + + static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr) +@@ -1191,8 +1218,10 @@ encode_getattr_three(struct xdr_stream * + + static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) + { +- encode_getattr_two(xdr, bitmask[0] & nfs4_fattr_bitmap[0], +- bitmask[1] & nfs4_fattr_bitmap[1], hdr); ++ encode_getattr_three(xdr, bitmask[0] & nfs4_fattr_bitmap[0], ++ bitmask[1] & nfs4_fattr_bitmap[1], ++ bitmask[2] & nfs4_fattr_bitmap[2], ++ hdr); + } + + static void encode_getfattr_open(struct xdr_stream *xdr, const u32 *bitmask, +@@ -1370,21 +1399,23 @@ static inline void encode_createmode(str + switch(arg->open_flags & O_EXCL) { + case 0: + *p = cpu_to_be32(NFS4_CREATE_UNCHECKED); +- encode_attrs(xdr, arg->u.attrs, arg->server); ++ encode_attrs(xdr, arg->u.attrs, arg->label, arg->server); + break; + default: + clp = arg->server->nfs_client; + if (clp->cl_mvops->minor_version > 0) { + if (nfs4_has_persistent_session(clp)) { + *p = cpu_to_be32(NFS4_CREATE_GUARDED); +- encode_attrs(xdr, arg->u.attrs, arg->server); ++ encode_attrs(xdr, arg->u.attrs, arg->label, ++ arg->server); + } else { + struct iattr dummy; + + *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1); + encode_nfs4_verifier(xdr, &arg->u.verifier); + dummy.ia_valid = 0; +- encode_attrs(xdr, &dummy, arg->server); ++ encode_attrs(xdr, &dummy, arg->label, ++ arg->server); + } + } else { + *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE); +@@ -1564,20 +1595,43 @@ static void encode_readdir(struct xdr_st + encode_op_hdr(xdr, OP_READDIR, decode_readdir_maxsz, hdr); + encode_uint64(xdr, readdir->cookie); + encode_nfs4_verifier(xdr, &readdir->verifier); ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ p = reserve_space(xdr, 24); ++#else + p = reserve_space(xdr, 20); ++#endif + *p++ = cpu_to_be32(dircount); + *p++ = cpu_to_be32(readdir->count); ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ *p++ = cpu_to_be32(3); ++#else + *p++ = cpu_to_be32(2); +- ++#endif + *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]); ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ *p++ = cpu_to_be32(attrs[1] & readdir->bitmask[1]); ++ *p = cpu_to_be32(readdir->bitmask[2]); ++#else + *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]); ++#endif + memcpy(verf, readdir->verifier.data, sizeof(verf)); +- dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ dprintk("%s: cookie = %llu, verifier = %08x:%08x, bitmap = %08x:%08x:%08x\n", ++ __func__, ++ (unsigned long long)readdir->cookie, ++ verf[0], verf[1], ++ attrs[0] & readdir->bitmask[0], ++ attrs[1] & readdir->bitmask[1], ++ readdir->bitmask[2]); ++#else ++ dprintk("%s: cookie = %llu, verifier = %08x:%08x, bitmap = %08x:%08x\n", + __func__, + (unsigned long long)readdir->cookie, + verf[0], verf[1], + attrs[0] & readdir->bitmask[0], + attrs[1] & readdir->bitmask[1]); ++#endif ++ + } + + static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr) +@@ -1637,7 +1691,7 @@ static void encode_setattr(struct xdr_st + { + encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr); + encode_nfs4_stateid(xdr, &arg->stateid); +- encode_attrs(xdr, arg->iap, server); ++ encode_attrs(xdr, arg->iap, arg->label, server); + } + + static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr) +@@ -4056,6 +4110,67 @@ static int decode_attr_time_delta(struct + return status; + } + ++static int decode_attr_security_label(struct xdr_stream *xdr, uint32_t *bitmap, ++ struct nfs4_label *label) ++{ ++ uint32_t pi = 0; ++ uint32_t lfs = 0; ++ __u32 len; ++ __be32 *p; ++ int status = 0; ++ ++ if (unlikely(bitmap[2] & (FATTR4_WORD2_SECURITY_LABEL - 1U))) ++ return -EIO; ++ if (likely(bitmap[2] & FATTR4_WORD2_SECURITY_LABEL)) { ++ p = xdr_inline_decode(xdr, 4); ++ if (unlikely(!p)) ++ goto out_overflow; ++ lfs = be32_to_cpup(p++); ++ p = xdr_inline_decode(xdr, 4); ++ if (unlikely(!p)) ++ goto out_overflow; ++ pi = be32_to_cpup(p++); ++ p = xdr_inline_decode(xdr, 4); ++ if (unlikely(!p)) ++ goto out_overflow; ++ len = be32_to_cpup(p++); ++ p = xdr_inline_decode(xdr, len); ++ if (unlikely(!p)) ++ goto out_overflow; ++ if (len < XDR_MAX_NETOBJ) { ++ if (label) { ++ nfs4_label_init(label); ++ if (label->len < len) { ++ printk(KERN_ERR ++ "%s(): label->len %d < len %d\n", ++ __func__, label->len, len); ++ } else { ++ memcpy(label->label, p, len); ++ label->len = len; ++ label->pi = pi; ++ label->lfs = lfs; ++ status = NFS_ATTR_FATTR_V4_SECURITY_LABEL; ++ } ++ } else { ++ printk("%s(): NULL label.\n", __func__); ++ dump_stack(); ++ goto out_overflow; ++ } ++ bitmap[2] &= ~FATTR4_WORD2_SECURITY_LABEL; ++ } else ++ printk(KERN_WARNING "%s: label too long (%u)!\n", ++ __func__, len); ++ } ++ if (label && label->label) ++ dprintk("%s: label=%s, len=%d, PI=%d, LFS=%d\n", __func__, ++ label->label, label->len, label->pi, label->lfs); ++ return status; ++ ++out_overflow: ++ print_overflow_msg(__func__, xdr); ++ return -EIO; ++} ++ + static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time) + { + int status = 0; +@@ -4398,7 +4513,7 @@ out_overflow: + + static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, + struct nfs_fattr *fattr, struct nfs_fh *fh, +- struct nfs4_fs_locations *fs_loc, ++ struct nfs4_fs_locations *fs_loc, struct nfs4_label *label, + const struct nfs_server *server) + { + int status; +@@ -4506,6 +4621,11 @@ static int decode_getfattr_attrs(struct + if (status < 0) + goto xdr_error; + ++ status = decode_attr_security_label(xdr, bitmap, label); ++ if (status < 0) ++ goto xdr_error; ++ fattr->valid |= status; ++ + xdr_error: + dprintk("%s: xdr returned %d\n", __func__, -status); + return status; +@@ -4513,7 +4633,7 @@ xdr_error: + + static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr, + struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc, +- const struct nfs_server *server) ++ struct nfs4_label *label, const struct nfs_server *server) + { + unsigned int savep; + uint32_t attrlen, +@@ -4532,7 +4652,8 @@ static int decode_getfattr_generic(struc + if (status < 0) + goto xdr_error; + +- status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, fs_loc, server); ++ status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, fs_loc, ++ label, server); + if (status < 0) + goto xdr_error; + +@@ -4543,9 +4664,9 @@ xdr_error: + } + + static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, +- const struct nfs_server *server) ++ struct nfs4_label *label, const struct nfs_server *server) + { +- return decode_getfattr_generic(xdr, fattr, NULL, NULL, server); ++ return decode_getfattr_generic(xdr, fattr, NULL, NULL, label, server); + } + + /* +@@ -5877,7 +5998,7 @@ static int nfs4_xdr_dec_open_downgrade(s + status = decode_open_downgrade(xdr, res); + if (status != 0) + goto out; +- decode_getfattr(xdr, res->fattr, res->server); ++ decode_getfattr(xdr, res->fattr, res->label, res->server); + out: + return status; + } +@@ -5903,7 +6024,7 @@ static int nfs4_xdr_dec_access(struct rp + status = decode_access(xdr, &res->supported, &res->access); + if (status != 0) + goto out; +- decode_getfattr(xdr, res->fattr, res->server); ++ decode_getfattr(xdr, res->fattr, res->label, res->server); + out: + return status; + } +@@ -5932,7 +6053,7 @@ static int nfs4_xdr_dec_lookup(struct rp + status = decode_getfh(xdr, res->fh); + if (status) + goto out; +- status = decode_getfattr(xdr, res->fattr, res->server); ++ status = decode_getfattr(xdr, res->fattr, res->label, res->server); + out: + return status; + } +@@ -5958,7 +6079,8 @@ static int nfs4_xdr_dec_lookup_root(stru + goto out; + status = decode_getfh(xdr, res->fh); + if (status == 0) +- status = decode_getfattr(xdr, res->fattr, res->server); ++ status = decode_getfattr(xdr, res->fattr, ++ res->label, res->server); + out: + return status; + } +@@ -6049,7 +6171,7 @@ static int nfs4_xdr_dec_link(struct rpc_ + status = decode_restorefh(xdr); + if (status) + goto out; +- decode_getfattr(xdr, res->fattr, res->server); ++ decode_getfattr(xdr, res->fattr, res->label, res->server); + out: + return status; + } +@@ -6078,7 +6200,7 @@ static int nfs4_xdr_dec_create(struct rp + status = decode_getfh(xdr, res->fh); + if (status) + goto out; +- decode_getfattr(xdr, res->fattr, res->server); ++ decode_getfattr(xdr, res->fattr, res->label, res->server); + out: + return status; + } +@@ -6110,7 +6232,7 @@ static int nfs4_xdr_dec_getattr(struct r + status = decode_putfh(xdr); + if (status) + goto out; +- status = decode_getfattr(xdr, res->fattr, res->server); ++ status = decode_getfattr(xdr, res->fattr, res->label, res->server); + out: + return status; + } +@@ -6212,7 +6334,7 @@ static int nfs4_xdr_dec_close(struct rpc + * an ESTALE error. Shouldn't be a problem, + * though, since fattr->valid will remain unset. + */ +- decode_getfattr(xdr, res->fattr, res->server); ++ decode_getfattr(xdr, res->fattr, res->label, res->server); + out: + return status; + } +@@ -6243,7 +6365,7 @@ static int nfs4_xdr_dec_open(struct rpc_ + goto out; + if (res->access_request) + decode_access(xdr, &res->access_supported, &res->access_result); +- decode_getfattr(xdr, res->f_attr, res->server); ++ decode_getfattr(xdr, res->f_attr, res->f_label, res->server); + out: + return status; + } +@@ -6293,7 +6415,7 @@ static int nfs4_xdr_dec_open_noattr(stru + goto out; + if (res->access_request) + decode_access(xdr, &res->access_supported, &res->access_result); +- decode_getfattr(xdr, res->f_attr, res->server); ++ decode_getfattr(xdr, res->f_attr, NULL, res->server); + out: + return status; + } +@@ -6320,7 +6442,7 @@ static int nfs4_xdr_dec_setattr(struct r + status = decode_setattr(xdr); + if (status) + goto out; +- decode_getfattr(xdr, res->fattr, res->server); ++ decode_getfattr(xdr, res->fattr, res->label, res->server); + out: + return status; + } +@@ -6500,7 +6622,7 @@ static int nfs4_xdr_dec_write(struct rpc + if (status) + goto out; + if (res->fattr) +- decode_getfattr(xdr, res->fattr, res->server); ++ decode_getfattr(xdr, res->fattr, NULL, res->server); + if (!status) + status = res->count; + out: +@@ -6681,7 +6803,7 @@ static int nfs4_xdr_dec_delegreturn(stru + status = decode_putfh(xdr); + if (status != 0) + goto out; +- status = decode_getfattr(xdr, res->fattr, res->server); ++ status = decode_getfattr(xdr, res->fattr, res->label, res->server); + if (status != 0) + goto out; + status = decode_delegreturn(xdr); +@@ -6714,7 +6836,7 @@ static int nfs4_xdr_dec_fs_locations(str + xdr_enter_page(xdr, PAGE_SIZE); + status = decode_getfattr_generic(xdr, &res->fs_locations->fattr, + NULL, res->fs_locations, +- res->fs_locations->server); ++ NULL, res->fs_locations->server); + out: + return status; + } +@@ -6995,7 +7117,7 @@ static int nfs4_xdr_dec_layoutcommit(str + status = decode_layoutcommit(xdr, rqstp, res); + if (status) + goto out; +- decode_getfattr(xdr, res->fattr, res->server); ++ decode_getfattr(xdr, res->fattr, NULL, res->server); + out: + return status; + } +@@ -7127,7 +7249,7 @@ int nfs4_decode_dirent(struct xdr_stream + goto out_overflow; + + if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, +- NULL, entry->server) < 0) ++ NULL, entry->label, entry->server) < 0) + goto out_overflow; + if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) + entry->ino = entry->fattr->mounted_on_fileid; +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/proc.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/proc.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/proc.c.orig 2012-09-30 19:47:46.000000000 -0400 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/proc.c 2012-12-03 10:53:55.668785396 -0500 +@@ -131,7 +131,7 @@ nfs_proc_get_root(struct nfs_server *ser + */ + static int + nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, +- struct nfs_fattr *fattr) ++ struct nfs_fattr *fattr, struct nfs4_label *label) + { + struct rpc_message msg = { + .rpc_proc = &nfs_procedures[NFSPROC_GETATTR], +@@ -179,7 +179,8 @@ nfs_proc_setattr(struct dentry *dentry, + + static int + nfs_proc_lookup(struct inode *dir, struct qstr *name, +- struct nfs_fh *fhandle, struct nfs_fattr *fattr) ++ struct nfs_fh *fhandle, struct nfs_fattr *fattr, ++ struct nfs4_label *label) + { + struct nfs_diropargs arg = { + .fh = NFS_FH(dir), +@@ -276,7 +277,7 @@ nfs_proc_create(struct inode *dir, struc + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + nfs_mark_for_revalidate(dir); + if (status == 0) +- status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); ++ status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL); + nfs_free_createdata(data); + out: + dprintk("NFS reply create: %d\n", status); +@@ -323,7 +324,7 @@ nfs_proc_mknod(struct inode *dir, struct + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + } + if (status == 0) +- status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); ++ status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL); + nfs_free_createdata(data); + out: + dprintk("NFS reply mknod: %d\n", status); +@@ -479,7 +480,7 @@ nfs_proc_symlink(struct inode *dir, stru + * should fill in the data with a LOOKUP call on the wire. + */ + if (status == 0) +- status = nfs_instantiate(dentry, fh, fattr); ++ status = nfs_instantiate(dentry, fh, fattr, NULL); + + out_free: + nfs_free_fattr(fattr); +@@ -508,7 +509,7 @@ nfs_proc_mkdir(struct inode *dir, struct + status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); + nfs_mark_for_revalidate(dir); + if (status == 0) +- status = nfs_instantiate(dentry, data->res.fh, data->res.fattr); ++ status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL); + nfs_free_createdata(data); + out: + dprintk("NFS reply mkdir: %d\n", status); +@@ -647,7 +648,7 @@ static int nfs_read_done(struct rpc_task + + nfs_invalidate_atime(inode); + if (task->tk_status >= 0) { +- nfs_refresh_inode(inode, data->res.fattr); ++ nfs_refresh_inode(inode, data->res.fattr, data->res.label); + /* Emulate the eof flag, which isn't normally needed in NFSv2 + * as it is guaranteed to always return the file attributes + */ +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/super.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/super.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/super.c.orig 2012-11-29 16:37:13.972901705 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/fs/nfs/super.c 2012-12-03 10:53:55.669785397 -0500 +@@ -875,6 +875,7 @@ int nfs_show_stats(struct seq_file *m, s + seq_printf(m, "\n\tnfsv4:\t"); + seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); + seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); ++ seq_printf(m, ",bm2=0x%x", nfss->attr_bitmask[2]); + seq_printf(m, ",acl=0x%x", nfss->acl_bitmask); + show_sessions(m, nfss); + show_pnfs(m, nfss); +@@ -2405,7 +2406,23 @@ static int nfs_bdi_register(struct nfs_s + int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot, + struct nfs_mount_info *mount_info) + { +- return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts); ++ int error; ++ unsigned long kflags = 0, kflags_out = 0; ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL) ++ kflags |= SECURITY_LSM_NATIVE_LABELS; ++#endif ++ error = security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts, ++ kflags, &kflags_out); ++ if (error) ++ goto err; ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL && ++ !(kflags_out & SECURITY_LSM_NATIVE_LABELS)) ++ NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL; ++#endif ++err: ++ return error; + } + EXPORT_SYMBOL_GPL(nfs_set_sb_security); + +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/nfs4.h.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/nfs4.h +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/nfs4.h.orig 2012-11-29 16:37:19.038905615 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/nfs4.h 2012-12-03 10:53:55.698785414 -0500 +@@ -28,6 +28,14 @@ struct nfs4_acl { + struct nfs4_ace aces[0]; + }; + ++struct nfs4_label { ++ uint32_t lfs; ++ uint32_t pi; ++ u32 len; ++ void *label; ++}; ++ ++ + typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier; + + struct nfs_stateid4 { +@@ -373,6 +381,7 @@ enum lock_type4 { + #define FATTR4_WORD1_MOUNTED_ON_FILEID (1UL << 23) + #define FATTR4_WORD1_FS_LAYOUT_TYPES (1UL << 30) + #define FATTR4_WORD2_LAYOUT_BLKSIZE (1UL << 1) ++#define FATTR4_WORD2_SECURITY_LABEL (1UL << 17) + #define FATTR4_WORD2_MDSTHRESHOLD (1UL << 4) + + /* MDS threshold bitmap bits */ +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/nfs_fs.h.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/nfs_fs.h +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/nfs_fs.h.orig 2012-11-29 16:37:19.047905624 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/nfs_fs.h 2012-12-03 10:53:55.699785414 -0500 +@@ -199,6 +199,7 @@ struct nfs_inode { + #define NFS_INO_INVALID_ACL 0x0010 /* cached acls are invalid */ + #define NFS_INO_REVAL_PAGECACHE 0x0020 /* must revalidate pagecache */ + #define NFS_INO_REVAL_FORCED 0x0040 /* force revalidation ignoring a delegation */ ++#define NFS_INO_INVALID_LABEL 0x0080 /* cached label is invalid */ + + /* + * Bit offsets in flags field +@@ -328,9 +329,9 @@ extern void nfs_zap_mapping(struct inode + extern void nfs_zap_caches(struct inode *); + extern void nfs_invalidate_atime(struct inode *); + extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *, +- struct nfs_fattr *); +-extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *); +-extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr); ++ struct nfs_fattr *, struct nfs4_label *); ++extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *, struct nfs4_label *); ++extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *); + extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr); + extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); + extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *); +@@ -344,6 +345,8 @@ extern int __nfs_revalidate_inode(struct + extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping); + extern int nfs_setattr(struct dentry *, struct iattr *); + extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr); ++extern void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, ++ struct nfs4_label *label); + extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); + extern void put_nfs_open_context(struct nfs_open_context *ctx); + extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode); +@@ -460,7 +463,8 @@ extern const struct file_operations nfs_ + extern const struct dentry_operations nfs_dentry_operations; + + extern void nfs_force_lookup_revalidate(struct inode *dir); +-extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr); ++extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, ++ struct nfs_fattr *fattr, struct nfs4_label *label); + extern int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags); + extern void nfs_access_zap_cache(struct inode *inode); + +@@ -489,6 +493,20 @@ extern int nfs_mountpoint_expiry_timeout + extern void nfs_release_automount_timer(void); + + /* ++ * linux/fs/nfs/nfs4proc.c ++ */ ++ ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++extern struct nfs4_label *nfs4_label_alloc(gfp_t flags); ++extern void nfs4_label_init(struct nfs4_label *); ++extern void nfs4_label_free(struct nfs4_label *); ++#else ++static inline struct nfs4_label *nfs4_label_alloc(gfp_t flags) { return NULL; } ++static inline void nfs4_label_init(struct nfs4_label *) {} ++static inline void nfs4_label_free(struct nfs4_label *label) {} ++#endif ++ ++/* + * linux/fs/nfs/unlink.c + */ + extern void nfs_complete_unlink(struct dentry *dentry, struct inode *); +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/nfs_fs_sb.h.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/nfs_fs_sb.h +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/nfs_fs_sb.h.orig 2012-11-29 16:37:19.054905631 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/nfs_fs_sb.h 2012-12-03 10:53:55.707785421 -0500 +@@ -145,11 +145,18 @@ struct nfs_server { + u32 attr_bitmask[3];/* V4 bitmask representing the set + of attributes supported on this + filesystem */ +- u32 cache_consistency_bitmask[2]; ++ u32 attr_bitmask_nl[3]; ++ /* V4 bitmask representing the ++ set of attributes supported ++ on this filesystem excluding ++ the label support bit. */ ++ u32 cache_consistency_bitmask[3]; + /* V4 bitmask representing the subset + of change attribute, size, ctime + and mtime attributes supported by + the server */ ++ u32 cache_consistency_bitmask_nl[3]; ++ /* As above, excluding label. */ + u32 acl_bitmask; /* V4 bitmask representing the ACEs + that are supported on this + filesystem */ +@@ -197,6 +204,7 @@ struct nfs_server { + #define NFS_CAP_MTIME (1U << 13) + #define NFS_CAP_POSIX_LOCK (1U << 14) + #define NFS_CAP_UIDGID_NOMAP (1U << 15) ++#define NFS_CAP_SECURITY_LABEL (1U << 16) + + + /* maximum number of slots to use */ +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/nfs_xdr.h.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/nfs_xdr.h +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/nfs_xdr.h.orig 2012-11-29 16:37:19.071905644 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/nfs_xdr.h 2012-12-03 10:53:55.708785422 -0500 +@@ -104,6 +104,7 @@ struct nfs_fattr { + #define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 22) + #define NFS_ATTR_FATTR_OWNER_NAME (1U << 23) + #define NFS_ATTR_FATTR_GROUP_NAME (1U << 24) ++#define NFS_ATTR_FATTR_V4_SECURITY_LABEL (1U << 25) + + #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \ + | NFS_ATTR_FATTR_MODE \ +@@ -123,7 +124,8 @@ struct nfs_fattr { + #define NFS_ATTR_FATTR_V3 (NFS_ATTR_FATTR \ + | NFS_ATTR_FATTR_SPACE_USED) + #define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \ +- | NFS_ATTR_FATTR_SPACE_USED) ++ | NFS_ATTR_FATTR_SPACE_USED \ ++ | NFS_ATTR_FATTR_V4_SECURITY_LABEL) + + /* + * Info on the file system +@@ -350,6 +352,7 @@ struct nfs_openargs { + const u32 * bitmask; + const u32 * open_bitmap; + __u32 claim; ++ const struct nfs4_label *label; + struct nfs4_sequence_args seq_args; + }; + +@@ -359,6 +362,7 @@ struct nfs_openres { + struct nfs4_change_info cinfo; + __u32 rflags; + struct nfs_fattr * f_attr; ++ struct nfs4_label *f_label; + struct nfs_seqid * seqid; + const struct nfs_server *server; + fmode_t delegation_type; +@@ -403,6 +407,7 @@ struct nfs_closeargs { + struct nfs_closeres { + nfs4_stateid stateid; + struct nfs_fattr * fattr; ++ struct nfs4_label *label; + struct nfs_seqid * seqid; + const struct nfs_server *server; + struct nfs4_sequence_res seq_res; +@@ -476,6 +481,7 @@ struct nfs4_delegreturnargs { + + struct nfs4_delegreturnres { + struct nfs_fattr * fattr; ++ struct nfs4_label *label; + const struct nfs_server *server; + struct nfs4_sequence_res seq_res; + }; +@@ -496,6 +502,7 @@ struct nfs_readargs { + + struct nfs_readres { + struct nfs_fattr * fattr; ++ struct nfs4_label *label; + __u32 count; + int eof; + struct nfs4_sequence_res seq_res; +@@ -564,6 +571,7 @@ struct nfs_removeargs { + struct nfs_removeres { + const struct nfs_server *server; + struct nfs_fattr *dir_attr; ++ struct nfs4_label *dir_label; + struct nfs4_change_info cinfo; + struct nfs4_sequence_res seq_res; + }; +@@ -576,6 +584,8 @@ struct nfs_renameargs { + const struct nfs_fh *new_dir; + const struct qstr *old_name; + const struct qstr *new_name; ++ const struct nfs4_label *old_label; ++ const struct nfs4_label *new_label; + struct nfs4_sequence_args seq_args; + }; + +@@ -583,8 +593,10 @@ struct nfs_renameres { + const struct nfs_server *server; + struct nfs4_change_info old_cinfo; + struct nfs_fattr *old_fattr; ++ struct nfs4_label *old_label; + struct nfs4_change_info new_cinfo; + struct nfs_fattr *new_fattr; ++ struct nfs4_label *new_label; + struct nfs4_sequence_res seq_res; + }; + +@@ -600,6 +612,7 @@ struct nfs_entry { + int eof; + struct nfs_fh * fh; + struct nfs_fattr * fattr; ++ struct nfs4_label *label; + unsigned char d_type; + struct nfs_server * server; + }; +@@ -631,6 +644,7 @@ struct nfs_setattrargs { + struct iattr * iap; + const struct nfs_server * server; /* Needed for name mapping */ + const u32 * bitmask; ++ const struct nfs4_label *label; + struct nfs4_sequence_args seq_args; + }; + +@@ -666,6 +680,7 @@ struct nfs_getaclres { + + struct nfs_setattrres { + struct nfs_fattr * fattr; ++ struct nfs4_label *label; + const struct nfs_server * server; + struct nfs4_sequence_res seq_res; + }; +@@ -712,6 +727,7 @@ struct nfs3_setaclargs { + struct nfs_diropok { + struct nfs_fh * fh; + struct nfs_fattr * fattr; ++ struct nfs4_label *label; + }; + + struct nfs_readlinkargs { +@@ -841,6 +857,7 @@ struct nfs4_accessargs { + struct nfs4_accessres { + const struct nfs_server * server; + struct nfs_fattr * fattr; ++ struct nfs4_label *label; + u32 supported; + u32 access; + struct nfs4_sequence_res seq_res; +@@ -863,6 +880,7 @@ struct nfs4_create_arg { + const struct iattr * attrs; + const struct nfs_fh * dir_fh; + const u32 * bitmask; ++ const struct nfs4_label *label; + struct nfs4_sequence_args seq_args; + }; + +@@ -870,6 +888,7 @@ struct nfs4_create_res { + const struct nfs_server * server; + struct nfs_fh * fh; + struct nfs_fattr * fattr; ++ struct nfs4_label *label; + struct nfs4_change_info dir_cinfo; + struct nfs4_sequence_res seq_res; + }; +@@ -895,6 +914,7 @@ struct nfs4_getattr_res { + const struct nfs_server * server; + struct nfs_fattr * fattr; + struct nfs4_sequence_res seq_res; ++ struct nfs4_label *label; + }; + + struct nfs4_link_arg { +@@ -908,8 +928,10 @@ struct nfs4_link_arg { + struct nfs4_link_res { + const struct nfs_server * server; + struct nfs_fattr * fattr; ++ struct nfs4_label *label; + struct nfs4_change_info cinfo; + struct nfs_fattr * dir_attr; ++ struct nfs4_label *dir_label; + struct nfs4_sequence_res seq_res; + }; + +@@ -925,6 +947,7 @@ struct nfs4_lookup_res { + const struct nfs_server * server; + struct nfs_fattr * fattr; + struct nfs_fh * fh; ++ struct nfs4_label *label; + struct nfs4_sequence_res seq_res; + }; + +@@ -1379,11 +1402,12 @@ struct nfs_rpc_ops { + struct dentry *(*try_mount) (int, const char *, struct nfs_mount_info *, + struct nfs_subversion *); + int (*getattr) (struct nfs_server *, struct nfs_fh *, +- struct nfs_fattr *); ++ struct nfs_fattr *, struct nfs4_label *); + int (*setattr) (struct dentry *, struct nfs_fattr *, + struct iattr *); + int (*lookup) (struct inode *, struct qstr *, +- struct nfs_fh *, struct nfs_fattr *); ++ struct nfs_fh *, struct nfs_fattr *, ++ struct nfs4_label *); + int (*access) (struct inode *, struct nfs_access_entry *); + int (*readlink)(struct inode *, struct page *, unsigned int, + unsigned int); +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/security.h.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/security.h +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/security.h.orig 2012-11-29 16:37:19.946906321 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/linux/security.h 2012-12-03 10:53:55.710785424 -0500 +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + struct linux_binprm; + struct cred; +@@ -60,6 +61,9 @@ struct mm_struct; + #define SECURITY_CAP_NOAUDIT 0 + #define SECURITY_CAP_AUDIT 1 + ++/* LSM Agnostic defines for sb_set_mnt_opts */ ++#define SECURITY_LSM_NATIVE_LABELS 1 ++ + struct ctl_table; + struct audit_krule; + struct user_namespace; +@@ -306,6 +310,15 @@ static inline void security_free_mnt_opt + * Parse a string of security data filling in the opts structure + * @options string containing all mount options known by the LSM + * @opts binary data structure usable by the LSM ++ * @dentry_init_security: ++ * Compute a context for a dentry as the inode is not yet available ++ * since NFSv4 has no label backed by an EA anyway. ++ * @dentry dentry to use in calculating the context. ++ * @mode mode used to determine resource type. ++ * @name name of the last path component used to create file ++ * @ctx pointer to place the pointer to the resulting context in. ++ * @ctxlen point to place the length of the resulting context. ++ * + * + * Security hooks for inode operations. + * +@@ -1291,6 +1304,13 @@ static inline void security_free_mnt_opt + * @pages contains the number of pages. + * Return 0 if permission is granted. + * ++ * @ismaclabel: ++ * Check if the extended attribute specified by @name ++ * represents a MAC label. Returns 0 if name is a MAC ++ * attribute otherwise returns non-zero. ++ * @name full extended attribute name to check against ++ * LSM as a MAC label. ++ * + * @secid_to_secctx: + * Convert secid to security context. If secdata is NULL the length of + * the result will be returned in seclen, but no secdata will be returned. +@@ -1417,10 +1437,16 @@ struct security_operations { + int (*sb_pivotroot) (struct path *old_path, + struct path *new_path); + int (*sb_set_mnt_opts) (struct super_block *sb, +- struct security_mnt_opts *opts); ++ struct security_mnt_opts *opts, ++ unsigned long kern_flags, ++ unsigned long *set_kern_flags); + void (*sb_clone_mnt_opts) (const struct super_block *oldsb, + struct super_block *newsb); + int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts); ++ int (*dentry_init_security) (struct dentry *dentry, int mode, ++ struct qstr *name, void **ctx, ++ u32 *ctxlen); ++ + + #ifdef CONFIG_SECURITY_PATH + int (*path_unlink) (struct path *dir, struct dentry *dentry); +@@ -1567,6 +1593,7 @@ struct security_operations { + + int (*getprocattr) (struct task_struct *p, char *name, char **value); + int (*setprocattr) (struct task_struct *p, char *name, void *value, size_t size); ++ int (*ismaclabel) (const char *name); + int (*secid_to_secctx) (u32 secid, char **secdata, u32 *seclen); + int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid); + void (*release_secctx) (char *secdata, u32 seclen); +@@ -1698,10 +1725,16 @@ int security_sb_mount(const char *dev_na + const char *type, unsigned long flags, void *data); + int security_sb_umount(struct vfsmount *mnt, int flags); + int security_sb_pivotroot(struct path *old_path, struct path *new_path); +-int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts); ++int security_sb_set_mnt_opts(struct super_block *sb, ++ struct security_mnt_opts *opts, ++ unsigned long kern_flags, ++ unsigned long *set_kern_flags); + void security_sb_clone_mnt_opts(const struct super_block *oldsb, + struct super_block *newsb); + int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts); ++int security_dentry_init_security(struct dentry *dentry, int mode, ++ struct qstr *name, void **ctx, ++ u32 *ctxlen); + + int security_inode_alloc(struct inode *inode); + void security_inode_free(struct inode *inode); +@@ -1812,6 +1845,7 @@ void security_d_instantiate(struct dentr + int security_getprocattr(struct task_struct *p, char *name, char **value); + int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size); + int security_netlink_send(struct sock *sk, struct sk_buff *skb); ++int security_ismaclabel(const char *name); + int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); + int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); + void security_release_secctx(char *secdata, u32 seclen); +@@ -1983,7 +2017,9 @@ static inline int security_sb_pivotroot( + } + + static inline int security_sb_set_mnt_opts(struct super_block *sb, +- struct security_mnt_opts *opts) ++ struct security_mnt_opts *opts, ++ unsigned long kern_flags, ++ unsigned long *set_kern_flags) + { + return 0; + } +@@ -2005,6 +2041,16 @@ static inline int security_inode_alloc(s + static inline void security_inode_free(struct inode *inode) + { } + ++static inline int security_dentry_init_security(struct dentry *dentry, ++ int mode, ++ struct qstr *name, ++ void **ctx, ++ u32 *ctxlen) ++{ ++ return -EOPNOTSUPP; ++} ++ ++ + static inline int security_inode_init_security(struct inode *inode, + struct inode *dir, + const struct qstr *qstr, +@@ -2485,6 +2531,11 @@ static inline int security_netlink_send( + return cap_netlink_send(sk, skb); + } + ++static inline int security_ismaclabel(const char *name) ++{ ++ return 0; ++} ++ + static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) + { + return -EOPNOTSUPP; +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/uapi/linux/nfs4.h.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/uapi/linux/nfs4.h +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/uapi/linux/nfs4.h.orig 2012-11-29 16:37:22.518908252 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/uapi/linux/nfs4.h 2012-12-03 10:53:55.711785425 -0500 +@@ -25,6 +25,7 @@ + #define NFS4_MAXNAMLEN NAME_MAX + #define NFS4_OPAQUE_LIMIT 1024 + #define NFS4_MAX_SESSIONID_LEN 16 ++#define NFS4_MAXLABELLEN 4096 + + #define NFS4_ACCESS_READ 0x0001 + #define NFS4_ACCESS_LOOKUP 0x0002 +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/uapi/linux/nfsd/export.h.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/uapi/linux/nfsd/export.h +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/uapi/linux/nfsd/export.h.orig 2012-11-29 16:37:22.520908254 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/include/uapi/linux/nfsd/export.h 2012-12-03 10:53:55.711785425 -0500 +@@ -28,7 +28,8 @@ + #define NFSEXP_ALLSQUASH 0x0008 + #define NFSEXP_ASYNC 0x0010 + #define NFSEXP_GATHERED_WRITES 0x0020 +-/* 40 80 100 currently unused */ ++#define NFSEXP_SECURITY_LABEL 0x0040 /* Support security label fattr4 */ ++/* 80 100 currently unused */ + #define NFSEXP_NOHIDE 0x0200 + #define NFSEXP_NOSUBTREECHECK 0x0400 + #define NFSEXP_NOAUTHNLM 0x0800 /* Don't authenticate NLM requests - just trust */ +@@ -47,7 +48,7 @@ + */ + #define NFSEXP_V4ROOT 0x10000 + /* All flags that we claim to support. (Note we don't support NOACL.) */ +-#define NFSEXP_ALLFLAGS 0x17E3F ++#define NFSEXP_ALLFLAGS 0x17E7F + + /* The flags that may vary depending on security flavor: */ + #define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \ +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/capability.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/capability.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/capability.c.orig 2012-11-29 16:37:29.717913881 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/capability.c 2012-12-03 10:53:55.711785425 -0500 +@@ -91,7 +91,10 @@ static int cap_sb_pivotroot(struct path + } + + static int cap_sb_set_mnt_opts(struct super_block *sb, +- struct security_mnt_opts *opts) ++ struct security_mnt_opts *opts, ++ unsigned long kern_flags, ++ unsigned long *set_kern_flags) ++ + { + if (unlikely(opts->num_mnt_opts)) + return -EOPNOTSUPP; +@@ -108,6 +111,13 @@ static int cap_sb_parse_opts_str(char *o + return 0; + } + ++static int cap_dentry_init_security(struct dentry *dentry, int mode, ++ struct qstr *name, void **ctx, ++ u32 *ctxlen) ++{ ++ return 0; ++} ++ + static int cap_inode_alloc_security(struct inode *inode) + { + return 0; +@@ -790,6 +800,11 @@ static int cap_setprocattr(struct task_s + return -EINVAL; + } + ++static int cap_ismaclabel(const char *name) ++{ ++ return 0; ++} ++ + static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) + { + return -EOPNOTSUPP; +@@ -905,6 +920,7 @@ void __init security_fixup_ops(struct se + set_to_cap_if_null(ops, sb_set_mnt_opts); + set_to_cap_if_null(ops, sb_clone_mnt_opts); + set_to_cap_if_null(ops, sb_parse_opts_str); ++ set_to_cap_if_null(ops, dentry_init_security); + set_to_cap_if_null(ops, inode_alloc_security); + set_to_cap_if_null(ops, inode_free_security); + set_to_cap_if_null(ops, inode_init_security); +@@ -1007,6 +1023,7 @@ void __init security_fixup_ops(struct se + set_to_cap_if_null(ops, d_instantiate); + set_to_cap_if_null(ops, getprocattr); + set_to_cap_if_null(ops, setprocattr); ++ set_to_cap_if_null(ops, ismaclabel); + set_to_cap_if_null(ops, secid_to_secctx); + set_to_cap_if_null(ops, secctx_to_secid); + set_to_cap_if_null(ops, release_secctx); +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/security.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/security.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/security.c.orig 2012-11-29 16:37:29.952914090 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/security.c 2012-12-03 10:53:55.712785426 -0500 +@@ -12,6 +12,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -293,9 +294,12 @@ int security_sb_pivotroot(struct path *o + } + + int security_sb_set_mnt_opts(struct super_block *sb, +- struct security_mnt_opts *opts) ++ struct security_mnt_opts *opts, ++ unsigned long kern_flags, ++ unsigned long *set_kern_flags) + { +- return security_ops->sb_set_mnt_opts(sb, opts); ++ return security_ops->sb_set_mnt_opts(sb, opts, kern_flags, ++ set_kern_flags); + } + EXPORT_SYMBOL(security_sb_set_mnt_opts); + +@@ -324,6 +328,15 @@ void security_inode_free(struct inode *i + security_ops->inode_free_security(inode); + } + ++int security_dentry_init_security(struct dentry *dentry, int mode, ++ struct qstr *name, void **ctx, ++ u32 *ctxlen) ++{ ++ return security_ops->dentry_init_security(dentry, mode, name, ++ ctx, ctxlen); ++} ++EXPORT_SYMBOL(security_dentry_init_security); ++ + int security_inode_init_security(struct inode *inode, struct inode *dir, + const struct qstr *qstr, + const initxattrs initxattrs, void *fs_data) +@@ -647,6 +660,7 @@ int security_inode_listsecurity(struct i + return 0; + return security_ops->inode_listsecurity(inode, buffer, buffer_size); + } ++EXPORT_SYMBOL(security_inode_listsecurity); + + void security_inode_getsecid(const struct inode *inode, u32 *secid) + { +@@ -1037,6 +1051,12 @@ int security_netlink_send(struct sock *s + return security_ops->netlink_send(sk, skb); + } + ++int security_ismaclabel(const char *name) ++{ ++ return security_ops->ismaclabel(name); ++} ++EXPORT_SYMBOL(security_ismaclabel); ++ + int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) + { + return security_ops->secid_to_secctx(secid, secdata, seclen); +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/selinux/hooks.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/selinux/hooks.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/selinux/hooks.c.orig 2012-11-30 09:16:55.312835507 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/selinux/hooks.c 2012-12-03 10:53:55.714785428 -0500 +@@ -80,6 +80,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -283,13 +284,14 @@ static void superblock_free_security(str + + /* The file system's label must be initialized prior to use. */ + +-static const char *labeling_behaviors[6] = { ++static const char *labeling_behaviors[7] = { + "uses xattr", + "uses transition SIDs", + "uses task SIDs", + "uses genfs_contexts", + "not configured for labeling", + "uses mountpoint labeling", ++ "uses native labeling", + }; + + static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry); +@@ -551,7 +553,9 @@ static int bad_option(struct superblock_ + * labeling information. + */ + static int selinux_set_mnt_opts(struct super_block *sb, +- struct security_mnt_opts *opts) ++ struct security_mnt_opts *opts, ++ unsigned long kern_flags, ++ unsigned long *set_kern_flags) + { + const struct cred *cred = current_cred(); + int rc = 0, i; +@@ -579,6 +583,12 @@ static int selinux_set_mnt_opts(struct s + "before the security server is initialized\n"); + goto out; + } ++ if (kern_flags && !set_kern_flags) { ++ /* Specifying internal flags without providing a place to ++ * place the results is not allowed */ ++ rc = -EINVAL; ++ goto out; ++ } + + /* + * Binary mount data FS will come through this function twice. Once +@@ -669,14 +679,21 @@ static int selinux_set_mnt_opts(struct s + if (strcmp(sb->s_type->name, "proc") == 0) + sbsec->flags |= SE_SBPROC; + +- /* Determine the labeling behavior to use for this filesystem type. */ +- rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid); +- if (rc) { +- printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", +- __func__, sb->s_type->name, rc); +- goto out; ++ if (!sbsec->behavior) { ++ /* ++ * Determine the labeling behavior to use for this ++ * filesystem type. ++ */ ++ rc = security_fs_use((sbsec->flags & SE_SBPROC) ? ++ "proc" : sb->s_type->name, ++ &sbsec->behavior, &sbsec->sid); ++ if (rc) { ++ printk(KERN_WARNING ++ "%s: security_fs_use(%s) returned %d\n", ++ __func__, sb->s_type->name, rc); ++ goto out; ++ } + } +- + /* sets the context of the superblock for the fs being mounted. */ + if (fscontext_sid) { + rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred); +@@ -691,6 +708,11 @@ static int selinux_set_mnt_opts(struct s + * sets the label used on all file below the mountpoint, and will set + * the superblock context if not already set. + */ ++ if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) { ++ sbsec->behavior = SECURITY_FS_USE_NATIVE; ++ *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS; ++ } ++ + if (context_sid) { + if (!fscontext_sid) { + rc = may_context_mount_sb_relabel(context_sid, sbsec, +@@ -722,7 +744,8 @@ static int selinux_set_mnt_opts(struct s + } + + if (defcontext_sid) { +- if (sbsec->behavior != SECURITY_FS_USE_XATTR) { ++ if (sbsec->behavior != SECURITY_FS_USE_XATTR && ++ sbsec->behavior != SECURITY_FS_USE_NATIVE) { + rc = -EINVAL; + printk(KERN_WARNING "SELinux: defcontext option is " + "invalid for this filesystem type\n"); +@@ -948,7 +971,7 @@ static int superblock_doinit(struct supe + goto out_err; + + out: +- rc = selinux_set_mnt_opts(sb, &opts); ++ rc = selinux_set_mnt_opts(sb, &opts, 0, NULL); + + out_err: + security_free_mnt_opts(&opts); +@@ -1190,6 +1213,8 @@ static int inode_doinit_with_dentry(stru + } + + switch (sbsec->behavior) { ++ case SECURITY_FS_USE_NATIVE: ++ break; + case SECURITY_FS_USE_XATTR: + if (!inode->i_op->getxattr) { + isec->sid = sbsec->def_sid; +@@ -2521,6 +2546,40 @@ static void selinux_inode_free_security( + inode_free_security(inode); + } + ++static int selinux_dentry_init_security(struct dentry *dentry, int mode, ++ struct qstr *name, void **ctx, ++ u32 *ctxlen) ++{ ++ struct cred *cred = current_cred(); ++ struct task_security_struct *tsec; ++ struct inode_security_struct *dsec; ++ struct superblock_security_struct *sbsec; ++ struct inode *dir = dentry->d_parent->d_inode; ++ u32 newsid; ++ int rc; ++ ++ tsec = cred->security; ++ dsec = dir->i_security; ++ sbsec = dir->i_sb->s_security; ++ ++ if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { ++ newsid = tsec->create_sid; ++ } else { ++ rc = security_transition_sid(tsec->sid, dsec->sid, ++ inode_mode_to_security_class(mode), ++ name, ++ &newsid); ++ if (rc) { ++ printk(KERN_WARNING ++ "%s: security_transition_sid failed, rc=%d\n", ++ __func__, -rc); ++ return rc; ++ } ++ } ++ ++ return security_sid_to_context(newsid, (char **)ctx, ctxlen); ++} ++ + static int selinux_inode_init_security(struct inode *inode, struct inode *dir, + const struct qstr *qstr, char **name, + void **value, size_t *len) +@@ -2855,7 +2914,10 @@ static void selinux_inode_post_setxattr( + return; + } + ++ isec->sclass = inode_mode_to_security_class(inode->i_mode); + isec->sid = newsid; ++ isec->initialized = 1; ++ + return; + } + +@@ -2943,6 +3005,7 @@ static int selinux_inode_setsecurity(str + if (rc) + return rc; + ++ isec->sclass = inode_mode_to_security_class(inode->i_mode); + isec->sid = newsid; + isec->initialized = 1; + return 0; +@@ -5405,6 +5468,11 @@ abort_change: + return error; + } + ++static int selinux_ismaclabel(const char *name) ++{ ++ return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0); ++} ++ + static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) + { + return security_sid_to_context(secid, secdata, seclen); +@@ -5547,6 +5615,7 @@ static struct security_operations selinu + .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts, + .sb_parse_opts_str = selinux_parse_opts_str, + ++ .dentry_init_security = selinux_dentry_init_security, + + .inode_alloc_security = selinux_inode_alloc_security, + .inode_free_security = selinux_inode_free_security, +@@ -5642,6 +5711,7 @@ static struct security_operations selinu + .getprocattr = selinux_getprocattr, + .setprocattr = selinux_setprocattr, + ++ .ismaclabel = selinux_ismaclabel, + .secid_to_secctx = selinux_secid_to_secctx, + .secctx_to_secid = selinux_secctx_to_secid, + .release_secctx = selinux_release_secctx, +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/selinux/include/security.h.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/selinux/include/security.h +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/selinux/include/security.h.orig 2012-11-30 09:16:55.312835507 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/selinux/include/security.h 2012-12-03 10:53:55.715785429 -0500 +@@ -171,6 +171,8 @@ int security_get_allow_unknown(void); + #define SECURITY_FS_USE_GENFS 4 /* use the genfs support */ + #define SECURITY_FS_USE_NONE 5 /* no labeling support */ + #define SECURITY_FS_USE_MNTPOINT 6 /* use mountpoint labeling */ ++#define SECURITY_FS_USE_NATIVE 7 /* use native label support */ ++#define SECURITY_FS_USE_MAX 7 /* Highest SECURITY_FS_USE_XXX */ + + int security_fs_use(const char *fstype, unsigned int *behavior, + u32 *sid); +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/selinux/ss/policydb.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/selinux/ss/policydb.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/selinux/ss/policydb.c.orig 2012-09-30 19:47:46.000000000 -0400 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/selinux/ss/policydb.c 2012-12-03 10:53:55.716785430 -0500 +@@ -2168,7 +2168,10 @@ static int ocontext_read(struct policydb + + rc = -EINVAL; + c->v.behavior = le32_to_cpu(buf[0]); +- if (c->v.behavior > SECURITY_FS_USE_NONE) ++ /* Determined at runtime, not in policy DB. */ ++ if (c->v.behavior == SECURITY_FS_USE_MNTPOINT) ++ goto out; ++ if (c->v.behavior > SECURITY_FS_USE_MAX) + goto out; + + rc = -ENOMEM; +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/smack/smack_lsm.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/smack/smack_lsm.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/smack/smack_lsm.c.orig 2012-11-29 16:37:30.025914150 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc19.x86_64/security/smack/smack_lsm.c 2012-12-03 10:53:55.718785432 -0500 +@@ -3335,6 +3335,16 @@ static void smack_audit_rule_free(void * + #endif /* CONFIG_AUDIT */ + + /** ++ * smack_ismaclabel - check if xattr @name references a smack MAC label ++ * @name: Full xattr name to check. ++ */ ++static int smack_ismaclabel(const char *name) ++{ ++ return (strcmp(name, XATTR_SMACK_SUFFIX) == 0); ++} ++ ++ ++/** + * smack_secid_to_secctx - return the smack label for a secid + * @secid: incoming integer + * @secdata: destination +@@ -3530,6 +3540,7 @@ struct security_operations smack_ops = { + .audit_rule_free = smack_audit_rule_free, + #endif /* CONFIG_AUDIT */ + ++ .ismaclabel = smack_ismaclabel, + .secid_to_secctx = smack_secid_to_secctx, + .secctx_to_secid = smack_secctx_to_secid, + .release_secctx = smack_release_secctx, diff --git a/lnfs-unset-3.7.0-0.rc7.git1.2.fc19.patch b/lnfs-unset-3.7.0-0.rc7.git1.2.fc19.patch new file mode 100644 index 000000000..2a1d7641e --- /dev/null +++ b/lnfs-unset-3.7.0-0.rc7.git1.2.fc19.patch @@ -0,0 +1,124 @@ +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc17.x86_64/fs/nfs/nfs4proc.c.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc17.x86_64/fs/nfs/nfs4proc.c +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc17.x86_64/fs/nfs/nfs4proc.c.orig 2012-12-03 10:58:51.086841436 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc17.x86_64/fs/nfs/nfs4proc.c 2012-12-03 11:34:01.065752872 -0500 +@@ -925,8 +925,8 @@ err_free_label: + #ifdef CONFIG_NFS_V4_SECURITY_LABEL + if (server->caps & NFS_CAP_SECURITY_LABEL) + nfs4_label_free(p->f_label); +-#endif + err_free_p: ++#endif + kfree(p); + err: + dput(parent); +@@ -2440,9 +2440,10 @@ static struct inode * + nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr) + { + struct nfs4_state *state; +- struct nfs4_label l, *label = NULL; +- ++ struct nfs4_label *label = NULL; + #ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ struct nfs4_label l; ++ + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) { + struct dentry *dentry = ctx->dentry; + int error; +@@ -3028,8 +3029,8 @@ static int _nfs4_proc_access(struct inod + #ifdef CONFIG_NFS_V4_SECURITY_LABEL + if (server->caps & NFS_CAP_SECURITY_LABEL) + nfs4_label_free(res.label); +-#endif + out: ++#endif + nfs_free_fattr(res.fattr); + return status; + } +@@ -3107,7 +3108,10 @@ static int + nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, + int flags) + { +- struct nfs4_label l, *ilabel = NULL; ++ struct nfs4_label *ilabel = NULL; ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ struct nfs4_label l; ++#endif + struct nfs_open_context *ctx; + struct nfs4_state *state; + int status = 0; +@@ -3300,8 +3304,8 @@ static int _nfs4_proc_rename(struct inod + nfs4_label_free(res.old_label); + nfs4_label_free(res.new_label); + } +-#endif + out: ++#endif + return status; + } + +@@ -3420,7 +3424,9 @@ static struct nfs4_createdata *nfs4_allo + nfs_fattr_init(data->res.fattr); + } + return data; ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL + out_free: ++#endif + kfree(data); + return NULL; + } +@@ -3476,11 +3482,11 @@ static int nfs4_proc_symlink(struct inod + struct page *page, unsigned int len, struct iattr *sattr) + { + struct nfs4_exception exception = { }; +- struct nfs4_label l, *label = NULL; + int err; +- +- ++ struct nfs4_label *label = NULL; + #ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ struct nfs4_label l; ++ + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) { + err = security_dentry_init_security(dentry, sattr->ia_mode, + &dentry->d_name, &l.label, &l.len); +@@ -3524,7 +3530,10 @@ static int nfs4_proc_mkdir(struct inode + struct iattr *sattr) + { + struct nfs4_exception exception = { }; +- struct nfs4_label l, *label = NULL; ++ struct nfs4_label *label = NULL; ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ struct nfs4_label l; ++#endif + int err; + + #ifdef CONFIG_NFS_V4_SECURITY_LABEL +@@ -3642,9 +3651,12 @@ out: + static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, + struct iattr *sattr, dev_t rdev) + { +- struct nfs4_exception exception = { }; +- struct nfs4_label l, *label = NULL; + int err; ++ struct nfs4_exception exception = { }; ++ struct nfs4_label *label = NULL; ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++ struct nfs4_label l; ++#endif + + #ifdef CONFIG_NFS_V4_SECURITY_LABEL + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) { +diff -up linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc17.x86_64/include/linux/nfs_fs.h.orig linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc17.x86_64/include/linux/nfs_fs.h +--- linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc17.x86_64/include/linux/nfs_fs.h.orig 2012-12-03 11:08:32.524060597 -0500 ++++ linux-3.7.0-0.rc7.git1.2.lnfs37rc2.fc17.x86_64/include/linux/nfs_fs.h 2012-12-03 11:09:38.431071109 -0500 +@@ -502,8 +502,8 @@ extern void nfs4_label_init(struct nfs4_ + extern void nfs4_label_free(struct nfs4_label *); + #else + static inline struct nfs4_label *nfs4_label_alloc(gfp_t flags) { return NULL; } +-static inline void nfs4_label_init(struct nfs4_label *) {} +-static inline void nfs4_label_free(struct nfs4_label *label) {} ++static inline void nfs4_label_init(void *label) {} ++static inline void nfs4_label_free(void *label) {} + #endif + + /*