All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/17] lnfs: 3.9-rc8 release
@ 2013-04-24 20:17 Steve Dickson
  2013-04-24 20:17 ` [PATCH 01/17] NFSv4.2: Added v4.2 error codes Steve Dickson
                   ` (12 more replies)
  0 siblings, 13 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: Steve Dickson <steved@redhat.com>

Here is the next release of the Label NFS patches 
forward ported to linux-3.9-rc9.

The changes on this release are:

* Move the enabling of V4.2 patches to the front 
  of the series. 

* Changed nfsd_suppattrs2() to only give out minor version
  2 attrs on minor version 2 mounts.

* Fixed the return value of nfsd4_set_nfs4_label()
  when labels are not enabled.

* Made sure the sa_label point was initialized to NULL
  when labels are not enabled. 

* Added the encoding of the third bit mask in
  nfsd4_encode_setattr

The patches are on a git tree at
    git://fedorapeople.org/~steved/linux-steved lnfs-v3.9-rc8

David Quigley (12):
  Security: Add hook to calculate context based on a negative dentry.
  Security: Add Hook to test if the particular xattr is part of a MAC
    model.
  LSM: Add flags field to security_sb_set_mnt_opts for in kernel mount
    data.
  SELinux: Add new labeling type native labels
  NFSv4: Add label recommended attribute and NFSv4 flags
  NFSv4: Introduce new label structure
  NFSv4: Extend fattr bitmaps to support all 3 words
  NFS:Add labels to client function prototypes
  NFS: Add label lifecycle management
  NFS: Client implementation of Labeled-NFS
  NFS: Extend NFS xattr handlers to accept the security namespace
  NFSD: Server implementation of MAC Labeling

Steve Dickson (5):
  NFSv4.2: Added v4.2 error codes
  NFSv4.2: Added NFS v4.2 support to the NFS client
  NFSDv4.2: Added NFS v4.2 support to the NFS server
  Kconfig: Add Kconfig entry for Labeled NFS V4 client
  Kconfig: Add Kconfig entry for Labeled NFS V4 server

 fs/nfs/Kconfig                      |  28 ++
 fs/nfs/callback.c                   |   1 +
 fs/nfs/client.c                     |   2 +-
 fs/nfs/dir.c                        |  46 ++-
 fs/nfs/getroot.c                    |   2 +-
 fs/nfs/inode.c                      | 133 ++++++--
 fs/nfs/namespace.c                  |   2 +-
 fs/nfs/nfs3acl.c                    |   4 +-
 fs/nfs/nfs3proc.c                   |  41 +--
 fs/nfs/nfs4_fs.h                    |   8 +-
 fs/nfs/nfs4client.c                 |   5 +
 fs/nfs/nfs4namespace.c              |   2 +-
 fs/nfs/nfs4proc.c                   | 614 ++++++++++++++++++++++++++++++++----
 fs/nfs/nfs4xdr.c                    | 188 ++++++++---
 fs/nfs/pnfs.c                       |   2 +-
 fs/nfs/proc.c                       |  15 +-
 fs/nfs/super.c                      |  24 +-
 fs/nfsd/Kconfig                     |  16 +
 fs/nfsd/nfs4proc.c                  |  41 +++
 fs/nfsd/nfs4xdr.c                   | 122 ++++++-
 fs/nfsd/nfsd.h                      |  23 +-
 fs/nfsd/nfsproc.c                   |   1 +
 fs/nfsd/vfs.c                       |  28 ++
 fs/nfsd/vfs.h                       |   2 +
 fs/nfsd/xdr4.h                      |   3 +
 include/linux/nfs4.h                |  20 ++
 include/linux/nfs_fs.h              |  40 ++-
 include/linux/nfs_fs_sb.h           |  10 +-
 include/linux/nfs_xdr.h             |  30 +-
 include/linux/security.h            |  57 +++-
 include/uapi/linux/nfs4.h           |   2 +-
 security/capability.c               |  19 +-
 security/security.c                 |  24 +-
 security/selinux/hooks.c            |  92 +++++-
 security/selinux/include/security.h |   2 +
 security/selinux/ss/policydb.c      |   5 +-
 security/smack/smack_lsm.c          |  11 +
 37 files changed, 1447 insertions(+), 218 deletions(-)

-- 
1.8.1.4


^ permalink raw reply	[flat|nested] 71+ messages in thread

* [PATCH 01/17] NFSv4.2: Added v4.2 error codes
  2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
@ 2013-04-24 20:17 ` Steve Dickson
  2013-04-24 21:54   ` J. Bruce Fields
  2013-04-24 20:17 ` [PATCH 02/17] NFSv4.2: Added NFS v4.2 support to the NFS client Steve Dickson
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: Steve Dickson <steved@redhat.com>

Signed-off-by: Steve Dickson <steved@redhat.com>
---
 fs/nfsd/nfsd.h       | 6 ++++++
 fs/nfsd/nfsproc.c    | 1 +
 include/linux/nfs4.h | 8 ++++++++
 3 files changed, 15 insertions(+)

diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 07a473f..553b230 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -243,6 +243,12 @@ void		nfsd_lockd_shutdown(void);
 #define nfserr_reject_deleg		cpu_to_be32(NFS4ERR_REJECT_DELEG)
 #define nfserr_returnconflict		cpu_to_be32(NFS4ERR_RETURNCONFLICT)
 #define nfserr_deleg_revoked		cpu_to_be32(NFS4ERR_DELEG_REVOKED)
+#define nfserr_partner_notsupp		cpu_to_be32(NFS4ERR_PARTNER_NOTSUPP)
+#define nfserr_partner_no_auth		cpu_to_be32(NFS4ERR_PARTNER_NO_AUTH)
+#define nfserr_metadata_notsupp		cpu_to_be32(NFS4ERR_METADATA_NOTSUPP)
+#define nfserr_offload_denied		cpu_to_be32(NFS4ERR_OFFLOAD_DENIED)
+#define nfserr_wrong_lfs		cpu_to_be32(NFS4ERR_WRONG_LFS)
+#define nfs4err_badlabel		cpu_to_be32(NFS4ERR_BADLABEL)
 
 /* error codes for internal use */
 /* if a request fails due to kmalloc failure, it gets dropped.
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 54c6b3d..85289a5 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -743,6 +743,7 @@ nfserrno (int errno)
 		{ nfserr_notsupp, -EOPNOTSUPP },
 		{ nfserr_toosmall, -ETOOSMALL },
 		{ nfserr_serverfault, -ESERVERFAULT },
+		{ nfs4err_badlabel, -EMSGSIZE },
 	};
 	int	i;
 
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 7b8fc73..377fb3f 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -219,6 +219,14 @@ enum nfsstat4 {
 	NFS4ERR_REJECT_DELEG	= 10085,	/* on callback */
 	NFS4ERR_RETURNCONFLICT	= 10086,	/* outstanding layoutreturn */
 	NFS4ERR_DELEG_REVOKED	= 10087,	/* deleg./layout revoked */
+
+	/* nfs42 */
+	NFS4ERR_PARTNER_NOTSUPP	= 10088,
+	NFS4ERR_PARTNER_NO_AUTH	= 10089,
+	NFS4ERR_METADATA_NOTSUPP = 10090,
+	NFS4ERR_OFFLOAD_DENIED = 10091,
+	NFS4ERR_WRONG_LFS = 10092,
+	NFS4ERR_BADLABEL = 10093,
 };
 
 static inline bool seqid_mutating_err(u32 err)
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 02/17] NFSv4.2: Added NFS v4.2 support to the NFS client
  2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
  2013-04-24 20:17 ` [PATCH 01/17] NFSv4.2: Added v4.2 error codes Steve Dickson
@ 2013-04-24 20:17 ` Steve Dickson
  2013-04-24 21:56   ` J. Bruce Fields
  2013-04-24 20:17 ` [PATCH 03/17] NFSDv4.2: Added NFS v4.2 support to the NFS server Steve Dickson
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: Steve Dickson <steved@redhat.com>

This enable NFSv4.2 support. To enable this code the
CONFIG_NFS_V4_2 Kconfig define needs to be set and
the -o v4.2 mount option need to be used.

Signed-off-by: Steve Dickson <steved@redhat.com>
---
 fs/nfs/Kconfig       |  9 +++++++++
 fs/nfs/callback.c    |  1 +
 fs/nfs/nfs4client.c  |  5 +++++
 fs/nfs/nfs4proc.c    | 15 +++++++++++++++
 fs/nfs/super.c       |  7 ++++++-
 include/linux/nfs4.h |  4 ++++
 6 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index 13ca196..79c500e 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -104,6 +104,15 @@ config NFS_V4_1
 
 	  If unsure, say N.
 
+config NFS_V4_2
+	bool "NFS client support for NFSv4.2"
+	depends on NFS_V4_1
+	help
+	  This option enables support for minor version 1 of the NFSv4 protocol
+	  in the kernel's NFS client.
+
+	  If unsure, say N.
+
 config PNFS_FILE_LAYOUT
 	tristate
 	depends on NFS_V4_1
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 5088b57..cb35747 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -279,6 +279,7 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, struct n
 			ret = nfs4_callback_up_net(serv, net);
 			break;
 		case 1:
+		case 2:
 			ret = nfs41_callback_up_net(serv, net);
 			break;
 		default:
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 66b6664..a30c6a7 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -66,6 +66,11 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
 	if (err)
 		goto error;
 
+	if (cl_init->minorversion > NFS4_MAX_MINOR_VERSION) {
+		err = -EINVAL;
+		goto error;
+	}
+		
 	spin_lock_init(&clp->cl_lock);
 	INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
 	rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 0ad025e..3fd1040 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -6746,11 +6746,26 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
 };
 #endif
 
+#if defined(CONFIG_NFS_V4_2)
+static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
+	.minor_version = 2,
+	.call_sync = nfs4_call_sync_sequence,
+	.match_stateid = nfs41_match_stateid,
+	.find_root_sec = nfs41_find_root_sec,
+	.reboot_recovery_ops = &nfs41_reboot_recovery_ops,
+	.nograce_recovery_ops = &nfs41_nograce_recovery_ops,
+	.state_renewal_ops = &nfs41_state_renewal_ops,
+};
+#endif
+
 const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
 	[0] = &nfs_v4_0_minor_ops,
 #if defined(CONFIG_NFS_V4_1)
 	[1] = &nfs_v4_1_minor_ops,
 #endif
+#if defined(CONFIG_NFS_V4_2)
+	[2] = &nfs_v4_2_minor_ops,
+#endif
 };
 
 const struct inode_operations nfs4_dir_inode_operations = {
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 2f8a29d..29f2d86 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -269,7 +269,7 @@ static match_table_t nfs_local_lock_tokens = {
 
 enum {
 	Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0,
-	Opt_vers_4_1,
+	Opt_vers_4_1, Opt_vers_4_2,
 
 	Opt_vers_err
 };
@@ -280,6 +280,7 @@ static match_table_t nfs_vers_tokens = {
 	{ Opt_vers_4, "4" },
 	{ Opt_vers_4_0, "4.0" },
 	{ Opt_vers_4_1, "4.1" },
+	{ Opt_vers_4_2, "4.2" },
 
 	{ Opt_vers_err, NULL }
 };
@@ -1097,6 +1098,10 @@ static int nfs_parse_version_string(char *string,
 		mnt->version = 4;
 		mnt->minorversion = 1;
 		break;
+	case Opt_vers_4_2:
+		mnt->version = 4;
+		mnt->minorversion = 2;
+		break;
 	default:
 		return 0;
 	}
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 377fb3f..7e18a66 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -398,11 +398,15 @@ enum lock_type4 {
 #define NFS4_VERSION 4
 #define NFS4_MINOR_VERSION 0
 
+#if defined(CONFIG_NFS_V4_2)
+#define NFS4_MAX_MINOR_VERSION 2
+#else
 #if defined(CONFIG_NFS_V4_1)
 #define NFS4_MAX_MINOR_VERSION 1
 #else
 #define NFS4_MAX_MINOR_VERSION 0
 #endif /* CONFIG_NFS_V4_1 */
+#endif /* CONFIG_NFS_V4_2 */
 
 #define NFS4_DEBUG 1
 
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 03/17] NFSDv4.2: Added NFS v4.2 support to the NFS server
  2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
  2013-04-24 20:17 ` [PATCH 01/17] NFSv4.2: Added v4.2 error codes Steve Dickson
  2013-04-24 20:17 ` [PATCH 02/17] NFSv4.2: Added NFS v4.2 support to the NFS client Steve Dickson
@ 2013-04-24 20:17 ` Steve Dickson
  2013-04-24 22:02   ` J. Bruce Fields
  2013-04-24 20:17 ` [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry Steve Dickson
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: Steve Dickson <steved@redhat.com>

This enable NFSv4.2 support for the server. To enable this
code do the following:
  echo "+4.2" >/proc/fs/nfsd/versions

after the nfsd kernel module is loaded.

Signed-off-by: Steve Dickson <steved@redhat.com>
---
 fs/nfsd/nfs4xdr.c | 1 +
 fs/nfsd/nfsd.h    | 7 ++++++-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index a272007..b38de7a 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1572,6 +1572,7 @@ struct nfsd4_minorversion_ops {
 static struct nfsd4_minorversion_ops nfsd4_minorversion[] = {
 	[0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) },
 	[1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
+	[2] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
 };
 
 static __be32
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 553b230..b5eade7 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -24,7 +24,7 @@
 /*
  * nfsd version
  */
-#define NFSD_SUPPORTED_MINOR_VERSION	1
+#define NFSD_SUPPORTED_MINOR_VERSION	2
 /*
  * Maximum blocksizes supported by daemon under various circumstances.
  */
@@ -328,6 +328,8 @@ void		nfsd_lockd_shutdown(void);
 #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \
 	(NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT)
 
+#define NFSD4_2_SUPPORTED_ATTRS_WORD2 0
+
 static inline u32 nfsd_suppattrs0(u32 minorversion)
 {
 	return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0
@@ -342,6 +344,9 @@ static inline u32 nfsd_suppattrs1(u32 minorversion)
 
 static inline u32 nfsd_suppattrs2(u32 minorversion)
 {
+	if (minorversion == 2)
+		return NFSD4_2_SUPPORTED_ATTRS_WORD2;
+
 	return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2
 			    : NFSD4_SUPPORTED_ATTRS_WORD2;
 }
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
  2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
                   ` (2 preceding siblings ...)
  2013-04-24 20:17 ` [PATCH 03/17] NFSDv4.2: Added NFS v4.2 support to the NFS server Steve Dickson
@ 2013-04-24 20:17 ` Steve Dickson
  2013-04-24 22:02   ` J. Bruce Fields
  2013-04-24 20:17 ` [PATCH 06/17] LSM: Add flags field to security_sb_set_mnt_opts for in kernel mount data Steve Dickson
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl@davequigley.com>

There is a time where we need to calculate a context without the
inode having been created yet. To do this we take the negative dentry and
calculate a context based on the process and the parent directory contexts.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
---
 include/linux/security.h | 27 +++++++++++++++++++++++++++
 security/capability.c    |  8 ++++++++
 security/security.c      | 10 ++++++++++
 security/selinux/hooks.c | 35 +++++++++++++++++++++++++++++++++++
 4 files changed, 80 insertions(+)

diff --git a/include/linux/security.h b/include/linux/security.h
index 032c366..f3d7956 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -26,6 +26,7 @@
 #include <linux/capability.h>
 #include <linux/slab.h>
 #include <linux/err.h>
+#include <linux/string.h>
 
 struct linux_binprm;
 struct cred;
@@ -306,6 +307,15 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *	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.
  *
@@ -1443,6 +1453,10 @@ struct security_operations {
 	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);
@@ -1729,6 +1743,9 @@ int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *o
 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);
@@ -2033,6 +2050,16 @@ static inline int security_inode_alloc(struct inode *inode)
 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,
diff --git a/security/capability.c b/security/capability.c
index 6783c3e..782045e 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -108,6 +108,13 @@ static int cap_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
 	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;
@@ -930,6 +937,7 @@ void __init security_fixup_ops(struct security_operations *ops)
 	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);
diff --git a/security/security.c b/security/security.c
index 03f248b..7c18e3c 100644
--- a/security/security.c
+++ b/security/security.c
@@ -12,6 +12,7 @@
  */
 
 #include <linux/capability.h>
+#include <linux/dcache.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -324,6 +325,15 @@ void security_inode_free(struct inode *inode)
 	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)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 7171a95..622b205 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2484,6 +2484,40 @@ static void selinux_inode_free_security(struct inode *inode)
 	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)
@@ -5531,6 +5565,7 @@ static struct security_operations selinux_ops = {
 	.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,
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 05/17] Security: Add Hook to test if the particular xattr is part of a MAC model.
  2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
@ 2013-04-24 20:17     ` Steve Dickson
  2013-04-24 20:17 ` [PATCH 02/17] NFSv4.2: Added NFS v4.2 support to the NFS client Steve Dickson
                       ` (11 subsequent siblings)
  12 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl-a7DkhOHRHBuN9aS15agKxg@public.gmane.org>

The interface to request security labels from user space is the xattr
interface. When requesting the security label from an NFS server it is
important to make sure the requested xattr actually is a MAC label. This allows
us to make sure that we get the desired semantics from the attribute instead of
something else such as capabilities or a time based LSM.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM-geVtEqcQUv4Eyxwt80+Gtti2O/JbrIOy@public.gmane.org>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene-geVtEqcQUv4Eyxwt80+Gtti2O/JbrIOy@public.gmane.org>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG-geVtEqcQUv4Eyxwt80+Gtti2O/JbrIOy@public.gmane.org>
---
 include/linux/security.h   | 14 ++++++++++++++
 security/capability.c      |  6 ++++++
 security/security.c        |  6 ++++++
 security/selinux/hooks.c   |  6 ++++++
 security/smack/smack_lsm.c | 11 +++++++++++
 5 files changed, 43 insertions(+)

diff --git a/include/linux/security.h b/include/linux/security.h
index f3d7956..934f96f 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1323,6 +1323,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *	@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 1 if name is a MAC
+ *	attribute otherwise returns 0.
+ *	@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.
@@ -1604,6 +1611,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);
@@ -1857,6 +1865,7 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode);
 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);
@@ -2545,6 +2554,11 @@ static inline int security_netlink_send(struct sock *sk, struct sk_buff *skb)
 	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 --git a/security/capability.c b/security/capability.c
index 782045e..71e5052 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -822,6 +822,11 @@ static int cap_setprocattr(struct task_struct *p, char *name, void *value,
 	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;
@@ -1041,6 +1046,7 @@ void __init security_fixup_ops(struct security_operations *ops)
 	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 --git a/security/security.c b/security/security.c
index 7c18e3c..07391f3 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1057,6 +1057,12 @@ int security_netlink_send(struct sock *sk, struct sk_buff *skb)
 	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 --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 622b205..273e28b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5423,6 +5423,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);
@@ -5661,6 +5666,7 @@ static struct security_operations selinux_ops = {
 	.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 --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index fa64740..ca01d71 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -3329,6 +3329,16 @@ static void smack_audit_rule_free(void *vrule)
 #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
@@ -3524,6 +3534,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,
-- 
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 05/17] Security: Add Hook to test if the particular xattr is part of a MAC model.
@ 2013-04-24 20:17     ` Steve Dickson
  0 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl@davequigley.com>

The interface to request security labels from user space is the xattr
interface. When requesting the security label from an NFS server it is
important to make sure the requested xattr actually is a MAC label. This allows
us to make sure that we get the desired semantics from the attribute instead of
something else such as capabilities or a time based LSM.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
---
 include/linux/security.h   | 14 ++++++++++++++
 security/capability.c      |  6 ++++++
 security/security.c        |  6 ++++++
 security/selinux/hooks.c   |  6 ++++++
 security/smack/smack_lsm.c | 11 +++++++++++
 5 files changed, 43 insertions(+)

diff --git a/include/linux/security.h b/include/linux/security.h
index f3d7956..934f96f 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1323,6 +1323,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *	@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 1 if name is a MAC
+ *	attribute otherwise returns 0.
+ *	@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.
@@ -1604,6 +1611,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);
@@ -1857,6 +1865,7 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode);
 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);
@@ -2545,6 +2554,11 @@ static inline int security_netlink_send(struct sock *sk, struct sk_buff *skb)
 	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 --git a/security/capability.c b/security/capability.c
index 782045e..71e5052 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -822,6 +822,11 @@ static int cap_setprocattr(struct task_struct *p, char *name, void *value,
 	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;
@@ -1041,6 +1046,7 @@ void __init security_fixup_ops(struct security_operations *ops)
 	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 --git a/security/security.c b/security/security.c
index 7c18e3c..07391f3 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1057,6 +1057,12 @@ int security_netlink_send(struct sock *sk, struct sk_buff *skb)
 	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 --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 622b205..273e28b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5423,6 +5423,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);
@@ -5661,6 +5666,7 @@ static struct security_operations selinux_ops = {
 	.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 --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index fa64740..ca01d71 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -3329,6 +3329,16 @@ static void smack_audit_rule_free(void *vrule)
 #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
@@ -3524,6 +3534,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,
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 06/17] LSM: Add flags field to security_sb_set_mnt_opts for in kernel mount data.
  2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
                   ` (3 preceding siblings ...)
  2013-04-24 20:17 ` [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry Steve Dickson
@ 2013-04-24 20:17 ` Steve Dickson
  2013-04-24 22:03   ` J. Bruce Fields
  2013-04-24 20:17 ` [PATCH 07/17] SELinux: Add new labeling type native labels Steve Dickson
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl@davequigley.com>

There is no way to differentiate if a text mount option is passed from user
space or the kernel. A flags field is being added to the
security_sb_set_mnt_opts hook to allow for in kernel security flags to be sent
to the LSM for processing in addition to the text options received from mount.
This patch also updated existing code to fix compilation errors.

Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
---
 fs/nfs/super.c           |  3 ++-
 include/linux/security.h | 13 ++++++++++---
 security/capability.c    |  5 ++++-
 security/security.c      |  7 +++++--
 security/selinux/hooks.c | 12 ++++++++++--
 5 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 29f2d86..d84eb57 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2378,7 +2378,8 @@ static int nfs_bdi_register(struct nfs_server *server)
 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);
+	return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts,
+								0, NULL);
 }
 EXPORT_SYMBOL_GPL(nfs_set_sb_security);
 
diff --git a/include/linux/security.h b/include/linux/security.h
index 934f96f..4ab51e2 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1456,7 +1456,9 @@ 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);
@@ -1747,7 +1749,10 @@ int security_sb_mount(const char *dev_name, struct path *path,
 		      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);
@@ -2037,7 +2042,9 @@ static inline int security_sb_pivotroot(struct path *old_path,
 }
 
 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;
 }
diff --git a/security/capability.c b/security/capability.c
index 71e5052..4708973 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -91,7 +91,10 @@ static int cap_sb_pivotroot(struct path *old_path, struct path *new_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;
diff --git a/security/security.c b/security/security.c
index 07391f3..df8ade2 100644
--- a/security/security.c
+++ b/security/security.c
@@ -294,9 +294,12 @@ 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)
+				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);
 
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 273e28b..6cb24ec 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -552,7 +552,9 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
  * 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;
@@ -580,6 +582,12 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 			"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
@@ -949,7 +957,7 @@ static int superblock_doinit(struct super_block *sb, void *data)
 		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);
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 07/17] SELinux: Add new labeling type native labels
  2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
                   ` (4 preceding siblings ...)
  2013-04-24 20:17 ` [PATCH 06/17] LSM: Add flags field to security_sb_set_mnt_opts for in kernel mount data Steve Dickson
@ 2013-04-24 20:17 ` Steve Dickson
  2013-04-24 22:03   ` J. Bruce Fields
  2013-04-24 20:17 ` [PATCH 09/17] NFSv4: Introduce new label structure Steve Dickson
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl@davequigley.com>

There currently doesn't exist a labeling type that is adequate for use with
labeled NFS. Since NFS doesn't really support xattrs we can't use the use xattr
labeling behavior. For this we developed a new labeling type. The native
labeling type is used solely by NFS to ensure NFS inodes are labeled at runtime
by the NFS code instead of relying on the SELinux security server on the client
end.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
---
 include/linux/security.h            |  3 +++
 security/selinux/hooks.c            | 35 ++++++++++++++++++++++++++---------
 security/selinux/include/security.h |  2 ++
 security/selinux/ss/policydb.c      |  5 ++++-
 4 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index 4ab51e2..bc924d7 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -61,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;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 6cb24ec..d7ff806 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -81,6 +81,7 @@
 #include <linux/syslog.h>
 #include <linux/user_namespace.h>
 #include <linux/export.h>
+#include <linux/security.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
 
@@ -284,13 +285,14 @@ static void superblock_free_security(struct super_block *sb)
 
 /* 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);
@@ -678,14 +680,21 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 	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);
@@ -700,6 +709,11 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 	 * 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,
@@ -731,7 +745,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 	}
 
 	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");
@@ -1199,6 +1214,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
 	}
 
 	switch (sbsec->behavior) {
+	case SECURITY_FS_USE_NATIVE:
+		break;
 	case SECURITY_FS_USE_XATTR:
 		if (!inode->i_op->getxattr) {
 			isec->sid = sbsec->def_sid;
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 6d38851..8fd8e18 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -169,6 +169,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 --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 9cd9b7c..c8adde3 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -2168,7 +2168,10 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
 
 				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;
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 08/17] NFSv4: Add label recommended attribute and NFSv4 flags
  2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
@ 2013-04-24 20:17     ` Steve Dickson
  2013-04-24 20:17 ` [PATCH 02/17] NFSv4.2: Added NFS v4.2 support to the NFS client Steve Dickson
                       ` (11 subsequent siblings)
  12 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl-a7DkhOHRHBuN9aS15agKxg@public.gmane.org>

This patch adds several new flags to allow the NFS client and server to
determine if this attribute is supported and if it is being sent over the wire.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM-geVtEqcQUv4Eyxwt80+Gtti2O/JbrIOy@public.gmane.org>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene-geVtEqcQUv4Eyxwt80+Gtti2O/JbrIOy@public.gmane.org>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG-geVtEqcQUv4Eyxwt80+Gtti2O/JbrIOy@public.gmane.org>
---
 include/linux/nfs4.h      | 1 +
 include/linux/nfs_fs_sb.h | 1 +
 include/linux/nfs_xdr.h   | 4 +++-
 3 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 7e18a66..6f44cc1 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -385,6 +385,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 --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 6c6ed15..d507357 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -197,5 +197,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 --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 4b993d3..9f2dba3 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -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
-- 
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 08/17] NFSv4: Add label recommended attribute and NFSv4 flags
@ 2013-04-24 20:17     ` Steve Dickson
  0 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl@davequigley.com>

This patch adds several new flags to allow the NFS client and server to
determine if this attribute is supported and if it is being sent over the wire.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
---
 include/linux/nfs4.h      | 1 +
 include/linux/nfs_fs_sb.h | 1 +
 include/linux/nfs_xdr.h   | 4 +++-
 3 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 7e18a66..6f44cc1 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -385,6 +385,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 --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 6c6ed15..d507357 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -197,5 +197,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 --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 4b993d3..9f2dba3 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -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
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 09/17] NFSv4: Introduce new label structure
  2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
                   ` (5 preceding siblings ...)
  2013-04-24 20:17 ` [PATCH 07/17] SELinux: Add new labeling type native labels Steve Dickson
@ 2013-04-24 20:17 ` Steve Dickson
  2013-04-24 20:17 ` [PATCH 10/17] NFSv4: Extend fattr bitmaps to support all 3 words Steve Dickson
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl@davequigley.com>

In order to mimic the way that NFSv4 ACLs are implemented we have created a
structure to be used to pass label data up and down the call chain. This patch
adds the new structure and new members to the required NFSv4 call structures.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
---
 fs/nfs/inode.c            | 28 ++++++++++++++++++++++++++++
 include/linux/nfs4.h      |  7 +++++++
 include/linux/nfs_fs.h    | 18 ++++++++++++++++++
 include/linux/nfs_xdr.h   | 21 +++++++++++++++++++++
 include/uapi/linux/nfs4.h |  2 +-
 5 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 1f94167..c88255c 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -257,6 +257,34 @@ nfs_init_locked(struct inode *inode, void *opaque)
 	return 0;
 }
 
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags)
+{
+	struct nfs4_label *label = NULL;
+	int minor_version = server->nfs_client->cl_minorversion;
+
+	if (minor_version < 2)
+		return label;
+
+	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);
+#endif
+
 /*
  * This is our front-end to iget that looks up inodes by file handle
  * instead of inode number.
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 6f44cc1..4c61ef4 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -32,6 +32,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 {
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 1cc2568..e0e1806 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -489,6 +489,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 --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 9f2dba3..4d2fdf6 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -351,6 +351,7 @@ struct nfs_openargs {
 	const u32 *		bitmask;
 	const u32 *		open_bitmap;
 	__u32			claim;
+	const struct nfs4_label *label;
 };
 
 struct nfs_openres {
@@ -360,6 +361,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;
@@ -404,6 +406,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;
 };
@@ -477,6 +480,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;
 };
 
@@ -497,6 +501,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;
 };
@@ -565,6 +570,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;
 };
 
@@ -577,6 +583,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 {
@@ -584,8 +592,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;
 };
 
 /*
@@ -600,6 +610,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;
 };
@@ -632,6 +643,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 {
@@ -667,6 +679,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;
 };
 
@@ -712,6 +725,7 @@ struct nfs3_setaclargs {
 struct nfs_diropok {
 	struct nfs_fh *		fh;
 	struct nfs_fattr *	fattr;
+	struct nfs4_label	*label;
 };
 
 struct nfs_readlinkargs {
@@ -842,6 +856,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;
 };
@@ -864,6 +879,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 {
@@ -871,6 +887,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;
 };
 
@@ -895,6 +912,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 {
@@ -909,8 +927,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;
 };
 
 
@@ -926,6 +946,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 {
diff --git a/include/uapi/linux/nfs4.h b/include/uapi/linux/nfs4.h
index 788128e..78d25b5 100644
--- a/include/uapi/linux/nfs4.h
+++ b/include/uapi/linux/nfs4.h
@@ -25,7 +25,7 @@
 #define NFS4_MAXNAMLEN		NAME_MAX
 #define NFS4_OPAQUE_LIMIT	1024
 #define NFS4_MAX_SESSIONID_LEN	16
-
+#define NFS4_MAXLABELLEN	2048 
 #define NFS4_ACCESS_READ        0x0001
 #define NFS4_ACCESS_LOOKUP      0x0002
 #define NFS4_ACCESS_MODIFY      0x0004
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 10/17] NFSv4: Extend fattr bitmaps to support all 3 words
  2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
                   ` (6 preceding siblings ...)
  2013-04-24 20:17 ` [PATCH 09/17] NFSv4: Introduce new label structure Steve Dickson
@ 2013-04-24 20:17 ` Steve Dickson
  2013-04-24 20:17 ` [PATCH 12/17] NFS: Add label lifecycle management Steve Dickson
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl@davequigley.com>

The fattr handling bitmap code only uses the first two fattr words sofar. This
patch adds the 3rd word to being sent but doesn't populate it yet.

Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
---
 fs/nfs/nfs4_fs.h          |  6 +++---
 fs/nfs/nfs4proc.c         | 10 +++++-----
 fs/nfs/nfs4xdr.c          | 20 ++++++++++++--------
 fs/nfs/super.c            |  1 +
 include/linux/nfs_fs_sb.h |  2 +-
 5 files changed, 22 insertions(+), 17 deletions(-)

diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 944c9a5..1de30a8 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -295,10 +295,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 --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 3fd1040..5c50495 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -159,7 +159,7 @@ static const u32 nfs4_open_noattr_bitmap[3] = {
 	| 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,
@@ -168,7 +168,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
@@ -183,7 +183,7 @@ const u32 nfs4_fsinfo_bitmap[3] = { FATTR4_WORD0_MAXFILESIZE
 			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
@@ -199,7 +199,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,
@@ -5136,7 +5136,7 @@ static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
 				   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 = {
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index e3edda5..4fa0bf1 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -983,15 +983,16 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
 	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)
@@ -1035,9 +1036,9 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
 	 * 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;
@@ -1086,9 +1087,10 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
 				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: */
@@ -1194,8 +1196,10 @@ encode_getattr_three(struct xdr_stream *xdr,
 
 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,
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index d84eb57..00af026 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -833,6 +833,7 @@ int nfs_show_stats(struct seq_file *m, struct dentry *root)
 		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);
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index d507357..e6ed3c2 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -145,7 +145,7 @@ struct nfs_server {
 	u32			attr_bitmask[3];/* V4 bitmask representing the set
 						   of attributes supported on this
 						   filesystem */
-	u32			cache_consistency_bitmask[2];
+	u32			cache_consistency_bitmask[3];
 						/* V4 bitmask representing the subset
 						   of change attribute, size, ctime
 						   and mtime attributes supported by
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 11/17] NFS:Add labels to client function prototypes
  2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
@ 2013-04-24 20:17     ` Steve Dickson
  2013-04-24 20:17 ` [PATCH 02/17] NFSv4.2: Added NFS v4.2 support to the NFS client Steve Dickson
                       ` (11 subsequent siblings)
  12 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl-a7DkhOHRHBuN9aS15agKxg@public.gmane.org>

>From David Quigley <dpquigl-a7DkhOHRHBuN9aS15agKxg@public.gmane.org>

After looking at all of the nfsv4 operations the label structure has been added
to the prototypes of the functions which can transmit label data.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM-geVtEqcQUv4Eyxwt80+Gtti2O/JbrIOy@public.gmane.org>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene-geVtEqcQUv4Eyxwt80+Gtti2O/JbrIOy@public.gmane.org>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG-geVtEqcQUv4Eyxwt80+Gtti2O/JbrIOy@public.gmane.org>
---
 fs/nfs/client.c         |   2 +-
 fs/nfs/dir.c            |  23 +++++-----
 fs/nfs/getroot.c        |   2 +-
 fs/nfs/inode.c          |  33 +++++++-------
 fs/nfs/namespace.c      |   2 +-
 fs/nfs/nfs3acl.c        |   4 +-
 fs/nfs/nfs3proc.c       |  41 ++++++++---------
 fs/nfs/nfs4_fs.h        |   2 +-
 fs/nfs/nfs4namespace.c  |   2 +-
 fs/nfs/nfs4proc.c       | 117 +++++++++++++++++++++++++++++++-----------------
 fs/nfs/proc.c           |  15 ++++---
 include/linux/nfs_fs.h  |   9 ++--
 include/linux/nfs_xdr.h |   5 ++-
 13 files changed, 149 insertions(+), 108 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 84d8eae..665e123 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -1074,7 +1074,7 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
 	}
 
 	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 --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index f23f455..e85753b 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -447,7 +447,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
 	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 *parent, struct nfs_entry *entry)
 	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;
 
@@ -1040,6 +1040,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 	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,12 +1083,12 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 	if (fhandle == NULL || fattr == NULL)
 		goto out_error;
 
-	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)
 		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);
@@ -1256,6 +1257,7 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
 	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",
@@ -1285,14 +1287,14 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
 	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;
@@ -1526,7 +1528,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;
@@ -1539,18 +1542,18 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
 	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 --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 44efaa8..66984a9 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -95,7 +95,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
 		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 --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index c88255c..5965c8b 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -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;
 
