From ea57d29b2dbaa4268d1017773c5ee6e0b9aab4a1 Mon Sep 17 00:00:00 2001 From: Steve Dickson Date: Feb 20 2013 20:56:41 +0000 Subject: Added the latest label NFS code Signed-off-by: Steve Dickson --- diff --git a/config-x86-generic b/config-x86-generic index e8335a2..0adb915 100644 --- a/config-x86-generic +++ b/config-x86-generic @@ -434,3 +434,7 @@ CONFIG_MODULE_SIG_SHA256=y # CONFIG_MODULE_SIG_FORCE is not set CONFIG_MODULE_SIG_BLACKLIST=y CONFIG_MODULE_SIG_UEFI=y + +CONFIG_NFS_V4_SECURITY_LABEL=y +CONFIG_NFSD_V4_SECURITY_LABEL=y + diff --git a/kernel.spec b/kernel.spec index 857b4ce..7121cd6 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 .lnfs ################################################################### # The buildid can also be specified on the rpmbuild command line @@ -694,6 +694,7 @@ Patch2901: v4l-dvb-experimental.patch # fs fixes # NFSv4 +Patch4000: lnfs-3.8.0-2.patch # patches headed upstream Patch10000: fs-proc-devtree-remove_proc_entry.patch @@ -1336,6 +1337,7 @@ ApplyPatch arm-imx-fixdrm.patch # eCryptfs # NFSv4 +ApplyPatch lnfs-3.8.0-2.patch # USB diff --git a/lnfs-3.8.0-2.patch b/lnfs-3.8.0-2.patch new file mode 100644 index 0000000..837d00d --- /dev/null +++ b/lnfs-3.8.0-2.patch @@ -0,0 +1,3819 @@ +diff -up linux-3.8.0-2.fc19.x86_64/fs/nfs/client.c.orig linux-3.8.0-2.fc19.x86_64/fs/nfs/client.c +--- linux-3.8.0-2.fc19.x86_64/fs/nfs/client.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfs/client.c 2013-02-19 15:09:09.204816000 -0500 +@@ -1075,7 +1075,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.8.0-2.fc19.x86_64/fs/nfs/dir.c.orig linux-3.8.0-2.fc19.x86_64/fs/nfs/dir.c +--- linux-3.8.0-2.fc19.x86_64/fs/nfs/dir.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfs/dir.c 2013-02-19 15:09:09.211815000 -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 { + if (d_invalidate(dentry) != 0) +@@ -460,7 +460,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; + +@@ -585,10 +585,16 @@ int nfs_readdir_xdr_to_array(nfs_readdir + if (entry.fh == NULL || entry.fattr == NULL) + goto out; + ++ entry.label = nfs4_label_alloc(NFS_SERVER(inode), GFP_NOWAIT); ++ if (IS_ERR(entry.label)) { ++ status = PTR_ERR(entry.label); ++ goto out; ++ } ++ + array = nfs_readdir_get_array(page); + if (IS_ERR(array)) { + status = PTR_ERR(array); +- goto out; ++ goto out_label_free; + } + memset(array, 0, sizeof(struct nfs_cache_array)); + array->eof_index = -1; +@@ -614,6 +620,8 @@ int nfs_readdir_xdr_to_array(nfs_readdir + nfs_readdir_free_large_page(pages_ptr, pages, array_size); + out_release_array: + nfs_readdir_release_array(page); ++out_label_free: ++ nfs4_label_free(entry.label); + out: + nfs_free_fattr(entry.fattr); + nfs_free_fhandle(entry.fh); +@@ -1040,6 +1048,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) +@@ -1082,16 +1091,22 @@ 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); ++ label = nfs4_label_alloc(NFS_SERVER(inode), GFP_NOWAIT); ++ if (IS_ERR(label)) ++ goto out_error; ++ ++ 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); ++ nfs4_label_free(label); ++ + out_set_verifier: + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); + out_valid: +@@ -1108,6 +1123,7 @@ out_zap_parent: + out_bad: + nfs_free_fattr(fattr); + nfs_free_fhandle(fhandle); ++ nfs4_label_free(label); + nfs_mark_for_revalidate(dir); + if (inode && S_ISDIR(inode->i_mode)) { + /* Purge readdir caches. */ +@@ -1128,6 +1144,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, +@@ -1216,6 +1233,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", +@@ -1242,17 +1260,21 @@ struct dentry *nfs_lookup(struct inode * + if (fhandle == NULL || fattr == NULL) + goto out; + ++ label = nfs4_label_alloc(NFS_SERVER(dir), GFP_NOWAIT); ++ if (IS_ERR(label)) ++ goto out; ++ + 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; +@@ -1270,6 +1292,7 @@ no_entry: + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); + out_unblock_sillyrename: + nfs_unblock_sillyrename(parent); ++ nfs4_label_free(label); + out: + nfs_free_fattr(fattr); + nfs_free_fhandle(fhandle); +@@ -1486,7 +1509,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; +@@ -1499,18 +1523,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.8.0-2.fc19.x86_64/fs/nfsd/Kconfig.orig linux-3.8.0-2.fc19.x86_64/fs/nfsd/Kconfig +--- linux-3.8.0-2.fc19.x86_64/fs/nfsd/Kconfig.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfsd/Kconfig 2013-02-19 15:09:09.286819000 -0500 +@@ -81,6 +81,22 @@ 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. ++ ++ WARNING: there is still a chance of backwards-incompatible protocol changes. ++ For now we recommend "Y" only for developers and testers." ++ + config NFSD_FAULT_INJECTION + bool "NFS server manual fault injection" + depends on NFSD_V4 && DEBUG_KERNEL +diff -up linux-3.8.0-2.fc19.x86_64/fs/nfsd/nfs4proc.c.orig linux-3.8.0-2.fc19.x86_64/fs/nfsd/nfs4proc.c +--- linux-3.8.0-2.fc19.x86_64/fs/nfsd/nfs4proc.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfsd/nfs4proc.c 2013-02-19 15:09:09.292818000 -0500 +@@ -42,6 +42,36 @@ + #include "current_stateid.h" + #include "netns.h" + ++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL ++#include ++ ++static inline void ++nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct nfs4_label *label, u32 *bmval) ++{ ++ struct inode *inode = resfh->fh_dentry->d_inode; ++ int status; ++ ++ mutex_lock(&inode->i_mutex); ++ status = security_inode_setsecctx(resfh->fh_dentry, ++ label->label, label->len); ++ mutex_unlock(&inode->i_mutex); ++ ++ if (status) ++ /* ++ * We should probably fail the whole open at this point, ++ * but we've already created or opened the file, so it's ++ * too late; So this seems the least of evils: ++ */ ++ bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL; ++ ++ return; ++} ++#else ++static inline void ++nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct nfs4_label *label, u32 *bmval) ++{ } ++#endif ++ + #define NFSDDBG_FACILITY NFSDDBG_PROC + + static u32 nfsd_attrmask[] = { +@@ -230,6 +260,9 @@ do_open_lookup(struct svc_rqst *rqstp, s + (u32 *)open->op_verf.data, + &open->op_truncate, &open->op_created); + ++ if (!status && open->op_label != NULL) ++ nfsd4_security_inode_setsecctx(resfh, open->op_label, open->op_bmval); ++ + /* + * Following rfc 3530 14.2.16, use the returned bitmask + * to indicate which attributes we used to store the +@@ -599,6 +632,9 @@ nfsd4_create(struct svc_rqst *rqstp, str + if (status) + goto out; + ++ if (create->cr_label != NULL) ++ nfsd4_security_inode_setsecctx(&resfh, create->cr_label, create->cr_bmval); ++ + if (create->cr_acl != NULL) + do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, + create->cr_bmval); +@@ -888,6 +924,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.8.0-2.fc19.x86_64/fs/nfsd/nfs4xdr.c.orig linux-3.8.0-2.fc19.x86_64/fs/nfsd/nfs4xdr.c +--- linux-3.8.0-2.fc19.x86_64/fs/nfsd/nfs4xdr.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfsd/nfs4xdr.c 2013-02-19 15:09:09.299819000 -0500 +@@ -55,6 +55,11 @@ + #include "cache.h" + #include "netns.h" + ++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL ++#include ++#endif ++ ++ + #define NFSDDBG_FACILITY NFSDDBG_XDR + + /* +@@ -79,6 +84,24 @@ check_filename(char *str, int len) + return nfserr_badname; + return 0; + } ++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL ++static struct nfs4_label *nfsd4_label_alloc(u32 len) ++{ ++ struct nfs4_label *label = NULL; ++ ++ if (len > NFS4_MAXLABELLEN) ++ return ERR_PTR(-ENAMETOOLONG); ++ ++ label = kzalloc(len + sizeof(struct nfs4_label), GFP_KERNEL); ++ if (label == NULL) ++ return ERR_PTR(-ENOMEM); ++ ++ label->label = (char *)(label + 1); ++ label->len = len; ++ ++ return label; ++} ++#endif + + #define DECODE_HEAD \ + __be32 *p; \ +@@ -242,7 +265,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; +@@ -386,6 +410,38 @@ 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); ++ ++ *label = nfsd4_label_alloc(dummy32); ++ if (*label == NULL) { ++ host_err = PTR_ERR(label); ++ goto out_nfserr; ++ } ++ ++ memcpy((*label)->label, buf, (*label)->len); ++ ((char *)(*label)->label)[(*label)->len] = '\0'; ++ (*label)->pi = pi; ++ (*label)->lfs = lfs; ++ ++ 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) +@@ -575,7 +631,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; + +@@ -825,7 +881,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; +@@ -839,7 +895,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; +@@ -1061,7 +1117,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 +@@ -1970,6 +2026,50 @@ 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; ++ ++ *pp = p; ++out: ++ security_release_secctx(context, len); ++ return err; ++} ++#else ++static inline __be32 ++nfsd4_encode_security_label(struct svc_rqst *rqstp, struct dentry *dentry, __be32 **pp, int *buflen) ++{ return 0; } ++#endif ++ + static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err) + { + /* As per referral draft: */ +@@ -2423,6 +2523,12 @@ out_acl: + get_parent_attributes(exp, &stat); + WRITE64(stat.ino); + } ++ if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { ++ status = nfsd4_encode_security_label(rqstp, dentry, ++ &p, &buflen); ++ if (status) ++ goto out; ++ } + if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { + WRITE32(3); + WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0); +diff -up linux-3.8.0-2.fc19.x86_64/fs/nfsd/nfsd.h.orig linux-3.8.0-2.fc19.x86_64/fs/nfsd/nfsd.h +--- linux-3.8.0-2.fc19.x86_64/fs/nfsd/nfsd.h.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfsd/nfsd.h 2013-02-19 15:09:09.304820000 -0500 +@@ -311,7 +311,11 @@ void nfsd_lockd_shutdown(void); + | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA \ + | FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID) + ++#ifdef CONFIG_NFSD_V4_SECURITY_LABEL ++#define NFSD4_SUPPORTED_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL ++#else + #define NFSD4_SUPPORTED_ATTRS_WORD2 0 ++#endif + + #define NFSD4_1_SUPPORTED_ATTRS_WORD0 \ + NFSD4_SUPPORTED_ATTRS_WORD0 +@@ -350,7 +354,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.8.0-2.fc19.x86_64/fs/nfsd/vfs.c.orig linux-3.8.0-2.fc19.x86_64/fs/nfsd/vfs.c +--- linux-3.8.0-2.fc19.x86_64/fs/nfsd/vfs.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfsd/vfs.c 2013-02-19 15:09:09.310819000 -0500 +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #ifdef CONFIG_NFSD_V3 + #include "xdr3.h" +@@ -621,6 +622,34 @@ 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; ++ ++ /* 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.8.0-2.fc19.x86_64/fs/nfsd/vfs.h.orig linux-3.8.0-2.fc19.x86_64/fs/nfsd/vfs.h +--- linux-3.8.0-2.fc19.x86_64/fs/nfsd/vfs.h.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfsd/vfs.h 2013-02-19 15:09:09.315825000 -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.8.0-2.fc19.x86_64/fs/nfsd/xdr4.h.orig linux-3.8.0-2.fc19.x86_64/fs/nfsd/xdr4.h +--- linux-3.8.0-2.fc19.x86_64/fs/nfsd/xdr4.h.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfsd/xdr4.h 2013-02-19 15:09:09.320825000 -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.8.0-2.fc19.x86_64/fs/nfs/getroot.c.orig linux-3.8.0-2.fc19.x86_64/fs/nfs/getroot.c +--- linux-3.8.0-2.fc19.x86_64/fs/nfs/getroot.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfs/getroot.c 2013-02-19 15:09:09.216816000 -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.8.0-2.fc19.x86_64/fs/nfs/inode.c.orig linux-3.8.0-2.fc19.x86_64/fs/nfs/inode.c +--- linux-3.8.0-2.fc19.x86_64/fs/nfs/inode.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfs/inode.c 2013-02-19 15:09:09.222816000 -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; + +@@ -162,11 +162,19 @@ 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; + nfs_fscache_invalidate(inode); +- } 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_DATA ++ | NFS_INO_INVALID_ACCESS ++ | NFS_INO_INVALID_ACL ++ | NFS_INO_REVAL_PAGECACHE; ++ } else ++ 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) +@@ -255,12 +263,60 @@ 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(struct nfs_server *server, gfp_t flags) ++{ ++ struct nfs4_label *label = NULL; ++ ++ if (!(server->caps & NFS_CAP_SECURITY_LABEL)) ++ return label; ++ ++ label = kzalloc(sizeof(struct nfs4_label), flags); ++ if (label == NULL) ++ return ERR_PTR(-ENOMEM); ++ ++ label->label = kzalloc(NFS4_MAXLABELLEN, flags); ++ if (label->label == NULL) { ++ kfree(label); ++ return ERR_PTR(-ENOMEM); ++ } ++ label->len = NFS4_MAXLABELLEN; ++ ++ return label; ++} ++EXPORT_SYMBOL_GPL(nfs4_label_alloc); ++#else ++void inline 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, +@@ -382,6 +438,9 @@ nfs_fhget(struct super_block *sb, struct + */ + inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); + } ++ ++ nfs_setsecurity(inode, fattr, label); ++ + nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); + nfsi->attrtimeo_timestamp = now; + nfsi->access_cache = RB_ROOT; +@@ -390,7 +449,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), +@@ -447,7 +506,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; +@@ -744,6 +803,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) + { +@@ -789,6 +849,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); + +@@ -806,7 +867,14 @@ __nfs_revalidate_inode(struct nfs_server + goto out; + + nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); +- status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr); ++ ++ label = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL); ++ if (IS_ERR(label)) { ++ status = PTR_ERR(label); ++ goto out; ++ } ++ ++ 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, +@@ -816,15 +884,15 @@ __nfs_revalidate_inode(struct nfs_server + if (!S_ISDIR(inode->i_mode)) + set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); + } +- goto out; ++ goto err_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, + (long long)NFS_FILEID(inode), status); +- goto out; ++ goto err_out; + } + + if (nfsi->cache_validity & NFS_INO_INVALID_ACL) +@@ -834,7 +902,9 @@ __nfs_revalidate_inode(struct nfs_server + inode->i_sb->s_id, + (long long)NFS_FILEID(inode)); + +- out: ++err_out: ++ nfs4_label_free(label); ++out: + nfs_free_fattr(fattr); + return status; + } +@@ -862,7 +932,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); +@@ -1176,10 +1247,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); + } + +@@ -1193,21 +1264,24 @@ 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); + ++ if (label && !status) ++ nfs_setsecurity(inode, fattr, label); ++ + 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); + +@@ -1218,7 +1292,7 @@ static int nfs_post_op_update_inode_lock + } + if ((fattr->valid & NFS_ATTR_FATTR) == 0) + return 0; +- return nfs_refresh_inode_locked(inode, fattr); ++ return nfs_refresh_inode_locked(inode, fattr, label); + } + + /** +@@ -1235,13 +1309,17 @@ 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); ++ if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) { ++ if (label && !status) ++ nfs_setsecurity(inode, fattr, label); ++ } + return status; + } + EXPORT_SYMBOL_GPL(nfs_post_op_update_inode); +@@ -1292,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; + } +@@ -1310,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); +@@ -1482,7 +1560,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; +@@ -1495,6 +1573,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.8.0-2.fc19.x86_64/fs/nfs/Kconfig.orig linux-3.8.0-2.fc19.x86_64/fs/nfs/Kconfig +--- linux-3.8.0-2.fc19.x86_64/fs/nfs/Kconfig.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfs/Kconfig 2013-02-19 15:09:09.198816000 -0500 +@@ -131,6 +131,24 @@ 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. ++ ++ WARNING: there is still a chance of backwards-incompatible protocol changes. ++ For now we recommend "Y" only for developers and testers." ++ ++ If unsure, say N. ++ + config ROOT_NFS + bool "Root file system on NFS" + depends on NFS_FS=y && IP_PNP +diff -up linux-3.8.0-2.fc19.x86_64/fs/nfs/namespace.c.orig linux-3.8.0-2.fc19.x86_64/fs/nfs/namespace.c +--- linux-3.8.0-2.fc19.x86_64/fs/nfs/namespace.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfs/namespace.c 2013-02-19 15:09:09.228817000 -0500 +@@ -280,7 +280,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.8.0-2.fc19.x86_64/fs/nfs/nfs3acl.c.orig linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs3acl.c +--- linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs3acl.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs3acl.c 2013-02-19 15:09:09.233817000 -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.8.0-2.fc19.x86_64/fs/nfs/nfs3proc.c.orig linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs3proc.c +--- linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs3proc.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs3proc.c 2013-02-19 15:09:09.239817000 -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.8.0-2.fc19.x86_64/fs/nfs/nfs4_fs.h.orig linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs4_fs.h +--- linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs4_fs.h.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs4_fs.h 2013-02-19 15:09:09.244821000 -0500 +@@ -225,7 +225,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[]; +@@ -291,10 +291,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.8.0-2.fc19.x86_64/fs/nfs/nfs4namespace.c.orig linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs4namespace.c +--- linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs4namespace.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs4namespace.c 2013-02-19 15:09:09.250817000 -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.8.0-2.fc19.x86_64/fs/nfs/nfs4proc.c.orig linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs4proc.c +--- linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs4proc.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs4proc.c 2013-02-19 15:09:09.260817000 -0500 +@@ -77,15 +77,49 @@ 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 *); + #endif ++ ++#ifdef CONFIG_NFS_V4_SECURITY_LABEL ++static inline struct nfs4_label * ++nfs4_label_init_security(struct inode *dir, struct dentry *dentry, ++ struct iattr *sattr, struct nfs4_label *l) ++{ ++ int err; ++ ++ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) { ++ err = security_dentry_init_security(dentry, sattr->ia_mode, ++ &dentry->d_name, (void **)&l->label, &l->len); ++ if (err == 0) ++ return l; ++ } ++ return NULL; ++} ++static inline void ++nfs4_label_release_security(struct nfs4_label *label) ++{ ++ if (label) ++ security_release_secctx(label->label, label->len); ++} ++#else ++static inline struct nfs4_label * ++nfs4_label_init_security(struct inode *dir, struct dentry *dentry, ++ struct iattr *sattr, struct nfs4_label *l) ++{ return NULL; } ++ ++static inline void ++nfs4_label_release_security(struct nfs4_label *label) ++{ return; } ++#endif ++ + /* Prevent leaks of NFSv4 errors into userland */ + static int nfs4_map_errors(int err) + { +@@ -130,7 +164,8 @@ 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, ++ FATTR4_WORD2_SECURITY_LABEL + }; + + static const u32 nfs4_pnfs_open_bitmap[3] = { +@@ -157,7 +192,7 @@ 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, +@@ -166,7 +201,7 @@ const u32 nfs4_statfs_bitmap[2] = { + | FATTR4_WORD1_SPACE_TOTAL + }; + +-const u32 nfs4_pathconf_bitmap[2] = { ++const u32 nfs4_pathconf_bitmap[3] = { + FATTR4_WORD0_MAXLINK + | FATTR4_WORD0_MAXNAME, + 0 +@@ -181,7 +216,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 +@@ -197,7 +232,7 @@ 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, + }; + + static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry, +@@ -747,6 +782,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; +@@ -762,6 +798,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; +@@ -772,7 +809,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); +@@ -783,9 +820,14 @@ static struct nfs4_opendata *nfs4_openda + p = kzalloc(sizeof(*p), gfp_mask); + if (p == NULL) + goto err; ++ ++ p->f_label = nfs4_label_alloc(server, gfp_mask); ++ if (IS_ERR(p->f_label)) ++ goto err_free_p; ++ + 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; +@@ -810,6 +852,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]; + +@@ -827,7 +870,10 @@ static struct nfs4_opendata *nfs4_openda + nfs4_init_opendata_res(p); + kref_init(&p->kref); + return p; +-err_free: ++ ++err_free_label: ++ nfs4_label_free(p->f_label); ++err_free_p: + kfree(p); + err: + dput(parent); +@@ -844,6 +890,9 @@ static void nfs4_opendata_free(struct kr + if (p->state != NULL) + nfs4_put_open_state(p->state); + nfs4_put_state_owner(p->owner); ++ ++ nfs4_label_free(p->f_label); ++ + dput(p->dir); + dput(p->dentry); + nfs_sb_deactive(sb); +@@ -1111,7 +1160,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; + +@@ -1141,7 +1190,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; +@@ -1191,7 +1240,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; +@@ -1694,7 +1743,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; + } + +@@ -1853,6 +1902,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) +@@ -1861,6 +1911,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 */ +@@ -1876,10 +1927,18 @@ 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; + ++ if (label) { ++ olabel = nfs4_label_alloc(server, GFP_KERNEL); ++ if (IS_ERR(olabel)) { ++ status = PTR_ERR(olabel); ++ goto err_opendata_put; ++ } ++ } ++ + if (ctx_th && server->attr_bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD) { + opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc(); + if (!opendata->f_attr.mdsthreshold) +@@ -1891,18 +1950,18 @@ static int _nfs4_do_open(struct inode *d + + status = _nfs4_proc_open(opendata); + if (status != 0) +- goto err_opendata_put; ++ goto err_free_label; + + state = nfs4_opendata_to_nfs4_state(opendata); + status = PTR_ERR(state); + if (IS_ERR(state)) +- goto err_opendata_put; ++ goto err_free_label; + if (server->caps & NFS_CAP_POSIX_LOCK) + set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); + + status = nfs4_opendata_access(cred, opendata, state, fmode, flags); + if (status != 0) +- goto err_opendata_put; ++ goto err_free_label; + + if (opendata->o_arg.open_flags & O_EXCL) { + nfs4_exclusive_attrset(opendata, sattr); +@@ -1910,10 +1969,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)) +@@ -1922,10 +1983,14 @@ static int _nfs4_do_open(struct inode *d + kfree(opendata->f_attr.mdsthreshold); + opendata->f_attr.mdsthreshold = NULL; + ++ nfs4_label_free(olabel); ++ + nfs4_opendata_put(opendata); + nfs4_put_state_owner(sp); + *res = state; + return 0; ++err_free_label: ++ nfs4_label_free(olabel); + err_opendata_put: + kfree(opendata->f_attr.mdsthreshold); + nfs4_opendata_put(opendata); +@@ -1942,6 +2007,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) + { +@@ -1951,7 +2017,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; +@@ -1996,7 +2062,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 = { +@@ -2004,9 +2071,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 = { +@@ -2018,6 +2087,9 @@ static int _nfs4_do_setattr(struct inode + unsigned long timestamp = jiffies; + int status; + ++ if (ilabel == NULL || olabel == NULL) ++ arg.bitmask = server->attr_bitmask_nl; ++ + nfs_fattr_init(fattr); + + if (state != NULL) { +@@ -2041,7 +2113,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 = { +@@ -2050,7 +2123,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)) { +@@ -2137,7 +2210,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); + } + +@@ -2244,7 +2317,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; +@@ -2274,10 +2347,16 @@ 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; ++ ++ label = nfs4_label_init_security(dir, ctx->dentry, attr, &l); + + /* 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); ++ ++ nfs4_label_release_security(label); ++ + if (IS_ERR(state)) + return ERR_CAST(state); + ctx->state = state; +@@ -2337,10 +2416,27 @@ 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; ++ ++ memcpy(server->attr_bitmask_nl, res.attr_bitmask, ++ sizeof(server->attr_bitmask)); ++ ++ if (server->caps & NFS_CAP_SECURITY_LABEL) ++ server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL; + + 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; + } +@@ -2363,8 +2459,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, +@@ -2377,6 +2474,13 @@ static int _nfs4_lookup_root(struct nfs_ + .rpc_resp = &res, + }; + ++ bitmask[0] = nfs4_fattr_bitmap[0]; ++ bitmask[1] = nfs4_fattr_bitmap[1]; ++ /* ++ * Process the label in the upcoming getfattr ++ */ ++ 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); + } +@@ -2475,6 +2579,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) { +@@ -2482,16 +2587,23 @@ static int nfs4_proc_get_root(struct nfs + return error; + } + +- error = nfs4_proc_getattr(server, mntfh, fattr); ++ label = nfs4_label_alloc(server, GFP_KERNEL); ++ if (IS_ERR(label)) ++ return PTR_ERR(label); ++ ++ error = nfs4_proc_getattr(server, mntfh, fattr, label); + if (error < 0) { + dprintk("nfs4_get_root: getattr error = %d\n", -error); +- return error; ++ goto err_free_label; + } + + if (fattr->valid & NFS_ATTR_FATTR_FSID && + !nfs_fsid_equal(&server->fsid, &fattr->fsid)) + memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid)); + ++err_free_label: ++ nfs4_label_free(label); ++ + return error; + } + +@@ -2538,7 +2650,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, +@@ -2546,6 +2659,7 @@ static int _nfs4_proc_getattr(struct nfs + }; + struct nfs4_getattr_res res = { + .fattr = fattr, ++ .label = label, + .server = server, + }; + struct rpc_message msg = { +@@ -2553,18 +2667,22 @@ static int _nfs4_proc_getattr(struct nfs + .rpc_argp = &args, + .rpc_resp = &res, + }; +- ++ ++ if (!label) ++ args.bitmask = server->attr_bitmask_nl; ++ + 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; +@@ -2594,6 +2712,7 @@ 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 *label = NULL; + int status; + + if (pnfs_ld_layoutret_on_setattr(inode)) +@@ -2620,15 +2739,21 @@ nfs4_proc_setattr(struct dentry *dentry, + } + } + +- status = nfs4_do_setattr(inode, cred, fattr, sattr, state); ++ label = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL); ++ if (IS_ERR(label)) ++ return PTR_ERR(label); ++ ++ status = nfs4_do_setattr(inode, cred, fattr, sattr, state, NULL, label); + if (status == 0) + nfs_setattr_update_inode(inode, sattr); ++ ++ nfs4_label_free(label); + return status; + } + + 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; +@@ -2640,6 +2765,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 = { +@@ -2648,6 +2774,9 @@ static int _nfs4_proc_lookup(struct rpc_ + .rpc_resp = &res, + }; + ++ if (label == NULL) ++ args.bitmask = server->attr_bitmask_nl; ++ + nfs_fattr_init(fattr); + + dprintk("NFS call lookup %s\n", name->name); +@@ -2666,13 +2795,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; +@@ -2706,12 +2835,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); +@@ -2721,12 +2851,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); +@@ -2743,6 +2874,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], +@@ -2751,7 +2883,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... +@@ -2774,11 +2906,21 @@ static int _nfs4_proc_access(struct inod + if (res.fattr == NULL) + return -ENOMEM; + ++ res.label = nfs4_label_alloc(server, GFP_KERNEL); ++ if (IS_ERR(res.label)) { ++ status = PTR_ERR(res.label); ++ goto out; ++ } ++ + 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); + } ++ ++ nfs4_label_free(res.label); ++ ++out: + nfs_free_fattr(res.fattr); + return status; + } +@@ -2856,6 +2998,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; +@@ -2864,9 +3007,11 @@ nfs4_proc_create(struct inode *dir, stru + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + ++ ilabel = nfs4_label_init_security(dir, dentry, sattr, &l); ++ + 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)) { +@@ -2877,6 +3022,7 @@ nfs4_proc_create(struct inode *dir, stru + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); + ctx->state = state; + out: ++ nfs4_label_release_security(ilabel); + put_nfs_open_context(ctx); + return status; + } +@@ -2925,6 +3071,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) +@@ -2990,6 +3138,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, +@@ -3000,12 +3150,33 @@ static int _nfs4_proc_rename(struct inod + .rpc_resp = &res, + }; + int status = -ENOMEM; ++ ++ ++ if (server->caps & NFS_CAP_SECURITY_LABEL) { ++ res.old_label = nfs4_label_alloc(server, GFP_NOWAIT); ++ if (IS_ERR(res.old_label)) { ++ status = PTR_ERR(res.old_label); ++ goto out; ++ } ++ res.new_label = nfs4_label_alloc(server, GFP_NOWAIT); ++ if (IS_ERR(res.new_label)) { ++ status = PTR_ERR(res.new_label); ++ nfs4_label_free(res.old_label); ++ goto out; ++ } ++ } ++ + + 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); + } ++ ++ nfs4_label_free(res.old_label); ++ nfs4_label_free(res.new_label); ++ ++out: + return status; + } + +@@ -3034,6 +3205,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], +@@ -3046,11 +3218,21 @@ static int _nfs4_proc_link(struct inode + if (res.fattr == NULL) + goto out; + ++ res.label = nfs4_label_alloc(server, GFP_KERNEL); ++ if (IS_ERR(res.label)) { ++ status = PTR_ERR(res.label); ++ goto out; ++ } ++ + 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); + } ++ ++ ++ nfs4_label_free(res.label); ++ + out: + nfs_free_fattr(res.fattr); + return status; +@@ -3074,6 +3256,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, +@@ -3085,6 +3268,10 @@ static struct nfs4_createdata *nfs4_allo + if (data != NULL) { + struct nfs_server *server = NFS_SERVER(dir); + ++ data->label = nfs4_label_alloc(server, GFP_KERNEL); ++ if (IS_ERR(data->label)) ++ goto out_free; ++ + data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE]; + data->msg.rpc_argp = &data->arg; + data->msg.rpc_resp = &data->res; +@@ -3097,9 +3284,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) +@@ -3108,18 +3299,20 @@ 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) + { ++ nfs4_label_free(data->label); + 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; +@@ -3135,6 +3328,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); + +@@ -3147,18 +3341,24 @@ 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; ++ ++ label = nfs4_label_init_security(dir, dentry, sattr, &l); ++ + do { + err = nfs4_handle_exception(NFS_SERVER(dir), + _nfs4_proc_symlink(dir, dentry, page, +- len, sattr), ++ len, sattr, label), + &exception); + } while (exception.retry); ++ ++ nfs4_label_release_security(label); + 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; +@@ -3167,6 +3367,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); +@@ -3178,14 +3379,19 @@ static int nfs4_proc_mkdir(struct inode + struct iattr *sattr) + { + struct nfs4_exception exception = { }; ++ struct nfs4_label l, *label = NULL; + int err; + ++ label = nfs4_label_init_security(dir, dentry, sattr, &l); ++ + 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); ++ nfs4_label_release_security(label); ++ + return err; + } + +@@ -3201,7 +3407,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, +@@ -3243,7 +3451,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; +@@ -3268,7 +3476,8 @@ static int _nfs4_proc_mknod(struct inode + status = -EINVAL; + goto out_free; + } +- ++ ++ data->arg.label = label; + status = nfs4_do_create(dir, dentry, data); + out_free: + nfs4_free_createdata(data); +@@ -3280,14 +3489,20 @@ 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; + ++ label = nfs4_label_init_security(dir, dentry, sattr, &l); ++ + 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); ++ ++ nfs4_label_release_security(label); ++ + return err; + } + +@@ -3503,7 +3718,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; +@@ -3928,6 +4147,178 @@ 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 = {0, 0, buflen, buf}; ++ 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; ++ ++ 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 = {0}; ++ 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; ++ ++ 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(NFS_SERVER(inode), GFP_KERNEL); ++ if (IS_ERR(olabel)) { ++ status = -PTR_ERR(olabel); ++ 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) + { +@@ -4216,7 +4607,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; +@@ -4240,7 +4631,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; +@@ -5059,6 +5450,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 + */ +@@ -5082,7 +5520,7 @@ 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, + }; + struct nfs4_fs_locations_arg args = { +@@ -6797,6 +7235,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.8.0-2.fc19.x86_64/fs/nfs/nfs4xdr.c.orig linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs4xdr.c +--- linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs4xdr.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfs/nfs4xdr.c 2013-02-19 15:09:09.269822000 -0500 +@@ -102,12 +102,23 @@ 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)) ++#define encode_readdir_space 24 ++#define encode_readdir_bitmask_sz 3 ++#else ++#define nfs4_label_maxsz 0 ++#define encode_readdir_space 20 ++#define encode_readdir_bitmask_sz 2 ++#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) +@@ -115,6 +126,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) +@@ -192,9 +204,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 + \ +@@ -972,7 +986,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]; +@@ -983,15 +999,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) +@@ -1021,6 +1038,8 @@ static void encode_attrs(struct xdr_stre + } + len += 4 + (XDR_QUADLEN(owner_grouplen) << 2); + } ++ if (label) ++ len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2); + if (iap->ia_valid & ATTR_ATIME_SET) + len += 16; + else if (iap->ia_valid & ATTR_ATIME) +@@ -1035,9 +1054,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; +@@ -1077,6 +1096,13 @@ static void encode_attrs(struct xdr_stre + bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET; + *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME); + } ++ 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); ++ } + + /* + * Now we backfill the bitmap and the attribute buffer length. +@@ -1086,9 +1112,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: */ +@@ -1142,7 +1169,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) +@@ -1194,8 +1221,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, +@@ -1373,21 +1402,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); +@@ -1566,20 +1597,34 @@ 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); +- p = reserve_space(xdr, 20); ++ p = reserve_space(xdr, encode_readdir_space); + *p++ = cpu_to_be32(dircount); + *p++ = cpu_to_be32(readdir->count); +- *p++ = cpu_to_be32(2); +- ++ *p++ = cpu_to_be32(encode_readdir_bitmask_sz); + *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]); +- *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]); ++ *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]); ++ if (encode_readdir_bitmask_sz > 2) { ++ p++, *p++ = cpu_to_be32(readdir->bitmask[2]); ++ } + 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) +@@ -1638,7 +1683,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 +4101,60 @@ 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 < NFS4_MAXLABELLEN) { ++ if (label) { ++ 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__, ++ (char *)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 +4497,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 +4605,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 +4617,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 +4636,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 +4648,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); + } + + /* +@@ -5879,7 +5984,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; + } +@@ -5905,7 +6010,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; + } +@@ -5934,7 +6039,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; + } +@@ -5960,7 +6065,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; + } +@@ -6051,7 +6157,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; + } +@@ -6080,7 +6186,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; + } +@@ -6112,7 +6218,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; + } +@@ -6214,7 +6320,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; + } +@@ -6245,7 +6351,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; + } +@@ -6295,7 +6401,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; + } +@@ -6322,7 +6428,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; + } +@@ -6502,7 +6608,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: +@@ -6683,7 +6789,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); +@@ -6716,7 +6822,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; + } +@@ -6997,7 +7103,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; + } +@@ -7129,7 +7235,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.8.0-2.fc19.x86_64/fs/nfs/proc.c.orig linux-3.8.0-2.fc19.x86_64/fs/nfs/proc.c +--- linux-3.8.0-2.fc19.x86_64/fs/nfs/proc.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfs/proc.c 2013-02-19 15:09:09.275818000 -0500 +@@ -98,7 +98,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], +@@ -146,7 +146,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), +@@ -243,7 +244,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); +@@ -290,7 +291,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); +@@ -442,7 +443,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); +@@ -471,7 +472,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); +@@ -607,7 +608,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.8.0-2.fc19.x86_64/fs/nfs/super.c.orig linux-3.8.0-2.fc19.x86_64/fs/nfs/super.c +--- linux-3.8.0-2.fc19.x86_64/fs/nfs/super.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/fs/nfs/super.c 2013-02-19 15:09:09.282818000 -0500 +@@ -877,6 +877,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); +@@ -2418,7 +2419,21 @@ 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; ++ if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL) ++ kflags |= SECURITY_LSM_NATIVE_LABELS; ++ ++ error = security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts, ++ kflags, &kflags_out); ++ if (error) ++ goto err; ++ ++ if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL && ++ !(kflags_out & SECURITY_LSM_NATIVE_LABELS)) ++ NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL; ++err: ++ return error; + } + EXPORT_SYMBOL_GPL(nfs_set_sb_security); + +diff -up linux-3.8.0-2.fc19.x86_64/include/linux/nfs4.h.orig linux-3.8.0-2.fc19.x86_64/include/linux/nfs4.h +--- linux-3.8.0-2.fc19.x86_64/include/linux/nfs4.h.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/include/linux/nfs4.h 2013-02-19 15:09:09.325819000 -0500 +@@ -28,6 +28,13 @@ struct nfs4_acl { + struct nfs4_ace aces[0]; + }; + ++struct nfs4_label { ++ uint32_t lfs; ++ uint32_t pi; ++ u32 len; ++ char *label; ++}; ++ + typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier; + + struct nfs_stateid4 { +@@ -373,6 +380,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.8.0-2.fc19.x86_64/include/linux/nfs_fs.h.orig linux-3.8.0-2.fc19.x86_64/include/linux/nfs_fs.h +--- linux-3.8.0-2.fc19.x86_64/include/linux/nfs_fs.h.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/include/linux/nfs_fs.h 2013-02-19 15:09:09.343825000 -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,24 @@ 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(struct nfs_server *server, gfp_t flags); ++static inline void nfs4_label_free(struct nfs4_label *label) ++{ ++ if (label) { ++ kfree(label->label); ++ kfree(label); ++ } ++ return; ++} ++#else ++static inline struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags) { return NULL; } ++static inline void nfs4_label_free(void *label) {} ++#endif ++ ++/* + * linux/fs/nfs/unlink.c + */ + extern void nfs_complete_unlink(struct dentry *dentry, struct inode *); +diff -up linux-3.8.0-2.fc19.x86_64/include/linux/nfs_fs_sb.h.orig linux-3.8.0-2.fc19.x86_64/include/linux/nfs_fs_sb.h +--- linux-3.8.0-2.fc19.x86_64/include/linux/nfs_fs_sb.h.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/include/linux/nfs_fs_sb.h 2013-02-19 15:09:09.362820000 -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,5 +204,6 @@ 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) + + #endif +diff -up linux-3.8.0-2.fc19.x86_64/include/linux/nfs_xdr.h.orig linux-3.8.0-2.fc19.x86_64/include/linux/nfs_xdr.h +--- linux-3.8.0-2.fc19.x86_64/include/linux/nfs_xdr.h.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/include/linux/nfs_xdr.h 2013-02-19 15:09:09.380821000 -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 +@@ -348,6 +350,7 @@ struct nfs_openargs { + const u32 * bitmask; + const u32 * open_bitmap; + __u32 claim; ++ const struct nfs4_label *label; + }; + + struct nfs_openres { +@@ -357,6 +360,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; +@@ -401,6 +405,7 @@ struct nfs_closeres { + struct nfs4_sequence_res seq_res; + nfs4_stateid stateid; + struct nfs_fattr * fattr; ++ struct nfs4_label *label; + struct nfs_seqid * seqid; + const struct nfs_server *server; + }; +@@ -474,6 +479,7 @@ struct nfs4_delegreturnargs { + struct nfs4_delegreturnres { + struct nfs4_sequence_res seq_res; + struct nfs_fattr * fattr; ++ struct nfs4_label *label; + const struct nfs_server *server; + }; + +@@ -494,6 +500,7 @@ struct nfs_readargs { + struct nfs_readres { + struct nfs4_sequence_res seq_res; + struct nfs_fattr * fattr; ++ struct nfs4_label *label; + __u32 count; + int eof; + }; +@@ -562,6 +569,7 @@ struct nfs_removeres { + struct nfs4_sequence_res seq_res; + const struct nfs_server *server; + struct nfs_fattr *dir_attr; ++ struct nfs4_label *dir_label; + struct nfs4_change_info cinfo; + }; + +@@ -574,6 +582,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 nfs_renameres { +@@ -581,8 +591,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; + }; + + /* +@@ -597,6 +609,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; + }; +@@ -629,6 +642,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 nfs_setaclargs { +@@ -664,6 +678,7 @@ struct nfs_getaclres { + struct nfs_setattrres { + struct nfs4_sequence_res seq_res; + struct nfs_fattr * fattr; ++ struct nfs4_label *label; + const struct nfs_server * server; + }; + +@@ -709,6 +724,7 @@ struct nfs3_setaclargs { + struct nfs_diropok { + struct nfs_fh * fh; + struct nfs_fattr * fattr; ++ struct nfs4_label *label; + }; + + struct nfs_readlinkargs { +@@ -839,6 +855,7 @@ struct nfs4_accessres { + struct nfs4_sequence_res seq_res; + const struct nfs_server * server; + struct nfs_fattr * fattr; ++ struct nfs4_label *label; + u32 supported; + u32 access; + }; +@@ -861,6 +878,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_create_res { +@@ -868,6 +886,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; + }; + +@@ -892,6 +911,7 @@ struct nfs4_getattr_res { + struct nfs4_sequence_res seq_res; + const struct nfs_server * server; + struct nfs_fattr * fattr; ++ struct nfs4_label *label; + }; + + struct nfs4_link_arg { +@@ -906,8 +926,10 @@ struct nfs4_link_res { + struct nfs4_sequence_res seq_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; + }; + + +@@ -923,6 +945,7 @@ struct nfs4_lookup_res { + const struct nfs_server * server; + struct nfs_fattr * fattr; + struct nfs_fh * fh; ++ struct nfs4_label *label; + }; + + struct nfs4_lookup_root_arg { +@@ -1376,11 +1399,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.8.0-2.fc19.x86_64/include/linux/security.h.orig linux-3.8.0-2.fc19.x86_64/include/linux/security.h +--- linux-3.8.0-2.fc19.x86_64/include/linux/security.h.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/include/linux/security.h 2013-02-19 15:09:09.400826000 -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. + * +@@ -1309,6 +1322,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. +@@ -1435,10 +1455,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); +@@ -1586,6 +1612,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); +@@ -1720,10 +1747,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); +@@ -1835,6 +1868,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); +@@ -2006,7 +2040,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; + } +@@ -2028,6 +2064,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, +@@ -2513,6 +2559,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.8.0-2.fc19.x86_64/include/uapi/linux/nfs4.h.orig linux-3.8.0-2.fc19.x86_64/include/uapi/linux/nfs4.h +--- linux-3.8.0-2.fc19.x86_64/include/uapi/linux/nfs4.h.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/include/uapi/linux/nfs4.h 2013-02-19 15:09:09.405822000 -0500 +@@ -25,7 +25,7 @@ + #define NFS4_MAXNAMLEN NAME_MAX + #define NFS4_OPAQUE_LIMIT 1024 + #define NFS4_MAX_SESSIONID_LEN 16 +- ++#define NFS4_MAXLABELLEN 128 + #define NFS4_ACCESS_READ 0x0001 + #define NFS4_ACCESS_LOOKUP 0x0002 + #define NFS4_ACCESS_MODIFY 0x0004 +diff -up linux-3.8.0-2.fc19.x86_64/security/capability.c.orig linux-3.8.0-2.fc19.x86_64/security/capability.c +--- linux-3.8.0-2.fc19.x86_64/security/capability.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/security/capability.c 2013-02-19 15:09:09.410822000 -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; +@@ -810,6 +820,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; +@@ -925,6 +940,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); +@@ -1028,6 +1044,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.8.0-2.fc19.x86_64/security/security.c.orig linux-3.8.0-2.fc19.x86_64/security/security.c +--- linux-3.8.0-2.fc19.x86_64/security/security.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/security/security.c 2013-02-19 15:09:09.416822000 -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) + { +@@ -1047,6 +1061,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.8.0-2.fc19.x86_64/security/selinux/hooks.c.orig linux-3.8.0-2.fc19.x86_64/security/selinux/hooks.c +--- linux-3.8.0-2.fc19.x86_64/security/selinux/hooks.c.orig 2013-02-19 15:08:03.746882000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/security/selinux/hooks.c 2013-02-19 15:09:09.424822000 -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) ++{ ++ const 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; +@@ -5430,6 +5493,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); +@@ -5572,6 +5640,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, +@@ -5667,6 +5736,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.8.0-2.fc19.x86_64/security/selinux/include/security.h.orig linux-3.8.0-2.fc19.x86_64/security/selinux/include/security.h +--- linux-3.8.0-2.fc19.x86_64/security/selinux/include/security.h.orig 2013-02-19 15:08:03.755880000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/security/selinux/include/security.h 2013-02-19 15:09:09.429823000 -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.8.0-2.fc19.x86_64/security/selinux/ss/policydb.c.orig linux-3.8.0-2.fc19.x86_64/security/selinux/ss/policydb.c +--- linux-3.8.0-2.fc19.x86_64/security/selinux/ss/policydb.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/security/selinux/ss/policydb.c 2013-02-19 15:09:09.435825000 -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.8.0-2.fc19.x86_64/security/smack/smack_lsm.c.orig linux-3.8.0-2.fc19.x86_64/security/smack/smack_lsm.c +--- linux-3.8.0-2.fc19.x86_64/security/smack/smack_lsm.c.orig 2013-02-18 18:58:34.000000000 -0500 ++++ linux-3.8.0-2.fc19.x86_64/security/smack/smack_lsm.c 2013-02-19 15:09:09.452825000 -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,