@@ -290,7 +290,7 @@ EXPORT_SYMBOL_GPL(nfs4_label_alloc);
  * 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,
@@ -420,7 +420,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 
 		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),
@@ -477,7 +477,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
 		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;
@@ -816,6 +816,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);
 
@@ -833,7 +834,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 		goto out;
 
 	nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
-	status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr);
+	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,
@@ -846,7 +847,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 		goto out;
 	}
 
-	status = nfs_refresh_inode(inode, fattr);
+	status = nfs_refresh_inode(inode, fattr, label);
 	if (status) {
 		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n",
 			 inode->i_sb->s_id,
@@ -1203,10 +1204,10 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n
 		((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);
 }
 
@@ -1220,21 +1221,21 @@ static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr
  * safe to do a full update of the inode attributes, or whether just to
  * call nfs_check_inode_attributes.
  */
-int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
+int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label)
 {
 	int status;
 
 	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
 		return 0;
 	spin_lock(&inode->i_lock);
-	status = nfs_refresh_inode_locked(inode, fattr);
+	status = nfs_refresh_inode_locked(inode, fattr, label);
 	spin_unlock(&inode->i_lock);
 
 	return status;
 }
 EXPORT_SYMBOL_GPL(nfs_refresh_inode);
 
-static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
+static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 
@@ -1245,7 +1246,7 @@ static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr
 	}
 	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
 		return 0;
-	return nfs_refresh_inode_locked(inode, fattr);
+	return nfs_refresh_inode_locked(inode, fattr, label);
 }
 
 /**
@@ -1262,12 +1263,12 @@ static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr
  * are expected to change one or more attributes, to avoid
  * unnecessary NFS requests and trips through nfs_update_inode().
  */
-int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
+int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label)
 {
 	int status;
 
 	spin_lock(&inode->i_lock);
-	status = nfs_post_op_update_inode_locked(inode, fattr);
+	status = nfs_post_op_update_inode_locked(inode, fattr, label);
 	spin_unlock(&inode->i_lock);
 	return status;
 }
@@ -1319,7 +1320,7 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa
 		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;
 }
@@ -1337,7 +1338,7 @@ EXPORT_SYMBOL_GPL(nfs_post_op_update_inode_force_wcc);
  *
  * 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);
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index fc8dc20..348b535 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -280,7 +280,7 @@ struct vfsmount *nfs_submount(struct nfs_server *server, struct dentry *dentry,
 	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 --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 4a1aafb..1a2f11b 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -240,7 +240,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
 
 	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 inode *inode, struct posix_acl *acl,
 
 	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 --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 43ea96c..e2f2755 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -98,7 +98,7 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
  */
 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, struct nfs_fattr *fattr,
 
 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, struct qstr *name,
 
 	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 *inode, struct nfs_access_entry *entry)
 		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 inode *inode, struct page *page,
 	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 *dir, struct dentry *dentry, struct nfs3_
 	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, struct dentry *dentry, struct iattr *sattr,
 		 * 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, struct qstr *name)
 		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 *task, struct inode *dir)
 	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 *task, struct inode *old_dir,
 		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, struct qstr *old_name,
 		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, struct inode *dir, struct qstr *name)
 		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, struct qstr *name)
 
 	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, struct rpc_cred *cred,
 	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_task *task, struct nfs_read_data *data)
 		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_task *task, struct nfs_commit_data *data)
 {
 	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 --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 1de30a8..2796c31 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -229,7 +229,7 @@ extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fh
 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[];
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index 0dd7660..703ebc6 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -369,7 +369,7 @@ struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry,
 	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 --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 5c50495..e711552 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -77,11 +77,12 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
 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 *);
@@ -749,6 +750,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;
@@ -764,6 +766,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;
@@ -774,7 +777,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
 
 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);
@@ -812,6 +815,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
 	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];
 
@@ -1117,7 +1121,7 @@ _nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
 	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;
 
@@ -1147,7 +1151,7 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
 	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;
@@ -1198,7 +1202,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context
 {
 	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;
@@ -1702,7 +1706,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
 			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;
 }
 
@@ -1898,6 +1902,7 @@ static int _nfs4_do_open(struct inode *dir,
 			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)
@@ -1906,6 +1911,7 @@ static int _nfs4_do_open(struct inode *dir,
 	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 */
@@ -1921,7 +1927,7 @@ static int _nfs4_do_open(struct inode *dir,
 	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;
 
@@ -1944,10 +1950,11 @@ static int _nfs4_do_open(struct inode *dir,
 		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);
+		}
 	}
 
 	if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server))
@@ -1976,6 +1983,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
 					fmode_t fmode,
 					int flags,
 					struct iattr *sattr,
+					struct nfs4_label *label,
 					struct rpc_cred *cred,
 					struct nfs4_threshold **ctx_th)
 {
@@ -1985,7 +1993,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
 
 	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;
@@ -2030,7 +2038,8 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
 
 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 = {
@@ -2038,9 +2047,11 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
                 .iap            = sattr,
 		.server		= server,
 		.bitmask = server->attr_bitmask,
+		.label		= ilabel,
         };
         struct nfs_setattrres  res = {
 		.fattr		= fattr,
+		.label		= olabel,
 		.server		= server,
         };
         struct rpc_message msg = {
@@ -2075,7 +2086,8 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 
 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 = {
@@ -2084,7 +2096,7 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 	};
 	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)) {
@@ -2171,7 +2183,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
 				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);
 }
 
@@ -2310,9 +2322,10 @@ static struct inode *
 nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr)
 {
 	struct nfs4_state *state;
+	struct nfs4_label *label = NULL;
 
 	/* 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);
 	if (IS_ERR(state))
 		return ERR_CAST(state);
@@ -2511,6 +2524,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
 {
 	int error;
 	struct nfs_fattr *fattr = info->fattr;
+	struct nfs4_label *label = NULL;
 
 	error = nfs4_server_capabilities(server, mntfh);
 	if (error < 0) {
@@ -2518,7 +2532,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
 		return error;
 	}
 
-	error = nfs4_proc_getattr(server, mntfh, fattr);
+	error = nfs4_proc_getattr(server, mntfh, fattr, label);
 	if (error < 0) {
 		dprintk("nfs4_get_root: getattr error = %d\n", -error);
 		return error;
@@ -2574,7 +2588,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,
@@ -2582,6 +2597,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
 	};
 	struct nfs4_getattr_res res = {
 		.fattr = fattr,
+		.label = label,
 		.server = server,
 	};
 	struct rpc_message msg = {
@@ -2594,13 +2610,14 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
 	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;
@@ -2656,7 +2673,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 		}
 	}
 
-	status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
+	status = nfs4_do_setattr(inode, cred, fattr, sattr, state, NULL, NULL);
 	if (status == 0)
 		nfs_setattr_update_inode(inode, sattr);
 	return status;
@@ -2664,7 +2681,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 
 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;
@@ -2702,13 +2719,13 @@ static void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr)
 
 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;
@@ -2742,12 +2759,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);
@@ -2757,12 +2775,13 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name,
 
 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);
@@ -2779,6 +2798,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 	};
 	struct nfs4_accessres res = {
 		.server = server,
+		.label = NULL,
 	};
 	struct rpc_message msg = {
 		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
@@ -2813,7 +2833,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 	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);
 	}
 	nfs_free_fattr(res.fattr);
 	return status;
@@ -2892,6 +2912,7 @@ static int
 nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 		 int flags)
 {
+	struct nfs4_label *ilabel = NULL;
 	struct nfs_open_context *ctx;
 	struct nfs4_state *state;
 	int status = 0;
@@ -2902,7 +2923,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 
 	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)) {
@@ -3026,6 +3047,8 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
 		.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,
@@ -3070,6 +3093,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
 	};
 	struct nfs4_link_res res = {
 		.server = server,
+		.label = NULL,
 	};
 	struct rpc_message msg = {
 		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK],
@@ -3085,7 +3109,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
 	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);
 	}
 out:
 	nfs_free_fattr(res.fattr);
@@ -3110,6 +3134,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,
@@ -3133,6 +3158,7 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
 		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;
@@ -3144,7 +3170,7 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_
 				    &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;
 }
@@ -3155,7 +3181,8 @@ static void nfs4_free_createdata(struct nfs4_createdata *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;
@@ -3171,6 +3198,7 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
 	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);
 
@@ -3183,18 +3211,19 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
 		struct page *page, unsigned int len, struct iattr *sattr)
 {
 	struct nfs4_exception exception = { };
+	struct nfs4_label *label = NULL;
 	int err;
 	do {
 		err = nfs4_handle_exception(NFS_SERVER(dir),
 				_nfs4_proc_symlink(dir, dentry, page,
-							len, sattr),
+							len, sattr, label),
 				&exception);
 	} while (exception.retry);
 	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;
@@ -3203,6 +3232,7 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 	if (data == NULL)
 		goto out;
 
+	data->arg.label = label;
 	status = nfs4_do_create(dir, dentry, data);
 
 	nfs4_free_createdata(data);
@@ -3214,12 +3244,13 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr)
 {
 	struct nfs4_exception exception = { };
+	struct nfs4_label *label = NULL;
 	int err;
 
 	sattr->ia_mode &= ~current_umask();
 	do {
 		err = nfs4_handle_exception(NFS_SERVER(dir),
-				_nfs4_proc_mkdir(dir, dentry, sattr),
+				_nfs4_proc_mkdir(dir, dentry, sattr, label),
 				&exception);
 	} while (exception.retry);
 	return err;
@@ -3279,7 +3310,7 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
 }
 
 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;
@@ -3304,7 +3335,8 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 		status = -EINVAL;
 		goto out_free;
 	}
-	
+
+	data->arg.label = label;	
 	status = nfs4_do_create(dir, dentry, data);
 out_free:
 	nfs4_free_createdata(data);
@@ -3316,12 +3348,13 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr, dev_t rdev)
 {
 	struct nfs4_exception exception = { };
+	struct nfs4_label *label = NULL;
 	int err;
 
 	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);
 	return err;
@@ -4276,7 +4309,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
 	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;
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index fc8de90..b9735fd 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -98,7 +98,7 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
  */
 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, struct nfs_fattr *fattr,
 
 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, struct dentry *dentry, struct iattr *sattr,
 	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 dentry *dentry, struct iattr *sattr,
 		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, struct dentry *dentry, struct page *page,
 	 * 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 dentry *dentry, struct iattr *sattr)
 	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 *task, struct nfs_read_data *data)
 
 	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 --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index e0e1806..1ef8eb4 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -328,9 +328,9 @@ extern void nfs_zap_mapping(struct inode *inode, struct address_space *mapping);
 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 *);
@@ -460,7 +460,8 @@ extern const struct file_operations nfs_dir_operations;
 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);
 
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 4d2fdf6..f57048f 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1400,11 +1400,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);
-- 
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 11/17] NFS:Add labels to client function prototypes
@ 2013-04-24 20:17     ` Steve Dickson
  0 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl@davequigley.com>

>From David Quigley <dpquigl@davequigley.com>

After looking at all of the nfsv4 operations the label structure has been added
to the prototypes of the functions which can transmit label data.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
---
 fs/nfs/client.c         |   2 +-
 fs/nfs/dir.c            |  23 +++++-----
 fs/nfs/getroot.c        |   2 +-
 fs/nfs/inode.c          |  33 +++++++-------
 fs/nfs/namespace.c      |   2 +-
 fs/nfs/nfs3acl.c        |   4 +-
 fs/nfs/nfs3proc.c       |  41 ++++++++---------
 fs/nfs/nfs4_fs.h        |   2 +-
 fs/nfs/nfs4namespace.c  |   2 +-
 fs/nfs/nfs4proc.c       | 117 +++++++++++++++++++++++++++++++-----------------
 fs/nfs/proc.c           |  15 ++++---
 include/linux/nfs_fs.h  |   9 ++--
 include/linux/nfs_xdr.h |   5 ++-
 13 files changed, 149 insertions(+), 108 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 84d8eae..665e123 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -1074,7 +1074,7 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
 	}
 
 	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 --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index f23f455..e85753b 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -447,7 +447,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
 	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 *parent, struct nfs_entry *entry)
 	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;
 
@@ -1040,6 +1040,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 	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,12 +1083,12 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 	if (fhandle == NULL || fattr == NULL)
 		goto out_error;
 
-	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)
 		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);
@@ -1256,6 +1257,7 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
 	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",
@@ -1285,14 +1287,14 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
 	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;
@@ -1526,7 +1528,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;
@@ -1539,18 +1542,18 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
 	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 --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 44efaa8..66984a9 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -95,7 +95,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
 		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 --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index c88255c..5965c8b 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -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;
 
@@ -290,7 +290,7 @@ EXPORT_SYMBOL_GPL(nfs4_label_alloc);
  * 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,
@@ -420,7 +420,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 
 		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),
@@ -477,7 +477,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
 		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;
@@ -816,6 +816,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);
 
@@ -833,7 +834,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 		goto out;
 
 	nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
-	status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr);
+	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,
@@ -846,7 +847,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 		goto out;
 	}
 
-	status = nfs_refresh_inode(inode, fattr);
+	status = nfs_refresh_inode(inode, fattr, label);
 	if (status) {
 		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n",
 			 inode->i_sb->s_id,
@@ -1203,10 +1204,10 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n
 		((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);
 }
 
@@ -1220,21 +1221,21 @@ static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr
  * safe to do a full update of the inode attributes, or whether just to
  * call nfs_check_inode_attributes.
  */
-int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
+int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label)
 {
 	int status;
 
 	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
 		return 0;
 	spin_lock(&inode->i_lock);
-	status = nfs_refresh_inode_locked(inode, fattr);
+	status = nfs_refresh_inode_locked(inode, fattr, label);
 	spin_unlock(&inode->i_lock);
 
 	return status;
 }
 EXPORT_SYMBOL_GPL(nfs_refresh_inode);
 
-static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
+static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 
@@ -1245,7 +1246,7 @@ static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr
 	}
 	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
 		return 0;
-	return nfs_refresh_inode_locked(inode, fattr);
+	return nfs_refresh_inode_locked(inode, fattr, label);
 }
 
 /**
@@ -1262,12 +1263,12 @@ static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr
  * are expected to change one or more attributes, to avoid
  * unnecessary NFS requests and trips through nfs_update_inode().
  */
-int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
+int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label)
 {
 	int status;
 
 	spin_lock(&inode->i_lock);
-	status = nfs_post_op_update_inode_locked(inode, fattr);
+	status = nfs_post_op_update_inode_locked(inode, fattr, label);
 	spin_unlock(&inode->i_lock);
 	return status;
 }
@@ -1319,7 +1320,7 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa
 		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;
 }
@@ -1337,7 +1338,7 @@ EXPORT_SYMBOL_GPL(nfs_post_op_update_inode_force_wcc);
  *
  * 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);
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index fc8dc20..348b535 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -280,7 +280,7 @@ struct vfsmount *nfs_submount(struct nfs_server *server, struct dentry *dentry,
 	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 --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 4a1aafb..1a2f11b 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -240,7 +240,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
 
 	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 inode *inode, struct posix_acl *acl,
 
 	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 --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 43ea96c..e2f2755 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -98,7 +98,7 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
  */
 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, struct nfs_fattr *fattr,
 
 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, struct qstr *name,
 
 	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 *inode, struct nfs_access_entry *entry)
 		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 inode *inode, struct page *page,
 	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 *dir, struct dentry *dentry, struct nfs3_
 	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, struct dentry *dentry, struct iattr *sattr,
 		 * 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, struct qstr *name)
 		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 *task, struct inode *dir)
 	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 *task, struct inode *old_dir,
 		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, struct qstr *old_name,
 		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, struct inode *dir, struct qstr *name)
 		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, struct qstr *name)
 
 	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, struct rpc_cred *cred,
 	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_task *task, struct nfs_read_data *data)
 		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_task *task, struct nfs_commit_data *data)
 {
 	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 --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 1de30a8..2796c31 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -229,7 +229,7 @@ extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fh
 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[];
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index 0dd7660..703ebc6 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -369,7 +369,7 @@ struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry,
 	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 --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 5c50495..e711552 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -77,11 +77,12 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
 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 *);
@@ -749,6 +750,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;
@@ -764,6 +766,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;
@@ -774,7 +777,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
 
 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);
@@ -812,6 +815,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
 	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];
 
@@ -1117,7 +1121,7 @@ _nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
 	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;
 
@@ -1147,7 +1151,7 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
 	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;
@@ -1198,7 +1202,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context
 {
 	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;
@@ -1702,7 +1706,7 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
 			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;
 }
 
@@ -1898,6 +1902,7 @@ static int _nfs4_do_open(struct inode *dir,
 			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)
@@ -1906,6 +1911,7 @@ static int _nfs4_do_open(struct inode *dir,
 	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 */
@@ -1921,7 +1927,7 @@ static int _nfs4_do_open(struct inode *dir,
 	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;
 
@@ -1944,10 +1950,11 @@ static int _nfs4_do_open(struct inode *dir,
 		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);
+		}
 	}
 
 	if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server))
@@ -1976,6 +1983,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
 					fmode_t fmode,
 					int flags,
 					struct iattr *sattr,
+					struct nfs4_label *label,
 					struct rpc_cred *cred,
 					struct nfs4_threshold **ctx_th)
 {
@@ -1985,7 +1993,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
 
 	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;
@@ -2030,7 +2038,8 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
 
 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 = {
@@ -2038,9 +2047,11 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
                 .iap            = sattr,
 		.server		= server,
 		.bitmask = server->attr_bitmask,
+		.label		= ilabel,
         };
         struct nfs_setattrres  res = {
 		.fattr		= fattr,
+		.label		= olabel,
 		.server		= server,
         };
         struct rpc_message msg = {
@@ -2075,7 +2086,8 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 
 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 = {
@@ -2084,7 +2096,7 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 	};
 	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)) {
@@ -2171,7 +2183,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
 				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);
 }
 
@@ -2310,9 +2322,10 @@ static struct inode *
 nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr)
 {
 	struct nfs4_state *state;
+	struct nfs4_label *label = NULL;
 
 	/* 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);
 	if (IS_ERR(state))
 		return ERR_CAST(state);
@@ -2511,6 +2524,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
 {
 	int error;
 	struct nfs_fattr *fattr = info->fattr;
+	struct nfs4_label *label = NULL;
 
 	error = nfs4_server_capabilities(server, mntfh);
 	if (error < 0) {
@@ -2518,7 +2532,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
 		return error;
 	}
 
-	error = nfs4_proc_getattr(server, mntfh, fattr);
+	error = nfs4_proc_getattr(server, mntfh, fattr, label);
 	if (error < 0) {
 		dprintk("nfs4_get_root: getattr error = %d\n", -error);
 		return error;
@@ -2574,7 +2588,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,
@@ -2582,6 +2597,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
 	};
 	struct nfs4_getattr_res res = {
 		.fattr = fattr,
+		.label = label,
 		.server = server,
 	};
 	struct rpc_message msg = {
@@ -2594,13 +2610,14 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
 	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;
@@ -2656,7 +2673,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 		}
 	}
 
-	status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
+	status = nfs4_do_setattr(inode, cred, fattr, sattr, state, NULL, NULL);
 	if (status == 0)
 		nfs_setattr_update_inode(inode, sattr);
 	return status;
@@ -2664,7 +2681,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 
 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;
@@ -2702,13 +2719,13 @@ static void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr)
 
 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;
@@ -2742,12 +2759,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);
@@ -2757,12 +2775,13 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name,
 
 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);
@@ -2779,6 +2798,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 	};
 	struct nfs4_accessres res = {
 		.server = server,
+		.label = NULL,
 	};
 	struct rpc_message msg = {
 		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
@@ -2813,7 +2833,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 	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);
 	}
 	nfs_free_fattr(res.fattr);
 	return status;
@@ -2892,6 +2912,7 @@ static int
 nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 		 int flags)
 {
+	struct nfs4_label *ilabel = NULL;
 	struct nfs_open_context *ctx;
 	struct nfs4_state *state;
 	int status = 0;
@@ -2902,7 +2923,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 
 	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)) {
@@ -3026,6 +3047,8 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
 		.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,
@@ -3070,6 +3093,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
 	};
 	struct nfs4_link_res res = {
 		.server = server,
+		.label = NULL,
 	};
 	struct rpc_message msg = {
 		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK],
@@ -3085,7 +3109,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
 	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);
 	}
 out:
 	nfs_free_fattr(res.fattr);
@@ -3110,6 +3134,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,
@@ -3133,6 +3158,7 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
 		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;
@@ -3144,7 +3170,7 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_
 				    &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;
 }
@@ -3155,7 +3181,8 @@ static void nfs4_free_createdata(struct nfs4_createdata *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;
@@ -3171,6 +3198,7 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
 	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);
 
@@ -3183,18 +3211,19 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
 		struct page *page, unsigned int len, struct iattr *sattr)
 {
 	struct nfs4_exception exception = { };
+	struct nfs4_label *label = NULL;
 	int err;
 	do {
 		err = nfs4_handle_exception(NFS_SERVER(dir),
 				_nfs4_proc_symlink(dir, dentry, page,
-							len, sattr),
+							len, sattr, label),
 				&exception);
 	} while (exception.retry);
 	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;
@@ -3203,6 +3232,7 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 	if (data == NULL)
 		goto out;
 
+	data->arg.label = label;
 	status = nfs4_do_create(dir, dentry, data);
 
 	nfs4_free_createdata(data);
@@ -3214,12 +3244,13 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr)
 {
 	struct nfs4_exception exception = { };
+	struct nfs4_label *label = NULL;
 	int err;
 
 	sattr->ia_mode &= ~current_umask();
 	do {
 		err = nfs4_handle_exception(NFS_SERVER(dir),
-				_nfs4_proc_mkdir(dir, dentry, sattr),
+				_nfs4_proc_mkdir(dir, dentry, sattr, label),
 				&exception);
 	} while (exception.retry);
 	return err;
@@ -3279,7 +3310,7 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
 }
 
 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;
@@ -3304,7 +3335,8 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 		status = -EINVAL;
 		goto out_free;
 	}
-	
+
+	data->arg.label = label;	
 	status = nfs4_do_create(dir, dentry, data);
 out_free:
 	nfs4_free_createdata(data);
@@ -3316,12 +3348,13 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr, dev_t rdev)
 {
 	struct nfs4_exception exception = { };
+	struct nfs4_label *label = NULL;
 	int err;
 
 	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);
 	return err;
@@ -4276,7 +4309,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
 	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;
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index fc8de90..b9735fd 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -98,7 +98,7 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
  */
 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, struct nfs_fattr *fattr,
 
 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, struct dentry *dentry, struct iattr *sattr,
 	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 dentry *dentry, struct iattr *sattr,
 		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, struct dentry *dentry, struct page *page,
 	 * 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 dentry *dentry, struct iattr *sattr)
 	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 *task, struct nfs_read_data *data)
 
 	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 --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index e0e1806..1ef8eb4 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -328,9 +328,9 @@ extern void nfs_zap_mapping(struct inode *inode, struct address_space *mapping);
 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 *);
@@ -460,7 +460,8 @@ extern const struct file_operations nfs_dir_operations;
 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);
 
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 4d2fdf6..f57048f 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1400,11 +1400,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);
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 12/17] NFS: Add label lifecycle management
  2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
                   ` (7 preceding siblings ...)
  2013-04-24 20:17 ` [PATCH 10/17] NFSv4: Extend fattr bitmaps to support all 3 words Steve Dickson
@ 2013-04-24 20:17 ` Steve Dickson
  2013-04-24 20:18 ` [PATCH 14/17] NFS: Extend NFS xattr handlers to accept the security namespace Steve Dickson
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl@davequigley.com>

>From David Quigley <dpquigl@davequigley.com>

This patch adds the lifecycle management for the security label structure
introduced in an earlier patch. The label is not used yet but allocations and
freeing of the structure is handled.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
---
 fs/nfs/dir.c      | 23 ++++++++++++-
 fs/nfs/inode.c    | 15 +++++++--
 fs/nfs/nfs4proc.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 126 insertions(+), 10 deletions(-)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index e85753b..b911195 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -585,10 +585,16 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
 	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_descriptor_t *desc, struct page *page,
 	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);
@@ -1083,6 +1091,10 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 	if (fhandle == NULL || fattr == NULL)
 		goto out_error;
 
+	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;
@@ -1093,6 +1105,8 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 
 	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:
@@ -1109,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. */
@@ -1129,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,
@@ -1284,6 +1300,10 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
 	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);
@@ -1312,6 +1332,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);
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 5965c8b..4e92dfb 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -834,6 +834,13 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 		goto out;
 
 	nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
+
+	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",
@@ -844,7 +851,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 			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, label);
@@ -852,7 +859,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 		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)
@@ -862,7 +869,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 		inode->i_sb->s_id,
 		(long long)NFS_FILEID(inode));
 
- out:
+err_out:
+	nfs4_label_free(label);
+out:
 	nfs_free_fattr(fattr);
 	return status;
 }
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index e711552..56f24c0 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -788,9 +788,14 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
 	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;
@@ -833,7 +838,10 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
 	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);
@@ -850,6 +858,9 @@ static void nfs4_opendata_free(struct kref *kref)
 	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);
@@ -1931,10 +1942,18 @@ static int _nfs4_do_open(struct inode *dir,
 	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)
-			goto err_opendata_put;
+			goto err_free_label;
 		opendata->o_arg.open_bitmap = &nfs4_pnfs_open_bitmap[0];
 	}
 	if (dentry->d_inode != NULL)
@@ -1942,7 +1961,7 @@ static int _nfs4_do_open(struct inode *dir,
 
 	status = _nfs4_open_and_get_state(opendata, fmode, flags, &state);
 	if (status != 0)
-		goto err_opendata_put;
+		goto err_free_label;
 
 	if (opendata->o_arg.open_flags & O_EXCL) {
 		nfs4_exclusive_attrset(opendata, sattr);
@@ -1963,10 +1982,14 @@ static int _nfs4_do_open(struct inode *dir,
 		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);
@@ -2532,16 +2555,23 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
 		return error;
 	}
 
+	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;
 }
 
@@ -2647,6 +2677,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 	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))
@@ -2673,9 +2704,15 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 		}
 	}
 
-	status = nfs4_do_setattr(inode, cred, fattr, sattr, state, NULL, NULL);
+	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;
 }
 
@@ -2830,11 +2867,21 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 	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, res.label);
 	}
+
+	nfs4_label_free(res.label);
+
+out:
 	nfs_free_fattr(res.fattr);
 	return status;
 }
@@ -3059,12 +3106,33 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
 		.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;
 }
 
@@ -3106,11 +3174,21 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
 	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, res.label);
 	}
+
+
+	nfs4_label_free(res.label);
+
 out:
 	nfs_free_fattr(res.fattr);
 	return status;
@@ -3146,6 +3224,10 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
 	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;
@@ -3162,6 +3244,9 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
 		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)
@@ -3177,6 +3262,7 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_
 
 static void nfs4_free_createdata(struct nfs4_createdata *data)
 {
+	nfs4_label_free(data->label);
 	kfree(data);
 }
 
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 13/17] NFS: Client implementation of Labeled-NFS
  2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
@ 2013-04-24 20:17     ` Steve Dickson
  2013-04-24 20:17 ` [PATCH 02/17] NFSv4.2: Added NFS v4.2 support to the NFS client Steve Dickson
                       ` (11 subsequent siblings)
  12 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl-a7DkhOHRHBuN9aS15agKxg@public.gmane.org>

This patch implements the client transport and handling support for labeled
NFS. The patch adds two functions to encode and decode the security label
recommended attribute which makes use of the LSM hooks added earlier. It also
adds code to grab the label from the file attribute structures and encode the
label to be sent back to the server.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM-geVtEqcQUv4Eyxwt80+Gtti2O/JbrIOy@public.gmane.org>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene-geVtEqcQUv4Eyxwt80+Gtti2O/JbrIOy@public.gmane.org>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG-geVtEqcQUv4Eyxwt80+Gtti2O/JbrIOy@public.gmane.org>
---
 fs/nfs/inode.c            |  57 +++++++-
 fs/nfs/nfs4proc.c         | 336 +++++++++++++++++++++++++++++++++++++++++++---
 fs/nfs/nfs4xdr.c          | 168 ++++++++++++++++++-----
 fs/nfs/pnfs.c             |   2 +-
 fs/nfs/super.c            |  17 ++-
 include/linux/nfs_fs.h    |  13 ++
 include/linux/nfs_fs_sb.h |   7 +
 security/selinux/hooks.c  |   4 +
 8 files changed, 541 insertions(+), 63 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 4e92dfb..cc1c85d 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -162,11 +162,19 @@ static void nfs_zap_caches_locked(struct inode *inode)
 
 	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)
@@ -258,6 +266,24 @@ nfs_init_locked(struct inode *inode, void *opaque)
 }
 
 #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;
@@ -283,7 +309,13 @@ struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags)
 	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
@@ -412,6 +444,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
 			 */
 			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;
@@ -771,6 +806,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_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)
 {
@@ -899,7 +935,8 @@ static int nfs_attribute_cache_expired(struct inode *inode)
  */
 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);
@@ -1240,6 +1277,9 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_
 	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);
@@ -1279,6 +1319,10 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr, struc
 	spin_lock(&inode->i_lock);
 	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);
@@ -1519,7 +1563,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
 		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;
@@ -1532,6 +1576,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
 		}
 	}
 	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 --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 56f24c0..c459bbd 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -87,6 +87,67 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 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;
+	int minor_version = NFS_SERVER(dir)->nfs_client->cl_minorversion;
+
+	if (minor_version < 2)
+		return NULL;
+
+	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);
+}
+static inline u32 *nfs4_bitmap(struct nfs4_label *label, u32 *bitmap)
+{
+	bitmap[0] =  nfs4_fattr_bitmap[0];
+	bitmap[1] =  nfs4_fattr_bitmap[1];
+	bitmap[2] =  nfs4_fattr_bitmap[2];
+
+	if (!label)
+		bitmap[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
+
+	return bitmap;
+}
+static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
+{
+	if (label)
+		return server->attr_bitmask;
+
+	return server->attr_bitmask_nl;
+}
+#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; }
+static inline u32 *
+nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
+{ return server->attr_bitmask; }
+static inline const u32 *
+nfs4_bitmap(struct nfs4_label *label, u32 *bitmap)
+{ return &nfs4_fattr_bitmap[0]; }
+#endif
+
 /* Prevent leaks of NFSv4 errors into userland */
 static int nfs4_map_errors(int err)
 {
@@ -133,7 +194,10 @@ const u32 nfs4_fattr_bitmap[3] = {
 	| FATTR4_WORD1_SPACE_USED
 	| FATTR4_WORD1_TIME_ACCESS
 	| FATTR4_WORD1_TIME_METADATA
-	| FATTR4_WORD1_TIME_MODIFY
+	| FATTR4_WORD1_TIME_MODIFY,
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	FATTR4_WORD2_SECURITY_LABEL
+#endif
 };
 
 static const u32 nfs4_pnfs_open_bitmap[3] = {
@@ -784,6 +848,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
 	struct inode *dir = parent->d_inode;
 	struct nfs_server *server = NFS_SERVER(dir);
 	struct nfs4_opendata *p;
+	u32 bitmap[3];
 
 	p = kzalloc(sizeof(*p), gfp_mask);
 	if (p == NULL)
@@ -817,8 +882,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
 	p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
 	p->o_arg.name = &dentry->d_name;
 	p->o_arg.server = server;
-	p->o_arg.bitmask = server->attr_bitmask;
-	p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
+	p->o_arg.open_bitmap = nfs4_bitmap(label, bitmap);
+	p->o_arg.bitmask = nfs4_bitmask(server, label);
 	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
 	p->o_arg.label = label;
 	if (attrs != NULL && attrs->ia_valid != 0) {
@@ -1973,6 +2038,7 @@ static int _nfs4_do_open(struct inode *dir,
 		if (status == 0) {
 			nfs_setattr_update_inode(state->inode, sattr);
 			nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr, olabel);
+			nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
 		}
 	}
 
@@ -2086,6 +2152,10 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 	unsigned long timestamp = jiffies;
 	int status;
 
+	arg.bitmask = nfs4_bitmask(server, ilabel);
+	if (ilabel)
+		arg.bitmask = nfs4_bitmask(server, olabel);
+
 	nfs_fattr_init(fattr);
 
 	if (state != NULL) {
@@ -2315,7 +2385,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
 	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;
@@ -2345,11 +2415,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 *label = NULL;
+	struct nfs4_label l = {0, 0, 0, NULL}, *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, label,
 			     ctx->cred, &ctx->mdsthreshold);
+
+	nfs4_label_release_security(label);
+
 	if (IS_ERR(state))
 		return ERR_CAST(state);
 	ctx->state = state;
@@ -2409,10 +2484,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
 			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;
+#endif
+		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;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
+#endif
+		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;
 	}
@@ -2435,8 +2526,9 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
 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,
@@ -2449,6 +2541,13 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
 		.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);
 }
@@ -2635,7 +2734,9 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
 		.rpc_argp = &args,
 		.rpc_resp = &res,
 	};
-	
+
+	args.bitmask = nfs4_bitmask(server, label);
+
 	nfs_fattr_init(fattr);
 	return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
 }
@@ -2730,6 +2831,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
 	struct nfs4_lookup_res res = {
 		.server = server,
 		.fattr = fattr,
+		.label = label,
 		.fh = fhandle,
 	};
 	struct rpc_message msg = {
@@ -2738,6 +2840,8 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
 		.rpc_resp = &res,
 	};
 
+	args.bitmask = nfs4_bitmask(server, label);
+
 	nfs_fattr_init(fattr);
 
 	dprintk("NFS call  lookup %s\n", name->name);
@@ -2844,7 +2948,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 		.rpc_cred = entry->cred,
 	};
 	int mode = entry->mask;
-	int status;
+	int status = 0;
 
 	/*
 	 * Determine which access bits we want to ask for...
@@ -2873,6 +2977,8 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 		goto out;
 	}
 
+	args.bitmask = nfs4_cache_bitmask(server, res.label);
+
 	status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
 	if (!status) {
 		nfs_access_set_mask(entry, res.access);
@@ -2959,7 +3065,7 @@ static int
 nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 		 int flags)
 {
-	struct nfs4_label *ilabel = NULL;
+	struct nfs4_label l, *ilabel = NULL;
 	struct nfs_open_context *ctx;
 	struct nfs4_state *state;
 	int status = 0;
@@ -2968,6 +3074,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 	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, ilabel, ctx->cred,
@@ -2981,6 +3089,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 	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;
 }
@@ -3029,6 +3138,8 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 	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)
@@ -3179,6 +3290,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
 		status = PTR_ERR(res.label);
 		goto out;
 	}
+	arg.bitmask = nfs4_bitmask(server, res.label);
 
 	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
 	if (!status) {
@@ -3236,7 +3348,7 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
 		data->arg.name = name;
 		data->arg.attrs = sattr;
 		data->arg.ftype = ftype;
-		data->arg.bitmask = server->attr_bitmask;
+		data->arg.bitmask = nfs4_bitmask(server, data->label);
 		data->res.server = server;
 		data->res.fh = &data->fh;
 		data->res.fattr = &data->fattr;
@@ -3297,14 +3409,19 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
 		struct page *page, unsigned int len, struct iattr *sattr)
 {
 	struct nfs4_exception exception = { };
-	struct nfs4_label *label = NULL;
+	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, label),
 				&exception);
 	} while (exception.retry);
+
+	nfs4_label_release_security(label);
 	return err;
 }
 
@@ -3330,15 +3447,19 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr)
 {
 	struct nfs4_exception exception = { };
-	struct nfs4_label *label = NULL;
+	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, label),
 				&exception);
 	} while (exception.retry);
+	nfs4_label_release_security(label);
+
 	return err;
 }
 
@@ -3354,7 +3475,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
 		.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,
@@ -3434,15 +3557,20 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr, dev_t rdev)
 {
 	struct nfs4_exception exception = { };
-	struct nfs4_label *label = NULL;
+	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, label, rdev),
 				&exception);
 	} while (exception.retry);
+
+	nfs4_label_release_security(label);
+
 	return err;
 }
 
@@ -3658,7 +3786,8 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
 		data->args.bitmask = NULL;
 		data->res.fattr = NULL;
 	} else
-		data->args.bitmask = server->cache_consistency_bitmask;
+
+	data->args.bitmask = nfs4_cache_bitmask(server, NULL);
 
 	if (!data->write_done_cb)
 		data->write_done_cb = nfs4_write_done_cb;
@@ -4083,6 +4212,179 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
 	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)
 {
@@ -4371,7 +4673,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
 	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;
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 4fa0bf1..2726f21 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -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 xdr_stream *xdr, const nfs4_verifier *ve
 	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];
@@ -1022,6 +1038,8 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
 		}
 		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)
@@ -1078,6 +1096,13 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
 		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.
@@ -1144,7 +1169,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
 	}
 
 	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)
@@ -1377,21 +1402,23 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
 	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);
@@ -1547,7 +1574,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
 
 static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
 {
-	uint32_t attrs[2] = {
+	uint32_t attrs[3] = {
 		FATTR4_WORD0_RDATTR_ERROR,
 		FATTR4_WORD1_MOUNTED_ON_FILEID,
 	};
@@ -1570,20 +1597,26 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
 	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) {
+		if (hdr->minorversion > 1)
+			attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
+		p++, *p++ = cpu_to_be32(attrs[2] & readdir->bitmask[2]);
+	}
 	memcpy(verf, readdir->verifier.data, sizeof(verf));
-	dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
+
+	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]);
+			attrs[1] & readdir->bitmask[1],
+			attrs[2] & readdir->bitmask[2]);
 }
 
 static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
@@ -1642,7 +1675,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs
 {
 	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)
@@ -4060,6 +4093,60 @@ static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap,
 	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;
@@ -4402,7 +4489,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;
@@ -4510,6 +4597,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
 	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;
@@ -4517,7 +4609,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,
@@ -4536,7 +4628,8 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
 	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;
 
@@ -4547,9 +4640,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);
 }
 
 /*
@@ -5883,7 +5976,7 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp,
 	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;
 }
@@ -5909,7 +6002,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -5938,7 +6031,7 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -5964,7 +6057,8 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp,
 		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;
 }
@@ -6055,7 +6149,7 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -6084,7 +6178,7 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -6116,7 +6210,7 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -6218,7 +6312,7 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	 * 	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;
 }
@@ -6249,7 +6343,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 		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;
 }
@@ -6299,7 +6393,7 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp,
 		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;
 }
@@ -6326,7 +6420,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp,
 	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;
 }
@@ -6506,7 +6600,7 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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:
@@ -6687,7 +6781,7 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
 	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);
@@ -6720,7 +6814,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
 	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;
 }
@@ -7001,7 +7095,7 @@ static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp,
 	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;
 }
@@ -7133,7 +7227,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
 		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 --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 4bdffe0..0ead05b 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1922,7 +1922,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
 	data->args.inode = inode;
 	data->cred = get_rpccred(nfsi->layout->plh_lc_cred);
 	nfs_fattr_init(&data->fattr);
-	data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
+	data->args.bitmask = nfs4_cache_bitmask(NFS_SERVER(inode), NULL);
 	data->res.fattr = &data->fattr;
 	data->args.lastbytewritten = end_pos - 1;
 	data->res.server = NFS_SERVER(inode);
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 00af026..68c42be 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2379,8 +2379,21 @@ static int nfs_bdi_register(struct nfs_server *server)
 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,
-								0, NULL);
+	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 --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 1ef8eb4..1510f4f 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -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
@@ -344,6 +345,8 @@ extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
 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);
@@ -502,9 +505,19 @@ static inline void nfs4_label_free(struct nfs4_label *label)
 	}
 	return;
 }
+static inline u32 *nfs4_cache_bitmask(struct nfs_server *server, struct nfs4_label *label)
+{
+	if (label)
+		return server->cache_consistency_bitmask;
+
+	return server->cache_consistency_bitmask_nl;
+}
 #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) {}
+static inline u32 *
+nfs4_cache_bitmask(struct nfs_server *server, struct nfs4_label *label)
+{ return server->cache_consistency_bitmask; }
 #endif
 
 /*
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index e6ed3c2..2a4f1d4 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -145,11 +145,18 @@ struct nfs_server {
 	u32			attr_bitmask[3];/* V4 bitmask representing the set
 						   of attributes supported on this
 						   filesystem */
+	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 */
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d7ff806..f68b577 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2877,7 +2877,10 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
 		return;
 	}
 
+	isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	isec->sid = newsid;
+	isec->initialized = 1;
+
 	return;
 }
 
@@ -2965,6 +2968,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
 	if (rc)
 		return rc;
 
+	isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	isec->sid = newsid;
 	isec->initialized = 1;
 	return 0;
-- 
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 13/17] NFS: Client implementation of Labeled-NFS
@ 2013-04-24 20:17     ` Steve Dickson
  0 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:17 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl@davequigley.com>

This patch implements the client transport and handling support for labeled
NFS. The patch adds two functions to encode and decode the security label
recommended attribute which makes use of the LSM hooks added earlier. It also
adds code to grab the label from the file attribute structures and encode the
label to be sent back to the server.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
---
 fs/nfs/inode.c            |  57 +++++++-
 fs/nfs/nfs4proc.c         | 336 +++++++++++++++++++++++++++++++++++++++++++---
 fs/nfs/nfs4xdr.c          | 168 ++++++++++++++++++-----
 fs/nfs/pnfs.c             |   2 +-
 fs/nfs/super.c            |  17 ++-
 include/linux/nfs_fs.h    |  13 ++
 include/linux/nfs_fs_sb.h |   7 +
 security/selinux/hooks.c  |   4 +
 8 files changed, 541 insertions(+), 63 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 4e92dfb..cc1c85d 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -162,11 +162,19 @@ static void nfs_zap_caches_locked(struct inode *inode)
 
 	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)
@@ -258,6 +266,24 @@ nfs_init_locked(struct inode *inode, void *opaque)
 }
 
 #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;
@@ -283,7 +309,13 @@ struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags)
 	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
@@ -412,6 +444,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
 			 */
 			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;
@@ -771,6 +806,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_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)
 {
@@ -899,7 +935,8 @@ static int nfs_attribute_cache_expired(struct inode *inode)
  */
 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);
@@ -1240,6 +1277,9 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_
 	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);
@@ -1279,6 +1319,10 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr, struc
 	spin_lock(&inode->i_lock);
 	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);
@@ -1519,7 +1563,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
 		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;
@@ -1532,6 +1576,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
 		}
 	}
 	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 --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 56f24c0..c459bbd 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -87,6 +87,67 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 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;
+	int minor_version = NFS_SERVER(dir)->nfs_client->cl_minorversion;
+
+	if (minor_version < 2)
+		return NULL;
+
+	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);
+}
+static inline u32 *nfs4_bitmap(struct nfs4_label *label, u32 *bitmap)
+{
+	bitmap[0] =  nfs4_fattr_bitmap[0];
+	bitmap[1] =  nfs4_fattr_bitmap[1];
+	bitmap[2] =  nfs4_fattr_bitmap[2];
+
+	if (!label)
+		bitmap[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
+
+	return bitmap;
+}
+static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
+{
+	if (label)
+		return server->attr_bitmask;
+
+	return server->attr_bitmask_nl;
+}
+#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; }
+static inline u32 *
+nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
+{ return server->attr_bitmask; }
+static inline const u32 *
+nfs4_bitmap(struct nfs4_label *label, u32 *bitmap)
+{ return &nfs4_fattr_bitmap[0]; }
+#endif
+
 /* Prevent leaks of NFSv4 errors into userland */
 static int nfs4_map_errors(int err)
 {
@@ -133,7 +194,10 @@ const u32 nfs4_fattr_bitmap[3] = {
 	| FATTR4_WORD1_SPACE_USED
 	| FATTR4_WORD1_TIME_ACCESS
 	| FATTR4_WORD1_TIME_METADATA
-	| FATTR4_WORD1_TIME_MODIFY
+	| FATTR4_WORD1_TIME_MODIFY,
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	FATTR4_WORD2_SECURITY_LABEL
+#endif
 };
 
 static const u32 nfs4_pnfs_open_bitmap[3] = {
@@ -784,6 +848,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
 	struct inode *dir = parent->d_inode;
 	struct nfs_server *server = NFS_SERVER(dir);
 	struct nfs4_opendata *p;
+	u32 bitmap[3];
 
 	p = kzalloc(sizeof(*p), gfp_mask);
 	if (p == NULL)
@@ -817,8 +882,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
 	p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
 	p->o_arg.name = &dentry->d_name;
 	p->o_arg.server = server;
-	p->o_arg.bitmask = server->attr_bitmask;
-	p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
+	p->o_arg.open_bitmap = nfs4_bitmap(label, bitmap);
+	p->o_arg.bitmask = nfs4_bitmask(server, label);
 	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
 	p->o_arg.label = label;
 	if (attrs != NULL && attrs->ia_valid != 0) {
@@ -1973,6 +2038,7 @@ static int _nfs4_do_open(struct inode *dir,
 		if (status == 0) {
 			nfs_setattr_update_inode(state->inode, sattr);
 			nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr, olabel);
+			nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
 		}
 	}
 
@@ -2086,6 +2152,10 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 	unsigned long timestamp = jiffies;
 	int status;
 
+	arg.bitmask = nfs4_bitmask(server, ilabel);
+	if (ilabel)
+		arg.bitmask = nfs4_bitmask(server, olabel);
+
 	nfs_fattr_init(fattr);
 
 	if (state != NULL) {
@@ -2315,7 +2385,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
 	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;
@@ -2345,11 +2415,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 *label = NULL;
+	struct nfs4_label l = {0, 0, 0, NULL}, *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, label,
 			     ctx->cred, &ctx->mdsthreshold);
+
+	nfs4_label_release_security(label);
+
 	if (IS_ERR(state))
 		return ERR_CAST(state);
 	ctx->state = state;
@@ -2409,10 +2484,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
 			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;
+#endif
+		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;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
+#endif
+		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;
 	}
@@ -2435,8 +2526,9 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
 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,
@@ -2449,6 +2541,13 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
 		.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);
 }
@@ -2635,7 +2734,9 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
 		.rpc_argp = &args,
 		.rpc_resp = &res,
 	};
-	
+
+	args.bitmask = nfs4_bitmask(server, label);
+
 	nfs_fattr_init(fattr);
 	return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
 }
@@ -2730,6 +2831,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
 	struct nfs4_lookup_res res = {
 		.server = server,
 		.fattr = fattr,
+		.label = label,
 		.fh = fhandle,
 	};
 	struct rpc_message msg = {
@@ -2738,6 +2840,8 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
 		.rpc_resp = &res,
 	};
 
+	args.bitmask = nfs4_bitmask(server, label);
+
 	nfs_fattr_init(fattr);
 
 	dprintk("NFS call  lookup %s\n", name->name);
@@ -2844,7 +2948,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 		.rpc_cred = entry->cred,
 	};
 	int mode = entry->mask;
-	int status;
+	int status = 0;
 
 	/*
 	 * Determine which access bits we want to ask for...
@@ -2873,6 +2977,8 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 		goto out;
 	}
 
+	args.bitmask = nfs4_cache_bitmask(server, res.label);
+
 	status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
 	if (!status) {
 		nfs_access_set_mask(entry, res.access);
@@ -2959,7 +3065,7 @@ static int
 nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 		 int flags)
 {
-	struct nfs4_label *ilabel = NULL;
+	struct nfs4_label l, *ilabel = NULL;
 	struct nfs_open_context *ctx;
 	struct nfs4_state *state;
 	int status = 0;
@@ -2968,6 +3074,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 	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, ilabel, ctx->cred,
@@ -2981,6 +3089,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 	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;
 }
@@ -3029,6 +3138,8 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 	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)
@@ -3179,6 +3290,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
 		status = PTR_ERR(res.label);
 		goto out;
 	}
+	arg.bitmask = nfs4_bitmask(server, res.label);
 
 	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
 	if (!status) {
@@ -3236,7 +3348,7 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
 		data->arg.name = name;
 		data->arg.attrs = sattr;
 		data->arg.ftype = ftype;
-		data->arg.bitmask = server->attr_bitmask;
+		data->arg.bitmask = nfs4_bitmask(server, data->label);
 		data->res.server = server;
 		data->res.fh = &data->fh;
 		data->res.fattr = &data->fattr;
@@ -3297,14 +3409,19 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
 		struct page *page, unsigned int len, struct iattr *sattr)
 {
 	struct nfs4_exception exception = { };
-	struct nfs4_label *label = NULL;
+	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, label),
 				&exception);
 	} while (exception.retry);
+
+	nfs4_label_release_security(label);
 	return err;
 }
 
@@ -3330,15 +3447,19 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr)
 {
 	struct nfs4_exception exception = { };
-	struct nfs4_label *label = NULL;
+	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, label),
 				&exception);
 	} while (exception.retry);
+	nfs4_label_release_security(label);
+
 	return err;
 }
 
@@ -3354,7 +3475,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
 		.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,
@@ -3434,15 +3557,20 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr, dev_t rdev)
 {
 	struct nfs4_exception exception = { };
-	struct nfs4_label *label = NULL;
+	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, label, rdev),
 				&exception);
 	} while (exception.retry);
+
+	nfs4_label_release_security(label);
+
 	return err;
 }
 
@@ -3658,7 +3786,8 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
 		data->args.bitmask = NULL;
 		data->res.fattr = NULL;
 	} else
-		data->args.bitmask = server->cache_consistency_bitmask;
+
+	data->args.bitmask = nfs4_cache_bitmask(server, NULL);
 
 	if (!data->write_done_cb)
 		data->write_done_cb = nfs4_write_done_cb;
@@ -4083,6 +4212,179 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
 	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)
 {
@@ -4371,7 +4673,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
 	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;
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 4fa0bf1..2726f21 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -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 xdr_stream *xdr, const nfs4_verifier *ve
 	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];
@@ -1022,6 +1038,8 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
 		}
 		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)
@@ -1078,6 +1096,13 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
 		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.
@@ -1144,7 +1169,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
 	}
 
 	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)
@@ -1377,21 +1402,23 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
 	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);
@@ -1547,7 +1574,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
 
 static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
 {
-	uint32_t attrs[2] = {
+	uint32_t attrs[3] = {
 		FATTR4_WORD0_RDATTR_ERROR,
 		FATTR4_WORD1_MOUNTED_ON_FILEID,
 	};
@@ -1570,20 +1597,26 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
 	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) {
+		if (hdr->minorversion > 1)
+			attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
+		p++, *p++ = cpu_to_be32(attrs[2] & readdir->bitmask[2]);
+	}
 	memcpy(verf, readdir->verifier.data, sizeof(verf));
-	dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
+
+	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]);
+			attrs[1] & readdir->bitmask[1],
+			attrs[2] & readdir->bitmask[2]);
 }
 
 static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
@@ -1642,7 +1675,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs
 {
 	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)
@@ -4060,6 +4093,60 @@ static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap,
 	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;
@@ -4402,7 +4489,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;
@@ -4510,6 +4597,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
 	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;
@@ -4517,7 +4609,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,
@@ -4536,7 +4628,8 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
 	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;
 
@@ -4547,9 +4640,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);
 }
 
 /*
@@ -5883,7 +5976,7 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp,
 	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;
 }
@@ -5909,7 +6002,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -5938,7 +6031,7 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -5964,7 +6057,8 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp,
 		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;
 }
@@ -6055,7 +6149,7 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -6084,7 +6178,7 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -6116,7 +6210,7 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -6218,7 +6312,7 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	 * 	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;
 }
@@ -6249,7 +6343,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 		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;
 }
@@ -6299,7 +6393,7 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp,
 		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;
 }
@@ -6326,7 +6420,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp,
 	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;
 }
@@ -6506,7 +6600,7 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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:
@@ -6687,7 +6781,7 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
 	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);
@@ -6720,7 +6814,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
 	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;
 }
@@ -7001,7 +7095,7 @@ static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp,
 	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;
 }
@@ -7133,7 +7227,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
 		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 --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 4bdffe0..0ead05b 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1922,7 +1922,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
 	data->args.inode = inode;
 	data->cred = get_rpccred(nfsi->layout->plh_lc_cred);
 	nfs_fattr_init(&data->fattr);
-	data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
+	data->args.bitmask = nfs4_cache_bitmask(NFS_SERVER(inode), NULL);
 	data->res.fattr = &data->fattr;
 	data->args.lastbytewritten = end_pos - 1;
 	data->res.server = NFS_SERVER(inode);
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 00af026..68c42be 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2379,8 +2379,21 @@ static int nfs_bdi_register(struct nfs_server *server)
 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,
-								0, NULL);
+	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 --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 1ef8eb4..1510f4f 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -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
@@ -344,6 +345,8 @@ extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
 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);
@@ -502,9 +505,19 @@ static inline void nfs4_label_free(struct nfs4_label *label)
 	}
 	return;
 }
+static inline u32 *nfs4_cache_bitmask(struct nfs_server *server, struct nfs4_label *label)
+{
+	if (label)
+		return server->cache_consistency_bitmask;
+
+	return server->cache_consistency_bitmask_nl;
+}
 #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) {}
+static inline u32 *
+nfs4_cache_bitmask(struct nfs_server *server, struct nfs4_label *label)
+{ return server->cache_consistency_bitmask; }
 #endif
 
 /*
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index e6ed3c2..2a4f1d4 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -145,11 +145,18 @@ struct nfs_server {
 	u32			attr_bitmask[3];/* V4 bitmask representing the set
 						   of attributes supported on this
 						   filesystem */
+	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 */
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d7ff806..f68b577 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2877,7 +2877,10 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
 		return;
 	}
 
+	isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	isec->sid = newsid;
+	isec->initialized = 1;
+
 	return;
 }
 
@@ -2965,6 +2968,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
 	if (rc)
 		return rc;
 
+	isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	isec->sid = newsid;
 	isec->initialized = 1;
 	return 0;
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 14/17] NFS: Extend NFS xattr handlers to accept the security namespace
  2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
                   ` (8 preceding siblings ...)
  2013-04-24 20:17 ` [PATCH 12/17] NFS: Add label lifecycle management Steve Dickson
@ 2013-04-24 20:18 ` Steve Dickson
       [not found] ` <1366834683-29075-1-git-send-email-SteveD-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:18 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl@davequigley.com>

The existing NFSv4 xattr handlers do not accept xattr calls to the security
namespace. This patch extends these handlers to accept xattrs from the security
namespace in addition to the default NFSv4 ACL namespace.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
---
 fs/nfs/nfs4proc.c   | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 security/security.c |  1 +
 2 files changed, 51 insertions(+)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index c459bbd..53cdb8b 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -5534,6 +5534,53 @@ static size_t nfs4_xattr_list_nfs4_acl(struct dentry *dentry, char *list,
 	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
  */
@@ -7286,6 +7333,9 @@ static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
 
 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 --git a/security/security.c b/security/security.c
index df8ade2..758af6b 100644
--- a/security/security.c
+++ b/security/security.c
@@ -660,6 +660,7 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer
 		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)
 {
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 15/17] Kconfig: Add Kconfig entry for Labeled NFS V4 client
  2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
@ 2013-04-24 20:18     ` Steve Dickson
  2013-04-24 20:17 ` [PATCH 02/17] NFSv4.2: Added NFS v4.2 support to the NFS client Steve Dickson
                       ` (11 subsequent siblings)
  12 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:18 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: Steve Dickson <steved-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

This patch adds the NFS_V4_SECURITY_LABEL entry which
enables security label support for the NFSv4 client

Signed-off-by: Steve Dickson <steved-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
 fs/nfs/Kconfig | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index 79c500e..771831d3 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -107,6 +107,7 @@ config NFS_V4_1
 config NFS_V4_2
 	bool "NFS client support for NFSv4.2"
 	depends on NFS_V4_1
+	select NFS_V4_SECURITY_LABEL
 	help
 	  This option enables support for minor version 1 of the NFSv4 protocol
 	  in the kernel's NFS client.
@@ -140,6 +141,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
-- 
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 15/17] Kconfig: Add Kconfig entry for Labeled NFS V4 client
@ 2013-04-24 20:18     ` Steve Dickson
  0 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:18 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: Steve Dickson <steved@redhat.com>

This patch adds the NFS_V4_SECURITY_LABEL entry which
enables security label support for the NFSv4 client

Signed-off-by: Steve Dickson <steved@redhat.com>
---
 fs/nfs/Kconfig | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index 79c500e..771831d3 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -107,6 +107,7 @@ config NFS_V4_1
 config NFS_V4_2
 	bool "NFS client support for NFSv4.2"
 	depends on NFS_V4_1
+	select NFS_V4_SECURITY_LABEL
 	help
 	  This option enables support for minor version 1 of the NFSv4 protocol
 	  in the kernel's NFS client.
@@ -140,6 +141,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
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 16/17] NFSD: Server implementation of MAC Labeling
  2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
                   ` (10 preceding siblings ...)
       [not found] ` <1366834683-29075-1-git-send-email-SteveD-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
@ 2013-04-24 20:18 ` Steve Dickson
  2013-04-24 21:28   ` J. Bruce Fields
  2013-04-24 20:18 ` [PATCH 17/17] Kconfig: Add Kconfig entry for Labeled NFS V4 server Steve Dickson
  12 siblings, 1 reply; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:18 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl@davequigley.com>

This patch adds the ability to encode and decode file labels on the server for
the purpose of sending them to the client and also to process label change
requests from the client.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
---
 fs/nfsd/nfs4proc.c |  41 ++++++++++++++++++
 fs/nfsd/nfs4xdr.c  | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 fs/nfsd/nfsd.h     |  10 +++++
 fs/nfsd/vfs.c      |  28 +++++++++++++
 fs/nfsd/vfs.h      |   2 +
 fs/nfsd/xdr4.h     |   3 ++
 6 files changed, 200 insertions(+), 5 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index ae73175..bb17589 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -42,6 +42,36 @@
 #include "current_stateid.h"
 #include "netns.h"
 
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+#include <linux/security.h>
+
+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, struct svc_fh *current_fh, struct nfsd4_o
 					(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, struct nfsd4_compound_state *cstate,
 	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, struct nfsd4_compound_state *cstate,
 					    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 --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index b38de7a..635b9c1 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -55,6 +55,11 @@
 #include "cache.h"
 #include "netns.h"
 
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+#include <linux/security.h>
+#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(-EMSGSIZE);
+
+	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_compoundargs *argp, u32 *bmval)
 
 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,41 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
 			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 (IS_ERR(*label)) {
+			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);
+	}
+#else 
+	*label = NULL;
+#endif
+
 	if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0
 	    || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1
 	    || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2)
@@ -582,7 +641,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
 		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;
 
@@ -832,7 +891,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
 		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;
@@ -846,7 +905,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
 			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;
@@ -1068,7 +1127,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta
 	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
@@ -1989,6 +2048,50 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, struct nfs4_ace *ace,
 			      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;
+	}
+
+	/*
+	 * For now we use a 0 here to indicate the null translation; in
+	 * the future we may place a call to translation code here.
+	 */
+	if ((*buflen -= 8) < 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:  */
@@ -2439,6 +2542,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);
@@ -3231,11 +3340,13 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
 		WRITE32(2);
 		WRITE32(0);
 		WRITE32(0);
+		WRITE32(0);
 	}
 	else {
 		WRITE32(2);
 		WRITE32(setattr->sa_bmval[0]);
 		WRITE32(setattr->sa_bmval[1]);
+		WRITE32(setattr->sa_bmval[2]);
 	}
 	ADJUST_ARGS();
 	return nfserr;
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index b5eade7..0a2e30c 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -328,7 +328,13 @@ void		nfsd_lockd_shutdown(void);
 #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \
 	(NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT)
 
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+#define NFSD4_2_SUPPORTED_ATTRS_WORD2 \
+	(NFSD4_SUPPORTED_ATTRS_WORD2 | NFSD4_1_SUPPORTED_ATTRS_WORD2 | \
+		FATTR4_WORD2_SECURITY_LABEL)
+#else
 #define NFSD4_2_SUPPORTED_ATTRS_WORD2 0
+#endif
 
 static inline u32 nfsd_suppattrs0(u32 minorversion)
 {
@@ -361,7 +367,11 @@ static inline u32 nfsd_suppattrs2(u32 minorversion)
 #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)
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+#define NFSD_WRITEABLE_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL
+#else
 #define NFSD_WRITEABLE_ATTRS_WORD2 0
+#endif
 
 #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \
 	NFSD_WRITEABLE_ATTRS_WORD0
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 2b2e239..96f9a82 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -28,6 +28,7 @@
 #include <asm/uaccess.h>
 #include <linux/exportfs.h>
 #include <linux/writeback.h>
+#include <linux/security.h>
 
 #ifdef CONFIG_NFSD_V3
 #include "xdr3.h"
@@ -621,6 +622,33 @@ int nfsd4_is_junction(struct dentry *dentry)
 		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;
+
+	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 nfserr_notsupp;
+}
+#endif
+
 #endif /* defined(CONFIG_NFSD_V4) */
 
 #ifdef CONFIG_NFSD_V3
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index 5b58941..a9d6f0f 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -56,6 +56,8 @@ int nfsd_mountpoint(struct dentry *, struct svc_export *);
 __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 --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 546f898..132a671 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -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 {
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* [PATCH 17/17] Kconfig: Add Kconfig entry for Labeled NFS V4 server
  2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
                   ` (11 preceding siblings ...)
  2013-04-24 20:18 ` [PATCH 16/17] NFSD: Server implementation of MAC Labeling Steve Dickson
@ 2013-04-24 20:18 ` Steve Dickson
  12 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 20:18 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: Steve Dickson <steved@redhat.com>

This patch adds the NFSd_V4_SECURITY_LABEL entry which
enables security label support for the NFSv4 server

Signed-off-by: Steve Dickson <steved@redhat.com>
---
 fs/nfsd/Kconfig | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
index 430b687..c37a046 100644
--- a/fs/nfsd/Kconfig
+++ b/fs/nfsd/Kconfig
@@ -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
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* Re: [PATCH 16/17] NFSD: Server implementation of MAC Labeling
  2013-04-24 20:18 ` [PATCH 16/17] NFSD: Server implementation of MAC Labeling Steve Dickson
@ 2013-04-24 21:28   ` J. Bruce Fields
  2013-04-24 22:14     ` Steve Dickson
  0 siblings, 1 reply; 71+ messages in thread
From: J. Bruce Fields @ 2013-04-24 21:28 UTC (permalink / raw)
  To: Steve Dickson
  Cc: Trond Myklebust, J. Bruce Fields, David P. Quigley,
	Linux NFS list, Linux FS devel list, Linux Security List,
	SELinux List

On Wed, Apr 24, 2013 at 04:18:02PM -0400, Steve Dickson wrote:
> From: David Quigley <dpquigl@davequigley.com>
> 
> This patch adds the ability to encode and decode file labels on the server for
> the purpose of sending them to the client and also to process label change
> requests from the client.
> 
> Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
> Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
> Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
> ---
>  fs/nfsd/nfs4proc.c |  41 ++++++++++++++++++
>  fs/nfsd/nfs4xdr.c  | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++---
>  fs/nfsd/nfsd.h     |  10 +++++
>  fs/nfsd/vfs.c      |  28 +++++++++++++
>  fs/nfsd/vfs.h      |   2 +
>  fs/nfsd/xdr4.h     |   3 ++
>  6 files changed, 200 insertions(+), 5 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index ae73175..bb17589 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -42,6 +42,36 @@
>  #include "current_stateid.h"
>  #include "netns.h"
>  
> +#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
> +#include <linux/security.h>
> +
> +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, struct svc_fh *current_fh, struct nfsd4_o
>  					(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, struct nfsd4_compound_state *cstate,
>  	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, struct nfsd4_compound_state *cstate,
>  					    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 --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index b38de7a..635b9c1 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -55,6 +55,11 @@
>  #include "cache.h"
>  #include "netns.h"
>  
> +#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
> +#include <linux/security.h>
> +#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(-EMSGSIZE);
> +
> +	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_compoundargs *argp, u32 *bmval)
>  
>  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,41 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
>  			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 (IS_ERR(*label)) {
> +			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);
> +	}
> +#else 
> +	*label = NULL;
> +#endif
> +
>  	if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0
>  	    || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1
>  	    || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2)
> @@ -582,7 +641,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
>  		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;
>  
> @@ -832,7 +891,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
>  		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;
> @@ -846,7 +905,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
>  			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;
> @@ -1068,7 +1127,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta
>  	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
> @@ -1989,6 +2048,50 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, struct nfs4_ace *ace,
>  			      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;
> +	}
> +
> +	/*
> +	 * For now we use a 0 here to indicate the null translation; in
> +	 * the future we may place a call to translation code here.
> +	 */
> +	if ((*buflen -= 8) < 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:  */
> @@ -2439,6 +2542,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);
> @@ -3231,11 +3340,13 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
>  		WRITE32(2);
>  		WRITE32(0);
>  		WRITE32(0);
> +		WRITE32(0);

Note that "2" above is the length of the bitmap field that follows.

>  	}
>  	else {
>  		WRITE32(2);
>  		WRITE32(setattr->sa_bmval[0]);
>  		WRITE32(setattr->sa_bmval[1]);
> +		WRITE32(setattr->sa_bmval[2]);

Ditto.

--b.

>  	}
>  	ADJUST_ARGS();
>  	return nfserr;
> diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
> index b5eade7..0a2e30c 100644
> --- a/fs/nfsd/nfsd.h
> +++ b/fs/nfsd/nfsd.h
> @@ -328,7 +328,13 @@ void		nfsd_lockd_shutdown(void);
>  #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \
>  	(NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT)
>  
> +#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
> +#define NFSD4_2_SUPPORTED_ATTRS_WORD2 \
> +	(NFSD4_SUPPORTED_ATTRS_WORD2 | NFSD4_1_SUPPORTED_ATTRS_WORD2 | \
> +		FATTR4_WORD2_SECURITY_LABEL)
> +#else
>  #define NFSD4_2_SUPPORTED_ATTRS_WORD2 0
> +#endif
>  
>  static inline u32 nfsd_suppattrs0(u32 minorversion)
>  {
> @@ -361,7 +367,11 @@ static inline u32 nfsd_suppattrs2(u32 minorversion)
>  #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)
> +#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
> +#define NFSD_WRITEABLE_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL
> +#else
>  #define NFSD_WRITEABLE_ATTRS_WORD2 0
> +#endif
>  
>  #define NFSD_SUPPATTR_EXCLCREAT_WORD0 \
>  	NFSD_WRITEABLE_ATTRS_WORD0
> diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
> index 2b2e239..96f9a82 100644
> --- a/fs/nfsd/vfs.c
> +++ b/fs/nfsd/vfs.c
> @@ -28,6 +28,7 @@
>  #include <asm/uaccess.h>
>  #include <linux/exportfs.h>
>  #include <linux/writeback.h>
> +#include <linux/security.h>
>  
>  #ifdef CONFIG_NFSD_V3
>  #include "xdr3.h"
> @@ -621,6 +622,33 @@ int nfsd4_is_junction(struct dentry *dentry)
>  		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;
> +
> +	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 nfserr_notsupp;
> +}
> +#endif
> +
>  #endif /* defined(CONFIG_NFSD_V4) */
>  
>  #ifdef CONFIG_NFSD_V3
> diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
> index 5b58941..a9d6f0f 100644
> --- a/fs/nfsd/vfs.h
> +++ b/fs/nfsd/vfs.h
> @@ -56,6 +56,8 @@ int nfsd_mountpoint(struct dentry *, struct svc_export *);
>  __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 --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
> index 546f898..132a671 100644
> --- a/fs/nfsd/xdr4.h
> +++ b/fs/nfsd/xdr4.h
> @@ -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 {
> -- 
> 1.8.1.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 01/17] NFSv4.2: Added v4.2 error codes
  2013-04-24 20:17 ` [PATCH 01/17] NFSv4.2: Added v4.2 error codes Steve Dickson
@ 2013-04-24 21:54   ` J. Bruce Fields
  0 siblings, 0 replies; 71+ messages in thread
From: J. Bruce Fields @ 2013-04-24 21:54 UTC (permalink / raw)
  To: Steve Dickson
  Cc: Trond Myklebust, J. Bruce Fields, David P. Quigley,
	Linux NFS list, Linux FS devel list, Linux Security List,
	SELinux List

On Wed, Apr 24, 2013 at 04:17:47PM -0400, Steve Dickson wrote:
> From: Steve Dickson <steved@redhat.com>

This seems uncontroversial; applying to 3.10 absent any objections,
except:

> 
> Signed-off-by: Steve Dickson <steved@redhat.com>
> ---
>  fs/nfsd/nfsd.h       | 6 ++++++
>  fs/nfsd/nfsproc.c    | 1 +
>  include/linux/nfs4.h | 8 ++++++++
>  3 files changed, 15 insertions(+)
> 
> diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
> index 07a473f..553b230 100644
> --- a/fs/nfsd/nfsd.h
> +++ b/fs/nfsd/nfsd.h
> @@ -243,6 +243,12 @@ void		nfsd_lockd_shutdown(void);
>  #define nfserr_reject_deleg		cpu_to_be32(NFS4ERR_REJECT_DELEG)
>  #define nfserr_returnconflict		cpu_to_be32(NFS4ERR_RETURNCONFLICT)
>  #define nfserr_deleg_revoked		cpu_to_be32(NFS4ERR_DELEG_REVOKED)
> +#define nfserr_partner_notsupp		cpu_to_be32(NFS4ERR_PARTNER_NOTSUPP)
> +#define nfserr_partner_no_auth		cpu_to_be32(NFS4ERR_PARTNER_NO_AUTH)
> +#define nfserr_metadata_notsupp		cpu_to_be32(NFS4ERR_METADATA_NOTSUPP)
> +#define nfserr_offload_denied		cpu_to_be32(NFS4ERR_OFFLOAD_DENIED)
> +#define nfserr_wrong_lfs		cpu_to_be32(NFS4ERR_WRONG_LFS)
> +#define nfs4err_badlabel		cpu_to_be32(NFS4ERR_BADLABEL)
>  
>  /* error codes for internal use */
>  /* if a request fails due to kmalloc failure, it gets dropped.
> diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
> index 54c6b3d..85289a5 100644
> --- a/fs/nfsd/nfsproc.c
> +++ b/fs/nfsd/nfsproc.c
> @@ -743,6 +743,7 @@ nfserrno (int errno)
>  		{ nfserr_notsupp, -EOPNOTSUPP },
>  		{ nfserr_toosmall, -ETOOSMALL },
>  		{ nfserr_serverfault, -ESERVERFAULT },
> +		{ nfs4err_badlabel, -EMSGSIZE },

dropping this one chunk, it should probably go in patch 16/17 with the
other nfsd code.

--b.

>  	};
>  	int	i;
>  
> diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
> index 7b8fc73..377fb3f 100644
> --- a/include/linux/nfs4.h
> +++ b/include/linux/nfs4.h
> @@ -219,6 +219,14 @@ enum nfsstat4 {
>  	NFS4ERR_REJECT_DELEG	= 10085,	/* on callback */
>  	NFS4ERR_RETURNCONFLICT	= 10086,	/* outstanding layoutreturn */
>  	NFS4ERR_DELEG_REVOKED	= 10087,	/* deleg./layout revoked */
> +
> +	/* nfs42 */
> +	NFS4ERR_PARTNER_NOTSUPP	= 10088,
> +	NFS4ERR_PARTNER_NO_AUTH	= 10089,
> +	NFS4ERR_METADATA_NOTSUPP = 10090,
> +	NFS4ERR_OFFLOAD_DENIED = 10091,
> +	NFS4ERR_WRONG_LFS = 10092,
> +	NFS4ERR_BADLABEL = 10093,
>  };
>  
>  static inline bool seqid_mutating_err(u32 err)
> -- 
> 1.8.1.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 02/17] NFSv4.2: Added NFS v4.2 support to the NFS client
  2013-04-24 20:17 ` [PATCH 02/17] NFSv4.2: Added NFS v4.2 support to the NFS client Steve Dickson
@ 2013-04-24 21:56   ` J. Bruce Fields
  0 siblings, 0 replies; 71+ messages in thread
From: J. Bruce Fields @ 2013-04-24 21:56 UTC (permalink / raw)
  To: Steve Dickson
  Cc: Trond Myklebust, J. Bruce Fields, David P. Quigley,
	Linux NFS list, Linux FS devel list, Linux Security List,
	SELinux List

On Wed, Apr 24, 2013 at 04:17:48PM -0400, Steve Dickson wrote:
> From: Steve Dickson <steved@redhat.com>
> 
> This enable NFSv4.2 support. To enable this code the
> CONFIG_NFS_V4_2 Kconfig define needs to be set and
> the -o v4.2 mount option need to be used.

Looks fine to me.--b.

> 
> Signed-off-by: Steve Dickson <steved@redhat.com>
> ---
>  fs/nfs/Kconfig       |  9 +++++++++
>  fs/nfs/callback.c    |  1 +
>  fs/nfs/nfs4client.c  |  5 +++++
>  fs/nfs/nfs4proc.c    | 15 +++++++++++++++
>  fs/nfs/super.c       |  7 ++++++-
>  include/linux/nfs4.h |  4 ++++
>  6 files changed, 40 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
> index 13ca196..79c500e 100644
> --- a/fs/nfs/Kconfig
> +++ b/fs/nfs/Kconfig
> @@ -104,6 +104,15 @@ config NFS_V4_1
>  
>  	  If unsure, say N.
>  
> +config NFS_V4_2
> +	bool "NFS client support for NFSv4.2"
> +	depends on NFS_V4_1
> +	help
> +	  This option enables support for minor version 1 of the NFSv4 protocol
> +	  in the kernel's NFS client.
> +
> +	  If unsure, say N.
> +
>  config PNFS_FILE_LAYOUT
>  	tristate
>  	depends on NFS_V4_1
> diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
> index 5088b57..cb35747 100644
> --- a/fs/nfs/callback.c
> +++ b/fs/nfs/callback.c
> @@ -279,6 +279,7 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, struct n
>  			ret = nfs4_callback_up_net(serv, net);
>  			break;
>  		case 1:
> +		case 2:
>  			ret = nfs41_callback_up_net(serv, net);
>  			break;
>  		default:
> diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
> index 66b6664..a30c6a7 100644
> --- a/fs/nfs/nfs4client.c
> +++ b/fs/nfs/nfs4client.c
> @@ -66,6 +66,11 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
>  	if (err)
>  		goto error;
>  
> +	if (cl_init->minorversion > NFS4_MAX_MINOR_VERSION) {
> +		err = -EINVAL;
> +		goto error;
> +	}
> +		
>  	spin_lock_init(&clp->cl_lock);
>  	INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
>  	rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> index 0ad025e..3fd1040 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -6746,11 +6746,26 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
>  };
>  #endif
>  
> +#if defined(CONFIG_NFS_V4_2)
> +static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
> +	.minor_version = 2,
> +	.call_sync = nfs4_call_sync_sequence,
> +	.match_stateid = nfs41_match_stateid,
> +	.find_root_sec = nfs41_find_root_sec,
> +	.reboot_recovery_ops = &nfs41_reboot_recovery_ops,
> +	.nograce_recovery_ops = &nfs41_nograce_recovery_ops,
> +	.state_renewal_ops = &nfs41_state_renewal_ops,
> +};
> +#endif
> +
>  const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
>  	[0] = &nfs_v4_0_minor_ops,
>  #if defined(CONFIG_NFS_V4_1)
>  	[1] = &nfs_v4_1_minor_ops,
>  #endif
> +#if defined(CONFIG_NFS_V4_2)
> +	[2] = &nfs_v4_2_minor_ops,
> +#endif
>  };
>  
>  const struct inode_operations nfs4_dir_inode_operations = {
> diff --git a/fs/nfs/super.c b/fs/nfs/super.c
> index 2f8a29d..29f2d86 100644
> --- a/fs/nfs/super.c
> +++ b/fs/nfs/super.c
> @@ -269,7 +269,7 @@ static match_table_t nfs_local_lock_tokens = {
>  
>  enum {
>  	Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0,
> -	Opt_vers_4_1,
> +	Opt_vers_4_1, Opt_vers_4_2,
>  
>  	Opt_vers_err
>  };
> @@ -280,6 +280,7 @@ static match_table_t nfs_vers_tokens = {
>  	{ Opt_vers_4, "4" },
>  	{ Opt_vers_4_0, "4.0" },
>  	{ Opt_vers_4_1, "4.1" },
> +	{ Opt_vers_4_2, "4.2" },
>  
>  	{ Opt_vers_err, NULL }
>  };
> @@ -1097,6 +1098,10 @@ static int nfs_parse_version_string(char *string,
>  		mnt->version = 4;
>  		mnt->minorversion = 1;
>  		break;
> +	case Opt_vers_4_2:
> +		mnt->version = 4;
> +		mnt->minorversion = 2;
> +		break;
>  	default:
>  		return 0;
>  	}
> diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
> index 377fb3f..7e18a66 100644
> --- a/include/linux/nfs4.h
> +++ b/include/linux/nfs4.h
> @@ -398,11 +398,15 @@ enum lock_type4 {
>  #define NFS4_VERSION 4
>  #define NFS4_MINOR_VERSION 0
>  
> +#if defined(CONFIG_NFS_V4_2)
> +#define NFS4_MAX_MINOR_VERSION 2
> +#else
>  #if defined(CONFIG_NFS_V4_1)
>  #define NFS4_MAX_MINOR_VERSION 1
>  #else
>  #define NFS4_MAX_MINOR_VERSION 0
>  #endif /* CONFIG_NFS_V4_1 */
> +#endif /* CONFIG_NFS_V4_2 */
>  
>  #define NFS4_DEBUG 1
>  
> -- 
> 1.8.1.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 03/17] NFSDv4.2: Added NFS v4.2 support to the NFS server
  2013-04-24 20:17 ` [PATCH 03/17] NFSDv4.2: Added NFS v4.2 support to the NFS server Steve Dickson
@ 2013-04-24 22:02   ` J. Bruce Fields
       [not found]     ` <20130424220226.GN20275-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
  0 siblings, 1 reply; 71+ messages in thread
From: J. Bruce Fields @ 2013-04-24 22:02 UTC (permalink / raw)
  To: Steve Dickson
  Cc: Trond Myklebust, J. Bruce Fields, David P. Quigley,
	Linux NFS list, Linux FS devel list, Linux Security List,
	SELinux List

On Wed, Apr 24, 2013 at 04:17:49PM -0400, Steve Dickson wrote:
> From: Steve Dickson <steved@redhat.com>
> 
> This enable NFSv4.2 support for the server. To enable this
> code do the following:
>   echo "+4.2" >/proc/fs/nfsd/versions
> 
> after the nfsd kernel module is loaded.
> 
> Signed-off-by: Steve Dickson <steved@redhat.com>
> ---
>  fs/nfsd/nfs4xdr.c | 1 +
>  fs/nfsd/nfsd.h    | 7 ++++++-
>  2 files changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index a272007..b38de7a 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -1572,6 +1572,7 @@ struct nfsd4_minorversion_ops {
>  static struct nfsd4_minorversion_ops nfsd4_minorversion[] = {
>  	[0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) },
>  	[1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
> +	[2] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
>  };
>  
>  static __be32
> diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
> index 553b230..b5eade7 100644
> --- a/fs/nfsd/nfsd.h
> +++ b/fs/nfsd/nfsd.h
> @@ -24,7 +24,7 @@
>  /*
>   * nfsd version
>   */
> -#define NFSD_SUPPORTED_MINOR_VERSION	1
> +#define NFSD_SUPPORTED_MINOR_VERSION	2
>  /*
>   * Maximum blocksizes supported by daemon under various circumstances.
>   */

These last two chunks belong with a later patch, whenever we make other
4.2 attribute changes:

--b.

> @@ -328,6 +328,8 @@ void		nfsd_lockd_shutdown(void);
>  #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \
>  	(NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT)
>  
> +#define NFSD4_2_SUPPORTED_ATTRS_WORD2 0
> +
>  static inline u32 nfsd_suppattrs0(u32 minorversion)
>  {
>  	return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0
> @@ -342,6 +344,9 @@ static inline u32 nfsd_suppattrs1(u32 minorversion)
>  
>  static inline u32 nfsd_suppattrs2(u32 minorversion)
>  {
> +	if (minorversion == 2)
> +		return NFSD4_2_SUPPORTED_ATTRS_WORD2;
> +
>  	return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2
>  			    : NFSD4_SUPPORTED_ATTRS_WORD2;
>  }
> -- 
> 1.8.1.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
  2013-04-24 20:17 ` [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry Steve Dickson
@ 2013-04-24 22:02   ` J. Bruce Fields
       [not found]     ` <20130424220258.GO20275-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
  0 siblings, 1 reply; 71+ messages in thread
From: J. Bruce Fields @ 2013-04-24 22:02 UTC (permalink / raw)
  To: Steve Dickson
  Cc: Trond Myklebust, J. Bruce Fields, David P. Quigley,
	Linux NFS list, Linux FS devel list, Linux Security List,
	SELinux List

On Wed, Apr 24, 2013 at 04:17:50PM -0400, Steve Dickson wrote:
> From: David Quigley <dpquigl@davequigley.com>
> 
> There is a time where we need to calculate a context without the
> inode having been created yet. To do this we take the negative dentry and
> calculate a context based on the process and the parent directory contexts.

How can we get review from security/selinux folks?  I can't apply these
without....

--b.

> 
> Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
> Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
> Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
> ---
>  include/linux/security.h | 27 +++++++++++++++++++++++++++
>  security/capability.c    |  8 ++++++++
>  security/security.c      | 10 ++++++++++
>  security/selinux/hooks.c | 35 +++++++++++++++++++++++++++++++++++
>  4 files changed, 80 insertions(+)
> 
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 032c366..f3d7956 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -26,6 +26,7 @@
>  #include <linux/capability.h>
>  #include <linux/slab.h>
>  #include <linux/err.h>
> +#include <linux/string.h>
>  
>  struct linux_binprm;
>  struct cred;
> @@ -306,6 +307,15 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
>   *	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.
>   *
> @@ -1443,6 +1453,10 @@ struct security_operations {
>  	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);
> @@ -1729,6 +1743,9 @@ int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *o
>  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);
> @@ -2033,6 +2050,16 @@ static inline int security_inode_alloc(struct inode *inode)
>  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,
> diff --git a/security/capability.c b/security/capability.c
> index 6783c3e..782045e 100644
> --- a/security/capability.c
> +++ b/security/capability.c
> @@ -108,6 +108,13 @@ static int cap_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
>  	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;
> @@ -930,6 +937,7 @@ void __init security_fixup_ops(struct security_operations *ops)
>  	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);
> diff --git a/security/security.c b/security/security.c
> index 03f248b..7c18e3c 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -12,6 +12,7 @@
>   */
>  
>  #include <linux/capability.h>
> +#include <linux/dcache.h>
>  #include <linux/module.h>
>  #include <linux/init.h>
>  #include <linux/kernel.h>
> @@ -324,6 +325,15 @@ void security_inode_free(struct inode *inode)
>  	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)
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 7171a95..622b205 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -2484,6 +2484,40 @@ static void selinux_inode_free_security(struct inode *inode)
>  	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)
> @@ -5531,6 +5565,7 @@ static struct security_operations selinux_ops = {
>  	.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,
> -- 
> 1.8.1.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 05/17] Security: Add Hook to test if the particular xattr is part of a MAC model.
  2013-04-24 20:17     ` Steve Dickson
  (?)
@ 2013-04-24 22:03     ` J. Bruce Fields
  -1 siblings, 0 replies; 71+ messages in thread
From: J. Bruce Fields @ 2013-04-24 22:03 UTC (permalink / raw)
  To: Steve Dickson
  Cc: Trond Myklebust, J. Bruce Fields, David P. Quigley,
	Linux NFS list, Linux FS devel list, Linux Security List,
	SELinux List

On Wed, Apr 24, 2013 at 04:17:51PM -0400, Steve Dickson wrote:
> From: David Quigley <dpquigl@davequigley.com>
> 
> The interface to request security labels from user space is the xattr
> interface. When requesting the security label from an NFS server it is
> important to make sure the requested xattr actually is a MAC label. This allows
> us to make sure that we get the desired semantics from the attribute instead of
> something else such as capabilities or a time based LSM.

Ditto.--b.

> 
> Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
> Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
> Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
> ---
>  include/linux/security.h   | 14 ++++++++++++++
>  security/capability.c      |  6 ++++++
>  security/security.c        |  6 ++++++
>  security/selinux/hooks.c   |  6 ++++++
>  security/smack/smack_lsm.c | 11 +++++++++++
>  5 files changed, 43 insertions(+)
> 
> diff --git a/include/linux/security.h b/include/linux/security.h
> index f3d7956..934f96f 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -1323,6 +1323,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
>   *	@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 1 if name is a MAC
> + *	attribute otherwise returns 0.
> + *	@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.
> @@ -1604,6 +1611,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);
> @@ -1857,6 +1865,7 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode);
>  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);
> @@ -2545,6 +2554,11 @@ static inline int security_netlink_send(struct sock *sk, struct sk_buff *skb)
>  	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 --git a/security/capability.c b/security/capability.c
> index 782045e..71e5052 100644
> --- a/security/capability.c
> +++ b/security/capability.c
> @@ -822,6 +822,11 @@ static int cap_setprocattr(struct task_struct *p, char *name, void *value,
>  	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;
> @@ -1041,6 +1046,7 @@ void __init security_fixup_ops(struct security_operations *ops)
>  	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 --git a/security/security.c b/security/security.c
> index 7c18e3c..07391f3 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -1057,6 +1057,12 @@ int security_netlink_send(struct sock *sk, struct sk_buff *skb)
>  	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 --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 622b205..273e28b 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -5423,6 +5423,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);
> @@ -5661,6 +5666,7 @@ static struct security_operations selinux_ops = {
>  	.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 --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index fa64740..ca01d71 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -3329,6 +3329,16 @@ static void smack_audit_rule_free(void *vrule)
>  #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
> @@ -3524,6 +3534,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,
> -- 
> 1.8.1.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 06/17] LSM: Add flags field to security_sb_set_mnt_opts for in kernel mount data.
  2013-04-24 20:17 ` [PATCH 06/17] LSM: Add flags field to security_sb_set_mnt_opts for in kernel mount data Steve Dickson
@ 2013-04-24 22:03   ` J. Bruce Fields
  0 siblings, 0 replies; 71+ messages in thread
From: J. Bruce Fields @ 2013-04-24 22:03 UTC (permalink / raw)
  To: Steve Dickson
  Cc: Trond Myklebust, J. Bruce Fields, David P. Quigley,
	Linux NFS list, Linux FS devel list, Linux Security List,
	SELinux List

On Wed, Apr 24, 2013 at 04:17:52PM -0400, Steve Dickson wrote:
> From: David Quigley <dpquigl@davequigley.com>
> 
> There is no way to differentiate if a text mount option is passed from user
> space or the kernel. A flags field is being added to the
> security_sb_set_mnt_opts hook to allow for in kernel security flags to be sent
> to the LSM for processing in addition to the text options received from mount.
> This patch also updated existing code to fix compilation errors.

Ditto.

--b.

> 
> Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
> Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
> Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
> Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
> ---
>  fs/nfs/super.c           |  3 ++-
>  include/linux/security.h | 13 ++++++++++---
>  security/capability.c    |  5 ++++-
>  security/security.c      |  7 +++++--
>  security/selinux/hooks.c | 12 ++++++++++--
>  5 files changed, 31 insertions(+), 9 deletions(-)
> 
> diff --git a/fs/nfs/super.c b/fs/nfs/super.c
> index 29f2d86..d84eb57 100644
> --- a/fs/nfs/super.c
> +++ b/fs/nfs/super.c
> @@ -2378,7 +2378,8 @@ static int nfs_bdi_register(struct nfs_server *server)
>  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);
> +	return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts,
> +								0, NULL);
>  }
>  EXPORT_SYMBOL_GPL(nfs_set_sb_security);
>  
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 934f96f..4ab51e2 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -1456,7 +1456,9 @@ 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);
> @@ -1747,7 +1749,10 @@ int security_sb_mount(const char *dev_name, struct path *path,
>  		      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);
> @@ -2037,7 +2042,9 @@ static inline int security_sb_pivotroot(struct path *old_path,
>  }
>  
>  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;
>  }
> diff --git a/security/capability.c b/security/capability.c
> index 71e5052..4708973 100644
> --- a/security/capability.c
> +++ b/security/capability.c
> @@ -91,7 +91,10 @@ static int cap_sb_pivotroot(struct path *old_path, struct path *new_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;
> diff --git a/security/security.c b/security/security.c
> index 07391f3..df8ade2 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -294,9 +294,12 @@ 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)
> +				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);
>  
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 273e28b..6cb24ec 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -552,7 +552,9 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
>   * 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;
> @@ -580,6 +582,12 @@ static int selinux_set_mnt_opts(struct super_block *sb,
>  			"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
> @@ -949,7 +957,7 @@ static int superblock_doinit(struct super_block *sb, void *data)
>  		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);
> -- 
> 1.8.1.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 07/17] SELinux: Add new labeling type native labels
  2013-04-24 20:17 ` [PATCH 07/17] SELinux: Add new labeling type native labels Steve Dickson
@ 2013-04-24 22:03   ` J. Bruce Fields
       [not found]     ` <20130424220359.GR20275-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
  0 siblings, 1 reply; 71+ messages in thread
From: J. Bruce Fields @ 2013-04-24 22:03 UTC (permalink / raw)
  To: Steve Dickson
  Cc: Trond Myklebust, J. Bruce Fields, David P. Quigley,
	Linux NFS list, Linux FS devel list, Linux Security List,
	SELinux List

On Wed, Apr 24, 2013 at 04:17:53PM -0400, Steve Dickson wrote:
> From: David Quigley <dpquigl@davequigley.com>
> 
> There currently doesn't exist a labeling type that is adequate for use with
> labeled NFS. Since NFS doesn't really support xattrs we can't use the use xattr
> labeling behavior. For this we developed a new labeling type. The native
> labeling type is used solely by NFS to ensure NFS inodes are labeled at runtime
> by the NFS code instead of relying on the SELinux security server on the client
> end.

Ditto, can we get get an ACK/NACK from someone responsible for this
code?

--b.

> 
> Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
> Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
> Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
> ---
>  include/linux/security.h            |  3 +++
>  security/selinux/hooks.c            | 35 ++++++++++++++++++++++++++---------
>  security/selinux/include/security.h |  2 ++
>  security/selinux/ss/policydb.c      |  5 ++++-
>  4 files changed, 35 insertions(+), 10 deletions(-)
> 
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 4ab51e2..bc924d7 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -61,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;
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 6cb24ec..d7ff806 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -81,6 +81,7 @@
>  #include <linux/syslog.h>
>  #include <linux/user_namespace.h>
>  #include <linux/export.h>
> +#include <linux/security.h>
>  #include <linux/msg.h>
>  #include <linux/shm.h>
>  
> @@ -284,13 +285,14 @@ static void superblock_free_security(struct super_block *sb)
>  
>  /* 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);
> @@ -678,14 +680,21 @@ static int selinux_set_mnt_opts(struct super_block *sb,
>  	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);
> @@ -700,6 +709,11 @@ static int selinux_set_mnt_opts(struct super_block *sb,
>  	 * 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,
> @@ -731,7 +745,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
>  	}
>  
>  	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");
> @@ -1199,6 +1214,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
>  	}
>  
>  	switch (sbsec->behavior) {
> +	case SECURITY_FS_USE_NATIVE:
> +		break;
>  	case SECURITY_FS_USE_XATTR:
>  		if (!inode->i_op->getxattr) {
>  			isec->sid = sbsec->def_sid;
> diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
> index 6d38851..8fd8e18 100644
> --- a/security/selinux/include/security.h
> +++ b/security/selinux/include/security.h
> @@ -169,6 +169,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 --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
> index 9cd9b7c..c8adde3 100644
> --- a/security/selinux/ss/policydb.c
> +++ b/security/selinux/ss/policydb.c
> @@ -2168,7 +2168,10 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
>  
>  				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;
> -- 
> 1.8.1.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 07/17] SELinux: Add new labeling type native labels
  2013-04-24 22:03   ` J. Bruce Fields
       [not found]     ` <20130424220359.GR20275-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
@ 2013-04-24 22:06         ` David Quigley
  0 siblings, 0 replies; 71+ messages in thread
From: David Quigley @ 2013-04-24 22:06 UTC (permalink / raw)
  To: J. Bruce Fields, eparis-H+wXaHxf7aLQT0dZR+AlfA
  Cc: Steve Dickson, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List

On 04/24/2013 18:03, J. Bruce Fields wrote:
> On Wed, Apr 24, 2013 at 04:17:53PM -0400, Steve Dickson wrote:
>> From: David Quigley <dpquigl-a7DkhOHRHBuN9aS15agKxg@public.gmane.org>
>>
>> There currently doesn't exist a labeling type that is adequate for 
>> use with
>> labeled NFS. Since NFS doesn't really support xattrs we can't use 
>> the use xattr
>> labeling behavior. For this we developed a new labeling type. The 
>> native
>> labeling type is used solely by NFS to ensure NFS inodes are labeled 
>> at runtime
>> by the NFS code instead of relying on the SELinux security server on 
>> the client
>> end.
>
> Ditto, can we get get an ACK/NACK from someone responsible for this
> code?
>
> --b.
>
>>
>> Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
>> Signed-off-by: Miguel Rodel Felipe <Rodel_FM-geVtEqcQUv4Eyxwt80+Gtti2O/JbrIOy@public.gmane.org>
>> Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene-geVtEqcQUv4Eyxwt80+Gtti2O/JbrIOy@public.gmane.org>
>> Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG-geVtEqcQUv4Eyxwt80+Gtti2O/JbrIOy@public.gmane.org>
>> ---
>>  include/linux/security.h            |  3 +++
>>  security/selinux/hooks.c            | 35 
>> ++++++++++++++++++++++++++---------
>>  security/selinux/include/security.h |  2 ++
>>  security/selinux/ss/policydb.c      |  5 ++++-
>>  4 files changed, 35 insertions(+), 10 deletions(-)
>>
>> diff --git a/include/linux/security.h b/include/linux/security.h
>> index 4ab51e2..bc924d7 100644
>> --- a/include/linux/security.h
>> +++ b/include/linux/security.h
>> @@ -61,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;
>> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
>> index 6cb24ec..d7ff806 100644
>> --- a/security/selinux/hooks.c
>> +++ b/security/selinux/hooks.c
>> @@ -81,6 +81,7 @@
>>  #include <linux/syslog.h>
>>  #include <linux/user_namespace.h>
>>  #include <linux/export.h>
>> +#include <linux/security.h>
>>  #include <linux/msg.h>
>>  #include <linux/shm.h>
>>
>> @@ -284,13 +285,14 @@ static void superblock_free_security(struct 
>> super_block *sb)
>>
>>  /* 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);
>> @@ -678,14 +680,21 @@ static int selinux_set_mnt_opts(struct 
>> super_block *sb,
>>  	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);
>> @@ -700,6 +709,11 @@ static int selinux_set_mnt_opts(struct 
>> super_block *sb,
>>  	 * 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,
>> @@ -731,7 +745,8 @@ static int selinux_set_mnt_opts(struct 
>> super_block *sb,
>>  	}
>>
>>  	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");
>> @@ -1199,6 +1214,8 @@ static int inode_doinit_with_dentry(struct 
>> inode *inode, struct dentry *opt_dent
>>  	}
>>
>>  	switch (sbsec->behavior) {
>> +	case SECURITY_FS_USE_NATIVE:
>> +		break;
>>  	case SECURITY_FS_USE_XATTR:
>>  		if (!inode->i_op->getxattr) {
>>  			isec->sid = sbsec->def_sid;
>> diff --git a/security/selinux/include/security.h 
>> b/security/selinux/include/security.h
>> index 6d38851..8fd8e18 100644
>> --- a/security/selinux/include/security.h
>> +++ b/security/selinux/include/security.h
>> @@ -169,6 +169,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 --git a/security/selinux/ss/policydb.c 
>> b/security/selinux/ss/policydb.c
>> index 9cd9b7c..c8adde3 100644
>> --- a/security/selinux/ss/policydb.c
>> +++ b/security/selinux/ss/policydb.c
>> @@ -2168,7 +2168,10 @@ static int ocontext_read(struct policydb *p, 
>> struct policydb_compat_info *info,
>>
>>  				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;
>> --
>> 1.8.1.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-nfs" 
>> in
>> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> --
> To unsubscribe from this list: send the line "unsubscribe
> linux-security-module" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


Eric,
    Can I get a review of the code and an ACK? I know people did this a 
long time ago but we need someone to review it more recently and I've 
been told you've been the one keeping an eye on SELinux related kernel 
changes.

Dave
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 07/17] SELinux: Add new labeling type native labels
@ 2013-04-24 22:06         ` David Quigley
  0 siblings, 0 replies; 71+ messages in thread
From: David Quigley @ 2013-04-24 22:06 UTC (permalink / raw)
  To: J. Bruce Fields, eparis
  Cc: Steve Dickson, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List

On 04/24/2013 18:03, J. Bruce Fields wrote:
> On Wed, Apr 24, 2013 at 04:17:53PM -0400, Steve Dickson wrote:
>> From: David Quigley <dpquigl@davequigley.com>
>>
>> There currently doesn't exist a labeling type that is adequate for 
>> use with
>> labeled NFS. Since NFS doesn't really support xattrs we can't use 
>> the use xattr
>> labeling behavior. For this we developed a new labeling type. The 
>> native
>> labeling type is used solely by NFS to ensure NFS inodes are labeled 
>> at runtime
>> by the NFS code instead of relying on the SELinux security server on 
>> the client
>> end.
>
> Ditto, can we get get an ACK/NACK from someone responsible for this
> code?
>
> --b.
>
>>
>> Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
>> Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
>> Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
>> Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
>> ---
>>  include/linux/security.h            |  3 +++
>>  security/selinux/hooks.c            | 35 
>> ++++++++++++++++++++++++++---------
>>  security/selinux/include/security.h |  2 ++
>>  security/selinux/ss/policydb.c      |  5 ++++-
>>  4 files changed, 35 insertions(+), 10 deletions(-)
>>
>> diff --git a/include/linux/security.h b/include/linux/security.h
>> index 4ab51e2..bc924d7 100644
>> --- a/include/linux/security.h
>> +++ b/include/linux/security.h
>> @@ -61,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;
>> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
>> index 6cb24ec..d7ff806 100644
>> --- a/security/selinux/hooks.c
>> +++ b/security/selinux/hooks.c
>> @@ -81,6 +81,7 @@
>>  #include <linux/syslog.h>
>>  #include <linux/user_namespace.h>
>>  #include <linux/export.h>
>> +#include <linux/security.h>
>>  #include <linux/msg.h>
>>  #include <linux/shm.h>
>>
>> @@ -284,13 +285,14 @@ static void superblock_free_security(struct 
>> super_block *sb)
>>
>>  /* 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);
>> @@ -678,14 +680,21 @@ static int selinux_set_mnt_opts(struct 
>> super_block *sb,
>>  	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);
>> @@ -700,6 +709,11 @@ static int selinux_set_mnt_opts(struct 
>> super_block *sb,
>>  	 * 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,
>> @@ -731,7 +745,8 @@ static int selinux_set_mnt_opts(struct 
>> super_block *sb,
>>  	}
>>
>>  	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");
>> @@ -1199,6 +1214,8 @@ static int inode_doinit_with_dentry(struct 
>> inode *inode, struct dentry *opt_dent
>>  	}
>>
>>  	switch (sbsec->behavior) {
>> +	case SECURITY_FS_USE_NATIVE:
>> +		break;
>>  	case SECURITY_FS_USE_XATTR:
>>  		if (!inode->i_op->getxattr) {
>>  			isec->sid = sbsec->def_sid;
>> diff --git a/security/selinux/include/security.h 
>> b/security/selinux/include/security.h
>> index 6d38851..8fd8e18 100644
>> --- a/security/selinux/include/security.h
>> +++ b/security/selinux/include/security.h
>> @@ -169,6 +169,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 --git a/security/selinux/ss/policydb.c 
>> b/security/selinux/ss/policydb.c
>> index 9cd9b7c..c8adde3 100644
>> --- a/security/selinux/ss/policydb.c
>> +++ b/security/selinux/ss/policydb.c
>> @@ -2168,7 +2168,10 @@ static int ocontext_read(struct policydb *p, 
>> struct policydb_compat_info *info,
>>
>>  				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;
>> --
>> 1.8.1.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-nfs" 
>> in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> --
> To unsubscribe from this list: send the line "unsubscribe
> linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


Eric,
    Can I get a review of the code and an ACK? I know people did this a 
long time ago but we need someone to review it more recently and I've 
been told you've been the one keeping an eye on SELinux related kernel 
changes.

Dave

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 07/17] SELinux: Add new labeling type native labels
@ 2013-04-24 22:06         ` David Quigley
  0 siblings, 0 replies; 71+ messages in thread
From: David Quigley @ 2013-04-24 22:06 UTC (permalink / raw)
  To: J. Bruce Fields, eparis
  Cc: Steve Dickson, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List

On 04/24/2013 18:03, J. Bruce Fields wrote:
> On Wed, Apr 24, 2013 at 04:17:53PM -0400, Steve Dickson wrote:
>> From: David Quigley <dpquigl@davequigley.com>
>>
>> There currently doesn't exist a labeling type that is adequate for 
>> use with
>> labeled NFS. Since NFS doesn't really support xattrs we can't use 
>> the use xattr
>> labeling behavior. For this we developed a new labeling type. The 
>> native
>> labeling type is used solely by NFS to ensure NFS inodes are labeled 
>> at runtime
>> by the NFS code instead of relying on the SELinux security server on 
>> the client
>> end.
>
> Ditto, can we get get an ACK/NACK from someone responsible for this
> code?
>
> --b.
>
>>
>> Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
>> Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
>> Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
>> Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
>> ---
>>  include/linux/security.h            |  3 +++
>>  security/selinux/hooks.c            | 35 
>> ++++++++++++++++++++++++++---------
>>  security/selinux/include/security.h |  2 ++
>>  security/selinux/ss/policydb.c      |  5 ++++-
>>  4 files changed, 35 insertions(+), 10 deletions(-)
>>
>> diff --git a/include/linux/security.h b/include/linux/security.h
>> index 4ab51e2..bc924d7 100644
>> --- a/include/linux/security.h
>> +++ b/include/linux/security.h
>> @@ -61,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;
>> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
>> index 6cb24ec..d7ff806 100644
>> --- a/security/selinux/hooks.c
>> +++ b/security/selinux/hooks.c
>> @@ -81,6 +81,7 @@
>>  #include <linux/syslog.h>
>>  #include <linux/user_namespace.h>
>>  #include <linux/export.h>
>> +#include <linux/security.h>
>>  #include <linux/msg.h>
>>  #include <linux/shm.h>
>>
>> @@ -284,13 +285,14 @@ static void superblock_free_security(struct 
>> super_block *sb)
>>
>>  /* 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);
>> @@ -678,14 +680,21 @@ static int selinux_set_mnt_opts(struct 
>> super_block *sb,
>>  	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);
>> @@ -700,6 +709,11 @@ static int selinux_set_mnt_opts(struct 
>> super_block *sb,
>>  	 * 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,
>> @@ -731,7 +745,8 @@ static int selinux_set_mnt_opts(struct 
>> super_block *sb,
>>  	}
>>
>>  	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");
>> @@ -1199,6 +1214,8 @@ static int inode_doinit_with_dentry(struct 
>> inode *inode, struct dentry *opt_dent
>>  	}
>>
>>  	switch (sbsec->behavior) {
>> +	case SECURITY_FS_USE_NATIVE:
>> +		break;
>>  	case SECURITY_FS_USE_XATTR:
>>  		if (!inode->i_op->getxattr) {
>>  			isec->sid = sbsec->def_sid;
>> diff --git a/security/selinux/include/security.h 
>> b/security/selinux/include/security.h
>> index 6d38851..8fd8e18 100644
>> --- a/security/selinux/include/security.h
>> +++ b/security/selinux/include/security.h
>> @@ -169,6 +169,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 --git a/security/selinux/ss/policydb.c 
>> b/security/selinux/ss/policydb.c
>> index 9cd9b7c..c8adde3 100644
>> --- a/security/selinux/ss/policydb.c
>> +++ b/security/selinux/ss/policydb.c
>> @@ -2168,7 +2168,10 @@ static int ocontext_read(struct policydb *p, 
>> struct policydb_compat_info *info,
>>
>>  				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;
>> --
>> 1.8.1.4
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-nfs" 
>> in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> --
> To unsubscribe from this list: send the line "unsubscribe
> linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


Eric,
    Can I get a review of the code and an ACK? I know people did this a 
long time ago but we need someone to review it more recently and I've 
been told you've been the one keeping an eye on SELinux related kernel 
changes.

Dave

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
  2013-04-24 22:02   ` J. Bruce Fields
       [not found]     ` <20130424220258.GO20275-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
@ 2013-04-24 22:09         ` David Quigley
  0 siblings, 0 replies; 71+ messages in thread
From: David Quigley @ 2013-04-24 22:09 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: Steve Dickson, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List

I'll contact Eric Paris about reviewing the patches. I'm sure he would 
be happy to look them over. Hopefully we can get it done soon.

Dave
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
@ 2013-04-24 22:09         ` David Quigley
  0 siblings, 0 replies; 71+ messages in thread
From: David Quigley @ 2013-04-24 22:09 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: Steve Dickson, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List

I'll contact Eric Paris about reviewing the patches. I'm sure he would 
be happy to look them over. Hopefully we can get it done soon.

Dave

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
@ 2013-04-24 22:09         ` David Quigley
  0 siblings, 0 replies; 71+ messages in thread
From: David Quigley @ 2013-04-24 22:09 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: Steve Dickson, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List

I'll contact Eric Paris about reviewing the patches. I'm sure he would 
be happy to look them over. Hopefully we can get it done soon.

Dave

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
  2013-04-24 22:02   ` J. Bruce Fields
@ 2013-04-24 22:12         ` Steve Dickson
  0 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 22:12 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: Trond Myklebust, J. Bruce Fields, David P. Quigley,
	Linux NFS list, Linux FS devel list, Linux Security List,
	SELinux List



On 24/04/13 18:02, J. Bruce Fields wrote:
> n Wed, Apr 24, 2013 at 04:17:50PM -0400, Steve Dickson wrote:
>> > From: David Quigley <dpquigl-a7DkhOHRHBuN9aS15agKxg@public.gmane.org>
>> > 
>> > There is a time where we need to calculate a context without the
>> > inode having been created yet. To do this we take the negative dentry and
>> > calculate a context based on the process and the parent directory contexts.
> How can we get review from security/selinux folks?  I can't apply these
> without....
Its my understand they have been reviewed a number times... And they have not
change since I've working on these patches... 

steved.
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
@ 2013-04-24 22:12         ` Steve Dickson
  0 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 22:12 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: Trond Myklebust, J. Bruce Fields, David P. Quigley,
	Linux NFS list, Linux FS devel list, Linux Security List,
	SELinux List



On 24/04/13 18:02, J. Bruce Fields wrote:
> n Wed, Apr 24, 2013 at 04:17:50PM -0400, Steve Dickson wrote:
>> > From: David Quigley <dpquigl@davequigley.com>
>> > 
>> > There is a time where we need to calculate a context without the
>> > inode having been created yet. To do this we take the negative dentry and
>> > calculate a context based on the process and the parent directory contexts.
> How can we get review from security/selinux folks?  I can't apply these
> without....
Its my understand they have been reviewed a number times... And they have not
change since I've working on these patches... 

steved.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
  2013-04-24 22:12         ` Steve Dickson
  (?)
@ 2013-04-24 22:14             ` David Quigley
  -1 siblings, 0 replies; 71+ messages in thread
From: David Quigley @ 2013-04-24 22:14 UTC (permalink / raw)
  To: Steve Dickson
  Cc: J. Bruce Fields, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List, eparis-H+wXaHxf7aLQT0dZR+AlfA,
	sds-+05T5uksL2qpZYMLLGbcSA

On 04/24/2013 18:12, Steve Dickson wrote:
> On 24/04/13 18:02, J. Bruce Fields wrote:
>> n Wed, Apr 24, 2013 at 04:17:50PM -0400, Steve Dickson wrote:
>>> > From: David Quigley <dpquigl-a7DkhOHRHBuN9aS15agKxg@public.gmane.org>
>>> >
>>> > There is a time where we need to calculate a context without the
>>> > inode having been created yet. To do this we take the negative 
>>> dentry and
>>> > calculate a context based on the process and the parent directory 
>>> contexts.
>> How can we get review from security/selinux folks?  I can't apply 
>> these
>> without....
> Its my understand they have been reviewed a number times... And they 
> have not
> change since I've working on these patches...
>
> steved.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" 
> in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

That is correct. They have been acked in the past and haven't changed 
at all since then. I have contacted Eric Paris about reviewing them 
anyway so you can have a more recent ack on the patches.

Dave
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
@ 2013-04-24 22:14             ` David Quigley
  0 siblings, 0 replies; 71+ messages in thread
From: David Quigley @ 2013-04-24 22:14 UTC (permalink / raw)
  To: Steve Dickson
  Cc: J. Bruce Fields, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List, eparis, sds

On 04/24/2013 18:12, Steve Dickson wrote:
> On 24/04/13 18:02, J. Bruce Fields wrote:
>> n Wed, Apr 24, 2013 at 04:17:50PM -0400, Steve Dickson wrote:
>>> > From: David Quigley <dpquigl@davequigley.com>
>>> >
>>> > There is a time where we need to calculate a context without the
>>> > inode having been created yet. To do this we take the negative 
>>> dentry and
>>> > calculate a context based on the process and the parent directory 
>>> contexts.
>> How can we get review from security/selinux folks?  I can't apply 
>> these
>> without....
> Its my understand they have been reviewed a number times... And they 
> have not
> change since I've working on these patches...
>
> steved.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" 
> in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

That is correct. They have been acked in the past and haven't changed 
at all since then. I have contacted Eric Paris about reviewing them 
anyway so you can have a more recent ack on the patches.

Dave

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
@ 2013-04-24 22:14             ` David Quigley
  0 siblings, 0 replies; 71+ messages in thread
From: David Quigley @ 2013-04-24 22:14 UTC (permalink / raw)
  To: Steve Dickson
  Cc: J. Bruce Fields, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List, eparis, sds

On 04/24/2013 18:12, Steve Dickson wrote:
> On 24/04/13 18:02, J. Bruce Fields wrote:
>> n Wed, Apr 24, 2013 at 04:17:50PM -0400, Steve Dickson wrote:
>>> > From: David Quigley <dpquigl@davequigley.com>
>>> >
>>> > There is a time where we need to calculate a context without the
>>> > inode having been created yet. To do this we take the negative 
>>> dentry and
>>> > calculate a context based on the process and the parent directory 
>>> contexts.
>> How can we get review from security/selinux folks?  I can't apply 
>> these
>> without....
> Its my understand they have been reviewed a number times... And they 
> have not
> change since I've working on these patches...
>
> steved.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" 
> in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

That is correct. They have been acked in the past and haven't changed 
at all since then. I have contacted Eric Paris about reviewing them 
anyway so you can have a more recent ack on the patches.

Dave

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 16/17] NFSD: Server implementation of MAC Labeling
  2013-04-24 21:28   ` J. Bruce Fields
@ 2013-04-24 22:14     ` Steve Dickson
       [not found]       ` <51785962.7080008-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 71+ messages in thread
From: Steve Dickson @ 2013-04-24 22:14 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: Trond Myklebust, J. Bruce Fields, David P. Quigley,
	Linux NFS list, Linux FS devel list, Linux Security List,
	SELinux List

On 24/04/13 17:28, J. Bruce Fields wrote:
>> @@ -3231,11 +3340,13 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
>> >  		WRITE32(2);
>> >  		WRITE32(0);
>> >  		WRITE32(0);
>> > +		WRITE32(0);
> Note that "2" above is the length of the bitmap field that follows.
> 
>> >  	}
>> >  	else {
>> >  		WRITE32(2);
>> >  		WRITE32(setattr->sa_bmval[0]);
>> >  		WRITE32(setattr->sa_bmval[1]);
>> > +		WRITE32(setattr->sa_bmval[2]);
> Ditto.
Right... I did miss that....

steved.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
  2013-04-24 22:14             ` David Quigley
@ 2013-04-24 23:03                 ` J. Bruce Fields
  -1 siblings, 0 replies; 71+ messages in thread
From: J. Bruce Fields @ 2013-04-24 23:03 UTC (permalink / raw)
  To: David Quigley
  Cc: Steve Dickson, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List, eparis-H+wXaHxf7aLQT0dZR+AlfA,
	sds-+05T5uksL2qpZYMLLGbcSA

On Wed, Apr 24, 2013 at 06:14:16PM -0400, David Quigley wrote:
> On 04/24/2013 18:12, Steve Dickson wrote:
> >On 24/04/13 18:02, J. Bruce Fields wrote:
> >>n Wed, Apr 24, 2013 at 04:17:50PM -0400, Steve Dickson wrote:
> >>>> From: David Quigley <dpquigl-a7DkhOHRHBuN9aS15agKxg@public.gmane.org>
> >>>>
> >>>> There is a time where we need to calculate a context without the
> >>>> inode having been created yet. To do this we take the
> >>>negative dentry and
> >>>> calculate a context based on the process and the parent
> >>>directory contexts.
> >>How can we get review from security/selinux folks?  I can't
> >>apply these
> >>without....
> >Its my understand they have been reviewed a number times... And
> >they have not
> >change since I've working on these patches...
> >
> >steved.
> >--
> >To unsubscribe from this list: send the line "unsubscribe
> >linux-nfs" in
> >the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> >More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> That is correct. They have been acked in the past and haven't
> changed at all since then.

Oh, OK, sorry--I lost track.  (Do you have a pointer?)

> I have contacted Eric Paris about
> reviewing them anyway so you can have a more recent ack on the
> patches.

But that would be helpful too, thanks.

--b.
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
@ 2013-04-24 23:03                 ` J. Bruce Fields
  0 siblings, 0 replies; 71+ messages in thread
From: J. Bruce Fields @ 2013-04-24 23:03 UTC (permalink / raw)
  To: David Quigley
  Cc: Steve Dickson, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List, eparis, sds

On Wed, Apr 24, 2013 at 06:14:16PM -0400, David Quigley wrote:
> On 04/24/2013 18:12, Steve Dickson wrote:
> >On 24/04/13 18:02, J. Bruce Fields wrote:
> >>n Wed, Apr 24, 2013 at 04:17:50PM -0400, Steve Dickson wrote:
> >>>> From: David Quigley <dpquigl@davequigley.com>
> >>>>
> >>>> There is a time where we need to calculate a context without the
> >>>> inode having been created yet. To do this we take the
> >>>negative dentry and
> >>>> calculate a context based on the process and the parent
> >>>directory contexts.
> >>How can we get review from security/selinux folks?  I can't
> >>apply these
> >>without....
> >Its my understand they have been reviewed a number times... And
> >they have not
> >change since I've working on these patches...
> >
> >steved.
> >--
> >To unsubscribe from this list: send the line "unsubscribe
> >linux-nfs" in
> >the body of a message to majordomo@vger.kernel.org
> >More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> That is correct. They have been acked in the past and haven't
> changed at all since then.

Oh, OK, sorry--I lost track.  (Do you have a pointer?)

> I have contacted Eric Paris about
> reviewing them anyway so you can have a more recent ack on the
> patches.

But that would be helpful too, thanks.

--b.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 16/17] NFSD: Server implementation of MAC Labeling
  2013-04-24 22:14     ` Steve Dickson
@ 2013-04-24 23:04           ` J. Bruce Fields
  0 siblings, 0 replies; 71+ messages in thread
From: J. Bruce Fields @ 2013-04-24 23:04 UTC (permalink / raw)
  To: Steve Dickson
  Cc: Trond Myklebust, J. Bruce Fields, David P. Quigley,
	Linux NFS list, Linux FS devel list, Linux Security List,
	SELinux List

On Wed, Apr 24, 2013 at 06:14:58PM -0400, Steve Dickson wrote:
> On 24/04/13 17:28, J. Bruce Fields wrote:
> >> @@ -3231,11 +3340,13 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
> >> >  		WRITE32(2);
> >> >  		WRITE32(0);
> >> >  		WRITE32(0);
> >> > +		WRITE32(0);
> > Note that "2" above is the length of the bitmap field that follows.
> > 
> >> >  	}
> >> >  	else {
> >> >  		WRITE32(2);
> >> >  		WRITE32(setattr->sa_bmval[0]);
> >> >  		WRITE32(setattr->sa_bmval[1]);
> >> > +		WRITE32(setattr->sa_bmval[2]);
> > Ditto.
> Right... I did miss that....

With that change the pynfs tests all pass this time.

--b.

diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 75b5b6d..7bbc698 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3310,13 +3310,13 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
 
 	RESERVE_SPACE(12);
 	if (nfserr) {
-		WRITE32(2);
+		WRITE32(3);
 		WRITE32(0);
 		WRITE32(0);
 		WRITE32(0);
 	}
 	else {
-		WRITE32(2);
+		WRITE32(3);
 		WRITE32(setattr->sa_bmval[0]);
 		WRITE32(setattr->sa_bmval[1]);
 		WRITE32(setattr->sa_bmval[2]);
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* Re: [PATCH 16/17] NFSD: Server implementation of MAC Labeling
@ 2013-04-24 23:04           ` J. Bruce Fields
  0 siblings, 0 replies; 71+ messages in thread
From: J. Bruce Fields @ 2013-04-24 23:04 UTC (permalink / raw)
  To: Steve Dickson
  Cc: Trond Myklebust, J. Bruce Fields, David P. Quigley,
	Linux NFS list, Linux FS devel list, Linux Security List,
	SELinux List

On Wed, Apr 24, 2013 at 06:14:58PM -0400, Steve Dickson wrote:
> On 24/04/13 17:28, J. Bruce Fields wrote:
> >> @@ -3231,11 +3340,13 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
> >> >  		WRITE32(2);
> >> >  		WRITE32(0);
> >> >  		WRITE32(0);
> >> > +		WRITE32(0);
> > Note that "2" above is the length of the bitmap field that follows.
> > 
> >> >  	}
> >> >  	else {
> >> >  		WRITE32(2);
> >> >  		WRITE32(setattr->sa_bmval[0]);
> >> >  		WRITE32(setattr->sa_bmval[1]);
> >> > +		WRITE32(setattr->sa_bmval[2]);
> > Ditto.
> Right... I did miss that....

With that change the pynfs tests all pass this time.

--b.

diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 75b5b6d..7bbc698 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3310,13 +3310,13 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
 
 	RESERVE_SPACE(12);
 	if (nfserr) {
-		WRITE32(2);
+		WRITE32(3);
 		WRITE32(0);
 		WRITE32(0);
 		WRITE32(0);
 	}
 	else {
-		WRITE32(2);
+		WRITE32(3);
 		WRITE32(setattr->sa_bmval[0]);
 		WRITE32(setattr->sa_bmval[1]);
 		WRITE32(setattr->sa_bmval[2]);

^ permalink raw reply related	[flat|nested] 71+ messages in thread

* Re: [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
  2013-04-24 23:03                 ` J. Bruce Fields
@ 2013-04-24 23:05                   ` David Quigley
  -1 siblings, 0 replies; 71+ messages in thread
From: David Quigley @ 2013-04-24 23:05 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: Steve Dickson, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List, eparis, sds

On 04/24/2013 19:03, J. Bruce Fields wrote:
> On Wed, Apr 24, 2013 at 06:14:16PM -0400, David Quigley wrote:
>> On 04/24/2013 18:12, Steve Dickson wrote:
>> >On 24/04/13 18:02, J. Bruce Fields wrote:
>> >>n Wed, Apr 24, 2013 at 04:17:50PM -0400, Steve Dickson wrote:
>> >>>> From: David Quigley <dpquigl@davequigley.com>
>> >>>>
>> >>>> There is a time where we need to calculate a context without 
>> the
>> >>>> inode having been created yet. To do this we take the
>> >>>negative dentry and
>> >>>> calculate a context based on the process and the parent
>> >>>directory contexts.
>> >>How can we get review from security/selinux folks?  I can't
>> >>apply these
>> >>without....
>> >Its my understand they have been reviewed a number times... And
>> >they have not
>> >change since I've working on these patches...
>> >
>> >steved.
>> >--
>> >To unsubscribe from this list: send the line "unsubscribe
>> >linux-nfs" in
>> >the body of a message to majordomo@vger.kernel.org
>> >More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>> That is correct. They have been acked in the past and haven't
>> changed at all since then.
>
> Oh, OK, sorry--I lost track.  (Do you have a pointer?)

I may be able to crawl through MARC.info for my old email address to 
see if I can find it but that is probably more effort than its worth. 
All of those ACKs and what not are saved in my old NSA email (assuming 
its still being kept around).

>
>> I have contacted Eric Paris about
>> reviewing them anyway so you can have a more recent ack on the
>> patches.
>
> But that would be helpful too, thanks.
>
> --b.


I think its a good idea to have Eric look through them anyway just to 
be sure.

Dave

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
@ 2013-04-24 23:05                   ` David Quigley
  0 siblings, 0 replies; 71+ messages in thread
From: David Quigley @ 2013-04-24 23:05 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: Steve Dickson, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List, eparis, sds

On 04/24/2013 19:03, J. Bruce Fields wrote:
> On Wed, Apr 24, 2013 at 06:14:16PM -0400, David Quigley wrote:
>> On 04/24/2013 18:12, Steve Dickson wrote:
>> >On 24/04/13 18:02, J. Bruce Fields wrote:
>> >>n Wed, Apr 24, 2013 at 04:17:50PM -0400, Steve Dickson wrote:
>> >>>> From: David Quigley <dpquigl@davequigley.com>
>> >>>>
>> >>>> There is a time where we need to calculate a context without 
>> the
>> >>>> inode having been created yet. To do this we take the
>> >>>negative dentry and
>> >>>> calculate a context based on the process and the parent
>> >>>directory contexts.
>> >>How can we get review from security/selinux folks?  I can't
>> >>apply these
>> >>without....
>> >Its my understand they have been reviewed a number times... And
>> >they have not
>> >change since I've working on these patches...
>> >
>> >steved.
>> >--
>> >To unsubscribe from this list: send the line "unsubscribe
>> >linux-nfs" in
>> >the body of a message to majordomo@vger.kernel.org
>> >More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>> That is correct. They have been acked in the past and haven't
>> changed at all since then.
>
> Oh, OK, sorry--I lost track.  (Do you have a pointer?)

I may be able to crawl through MARC.info for my old email address to 
see if I can find it but that is probably more effort than its worth. 
All of those ACKs and what not are saved in my old NSA email (assuming 
its still being kept around).

>
>> I have contacted Eric Paris about
>> reviewing them anyway so you can have a more recent ack on the
>> patches.
>
> But that would be helpful too, thanks.
>
> --b.


I think its a good idea to have Eric look through them anyway just to 
be sure.

Dave

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
  2013-04-24 23:05                   ` David Quigley
@ 2013-04-25  1:27                     ` Casey Schaufler
  -1 siblings, 0 replies; 71+ messages in thread
From: Casey Schaufler @ 2013-04-25  1:27 UTC (permalink / raw)
  To: David Quigley
  Cc: J. Bruce Fields, Steve Dickson, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List, eparis, sds, Casey Schaufler

On 4/24/2013 4:05 PM, David Quigley wrote:
> On 04/24/2013 19:03, J. Bruce Fields wrote:
>> On Wed, Apr 24, 2013 at 06:14:16PM -0400, David Quigley wrote:
>>> On 04/24/2013 18:12, Steve Dickson wrote:
>>> >On 24/04/13 18:02, J. Bruce Fields wrote:
>>> >>n Wed, Apr 24, 2013 at 04:17:50PM -0400, Steve Dickson wrote:
>>> >>>> From: David Quigley <dpquigl@davequigley.com>
>>> >>>>
>>> >>>> There is a time where we need to calculate a context without the
>>> >>>> inode having been created yet. To do this we take the
>>> >>>negative dentry and
>>> >>>> calculate a context based on the process and the parent
>>> >>>directory contexts.
>>> >>How can we get review from security/selinux folks?  I can't
>>> >>apply these
>>> >>without....
>>> >Its my understand they have been reviewed a number times... And
>>> >they have not
>>> >change since I've working on these patches...
>>> >
>>> >steved.
>>> >--
>>> >To unsubscribe from this list: send the line "unsubscribe
>>> >linux-nfs" in
>>> >the body of a message to majordomo@vger.kernel.org
>>> >More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>
>>> That is correct. They have been acked in the past and haven't
>>> changed at all since then.

For the record, I haven't ACKed because I have been unable to
get the NFS labeling to work with Smack. I also note that I
am not NAKing, either, as I have not had the time to determine
what's wrong. I do know that the ideas floated at the time turned
out to not be the problem. Hopefully I'll have time to look
into this sometime.


>>
>> Oh, OK, sorry--I lost track.  (Do you have a pointer?)
>
> I may be able to crawl through MARC.info for my old email address to
> see if I can find it but that is probably more effort than its worth.
> All of those ACKs and what not are saved in my old NSA email (assuming
> its still being kept around).
>
>>
>>> I have contacted Eric Paris about
>>> reviewing them anyway so you can have a more recent ack on the
>>> patches.
>>
>> But that would be helpful too, thanks.
>>
>> --b.
>
>
> I think its a good idea to have Eric look through them anyway just to
> be sure.
>
> Dave
>
> -- 
> This message was distributed to subscribers of the selinux mailing list.
> If you no longer wish to subscribe, send mail to
> majordomo@tycho.nsa.gov with
> the words "unsubscribe selinux" without quotes as the message.
>


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
@ 2013-04-25  1:27                     ` Casey Schaufler
  0 siblings, 0 replies; 71+ messages in thread
From: Casey Schaufler @ 2013-04-25  1:27 UTC (permalink / raw)
  To: David Quigley
  Cc: J. Bruce Fields, Steve Dickson, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List, eparis, sds, Casey Schaufler

On 4/24/2013 4:05 PM, David Quigley wrote:
> On 04/24/2013 19:03, J. Bruce Fields wrote:
>> On Wed, Apr 24, 2013 at 06:14:16PM -0400, David Quigley wrote:
>>> On 04/24/2013 18:12, Steve Dickson wrote:
>>> >On 24/04/13 18:02, J. Bruce Fields wrote:
>>> >>n Wed, Apr 24, 2013 at 04:17:50PM -0400, Steve Dickson wrote:
>>> >>>> From: David Quigley <dpquigl@davequigley.com>
>>> >>>>
>>> >>>> There is a time where we need to calculate a context without the
>>> >>>> inode having been created yet. To do this we take the
>>> >>>negative dentry and
>>> >>>> calculate a context based on the process and the parent
>>> >>>directory contexts.
>>> >>How can we get review from security/selinux folks?  I can't
>>> >>apply these
>>> >>without....
>>> >Its my understand they have been reviewed a number times... And
>>> >they have not
>>> >change since I've working on these patches...
>>> >
>>> >steved.
>>> >--
>>> >To unsubscribe from this list: send the line "unsubscribe
>>> >linux-nfs" in
>>> >the body of a message to majordomo@vger.kernel.org
>>> >More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>
>>> That is correct. They have been acked in the past and haven't
>>> changed at all since then.

For the record, I haven't ACKed because I have been unable to
get the NFS labeling to work with Smack. I also note that I
am not NAKing, either, as I have not had the time to determine
what's wrong. I do know that the ideas floated at the time turned
out to not be the problem. Hopefully I'll have time to look
into this sometime.


>>
>> Oh, OK, sorry--I lost track.  (Do you have a pointer?)
>
> I may be able to crawl through MARC.info for my old email address to
> see if I can find it but that is probably more effort than its worth.
> All of those ACKs and what not are saved in my old NSA email (assuming
> its still being kept around).
>
>>
>>> I have contacted Eric Paris about
>>> reviewing them anyway so you can have a more recent ack on the
>>> patches.
>>
>> But that would be helpful too, thanks.
>>
>> --b.
>
>
> I think its a good idea to have Eric look through them anyway just to
> be sure.
>
> Dave
>
> -- 
> This message was distributed to subscribers of the selinux mailing list.
> If you no longer wish to subscribe, send mail to
> majordomo@tycho.nsa.gov with
> the words "unsubscribe selinux" without quotes as the message.
>


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
  2013-04-25  1:27                     ` Casey Schaufler
@ 2013-04-25  1:43                         ` J. Bruce Fields
  -1 siblings, 0 replies; 71+ messages in thread
From: J. Bruce Fields @ 2013-04-25  1:43 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: David Quigley, Steve Dickson, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List, eparis-H+wXaHxf7aLQT0dZR+AlfA,
	sds-+05T5uksL2qpZYMLLGbcSA

On Wed, Apr 24, 2013 at 06:27:26PM -0700, Casey Schaufler wrote:
> On 4/24/2013 4:05 PM, David Quigley wrote:
> > On 04/24/2013 19:03, J. Bruce Fields wrote:
> >> On Wed, Apr 24, 2013 at 06:14:16PM -0400, David Quigley wrote:
> >>> On 04/24/2013 18:12, Steve Dickson wrote:
> >>> >On 24/04/13 18:02, J. Bruce Fields wrote:
> >>> >>n Wed, Apr 24, 2013 at 04:17:50PM -0400, Steve Dickson wrote:
> >>> >>>> From: David Quigley <dpquigl-a7DkhOHRHBuN9aS15agKxg@public.gmane.org>
> >>> >>>>
> >>> >>>> There is a time where we need to calculate a context without the
> >>> >>>> inode having been created yet. To do this we take the
> >>> >>>negative dentry and
> >>> >>>> calculate a context based on the process and the parent
> >>> >>>directory contexts.
> >>> >>How can we get review from security/selinux folks?  I can't
> >>> >>apply these
> >>> >>without....
> >>> >Its my understand they have been reviewed a number times... And
> >>> >they have not
> >>> >change since I've working on these patches...
> >>> >
> >>> >steved.
> >>> >--
> >>> >To unsubscribe from this list: send the line "unsubscribe
> >>> >linux-nfs" in
> >>> >the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> >>> >More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >>>
> >>> That is correct. They have been acked in the past and haven't
> >>> changed at all since then.
> 
> For the record, I haven't ACKed because I have been unable to
> get the NFS labeling to work with Smack. I also note that I
> am not NAKing, either, as I have not had the time to determine
> what's wrong. I do know that the ideas floated at the time turned
> out to not be the problem. Hopefully I'll have time to look
> into this sometime.

OK, we'll add an:

neither-acked-nor-nacked-by: Casey Schaufler <casey-iSGtlc1asvQWG2LlvL+J4A@public.gmane.org>

--b.
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry.
@ 2013-04-25  1:43                         ` J. Bruce Fields
  0 siblings, 0 replies; 71+ messages in thread
From: J. Bruce Fields @ 2013-04-25  1:43 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: David Quigley, Steve Dickson, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List, eparis, sds

On Wed, Apr 24, 2013 at 06:27:26PM -0700, Casey Schaufler wrote:
> On 4/24/2013 4:05 PM, David Quigley wrote:
> > On 04/24/2013 19:03, J. Bruce Fields wrote:
> >> On Wed, Apr 24, 2013 at 06:14:16PM -0400, David Quigley wrote:
> >>> On 04/24/2013 18:12, Steve Dickson wrote:
> >>> >On 24/04/13 18:02, J. Bruce Fields wrote:
> >>> >>n Wed, Apr 24, 2013 at 04:17:50PM -0400, Steve Dickson wrote:
> >>> >>>> From: David Quigley <dpquigl@davequigley.com>
> >>> >>>>
> >>> >>>> There is a time where we need to calculate a context without the
> >>> >>>> inode having been created yet. To do this we take the
> >>> >>>negative dentry and
> >>> >>>> calculate a context based on the process and the parent
> >>> >>>directory contexts.
> >>> >>How can we get review from security/selinux folks?  I can't
> >>> >>apply these
> >>> >>without....
> >>> >Its my understand they have been reviewed a number times... And
> >>> >they have not
> >>> >change since I've working on these patches...
> >>> >
> >>> >steved.
> >>> >--
> >>> >To unsubscribe from this list: send the line "unsubscribe
> >>> >linux-nfs" in
> >>> >the body of a message to majordomo@vger.kernel.org
> >>> >More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >>>
> >>> That is correct. They have been acked in the past and haven't
> >>> changed at all since then.
> 
> For the record, I haven't ACKed because I have been unable to
> get the NFS labeling to work with Smack. I also note that I
> am not NAKing, either, as I have not had the time to determine
> what's wrong. I do know that the ideas floated at the time turned
> out to not be the problem. Hopefully I'll have time to look
> into this sometime.

OK, we'll add an:

neither-acked-nor-nacked-by: Casey Schaufler <casey@schaufler-ca.com>

--b.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 03/17] NFSDv4.2: Added NFS v4.2 support to the NFS server
  2013-04-24 22:02   ` J. Bruce Fields
@ 2013-04-25 14:10         ` Steve Dickson
  0 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-25 14:10 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: Trond Myklebust, J. Bruce Fields, David P. Quigley,
	Linux NFS list, Linux FS devel list, Linux Security List,
	SELinux List

On 24/04/13 18:02, J. Bruce Fields wrote:
> On Wed, Apr 24, 2013 at 04:17:49PM -0400, Steve Dickson wrote:
>> From: Steve Dickson <steved-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>>
>> This enable NFSv4.2 support for the server. To enable this
>> code do the following:
>>   echo "+4.2" >/proc/fs/nfsd/versions
>>
>> after the nfsd kernel module is loaded.
>>
>> Signed-off-by: Steve Dickson <steved-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>> ---
>>  fs/nfsd/nfs4xdr.c | 1 +
>>  fs/nfsd/nfsd.h    | 7 ++++++-
>>  2 files changed, 7 insertions(+), 1 deletion(-)
>>
>> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
>> index a272007..b38de7a 100644
>> --- a/fs/nfsd/nfs4xdr.c
>> +++ b/fs/nfsd/nfs4xdr.c
>> @@ -1572,6 +1572,7 @@ struct nfsd4_minorversion_ops {
>>  static struct nfsd4_minorversion_ops nfsd4_minorversion[] = {
>>  	[0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) },
>>  	[1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
>> +	[2] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
>>  };
>>  
>>  static __be32
>> diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
>> index 553b230..b5eade7 100644
>> --- a/fs/nfsd/nfsd.h
>> +++ b/fs/nfsd/nfsd.h
>> @@ -24,7 +24,7 @@
>>  /*
>>   * nfsd version
>>   */
>> -#define NFSD_SUPPORTED_MINOR_VERSION	1
>> +#define NFSD_SUPPORTED_MINOR_VERSION	2
>>  /*
>>   * Maximum blocksizes supported by daemon under various circumstances.
>>   */
> 
> These last two chunks belong with a later patch, whenever we make other
> 4.2 attribute changes:
I'm a bit confused by this request... 

The purpose of this patch is to allow echo "+4.2" >/proc/fs/nfsd/versions 
to work. Basically enabling the setting of the v4.2. Without the above two chunks 
that echo will fail which means v4.2 can not be set.

Plus the two chunks below are where the generic 4.2 attribute changes are 
made:
>> @@ -328,6 +328,8 @@ void		nfsd_lockd_shutdown(void);
>>  #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \
>>  	(NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT)
>>  
>> +#define NFSD4_2_SUPPORTED_ATTRS_WORD2 0
>> +
>>  static inline u32 nfsd_suppattrs0(u32 minorversion)
>>  {
>>  	return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0
>> @@ -342,6 +344,9 @@ static inline u32 nfsd_suppattrs1(u32 minorversion)
>>  
>>  static inline u32 nfsd_suppattrs2(u32 minorversion)
>>  {
>> +	if (minorversion == 2)
>> +		return NFSD4_2_SUPPORTED_ATTRS_WORD2;
>> +
>>  	return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2
>>  			    : NFSD4_SUPPORTED_ATTRS_WORD2;
>>  }
Now in the [PATCH 16/17] NFSD: Server implementation of MAC Labeling
patch is where the definition of NFSD4_2_SUPPORTED_ATTRS_WORD2
changes when labels are enabled.

So it seems to me this patch does want you wanted it to do.
Enable the setting of v4.2 and only return 4.2 attributes 
on a v4.2 mount. It's just at this point there are no 4.2
attributes defined...

What am I missing?

steved.
 
 
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 03/17] NFSDv4.2: Added NFS v4.2 support to the NFS server
@ 2013-04-25 14:10         ` Steve Dickson
  0 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-04-25 14:10 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: Trond Myklebust, J. Bruce Fields, David P. Quigley,
	Linux NFS list, Linux FS devel list, Linux Security List,
	SELinux List

On 24/04/13 18:02, J. Bruce Fields wrote:
> On Wed, Apr 24, 2013 at 04:17:49PM -0400, Steve Dickson wrote:
>> From: Steve Dickson <steved@redhat.com>
>>
>> This enable NFSv4.2 support for the server. To enable this
>> code do the following:
>>   echo "+4.2" >/proc/fs/nfsd/versions
>>
>> after the nfsd kernel module is loaded.
>>
>> Signed-off-by: Steve Dickson <steved@redhat.com>
>> ---
>>  fs/nfsd/nfs4xdr.c | 1 +
>>  fs/nfsd/nfsd.h    | 7 ++++++-
>>  2 files changed, 7 insertions(+), 1 deletion(-)
>>
>> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
>> index a272007..b38de7a 100644
>> --- a/fs/nfsd/nfs4xdr.c
>> +++ b/fs/nfsd/nfs4xdr.c
>> @@ -1572,6 +1572,7 @@ struct nfsd4_minorversion_ops {
>>  static struct nfsd4_minorversion_ops nfsd4_minorversion[] = {
>>  	[0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) },
>>  	[1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
>> +	[2] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
>>  };
>>  
>>  static __be32
>> diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
>> index 553b230..b5eade7 100644
>> --- a/fs/nfsd/nfsd.h
>> +++ b/fs/nfsd/nfsd.h
>> @@ -24,7 +24,7 @@
>>  /*
>>   * nfsd version
>>   */
>> -#define NFSD_SUPPORTED_MINOR_VERSION	1
>> +#define NFSD_SUPPORTED_MINOR_VERSION	2
>>  /*
>>   * Maximum blocksizes supported by daemon under various circumstances.
>>   */
> 
> These last two chunks belong with a later patch, whenever we make other
> 4.2 attribute changes:
I'm a bit confused by this request... 

The purpose of this patch is to allow echo "+4.2" >/proc/fs/nfsd/versions 
to work. Basically enabling the setting of the v4.2. Without the above two chunks 
that echo will fail which means v4.2 can not be set.

Plus the two chunks below are where the generic 4.2 attribute changes are 
made:
>> @@ -328,6 +328,8 @@ void		nfsd_lockd_shutdown(void);
>>  #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \
>>  	(NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT)
>>  
>> +#define NFSD4_2_SUPPORTED_ATTRS_WORD2 0
>> +
>>  static inline u32 nfsd_suppattrs0(u32 minorversion)
>>  {
>>  	return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0
>> @@ -342,6 +344,9 @@ static inline u32 nfsd_suppattrs1(u32 minorversion)
>>  
>>  static inline u32 nfsd_suppattrs2(u32 minorversion)
>>  {
>> +	if (minorversion == 2)
>> +		return NFSD4_2_SUPPORTED_ATTRS_WORD2;
>> +
>>  	return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2
>>  			    : NFSD4_SUPPORTED_ATTRS_WORD2;
>>  }
Now in the [PATCH 16/17] NFSD: Server implementation of MAC Labeling
patch is where the definition of NFSD4_2_SUPPORTED_ATTRS_WORD2
changes when labels are enabled.

So it seems to me this patch does want you wanted it to do.
Enable the setting of v4.2 and only return 4.2 attributes 
on a v4.2 mount. It's just at this point there are no 4.2
attributes defined...

What am I missing?

steved.
 
 

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 03/17] NFSDv4.2: Added NFS v4.2 support to the NFS server
  2013-04-25 14:10         ` Steve Dickson
  (?)
@ 2013-04-25 18:26         ` J. Bruce Fields
  -1 siblings, 0 replies; 71+ messages in thread
From: J. Bruce Fields @ 2013-04-25 18:26 UTC (permalink / raw)
  To: Steve Dickson
  Cc: Trond Myklebust, J. Bruce Fields, David P. Quigley,
	Linux NFS list, Linux FS devel list, Linux Security List,
	SELinux List

On Thu, Apr 25, 2013 at 10:10:52AM -0400, Steve Dickson wrote:
> On 24/04/13 18:02, J. Bruce Fields wrote:
> > On Wed, Apr 24, 2013 at 04:17:49PM -0400, Steve Dickson wrote:
> >> From: Steve Dickson <steved@redhat.com>
> >>
> >> This enable NFSv4.2 support for the server. To enable this
> >> code do the following:
> >>   echo "+4.2" >/proc/fs/nfsd/versions
> >>
> >> after the nfsd kernel module is loaded.
> >>
> >> Signed-off-by: Steve Dickson <steved@redhat.com>
> >> ---
> >>  fs/nfsd/nfs4xdr.c | 1 +
> >>  fs/nfsd/nfsd.h    | 7 ++++++-
> >>  2 files changed, 7 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> >> index a272007..b38de7a 100644
> >> --- a/fs/nfsd/nfs4xdr.c
> >> +++ b/fs/nfsd/nfs4xdr.c
> >> @@ -1572,6 +1572,7 @@ struct nfsd4_minorversion_ops {
> >>  static struct nfsd4_minorversion_ops nfsd4_minorversion[] = {
> >>  	[0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) },
> >>  	[1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
> >> +	[2] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
> >>  };
> >>  
> >>  static __be32
> >> diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
> >> index 553b230..b5eade7 100644
> >> --- a/fs/nfsd/nfsd.h
> >> +++ b/fs/nfsd/nfsd.h
> >> @@ -24,7 +24,7 @@
> >>  /*
> >>   * nfsd version
> >>   */
> >> -#define NFSD_SUPPORTED_MINOR_VERSION	1
> >> +#define NFSD_SUPPORTED_MINOR_VERSION	2
> >>  /*
> >>   * Maximum blocksizes supported by daemon under various circumstances.
> >>   */
> > 
> > These last two chunks belong with a later patch, whenever we make other
> > 4.2 attribute changes:
> I'm a bit confused by this request... 
> 
> The purpose of this patch is to allow echo "+4.2" >/proc/fs/nfsd/versions 
> to work. Basically enabling the setting of the v4.2. Without the above two chunks 
> that echo will fail which means v4.2 can not be set.

Right by "last two chunks" I meant the below.--b.

> 
> Plus the two chunks below are where the generic 4.2 attribute changes are 
> made:
> >> @@ -328,6 +328,8 @@ void		nfsd_lockd_shutdown(void);
> >>  #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \
> >>  	(NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT)
> >>  
> >> +#define NFSD4_2_SUPPORTED_ATTRS_WORD2 0
> >> +
> >>  static inline u32 nfsd_suppattrs0(u32 minorversion)
> >>  {
> >>  	return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0
> >> @@ -342,6 +344,9 @@ static inline u32 nfsd_suppattrs1(u32 minorversion)
> >>  
> >>  static inline u32 nfsd_suppattrs2(u32 minorversion)
> >>  {
> >> +	if (minorversion == 2)
> >> +		return NFSD4_2_SUPPORTED_ATTRS_WORD2;
> >> +
> >>  	return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD2
> >>  			    : NFSD4_SUPPORTED_ATTRS_WORD2;
> >>  }
> Now in the [PATCH 16/17] NFSD: Server implementation of MAC Labeling
> patch is where the definition of NFSD4_2_SUPPORTED_ATTRS_WORD2
> changes when labels are enabled.
> 
> So it seems to me this patch does want you wanted it to do.
> Enable the setting of v4.2 and only return 4.2 attributes 
> on a v4.2 mount. It's just at this point there are no 4.2
> attributes defined...
> 
> What am I missing?
> 
> steved.
>  
>  

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 13/17] NFS: Client implementation of Labeled-NFS
  2013-05-08 18:41                     ` Steve Dickson
  (?)
@ 2013-05-08 18:47                     ` Myklebust, Trond
  -1 siblings, 0 replies; 71+ messages in thread
From: Myklebust, Trond @ 2013-05-08 18:47 UTC (permalink / raw)
  To: Steve Dickson
  Cc: J. Bruce Fields, David P. Quigley, Linux NFS list,
	Linux FS devel list, Linux Security List, SELinux List

On Wed, 2013-05-08 at 14:41 -0400, Steve Dickson wrote:
> 
> On 08/05/13 14:31, Myklebust, Trond wrote:
> > On Wed, 2013-05-08 at 14:27 -0400, Steve Dickson wrote:
> >>
> >> On 08/05/13 14:07, Myklebust, Trond wrote:
> >>> On Wed, 2013-05-08 at 13:39 -0400, Steve Dickson wrote:
> >>>>
> >>>> On 08/05/13 12:43, Myklebust, Trond wrote:
> >>>>> On Wed, 2013-05-08 at 12:39 -0400, Steve Dickson wrote:
> >>>>>>
> >>>>>> On 01/05/13 15:03, Myklebust, Trond wrote:
> >>>>>>>> @@ -2409,10 +2468,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
> >>>>>>>>>  			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;
> >>>>>>>>> +#endif
> >>>>>>>>> +		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;
> >>>>>>>>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> >>>>>>>>> +		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
> >>>>>>> Why? How is the security label relevant to cache consistency?
> >>>>>> Its used to the set label bit in the GETATTR that goes out with ACCESS compound.
> >>>>>
> >>>>> The GETATTR that goes out with ACCESS is only there in order to get the
> >>>>> change attribute so that we know when to invalidate the access cache. It
> >>>>> is _only_ for cache consistency.
> >>>>>
> >>>>> Why do we need to fetch the label too?
> >>>>>
> >>>> I think I answer this in the other thread but in short 
> >>>> access updates the inode and so it appears the goal 
> >>>> is to synchronize inode updates and label updates.
> >>>
> >>> Those are not inode updates.
> >> Ah... OK... but they all end up calling nfs_refresh_inode() with 
> >> the valid label pointer... So there is an effort to keep the 
> >> inode attribute cache updates synchronized with label updates... 
> >>
> >> So I guess the question is that needed... Is the setting of 
> >> the label in nfs_fhget() and/or _nfs4_do_open() good enough.
> > 
> > Until someone comes up with a different cache consistency model, then
> > I'd say yes. The only other case that comes to mind, is when our client
> > actively changes the label...
> On the server side as well, correct? What stops a process on the server side
> from changing the label? 

Nothing, but what is the expectation for how that will change client behaviour?

> I'm thinking that is reason the label was put in all those GETATTRs  

They are not part of a well thought-out caching model. Instead, these
are just random revalidations. If someone changes the label on the
server, then I can still do a million things on the client through
caching until I discover that the label has changed.

-- 
Trond Myklebust
Linux NFS client maintainer

NetApp
Trond.Myklebust@netapp.com
www.netapp.com

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 13/17] NFS: Client implementation of Labeled-NFS
  2013-05-08 18:31               ` Myklebust, Trond
@ 2013-05-08 18:41                     ` Steve Dickson
  0 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-05-08 18:41 UTC (permalink / raw)
  To: Myklebust, Trond
  Cc: J. Bruce Fields, David P. Quigley, Linux NFS list,
	Linux FS devel list, Linux Security List, SELinux List



On 08/05/13 14:31, Myklebust, Trond wrote:
> On Wed, 2013-05-08 at 14:27 -0400, Steve Dickson wrote:
>>
>> On 08/05/13 14:07, Myklebust, Trond wrote:
>>> On Wed, 2013-05-08 at 13:39 -0400, Steve Dickson wrote:
>>>>
>>>> On 08/05/13 12:43, Myklebust, Trond wrote:
>>>>> On Wed, 2013-05-08 at 12:39 -0400, Steve Dickson wrote:
>>>>>>
>>>>>> On 01/05/13 15:03, Myklebust, Trond wrote:
>>>>>>>> @@ -2409,10 +2468,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
>>>>>>>>>  			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;
>>>>>>>>> +#endif
>>>>>>>>> +		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;
>>>>>>>>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>>>>>>>>> +		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
>>>>>>> Why? How is the security label relevant to cache consistency?
>>>>>> Its used to the set label bit in the GETATTR that goes out with ACCESS compound.
>>>>>
>>>>> The GETATTR that goes out with ACCESS is only there in order to get the
>>>>> change attribute so that we know when to invalidate the access cache. It
>>>>> is _only_ for cache consistency.
>>>>>
>>>>> Why do we need to fetch the label too?
>>>>>
>>>> I think I answer this in the other thread but in short 
>>>> access updates the inode and so it appears the goal 
>>>> is to synchronize inode updates and label updates.
>>>
>>> Those are not inode updates.
>> Ah... OK... but they all end up calling nfs_refresh_inode() with 
>> the valid label pointer... So there is an effort to keep the 
>> inode attribute cache updates synchronized with label updates... 
>>
>> So I guess the question is that needed... Is the setting of 
>> the label in nfs_fhget() and/or _nfs4_do_open() good enough.
> 
> Until someone comes up with a different cache consistency model, then
> I'd say yes. The only other case that comes to mind, is when our client
> actively changes the label...
On the server side as well, correct? What stops a process on the server side
from changing the label? 

I'm thinking that is reason the label was put in all those GETATTRs  

steved.
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 13/17] NFS: Client implementation of Labeled-NFS
@ 2013-05-08 18:41                     ` Steve Dickson
  0 siblings, 0 replies; 71+ messages in thread
From: Steve Dickson @ 2013-05-08 18:41 UTC (permalink / raw)
  To: Myklebust, Trond
  Cc: J. Bruce Fields, David P. Quigley, Linux NFS list,
	Linux FS devel list, Linux Security List, SELinux List



On 08/05/13 14:31, Myklebust, Trond wrote:
> On Wed, 2013-05-08 at 14:27 -0400, Steve Dickson wrote:
>>
>> On 08/05/13 14:07, Myklebust, Trond wrote:
>>> On Wed, 2013-05-08 at 13:39 -0400, Steve Dickson wrote:
>>>>
>>>> On 08/05/13 12:43, Myklebust, Trond wrote:
>>>>> On Wed, 2013-05-08 at 12:39 -0400, Steve Dickson wrote:
>>>>>>
>>>>>> On 01/05/13 15:03, Myklebust, Trond wrote:
>>>>>>>> @@ -2409,10 +2468,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
>>>>>>>>>  			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;
>>>>>>>>> +#endif
>>>>>>>>> +		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;
>>>>>>>>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>>>>>>>>> +		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
>>>>>>> Why? How is the security label relevant to cache consistency?
>>>>>> Its used to the set label bit in the GETATTR that goes out with ACCESS compound.
>>>>>
>>>>> The GETATTR that goes out with ACCESS is only there in order to get the
>>>>> change attribute so that we know when to invalidate the access cache. It
>>>>> is _only_ for cache consistency.
>>>>>
>>>>> Why do we need to fetch the label too?
>>>>>
>>>> I think I answer this in the other thread but in short 
>>>> access updates the inode and so it appears the goal 
>>>> is to synchronize inode updates and label updates.
>>>
>>> Those are not inode updates.
>> Ah... OK... but they all end up calling nfs_refresh_inode() with 
>> the valid label pointer... So there is an effort to keep the 
>> inode attribute cache updates synchronized with label updates... 
>>
>> So I guess the question is that needed... Is the setting of 
>> the label in nfs_fhget() and/or _nfs4_do_open() good enough.
> 
> Until someone comes up with a different cache consistency model, then
> I'd say yes. The only other case that comes to mind, is when our client
> actively changes the label...
On the server side as well, correct? What stops a process on the server side
from changing the label? 

I'm thinking that is reason the label was put in all those GETATTRs  

steved.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 13/17] NFS: Client implementation of Labeled-NFS
  2013-05-08 18:27             ` Steve Dickson
@ 2013-05-08 18:31               ` Myklebust, Trond
       [not found]                 ` <1368037873.5978.34.camel-5lNtUQgoD8Pfa3cDbr2K10B+6BGkLq7r@public.gmane.org>
  0 siblings, 1 reply; 71+ messages in thread
From: Myklebust, Trond @ 2013-05-08 18:31 UTC (permalink / raw)
  To: Steve Dickson
  Cc: J. Bruce Fields, David P. Quigley, Linux NFS list,
	Linux FS devel list, Linux Security List, SELinux List

On Wed, 2013-05-08 at 14:27 -0400, Steve Dickson wrote:
> 
> On 08/05/13 14:07, Myklebust, Trond wrote:
> > On Wed, 2013-05-08 at 13:39 -0400, Steve Dickson wrote:
> >>
> >> On 08/05/13 12:43, Myklebust, Trond wrote:
> >>> On Wed, 2013-05-08 at 12:39 -0400, Steve Dickson wrote:
> >>>>
> >>>> On 01/05/13 15:03, Myklebust, Trond wrote:
> >>>>>> @@ -2409,10 +2468,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
> >>>>>>>  			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;
> >>>>>>> +#endif
> >>>>>>> +		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;
> >>>>>>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> >>>>>>> +		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
> >>>>> Why? How is the security label relevant to cache consistency?
> >>>> Its used to the set label bit in the GETATTR that goes out with ACCESS compound.
> >>>
> >>> The GETATTR that goes out with ACCESS is only there in order to get the
> >>> change attribute so that we know when to invalidate the access cache. It
> >>> is _only_ for cache consistency.
> >>>
> >>> Why do we need to fetch the label too?
> >>>
> >> I think I answer this in the other thread but in short 
> >> access updates the inode and so it appears the goal 
> >> is to synchronize inode updates and label updates.
> > 
> > Those are not inode updates.
> Ah... OK... but they all end up calling nfs_refresh_inode() with 
> the valid label pointer... So there is an effort to keep the 
> inode attribute cache updates synchronized with label updates... 
> 
> So I guess the question is that needed... Is the setting of 
> the label in nfs_fhget() and/or _nfs4_do_open() good enough.

Until someone comes up with a different cache consistency model, then
I'd say yes. The only other case that comes to mind, is when our client
actively changes the label...


-- 
Trond Myklebust
Linux NFS client maintainer

NetApp
Trond.Myklebust@netapp.com
www.netapp.com

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 13/17] NFS: Client implementation of Labeled-NFS
  2013-05-08 18:07           ` Myklebust, Trond
@ 2013-05-08 18:27             ` Steve Dickson
  2013-05-08 18:31               ` Myklebust, Trond
  0 siblings, 1 reply; 71+ messages in thread
From: Steve Dickson @ 2013-05-08 18:27 UTC (permalink / raw)
  To: Myklebust, Trond
  Cc: J. Bruce Fields, David P. Quigley, Linux NFS list,
	Linux FS devel list, Linux Security List, SELinux List



On 08/05/13 14:07, Myklebust, Trond wrote:
> On Wed, 2013-05-08 at 13:39 -0400, Steve Dickson wrote:
>>
>> On 08/05/13 12:43, Myklebust, Trond wrote:
>>> On Wed, 2013-05-08 at 12:39 -0400, Steve Dickson wrote:
>>>>
>>>> On 01/05/13 15:03, Myklebust, Trond wrote:
>>>>>> @@ -2409,10 +2468,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
>>>>>>>  			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;
>>>>>>> +#endif
>>>>>>> +		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;
>>>>>>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>>>>>>> +		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
>>>>> Why? How is the security label relevant to cache consistency?
>>>> Its used to the set label bit in the GETATTR that goes out with ACCESS compound.
>>>
>>> The GETATTR that goes out with ACCESS is only there in order to get the
>>> change attribute so that we know when to invalidate the access cache. It
>>> is _only_ for cache consistency.
>>>
>>> Why do we need to fetch the label too?
>>>
>> I think I answer this in the other thread but in short 
>> access updates the inode and so it appears the goal 
>> is to synchronize inode updates and label updates.
> 
> Those are not inode updates.
Ah... OK... but they all end up calling nfs_refresh_inode() with 
the valid label pointer... So there is an effort to keep the 
inode attribute cache updates synchronized with label updates... 

So I guess the question is that needed... Is the setting of 
the label in nfs_fhget() and/or _nfs4_do_open() good enough.

steved.




^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 13/17] NFS: Client implementation of Labeled-NFS
  2013-05-08 17:39         ` Steve Dickson
@ 2013-05-08 18:07           ` Myklebust, Trond
  2013-05-08 18:27             ` Steve Dickson
  0 siblings, 1 reply; 71+ messages in thread
From: Myklebust, Trond @ 2013-05-08 18:07 UTC (permalink / raw)
  To: Steve Dickson
  Cc: J. Bruce Fields, David P. Quigley, Linux NFS list,
	Linux FS devel list, Linux Security List, SELinux List

On Wed, 2013-05-08 at 13:39 -0400, Steve Dickson wrote:
> 
> On 08/05/13 12:43, Myklebust, Trond wrote:
> > On Wed, 2013-05-08 at 12:39 -0400, Steve Dickson wrote:
> >>
> >> On 01/05/13 15:03, Myklebust, Trond wrote:
> >>>> @@ -2409,10 +2468,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
> >>>>>  			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;
> >>>>> +#endif
> >>>>> +		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;
> >>>>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> >>>>> +		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
> >>> Why? How is the security label relevant to cache consistency?
> >> Its used to the set label bit in the GETATTR that goes out with ACCESS compound.
> > 
> > The GETATTR that goes out with ACCESS is only there in order to get the
> > change attribute so that we know when to invalidate the access cache. It
> > is _only_ for cache consistency.
> > 
> > Why do we need to fetch the label too?
> > 
> I think I answer this in the other thread but in short 
> access updates the inode and so it appears the goal 
> is to synchronize inode updates and label updates.

Those are not inode updates.


-- 
Trond Myklebust
Linux NFS client maintainer

NetApp
Trond.Myklebust@netapp.com
www.netapp.com

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 13/17] NFS: Client implementation of Labeled-NFS
  2013-05-08 16:43       ` Myklebust, Trond
@ 2013-05-08 17:39         ` Steve Dickson
  2013-05-08 18:07           ` Myklebust, Trond
  0 siblings, 1 reply; 71+ messages in thread
From: Steve Dickson @ 2013-05-08 17:39 UTC (permalink / raw)
  To: Myklebust, Trond
  Cc: J. Bruce Fields, David P. Quigley, Linux NFS list,
	Linux FS devel list, Linux Security List, SELinux List



On 08/05/13 12:43, Myklebust, Trond wrote:
> On Wed, 2013-05-08 at 12:39 -0400, Steve Dickson wrote:
>>
>> On 01/05/13 15:03, Myklebust, Trond wrote:
>>>> @@ -2409,10 +2468,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
>>>>>  			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;
>>>>> +#endif
>>>>> +		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;
>>>>> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>>>>> +		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
>>> Why? How is the security label relevant to cache consistency?
>> Its used to the set label bit in the GETATTR that goes out with ACCESS compound.
> 
> The GETATTR that goes out with ACCESS is only there in order to get the
> change attribute so that we know when to invalidate the access cache. It
> is _only_ for cache consistency.
> 
> Why do we need to fetch the label too?
> 
I think I answer this in the other thread but in short 
access updates the inode and so it appears the goal 
is to synchronize inode updates and label updates.

steved.
 

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 13/17] NFS: Client implementation of Labeled-NFS
  2013-05-08 16:39     ` Steve Dickson
@ 2013-05-08 16:43       ` Myklebust, Trond
  2013-05-08 17:39         ` Steve Dickson
  0 siblings, 1 reply; 71+ messages in thread
From: Myklebust, Trond @ 2013-05-08 16:43 UTC (permalink / raw)
  To: Steve Dickson
  Cc: J. Bruce Fields, David P. Quigley, Linux NFS list,
	Linux FS devel list, Linux Security List, SELinux List

On Wed, 2013-05-08 at 12:39 -0400, Steve Dickson wrote:
> 
> On 01/05/13 15:03, Myklebust, Trond wrote:
> >> @@ -2409,10 +2468,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
> >> >  			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;
> >> > +#endif
> >> > +		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;
> >> > +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> >> > +		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
> > Why? How is the security label relevant to cache consistency?
> Its used to the set label bit in the GETATTR that goes out with ACCESS compound.

The GETATTR that goes out with ACCESS is only there in order to get the
change attribute so that we know when to invalidate the access cache. It
is _only_ for cache consistency.

Why do we need to fetch the label too?

-- 
Trond Myklebust
Linux NFS client maintainer

NetApp
Trond.Myklebust@netapp.com
www.netapp.com

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 13/17] NFS: Client implementation of Labeled-NFS
  2013-05-01 19:03   ` Myklebust, Trond
@ 2013-05-08 16:39     ` Steve Dickson
  2013-05-08 16:43       ` Myklebust, Trond
  0 siblings, 1 reply; 71+ messages in thread
From: Steve Dickson @ 2013-05-08 16:39 UTC (permalink / raw)
  To: Myklebust, Trond
  Cc: J. Bruce Fields, David P. Quigley, Linux NFS list,
	Linux FS devel list, Linux Security List, SELinux List



On 01/05/13 15:03, Myklebust, Trond wrote:
>> @@ -2409,10 +2468,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
>> >  			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;
>> > +#endif
>> > +		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;
>> > +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
>> > +		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
> Why? How is the security label relevant to cache consistency?
Its used to the set label bit in the GETATTR that goes out with ACCESS compound.

steved.

   

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 13/17] NFS: Client implementation of Labeled-NFS
  2013-05-04 19:26   ` J. Bruce Fields
@ 2013-05-06  8:17       ` James Morris
  0 siblings, 0 replies; 71+ messages in thread
From: James Morris @ 2013-05-06  8:17 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: Steve Dickson, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List

On Sat, 4 May 2013, J. Bruce Fields wrote:

> James, thanks very much for taking a look at these.  I notice this is
> the one patch that touches security that you didn't respond to (note the
> 4 lines in hooks.c)--do you see any problem here, or does this look OK
> too?

Yep, looks fine.

Acked-by: James Morris <james.l.morris@oracle.com>



> 
> --b.
> 
> On Thu, May 02, 2013 at 01:19:07PM -0400, Steve Dickson wrote:
> > From: David Quigley <dpquigl@davequigley.com>
> > 
> > This patch implements the client transport and handling support for labeled
> > NFS. The patch adds two functions to encode and decode the security label
> > recommended attribute which makes use of the LSM hooks added earlier. It also
> > adds code to grab the label from the file attribute structures and encode the
> > label to be sent back to the server.
> > 
> > Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> > Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
> > Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
> > Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
> > ---
> >  fs/nfs/inode.c            |  57 ++++++++-
> >  fs/nfs/nfs4proc.c         | 318 +++++++++++++++++++++++++++++++++++++++++++---
> >  fs/nfs/nfs4xdr.c          | 168 ++++++++++++++++++------
> >  fs/nfs/pnfs.c             |   2 +-
> >  fs/nfs/super.c            |  17 ++-
> >  include/linux/nfs_fs.h    |  13 ++
> >  include/linux/nfs_fs_sb.h |   7 +
> >  security/selinux/hooks.c  |   4 +
> >  8 files changed, 524 insertions(+), 62 deletions(-)
> > 
> > diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> > index 4e92dfb..cc1c85d 100644
> > --- a/fs/nfs/inode.c
> > +++ b/fs/nfs/inode.c
> > @@ -162,11 +162,19 @@ static void nfs_zap_caches_locked(struct inode *inode)
> >  
> >  	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)
> > @@ -258,6 +266,24 @@ nfs_init_locked(struct inode *inode, void *opaque)
> >  }
> >  
> >  #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;
> > @@ -283,7 +309,13 @@ struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags)
> >  	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
> > @@ -412,6 +444,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
> >  			 */
> >  			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;
> > @@ -771,6 +806,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_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)
> >  {
> > @@ -899,7 +935,8 @@ static int nfs_attribute_cache_expired(struct inode *inode)
> >   */
> >  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);
> > @@ -1240,6 +1277,9 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_
> >  	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);
> > @@ -1279,6 +1319,10 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr, struc
> >  	spin_lock(&inode->i_lock);
> >  	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);
> > @@ -1519,7 +1563,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
> >  		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;
> > @@ -1532,6 +1576,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
> >  		}
> >  	}
> >  	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 --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> > index 56f24c0..0e5b319 100644
> > --- a/fs/nfs/nfs4proc.c
> > +++ b/fs/nfs/nfs4proc.c
> > @@ -87,6 +87,52 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
> >  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;
> > +	int minor_version = NFS_SERVER(dir)->nfs_client->cl_minorversion;
> > +
> > +	if (minor_version < 2)
> > +		return NULL;
> > +
> > +	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);
> > +}
> > +static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
> > +{
> > +	if (label)
> > +		return server->attr_bitmask;
> > +
> > +	return server->attr_bitmask_nl;
> > +}
> > +#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; }
> > +static inline u32 *
> > +nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
> > +{ return server->attr_bitmask; }
> > +#endif
> > +
> >  /* Prevent leaks of NFSv4 errors into userland */
> >  static int nfs4_map_errors(int err)
> >  {
> > @@ -133,7 +179,10 @@ const u32 nfs4_fattr_bitmap[3] = {
> >  	| FATTR4_WORD1_SPACE_USED
> >  	| FATTR4_WORD1_TIME_ACCESS
> >  	| FATTR4_WORD1_TIME_METADATA
> > -	| FATTR4_WORD1_TIME_MODIFY
> > +	| FATTR4_WORD1_TIME_MODIFY,
> > +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> > +	FATTR4_WORD2_SECURITY_LABEL
> > +#endif
> >  };
> >  
> >  static const u32 nfs4_pnfs_open_bitmap[3] = {
> > @@ -817,7 +866,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
> >  	p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
> >  	p->o_arg.name = &dentry->d_name;
> >  	p->o_arg.server = server;
> > -	p->o_arg.bitmask = server->attr_bitmask;
> > +	p->o_arg.bitmask = nfs4_bitmask(server, label);
> >  	p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
> >  	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
> >  	p->o_arg.label = label;
> > @@ -1973,6 +2022,7 @@ static int _nfs4_do_open(struct inode *dir,
> >  		if (status == 0) {
> >  			nfs_setattr_update_inode(state->inode, sattr);
> >  			nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr, olabel);
> > +			nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
> >  		}
> >  	}
> >  
> > @@ -2086,6 +2136,10 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
> >  	unsigned long timestamp = jiffies;
> >  	int status;
> >  
> > +	arg.bitmask = nfs4_bitmask(server, ilabel);
> > +	if (ilabel)
> > +		arg.bitmask = nfs4_bitmask(server, olabel);
> > +
> >  	nfs_fattr_init(fattr);
> >  
> >  	if (state != NULL) {
> > @@ -2315,7 +2369,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
> >  	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;
> > @@ -2345,11 +2399,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 *label = NULL;
> > +	struct nfs4_label l = {0, 0, 0, NULL}, *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, label,
> >  			     ctx->cred, &ctx->mdsthreshold);
> > +
> > +	nfs4_label_release_security(label);
> > +
> >  	if (IS_ERR(state))
> >  		return ERR_CAST(state);
> >  	ctx->state = state;
> > @@ -2409,10 +2468,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
> >  			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;
> > +#endif
> > +		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;
> > +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> > +		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
> > +#endif
> > +		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;
> >  	}
> > @@ -2435,8 +2510,9 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
> >  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,
> > @@ -2449,6 +2525,13 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
> >  		.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);
> >  }
> > @@ -2635,7 +2718,9 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
> >  		.rpc_argp = &args,
> >  		.rpc_resp = &res,
> >  	};
> > -	
> > +
> > +	args.bitmask = nfs4_bitmask(server, label);
> > +
> >  	nfs_fattr_init(fattr);
> >  	return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
> >  }
> > @@ -2730,6 +2815,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
> >  	struct nfs4_lookup_res res = {
> >  		.server = server,
> >  		.fattr = fattr,
> > +		.label = label,
> >  		.fh = fhandle,
> >  	};
> >  	struct rpc_message msg = {
> > @@ -2738,6 +2824,8 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
> >  		.rpc_resp = &res,
> >  	};
> >  
> > +	args.bitmask = nfs4_bitmask(server, label);
> > +
> >  	nfs_fattr_init(fattr);
> >  
> >  	dprintk("NFS call  lookup %s\n", name->name);
> > @@ -2844,7 +2932,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
> >  		.rpc_cred = entry->cred,
> >  	};
> >  	int mode = entry->mask;
> > -	int status;
> > +	int status = 0;
> >  
> >  	/*
> >  	 * Determine which access bits we want to ask for...
> > @@ -2873,6 +2961,8 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
> >  		goto out;
> >  	}
> >  
> > +	args.bitmask = nfs4_cache_bitmask(server, res.label);
> > +
> >  	status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
> >  	if (!status) {
> >  		nfs_access_set_mask(entry, res.access);
> > @@ -2959,7 +3049,7 @@ static int
> >  nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
> >  		 int flags)
> >  {
> > -	struct nfs4_label *ilabel = NULL;
> > +	struct nfs4_label l, *ilabel = NULL;
> >  	struct nfs_open_context *ctx;
> >  	struct nfs4_state *state;
> >  	int status = 0;
> > @@ -2968,6 +3058,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
> >  	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, ilabel, ctx->cred,
> > @@ -2981,6 +3073,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
> >  	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;
> >  }
> > @@ -3029,6 +3122,8 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
> >  	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)
> > @@ -3179,6 +3274,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
> >  		status = PTR_ERR(res.label);
> >  		goto out;
> >  	}
> > +	arg.bitmask = nfs4_bitmask(server, res.label);
> >  
> >  	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
> >  	if (!status) {
> > @@ -3236,7 +3332,7 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
> >  		data->arg.name = name;
> >  		data->arg.attrs = sattr;
> >  		data->arg.ftype = ftype;
> > -		data->arg.bitmask = server->attr_bitmask;
> > +		data->arg.bitmask = nfs4_bitmask(server, data->label);
> >  		data->res.server = server;
> >  		data->res.fh = &data->fh;
> >  		data->res.fattr = &data->fattr;
> > @@ -3297,14 +3393,19 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
> >  		struct page *page, unsigned int len, struct iattr *sattr)
> >  {
> >  	struct nfs4_exception exception = { };
> > -	struct nfs4_label *label = NULL;
> > +	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, label),
> >  				&exception);
> >  	} while (exception.retry);
> > +
> > +	nfs4_label_release_security(label);
> >  	return err;
> >  }
> >  
> > @@ -3330,15 +3431,19 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
> >  		struct iattr *sattr)
> >  {
> >  	struct nfs4_exception exception = { };
> > -	struct nfs4_label *label = NULL;
> > +	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, label),
> >  				&exception);
> >  	} while (exception.retry);
> > +	nfs4_label_release_security(label);
> > +
> >  	return err;
> >  }
> >  
> > @@ -3354,7 +3459,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
> >  		.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,
> > @@ -3434,15 +3541,20 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
> >  		struct iattr *sattr, dev_t rdev)
> >  {
> >  	struct nfs4_exception exception = { };
> > -	struct nfs4_label *label = NULL;
> > +	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, label, rdev),
> >  				&exception);
> >  	} while (exception.retry);
> > +
> > +	nfs4_label_release_security(label);
> > +
> >  	return err;
> >  }
> >  
> > @@ -3658,7 +3770,8 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
> >  		data->args.bitmask = NULL;
> >  		data->res.fattr = NULL;
> >  	} else
> > -		data->args.bitmask = server->cache_consistency_bitmask;
> > +
> > +	data->args.bitmask = nfs4_cache_bitmask(server, NULL);
> >  
> >  	if (!data->write_done_cb)
> >  		data->write_done_cb = nfs4_write_done_cb;
> > @@ -4083,6 +4196,179 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
> >  	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)
> >  {
> > @@ -4371,7 +4657,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
> >  	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;
> > diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
> > index 4fa0bf1..2726f21 100644
> > --- a/fs/nfs/nfs4xdr.c
> > +++ b/fs/nfs/nfs4xdr.c
> > @@ -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 xdr_stream *xdr, const nfs4_verifier *ve
> >  	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];
> > @@ -1022,6 +1038,8 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
> >  		}
> >  		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)
> > @@ -1078,6 +1096,13 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
> >  		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.
> > @@ -1144,7 +1169,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
> >  	}
> >  
> >  	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)
> > @@ -1377,21 +1402,23 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
> >  	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);
> > @@ -1547,7 +1574,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
> >  
> >  static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
> >  {
> > -	uint32_t attrs[2] = {
> > +	uint32_t attrs[3] = {
> >  		FATTR4_WORD0_RDATTR_ERROR,
> >  		FATTR4_WORD1_MOUNTED_ON_FILEID,
> >  	};
> > @@ -1570,20 +1597,26 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
> >  	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) {
> > +		if (hdr->minorversion > 1)
> > +			attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
> > +		p++, *p++ = cpu_to_be32(attrs[2] & readdir->bitmask[2]);
> > +	}
> >  	memcpy(verf, readdir->verifier.data, sizeof(verf));
> > -	dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
> > +
> > +	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]);
> > +			attrs[1] & readdir->bitmask[1],
> > +			attrs[2] & readdir->bitmask[2]);
> >  }
> >  
> >  static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
> > @@ -1642,7 +1675,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs
> >  {
> >  	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)
> > @@ -4060,6 +4093,60 @@ static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap,
> >  	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;
> > @@ -4402,7 +4489,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;
> > @@ -4510,6 +4597,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
> >  	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;
> > @@ -4517,7 +4609,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,
> > @@ -4536,7 +4628,8 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
> >  	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;
> >  
> > @@ -4547,9 +4640,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);
> >  }
> >  
> >  /*
> > @@ -5883,7 +5976,7 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp,
> >  	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;
> >  }
> > @@ -5909,7 +6002,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> >  	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;
> >  }
> > @@ -5938,7 +6031,7 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> >  	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;
> >  }
> > @@ -5964,7 +6057,8 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp,
> >  		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;
> >  }
> > @@ -6055,7 +6149,7 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> >  	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;
> >  }
> > @@ -6084,7 +6178,7 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> >  	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;
> >  }
> > @@ -6116,7 +6210,7 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> >  	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;
> >  }
> > @@ -6218,7 +6312,7 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> >  	 * 	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;
> >  }
> > @@ -6249,7 +6343,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> >  		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;
> >  }
> > @@ -6299,7 +6393,7 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp,
> >  		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;
> >  }
> > @@ -6326,7 +6420,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp,
> >  	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;
> >  }
> > @@ -6506,7 +6600,7 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> >  	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:
> > @@ -6687,7 +6781,7 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
> >  	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);
> > @@ -6720,7 +6814,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
> >  	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;
> >  }
> > @@ -7001,7 +7095,7 @@ static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp,
> >  	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;
> >  }
> > @@ -7133,7 +7227,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
> >  		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 --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
> > index 4bdffe0..0ead05b 100644
> > --- a/fs/nfs/pnfs.c
> > +++ b/fs/nfs/pnfs.c
> > @@ -1922,7 +1922,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
> >  	data->args.inode = inode;
> >  	data->cred = get_rpccred(nfsi->layout->plh_lc_cred);
> >  	nfs_fattr_init(&data->fattr);
> > -	data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
> > +	data->args.bitmask = nfs4_cache_bitmask(NFS_SERVER(inode), NULL);
> >  	data->res.fattr = &data->fattr;
> >  	data->args.lastbytewritten = end_pos - 1;
> >  	data->res.server = NFS_SERVER(inode);
> > diff --git a/fs/nfs/super.c b/fs/nfs/super.c
> > index 00af026..68c42be 100644
> > --- a/fs/nfs/super.c
> > +++ b/fs/nfs/super.c
> > @@ -2379,8 +2379,21 @@ static int nfs_bdi_register(struct nfs_server *server)
> >  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,
> > -								0, NULL);
> > +	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 --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
> > index 1ef8eb4..1510f4f 100644
> > --- a/include/linux/nfs_fs.h
> > +++ b/include/linux/nfs_fs.h
> > @@ -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
> > @@ -344,6 +345,8 @@ extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
> >  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);
> > @@ -502,9 +505,19 @@ static inline void nfs4_label_free(struct nfs4_label *label)
> >  	}
> >  	return;
> >  }
> > +static inline u32 *nfs4_cache_bitmask(struct nfs_server *server, struct nfs4_label *label)
> > +{
> > +	if (label)
> > +		return server->cache_consistency_bitmask;
> > +
> > +	return server->cache_consistency_bitmask_nl;
> > +}
> >  #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) {}
> > +static inline u32 *
> > +nfs4_cache_bitmask(struct nfs_server *server, struct nfs4_label *label)
> > +{ return server->cache_consistency_bitmask; }
> >  #endif
> >  
> >  /*
> > diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
> > index e6ed3c2..2a4f1d4 100644
> > --- a/include/linux/nfs_fs_sb.h
> > +++ b/include/linux/nfs_fs_sb.h
> > @@ -145,11 +145,18 @@ struct nfs_server {
> >  	u32			attr_bitmask[3];/* V4 bitmask representing the set
> >  						   of attributes supported on this
> >  						   filesystem */
> > +	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 */
> > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > index d7ff806..f68b577 100644
> > --- a/security/selinux/hooks.c
> > +++ b/security/selinux/hooks.c
> > @@ -2877,7 +2877,10 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
> >  		return;
> >  	}
> >  
> > +	isec->sclass = inode_mode_to_security_class(inode->i_mode);
> >  	isec->sid = newsid;
> > +	isec->initialized = 1;
> > +
> >  	return;
> >  }
> >  
> > @@ -2965,6 +2968,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
> >  	if (rc)
> >  		return rc;
> >  
> > +	isec->sclass = inode_mode_to_security_class(inode->i_mode);
> >  	isec->sid = newsid;
> >  	isec->initialized = 1;
> >  	return 0;
> > -- 
> > 1.8.1.4
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 13/17] NFS: Client implementation of Labeled-NFS
@ 2013-05-06  8:17       ` James Morris
  0 siblings, 0 replies; 71+ messages in thread
From: James Morris @ 2013-05-06  8:17 UTC (permalink / raw)
  To: J. Bruce Fields
  Cc: Steve Dickson, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List

On Sat, 4 May 2013, J. Bruce Fields wrote:

> James, thanks very much for taking a look at these.  I notice this is
> the one patch that touches security that you didn't respond to (note the
> 4 lines in hooks.c)--do you see any problem here, or does this look OK
> too?

Yep, looks fine.

Acked-by: James Morris <james.l.morris@oracle.com>



> 
> --b.
> 
> On Thu, May 02, 2013 at 01:19:07PM -0400, Steve Dickson wrote:
> > From: David Quigley <dpquigl@davequigley.com>
> > 
> > This patch implements the client transport and handling support for labeled
> > NFS. The patch adds two functions to encode and decode the security label
> > recommended attribute which makes use of the LSM hooks added earlier. It also
> > adds code to grab the label from the file attribute structures and encode the
> > label to be sent back to the server.
> > 
> > Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> > Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
> > Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
> > Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
> > ---
> >  fs/nfs/inode.c            |  57 ++++++++-
> >  fs/nfs/nfs4proc.c         | 318 +++++++++++++++++++++++++++++++++++++++++++---
> >  fs/nfs/nfs4xdr.c          | 168 ++++++++++++++++++------
> >  fs/nfs/pnfs.c             |   2 +-
> >  fs/nfs/super.c            |  17 ++-
> >  include/linux/nfs_fs.h    |  13 ++
> >  include/linux/nfs_fs_sb.h |   7 +
> >  security/selinux/hooks.c  |   4 +
> >  8 files changed, 524 insertions(+), 62 deletions(-)
> > 
> > diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> > index 4e92dfb..cc1c85d 100644
> > --- a/fs/nfs/inode.c
> > +++ b/fs/nfs/inode.c
> > @@ -162,11 +162,19 @@ static void nfs_zap_caches_locked(struct inode *inode)
> >  
> >  	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)
> > @@ -258,6 +266,24 @@ nfs_init_locked(struct inode *inode, void *opaque)
> >  }
> >  
> >  #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;
> > @@ -283,7 +309,13 @@ struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags)
> >  	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
> > @@ -412,6 +444,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
> >  			 */
> >  			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;
> > @@ -771,6 +806,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_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)
> >  {
> > @@ -899,7 +935,8 @@ static int nfs_attribute_cache_expired(struct inode *inode)
> >   */
> >  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);
> > @@ -1240,6 +1277,9 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_
> >  	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);
> > @@ -1279,6 +1319,10 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr, struc
> >  	spin_lock(&inode->i_lock);
> >  	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);
> > @@ -1519,7 +1563,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
> >  		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;
> > @@ -1532,6 +1576,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
> >  		}
> >  	}
> >  	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 --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> > index 56f24c0..0e5b319 100644
> > --- a/fs/nfs/nfs4proc.c
> > +++ b/fs/nfs/nfs4proc.c
> > @@ -87,6 +87,52 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
> >  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;
> > +	int minor_version = NFS_SERVER(dir)->nfs_client->cl_minorversion;
> > +
> > +	if (minor_version < 2)
> > +		return NULL;
> > +
> > +	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);
> > +}
> > +static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
> > +{
> > +	if (label)
> > +		return server->attr_bitmask;
> > +
> > +	return server->attr_bitmask_nl;
> > +}
> > +#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; }
> > +static inline u32 *
> > +nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
> > +{ return server->attr_bitmask; }
> > +#endif
> > +
> >  /* Prevent leaks of NFSv4 errors into userland */
> >  static int nfs4_map_errors(int err)
> >  {
> > @@ -133,7 +179,10 @@ const u32 nfs4_fattr_bitmap[3] = {
> >  	| FATTR4_WORD1_SPACE_USED
> >  	| FATTR4_WORD1_TIME_ACCESS
> >  	| FATTR4_WORD1_TIME_METADATA
> > -	| FATTR4_WORD1_TIME_MODIFY
> > +	| FATTR4_WORD1_TIME_MODIFY,
> > +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> > +	FATTR4_WORD2_SECURITY_LABEL
> > +#endif
> >  };
> >  
> >  static const u32 nfs4_pnfs_open_bitmap[3] = {
> > @@ -817,7 +866,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
> >  	p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
> >  	p->o_arg.name = &dentry->d_name;
> >  	p->o_arg.server = server;
> > -	p->o_arg.bitmask = server->attr_bitmask;
> > +	p->o_arg.bitmask = nfs4_bitmask(server, label);
> >  	p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
> >  	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
> >  	p->o_arg.label = label;
> > @@ -1973,6 +2022,7 @@ static int _nfs4_do_open(struct inode *dir,
> >  		if (status == 0) {
> >  			nfs_setattr_update_inode(state->inode, sattr);
> >  			nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr, olabel);
> > +			nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
> >  		}
> >  	}
> >  
> > @@ -2086,6 +2136,10 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
> >  	unsigned long timestamp = jiffies;
> >  	int status;
> >  
> > +	arg.bitmask = nfs4_bitmask(server, ilabel);
> > +	if (ilabel)
> > +		arg.bitmask = nfs4_bitmask(server, olabel);
> > +
> >  	nfs_fattr_init(fattr);
> >  
> >  	if (state != NULL) {
> > @@ -2315,7 +2369,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
> >  	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;
> > @@ -2345,11 +2399,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 *label = NULL;
> > +	struct nfs4_label l = {0, 0, 0, NULL}, *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, label,
> >  			     ctx->cred, &ctx->mdsthreshold);
> > +
> > +	nfs4_label_release_security(label);
> > +
> >  	if (IS_ERR(state))
> >  		return ERR_CAST(state);
> >  	ctx->state = state;
> > @@ -2409,10 +2468,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
> >  			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;
> > +#endif
> > +		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;
> > +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> > +		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
> > +#endif
> > +		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;
> >  	}
> > @@ -2435,8 +2510,9 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
> >  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,
> > @@ -2449,6 +2525,13 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
> >  		.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);
> >  }
> > @@ -2635,7 +2718,9 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
> >  		.rpc_argp = &args,
> >  		.rpc_resp = &res,
> >  	};
> > -	
> > +
> > +	args.bitmask = nfs4_bitmask(server, label);
> > +
> >  	nfs_fattr_init(fattr);
> >  	return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
> >  }
> > @@ -2730,6 +2815,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
> >  	struct nfs4_lookup_res res = {
> >  		.server = server,
> >  		.fattr = fattr,
> > +		.label = label,
> >  		.fh = fhandle,
> >  	};
> >  	struct rpc_message msg = {
> > @@ -2738,6 +2824,8 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
> >  		.rpc_resp = &res,
> >  	};
> >  
> > +	args.bitmask = nfs4_bitmask(server, label);
> > +
> >  	nfs_fattr_init(fattr);
> >  
> >  	dprintk("NFS call  lookup %s\n", name->name);
> > @@ -2844,7 +2932,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
> >  		.rpc_cred = entry->cred,
> >  	};
> >  	int mode = entry->mask;
> > -	int status;
> > +	int status = 0;
> >  
> >  	/*
> >  	 * Determine which access bits we want to ask for...
> > @@ -2873,6 +2961,8 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
> >  		goto out;
> >  	}
> >  
> > +	args.bitmask = nfs4_cache_bitmask(server, res.label);
> > +
> >  	status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
> >  	if (!status) {
> >  		nfs_access_set_mask(entry, res.access);
> > @@ -2959,7 +3049,7 @@ static int
> >  nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
> >  		 int flags)
> >  {
> > -	struct nfs4_label *ilabel = NULL;
> > +	struct nfs4_label l, *ilabel = NULL;
> >  	struct nfs_open_context *ctx;
> >  	struct nfs4_state *state;
> >  	int status = 0;
> > @@ -2968,6 +3058,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
> >  	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, ilabel, ctx->cred,
> > @@ -2981,6 +3073,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
> >  	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;
> >  }
> > @@ -3029,6 +3122,8 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
> >  	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)
> > @@ -3179,6 +3274,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
> >  		status = PTR_ERR(res.label);
> >  		goto out;
> >  	}
> > +	arg.bitmask = nfs4_bitmask(server, res.label);
> >  
> >  	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
> >  	if (!status) {
> > @@ -3236,7 +3332,7 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
> >  		data->arg.name = name;
> >  		data->arg.attrs = sattr;
> >  		data->arg.ftype = ftype;
> > -		data->arg.bitmask = server->attr_bitmask;
> > +		data->arg.bitmask = nfs4_bitmask(server, data->label);
> >  		data->res.server = server;
> >  		data->res.fh = &data->fh;
> >  		data->res.fattr = &data->fattr;
> > @@ -3297,14 +3393,19 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
> >  		struct page *page, unsigned int len, struct iattr *sattr)
> >  {
> >  	struct nfs4_exception exception = { };
> > -	struct nfs4_label *label = NULL;
> > +	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, label),
> >  				&exception);
> >  	} while (exception.retry);
> > +
> > +	nfs4_label_release_security(label);
> >  	return err;
> >  }
> >  
> > @@ -3330,15 +3431,19 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
> >  		struct iattr *sattr)
> >  {
> >  	struct nfs4_exception exception = { };
> > -	struct nfs4_label *label = NULL;
> > +	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, label),
> >  				&exception);
> >  	} while (exception.retry);
> > +	nfs4_label_release_security(label);
> > +
> >  	return err;
> >  }
> >  
> > @@ -3354,7 +3459,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
> >  		.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,
> > @@ -3434,15 +3541,20 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
> >  		struct iattr *sattr, dev_t rdev)
> >  {
> >  	struct nfs4_exception exception = { };
> > -	struct nfs4_label *label = NULL;
> > +	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, label, rdev),
> >  				&exception);
> >  	} while (exception.retry);
> > +
> > +	nfs4_label_release_security(label);
> > +
> >  	return err;
> >  }
> >  
> > @@ -3658,7 +3770,8 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
> >  		data->args.bitmask = NULL;
> >  		data->res.fattr = NULL;
> >  	} else
> > -		data->args.bitmask = server->cache_consistency_bitmask;
> > +
> > +	data->args.bitmask = nfs4_cache_bitmask(server, NULL);
> >  
> >  	if (!data->write_done_cb)
> >  		data->write_done_cb = nfs4_write_done_cb;
> > @@ -4083,6 +4196,179 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
> >  	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)
> >  {
> > @@ -4371,7 +4657,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
> >  	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;
> > diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
> > index 4fa0bf1..2726f21 100644
> > --- a/fs/nfs/nfs4xdr.c
> > +++ b/fs/nfs/nfs4xdr.c
> > @@ -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 xdr_stream *xdr, const nfs4_verifier *ve
> >  	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];
> > @@ -1022,6 +1038,8 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
> >  		}
> >  		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)
> > @@ -1078,6 +1096,13 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
> >  		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.
> > @@ -1144,7 +1169,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
> >  	}
> >  
> >  	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)
> > @@ -1377,21 +1402,23 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
> >  	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);
> > @@ -1547,7 +1574,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
> >  
> >  static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
> >  {
> > -	uint32_t attrs[2] = {
> > +	uint32_t attrs[3] = {
> >  		FATTR4_WORD0_RDATTR_ERROR,
> >  		FATTR4_WORD1_MOUNTED_ON_FILEID,
> >  	};
> > @@ -1570,20 +1597,26 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
> >  	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) {
> > +		if (hdr->minorversion > 1)
> > +			attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
> > +		p++, *p++ = cpu_to_be32(attrs[2] & readdir->bitmask[2]);
> > +	}
> >  	memcpy(verf, readdir->verifier.data, sizeof(verf));
> > -	dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
> > +
> > +	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]);
> > +			attrs[1] & readdir->bitmask[1],
> > +			attrs[2] & readdir->bitmask[2]);
> >  }
> >  
> >  static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
> > @@ -1642,7 +1675,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs
> >  {
> >  	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)
> > @@ -4060,6 +4093,60 @@ static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap,
> >  	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;
> > @@ -4402,7 +4489,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;
> > @@ -4510,6 +4597,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
> >  	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;
> > @@ -4517,7 +4609,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,
> > @@ -4536,7 +4628,8 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
> >  	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;
> >  
> > @@ -4547,9 +4640,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);
> >  }
> >  
> >  /*
> > @@ -5883,7 +5976,7 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp,
> >  	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;
> >  }
> > @@ -5909,7 +6002,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> >  	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;
> >  }
> > @@ -5938,7 +6031,7 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> >  	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;
> >  }
> > @@ -5964,7 +6057,8 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp,
> >  		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;
> >  }
> > @@ -6055,7 +6149,7 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> >  	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;
> >  }
> > @@ -6084,7 +6178,7 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> >  	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;
> >  }
> > @@ -6116,7 +6210,7 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> >  	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;
> >  }
> > @@ -6218,7 +6312,7 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> >  	 * 	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;
> >  }
> > @@ -6249,7 +6343,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> >  		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;
> >  }
> > @@ -6299,7 +6393,7 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp,
> >  		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;
> >  }
> > @@ -6326,7 +6420,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp,
> >  	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;
> >  }
> > @@ -6506,7 +6600,7 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
> >  	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:
> > @@ -6687,7 +6781,7 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
> >  	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);
> > @@ -6720,7 +6814,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
> >  	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;
> >  }
> > @@ -7001,7 +7095,7 @@ static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp,
> >  	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;
> >  }
> > @@ -7133,7 +7227,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
> >  		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 --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
> > index 4bdffe0..0ead05b 100644
> > --- a/fs/nfs/pnfs.c
> > +++ b/fs/nfs/pnfs.c
> > @@ -1922,7 +1922,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
> >  	data->args.inode = inode;
> >  	data->cred = get_rpccred(nfsi->layout->plh_lc_cred);
> >  	nfs_fattr_init(&data->fattr);
> > -	data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
> > +	data->args.bitmask = nfs4_cache_bitmask(NFS_SERVER(inode), NULL);
> >  	data->res.fattr = &data->fattr;
> >  	data->args.lastbytewritten = end_pos - 1;
> >  	data->res.server = NFS_SERVER(inode);
> > diff --git a/fs/nfs/super.c b/fs/nfs/super.c
> > index 00af026..68c42be 100644
> > --- a/fs/nfs/super.c
> > +++ b/fs/nfs/super.c
> > @@ -2379,8 +2379,21 @@ static int nfs_bdi_register(struct nfs_server *server)
> >  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,
> > -								0, NULL);
> > +	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 --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
> > index 1ef8eb4..1510f4f 100644
> > --- a/include/linux/nfs_fs.h
> > +++ b/include/linux/nfs_fs.h
> > @@ -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
> > @@ -344,6 +345,8 @@ extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
> >  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);
> > @@ -502,9 +505,19 @@ static inline void nfs4_label_free(struct nfs4_label *label)
> >  	}
> >  	return;
> >  }
> > +static inline u32 *nfs4_cache_bitmask(struct nfs_server *server, struct nfs4_label *label)
> > +{
> > +	if (label)
> > +		return server->cache_consistency_bitmask;
> > +
> > +	return server->cache_consistency_bitmask_nl;
> > +}
> >  #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) {}
> > +static inline u32 *
> > +nfs4_cache_bitmask(struct nfs_server *server, struct nfs4_label *label)
> > +{ return server->cache_consistency_bitmask; }
> >  #endif
> >  
> >  /*
> > diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
> > index e6ed3c2..2a4f1d4 100644
> > --- a/include/linux/nfs_fs_sb.h
> > +++ b/include/linux/nfs_fs_sb.h
> > @@ -145,11 +145,18 @@ struct nfs_server {
> >  	u32			attr_bitmask[3];/* V4 bitmask representing the set
> >  						   of attributes supported on this
> >  						   filesystem */
> > +	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 */
> > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > index d7ff806..f68b577 100644
> > --- a/security/selinux/hooks.c
> > +++ b/security/selinux/hooks.c
> > @@ -2877,7 +2877,10 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
> >  		return;
> >  	}
> >  
> > +	isec->sclass = inode_mode_to_security_class(inode->i_mode);
> >  	isec->sid = newsid;
> > +	isec->initialized = 1;
> > +
> >  	return;
> >  }
> >  
> > @@ -2965,6 +2968,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
> >  	if (rc)
> >  		return rc;
> >  
> > +	isec->sclass = inode_mode_to_security_class(inode->i_mode);
> >  	isec->sid = newsid;
> >  	isec->initialized = 1;
> >  	return 0;
> > -- 
> > 1.8.1.4
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

-- 
James Morris
<jmorris@namei.org>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 13/17] NFS: Client implementation of Labeled-NFS
  2013-05-02 17:19 ` [PATCH 13/17] NFS: Client implementation of Labeled-NFS Steve Dickson
@ 2013-05-04 19:26   ` J. Bruce Fields
  2013-05-06  8:17       ` James Morris
  0 siblings, 1 reply; 71+ messages in thread
From: J. Bruce Fields @ 2013-05-04 19:26 UTC (permalink / raw)
  To: James Morris
  Cc: Steve Dickson, Trond Myklebust, J. Bruce Fields,
	David P. Quigley, Linux NFS list, Linux FS devel list,
	Linux Security List, SELinux List

James, thanks very much for taking a look at these.  I notice this is
the one patch that touches security that you didn't respond to (note the
4 lines in hooks.c)--do you see any problem here, or does this look OK
too?

--b.

On Thu, May 02, 2013 at 01:19:07PM -0400, Steve Dickson wrote:
> From: David Quigley <dpquigl@davequigley.com>
> 
> This patch implements the client transport and handling support for labeled
> NFS. The patch adds two functions to encode and decode the security label
> recommended attribute which makes use of the LSM hooks added earlier. It also
> adds code to grab the label from the file attribute structures and encode the
> label to be sent back to the server.
> 
> Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
> Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
> Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
> ---
>  fs/nfs/inode.c            |  57 ++++++++-
>  fs/nfs/nfs4proc.c         | 318 +++++++++++++++++++++++++++++++++++++++++++---
>  fs/nfs/nfs4xdr.c          | 168 ++++++++++++++++++------
>  fs/nfs/pnfs.c             |   2 +-
>  fs/nfs/super.c            |  17 ++-
>  include/linux/nfs_fs.h    |  13 ++
>  include/linux/nfs_fs_sb.h |   7 +
>  security/selinux/hooks.c  |   4 +
>  8 files changed, 524 insertions(+), 62 deletions(-)
> 
> diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> index 4e92dfb..cc1c85d 100644
> --- a/fs/nfs/inode.c
> +++ b/fs/nfs/inode.c
> @@ -162,11 +162,19 @@ static void nfs_zap_caches_locked(struct inode *inode)
>  
>  	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)
> @@ -258,6 +266,24 @@ nfs_init_locked(struct inode *inode, void *opaque)
>  }
>  
>  #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;
> @@ -283,7 +309,13 @@ struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags)
>  	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
> @@ -412,6 +444,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
>  			 */
>  			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;
> @@ -771,6 +806,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_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)
>  {
> @@ -899,7 +935,8 @@ static int nfs_attribute_cache_expired(struct inode *inode)
>   */
>  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);
> @@ -1240,6 +1277,9 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_
>  	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);
> @@ -1279,6 +1319,10 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr, struc
>  	spin_lock(&inode->i_lock);
>  	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);
> @@ -1519,7 +1563,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
>  		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;
> @@ -1532,6 +1576,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
>  		}
>  	}
>  	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 --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> index 56f24c0..0e5b319 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -87,6 +87,52 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
>  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;
> +	int minor_version = NFS_SERVER(dir)->nfs_client->cl_minorversion;
> +
> +	if (minor_version < 2)
> +		return NULL;
> +
> +	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);
> +}
> +static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
> +{
> +	if (label)
> +		return server->attr_bitmask;
> +
> +	return server->attr_bitmask_nl;
> +}
> +#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; }
> +static inline u32 *
> +nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
> +{ return server->attr_bitmask; }
> +#endif
> +
>  /* Prevent leaks of NFSv4 errors into userland */
>  static int nfs4_map_errors(int err)
>  {
> @@ -133,7 +179,10 @@ const u32 nfs4_fattr_bitmap[3] = {
>  	| FATTR4_WORD1_SPACE_USED
>  	| FATTR4_WORD1_TIME_ACCESS
>  	| FATTR4_WORD1_TIME_METADATA
> -	| FATTR4_WORD1_TIME_MODIFY
> +	| FATTR4_WORD1_TIME_MODIFY,
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> +	FATTR4_WORD2_SECURITY_LABEL
> +#endif
>  };
>  
>  static const u32 nfs4_pnfs_open_bitmap[3] = {
> @@ -817,7 +866,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
>  	p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
>  	p->o_arg.name = &dentry->d_name;
>  	p->o_arg.server = server;
> -	p->o_arg.bitmask = server->attr_bitmask;
> +	p->o_arg.bitmask = nfs4_bitmask(server, label);
>  	p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
>  	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
>  	p->o_arg.label = label;
> @@ -1973,6 +2022,7 @@ static int _nfs4_do_open(struct inode *dir,
>  		if (status == 0) {
>  			nfs_setattr_update_inode(state->inode, sattr);
>  			nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr, olabel);
> +			nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
>  		}
>  	}
>  
> @@ -2086,6 +2136,10 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
>  	unsigned long timestamp = jiffies;
>  	int status;
>  
> +	arg.bitmask = nfs4_bitmask(server, ilabel);
> +	if (ilabel)
> +		arg.bitmask = nfs4_bitmask(server, olabel);
> +
>  	nfs_fattr_init(fattr);
>  
>  	if (state != NULL) {
> @@ -2315,7 +2369,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
>  	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;
> @@ -2345,11 +2399,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 *label = NULL;
> +	struct nfs4_label l = {0, 0, 0, NULL}, *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, label,
>  			     ctx->cred, &ctx->mdsthreshold);
> +
> +	nfs4_label_release_security(label);
> +
>  	if (IS_ERR(state))
>  		return ERR_CAST(state);
>  	ctx->state = state;
> @@ -2409,10 +2468,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
>  			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;
> +#endif
> +		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;
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> +		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
> +#endif
> +		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;
>  	}
> @@ -2435,8 +2510,9 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
>  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,
> @@ -2449,6 +2525,13 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
>  		.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);
>  }
> @@ -2635,7 +2718,9 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
>  		.rpc_argp = &args,
>  		.rpc_resp = &res,
>  	};
> -	
> +
> +	args.bitmask = nfs4_bitmask(server, label);
> +
>  	nfs_fattr_init(fattr);
>  	return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
>  }
> @@ -2730,6 +2815,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
>  	struct nfs4_lookup_res res = {
>  		.server = server,
>  		.fattr = fattr,
> +		.label = label,
>  		.fh = fhandle,
>  	};
>  	struct rpc_message msg = {
> @@ -2738,6 +2824,8 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
>  		.rpc_resp = &res,
>  	};
>  
> +	args.bitmask = nfs4_bitmask(server, label);
> +
>  	nfs_fattr_init(fattr);
>  
>  	dprintk("NFS call  lookup %s\n", name->name);
> @@ -2844,7 +2932,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
>  		.rpc_cred = entry->cred,
>  	};
>  	int mode = entry->mask;
> -	int status;
> +	int status = 0;
>  
>  	/*
>  	 * Determine which access bits we want to ask for...
> @@ -2873,6 +2961,8 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
>  		goto out;
>  	}
>  
> +	args.bitmask = nfs4_cache_bitmask(server, res.label);
> +
>  	status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
>  	if (!status) {
>  		nfs_access_set_mask(entry, res.access);
> @@ -2959,7 +3049,7 @@ static int
>  nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
>  		 int flags)
>  {
> -	struct nfs4_label *ilabel = NULL;
> +	struct nfs4_label l, *ilabel = NULL;
>  	struct nfs_open_context *ctx;
>  	struct nfs4_state *state;
>  	int status = 0;
> @@ -2968,6 +3058,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
>  	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, ilabel, ctx->cred,
> @@ -2981,6 +3073,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
>  	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;
>  }
> @@ -3029,6 +3122,8 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
>  	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)
> @@ -3179,6 +3274,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
>  		status = PTR_ERR(res.label);
>  		goto out;
>  	}
> +	arg.bitmask = nfs4_bitmask(server, res.label);
>  
>  	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
>  	if (!status) {
> @@ -3236,7 +3332,7 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
>  		data->arg.name = name;
>  		data->arg.attrs = sattr;
>  		data->arg.ftype = ftype;
> -		data->arg.bitmask = server->attr_bitmask;
> +		data->arg.bitmask = nfs4_bitmask(server, data->label);
>  		data->res.server = server;
>  		data->res.fh = &data->fh;
>  		data->res.fattr = &data->fattr;
> @@ -3297,14 +3393,19 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
>  		struct page *page, unsigned int len, struct iattr *sattr)
>  {
>  	struct nfs4_exception exception = { };
> -	struct nfs4_label *label = NULL;
> +	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, label),
>  				&exception);
>  	} while (exception.retry);
> +
> +	nfs4_label_release_security(label);
>  	return err;
>  }
>  
> @@ -3330,15 +3431,19 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
>  		struct iattr *sattr)
>  {
>  	struct nfs4_exception exception = { };
> -	struct nfs4_label *label = NULL;
> +	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, label),
>  				&exception);
>  	} while (exception.retry);
> +	nfs4_label_release_security(label);
> +
>  	return err;
>  }
>  
> @@ -3354,7 +3459,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
>  		.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,
> @@ -3434,15 +3541,20 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
>  		struct iattr *sattr, dev_t rdev)
>  {
>  	struct nfs4_exception exception = { };
> -	struct nfs4_label *label = NULL;
> +	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, label, rdev),
>  				&exception);
>  	} while (exception.retry);
> +
> +	nfs4_label_release_security(label);
> +
>  	return err;
>  }
>  
> @@ -3658,7 +3770,8 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
>  		data->args.bitmask = NULL;
>  		data->res.fattr = NULL;
>  	} else
> -		data->args.bitmask = server->cache_consistency_bitmask;
> +
> +	data->args.bitmask = nfs4_cache_bitmask(server, NULL);
>  
>  	if (!data->write_done_cb)
>  		data->write_done_cb = nfs4_write_done_cb;
> @@ -4083,6 +4196,179 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
>  	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)
>  {
> @@ -4371,7 +4657,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
>  	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;
> diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
> index 4fa0bf1..2726f21 100644
> --- a/fs/nfs/nfs4xdr.c
> +++ b/fs/nfs/nfs4xdr.c
> @@ -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 xdr_stream *xdr, const nfs4_verifier *ve
>  	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];
> @@ -1022,6 +1038,8 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
>  		}
>  		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)
> @@ -1078,6 +1096,13 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
>  		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.
> @@ -1144,7 +1169,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
>  	}
>  
>  	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)
> @@ -1377,21 +1402,23 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
>  	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);
> @@ -1547,7 +1574,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
>  
>  static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
>  {
> -	uint32_t attrs[2] = {
> +	uint32_t attrs[3] = {
>  		FATTR4_WORD0_RDATTR_ERROR,
>  		FATTR4_WORD1_MOUNTED_ON_FILEID,
>  	};
> @@ -1570,20 +1597,26 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
>  	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) {
> +		if (hdr->minorversion > 1)
> +			attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
> +		p++, *p++ = cpu_to_be32(attrs[2] & readdir->bitmask[2]);
> +	}
>  	memcpy(verf, readdir->verifier.data, sizeof(verf));
> -	dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
> +
> +	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]);
> +			attrs[1] & readdir->bitmask[1],
> +			attrs[2] & readdir->bitmask[2]);
>  }
>  
>  static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
> @@ -1642,7 +1675,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs
>  {
>  	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)
> @@ -4060,6 +4093,60 @@ static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap,
>  	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;
> @@ -4402,7 +4489,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;
> @@ -4510,6 +4597,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
>  	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;
> @@ -4517,7 +4609,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,
> @@ -4536,7 +4628,8 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
>  	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;
>  
> @@ -4547,9 +4640,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);
>  }
>  
>  /*
> @@ -5883,7 +5976,7 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp,
>  	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;
>  }
> @@ -5909,7 +6002,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
>  	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;
>  }
> @@ -5938,7 +6031,7 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
>  	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;
>  }
> @@ -5964,7 +6057,8 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp,
>  		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;
>  }
> @@ -6055,7 +6149,7 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
>  	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;
>  }
> @@ -6084,7 +6178,7 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
>  	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;
>  }
> @@ -6116,7 +6210,7 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
>  	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;
>  }
> @@ -6218,7 +6312,7 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
>  	 * 	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;
>  }
> @@ -6249,7 +6343,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
>  		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;
>  }
> @@ -6299,7 +6393,7 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp,
>  		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;
>  }
> @@ -6326,7 +6420,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp,
>  	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;
>  }
> @@ -6506,7 +6600,7 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
>  	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:
> @@ -6687,7 +6781,7 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
>  	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);
> @@ -6720,7 +6814,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
>  	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;
>  }
> @@ -7001,7 +7095,7 @@ static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp,
>  	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;
>  }
> @@ -7133,7 +7227,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
>  		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 --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
> index 4bdffe0..0ead05b 100644
> --- a/fs/nfs/pnfs.c
> +++ b/fs/nfs/pnfs.c
> @@ -1922,7 +1922,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
>  	data->args.inode = inode;
>  	data->cred = get_rpccred(nfsi->layout->plh_lc_cred);
>  	nfs_fattr_init(&data->fattr);
> -	data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
> +	data->args.bitmask = nfs4_cache_bitmask(NFS_SERVER(inode), NULL);
>  	data->res.fattr = &data->fattr;
>  	data->args.lastbytewritten = end_pos - 1;
>  	data->res.server = NFS_SERVER(inode);
> diff --git a/fs/nfs/super.c b/fs/nfs/super.c
> index 00af026..68c42be 100644
> --- a/fs/nfs/super.c
> +++ b/fs/nfs/super.c
> @@ -2379,8 +2379,21 @@ static int nfs_bdi_register(struct nfs_server *server)
>  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,
> -								0, NULL);
> +	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 --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
> index 1ef8eb4..1510f4f 100644
> --- a/include/linux/nfs_fs.h
> +++ b/include/linux/nfs_fs.h
> @@ -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
> @@ -344,6 +345,8 @@ extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
>  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);
> @@ -502,9 +505,19 @@ static inline void nfs4_label_free(struct nfs4_label *label)
>  	}
>  	return;
>  }
> +static inline u32 *nfs4_cache_bitmask(struct nfs_server *server, struct nfs4_label *label)
> +{
> +	if (label)
> +		return server->cache_consistency_bitmask;
> +
> +	return server->cache_consistency_bitmask_nl;
> +}
>  #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) {}
> +static inline u32 *
> +nfs4_cache_bitmask(struct nfs_server *server, struct nfs4_label *label)
> +{ return server->cache_consistency_bitmask; }
>  #endif
>  
>  /*
> diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
> index e6ed3c2..2a4f1d4 100644
> --- a/include/linux/nfs_fs_sb.h
> +++ b/include/linux/nfs_fs_sb.h
> @@ -145,11 +145,18 @@ struct nfs_server {
>  	u32			attr_bitmask[3];/* V4 bitmask representing the set
>  						   of attributes supported on this
>  						   filesystem */
> +	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 */
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index d7ff806..f68b577 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -2877,7 +2877,10 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
>  		return;
>  	}
>  
> +	isec->sclass = inode_mode_to_security_class(inode->i_mode);
>  	isec->sid = newsid;
> +	isec->initialized = 1;
> +
>  	return;
>  }
>  
> @@ -2965,6 +2968,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
>  	if (rc)
>  		return rc;
>  
> +	isec->sclass = inode_mode_to_security_class(inode->i_mode);
>  	isec->sid = newsid;
>  	isec->initialized = 1;
>  	return 0;
> -- 
> 1.8.1.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [PATCH 13/17] NFS: Client implementation of Labeled-NFS
  2013-05-02 17:18 [PATCH 00/17] lnfs: linux-3.9 release Steve Dickson
@ 2013-05-02 17:19 ` Steve Dickson
  2013-05-04 19:26   ` J. Bruce Fields
  0 siblings, 1 reply; 71+ messages in thread
From: Steve Dickson @ 2013-05-02 17:19 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl@davequigley.com>

This patch implements the client transport and handling support for labeled
NFS. The patch adds two functions to encode and decode the security label
recommended attribute which makes use of the LSM hooks added earlier. It also
adds code to grab the label from the file attribute structures and encode the
label to be sent back to the server.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
---
 fs/nfs/inode.c            |  57 ++++++++-
 fs/nfs/nfs4proc.c         | 318 +++++++++++++++++++++++++++++++++++++++++++---
 fs/nfs/nfs4xdr.c          | 168 ++++++++++++++++++------
 fs/nfs/pnfs.c             |   2 +-
 fs/nfs/super.c            |  17 ++-
 include/linux/nfs_fs.h    |  13 ++
 include/linux/nfs_fs_sb.h |   7 +
 security/selinux/hooks.c  |   4 +
 8 files changed, 524 insertions(+), 62 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 4e92dfb..cc1c85d 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -162,11 +162,19 @@ static void nfs_zap_caches_locked(struct inode *inode)
 
 	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)
@@ -258,6 +266,24 @@ nfs_init_locked(struct inode *inode, void *opaque)
 }
 
 #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;
@@ -283,7 +309,13 @@ struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags)
 	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
@@ -412,6 +444,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
 			 */
 			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;
@@ -771,6 +806,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_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)
 {
@@ -899,7 +935,8 @@ static int nfs_attribute_cache_expired(struct inode *inode)
  */
 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);
@@ -1240,6 +1277,9 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_
 	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);
@@ -1279,6 +1319,10 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr, struc
 	spin_lock(&inode->i_lock);
 	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);
@@ -1519,7 +1563,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
 		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;
@@ -1532,6 +1576,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
 		}
 	}
 	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 --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 56f24c0..0e5b319 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -87,6 +87,52 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 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;
+	int minor_version = NFS_SERVER(dir)->nfs_client->cl_minorversion;
+
+	if (minor_version < 2)
+		return NULL;
+
+	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);
+}
+static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
+{
+	if (label)
+		return server->attr_bitmask;
+
+	return server->attr_bitmask_nl;
+}
+#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; }
+static inline u32 *
+nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
+{ return server->attr_bitmask; }
+#endif
+
 /* Prevent leaks of NFSv4 errors into userland */
 static int nfs4_map_errors(int err)
 {
@@ -133,7 +179,10 @@ const u32 nfs4_fattr_bitmap[3] = {
 	| FATTR4_WORD1_SPACE_USED
 	| FATTR4_WORD1_TIME_ACCESS
 	| FATTR4_WORD1_TIME_METADATA
-	| FATTR4_WORD1_TIME_MODIFY
+	| FATTR4_WORD1_TIME_MODIFY,
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	FATTR4_WORD2_SECURITY_LABEL
+#endif
 };
 
 static const u32 nfs4_pnfs_open_bitmap[3] = {
@@ -817,7 +866,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
 	p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
 	p->o_arg.name = &dentry->d_name;
 	p->o_arg.server = server;
-	p->o_arg.bitmask = server->attr_bitmask;
+	p->o_arg.bitmask = nfs4_bitmask(server, label);
 	p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
 	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
 	p->o_arg.label = label;
@@ -1973,6 +2022,7 @@ static int _nfs4_do_open(struct inode *dir,
 		if (status == 0) {
 			nfs_setattr_update_inode(state->inode, sattr);
 			nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr, olabel);
+			nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
 		}
 	}
 
@@ -2086,6 +2136,10 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 	unsigned long timestamp = jiffies;
 	int status;
 
+	arg.bitmask = nfs4_bitmask(server, ilabel);
+	if (ilabel)
+		arg.bitmask = nfs4_bitmask(server, olabel);
+
 	nfs_fattr_init(fattr);
 
 	if (state != NULL) {
@@ -2315,7 +2369,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
 	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;
@@ -2345,11 +2399,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 *label = NULL;
+	struct nfs4_label l = {0, 0, 0, NULL}, *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, label,
 			     ctx->cred, &ctx->mdsthreshold);
+
+	nfs4_label_release_security(label);
+
 	if (IS_ERR(state))
 		return ERR_CAST(state);
 	ctx->state = state;
@@ -2409,10 +2468,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
 			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;
+#endif
+		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;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
+#endif
+		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;
 	}
@@ -2435,8 +2510,9 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
 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,
@@ -2449,6 +2525,13 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
 		.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);
 }
@@ -2635,7 +2718,9 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
 		.rpc_argp = &args,
 		.rpc_resp = &res,
 	};
-	
+
+	args.bitmask = nfs4_bitmask(server, label);
+
 	nfs_fattr_init(fattr);
 	return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
 }
@@ -2730,6 +2815,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
 	struct nfs4_lookup_res res = {
 		.server = server,
 		.fattr = fattr,
+		.label = label,
 		.fh = fhandle,
 	};
 	struct rpc_message msg = {
@@ -2738,6 +2824,8 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
 		.rpc_resp = &res,
 	};
 
+	args.bitmask = nfs4_bitmask(server, label);
+
 	nfs_fattr_init(fattr);
 
 	dprintk("NFS call  lookup %s\n", name->name);
@@ -2844,7 +2932,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 		.rpc_cred = entry->cred,
 	};
 	int mode = entry->mask;
-	int status;
+	int status = 0;
 
 	/*
 	 * Determine which access bits we want to ask for...
@@ -2873,6 +2961,8 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 		goto out;
 	}
 
+	args.bitmask = nfs4_cache_bitmask(server, res.label);
+
 	status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
 	if (!status) {
 		nfs_access_set_mask(entry, res.access);
@@ -2959,7 +3049,7 @@ static int
 nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 		 int flags)
 {
-	struct nfs4_label *ilabel = NULL;
+	struct nfs4_label l, *ilabel = NULL;
 	struct nfs_open_context *ctx;
 	struct nfs4_state *state;
 	int status = 0;
@@ -2968,6 +3058,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 	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, ilabel, ctx->cred,
@@ -2981,6 +3073,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 	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;
 }
@@ -3029,6 +3122,8 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 	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)
@@ -3179,6 +3274,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
 		status = PTR_ERR(res.label);
 		goto out;
 	}
+	arg.bitmask = nfs4_bitmask(server, res.label);
 
 	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
 	if (!status) {
@@ -3236,7 +3332,7 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
 		data->arg.name = name;
 		data->arg.attrs = sattr;
 		data->arg.ftype = ftype;
-		data->arg.bitmask = server->attr_bitmask;
+		data->arg.bitmask = nfs4_bitmask(server, data->label);
 		data->res.server = server;
 		data->res.fh = &data->fh;
 		data->res.fattr = &data->fattr;
@@ -3297,14 +3393,19 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
 		struct page *page, unsigned int len, struct iattr *sattr)
 {
 	struct nfs4_exception exception = { };
-	struct nfs4_label *label = NULL;
+	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, label),
 				&exception);
 	} while (exception.retry);
+
+	nfs4_label_release_security(label);
 	return err;
 }
 
@@ -3330,15 +3431,19 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr)
 {
 	struct nfs4_exception exception = { };
-	struct nfs4_label *label = NULL;
+	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, label),
 				&exception);
 	} while (exception.retry);
+	nfs4_label_release_security(label);
+
 	return err;
 }
 
@@ -3354,7 +3459,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
 		.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,
@@ -3434,15 +3541,20 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr, dev_t rdev)
 {
 	struct nfs4_exception exception = { };
-	struct nfs4_label *label = NULL;
+	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, label, rdev),
 				&exception);
 	} while (exception.retry);
+
+	nfs4_label_release_security(label);
+
 	return err;
 }
 
@@ -3658,7 +3770,8 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
 		data->args.bitmask = NULL;
 		data->res.fattr = NULL;
 	} else
-		data->args.bitmask = server->cache_consistency_bitmask;
+
+	data->args.bitmask = nfs4_cache_bitmask(server, NULL);
 
 	if (!data->write_done_cb)
 		data->write_done_cb = nfs4_write_done_cb;
@@ -4083,6 +4196,179 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
 	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)
 {
@@ -4371,7 +4657,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
 	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;
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 4fa0bf1..2726f21 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -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 xdr_stream *xdr, const nfs4_verifier *ve
 	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];
@@ -1022,6 +1038,8 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
 		}
 		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)
@@ -1078,6 +1096,13 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
 		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.
@@ -1144,7 +1169,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
 	}
 
 	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)
@@ -1377,21 +1402,23 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
 	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);
@@ -1547,7 +1574,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
 
 static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
 {
-	uint32_t attrs[2] = {
+	uint32_t attrs[3] = {
 		FATTR4_WORD0_RDATTR_ERROR,
 		FATTR4_WORD1_MOUNTED_ON_FILEID,
 	};
@@ -1570,20 +1597,26 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
 	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) {
+		if (hdr->minorversion > 1)
+			attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
+		p++, *p++ = cpu_to_be32(attrs[2] & readdir->bitmask[2]);
+	}
 	memcpy(verf, readdir->verifier.data, sizeof(verf));
-	dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
+
+	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]);
+			attrs[1] & readdir->bitmask[1],
+			attrs[2] & readdir->bitmask[2]);
 }
 
 static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
@@ -1642,7 +1675,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs
 {
 	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)
@@ -4060,6 +4093,60 @@ static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap,
 	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;
@@ -4402,7 +4489,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;
@@ -4510,6 +4597,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
 	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;
@@ -4517,7 +4609,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,
@@ -4536,7 +4628,8 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
 	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;
 
@@ -4547,9 +4640,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);
 }
 
 /*
@@ -5883,7 +5976,7 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp,
 	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;
 }
@@ -5909,7 +6002,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -5938,7 +6031,7 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -5964,7 +6057,8 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp,
 		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;
 }
@@ -6055,7 +6149,7 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -6084,7 +6178,7 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -6116,7 +6210,7 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -6218,7 +6312,7 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	 * 	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;
 }
@@ -6249,7 +6343,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 		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;
 }
@@ -6299,7 +6393,7 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp,
 		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;
 }
@@ -6326,7 +6420,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp,
 	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;
 }
@@ -6506,7 +6600,7 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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:
@@ -6687,7 +6781,7 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
 	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);
@@ -6720,7 +6814,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
 	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;
 }
@@ -7001,7 +7095,7 @@ static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp,
 	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;
 }
@@ -7133,7 +7227,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
 		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 --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 4bdffe0..0ead05b 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1922,7 +1922,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
 	data->args.inode = inode;
 	data->cred = get_rpccred(nfsi->layout->plh_lc_cred);
 	nfs_fattr_init(&data->fattr);
-	data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
+	data->args.bitmask = nfs4_cache_bitmask(NFS_SERVER(inode), NULL);
 	data->res.fattr = &data->fattr;
 	data->args.lastbytewritten = end_pos - 1;
 	data->res.server = NFS_SERVER(inode);
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 00af026..68c42be 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2379,8 +2379,21 @@ static int nfs_bdi_register(struct nfs_server *server)
 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,
-								0, NULL);
+	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 --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 1ef8eb4..1510f4f 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -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
@@ -344,6 +345,8 @@ extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
 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);
@@ -502,9 +505,19 @@ static inline void nfs4_label_free(struct nfs4_label *label)
 	}
 	return;
 }
+static inline u32 *nfs4_cache_bitmask(struct nfs_server *server, struct nfs4_label *label)
+{
+	if (label)
+		return server->cache_consistency_bitmask;
+
+	return server->cache_consistency_bitmask_nl;
+}
 #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) {}
+static inline u32 *
+nfs4_cache_bitmask(struct nfs_server *server, struct nfs4_label *label)
+{ return server->cache_consistency_bitmask; }
 #endif
 
 /*
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index e6ed3c2..2a4f1d4 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -145,11 +145,18 @@ struct nfs_server {
 	u32			attr_bitmask[3];/* V4 bitmask representing the set
 						   of attributes supported on this
 						   filesystem */
+	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 */
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d7ff806..f68b577 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2877,7 +2877,10 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
 		return;
 	}
 
+	isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	isec->sid = newsid;
+	isec->initialized = 1;
+
 	return;
 }
 
@@ -2965,6 +2968,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
 	if (rc)
 		return rc;
 
+	isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	isec->sid = newsid;
 	isec->initialized = 1;
 	return 0;
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

* Re: [PATCH 13/17] NFS: Client implementation of Labeled-NFS
  2013-04-29 12:57 ` [PATCH 13/17] NFS: Client implementation of Labeled-NFS Steve Dickson
@ 2013-05-01 19:03   ` Myklebust, Trond
  2013-05-08 16:39     ` Steve Dickson
  0 siblings, 1 reply; 71+ messages in thread
From: Myklebust, Trond @ 2013-05-01 19:03 UTC (permalink / raw)
  To: Steve Dickson
  Cc: J. Bruce Fields, David P. Quigley, Linux NFS list,
	Linux FS devel list, Linux Security List, SELinux List

On Mon, 2013-04-29 at 08:57 -0400, Steve Dickson wrote:
> From: David Quigley <dpquigl@davequigley.com>
> 
> This patch implements the client transport and handling support for labeled
> NFS. The patch adds two functions to encode and decode the security label
> recommended attribute which makes use of the LSM hooks added earlier. It also
> adds code to grab the label from the file attribute structures and encode the
> label to be sent back to the server.
> 
> Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
> Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
> Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
> ---
>  fs/nfs/inode.c            |  57 ++++++++-
>  fs/nfs/nfs4proc.c         | 318 +++++++++++++++++++++++++++++++++++++++++++---
>  fs/nfs/nfs4xdr.c          | 168 ++++++++++++++++++------
>  fs/nfs/pnfs.c             |   2 +-
>  fs/nfs/super.c            |  17 ++-
>  include/linux/nfs_fs.h    |  13 ++
>  include/linux/nfs_fs_sb.h |   7 +
>  security/selinux/hooks.c  |   4 +
>  8 files changed, 524 insertions(+), 62 deletions(-)
> 
> diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> index 4e92dfb..cc1c85d 100644
> --- a/fs/nfs/inode.c
> +++ b/fs/nfs/inode.c
> @@ -162,11 +162,19 @@ static void nfs_zap_caches_locked(struct inode *inode)
>  
>  	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)
> @@ -258,6 +266,24 @@ nfs_init_locked(struct inode *inode, void *opaque)
>  }
>  
>  #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;
> @@ -283,7 +309,13 @@ struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags)
>  	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
> @@ -412,6 +444,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
>  			 */
>  			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;
> @@ -771,6 +806,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_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)
>  {
> @@ -899,7 +935,8 @@ static int nfs_attribute_cache_expired(struct inode *inode)
>   */
>  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);
> @@ -1240,6 +1277,9 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_
>  	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);
> @@ -1279,6 +1319,10 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr, struc
>  	spin_lock(&inode->i_lock);
>  	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);
> @@ -1519,7 +1563,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
>  		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;
> @@ -1532,6 +1576,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
>  		}
>  	}
>  	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 --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> index 56f24c0..0e5b319 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -87,6 +87,52 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
>  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;
> +	int minor_version = NFS_SERVER(dir)->nfs_client->cl_minorversion;
> +
> +	if (minor_version < 2)
> +		return NULL;
> +
> +	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);
> +}
> +static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
> +{
> +	if (label)
> +		return server->attr_bitmask;
> +
> +	return server->attr_bitmask_nl;
> +}
> +#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; }
> +static inline u32 *
> +nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
> +{ return server->attr_bitmask; }
> +#endif
> +
>  /* Prevent leaks of NFSv4 errors into userland */
>  static int nfs4_map_errors(int err)
>  {
> @@ -133,7 +179,10 @@ const u32 nfs4_fattr_bitmap[3] = {
>  	| FATTR4_WORD1_SPACE_USED
>  	| FATTR4_WORD1_TIME_ACCESS
>  	| FATTR4_WORD1_TIME_METADATA
> -	| FATTR4_WORD1_TIME_MODIFY
> +	| FATTR4_WORD1_TIME_MODIFY,
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> +	FATTR4_WORD2_SECURITY_LABEL
> +#endif
>  };
>  
>  static const u32 nfs4_pnfs_open_bitmap[3] = {
> @@ -817,7 +866,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
>  	p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
>  	p->o_arg.name = &dentry->d_name;
>  	p->o_arg.server = server;
> -	p->o_arg.bitmask = server->attr_bitmask;
> +	p->o_arg.bitmask = nfs4_bitmask(server, label);
>  	p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
>  	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
>  	p->o_arg.label = label;
> @@ -1973,6 +2022,7 @@ static int _nfs4_do_open(struct inode *dir,
>  		if (status == 0) {
>  			nfs_setattr_update_inode(state->inode, sattr);
>  			nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr, olabel);
> +			nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
>  		}
>  	}
>  
> @@ -2086,6 +2136,10 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
>  	unsigned long timestamp = jiffies;
>  	int status;
>  
> +	arg.bitmask = nfs4_bitmask(server, ilabel);
> +	if (ilabel)
> +		arg.bitmask = nfs4_bitmask(server, olabel);
> +
>  	nfs_fattr_init(fattr);
>  
>  	if (state != NULL) {
> @@ -2315,7 +2369,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
>  	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;
> @@ -2345,11 +2399,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 *label = NULL;
> +	struct nfs4_label l = {0, 0, 0, NULL}, *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, label,
>  			     ctx->cred, &ctx->mdsthreshold);
> +
> +	nfs4_label_release_security(label);
> +
>  	if (IS_ERR(state))
>  		return ERR_CAST(state);
>  	ctx->state = state;
> @@ -2409,10 +2468,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
>  			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;
> +#endif
> +		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;
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> +		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;

Why? How is the security label relevant to cache consistency?

-- 
Trond Myklebust
Linux NFS client maintainer

NetApp
Trond.Myklebust@netapp.com
www.netapp.com

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [PATCH 13/17] NFS: Client implementation of Labeled-NFS
  2013-04-29 12:57 [PATCH 00/17] lnfs: 3.9-rc8 release (take 2) Steve Dickson
@ 2013-04-29 12:57 ` Steve Dickson
  2013-05-01 19:03   ` Myklebust, Trond
  0 siblings, 1 reply; 71+ messages in thread
From: Steve Dickson @ 2013-04-29 12:57 UTC (permalink / raw)
  To: Trond Myklebust, J. Bruce Fields, David P. Quigley
  Cc: Linux NFS list, Linux FS devel list, Linux Security List, SELinux List

From: David Quigley <dpquigl@davequigley.com>

This patch implements the client transport and handling support for labeled
NFS. The patch adds two functions to encode and decode the security label
recommended attribute which makes use of the LSM hooks added earlier. It also
adds code to grab the label from the file attribute structures and encode the
label to be sent back to the server.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
---
 fs/nfs/inode.c            |  57 ++++++++-
 fs/nfs/nfs4proc.c         | 318 +++++++++++++++++++++++++++++++++++++++++++---
 fs/nfs/nfs4xdr.c          | 168 ++++++++++++++++++------
 fs/nfs/pnfs.c             |   2 +-
 fs/nfs/super.c            |  17 ++-
 include/linux/nfs_fs.h    |  13 ++
 include/linux/nfs_fs_sb.h |   7 +
 security/selinux/hooks.c  |   4 +
 8 files changed, 524 insertions(+), 62 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 4e92dfb..cc1c85d 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -162,11 +162,19 @@ static void nfs_zap_caches_locked(struct inode *inode)
 
 	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)
@@ -258,6 +266,24 @@ nfs_init_locked(struct inode *inode, void *opaque)
 }
 
 #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;
@@ -283,7 +309,13 @@ struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags)
 	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
@@ -412,6 +444,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
 			 */
 			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;
@@ -771,6 +806,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_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)
 {
@@ -899,7 +935,8 @@ static int nfs_attribute_cache_expired(struct inode *inode)
  */
 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);
@@ -1240,6 +1277,9 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_
 	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);
@@ -1279,6 +1319,10 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr, struc
 	spin_lock(&inode->i_lock);
 	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);
@@ -1519,7 +1563,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
 		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;
@@ -1532,6 +1576,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct
 		}
 	}
 	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 --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 56f24c0..0e5b319 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -87,6 +87,52 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 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;
+	int minor_version = NFS_SERVER(dir)->nfs_client->cl_minorversion;
+
+	if (minor_version < 2)
+		return NULL;
+
+	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);
+}
+static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
+{
+	if (label)
+		return server->attr_bitmask;
+
+	return server->attr_bitmask_nl;
+}
+#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; }
+static inline u32 *
+nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
+{ return server->attr_bitmask; }
+#endif
+
 /* Prevent leaks of NFSv4 errors into userland */
 static int nfs4_map_errors(int err)
 {
@@ -133,7 +179,10 @@ const u32 nfs4_fattr_bitmap[3] = {
 	| FATTR4_WORD1_SPACE_USED
 	| FATTR4_WORD1_TIME_ACCESS
 	| FATTR4_WORD1_TIME_METADATA
-	| FATTR4_WORD1_TIME_MODIFY
+	| FATTR4_WORD1_TIME_MODIFY,
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	FATTR4_WORD2_SECURITY_LABEL
+#endif
 };
 
 static const u32 nfs4_pnfs_open_bitmap[3] = {
@@ -817,7 +866,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
 	p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
 	p->o_arg.name = &dentry->d_name;
 	p->o_arg.server = server;
-	p->o_arg.bitmask = server->attr_bitmask;
+	p->o_arg.bitmask = nfs4_bitmask(server, label);
 	p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
 	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
 	p->o_arg.label = label;
@@ -1973,6 +2022,7 @@ static int _nfs4_do_open(struct inode *dir,
 		if (status == 0) {
 			nfs_setattr_update_inode(state->inode, sattr);
 			nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr, olabel);
+			nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
 		}
 	}
 
@@ -2086,6 +2136,10 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 	unsigned long timestamp = jiffies;
 	int status;
 
+	arg.bitmask = nfs4_bitmask(server, ilabel);
+	if (ilabel)
+		arg.bitmask = nfs4_bitmask(server, olabel);
+
 	nfs_fattr_init(fattr);
 
 	if (state != NULL) {
@@ -2315,7 +2369,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
 	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;
@@ -2345,11 +2399,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 *label = NULL;
+	struct nfs4_label l = {0, 0, 0, NULL}, *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, label,
 			     ctx->cred, &ctx->mdsthreshold);
+
+	nfs4_label_release_security(label);
+
 	if (IS_ERR(state))
 		return ERR_CAST(state);
 	ctx->state = state;
@@ -2409,10 +2468,26 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
 			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;
+#endif
+		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;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL;
+#endif
+		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;
 	}
@@ -2435,8 +2510,9 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
 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,
@@ -2449,6 +2525,13 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
 		.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);
 }
@@ -2635,7 +2718,9 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
 		.rpc_argp = &args,
 		.rpc_resp = &res,
 	};
-	
+
+	args.bitmask = nfs4_bitmask(server, label);
+
 	nfs_fattr_init(fattr);
 	return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
 }
@@ -2730,6 +2815,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
 	struct nfs4_lookup_res res = {
 		.server = server,
 		.fattr = fattr,
+		.label = label,
 		.fh = fhandle,
 	};
 	struct rpc_message msg = {
@@ -2738,6 +2824,8 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
 		.rpc_resp = &res,
 	};
 
+	args.bitmask = nfs4_bitmask(server, label);
+
 	nfs_fattr_init(fattr);
 
 	dprintk("NFS call  lookup %s\n", name->name);
@@ -2844,7 +2932,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 		.rpc_cred = entry->cred,
 	};
 	int mode = entry->mask;
-	int status;
+	int status = 0;
 
 	/*
 	 * Determine which access bits we want to ask for...
@@ -2873,6 +2961,8 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 		goto out;
 	}
 
+	args.bitmask = nfs4_cache_bitmask(server, res.label);
+
 	status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
 	if (!status) {
 		nfs_access_set_mask(entry, res.access);
@@ -2959,7 +3049,7 @@ static int
 nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 		 int flags)
 {
-	struct nfs4_label *ilabel = NULL;
+	struct nfs4_label l, *ilabel = NULL;
 	struct nfs_open_context *ctx;
 	struct nfs4_state *state;
 	int status = 0;
@@ -2968,6 +3058,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 	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, ilabel, ctx->cred,
@@ -2981,6 +3073,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 	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;
 }
@@ -3029,6 +3122,8 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 	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)
@@ -3179,6 +3274,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
 		status = PTR_ERR(res.label);
 		goto out;
 	}
+	arg.bitmask = nfs4_bitmask(server, res.label);
 
 	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
 	if (!status) {
@@ -3236,7 +3332,7 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
 		data->arg.name = name;
 		data->arg.attrs = sattr;
 		data->arg.ftype = ftype;
-		data->arg.bitmask = server->attr_bitmask;
+		data->arg.bitmask = nfs4_bitmask(server, data->label);
 		data->res.server = server;
 		data->res.fh = &data->fh;
 		data->res.fattr = &data->fattr;
@@ -3297,14 +3393,19 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
 		struct page *page, unsigned int len, struct iattr *sattr)
 {
 	struct nfs4_exception exception = { };
-	struct nfs4_label *label = NULL;
+	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, label),
 				&exception);
 	} while (exception.retry);
+
+	nfs4_label_release_security(label);
 	return err;
 }
 
@@ -3330,15 +3431,19 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr)
 {
 	struct nfs4_exception exception = { };
-	struct nfs4_label *label = NULL;
+	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, label),
 				&exception);
 	} while (exception.retry);
+	nfs4_label_release_security(label);
+
 	return err;
 }
 
@@ -3354,7 +3459,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
 		.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,
@@ -3434,15 +3541,20 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr, dev_t rdev)
 {
 	struct nfs4_exception exception = { };
-	struct nfs4_label *label = NULL;
+	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, label, rdev),
 				&exception);
 	} while (exception.retry);
+
+	nfs4_label_release_security(label);
+
 	return err;
 }
 
@@ -3658,7 +3770,8 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
 		data->args.bitmask = NULL;
 		data->res.fattr = NULL;
 	} else
-		data->args.bitmask = server->cache_consistency_bitmask;
+
+	data->args.bitmask = nfs4_cache_bitmask(server, NULL);
 
 	if (!data->write_done_cb)
 		data->write_done_cb = nfs4_write_done_cb;
@@ -4083,6 +4196,179 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
 	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)
 {
@@ -4371,7 +4657,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
 	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;
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 4fa0bf1..2726f21 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -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 xdr_stream *xdr, const nfs4_verifier *ve
 	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];
@@ -1022,6 +1038,8 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
 		}
 		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)
@@ -1078,6 +1096,13 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
 		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.
@@ -1144,7 +1169,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
 	}
 
 	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)
@@ -1377,21 +1402,23 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
 	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);
@@ -1547,7 +1574,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
 
 static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
 {
-	uint32_t attrs[2] = {
+	uint32_t attrs[3] = {
 		FATTR4_WORD0_RDATTR_ERROR,
 		FATTR4_WORD1_MOUNTED_ON_FILEID,
 	};
@@ -1570,20 +1597,26 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
 	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) {
+		if (hdr->minorversion > 1)
+			attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
+		p++, *p++ = cpu_to_be32(attrs[2] & readdir->bitmask[2]);
+	}
 	memcpy(verf, readdir->verifier.data, sizeof(verf));
-	dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
+
+	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]);
+			attrs[1] & readdir->bitmask[1],
+			attrs[2] & readdir->bitmask[2]);
 }
 
 static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
@@ -1642,7 +1675,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs
 {
 	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)
@@ -4060,6 +4093,60 @@ static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap,
 	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;
@@ -4402,7 +4489,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;
@@ -4510,6 +4597,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
 	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;
@@ -4517,7 +4609,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,
@@ -4536,7 +4628,8 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
 	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;
 
@@ -4547,9 +4640,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);
 }
 
 /*
@@ -5883,7 +5976,7 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp,
 	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;
 }
@@ -5909,7 +6002,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -5938,7 +6031,7 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -5964,7 +6057,8 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp,
 		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;
 }
@@ -6055,7 +6149,7 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -6084,7 +6178,7 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -6116,7 +6210,7 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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;
 }
@@ -6218,7 +6312,7 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	 * 	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;
 }
@@ -6249,7 +6343,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 		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;
 }
@@ -6299,7 +6393,7 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp,
 		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;
 }
@@ -6326,7 +6420,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp,
 	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;
 }
@@ -6506,7 +6600,7 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	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:
@@ -6687,7 +6781,7 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
 	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);
@@ -6720,7 +6814,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
 	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;
 }
@@ -7001,7 +7095,7 @@ static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp,
 	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;
 }
@@ -7133,7 +7227,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
 		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 --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 4bdffe0..0ead05b 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1922,7 +1922,7 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
 	data->args.inode = inode;
 	data->cred = get_rpccred(nfsi->layout->plh_lc_cred);
 	nfs_fattr_init(&data->fattr);
-	data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
+	data->args.bitmask = nfs4_cache_bitmask(NFS_SERVER(inode), NULL);
 	data->res.fattr = &data->fattr;
 	data->args.lastbytewritten = end_pos - 1;
 	data->res.server = NFS_SERVER(inode);
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 00af026..68c42be 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2379,8 +2379,21 @@ static int nfs_bdi_register(struct nfs_server *server)
 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,
-								0, NULL);
+	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 --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 1ef8eb4..1510f4f 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -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
@@ -344,6 +345,8 @@ extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
 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);
@@ -502,9 +505,19 @@ static inline void nfs4_label_free(struct nfs4_label *label)
 	}
 	return;
 }
+static inline u32 *nfs4_cache_bitmask(struct nfs_server *server, struct nfs4_label *label)
+{
+	if (label)
+		return server->cache_consistency_bitmask;
+
+	return server->cache_consistency_bitmask_nl;
+}
 #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) {}
+static inline u32 *
+nfs4_cache_bitmask(struct nfs_server *server, struct nfs4_label *label)
+{ return server->cache_consistency_bitmask; }
 #endif
 
 /*
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index e6ed3c2..2a4f1d4 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -145,11 +145,18 @@ struct nfs_server {
 	u32			attr_bitmask[3];/* V4 bitmask representing the set
 						   of attributes supported on this
 						   filesystem */
+	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 */
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index d7ff806..f68b577 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2877,7 +2877,10 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
 		return;
 	}
 
+	isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	isec->sid = newsid;
+	isec->initialized = 1;
+
 	return;
 }
 
@@ -2965,6 +2968,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
 	if (rc)
 		return rc;
 
+	isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	isec->sid = newsid;
 	isec->initialized = 1;
 	return 0;
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 71+ messages in thread

end of thread, other threads:[~2013-05-08 18:47 UTC | newest]

Thread overview: 71+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-04-24 20:17 [PATCH 00/17] lnfs: 3.9-rc8 release Steve Dickson
2013-04-24 20:17 ` [PATCH 01/17] NFSv4.2: Added v4.2 error codes Steve Dickson
2013-04-24 21:54   ` J. Bruce Fields
2013-04-24 20:17 ` [PATCH 02/17] NFSv4.2: Added NFS v4.2 support to the NFS client Steve Dickson
2013-04-24 21:56   ` J. Bruce Fields
2013-04-24 20:17 ` [PATCH 03/17] NFSDv4.2: Added NFS v4.2 support to the NFS server Steve Dickson
2013-04-24 22:02   ` J. Bruce Fields
     [not found]     ` <20130424220226.GN20275-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
2013-04-25 14:10       ` Steve Dickson
2013-04-25 14:10         ` Steve Dickson
2013-04-25 18:26         ` J. Bruce Fields
2013-04-24 20:17 ` [PATCH 04/17] Security: Add hook to calculate context based on a negative dentry Steve Dickson
2013-04-24 22:02   ` J. Bruce Fields
     [not found]     ` <20130424220258.GO20275-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
2013-04-24 22:09       ` David Quigley
2013-04-24 22:09         ` David Quigley
2013-04-24 22:09         ` David Quigley
2013-04-24 22:12       ` Steve Dickson
2013-04-24 22:12         ` Steve Dickson
     [not found]         ` <517858D1.5000406-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
2013-04-24 22:14           ` David Quigley
2013-04-24 22:14             ` David Quigley
2013-04-24 22:14             ` David Quigley
     [not found]             ` <faf7db0bcd9b208c201a652c718c720c-fuEpAR7jH0UNb0vsIHg089HuzzzSOjJt@public.gmane.org>
2013-04-24 23:03               ` J. Bruce Fields
2013-04-24 23:03                 ` J. Bruce Fields
2013-04-24 23:05                 ` David Quigley
2013-04-24 23:05                   ` David Quigley
2013-04-25  1:27                   ` Casey Schaufler
2013-04-25  1:27                     ` Casey Schaufler
     [not found]                     ` <5178867E.30704-iSGtlc1asvQWG2LlvL+J4A@public.gmane.org>
2013-04-25  1:43                       ` J. Bruce Fields
2013-04-25  1:43                         ` J. Bruce Fields
2013-04-24 20:17 ` [PATCH 06/17] LSM: Add flags field to security_sb_set_mnt_opts for in kernel mount data Steve Dickson
2013-04-24 22:03   ` J. Bruce Fields
2013-04-24 20:17 ` [PATCH 07/17] SELinux: Add new labeling type native labels Steve Dickson
2013-04-24 22:03   ` J. Bruce Fields
     [not found]     ` <20130424220359.GR20275-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
2013-04-24 22:06       ` David Quigley
2013-04-24 22:06         ` David Quigley
2013-04-24 22:06         ` David Quigley
2013-04-24 20:17 ` [PATCH 09/17] NFSv4: Introduce new label structure Steve Dickson
2013-04-24 20:17 ` [PATCH 10/17] NFSv4: Extend fattr bitmaps to support all 3 words Steve Dickson
2013-04-24 20:17 ` [PATCH 12/17] NFS: Add label lifecycle management Steve Dickson
2013-04-24 20:18 ` [PATCH 14/17] NFS: Extend NFS xattr handlers to accept the security namespace Steve Dickson
     [not found] ` <1366834683-29075-1-git-send-email-SteveD-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-04-24 20:17   ` [PATCH 05/17] Security: Add Hook to test if the particular xattr is part of a MAC model Steve Dickson
2013-04-24 20:17     ` Steve Dickson
2013-04-24 22:03     ` J. Bruce Fields
2013-04-24 20:17   ` [PATCH 08/17] NFSv4: Add label recommended attribute and NFSv4 flags Steve Dickson
2013-04-24 20:17     ` Steve Dickson
2013-04-24 20:17   ` [PATCH 11/17] NFS:Add labels to client function prototypes Steve Dickson
2013-04-24 20:17     ` Steve Dickson
2013-04-24 20:17   ` [PATCH 13/17] NFS: Client implementation of Labeled-NFS Steve Dickson
2013-04-24 20:17     ` Steve Dickson
2013-04-24 20:18   ` [PATCH 15/17] Kconfig: Add Kconfig entry for Labeled NFS V4 client Steve Dickson
2013-04-24 20:18     ` Steve Dickson
2013-04-24 20:18 ` [PATCH 16/17] NFSD: Server implementation of MAC Labeling Steve Dickson
2013-04-24 21:28   ` J. Bruce Fields
2013-04-24 22:14     ` Steve Dickson
     [not found]       ` <51785962.7080008-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
2013-04-24 23:04         ` J. Bruce Fields
2013-04-24 23:04           ` J. Bruce Fields
2013-04-24 20:18 ` [PATCH 17/17] Kconfig: Add Kconfig entry for Labeled NFS V4 server Steve Dickson
2013-04-29 12:57 [PATCH 00/17] lnfs: 3.9-rc8 release (take 2) Steve Dickson
2013-04-29 12:57 ` [PATCH 13/17] NFS: Client implementation of Labeled-NFS Steve Dickson
2013-05-01 19:03   ` Myklebust, Trond
2013-05-08 16:39     ` Steve Dickson
2013-05-08 16:43       ` Myklebust, Trond
2013-05-08 17:39         ` Steve Dickson
2013-05-08 18:07           ` Myklebust, Trond
2013-05-08 18:27             ` Steve Dickson
2013-05-08 18:31               ` Myklebust, Trond
     [not found]                 ` <1368037873.5978.34.camel-5lNtUQgoD8Pfa3cDbr2K10B+6BGkLq7r@public.gmane.org>
2013-05-08 18:41                   ` Steve Dickson
2013-05-08 18:41                     ` Steve Dickson
2013-05-08 18:47                     ` Myklebust, Trond
2013-05-02 17:18 [PATCH 00/17] lnfs: linux-3.9 release Steve Dickson
2013-05-02 17:19 ` [PATCH 13/17] NFS: Client implementation of Labeled-NFS Steve Dickson
2013-05-04 19:26   ` J. Bruce Fields
2013-05-06  8:17     ` James Morris
2013-05-06  8:17       ` James Morris

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.