linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 12/14] NFS: Client implementation of Labeled-NFS
  2008-09-15 20:41 [RFC] Labeled NFS Take 2 David P. Quigley
@ 2008-09-15 20:41 ` David P. Quigley
  0 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-15 20:41 UTC (permalink / raw)
  To: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields
  Cc: linux-kernel, linux-fsdevel, linux-security-module,
	David P. Quigley, Matthew N. Dodd

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: David P. Quigley <dpquigl@tycho.nsa.gov>
---
 fs/nfs/inode.c           |   45 ++++++-
 fs/nfs/nfs4proc.c        |  303 ++++++++++++++++++++++++++++++++++++++++++----
 fs/nfs/nfs4xdr.c         |   55 ++++++++-
 fs/nfs/super.c           |   16 +++-
 include/linux/nfs_fs.h   |    2 +
 security/selinux/hooks.c |    5 +
 6 files changed, 391 insertions(+), 35 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 40d7142..dde0667 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -143,10 +143,13 @@ static void nfs_zap_caches_locked(struct inode *inode)
 	nfsi->attrtimeo_timestamp = jiffies;
 
 	memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
+	nfsi->cache_validity |= NFS_INO_INVALID_ATTR| \
+				NFS_INO_INVALID_LABEL| \
+				NFS_INO_INVALID_ACCESS| \
+				NFS_INO_INVALID_ACL| \
+				NFS_INO_REVAL_PAGECACHE;
 	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;
-	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_DATA;
 }
 
 void nfs_zap_caches(struct inode *inode)
@@ -235,6 +238,29 @@ nfs_init_locked(struct inode *inode, void *opaque)
 /* Don't use READDIRPLUS on directories that we believe are too large */
 #define NFS_LIMIT_READDIRPLUS (8*PAGE_SIZE)
 
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr)
+{
+	int error;
+
+/*	BUG_ON(!mutex_is_locked(&inode->i_mutex)); */
+
+	if ((fattr->valid & NFS_ATTR_FATTR_V4) &&
+	    (fattr->bitmap[1] & FATTR4_WORD1_SECURITY_LABEL) &&
+	    (fattr->label != NULL) &&
+	    (inode->i_security != NULL)) {
+		error = security_inode_notifysecctx(inode, fattr->label,
+						   fattr->label_len);
+		/* XXX: debug output */
+		if (error)
+			printk(KERN_ERR "%s() %s %d "
+				"security_inode_notifysecctx() %d\n",
+				__func__,
+				(char *)fattr->label, fattr->label_len, error);
+	}
+}
+#endif
+
 /*
  * This is our front-end to iget that looks up inodes by file handle
  * instead of inode number.
@@ -316,6 +342,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 		inode->i_nlink = fattr->nlink;
 		inode->i_uid = fattr->uid;
 		inode->i_gid = fattr->gid;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		nfs_setsecurity(inode, fattr);
+#endif
+
 		if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
 			/*
 			 * report the blocks in 512byte units
@@ -790,7 +821,7 @@ int nfs_attribute_timeout(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_timeout(inode))
 		return NFS_STALE(inode) ? -ESTALE : 0;
 	return __nfs_revalidate_inode(server, inode);
@@ -1146,6 +1177,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 	inode->i_nlink = fattr->nlink;
 	inode->i_uid = fattr->uid;
 	inode->i_gid = fattr->gid;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	nfs_setsecurity(inode, fattr);
+#endif
 
 	if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
 		/*
@@ -1157,7 +1191,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
  	}
 
 	/* 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;
@@ -1175,6 +1209,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 			nfsi->last_updated = nfsi->read_cache_jiffies;
 	}
 	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 92522cc..622bf71 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -48,6 +48,7 @@
 #include <linux/smp_lock.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
+#include <linux/nfs4_mount.h>
 
 #include "nfs4_fs.h"
 #include "delegation.h"
@@ -97,6 +98,9 @@ const u32 nfs4_fattr_bitmap[2] = {
 	| FATTR4_WORD1_TIME_ACCESS
 	| FATTR4_WORD1_TIME_METADATA
 	| FATTR4_WORD1_TIME_MODIFY
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	| FATTR4_WORD1_SECURITY_LABEL
+#endif
 };
 
 const u32 nfs4_statfs_bitmap[2] = {
@@ -251,7 +255,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
 
 static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
 		struct nfs4_state_owner *sp, int flags,
-		const struct iattr *attrs)
+		const struct iattr *attrs, struct nfs4_label *label)
 {
 	struct dentry *parent = dget_parent(path->dentry);
 	struct inode *dir = parent->d_inode;
@@ -277,6 +281,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
 	p->o_arg.server = server;
 	p->o_arg.bitmask = server->attr_bitmask;
 	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
+	p->o_arg.label = label;
 	if (flags & O_EXCL) {
 		u32 *s = (u32 *) p->o_arg.u.verifier.data;
 		s[0] = jiffies;
@@ -563,7 +568,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context
 {
 	struct nfs4_opendata *opendata;
 
-	opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL);
+	opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL, NULL);
 	if (opendata == NULL)
 		return ERR_PTR(-ENOMEM);
 	opendata->state = state;
@@ -1042,7 +1047,7 @@ static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct
 /*
  * Returns a referenced nfs4_state
  */
-static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res)
+static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct nfs4_label *label, struct rpc_cred *cred, struct nfs4_state **res)
 {
 	struct nfs4_state_owner  *sp;
 	struct nfs4_state     *state = NULL;
@@ -1064,7 +1069,7 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct
 		nfs4_return_incompatible_delegation(path->dentry->d_inode, flags & (FMODE_READ|FMODE_WRITE));
 	down_read(&clp->cl_sem);
 	status = -ENOMEM;
-	opendata = nfs4_opendata_alloc(path, sp, flags, sattr);
+	opendata = nfs4_opendata_alloc(path, sp, flags, sattr, label);
 	if (opendata == NULL)
 		goto err_release_rwsem;
 
@@ -1099,14 +1104,14 @@ out_err:
 }
 
 
-static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred)
+static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct nfs4_label *label, struct rpc_cred *cred)
 {
 	struct nfs4_exception exception = { };
 	struct nfs4_state *res;
 	int status;
 
 	do {
-		status = _nfs4_do_open(dir, path, flags, sattr, cred, &res);
+		status = _nfs4_do_open(dir, path, flags, sattr, label, cred, &res);
 		if (status == 0)
 			break;
 		/* NOTE: BAD_SEQID means the server and client disagree about the
@@ -1150,14 +1155,15 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int
 
 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_label *label, struct nfs4_state *state)
 {
 	struct nfs_server *server = NFS_SERVER(inode);
         struct nfs_setattrargs  arg = {
                 .fh             = NFS_FH(inode),
                 .iap            = sattr,
 		.server		= server,
-		.bitmask = server->attr_bitmask,
+		.bitmask 	= server->attr_bitmask,
+		.label		= label,
         };
         struct nfs_setattrres  res = {
 		.fattr		= fattr,
@@ -1189,14 +1195,14 @@ 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_label *label, struct nfs4_state *state)
 {
 	struct nfs_server *server = NFS_SERVER(inode);
 	struct nfs4_exception exception = { };
 	int err;
 	do {
 		err = nfs4_handle_exception(server,
-				_nfs4_do_setattr(inode, cred, fattr, sattr, state),
+				_nfs4_do_setattr(inode, cred, fattr, sattr, label, state),
 				&exception);
 	} while (exception.retry);
 	return err;
@@ -1400,6 +1406,7 @@ out_close:
 struct dentry *
 nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 {
+	struct nfs4_label l, *label = NULL;
 	struct path path = {
 		.mnt = nd->path.mnt,
 		.dentry = dentry,
@@ -1413,11 +1420,21 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 	cred = rpc_lookup_cred();
 	if (IS_ERR(cred))
 		return (struct dentry *)cred;
+	memset(&attr, 0, sizeof(struct iattr));
 	if (nd->flags & LOOKUP_CREATE) {
 		attr.ia_mode = nd->intent.open.create_mode;
 		attr.ia_valid = ATTR_MODE;
 		if (!IS_POSIXACL(dir))
 			attr.ia_mode &= ~current->fs->umask;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+			int error;
+			error = security_dentry_init_security(dentry,
+					attr.ia_mode, &l.label, &l.len);
+			if (error == 0)
+				label = &l;
+		}
+#endif
 	} else {
 		attr.ia_valid = 0;
 		BUG_ON(nd->intent.open.flags & O_CREAT);
@@ -1426,8 +1443,12 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 	parent = dentry->d_parent;
 	/* Protect against concurrent sillydeletes */
 	nfs_block_sillyrename(parent);
-	state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred);
+	state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, label, cred);
 	put_rpccred(cred);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		security_release_secctx(l.label, l.len);
+#endif
 	if (IS_ERR(state)) {
 		if (PTR_ERR(state) == -ENOENT) {
 			d_add(dentry, NULL);
@@ -1458,7 +1479,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
 	cred = rpc_lookup_cred();
 	if (IS_ERR(cred))
 		return PTR_ERR(cred);
-	state = nfs4_do_open(dir, &path, openflags, NULL, cred);
+	state = nfs4_do_open(dir, &path, openflags, NULL, NULL, cred);
 	put_rpccred(cred);
 	if (IS_ERR(state)) {
 		switch (PTR_ERR(state)) {
@@ -1500,6 +1521,13 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
 		memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask));
 		if (res.attr_bitmask[0] & FATTR4_WORD0_ACL)
 			server->caps |= NFS_CAP_ACLS;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		if (server->flags & NFS4_MOUNT_SECURITY_LABEL &&
+		    res.attr_bitmask[1] & FATTR4_WORD1_SECURITY_LABEL) {
+			server->caps |= NFS_CAP_SECURITY_LABEL;
+		} else
+#endif
+		server->attr_bitmask[1] &= ~FATTR4_WORD1_SECURITY_LABEL;
 		if (res.has_links != 0)
 			server->caps |= NFS_CAP_HARDLINKS;
 		if (res.has_symlinks != 0)
@@ -1680,9 +1708,11 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 		state = ctx->state;
 	}
 
-	status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
-	if (status == 0)
+	status = nfs4_do_setattr(inode, cred, fattr, sattr, NULL, state);
+	if (status == 0) {
 		nfs_setattr_update_inode(inode, sattr);
+		nfs_setsecurity(inode, fattr);
+	}
 	return status;
 }
 
@@ -1903,6 +1933,7 @@ static int
 nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                  int flags, struct nameidata *nd)
 {
+	struct nfs4_label l, *label = NULL;
 	struct path path = {
 		.mnt = nd->path.mnt,
 		.dentry = dentry,
@@ -1916,7 +1947,18 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 		status = PTR_ERR(cred);
 		goto out;
 	}
-	state = nfs4_do_open(dir, &path, flags, sattr, cred);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (((nd->flags & LOOKUP_CREATE) != 0) &&
+	      nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+		status = security_dentry_init_security(dentry,
+				sattr->ia_mode, &l.label, &l.len);
+		/* XXX: should this be more fatal? */
+		if (status == 0)
+			label = &l;
+	}
+#endif
+
+	state = nfs4_do_open(dir, &path, flags, sattr, label, cred);
 	d_drop(dentry);
 	if (IS_ERR(state)) {
 		status = PTR_ERR(state);
@@ -1931,10 +1973,12 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 		if (nfs_server_capable(state->inode, NFS_CAP_SECURITY_LABEL))
 			nfs_fattr_alloc(&fattr, GFP_KERNEL);
 #endif
-		status = nfs4_do_setattr(state->inode, cred, &fattr, sattr, state);
-		if (status == 0)
+		status = nfs4_do_setattr(state->inode, cred, &fattr, sattr, label, state);
+		if (status == 0) {
 			nfs_setattr_update_inode(state->inode, sattr);
-		nfs_post_op_update_inode(state->inode, &fattr);
+			nfs_post_op_update_inode(state->inode, &fattr);
+			nfs_setsecurity(state->inode, &fattr);
+		}
 		nfs_fattr_fini(&fattr);
 	}
 	if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
@@ -1944,6 +1988,10 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 out_putcred:
 	put_rpccred(cred);
 out:
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		security_release_secctx(label->label, label->len);
+#endif
 	return status;
 }
 
@@ -2206,7 +2254,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;
@@ -2222,6 +2271,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);
 
@@ -2234,18 +2284,33 @@ 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 l, *label = NULL;
 	int err;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+		err = security_dentry_init_security(dentry,
+				sattr->ia_mode, &l.label, &l.len);
+		if (err == 0)
+			label = &l;
+	}
+#endif
+
 	do {
 		err = nfs4_handle_exception(NFS_SERVER(dir),
 				_nfs4_proc_symlink(dir, dentry, page,
-							len, sattr),
+							len, sattr, label),
 				&exception);
 	} while (exception.retry);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		security_release_secctx(l.label, l.len);
+#endif
 	return err;
 }
 
 static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
-		struct iattr *sattr)
+		struct iattr *sattr, struct nfs4_label *label)
 {
 	struct nfs4_createdata *data;
 	int status = -ENOMEM;
@@ -2254,6 +2319,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);
@@ -2265,12 +2331,27 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr)
 {
 	struct nfs4_exception exception = { };
+	struct nfs4_label l, *label = NULL;
 	int err;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+		err = security_dentry_init_security(dentry,
+				sattr->ia_mode, &l.label, &l.len);
+		if (err == 0)
+			label = &l;
+	}
+#endif
+
 	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);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		security_release_secctx(l.label, l.len);
+#endif
 	return err;
 }
 
@@ -2325,7 +2406,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;
@@ -2350,7 +2431,7 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 		data->arg.u.device.specdata1 = MAJOR(rdev);
 		data->arg.u.device.specdata2 = MINOR(rdev);
 	}
-	
+	data->arg.label = label;
 	status = nfs4_do_create(dir, dentry, data);
 
 	nfs4_free_createdata(data);
@@ -2362,12 +2443,27 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr, dev_t rdev)
 {
 	struct nfs4_exception exception = { };
+	struct nfs4_label l, *label = NULL;
 	int err;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+		err = security_dentry_init_security(dentry,
+				sattr->ia_mode, &l.label, &l.len);
+		if (err == 0)
+			label = &l;
+	}
+#endif
+
 	do {
 		err = nfs4_handle_exception(NFS_SERVER(dir),
-				_nfs4_proc_mknod(dir, dentry, sattr, rdev),
+				_nfs4_proc_mknod(dir, dentry, sattr, label, rdev),
 				&exception);
 	} while (exception.retry);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		security_release_secctx(l.label, l.len);
+#endif
 	return err;
 }
 
@@ -2815,6 +2911,163 @@ 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;
+	u32 bitmask[2] = { 0, FATTR4_WORD1_SECURITY_LABEL };
+	struct nfs4_getattr_arg args = {
+		.fh		= NFS_FH(inode),
+		.bitmask	= bitmask,
+	};
+	struct nfs4_getattr_res res = {
+		.fattr		= &fattr,
+		.server		= server,
+	};
+	struct rpc_message msg = {
+		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
+		.rpc_argp	= &args,
+		.rpc_resp	= &res,
+	};
+	int ret;
+
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+	nfs_fattr_alloc(&fattr, GFP_KERNEL);
+	nfs_fattr_init(&fattr);
+
+	ret = rpc_call_sync(server->client, &msg, 0);
+	if (ret)
+		goto out;
+	if (!(fattr.bitmap[1] & FATTR4_WORD1_SECURITY_LABEL))
+		return -ENOENT;
+	if (buflen < fattr.label_len) {
+		ret = -ERANGE;
+		goto out;
+	}
+	memcpy(buf, fattr.label, fattr.label_len);
+out:
+	nfs_fattr_fini(&fattr);
+	return ret;
+}
+
+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 *label,
+				      struct nfs_fattr *fattr,
+				      struct nfs4_state *state)
+{
+
+	struct iattr sattr;
+	struct nfs_server *server = NFS_SERVER(inode);
+	const u32 bitmask[2] = { 0, FATTR4_WORD1_SECURITY_LABEL };
+	struct nfs_setattrargs args = {
+		.fh             = NFS_FH(inode),
+		.iap            = &sattr,
+		.server		= server,
+		.bitmask	= bitmask,
+		.label		= label,
+	};
+	struct nfs_setattrres res = {
+		.fattr		= fattr,
+		.server		= server,
+	};
+	struct rpc_message msg = {
+		.rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
+		.rpc_argp       = &args,
+		.rpc_resp       = &res,
+	};
+	unsigned long timestamp = jiffies;
+	int status;
+
+	memset(&sattr, 0, sizeof(struct iattr));
+
+	if (nfs4_copy_delegation_stateid(&args.stateid, inode)) {
+		/* Use that stateid */
+	} else if (state != NULL) {
+		msg.rpc_cred = state->owner->so_cred;
+		nfs4_copy_stateid(&args.stateid, state, current->files);
+	} else
+		memcpy(&args.stateid, &zero_stateid, sizeof(args.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 *label,
+				     struct nfs_fattr *fattr,
+				     struct nfs4_state *state)
+{
+	struct nfs4_exception exception = { };
+	int err;
+
+	do {
+		err = nfs4_handle_exception(NFS_SERVER(inode),
+			_nfs4_do_set_security_label(inode, label, fattr, 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 label;
+	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;
+
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+	nfs_fattr_alloc(&fattr, GFP_KERNEL);
+	nfs_fattr_init(&fattr);
+
+	label.label = (char *)buf;
+	label.len = buflen;
+
+	cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+	if (IS_ERR(cred))
+		return PTR_ERR(cred);
+
+	/* 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, &label, &fattr, state);
+	if (status == 0)
+		nfs_setsecurity(inode, &fattr);
+	if (ctx != NULL)
+		put_nfs_open_context(ctx);
+	put_rpccred(cred);
+	nfs_fattr_fini(&fattr);
+	return status;
+}
+#endif	/* CONFIG_NFS_V4_SECURITY_LABEL */
+
 static int
 nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server)
 {
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index b916297..21f64a6 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -601,7 +601,7 @@ static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *ve
 	xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE);
 }
 
-static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
+static int 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];
@@ -651,6 +651,10 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
 		}
 		len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
 	}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		len += 4 + (XDR_QUADLEN(label->len) << 2);
+#endif
 	if (iap->ia_valid & ATTR_ATIME_SET)
 		len += 16;
 	else if (iap->ia_valid & ATTR_ATIME)
@@ -709,6 +713,13 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
 		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
 		WRITE32(NFS4_SET_TO_SERVER_TIME);
 	}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL) {
+		bmval1 |= FATTR4_WORD1_SECURITY_LABEL;
+		WRITE32(label->len);
+		WRITEMEM(label->label, label->len);
+	}
+#endif
 	
 	/*
 	 * Now we backfill the bitmap and the attribute buffer length.
@@ -792,7 +803,7 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c
 	WRITE32(create->name->len);
 	WRITEMEM(create->name->name, create->name->len);
 
-	return encode_attrs(xdr, create->attrs, create->server);
+	return encode_attrs(xdr, create->attrs, create->label, create->server);
 }
 
 static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
@@ -1000,7 +1011,7 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
 	switch(arg->open_flags & O_EXCL) {
 		case 0:
 			WRITE32(NFS4_CREATE_UNCHECKED);
-			encode_attrs(xdr, arg->u.attrs, arg->server);
+			encode_attrs(xdr, arg->u.attrs, arg->label, arg->server);
 			break;
 		default:
 			WRITE32(NFS4_CREATE_EXCLUSIVE);
@@ -1301,7 +1312,7 @@ static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *
         WRITE32(OP_SETATTR);
 	WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE);
 
-        if ((status = encode_attrs(xdr, arg->iap, server)))
+        if ((status = encode_attrs(xdr, arg->iap, arg->label, server)))
 		return status;
 
         return 0;
@@ -2954,6 +2965,39 @@ static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, str
 	return status;
 }
 
+static int decode_attr_security_label(struct xdr_stream *xdr, uint32_t *bitmap, char **ctx, u32 *ctxlen)
+{
+	__u32 len;
+	__be32 *p;
+	int rc = 0;
+
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_SECURITY_LABEL - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_SECURITY_LABEL)) {
+		READ_BUF(4);
+		READ32(len);
+		READ_BUF(len);
+		if (len < XDR_MAX_NETOBJ) {
+			if (*ctx != NULL) {
+				if (*ctxlen < len) {
+					printk(KERN_ERR
+						"%s(): ctxlen %d < len %d\n",
+						__func__, *ctxlen, len);
+					/* rc = -ENOMEM; */
+					*ctx = NULL;	/* leak */
+				} else {
+					memcpy(*ctx, p, len);
+				}
+			}
+			*ctxlen = len;
+		} else
+			printk(KERN_WARNING "%s: label too long (%u)!\n",
+					__FUNCTION__, len);
+		bitmap[1] &= ~FATTR4_WORD1_SECURITY_LABEL;
+	}
+	return rc;
+}
+
 static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
 {
 	unsigned int attrwords = XDR_QUADLEN(attrlen);
@@ -3188,6 +3232,9 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
 		goto xdr_error;
 	if ((status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid)) != 0)
 		goto xdr_error;
+	if ((status = decode_attr_security_label(xdr, bitmap,
+				&fattr->label, &fattr->label_len)) != 0)
+		goto xdr_error;
 	if (fattr->fileid == 0 && fileid != 0)
 		fattr->fileid = fileid;
 	if ((status = verify_attr_len(xdr, savep, attrlen)) == 0)
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 81cf6c5..bca62c1 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -554,8 +554,13 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
 		nfs_show_mountd_options(m, nfss, showdefaults);
 
 #ifdef CONFIG_NFS_V4
-	if (clp->rpc_ops->version == 4)
+	if (clp->rpc_ops->version == 4) {
 		seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		if (nfss->caps & NFS_CAP_SECURITY_LABEL)
+			seq_printf(m, ",security_label");
+#endif
+	}
 #endif
 }
 
@@ -612,6 +617,10 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
 		seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
 		seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
 		seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		if (nfss->caps & NFS_CAP_SECURITY_LABEL)
+			seq_printf(m, ",security_label");
+#endif
 	}
 #endif
 
@@ -2367,6 +2376,11 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
 		goto error_splat_super;
 	}
 
+#ifdef CONFIG_SECURITY_SELINUX
+	if (server->caps & NFS_CAP_SECURITY_LABEL)
+		security_sb_parse_opts_str("native_labels", &data->lsm_opts);
+#endif
+
 	error = security_sb_set_mnt_opts(s, &data->lsm_opts);
 	if (error)
 		goto error_splat_root;
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 192c056..7fdb309 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -196,6 +196,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
@@ -341,6 +342,7 @@ extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *map
 extern int nfs_revalidate_mapping_nolock(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);
 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, int mode);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 05a10be..f388235 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2851,7 +2851,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;
 }
 
@@ -2941,7 +2944,9 @@ 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.5.5.1


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

* [RFC v3] Security Label Support for NFSv4
@ 2008-09-29 17:06 David P. Quigley
  2008-09-29 17:06 ` [PATCH 01/14] VFS: Factor out part of vfs_setxattr so it can be called from the SELinux hook for inode_setsecctx David P. Quigley
                   ` (6 more replies)
  0 siblings, 7 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
  To: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields
  Cc: linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs


I sent this patchset out just before LPC so I think it might have been
overlooked by some people. I am resending the patchset with some corrections
based on comments by Casey and Steve in hopes that it gets more attention this
time.

It has been six months since the last time we submitted a patch set to the
mailing list for review. In this time we have fixed almost all of the issues
that people have had with the last patch set and have added a new feature to
allow for process labels to be transported with the RPC request. Below I
review each of the issues raised with the last patch set and what was done to
fix them. I also list the features present in this patch set and known issues.

When reviewing the code please be critical of it. We have reached the point
where we think we have the proper set of initial features implemented so we
would like to address all of the major and minor concerns with the code so it
can be cleaned up and submitted for inclusion. If you want a tree with the
patches already applied we have posted a public git tree that is ready for
cloning and use. This tree can be found at http://git.selinuxproject.org/git
and can be cloned with the command below. You can also find information on how
to setup a labeled nfs mount at http://www.selinuxproject.org/page/Labeled_NFS
however the putclientlabel mount option specified in the setup document is no
longer supported.

git-clone git://git.selinuxproject.org/~dpquigl/lnfs.git

Features:

* Client
	* Obtains labels from server for NFS files while still allowing for
	SELinux context mounts to override untrusted labeled servers.
	* Allows setting labels on files over NFS via xattr interface.
	* New security flavor (auth_seclabel) to transport process label to
	  server. This is a derivative of auth_unix so it does not support
	  kerberos which has its own issues that need to be dealt with.
* Server
	* Exports labels to clients. As of the moment there is no ability to
	restrict this based on label components such as MLS levels.
	* Persistent storage of labels assuming exported file system supports
	it.
	* If present uses process label for permission checks on server. Only
	effective if both client and server are running the same MAC model and
	policy. This will be addressed later by the label translation work.

Known Limitations/Bugs

If you want to utilize process label transport and file labels properly each
side must implement the same MAC model and be running the same policy. It is
possible for two SELinux systems to talk to each other if they have different
policies however from a policy perspective you can't be guaranteed that a type
on the client means the same thing on the server. Work is being done on
providing a DOI translation framework but is currently on the back burner so
work can be done to polish up this prototype and work on the IETF documents.

Concerns from last submission:

The patch to add maclabel_getname has been removed and replaced with the
{get,set,notify}secctx hooks that were discussed on the mailing list.

The use of the iattr structure to pass label data up and down the call stack
has been replace with a method that mimics the NFSv4 ACL implementation. A new
structure nfs4_label has been added and is added to the necessary functions to
pass the data around. 

Andrew's request to make the name and value pointers to the vfs helper for
setxattr const has been addressed.

The lifecycle management patch for the fattr structure has not been addressed
because it will probably be replaced with a method similar to what we did to
fix the iattr problem. Also the maximum label size has been set at 4096. I
know there are some concerns with hard limits on label size but Trond and
Bruce have brought up issues with doing memory reallocation inside of the XDR
handlers. Since it isn't appropriate to realloc memory there and there is no
effective retry capability if the buffer isn't large enough this doesn't seem
like an option.

The mount code has been changed to use Eric Paris's new security parameter
and now it uses the new text based mount system.

---

 fs/Kconfig                          |   17 ++
 fs/nfs/client.c                     |   18 ++-
 fs/nfs/dir.c                        |   24 ++
 fs/nfs/getroot.c                    |   34 +++
 fs/nfs/inode.c                      |   61 +++++-
 fs/nfs/namespace.c                  |    3 +
 fs/nfs/nfs3proc.c                   |   10 +
 fs/nfs/nfs4proc.c                   |  447 +++++++++++++++++++++++++++++++---
 fs/nfs/nfs4xdr.c                    |   56 ++++-
 fs/nfs/proc.c                       |   12 +-
 fs/nfs/super.c                      |   29 +++-
 fs/nfsd/auth.c                      |   21 ++
 fs/nfsd/export.c                    |    3 +
 fs/nfsd/nfs4proc.c                  |   25 ++-
 fs/nfsd/nfs4xdr.c                   |  101 ++++++++-
 fs/nfsd/vfs.c                       |   22 ++
 fs/xattr.c                          |   55 ++++-
 include/linux/nfs4.h                |    8 +
 include/linux/nfs4_mount.h          |    8 +-
 include/linux/nfs_fs.h              |   48 ++++
 include/linux/nfs_fs_sb.h           |    2 +-
 include/linux/nfs_xdr.h             |    7 +
 include/linux/nfsd/export.h         |    5 +-
 include/linux/nfsd/nfsd.h           |    9 +-
 include/linux/nfsd/xdr4.h           |    3 +
 include/linux/security.h            |   75 ++++++
 include/linux/sunrpc/auth.h         |    4 +
 include/linux/sunrpc/msg_prot.h     |    1 +
 include/linux/sunrpc/svcauth.h      |    4 +
 include/linux/xattr.h               |    1 +
 net/sunrpc/Makefile                 |    1 +
 net/sunrpc/auth.c                   |   16 ++
 net/sunrpc/auth_seclabel.c          |  291 +++++++++++++++++++++++
 net/sunrpc/svc.c                    |    1 +
 net/sunrpc/svcauth.c                |    6 +
 net/sunrpc/svcauth_unix.c           |   97 ++++++++-
 security/security.c                 |   34 +++
 security/selinux/hooks.c            |  148 ++++++++++--
 security/selinux/include/security.h |    4 +
 security/selinux/ss/policydb.c      |    5 +-
 security/smack/smack_lsm.c          |   11 +
 41 files changed, 1627 insertions(+), 100 deletions(-)


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

* [PATCH 01/14] VFS: Factor out part of vfs_setxattr so it can be called from the SELinux hook for inode_setsecctx.
  2008-09-29 17:06 [RFC v3] Security Label Support for NFSv4 David P. Quigley
@ 2008-09-29 17:06 ` David P. Quigley
  2008-09-30 19:51   ` Serge E. Hallyn
  2008-09-29 17:06 ` [PATCH 05/14] SELinux: Add new labeling type native labels David P. Quigley
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
  To: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields
  Cc: linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs, David P. Quigley, Matthew N. Dodd

This factors out the part of the vfs_setxattr function that performs the
setting of the xattr and its notification. This is needed so the SELinux
implementation of inode_setsecctx can handle the setting of it's xattr while
maintaining the proper separation of layers.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
---
 fs/xattr.c            |   55 +++++++++++++++++++++++++++++++++++++-----------
 include/linux/xattr.h |    1 +
 2 files changed, 43 insertions(+), 13 deletions(-)

diff --git a/fs/xattr.c b/fs/xattr.c
index 468377e..2f93006 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -66,22 +66,28 @@ xattr_permission(struct inode *inode, const char *name, int mask)
 	return inode_permission(inode, mask);
 }
 
-int
-vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
-		size_t size, int flags)
+/**
+ *  __vfs_setxattr_noperm - perform setxattr operation without performing
+ *  permission checks.
+ *
+ *  @dentry - object to perform setxattr on
+ *  @name - xattr name to set
+ *  @value - value to set @name to
+ *  @size - size of @value
+ *  @flags - flags to pass into filesystem operations
+ *
+ *  returns the result of the internal setxattr or setsecurity operations.
+ *
+ *  This function requires the caller to lock the inode's i_mutex before it
+ *  is executed. It also assumes that the caller will make the appropriate
+ *  permission checks.
+ */
+int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
+		const void *value, size_t size, int flags)
 {
 	struct inode *inode = dentry->d_inode;
-	int error;
-
-	error = xattr_permission(inode, name, MAY_WRITE);
-	if (error)
-		return error;
+	int error = -EOPNOTSUPP;
 
-	mutex_lock(&inode->i_mutex);
-	error = security_inode_setxattr(dentry, name, value, size, flags);
-	if (error)
-		goto out;
-	error = -EOPNOTSUPP;
 	if (inode->i_op->setxattr) {
 		error = inode->i_op->setxattr(dentry, name, value, size, flags);
 		if (!error) {
@@ -97,6 +103,29 @@ vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
 		if (!error)
 			fsnotify_xattr(dentry);
 	}
+
+	return error;
+}
+
+
+int
+vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
+		size_t size, int flags)
+{
+	struct inode *inode = dentry->d_inode;
+	int error;
+
+	error = xattr_permission(inode, name, MAY_WRITE);
+	if (error)
+		return error;
+
+	mutex_lock(&inode->i_mutex);
+	error = security_inode_setxattr(dentry, name, value, size, flags);
+	if (error)
+		goto out;
+
+	error = __vfs_setxattr_noperm(dentry, name, value, size, flags);
+
 out:
 	mutex_unlock(&inode->i_mutex);
 	return error;
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index d131e35..5c84af8 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -49,6 +49,7 @@ struct xattr_handler {
 ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
 ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t);
 ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
+int __vfs_setxattr_noperm(struct dentry *, const char *, const void *, size_t, int);
 int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int);
 int vfs_removexattr(struct dentry *, const char *);
 
-- 
1.5.5.1


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

* [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information.
       [not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
@ 2008-09-29 17:06   ` David P. Quigley
  2008-09-30 20:01     ` Serge E. Hallyn
  2008-09-30 20:22     ` Serge E. Hallyn
  2008-09-29 17:06   ` [PATCH 03/14] Security: Add hook to calculate context based on a negative dentry David P. Quigley
                     ` (7 subsequent siblings)
  8 siblings, 2 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
  To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
	casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
	matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
	trond.myklebust-41N18TsMXrtuMpJDpNschA,
	bfields-uC3wQj2KruNg9hUCZPvPmw
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	linux-security-module-u79uwXL29TY76Z2rM5mHXA,
	selinux-+05T5uksL2qpZYMLLGbcSA,
	labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
	Matthew N. Dodd

This patch introduces three new hooks. The inode_getsecctx hook is used to get
all relevant information from an LSM about an inode. The inode_setsecctx is
used to set both the in-core and on-disk state for the inode based on a context
derived from inode_getsecctx.The final hook inode_notifysecctx will notify the
LSM of a change for the in-core state of the inode in question. These hooks are
for use in the labeled NFS code and addresses concerns of how to set security
on an inode in a multi-xattr LSM. For historical reasons Stephen Smalley's
explanation of the reason for these hooks is pasted below.

Quote Stephen Smalley

inode_setsecctx:  Change the security context of an inode.  Updates the
in core security context managed by the security module and invokes the
fs code as needed (via __vfs_setxattr_noperm) to update any backing
xattrs that represent the context.  Example usage:  NFS server invokes
this hook to change the security context in its incore inode and on the
backing file system to a value provided by the client on a SETATTR
operation.

inode_notifysecctx:  Notify the security module of what the security
context of an inode should be.  Initializes the incore security context
managed by the security module for this inode.  Example usage:  NFS
client invokes this hook to initialize the security context in its
incore inode to the value provided by the server for the file when the
server returned the file's attributes to the client.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
 include/linux/security.h |   50 ++++++++++++++++++++++++++++++++++++++++++++++
 security/security.c      |   18 ++++++++++++++++
 security/selinux/hooks.c |   25 +++++++++++++++++++++++
 3 files changed, 93 insertions(+), 0 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index 80c4d00..8b5b041 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1289,6 +1289,36 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *	audit_rule_init.
  *	@rule contains the allocated rule
  *
+ * @inode_notifysecctx:
+ *	Notify the security module of what the security context of an inode
+ *	should be.  Initializes the incore security context managed by the
+ *	security module for this inode.  Example usage:  NFS client invokes
+ *	this hook to initialize the security context in its incore inode to the
+ *	value provided by the server for the file when the server returned the
+ *	file's attributes to the client.
+ *
+ * 	@inode we wish to set the security context of.
+ * 	@ctx contains the string which we wish to set in the inode.
+ * 	@ctxlen contains the length of @ctx.
+ *
+ * @inode_setsecctx:
+ * 	Change the security context of an inode.  Updates the
+ * 	incore security context managed by the security module and invokes the
+ * 	fs code as needed (via __vfs_setxattr_noperm) to update any backing
+ * 	xattrs that represent the context.  Example usage:  NFS server invokes
+ * 	this hook to change the security context in its incore inode and on the
+ * 	backing filesystem to a value provided by the client on a SETATTR
+ * 	operation.
+ *
+ * 	@dentry contains the inode we wish to set the security context of.
+ * 	@ctx contains the string which we wish to set in the inode.
+ * 	@ctxlen contains the length of @ctx.
+ *
+ * @inode_getsecctx:
+ * 	Returns a string containing all relavent security context information
+ * 	@inode we wish to set the security context of.
+ *	@ctx is a pointer to place the allocated security context should be placed.
+ *	@ctxlen points to the place to put the length of @ctx.
  * This is the main security structure.
  */
 struct security_operations {
@@ -1479,6 +1509,10 @@ struct security_operations {
 	int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
 	void (*release_secctx) (char *secdata, u32 seclen);
 
+	int (*inode_notifysecctx)(struct inode *inode, void *ctx, u32 ctxlen);
+	int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen);
+	int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen);
+
 #ifdef CONFIG_SECURITY_NETWORK
 	int (*unix_stream_connect) (struct socket *sock,
 				    struct socket *other, struct sock *newsk);
@@ -1727,6 +1761,9 @@ 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);
 
+int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
+int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
+int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
 #else /* CONFIG_SECURITY */
 struct security_mnt_opts {
 };
@@ -2458,6 +2495,19 @@ static inline int security_secctx_to_secid(const char *secdata,
 static inline void security_release_secctx(char *secdata, u32 seclen)
 {
 }
+
+static inline int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
+{
+	return -EOPNOTSUPP;
+}
+static inline int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
+{
+	return -EOPNOTSUPP;
+}
+static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+{
+	return -EOPNOTSUPP;
+}
 #endif	/* CONFIG_SECURITY */
 
 #ifdef CONFIG_SECURITY_NETWORK
diff --git a/security/security.c b/security/security.c
index 3a4b4f5..d0fd42a 100644
--- a/security/security.c
+++ b/security/security.c
@@ -869,6 +869,24 @@ void security_release_secctx(char *secdata, u32 seclen)
 }
 EXPORT_SYMBOL(security_release_secctx);
 
+int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
+{
+	return security_ops->inode_notifysecctx(inode, ctx, ctxlen);
+}
+EXPORT_SYMBOL(security_inode_notifysecctx);
+
+int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
+{
+	return security_ops->inode_setsecctx(dentry, ctx, ctxlen);
+}
+EXPORT_SYMBOL(security_inode_setsecctx);
+
+int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+{
+	return security_ops->inode_getsecctx(inode, ctx, ctxlen);
+}
+EXPORT_SYMBOL(security_inode_getsecctx);
+
 #ifdef CONFIG_SECURITY_NETWORK
 
 int security_unix_stream_connect(struct socket *sock, struct socket *other,
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 03fc6a8..b07871b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5285,6 +5285,28 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
 	kfree(secdata);
 }
 
+/*
+ *	This hook requires that the inode i_mutex be locked
+ */
+static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
+{
+	return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
+}
+
+/*
+ *	This hook requires that the inode i_mutex be locked
+ */
+static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
+{
+	return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
+}
+
+static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+{
+	*ctxlen = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
+						ctx, true);
+	return *ctxlen;
+}
 #ifdef CONFIG_KEYS
 
 static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
@@ -5491,6 +5513,9 @@ static struct security_operations selinux_ops = {
 	.secid_to_secctx =		selinux_secid_to_secctx,
 	.secctx_to_secid =		selinux_secctx_to_secid,
 	.release_secctx =		selinux_release_secctx,
+	.inode_notifysecctx =		selinux_inode_notifysecctx,
+	.inode_setsecctx =		selinux_inode_setsecctx,
+	.inode_getsecctx =		selinux_inode_getsecctx,
 
 	.unix_stream_connect =		selinux_socket_unix_stream_connect,
 	.unix_may_send =		selinux_socket_unix_may_send,
-- 
1.5.5.1

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

* [PATCH 03/14] Security: Add hook to calculate context based on a negative dentry.
       [not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
  2008-09-29 17:06   ` [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information David P. Quigley
@ 2008-09-29 17:06   ` David P. Quigley
  2008-09-30 20:15     ` Serge E. Hallyn
  2008-09-29 17:06   ` [PATCH 04/14] Security: Add Hook to test if the particular xattr is part of a MAC model David P. Quigley
                     ` (6 subsequent siblings)
  8 siblings, 1 reply; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
  To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
	casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
	matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
	trond.myklebust-41N18TsMXrtuMpJDpNschA,
	bfields-uC3wQj2KruNg9hUCZPvPmw
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	linux-security-module-u79uwXL29TY76Z2rM5mHXA,
	selinux-+05T5uksL2qpZYMLLGbcSA,
	labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
	Matthew N. Dodd

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-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
 include/linux/security.h |   14 ++++++++++++++
 security/security.c      |    7 +++++++
 security/selinux/hooks.c |   36 ++++++++++++++++++++++++++++++++++++
 3 files changed, 57 insertions(+), 0 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index 8b5b041..42b9128 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1379,6 +1379,9 @@ 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,
+				     void **ctx, u32 *ctxlen);
+
 
 	int (*inode_alloc_security) (struct inode *inode);
 	void (*inode_free_security) (struct inode *inode);
@@ -1651,6 +1654,8 @@ 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,
+				   void **ctx, u32 *ctxlen);
 
 int security_inode_alloc(struct inode *inode);
 void security_inode_free(struct inode *inode);
@@ -1994,6 +1999,15 @@ 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,
+						 void **ctx,
+						 u32 *ctxlen)
+{
+	return -EOPNOTSUPP;
+}
+
+
 static inline int security_inode_init_security(struct inode *inode,
 						struct inode *dir,
 						char **name,
diff --git a/security/security.c b/security/security.c
index d0fd42a..b22a110 100644
--- a/security/security.c
+++ b/security/security.c
@@ -349,6 +349,13 @@ void security_inode_free(struct inode *inode)
 	security_ops->inode_free_security(inode);
 }
 
+int security_dentry_init_security (struct dentry *dentry, int mode,
+				   void **ctx, u32 *ctxlen)
+{
+	return security_ops->dentry_init_security (dentry, mode, ctx, ctxlen);
+}
+EXPORT_SYMBOL(security_dentry_init_security);
+
 int security_inode_init_security(struct inode *inode, struct inode *dir,
 				  char **name, void **value, size_t *len)
 {
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b07871b..680db1d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2504,6 +2504,41 @@ static void selinux_inode_free_security(struct inode *inode)
 	inode_free_security(inode);
 }
 
+/*
+ * For now, we need a way to compute a SID for
+ * a dentry as the inode is not yet available
+ * (and under NFSv4 has no label backed by an EA anyway.
+ */
+static int selinux_dentry_init_security(struct dentry *dentry, int mode, void **ctx, u32 *ctxlen)
+{
+	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 = current->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),
+					     &newsid);
+		if (rc) {
+			printk(KERN_WARNING "%s:  "
+			       "security_transition_sid failed, rc=%d\n",
+			       __FUNCTION__, -rc);
+			return rc;
+		}
+	}
+
+	return security_sid_to_context(newsid, (char **)ctx, ctxlen);
+}
+
 static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
 				       char **name, void **value,
 				       size_t *len)
@@ -5413,6 +5448,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.5.5.1

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

* [PATCH 04/14] Security: Add Hook to test if the particular xattr is part of a MAC model.
       [not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
  2008-09-29 17:06   ` [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information David P. Quigley
  2008-09-29 17:06   ` [PATCH 03/14] Security: Add hook to calculate context based on a negative dentry David P. Quigley
@ 2008-09-29 17:06   ` David P. Quigley
  2008-09-29 17:06   ` [PATCH 07/14] NFSv4: Add label recommended attribute and NFSv4 flags David P. Quigley
                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
  To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
	casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
	matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
	trond.myklebust-41N18TsMXrtuMpJDpNschA,
	bfields-uC3wQj2KruNg9hUCZPvPmw
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	linux-security-module-u79uwXL29TY76Z2rM5mHXA,
	selinux-+05T5uksL2qpZYMLLGbcSA,
	labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
	Matthew N. Dodd

There are areas in the Labeled NFS code where where we need to test if the
attribute being requested exhibits the semantics of a MAC model. 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: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
 include/linux/security.h   |   11 +++++++++++
 security/security.c        |    6 ++++++
 security/selinux/hooks.c   |    6 ++++++
 security/smack/smack_lsm.c |   10 ++++++++++
 4 files changed, 33 insertions(+), 0 deletions(-)

diff --git a/include/linux/security.h b/include/linux/security.h
index 42b9128..3031e6c 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1244,6 +1244,10 @@ 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.
+ * 	@name full extended attribute name to check against LSM as a MAC label.
+ *
  * @secid_to_secctx:
  *	Convert secid to security context.
  *	@secid contains the security ID.
@@ -1508,6 +1512,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);
@@ -1762,6 +1767,7 @@ 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_netlink_recv(struct sk_buff *skb, int cap);
+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);
@@ -2494,6 +2500,11 @@ static inline void securityfs_remove(struct dentry *dentry)
 {
 }
 
+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/security.c b/security/security.c
index b22a110..1955094 100644
--- a/security/security.c
+++ b/security/security.c
@@ -858,6 +858,12 @@ int security_netlink_recv(struct sk_buff *skb, int cap)
 }
 EXPORT_SYMBOL(security_netlink_recv);
 
+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 680db1d..248fa5c 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5305,6 +5305,11 @@ static int selinux_setprocattr(struct task_struct *p,
 	return size;
 }
 
+static int selinux_ismaclabel(const char *name)
+{
+	return (strcmp(name,XATTR_NAME_SELINUX) == 0);
+}
+
 static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
 {
 	return security_sid_to_context(secid, secdata, seclen);
@@ -5546,6 +5551,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 87d7541..46e9888 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2526,6 +2526,15 @@ 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_NAME_SMACK) == 0);
+}
+
+/*
  * smack_secid_to_secctx - return the smack label for a secid
  * @secid: incoming integer
  * @secdata: destination
@@ -2703,6 +2712,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.5.5.1

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

* [PATCH 05/14] SELinux: Add new labeling type native labels
  2008-09-29 17:06 [RFC v3] Security Label Support for NFSv4 David P. Quigley
  2008-09-29 17:06 ` [PATCH 01/14] VFS: Factor out part of vfs_setxattr so it can be called from the SELinux hook for inode_setsecctx David P. Quigley
@ 2008-09-29 17:06 ` David P. Quigley
  2008-09-29 17:06 ` [PATCH 06/14] KConfig: Add KConfig entries for Labeled NFS David P. Quigley
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
  To: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields
  Cc: linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs, David P. Quigley, Matthew N. Dodd

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: David P. Quigley <dpquigl@tycho.nsa.gov>
---
 security/selinux/hooks.c            |   74 +++++++++++++++++++++++++++-------
 security/selinux/include/security.h |    4 ++
 security/selinux/ss/policydb.c      |    5 ++-
 3 files changed, 66 insertions(+), 17 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 248fa5c..78e79d3 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -88,7 +88,7 @@
 #define XATTR_SELINUX_SUFFIX "selinux"
 #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
 
-#define NUM_SEL_MNT_OPTS 4
+#define NUM_SEL_MNT_OPTS 5
 
 extern unsigned int policydb_loaded_version;
 extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
@@ -300,13 +300,14 @@ extern int ss_initialized;
 
 /* The file system's label must be initialized prior to use. */
 
-static char *labeling_behaviors[6] = {
+static char *labeling_behaviors[7] = {
 	"uses xattr",
 	"uses transition SIDs",
 	"uses task SIDs",
 	"uses genfs_contexts",
 	"not configured for labeling",
 	"uses mountpoint labeling",
+	"uses native labels",
 };
 
 static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
@@ -322,6 +323,7 @@ enum {
 	Opt_fscontext = 2,
 	Opt_defcontext = 3,
 	Opt_rootcontext = 4,
+	Opt_native_labels = 5,
 };
 
 static match_table_t tokens = {
@@ -329,6 +331,7 @@ static match_table_t tokens = {
 	{Opt_fscontext, FSCONTEXT_STR "%s"},
 	{Opt_defcontext, DEFCONTEXT_STR "%s"},
 	{Opt_rootcontext, ROOTCONTEXT_STR "%s"},
+	{Opt_native_labels, NATIVELABELS_STR},
 	{Opt_error, NULL},
 };
 
@@ -516,6 +519,10 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
 		opts->mnt_opts[i] = context;
 		opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
 	}
+	if (sbsec->flags == NATIVE_LABELS_MNT) {
+		opts->mnt_opts[i] = NULL;
+		opts->mnt_opts_flags[i++] = NATIVE_LABELS_MNT;
+	}
 
 	BUG_ON(i != opts->num_mnt_opts);
 
@@ -604,12 +611,16 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 	 */
 	for (i = 0; i < num_opts; i++) {
 		u32 sid;
+		if (flags[i] == NATIVE_LABELS_MNT) {
+			sbsec->flags | = NATIVE_LABELS_MNT;
+			continue;
+		}
 		rc = security_context_to_sid(mount_options[i],
-					     strlen(mount_options[i]), &sid);
+				strlen(mount_options[i]), &sid);
 		if (rc) {
 			printk(KERN_WARNING "SELinux: security_context_to_sid"
-			       "(%s) failed for (dev %s, type %s) errno=%d\n",
-			       mount_options[i], sb->s_id, name, rc);
+					"(%s) failed for (dev %s, type %s) errno=%d\n",
+					mount_options[i], sb->s_id, name, rc);
 			goto out;
 		}
 		switch (flags[i]) {
@@ -668,14 +679,15 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 	if (strcmp(sb->s_type->name, "proc") == 0)
 		sbsec->proc = 1;
 
-	/* Determine the labeling behavior to use for this filesystem type. */
-	rc = security_fs_use(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(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) {
 
@@ -691,6 +703,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.
 	 */
+	/* NATIVE_LABELS can be overridden by 'context=' mounts, below. */
+	if (sbsec->flags & NATIVE_LABELS_MNT) {
+		sbsec->behavior = SECURITY_FS_USE_NATIVE;
+	}
+
 	if (context_sid) {
 		if (!fscontext_sid) {
 			rc = may_context_mount_sb_relabel(context_sid, sbsec, tsec);
@@ -707,6 +724,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 
 		sbsec->mntpoint_sid = context_sid;
 		sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
+		sbsec->flags &= ~NATIVE_LABELS_MNT; /* Exclusive */
 	}
 
 	if (rootcontext_sid) {
@@ -719,7 +737,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");
@@ -816,6 +835,7 @@ static int selinux_parse_opts_str(char *options,
 	char *p;
 	char *context = NULL, *defcontext = NULL;
 	char *fscontext = NULL, *rootcontext = NULL;
+	int native_labels = 0;
 	int rc, num_mnt_opts = 0;
 
 	opts->num_mnt_opts = 0;
@@ -883,9 +903,15 @@ static int selinux_parse_opts_str(char *options,
 			}
 			break;
 
+		case Opt_native_labels:
+			printk("%s() got Opt_native_labels\n", __func__);
+			native_labels = 1;
+			break;
+
+
 		default:
 			rc = -EINVAL;
-			printk(KERN_WARNING "SELinux:  unknown mount option\n");
+			printk(KERN_WARNING "SELinux: unknown mount option \"%s\"\n", p);
 			goto out_err;
 
 		}
@@ -918,6 +944,10 @@ static int selinux_parse_opts_str(char *options,
 		opts->mnt_opts[num_mnt_opts] = defcontext;
 		opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
 	}
+	if (native_labels) {
+		opts->mnt_opts[num_mnt_opts] = NULL;
+		opts->mnt_opts_flags[num_mnt_opts++] = NATIVE_LABELS_MNT;
+	}
 
 	opts->num_mnt_opts = num_mnt_opts;
 	return 0;
@@ -963,7 +993,12 @@ void selinux_write_opts(struct seq_file *m, struct security_mnt_opts *opts)
 	char *prefix;
 
 	for (i = 0; i < opts->num_mnt_opts; i++) {
-		char *has_comma = strchr(opts->mnt_opts[i], ',');
+		char *has_comma;
+
+		if (opts->mnt_opts[i])
+			has_comma = strchr(opts->mnt_opts[i], ',');
+		else
+			has_comma = NULL;
 
 		switch (opts->mnt_opts_flags[i]) {
 		case CONTEXT_MNT:
@@ -978,6 +1013,10 @@ void selinux_write_opts(struct seq_file *m, struct security_mnt_opts *opts)
 		case DEFCONTEXT_MNT:
 			prefix = DEFCONTEXT_STR;
 			break;
+		case NATIVE_LABELS_MNT:
+			seq_putc(m, ',');
+			seq_puts(m, NATIVELABELS_STR);
+			continue;
 		default:
 			BUG();
 		};
@@ -1185,6 +1224,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;
@@ -2360,7 +2401,8 @@ static inline int selinux_option(char *option, int len)
 	return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
 		match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
 		match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
-		match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len));
+		match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) ||
+		match_prefix(NATIVELABELS_STR, sizeof(NATIVELABELS_STR)-1, option, len));
 }
 
 static inline void take_option(char **to, char *from, int *first, int len)
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 7c54300..effe060 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -40,11 +40,13 @@
 #define FSCONTEXT_MNT	0x02
 #define ROOTCONTEXT_MNT	0x04
 #define DEFCONTEXT_MNT	0x08
+#define	NATIVE_LABELS_MNT	0x10
 
 #define CONTEXT_STR	"context="
 #define FSCONTEXT_STR	"fscontext="
 #define ROOTCONTEXT_STR	"rootcontext="
 #define DEFCONTEXT_STR	"defcontext="
+#define NATIVELABELS_STR "native_labels"
 
 struct netlbl_lsm_secattr;
 
@@ -134,6 +136,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 2391761..4740a5a 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -1764,7 +1764,10 @@ int policydb_read(struct policydb *p, void *fp)
 				if (rc < 0)
 					goto bad;
 				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 bad;
+				if (c->v.behavior > SECURITY_FS_USE_MAX)
 					goto bad;
 				len = le32_to_cpu(buf[1]);
 				c->u.name = kmalloc(len + 1, GFP_KERNEL);
-- 
1.5.5.1


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

* [PATCH 06/14] KConfig: Add KConfig entries for Labeled NFS
  2008-09-29 17:06 [RFC v3] Security Label Support for NFSv4 David P. Quigley
  2008-09-29 17:06 ` [PATCH 01/14] VFS: Factor out part of vfs_setxattr so it can be called from the SELinux hook for inode_setsecctx David P. Quigley
  2008-09-29 17:06 ` [PATCH 05/14] SELinux: Add new labeling type native labels David P. Quigley
@ 2008-09-29 17:06 ` David P. Quigley
  2008-09-30 20:40   ` Serge E. Hallyn
  2008-09-29 17:06 ` [PATCH 10/14] NFSv4: Introduce new label structure David P. Quigley
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
  To: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields
  Cc: linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs, David P. Quigley, Matthew N. Dodd

This patch adds two entries into the fs/KConfig file. The first entry
NFS_V4_SECURITY_LABEL enables security label support for the NFSv4 client while
the second entry NFSD_V4_SECURITY_LABEL enables security labeling support on
the server side.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
---
 fs/Kconfig |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/fs/Kconfig b/fs/Kconfig
index abccb5d..47ffb42 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1633,6 +1633,7 @@ config NFS_V4
 
 	  If unsure, say N.
 
+
 config ROOT_NFS
 	bool "Root file system on NFS"
 	depends on NFS_FS=y && IP_PNP
@@ -1644,6 +1645,15 @@ config ROOT_NFS
 
 	  Most people say N here.
 
+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 label attribute support for NFS version 4.
+
+
+	  If unsure, say N.
+
 config NFSD
 	tristate "NFS server support"
 	depends on INET
@@ -1725,6 +1735,13 @@ 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
+	  If you would like to include support for label file attributes
+	  over NFSv4, say Y here.
+
 config LOCKD
 	tristate
 
-- 
1.5.5.1


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

* [PATCH 07/14] NFSv4: Add label recommended attribute and NFSv4 flags
       [not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
                     ` (2 preceding siblings ...)
  2008-09-29 17:06   ` [PATCH 04/14] Security: Add Hook to test if the particular xattr is part of a MAC model David P. Quigley
@ 2008-09-29 17:06   ` David P. Quigley
  2008-09-29 17:06   ` [PATCH 08/14] NFS: Add security_label text mount option and handling code to NFS David P. Quigley
                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
  To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
	casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
	matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
	trond.myklebust-41N18TsMXrtuMpJDpNschA,
	bfields-uC3wQj2KruNg9hUCZPvPmw
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	linux-security-module-u79uwXL29TY76Z2rM5mHXA,
	selinux-+05T5uksL2qpZYMLLGbcSA,
	labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
	Matthew N. Dodd

This patch adds a new recommended attribute named label into the NFSv4 file
attribute structure. It also 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: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
 include/linux/nfs4.h        |    2 ++
 include/linux/nfs_fs_sb.h   |    2 +-
 include/linux/nfs_xdr.h     |    4 ++++
 include/linux/nfsd/export.h |    5 +++--
 include/linux/nfsd/nfsd.h   |    7 ++++---
 5 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index ea03667..144eacf 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -21,6 +21,7 @@
 #define NFS4_FHSIZE		128
 #define NFS4_MAXPATHLEN		PATH_MAX
 #define NFS4_MAXNAMLEN		NAME_MAX
+#define NFS4_MAXLABELLEN	4096
 
 #define NFS4_ACCESS_READ        0x0001
 #define NFS4_ACCESS_LOOKUP      0x0002
@@ -345,6 +346,7 @@ enum lock_type4 {
 #define FATTR4_WORD1_TIME_MODIFY        (1UL << 21)
 #define FATTR4_WORD1_TIME_MODIFY_SET    (1UL << 22)
 #define FATTR4_WORD1_MOUNTED_ON_FILEID  (1UL << 23)
+#define FATTR4_WORD1_SECURITY_LABEL     (1UL << 31)
 
 #define NFSPROC4_NULL 0
 #define NFSPROC4_COMPOUND 1
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index c9beacd..9475bb0 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -135,5 +135,5 @@ struct nfs_server {
 #define NFS_CAP_SYMLINKS	(1U << 2)
 #define NFS_CAP_ACLS		(1U << 3)
 #define NFS_CAP_ATOMIC_OPEN	(1U << 4)
-
+#define NFS_CAP_SECURITY_LABEL (1U << 5)
 #endif
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 8c77c11..0d77568 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -56,6 +56,10 @@ struct nfs_fattr {
 	__u64			change_attr;	/* NFSv4 change attribute */
 	__u64			pre_change_attr;/* pre-op NFSv4 change attribute */
 	unsigned long		time_start;
+#ifdef CONFIG_SECURITY
+	void			*label;
+	__u32			 label_len;
+#endif
 };
 
 #define NFS_ATTR_WCC		0x0001		/* pre-op WCC data    */
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
index 5431512..bb831fc 100644
--- a/include/linux/nfsd/export.h
+++ b/include/linux/nfsd/export.h
@@ -32,7 +32,8 @@
 #define NFSEXP_ALLSQUASH	0x0008
 #define NFSEXP_ASYNC		0x0010
 #define NFSEXP_GATHERED_WRITES	0x0020
-/* 40 80 100 currently unused */
+#define NFSEXP_SECURITY_LABEL	0x0040  /* Support security label fattr4 */
+/* 80 100 currently unused */
 #define NFSEXP_NOHIDE		0x0200
 #define NFSEXP_NOSUBTREECHECK	0x0400
 #define	NFSEXP_NOAUTHNLM	0x0800		/* Don't authenticate NLM requests - just trust */
@@ -40,7 +41,7 @@
 #define NFSEXP_FSID		0x2000
 #define	NFSEXP_CROSSMOUNT	0x4000
 #define	NFSEXP_NOACL		0x8000	/* reserved for possible ACL related use */
-#define NFSEXP_ALLFLAGS		0xFE3F
+#define NFSEXP_ALLFLAGS		0xFE7F
 
 /* The flags that may vary depending on security flavor: */
 #define NFSEXP_SECINFO_FLAGS	(NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 108f47e..f329b96 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -317,8 +317,8 @@ extern struct timeval	nfssvc_boot;
  | FATTR4_WORD1_OWNER	        | FATTR4_WORD1_OWNER_GROUP  | FATTR4_WORD1_RAWDEV           \
  | FATTR4_WORD1_SPACE_AVAIL     | FATTR4_WORD1_SPACE_FREE   | FATTR4_WORD1_SPACE_TOTAL      \
  | FATTR4_WORD1_SPACE_USED      | FATTR4_WORD1_TIME_ACCESS  | FATTR4_WORD1_TIME_ACCESS_SET  \
- | FATTR4_WORD1_TIME_DELTA   | FATTR4_WORD1_TIME_METADATA    \
- | FATTR4_WORD1_TIME_MODIFY     | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID)
+ | FATTR4_WORD1_TIME_DELTA   	| FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY     \
+ | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID | FATTR4_WORD1_SECURITY_LABEL)
 
 /* These will return ERR_INVAL if specified in GETATTR or READDIR. */
 #define NFSD_WRITEONLY_ATTRS_WORD1							    \
@@ -329,7 +329,8 @@ extern struct timeval	nfssvc_boot;
 (FATTR4_WORD0_SIZE              | FATTR4_WORD0_ACL                                         )
 #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)
+ | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY_SET \
+ | FATTR4_WORD1_SECURITY_LABEL)
 
 #endif /* CONFIG_NFSD_V4 */
 
-- 
1.5.5.1

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

* [PATCH 08/14] NFS: Add security_label text mount option and handling code to NFS
       [not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
                     ` (3 preceding siblings ...)
  2008-09-29 17:06   ` [PATCH 07/14] NFSv4: Add label recommended attribute and NFSv4 flags David P. Quigley
@ 2008-09-29 17:06   ` David P. Quigley
  2008-09-29 17:06   ` [PATCH 09/14] NFS: Introduce lifecycle management for label attribute David P. Quigley
                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
  To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
	casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
	matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
	trond.myklebust-41N18TsMXrtuMpJDpNschA,
	bfields-uC3wQj2KruNg9hUCZPvPmw
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	linux-security-module-u79uwXL29TY76Z2rM5mHXA,
	selinux-+05T5uksL2qpZYMLLGbcSA,
	labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
	Matthew N. Dodd

This patch adds two new text options to to the NFS mount options to specify
security labeling. It also sends certain LSM related mount options into the
module for handling.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
 fs/nfs/super.c             |    9 +++++++++
 include/linux/nfs4_mount.h |    6 +++++-
 security/selinux/hooks.c   |    2 +-
 3 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 9abcd2b..256ce27 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -75,6 +75,7 @@ enum {
 	Opt_acl, Opt_noacl,
 	Opt_rdirplus, Opt_nordirplus,
 	Opt_sharecache, Opt_nosharecache,
+	Opt_security_label, Opt_nosecurity_label,
 
 	/* Mount options that take integer arguments */
 	Opt_port,
@@ -128,6 +129,8 @@ static match_table_t nfs_mount_option_tokens = {
 	{ Opt_nordirplus, "nordirplus" },
 	{ Opt_sharecache, "sharecache" },
 	{ Opt_nosharecache, "nosharecache" },
+	{ Opt_security_label, "security_label" },
+	{ Opt_nosecurity_label, "nosecurity_label" },
 
 	{ Opt_port, "port=%u" },
 	{ Opt_rsize, "rsize=%u" },
@@ -1033,6 +1036,12 @@ static int nfs_parse_mount_options(char *raw,
 		case Opt_nosharecache:
 			mnt->flags |= NFS_MOUNT_UNSHARED;
 			break;
+		case Opt_nosecurity_label:
+			mnt->flags &= ~NFS4_MOUNT_SECURITY_LABEL;
+			break;
+		case Opt_security_label:
+			mnt->flags |= NFS4_MOUNT_SECURITY_LABEL;
+			break;
 
 		/*
 		 * options that take numeric values
diff --git a/include/linux/nfs4_mount.h b/include/linux/nfs4_mount.h
index a0dcf66..e65067b 100644
--- a/include/linux/nfs4_mount.h
+++ b/include/linux/nfs4_mount.h
@@ -17,6 +17,7 @@
  * but here they are anyway.
  */
 #define NFS4_MOUNT_VERSION	1
+#define NFS4_MAX_CONTEXT_LEN	4096
 
 struct nfs_string {
 	unsigned int len;
@@ -53,6 +54,8 @@ struct nfs4_mount_data {
 	/* Pseudo-flavours to use for authentication. See RFC2623 */
 	int auth_flavourlen;			/* 1 */
 	int __user *auth_flavours;		/* 1 */
+
+	char context[NFS4_MAX_CONTEXT_LEN + 1];  /* 2 */
 };
 
 /* bits in the flags field */
@@ -66,6 +69,7 @@ struct nfs4_mount_data {
 #define NFS4_MOUNT_NOAC		0x0020	/* 1 */
 #define NFS4_MOUNT_STRICTLOCK	0x1000	/* 1 */
 #define NFS4_MOUNT_UNSHARED	0x8000	/* 1 */
-#define NFS4_MOUNT_FLAGMASK	0x9033
+#define NFS4_MOUNT_SECURITY_LABEL 0x10000 /* 2 */
+#define NFS4_MOUNT_FLAGMASK	0x19033
 
 #endif
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 78e79d3..6919766 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -612,7 +612,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 	for (i = 0; i < num_opts; i++) {
 		u32 sid;
 		if (flags[i] == NATIVE_LABELS_MNT) {
-			sbsec->flags | = NATIVE_LABELS_MNT;
+			sbsec->flags |= NATIVE_LABELS_MNT;
 			continue;
 		}
 		rc = security_context_to_sid(mount_options[i],
-- 
1.5.5.1

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

* [PATCH 09/14] NFS: Introduce lifecycle management for label attribute.
       [not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
                     ` (4 preceding siblings ...)
  2008-09-29 17:06   ` [PATCH 08/14] NFS: Add security_label text mount option and handling code to NFS David P. Quigley
@ 2008-09-29 17:06   ` David P. Quigley
  2008-09-29 17:06   ` [PATCH 12/14] NFS: Client implementation of Labeled-NFS David P. Quigley
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
  To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
	casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
	matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
	trond.myklebust-41N18TsMXrtuMpJDpNschA,
	bfields-uC3wQj2KruNg9hUCZPvPmw
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	linux-security-module-u79uwXL29TY76Z2rM5mHXA,
	selinux-+05T5uksL2qpZYMLLGbcSA,
	labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
	Matthew N. Dodd

Two fields have been added to the nfs_fattr structure to carry the security
label and its length. This has raised the need to provide lifecycle management
for these values. This patch introduces two macros nfs_fattr_alloc and
nfs_fattr_fini which are used to allocate and destroy these fields inside the
nfs_fattr structure. These macros do not modify any other components of the
structure so nfs_fattr_init still has to be used on these structures. In the
event that CONFIG_SECURITY is not set these calls should compile away.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
 fs/nfs/client.c        |   18 +++++++++-
 fs/nfs/dir.c           |   24 +++++++++++++
 fs/nfs/getroot.c       |   35 ++++++++++++++++++-
 fs/nfs/inode.c         |   16 +++++++++
 fs/nfs/namespace.c     |    3 ++
 fs/nfs/nfs3proc.c      |    7 ++++
 fs/nfs/nfs4proc.c      |   88 ++++++++++++++++++++++++++++++++++++++++++++++-
 fs/nfs/proc.c          |   12 ++++++-
 fs/nfs/super.c         |    4 ++
 include/linux/nfs_fs.h |   46 +++++++++++++++++++++++++
 10 files changed, 248 insertions(+), 5 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 5ee23e7..756d554 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -902,6 +902,8 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data,
 	struct nfs_fattr fattr;
 	int error;
 
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+
 	server = nfs_alloc_server();
 	if (!server)
 		return ERR_PTR(-ENOMEM);
@@ -952,10 +954,12 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data,
 	spin_unlock(&nfs_client_lock);
 
 	server->mount_time = jiffies;
+	nfs_fattr_fini(&fattr);
 	return server;
 
 error:
 	nfs_free_server(server);
+	nfs_fattr_fini(&fattr);
 	return ERR_PTR(error);
 }
 
@@ -1073,7 +1077,7 @@ static int nfs4_init_server(struct nfs_server *server,
 		goto error;
 
 	/* Initialise the client representation from the mount data */
-	server->flags = data->flags & NFS_MOUNT_FLAGMASK;
+	server->flags = data->flags & NFS4_MOUNT_FLAGMASK;
 	server->caps |= NFS_CAP_ATOMIC_OPEN;
 
 	if (data->rsize)
@@ -1109,6 +1113,8 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
 
 	dprintk("--> nfs4_create_server()\n");
 
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+
 	server = nfs_alloc_server();
 	if (!server)
 		return ERR_PTR(-ENOMEM);
@@ -1149,11 +1155,13 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
 	spin_unlock(&nfs_client_lock);
 
 	server->mount_time = jiffies;
+	nfs_fattr_fini(&fattr);
 	dprintk("<-- nfs4_create_server() = %p\n", server);
 	return server;
 
 error:
 	nfs_free_server(server);
+	nfs_fattr_fini(&fattr);
 	dprintk("<-- nfs4_create_server() = error %d\n", error);
 	return ERR_PTR(error);
 }
@@ -1171,6 +1179,8 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
 
 	dprintk("--> nfs4_create_referral_server()\n");
 
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+
 	server = nfs_alloc_server();
 	if (!server)
 		return ERR_PTR(-ENOMEM);
@@ -1227,10 +1237,12 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
 	server->mount_time = jiffies;
 
 	dprintk("<-- nfs_create_referral_server() = %p\n", server);
+	nfs_fattr_fini(&fattr);
 	return server;
 
 error:
 	nfs_free_server(server);
+	nfs_fattr_fini(&fattr);
 	dprintk("<-- nfs4_create_referral_server() = error %d\n", error);
 	return ERR_PTR(error);
 }
@@ -1252,6 +1264,8 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source,
 		(unsigned long long) fattr->fsid.major,
 		(unsigned long long) fattr->fsid.minor);
 
+	memset(&fattr_fsinfo, 0, sizeof(struct nfs_fattr));
+
 	server = nfs_alloc_server();
 	if (!server)
 		return ERR_PTR(-ENOMEM);
@@ -1294,11 +1308,13 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source,
 
 	server->mount_time = jiffies;
 
+	nfs_fattr_fini(&fattr_fsinfo);
 	dprintk("<-- nfs_clone_server() = %p\n", server);
 	return server;
 
 out_free_server:
 	nfs_free_server(server);
+	nfs_fattr_fini(&fattr_fsinfo);
 	dprintk("<-- nfs_clone_server() = error %d\n", error);
 	return ERR_PTR(error);
 }
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 74f92b7..db43b69 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -551,6 +551,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 	my_entry.eof = 0;
 	my_entry.fh = &fh;
 	my_entry.fattr = &fattr;
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
 	nfs_fattr_init(&fattr);
 	desc->entry = &my_entry;
 
@@ -588,6 +589,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 			res = 0;
 			break;
 		}
+		nfs_fattr_fini(&fattr);
 	}
 out:
 	nfs_unblock_sillyrename(dentry);
@@ -773,6 +775,8 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
 	struct nfs_fh fhandle;
 	struct nfs_fattr fattr;
 
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+
 	parent = dget_parent(dentry);
 	dir = parent->d_inode;
 	nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
@@ -801,6 +805,11 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
 	if (NFS_STALE(inode))
 		goto out_bad;
 
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL))
+		nfs_fattr_alloc(&fattr, GFP_NOWAIT);
+#endif
+
 	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
 	if (error)
 		goto out_bad;
@@ -812,6 +821,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
 	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
  out_valid:
 	dput(parent);
+	nfs_fattr_fini(&fattr);
 	dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is valid\n",
 			__func__, dentry->d_parent->d_name.name,
 			dentry->d_name.name);
@@ -830,6 +840,7 @@ out_zap_parent:
 	}
 	d_drop(dentry);
 	dput(parent);
+	nfs_fattr_fini(&fattr);
 	dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n",
 			__func__, dentry->d_parent->d_name.name,
 			dentry->d_name.name);
@@ -906,6 +917,8 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 	nfs_inc_stats(dir, NFSIOS_VFSLOOKUP);
 
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+
 	res = ERR_PTR(-ENAMETOOLONG);
 	if (dentry->d_name.len > NFS_SERVER(dir)->namelen)
 		goto out;
@@ -923,6 +936,11 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
 		goto out;
 	}
 
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL))
+		nfs_fattr_alloc(&fattr, GFP_NOWAIT);
+#endif
+
 	parent = dentry->d_parent;
 	/* Protect against concurrent sillydeletes */
 	nfs_block_sillyrename(parent);
@@ -949,6 +967,8 @@ no_entry:
 out_unblock_sillyrename:
 	nfs_unblock_sillyrename(parent);
 out:
+	/* Label will give 'unused' warning on 'no_entry' case. */
+	nfs_fattr_fini(&fattr);
 	return res;
 }
 
@@ -1214,6 +1234,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
 	dfprintk(VFS, "NFS: create(%s/%ld), %s\n",
 			dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
 
+	memset(&attr, 0, sizeof(struct iattr));
 	attr.ia_mode = mode;
 	attr.ia_valid = ATTR_MODE;
 
@@ -1244,6 +1265,7 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
 	if (!new_valid_dev(rdev))
 		return -EINVAL;
 
+	memset(&attr, 0, sizeof(struct iattr));
 	attr.ia_mode = mode;
 	attr.ia_valid = ATTR_MODE;
 
@@ -1267,6 +1289,7 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 	dfprintk(VFS, "NFS: mkdir(%s/%ld), %s\n",
 			dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
 
+	memset(&attr, 0, sizeof(struct iattr));
 	attr.ia_valid = ATTR_MODE;
 	attr.ia_mode = mode | S_IFDIR;
 
@@ -1476,6 +1499,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
 	if (pathlen > PAGE_SIZE)
 		return -ENAMETOOLONG;
 
+	memset(&attr, 0, sizeof(struct iattr));
 	attr.ia_mode = S_IFLNK | S_IRWXUGO;
 	attr.ia_valid = ATTR_MODE;
 
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index fae9719..bc23077 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -31,7 +31,6 @@
 #include <linux/vfs.h>
 #include <linux/namei.h>
 #include <linux/mnt_namespace.h>
-#include <linux/security.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -84,6 +83,8 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
 	struct inode *inode;
 	int error;
 
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+
 	/* get the actual root for this mount */
 	fsinfo.fattr = &fattr;
 
@@ -119,6 +120,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
 	if (!mntroot->d_op)
 		mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops;
 
+	nfs_fattr_fini(&fattr);
 	return mntroot;
 }
 
@@ -143,6 +145,12 @@ int nfs4_path_walk(struct nfs_server *server,
 
 	dprintk("--> nfs4_path_walk(,,%s)\n", path);
 
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	/* Unconditional, no server caps yet. */
+	nfs_fattr_alloc(&fattr, GFP_KERNEL);
+#endif
+
 	fsinfo.fattr = &fattr;
 	nfs_fattr_init(&fattr);
 
@@ -154,12 +162,14 @@ int nfs4_path_walk(struct nfs_server *server,
 	ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
 	if (ret < 0) {
 		dprintk("nfs4_get_root: getroot error = %d\n", -ret);
+		nfs_fattr_fini(&fattr);
 		return ret;
 	}
 
 	if (fattr.type != NFDIR) {
 		printk(KERN_ERR "nfs4_get_root:"
 		       " getroot encountered non-directory\n");
+		nfs_fattr_fini(&fattr);
 		return -ENOTDIR;
 	}
 
@@ -167,6 +177,7 @@ int nfs4_path_walk(struct nfs_server *server,
 	if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) {
 		printk(KERN_ERR "nfs4_get_root:"
 		       " getroot obtained referral\n");
+		nfs_fattr_fini(&fattr);
 		return -EREMOTE;
 	}
 
@@ -199,6 +210,7 @@ eat_dot_dir:
 	    ) {
 		printk(KERN_ERR "nfs4_get_root:"
 		       " Mount path contains reference to \"..\"\n");
+		nfs_fattr_fini(&fattr);
 		return -EINVAL;
 	}
 
@@ -207,16 +219,25 @@ eat_dot_dir:
 
 	dprintk("LookupFH: %*.*s [%s]\n", name.len, name.len, name.name, path);
 
+	nfs_fattr_fini(&fattr);
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (server->caps & NFS_CAP_SECURITY_LABEL)
+		nfs_fattr_alloc(&fattr, GFP_KERNEL);
+#endif
+
 	ret = server->nfs_client->rpc_ops->lookupfh(server, &lastfh, &name,
 						    mntfh, &fattr);
 	if (ret < 0) {
 		dprintk("nfs4_get_root: getroot error = %d\n", -ret);
+		nfs_fattr_fini(&fattr);
 		return ret;
 	}
 
 	if (fattr.type != NFDIR) {
 		printk(KERN_ERR "nfs4_get_root:"
 		       " lookupfh encountered non-directory\n");
+		nfs_fattr_fini(&fattr);
 		return -ENOTDIR;
 	}
 
@@ -224,6 +245,7 @@ eat_dot_dir:
 	if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) {
 		printk(KERN_ERR "nfs4_get_root:"
 		       " lookupfh obtained referral\n");
+		nfs_fattr_fini(&fattr);
 		return -EREMOTE;
 	}
 
@@ -231,6 +253,7 @@ eat_dot_dir:
 
 path_walk_complete:
 	memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid));
+	nfs_fattr_fini(&fattr);
 	dprintk("<-- nfs4_path_walk() = 0\n");
 	return 0;
 }
@@ -256,19 +279,29 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
 		return ERR_PTR(error);
 	}
 
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (server->caps & NFS_CAP_SECURITY_LABEL)
+		nfs_fattr_alloc(&fattr, GFP_KERNEL);
+#endif
+
 	/* get the actual root for this mount */
 	error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr);
 	if (error < 0) {
+		nfs_fattr_fini(&fattr);
 		dprintk("nfs_get_root: getattr error = %d\n", -error);
 		return ERR_PTR(error);
 	}
 
 	inode = nfs_fhget(sb, mntfh, &fattr);
 	if (IS_ERR(inode)) {
+		nfs_fattr_fini(&fattr);
 		dprintk("nfs_get_root: get root inode failed\n");
 		return ERR_CAST(inode);
 	}
 
+	nfs_fattr_fini(&fattr);
+
 	error = nfs_superblock_set_dummy_root(sb, inode);
 	if (error != 0)
 		return ERR_PTR(error);
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 52daefa..40d7142 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -360,6 +360,12 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
 	if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
 		attr->ia_valid &= ~ATTR_MODE;
 
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
+		nfs_fattr_alloc(&fattr, GFP_KERNEL);
+#endif
+
 	if (attr->ia_valid & ATTR_SIZE) {
 		if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode))
 			attr->ia_valid &= ~ATTR_SIZE;
@@ -383,6 +389,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
 	error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr);
 	if (error == 0)
 		nfs_refresh_inode(inode, &fattr);
+	nfs_fattr_fini(&fattr);
 	return error;
 }
 
@@ -698,6 +705,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 		inode->i_sb->s_id, (long long)NFS_FILEID(inode));
 
 	nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
+	
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+	
 	if (is_bad_inode(inode))
  		goto out_nowait;
 	if (NFS_STALE(inode))
@@ -711,6 +721,11 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 	if (NFS_STALE(inode))
 		goto out;
 
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
+		nfs_fattr_alloc(&fattr, GFP_KERNEL);
+#endif
+
 	status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), &fattr);
 	if (status != 0) {
 		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
@@ -746,6 +761,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 	nfs_wake_up_inode(inode);
 
  out_nowait:
+	nfs_fattr_fini(&fattr);
 	return status;
 }
 
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 66df08d..a20b428 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -105,6 +105,8 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
 
 	dprintk("--> nfs_follow_mountpoint()\n");
 
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+
 	BUG_ON(IS_ROOT(dentry));
 	dprintk("%s: enter\n", __func__);
 	dput(nd->path.dentry);
@@ -142,6 +144,7 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
 	nd->path.dentry = dget(mnt->mnt_root);
 	schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
 out:
+	nfs_fattr_fini(&fattr);
 	dprintk("%s: done, returned %d\n", __func__, err);
 
 	dprintk("<-- nfs_follow_mountpoint() = %d\n", err);
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 1e750e4..c49a2aa 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -294,6 +294,9 @@ static int nfs3_do_create(struct inode *dir, struct dentry *dentry, struct nfs3_
 
 static void nfs3_free_createdata(struct nfs3_createdata *data)
 {
+
+	nfs_fattr_fini(data->res.fattr);
+	nfs_fattr_fini(data->res.dir_attr);
 	kfree(data);
 }
 
@@ -420,6 +423,7 @@ nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 		return 0;
 	res = task->tk_msg.rpc_resp;
 	nfs_post_op_update_inode(dir, &res->dir_attr);
+	nfs_fattr_fini(&res->dir_attr);
 	return 1;
 }
 
@@ -618,6 +622,9 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
 	dprintk("NFS call  readdir%s %d\n",
 			plus? "plus" : "", (unsigned int) cookie);
 
+
+	memset(&dir_attr, 0, sizeof(struct nfs_fattr));
+
 	nfs_fattr_init(&dir_attr);
 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
 
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index c910413..c4a4271 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -243,6 +243,8 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
 	p->o_res.seqid = p->o_arg.seqid;
 	p->c_res.seqid = p->c_arg.seqid;
 	p->o_res.server = p->o_arg.server;
+	memset(&p->f_attr, 0, sizeof(struct nfs_fattr));
+	memset(&p->dir_attr, 0, sizeof(struct nfs_fattr));
 	nfs_fattr_init(&p->f_attr);
 	nfs_fattr_init(&p->dir_attr);
 }
@@ -288,6 +290,13 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
 	p->c_arg.seqid = p->o_arg.seqid;
 	nfs4_init_opendata_res(p);
 	kref_init(&p->kref);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (server->caps & NFS_CAP_SECURITY_LABEL) {
+		nfs_fattr_alloc(&p->f_attr, GFP_KERNEL);
+		nfs_fattr_alloc(&p->dir_attr, GFP_KERNEL);
+	}
+#endif
+
 	return p;
 err_free:
 	kfree(p);
@@ -304,6 +313,8 @@ static void nfs4_opendata_free(struct kref *kref)
 	nfs_free_seqid(p->o_arg.seqid);
 	if (p->state != NULL)
 		nfs4_put_open_state(p->state);
+	nfs_fattr_fini(&p->f_attr);
+	nfs_fattr_fini(&p->dir_attr);
 	nfs4_put_state_owner(p->owner);
 	dput(p->dir);
 	path_put(&p->path);
@@ -1210,6 +1221,7 @@ static void nfs4_free_closedata(void *data)
 	nfs_free_seqid(calldata->arg.seqid);
 	nfs4_put_state_owner(sp);
 	path_put(&calldata->path);
+	nfs_fattr_fini(&calldata->fattr);
 	kfree(calldata);
 }
 
@@ -1317,7 +1329,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
 	};
 	int status = -ENOMEM;
 
-	calldata = kmalloc(sizeof(*calldata), GFP_KERNEL);
+	calldata = kzalloc(sizeof(*calldata), GFP_KERNEL);
 	if (calldata == NULL)
 		goto out;
 	calldata->inode = state->inode;
@@ -1335,6 +1347,10 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
 	calldata->path.mnt = mntget(path->mnt);
 	calldata->path.dentry = dget(path->dentry);
 
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (server->caps & NFS_CAP_SECURITY_LABEL)
+		nfs_fattr_alloc(&calldata->fattr, GFP_KERNEL);
+#endif
 	msg.rpc_argp = &calldata->arg,
 	msg.rpc_resp = &calldata->res,
 	task_setup_data.callback_data = calldata;
@@ -1347,6 +1363,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
 	rpc_put_task(task);
 	return status;
 out_free_calldata:
+	nfs_fattr_fini(&calldata->fattr);
 	kfree(calldata);
 out:
 	nfs4_put_open_state(state);
@@ -1762,6 +1779,8 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 	int mode = entry->mask;
 	int status;
 
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+
 	/*
 	 * Determine which access bits we want to ask for...
 	 */
@@ -1778,6 +1797,10 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 		if (mode & MAY_EXEC)
 			args.access |= NFS4_ACCESS_EXECUTE;
 	}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (server->caps & NFS_CAP_SECURITY_LABEL)
+		nfs_fattr_alloc(&fattr, GFP_KERNEL);
+#endif
 	nfs_fattr_init(&fattr);
 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
 	if (!status) {
@@ -1790,6 +1813,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 			entry->mask |= MAY_EXEC;
 		nfs_refresh_inode(inode, &fattr);
 	}
+	nfs_fattr_fini(&fattr);
 	return status;
 }
 
@@ -1902,10 +1926,16 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 	if (flags & O_EXCL) {
 		struct nfs_fattr fattr;
+		memset(&fattr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		if (nfs_server_capable(state->inode, NFS_CAP_SECURITY_LABEL))
+			nfs_fattr_alloc(&fattr, GFP_KERNEL);
+#endif
 		status = nfs4_do_setattr(state->inode, cred, &fattr, sattr, state);
 		if (status == 0)
 			nfs_setattr_update_inode(state->inode, sattr);
 		nfs_post_op_update_inode(state->inode, &fattr);
+		nfs_fattr_fini(&fattr);
 	}
 	if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
 		status = nfs4_intent_set_file(nd, &path, state);
@@ -1936,12 +1966,18 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
 	};
 	int			status;
 
+	memset(&res.dir_attr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (server->caps & NFS_CAP_SECURITY_LABEL)
+		nfs_fattr_alloc(&res.dir_attr, GFP_KERNEL);
+#endif
 	nfs_fattr_init(&res.dir_attr);
 	status = rpc_call_sync(server->client, &msg, 0);
 	if (status == 0) {
 		update_changeattr(dir, &res.cinfo);
 		nfs_post_op_update_inode(dir, &res.dir_attr);
 	}
+	nfs_fattr_fini(&res.dir_attr);
 	return status;
 }
 
@@ -1966,6 +2002,13 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 	args->bitmask = server->attr_bitmask;
 	res->server = server;
 	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
+
+	memset(&res->dir_attr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (server->caps & NFS_CAP_SECURITY_LABEL)
+		nfs_fattr_alloc(&res->dir_attr, GFP_KERNEL);
+#endif
+	nfs_fattr_init(&res->dir_attr);
 }
 
 static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
@@ -1976,6 +2019,7 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 		return 0;
 	update_changeattr(dir, &res->cinfo);
 	nfs_post_op_update_inode(dir, &res->dir_attr);
+	nfs_fattr_fini(&res->dir_attr);
 	return 1;
 }
 
@@ -2003,6 +2047,15 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
 	};
 	int			status;
 	
+	memset(&old_fattr, 0, sizeof(struct nfs_fattr));
+	memset(&new_fattr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (server->caps & NFS_CAP_SECURITY_LABEL) {
+		nfs_fattr_alloc(&old_fattr, GFP_KERNEL);
+		nfs_fattr_alloc(&new_fattr, GFP_KERNEL);
+	}
+#endif
+
 	nfs_fattr_init(res.old_fattr);
 	nfs_fattr_init(res.new_fattr);
 	status = rpc_call_sync(server->client, &msg, 0);
@@ -2013,6 +2066,8 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
 		update_changeattr(new_dir, &res.new_cinfo);
 		nfs_post_op_update_inode(new_dir, res.new_fattr);
 	}
+	nfs_fattr_fini(&old_fattr);
+	nfs_fattr_fini(&new_fattr);
 	return status;
 }
 
@@ -2052,6 +2107,15 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
 	};
 	int			status;
 
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+	memset(&dir_attr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (server->caps & NFS_CAP_SECURITY_LABEL) {
+		nfs_fattr_alloc(&fattr, GFP_KERNEL);
+		nfs_fattr_alloc(&dir_attr, GFP_KERNEL);
+	}
+#endif
+
 	nfs_fattr_init(res.fattr);
 	nfs_fattr_init(res.dir_attr);
 	status = rpc_call_sync(server->client, &msg, 0);
@@ -2061,6 +2125,8 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
 		nfs_post_op_update_inode(inode, res.fattr);
 	}
 
+	nfs_fattr_fini(&fattr);
+	nfs_fattr_fini(&dir_attr);
 	return status;
 }
 
@@ -2107,6 +2173,14 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
 		data->res.fh = &data->fh;
 		data->res.fattr = &data->fattr;
 		data->res.dir_fattr = &data->dir_fattr;
+		memset(&data->fattr, 0, sizeof(struct nfs_fattr));
+		memset(&data->dir_fattr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		if (server->caps & NFS_CAP_SECURITY_LABEL) {
+			nfs_fattr_alloc(&data->fattr, GFP_KERNEL);
+			nfs_fattr_alloc(&data->dir_fattr, GFP_KERNEL);
+		}
+#endif
 		nfs_fattr_init(data->res.fattr);
 		nfs_fattr_init(data->res.dir_fattr);
 	}
@@ -2126,6 +2200,8 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_
 
 static void nfs4_free_createdata(struct nfs4_createdata *data)
 {
+	nfs_fattr_fini(&data->fattr);
+	nfs_fattr_fini(&data->dir_fattr);
 	kfree(data);
 }
 
@@ -2958,6 +3034,9 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
 
 static void nfs4_delegreturn_release(void *calldata)
 {
+	struct nfs4_delegreturndata *data = calldata;
+
+	nfs_fattr_fini(data->res.fattr);
 	kfree(calldata);
 }
 
@@ -2983,7 +3062,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
 	};
 	int status = 0;
 
-	data = kmalloc(sizeof(*data), GFP_KERNEL);
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (data == NULL)
 		return -ENOMEM;
 	data->args.fhandle = &data->fh;
@@ -2997,6 +3076,11 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
 	data->timestamp = jiffies;
 	data->rpc_status = 0;
 
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (server->caps & NFS_CAP_SECURITY_LABEL)
+		nfs_fattr_alloc(&data->fattr, GFP_KERNEL);
+#endif
+
 	task_setup_data.callback_data = data;
 	msg.rpc_argp = &data->args,
 	msg.rpc_resp = &data->res,
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 4dbb84d..3ff1bdf 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -210,12 +210,14 @@ nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 	};
 	int			status;
 
-	nfs_fattr_init(&fattr);
 	dprintk("NFS call  create %s\n", dentry->d_name.name);
 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+	nfs_fattr_init(&fattr);
 	nfs_mark_for_revalidate(dir);
 	if (status == 0)
 		status = nfs_instantiate(dentry, &fhandle, &fattr);
+	nfs_fattr_fini(&fattr);
 	dprintk("NFS reply create: %d\n", status);
 	return status;
 }
@@ -257,6 +259,7 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 		sattr->ia_size = new_encode_dev(rdev);/* get out your barf bag */
 	}
 
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
 	nfs_fattr_init(&fattr);
 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
 	nfs_mark_for_revalidate(dir);
@@ -268,6 +271,7 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 	}
 	if (status == 0)
 		status = nfs_instantiate(dentry, &fhandle, &fattr);
+	nfs_fattr_fini(&fattr);
 	dprintk("NFS reply mknod: %d\n", status);
 	return status;
 }
@@ -380,6 +384,8 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
 
 	dprintk("NFS call  symlink %s\n", dentry->d_name.name);
 
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+
 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
 	nfs_mark_for_revalidate(dir);
 
@@ -394,6 +400,7 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
 		status = nfs_instantiate(dentry, &fhandle, &fattr);
 	}
 
+	nfs_fattr_fini(&fattr);
 	dprintk("NFS reply symlink: %d\n", status);
 	return status;
 }
@@ -421,11 +428,14 @@ nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
 	int			status;
 
 	dprintk("NFS call  mkdir %s\n", dentry->d_name.name);
+
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
 	nfs_fattr_init(&fattr);
 	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
 	nfs_mark_for_revalidate(dir);
 	if (status == 0)
 		status = nfs_instantiate(dentry, &fhandle, &fattr);
+	nfs_fattr_fini(&fattr);
 	dprintk("NFS reply mkdir: %d\n", status);
 	return status;
 }
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 256ce27..81cf6c5 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -377,6 +377,8 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 	};
 	int error;
 
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+
 	error = server->nfs_client->rpc_ops->statfs(server, fh, &res);
 	if (error < 0)
 		goto out_err;
@@ -408,10 +410,12 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
 
 	buf->f_namelen = server->namelen;
 
+	nfs_fattr_fini(&fattr);
 	return 0;
 
  out_err:
 	dprintk("%s: statfs error = %d\n", __func__, -error);
+	nfs_fattr_fini(&fattr);
 	return error;
 }
 
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 78a5922..192c056 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -355,6 +355,52 @@ static inline void nfs_fattr_init(struct nfs_fattr *fattr)
 	fattr->time_start = jiffies;
 }
 
+#ifdef CONFIG_SECURITY
+void security_release_secctx(char *secdata, u32 seclen);
+
+static inline void nfs_fattr_alloc(struct nfs_fattr *fattr, gfp_t flags)
+{
+	fattr->label = kzalloc(NFS4_MAXLABELLEN, flags);
+	if (fattr->label == NULL)
+		panic("Can't allocate security label.");
+	fattr->label_len = NFS4_MAXLABELLEN;
+}
+
+#define	nfs_fattr_fini(fattr)	_nfs_fattr_fini(fattr, __FILE__, __LINE__, __func__)
+static inline void _nfs_fattr_fini(struct nfs_fattr *fattr,
+				  const char *file, int line, const char *func)
+{
+	if ((fattr)->label == NULL) {
+		if (fattr->label_len != 0) {
+			printk(KERN_WARNING
+				"%s:%d %s() nfs_fattr label available (%d)\n",
+				file, line, func,
+				fattr->label_len);
+		}
+	} else {
+		if (fattr->label_len == NFS4_MAXLABELLEN)
+			printk(KERN_WARNING
+				"%s:%d %s() nfs_fattr label unused\n",
+				file, line, func);
+		else
+		if (fattr->label_len != (strlen(fattr->label) + 1))
+			printk(KERN_WARNING
+				"%s:%d %s() nfs_fattr label size mismatch (label_len %d, strlen %d)\n",
+				file, line, func,
+				fattr->label_len, strlen(fattr->label) + 1);
+
+
+		security_release_secctx(fattr->label, fattr->label_len);
+		fattr->label = NULL;
+		fattr->label_len = 0;
+	}
+}
+#else
+#define	nfs_fattr_alloc(fattr, flags)
+#define	nfs_fattr_fini(fattr)
+#endif
+
+
 /*
  * linux/fs/nfs/file.c
  */
-- 
1.5.5.1

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

* [PATCH 10/14] NFSv4: Introduce new label structure
  2008-09-29 17:06 [RFC v3] Security Label Support for NFSv4 David P. Quigley
                   ` (2 preceding siblings ...)
  2008-09-29 17:06 ` [PATCH 06/14] KConfig: Add KConfig entries for Labeled NFS David P. Quigley
@ 2008-09-29 17:06 ` David P. Quigley
  2008-09-29 17:06 ` [PATCH 11/14] NFS/RPC: Add the auth_seclabel security flavor to allow the process label to be sent to the server David P. Quigley
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
  To: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields
  Cc: linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs, David P. Quigley, Matthew N. Dodd

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: David P. Quigley <dpquigl@tycho.nsa.gov>
---
 include/linux/nfs4.h      |    6 ++++++
 include/linux/nfs_xdr.h   |    3 +++
 include/linux/nfsd/xdr4.h |    3 +++
 3 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 144eacf..dd99b27 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -112,6 +112,12 @@ struct nfs4_acl {
 	struct nfs4_ace	aces[0];
 };
 
+struct nfs4_label {
+	void		*label;
+	u32		len;
+};
+
+
 typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
 typedef struct { char data[NFS4_STATEID_SIZE]; } nfs4_stateid;
 
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 0d77568..c4fa2df 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -135,6 +135,7 @@ struct nfs_openargs {
 	const struct nfs_server *server;	 /* Needed for ID mapping */
 	const u32 *		bitmask;
 	__u32			claim;
+	const struct nfs4_label *label;
 };
 
 struct nfs_openres {
@@ -353,6 +354,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 {
@@ -577,6 +579,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 {
diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
index 27bd3e3..a0f3d79 100644
--- a/include/linux/nfsd/xdr4.h
+++ b/include/linux/nfsd/xdr4.h
@@ -94,6 +94,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
@@ -223,6 +224,7 @@ struct nfsd4_open {
 	int		op_truncate;        /* used during processing */
 	struct nfs4_stateowner *op_stateowner; /* used during processing */
 	struct nfs4_acl *op_acl;
+	struct nfs4_label *op_label;
 };
 #define op_iattr	u.iattr
 #define op_verf		u.verf
@@ -304,6 +306,7 @@ struct nfsd4_setattr {
 	u32		sa_bmval[2];        /* request */
 	struct iattr	sa_iattr;           /* request */
 	struct nfs4_acl *sa_acl;
+	struct nfs4_label *sa_label;
 };
 
 struct nfsd4_setclientid {
-- 
1.5.5.1


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

* [PATCH 11/14] NFS/RPC: Add the auth_seclabel security flavor to allow the process label to be sent to the server.
  2008-09-29 17:06 [RFC v3] Security Label Support for NFSv4 David P. Quigley
                   ` (3 preceding siblings ...)
  2008-09-29 17:06 ` [PATCH 10/14] NFSv4: Introduce new label structure David P. Quigley
@ 2008-09-29 17:06 ` David P. Quigley
  2008-10-03 14:23   ` Andy Whitcroft
       [not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
  2008-10-13 23:31 ` [RFC v3] Security Label Support for NFSv4 James Morris
  6 siblings, 1 reply; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
  To: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields
  Cc: linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs, David P. Quigley, Matthew N. Dodd

This patch adds a new RPC flavor that allows the NFSv4 client to pass the
process label of the calling process on the client to the server to make an
access control decision. This is accomplished by taking the credential from the
wire and replacing the acting credential on the server for the NFSD process
with that new context.

Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
---
 fs/nfs/nfs4proc.c               |    6 +-
 fs/nfsd/auth.c                  |   21 +++
 include/linux/sunrpc/auth.h     |    4 +
 include/linux/sunrpc/msg_prot.h |    1 +
 include/linux/sunrpc/svcauth.h  |    4 +
 net/sunrpc/Makefile             |    1 +
 net/sunrpc/auth.c               |   16 ++
 net/sunrpc/auth_seclabel.c      |  291 +++++++++++++++++++++++++++++++++++++++
 net/sunrpc/svc.c                |    1 +
 net/sunrpc/svcauth.c            |    6 +
 net/sunrpc/svcauth_unix.c       |   97 +++++++++++++-
 security/security.c             |    2 +
 security/selinux/hooks.c        |    2 +-
 13 files changed, 446 insertions(+), 6 deletions(-)
 create mode 100644 net/sunrpc/auth_seclabel.c

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index c4a4271..92522cc 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1410,6 +1410,9 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 	struct nfs4_state *state;
 	struct dentry *res;
 
+	cred = rpc_lookup_cred();
+	if (IS_ERR(cred))
+		return (struct dentry *)cred;
 	if (nd->flags & LOOKUP_CREATE) {
 		attr.ia_mode = nd->intent.open.create_mode;
 		attr.ia_valid = ATTR_MODE;
@@ -1420,9 +1423,6 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 		BUG_ON(nd->intent.open.flags & O_CREAT);
 	}
 
-	cred = rpc_lookup_cred();
-	if (IS_ERR(cred))
-		return (struct dentry *)cred;
 	parent = dentry->d_parent;
 	/* Protect against concurrent sillydeletes */
 	nfs_block_sillyrename(parent);
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 294992e..400edf5 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -10,6 +10,9 @@
 #include <linux/sunrpc/svcauth.h>
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/export.h>
+#ifdef CONFIG_SECURITY
+#include <linux/security.h>
+#endif
 #include "auth.h"
 
 int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
@@ -32,6 +35,24 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
 	int flags = nfsexp_flags(rqstp, exp);
 	int ret;
 
+#ifdef CONFIG_SECURITY
+	if (cred.cr_label_len != 0) {
+		ret = security_setprocattr(current, "current",
+				(void *)cred.cr_label, cred.cr_label_len);
+		if (ret < 0) {
+			printk(KERN_ERR "%s(): "
+					"flavor %d "
+					"security_setprocattr(\"%*s\", %d) = %d\n",
+					__func__,
+					rqstp->rq_flavor,
+					cred.cr_label_len,
+					(char *)cred.cr_label,
+					cred.cr_label_len, ret);
+			return ret;
+		}
+	}
+#endif
+	
 	if (flags & NFSEXP_ALLSQUASH) {
 		cred.cr_uid = exp->ex_anon_uid;
 		cred.cr_gid = exp->ex_anon_gid;
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index 3f63218..11c054d 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -27,6 +27,10 @@ struct auth_cred {
 	gid_t	gid;
 	struct group_info *group_info;
 	unsigned char machine_cred : 1;
+#ifdef CONFIG_SECURITY
+	char   *label;
+	size_t  label_len;
+#endif
 };
 
 /*
diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h
index 70df4f1..e2667f6 100644
--- a/include/linux/sunrpc/msg_prot.h
+++ b/include/linux/sunrpc/msg_prot.h
@@ -24,6 +24,7 @@ enum rpc_auth_flavors {
 	RPC_AUTH_DES   = 3,
 	RPC_AUTH_KRB   = 4,
 	RPC_AUTH_GSS   = 6,
+	RPC_AUTH_SECLABEL = 7,
 	RPC_AUTH_MAXFLAVOR = 8,
 	/* pseudoflavors: */
 	RPC_AUTH_GSS_KRB5  = 390003,
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index d39dbdc..5557361 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -21,6 +21,10 @@ struct svc_cred {
 	uid_t			cr_uid;
 	gid_t			cr_gid;
 	struct group_info	*cr_group_info;
+#ifdef CONFIG_SECURITY
+	void			*cr_label;
+	u32			cr_label_len;
+#endif
 };
 
 struct svc_rqst;		/* forward decl */
diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile
index 5369aa3..5e03065 100644
--- a/net/sunrpc/Makefile
+++ b/net/sunrpc/Makefile
@@ -6,6 +6,7 @@
 obj-$(CONFIG_SUNRPC) += sunrpc.o
 obj-$(CONFIG_SUNRPC_GSS) += auth_gss/
 obj-$(CONFIG_SUNRPC_XPRT_RDMA) += xprtrdma/
+obj-$(CONFIG_SECURITY) += auth_seclabel.o
 
 sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
 	    auth.o auth_null.o auth_unix.o auth_generic.o \
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 6bfea9e..b1d9e4e 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -14,6 +14,7 @@
 #include <linux/hash.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/spinlock.h>
+#include <linux/security.h>
 
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY	RPCDBG_AUTH
@@ -359,11 +360,19 @@ rpcauth_lookupcred(struct rpc_auth *auth, int flags)
 
 	dprintk("RPC:       looking up %s cred\n",
 		auth->au_ops->au_name);
+#ifdef CONFIG_SECURITY
+	acred.label_len = security_getprocattr(current, "current",&acred.label);
+#endif
 	get_group_info(acred.group_info);
 	ret = auth->au_ops->lookup_cred(auth, &acred, flags);
 	put_group_info(acred.group_info);
+#ifdef CONFIG_SECURITY
+	if (acred.label != NULL)
+		security_release_secctx(acred.label, acred.label_len);
+#endif
 	return ret;
 }
+EXPORT_SYMBOL_GPL(rpcauth_lookupcred);
 
 void
 rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred,
@@ -403,11 +412,18 @@ rpcauth_bind_root_cred(struct rpc_task *task)
 
 	dprintk("RPC: %5u looking up %s cred\n",
 		task->tk_pid, task->tk_client->cl_auth->au_ops->au_name);
+#ifdef CONFIG_SECURITY
+	acred.label_len = security_getprocattr(current, "current",&acred.label);
+#endif
 	ret = auth->au_ops->lookup_cred(auth, &acred, 0);
 	if (!IS_ERR(ret))
 		task->tk_msg.rpc_cred = ret;
 	else
 		task->tk_status = PTR_ERR(ret);
+#ifdef CONFIG_SECURITY
+	if (acred.label != NULL)
+		security_release_secctx(acred.label, acred.label_len);
+#endif
 }
 
 static void
diff --git a/net/sunrpc/auth_seclabel.c b/net/sunrpc/auth_seclabel.c
new file mode 100644
index 0000000..3e3b8ef
--- /dev/null
+++ b/net/sunrpc/auth_seclabel.c
@@ -0,0 +1,291 @@
+/*
+ * linux/net/sunrpc/auth_seclabel.c
+ *
+ * UNIX-style authentication; no AUTH_SHORT support
+ * SECLABEL-style authentication with security label support
+ *
+ * Copyright (C) 2007, 2008, SPARTA, Inc.
+ * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/auth.h>
+#include <linux/security.h>
+
+#define NFS_NGROUPS	16
+
+struct seclabel_cred {
+	struct rpc_cred		slc_base;
+	gid_t			slc_gid;
+	gid_t			slc_gids[NFS_NGROUPS];
+	char		       *slc_label;
+	size_t			slc_label_len;
+};
+#define slc_uid			slc_base.cr_uid
+
+#define UNX_WRITESLACK		(21 + (UNX_MAXNODENAME >> 2))
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY	RPCDBG_AUTH
+#endif
+
+static struct rpc_auth		seclabel_auth;
+static struct rpc_cred_cache	seclabel_cred_cache;
+static const struct rpc_credops	seclabel_credops;
+
+static struct rpc_auth *
+seclabel_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
+{
+	dprintk("RPC:       creating SECLABEL authenticator for client %p\n",
+			clnt);
+	atomic_inc(&seclabel_auth.au_count);
+	return &seclabel_auth;
+}
+
+static void
+seclabel_destroy(struct rpc_auth *auth)
+{
+	dprintk("RPC:       destroying SECLABEL authenticator %p\n", auth);
+	rpcauth_clear_credcache(auth->au_credcache);
+}
+
+/*
+ * Lookup AUTH_SECLABEL creds for current process
+ */
+static struct rpc_cred *
+seclabel_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
+{
+	return rpcauth_lookup_credcache(auth, acred, flags);
+}
+
+static struct rpc_cred *
+seclabel_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
+{
+	struct seclabel_cred	*cred;
+	unsigned int groups = 0;
+	unsigned int i;
+
+	dprintk("RPC:       allocating SECLABEL cred for uid %d gid %d\n",
+			acred->uid, acred->gid);
+
+	if (!(cred = kmalloc(sizeof(*cred), GFP_KERNEL)))
+		return ERR_PTR(-ENOMEM);
+
+	cred->slc_label = kmalloc(acred->label_len, GFP_KERNEL);
+	if (cred->slc_label == NULL) {
+		kfree(cred);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	rpcauth_init_cred(&cred->slc_base, acred, auth, &seclabel_credops);
+	cred->slc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
+
+	if (acred->group_info != NULL)
+		groups = acred->group_info->ngroups;
+	if (groups > NFS_NGROUPS)
+		groups = NFS_NGROUPS;
+
+	cred->slc_gid = acred->gid;
+	for (i = 0; i < groups; i++)
+		cred->slc_gids[i] = GROUP_AT(acred->group_info, i);
+	if (i < NFS_NGROUPS)
+		cred->slc_gids[i] = NOGROUP;
+
+	cred->slc_label_len = acred->label_len;
+	memcpy(cred->slc_label, acred->label, acred->label_len);
+
+	return &cred->slc_base;
+}
+
+static void
+seclabel_free_cred(struct seclabel_cred *seclabel_cred)
+{
+	dprintk("RPC:       seclabel_free_cred %p\n", seclabel_cred);
+	security_release_secctx(seclabel_cred->slc_label,
+				seclabel_cred->slc_label_len);
+	kfree(seclabel_cred);
+}
+
+static void
+seclabel_free_cred_callback(struct rcu_head *head)
+{
+	struct seclabel_cred *seclabel_cred = container_of(head, struct seclabel_cred, slc_base.cr_rcu);
+	seclabel_free_cred(seclabel_cred);
+}
+
+static void
+seclabel_destroy_cred(struct rpc_cred *cred)
+{
+	call_rcu(&cred->cr_rcu, seclabel_free_cred_callback);
+}
+
+/*
+ * Match credentials against current process creds.
+ * The root_override argument takes care of cases where the caller may
+ * request root creds (e.g. for NFS swapping).
+ */
+static int
+seclabel_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags)
+{
+	struct seclabel_cred	*cred = container_of(rcred, struct seclabel_cred, slc_base);
+	unsigned int groups = 0;
+	unsigned int i;
+
+
+	if (acred->label_len != cred->slc_label_len)
+		return 0;
+	if (strcmp(acred->label, cred->slc_label) != 0)
+		return 0;
+	if (cred->slc_uid != acred->uid || cred->slc_gid != acred->gid)
+		return 0;
+
+	if (acred->group_info != NULL)
+		groups = acred->group_info->ngroups;
+	if (groups > NFS_NGROUPS)
+		groups = NFS_NGROUPS;
+	for (i = 0; i < groups ; i++)
+		if (cred->slc_gids[i] != GROUP_AT(acred->group_info, i))
+			return 0;
+	return 1;
+}
+
+/*
+ * Marshal credentials.
+ * Maybe we should keep a cached credential for performance reasons.
+ */
+static __be32 *
+seclabel_marshal(struct rpc_task *task, __be32 *p)
+{
+	struct rpc_clnt	*clnt = task->tk_client;
+	struct seclabel_cred	*cred = container_of(task->tk_msg.rpc_cred, struct seclabel_cred, slc_base);
+	__be32		*base, *hold;
+	int		i;
+
+	*p++ = htonl(RPC_AUTH_SECLABEL);
+	base = p++;
+	*p++ = htonl(jiffies/HZ);
+
+	/*
+	 * Copy the UTS nodename captured when the client was created.
+	 */
+	p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen);
+
+	/*
+	 * Label
+	 */
+	p = xdr_encode_array(p, cred->slc_label, cred->slc_label_len);
+
+	*p++ = htonl((u32) cred->slc_uid);
+	*p++ = htonl((u32) cred->slc_gid);
+	hold = p++;
+	for (i = 0; i < 16 && cred->slc_gids[i] != (gid_t) NOGROUP; i++)
+		*p++ = htonl((u32) cred->slc_gids[i]);
+	*hold = htonl(p - hold - 1);		/* gid array length */
+	*base = htonl((p - base - 1) << 2);	/* cred length */
+
+	*p++ = htonl(RPC_AUTH_NULL);
+	*p++ = htonl(0);
+
+	return p;
+}
+
+/*
+ * Refresh credentials. This is a no-op for AUTH_SECLABEL
+ */
+static int
+seclabel_refresh(struct rpc_task *task)
+{
+	set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_msg.rpc_cred->cr_flags);
+	return 0;
+}
+
+static __be32 *
+seclabel_validate(struct rpc_task *task, __be32 *p)
+{
+	rpc_authflavor_t	flavor;
+	u32			size;
+
+	flavor = ntohl(*p++);
+	if (flavor != RPC_AUTH_NULL &&
+	    flavor != RPC_AUTH_SECLABEL &&
+	    flavor != RPC_AUTH_SHORT) {
+		printk("RPC: bad verf flavor: %u\n", flavor);
+		return NULL;
+	}
+
+	size = ntohl(*p++);
+	if (size > RPC_MAX_AUTH_SIZE) {
+		printk("RPC: giant verf size: %u\n", size);
+		return NULL;
+	}
+	task->tk_msg.rpc_cred->cr_auth->au_rslack = (size >> 2) + 2;
+	p += (size >> 2);
+
+	return p;
+}
+
+static const struct rpc_authops authseclabel_ops = {
+	.owner		= THIS_MODULE,
+	.au_flavor	= RPC_AUTH_SECLABEL,
+	.au_name	= "SECLABEL",
+	.create		= seclabel_create,
+	.destroy	= seclabel_destroy,
+	.lookup_cred	= seclabel_lookup_cred,
+	.crcreate	= seclabel_create_cred,
+};
+
+static struct rpc_cred_cache	seclabel_cred_cache = {
+};
+
+static struct rpc_auth		seclabel_auth = {
+	.au_cslack	= UNX_WRITESLACK,
+	.au_rslack	= 2,			/* assume AUTH_NULL verf */
+	.au_ops		= &authseclabel_ops,
+	.au_flavor	= RPC_AUTH_SECLABEL,
+	.au_count	= ATOMIC_INIT(0),
+	.au_credcache	= &seclabel_cred_cache,
+};
+
+static const struct rpc_credops seclabel_credops = {
+	.cr_name	= "AUTH_SECLABEL",
+	.crdestroy	= seclabel_destroy_cred,
+	.crbind		= rpcauth_generic_bind_cred,
+	.crmatch	= seclabel_match,
+	.crmarshal	= seclabel_marshal,
+	.crrefresh	= seclabel_refresh,
+	.crvalidate	= seclabel_validate,
+};
+
+/*
+ * Initialize RPCSEC_GSS module
+ */
+static int __init init_auth_seclabel(void)
+{
+	int err = 0;
+
+	err = rpcauth_register(&authseclabel_ops);
+	if (err)
+		goto out;
+
+	spin_lock_init(&seclabel_cred_cache.lock);
+
+	return 0;
+out:
+	rpcauth_unregister(&authseclabel_ops);
+	return err;
+}
+
+static void __exit exit_auth_seclabel(void)
+{
+        rpcauth_unregister(&authseclabel_ops);
+}
+
+MODULE_LICENSE("GPL");
+module_init(init_auth_seclabel)
+module_exit(exit_auth_seclabel)
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 5a32cb7..126eeb1 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -830,6 +830,7 @@ svc_process(struct svc_rqst *rqstp)
 	rqstp->rq_res.buflen = PAGE_SIZE;
 	rqstp->rq_res.tail[0].iov_base = NULL;
 	rqstp->rq_res.tail[0].iov_len = 0;
+	memset(&rqstp->rq_cred, 0, sizeof(struct svc_cred));
 	/* Will be turned off only in gss privacy case: */
 	rqstp->rq_splice_ok = 1;
 
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
index 8a73cbb..ca8c99f 100644
--- a/net/sunrpc/svcauth.c
+++ b/net/sunrpc/svcauth.c
@@ -26,11 +26,17 @@
  */
 extern struct auth_ops svcauth_null;
 extern struct auth_ops svcauth_unix;
+#ifdef CONFIG_SECURITY
+extern struct auth_ops svcauth_seclabel;
+#endif
 
 static DEFINE_SPINLOCK(authtab_lock);
 static struct auth_ops	*authtab[RPC_AUTH_MAXFLAVOR] = {
 	[0] = &svcauth_null,
 	[1] = &svcauth_unix,
+#ifdef CONFIG_SECURITY
+	[RPC_AUTH_SECLABEL] = &svcauth_seclabel,
+#endif
 };
 
 int
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index f24800f..4dfecf0 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -31,6 +31,9 @@ struct unix_domain {
 };
 
 extern struct auth_ops svcauth_unix;
+#ifdef CONFIG_SECURITY
+extern struct auth_ops svcauth_seclabel;
+#endif
 
 struct auth_domain *unix_domain_find(char *name)
 {
@@ -43,7 +46,11 @@ struct auth_domain *unix_domain_find(char *name)
 			if (new && rv != &new->h)
 				auth_domain_put(&new->h);
 
-			if (rv->flavour != &svcauth_unix) {
+			if (rv->flavour != &svcauth_unix
+#ifdef CONFIG_SECURITY
+			    && rv->flavour != &svcauth_seclabel
+#endif
+			   ) {
 				auth_domain_put(rv);
 				return NULL;
 			}
@@ -358,7 +365,11 @@ int auth_unix_add_addr(struct in6_addr *addr, struct auth_domain *dom)
 	struct unix_domain *udom;
 	struct ip_map *ipmp;
 
-	if (dom->flavour != &svcauth_unix)
+	if (dom->flavour != &svcauth_unix
+#ifdef CONFIG_SECURITY
+	    && dom->flavour != &svcauth_seclabel
+#endif
+	   )
 		return -EINVAL;
 	udom = container_of(dom, struct unix_domain, h);
 	ipmp = ip_map_lookup("nfsd", addr);
@@ -374,6 +385,11 @@ int auth_unix_forget_old(struct auth_domain *dom)
 {
 	struct unix_domain *udom;
 
+	if (dom->flavour != &svcauth_unix
+#ifdef CONFIG_SECURITY
+	    && dom->flavour != &svcauth_seclabel
+#endif
+	   )
 	if (dom->flavour != &svcauth_unix)
 		return -EINVAL;
 	udom = container_of(dom, struct unix_domain, h);
@@ -873,3 +889,80 @@ struct auth_ops svcauth_unix = {
 	.set_client	= svcauth_unix_set_client,
 };
 
+#ifdef CONFIG_SECURITY
+static int
+svcauth_seclabel_accept(struct svc_rqst *rqstp, __be32 *authp)
+{
+	struct kvec	*argv = &rqstp->rq_arg.head[0];
+	struct kvec	*resv = &rqstp->rq_res.head[0];
+	struct svc_cred	*cred = &rqstp->rq_cred;
+	u32		slen, i;
+	int		len   = argv->iov_len;
+
+	cred->cr_group_info = NULL;
+	rqstp->rq_client = NULL;
+
+	if ((len -= 3*4) < 0)
+		return SVC_GARBAGE;
+
+	svc_getu32(argv);			/* length */
+	svc_getu32(argv);			/* time stamp */
+	slen = XDR_QUADLEN(svc_getnl(argv));	/* machname length */
+	if (slen > 64 || (len -= (slen + 3)*4) < 0)
+		goto badcred;
+	argv->iov_base = (void*)((__be32*)argv->iov_base + slen);	/* skip machname */
+	argv->iov_len -= slen*4;
+
+	slen = svc_getnl(argv);			/* security label length */
+	/* XXX: sanity check label... */
+	cred->cr_label = argv->iov_base;
+	cred->cr_label_len = slen;
+	argv->iov_base = (void*)((__be32*)argv->iov_base + XDR_QUADLEN(slen));
+	argv->iov_len -= slen;
+
+	cred->cr_uid = svc_getnl(argv);		/* uid */
+	cred->cr_gid = svc_getnl(argv);		/* gid */
+	slen = svc_getnl(argv);			/* gids length */
+	if (slen > 16 || (len -= (slen + 2)*4) < 0)
+		goto badcred;
+	if (unix_gid_find(cred->cr_uid, &cred->cr_group_info, rqstp)
+	    == -EAGAIN)
+		return SVC_DROP;
+	if (cred->cr_group_info == NULL) {
+		cred->cr_group_info = groups_alloc(slen);
+		if (cred->cr_group_info == NULL)
+			return SVC_DROP;
+		for (i = 0; i < slen; i++)
+			GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv);
+	} else {
+		for (i = 0; i < slen ; i++)
+			svc_getnl(argv);
+	}
+	if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
+		*authp = rpc_autherr_badverf;
+		return SVC_DENIED;
+	}
+
+	/* Put NULL verifier */
+	svc_putnl(resv, RPC_AUTH_NULL);
+	svc_putnl(resv, 0);
+
+	rqstp->rq_flavor = RPC_AUTH_SECLABEL;
+	return SVC_OK;
+
+badcred:
+	*authp = rpc_autherr_badcred;
+	return SVC_DENIED;
+}
+
+struct auth_ops svcauth_seclabel = {
+	.name		= "seclabel",
+	.owner		= THIS_MODULE,
+	.flavour	= RPC_AUTH_SECLABEL,
+	.accept 	= svcauth_seclabel_accept,
+	.release	= svcauth_unix_release,
+	.domain_release	= svcauth_unix_domain_release,
+	.set_client	= svcauth_unix_set_client,
+};
+#endif
+
diff --git a/security/security.c b/security/security.c
index 1955094..2337d7f 100644
--- a/security/security.c
+++ b/security/security.c
@@ -841,11 +841,13 @@ int security_getprocattr(struct task_struct *p, char *name, char **value)
 {
 	return security_ops->getprocattr(p, name, value);
 }
+EXPORT_SYMBOL(security_getprocattr);
 
 int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size)
 {
 	return security_ops->setprocattr(p, name, value, size);
 }
+EXPORT_SYMBOL(security_setprocattr);
 
 int security_netlink_send(struct sock *sk, struct sk_buff *skb)
 {
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 6919766..05a10be 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5298,7 +5298,7 @@ static int selinux_setprocattr(struct task_struct *p,
 			return -EINVAL;
 
 		/* Only allow single threaded processes to change context */
-		if (atomic_read(&p->mm->mm_users) != 1) {
+		if (p->mm && atomic_read(&p->mm->mm_users) != 1) {
 			struct task_struct *g, *t;
 			struct mm_struct *mm = p->mm;
 			read_lock(&tasklist_lock);
-- 
1.5.5.1


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

* [PATCH 12/14] NFS: Client implementation of Labeled-NFS
       [not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
                     ` (5 preceding siblings ...)
  2008-09-29 17:06   ` [PATCH 09/14] NFS: Introduce lifecycle management for label attribute David P. Quigley
@ 2008-09-29 17:06   ` David P. Quigley
  2008-09-29 17:06   ` [PATCH 13/14] NFS: Extend NFS xattr handlers to accept the security namespace David P. Quigley
  2008-09-29 17:06   ` [PATCH 14/14] NFSD: Server implementation of MAC Labeling David P. Quigley
  8 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
  To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
	casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
	matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
	trond.myklebust-41N18TsMXrtuMpJDpNschA,
	bfields-uC3wQj2KruNg9hUCZPvPmw
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	linux-security-module-u79uwXL29TY76Z2rM5mHXA,
	selinux-+05T5uksL2qpZYMLLGbcSA,
	labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
	Matthew N. Dodd

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: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
 fs/nfs/inode.c           |   45 ++++++-
 fs/nfs/nfs4proc.c        |  303 ++++++++++++++++++++++++++++++++++++++++++----
 fs/nfs/nfs4xdr.c         |   55 ++++++++-
 fs/nfs/super.c           |   16 +++-
 include/linux/nfs_fs.h   |    2 +
 security/selinux/hooks.c |    5 +
 6 files changed, 391 insertions(+), 35 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 40d7142..dde0667 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -143,10 +143,13 @@ static void nfs_zap_caches_locked(struct inode *inode)
 	nfsi->attrtimeo_timestamp = jiffies;
 
 	memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
+	nfsi->cache_validity |= NFS_INO_INVALID_ATTR| \
+				NFS_INO_INVALID_LABEL| \
+				NFS_INO_INVALID_ACCESS| \
+				NFS_INO_INVALID_ACL| \
+				NFS_INO_REVAL_PAGECACHE;
 	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;
-	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_DATA;
 }
 
 void nfs_zap_caches(struct inode *inode)
@@ -235,6 +238,29 @@ nfs_init_locked(struct inode *inode, void *opaque)
 /* Don't use READDIRPLUS on directories that we believe are too large */
 #define NFS_LIMIT_READDIRPLUS (8*PAGE_SIZE)
 
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr)
+{
+	int error;
+
+/*	BUG_ON(!mutex_is_locked(&inode->i_mutex)); */
+
+	if ((fattr->valid & NFS_ATTR_FATTR_V4) &&
+	    (fattr->bitmap[1] & FATTR4_WORD1_SECURITY_LABEL) &&
+	    (fattr->label != NULL) &&
+	    (inode->i_security != NULL)) {
+		error = security_inode_notifysecctx(inode, fattr->label,
+						   fattr->label_len);
+		/* XXX: debug output */
+		if (error)
+			printk(KERN_ERR "%s() %s %d "
+				"security_inode_notifysecctx() %d\n",
+				__func__,
+				(char *)fattr->label, fattr->label_len, error);
+	}
+}
+#endif
+
 /*
  * This is our front-end to iget that looks up inodes by file handle
  * instead of inode number.
@@ -316,6 +342,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 		inode->i_nlink = fattr->nlink;
 		inode->i_uid = fattr->uid;
 		inode->i_gid = fattr->gid;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		nfs_setsecurity(inode, fattr);
+#endif
+
 		if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
 			/*
 			 * report the blocks in 512byte units
@@ -790,7 +821,7 @@ int nfs_attribute_timeout(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_timeout(inode))
 		return NFS_STALE(inode) ? -ESTALE : 0;
 	return __nfs_revalidate_inode(server, inode);
@@ -1146,6 +1177,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 	inode->i_nlink = fattr->nlink;
 	inode->i_uid = fattr->uid;
 	inode->i_gid = fattr->gid;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	nfs_setsecurity(inode, fattr);
+#endif
 
 	if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
 		/*
@@ -1157,7 +1191,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
  	}
 
 	/* 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;
@@ -1175,6 +1209,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 			nfsi->last_updated = nfsi->read_cache_jiffies;
 	}
 	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 92522cc..622bf71 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -48,6 +48,7 @@
 #include <linux/smp_lock.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
+#include <linux/nfs4_mount.h>
 
 #include "nfs4_fs.h"
 #include "delegation.h"
@@ -97,6 +98,9 @@ const u32 nfs4_fattr_bitmap[2] = {
 	| FATTR4_WORD1_TIME_ACCESS
 	| FATTR4_WORD1_TIME_METADATA
 	| FATTR4_WORD1_TIME_MODIFY
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	| FATTR4_WORD1_SECURITY_LABEL
+#endif
 };
 
 const u32 nfs4_statfs_bitmap[2] = {
@@ -251,7 +255,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
 
 static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
 		struct nfs4_state_owner *sp, int flags,
-		const struct iattr *attrs)
+		const struct iattr *attrs, struct nfs4_label *label)
 {
 	struct dentry *parent = dget_parent(path->dentry);
 	struct inode *dir = parent->d_inode;
@@ -277,6 +281,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
 	p->o_arg.server = server;
 	p->o_arg.bitmask = server->attr_bitmask;
 	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
+	p->o_arg.label = label;
 	if (flags & O_EXCL) {
 		u32 *s = (u32 *) p->o_arg.u.verifier.data;
 		s[0] = jiffies;
@@ -563,7 +568,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context
 {
 	struct nfs4_opendata *opendata;
 
-	opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL);
+	opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL, NULL);
 	if (opendata == NULL)
 		return ERR_PTR(-ENOMEM);
 	opendata->state = state;
@@ -1042,7 +1047,7 @@ static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct
 /*
  * Returns a referenced nfs4_state
  */
-static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res)
+static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct nfs4_label *label, struct rpc_cred *cred, struct nfs4_state **res)
 {
 	struct nfs4_state_owner  *sp;
 	struct nfs4_state     *state = NULL;
@@ -1064,7 +1069,7 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct
 		nfs4_return_incompatible_delegation(path->dentry->d_inode, flags & (FMODE_READ|FMODE_WRITE));
 	down_read(&clp->cl_sem);
 	status = -ENOMEM;
-	opendata = nfs4_opendata_alloc(path, sp, flags, sattr);
+	opendata = nfs4_opendata_alloc(path, sp, flags, sattr, label);
 	if (opendata == NULL)
 		goto err_release_rwsem;
 
@@ -1099,14 +1104,14 @@ out_err:
 }
 
 
-static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred)
+static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct nfs4_label *label, struct rpc_cred *cred)
 {
 	struct nfs4_exception exception = { };
 	struct nfs4_state *res;
 	int status;
 
 	do {
-		status = _nfs4_do_open(dir, path, flags, sattr, cred, &res);
+		status = _nfs4_do_open(dir, path, flags, sattr, label, cred, &res);
 		if (status == 0)
 			break;
 		/* NOTE: BAD_SEQID means the server and client disagree about the
@@ -1150,14 +1155,15 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int
 
 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_label *label, struct nfs4_state *state)
 {
 	struct nfs_server *server = NFS_SERVER(inode);
         struct nfs_setattrargs  arg = {
                 .fh             = NFS_FH(inode),
                 .iap            = sattr,
 		.server		= server,
-		.bitmask = server->attr_bitmask,
+		.bitmask 	= server->attr_bitmask,
+		.label		= label,
         };
         struct nfs_setattrres  res = {
 		.fattr		= fattr,
@@ -1189,14 +1195,14 @@ 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_label *label, struct nfs4_state *state)
 {
 	struct nfs_server *server = NFS_SERVER(inode);
 	struct nfs4_exception exception = { };
 	int err;
 	do {
 		err = nfs4_handle_exception(server,
-				_nfs4_do_setattr(inode, cred, fattr, sattr, state),
+				_nfs4_do_setattr(inode, cred, fattr, sattr, label, state),
 				&exception);
 	} while (exception.retry);
 	return err;
@@ -1400,6 +1406,7 @@ out_close:
 struct dentry *
 nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 {
+	struct nfs4_label l, *label = NULL;
 	struct path path = {
 		.mnt = nd->path.mnt,
 		.dentry = dentry,
@@ -1413,11 +1420,21 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 	cred = rpc_lookup_cred();
 	if (IS_ERR(cred))
 		return (struct dentry *)cred;
+	memset(&attr, 0, sizeof(struct iattr));
 	if (nd->flags & LOOKUP_CREATE) {
 		attr.ia_mode = nd->intent.open.create_mode;
 		attr.ia_valid = ATTR_MODE;
 		if (!IS_POSIXACL(dir))
 			attr.ia_mode &= ~current->fs->umask;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+			int error;
+			error = security_dentry_init_security(dentry,
+					attr.ia_mode, &l.label, &l.len);
+			if (error == 0)
+				label = &l;
+		}
+#endif
 	} else {
 		attr.ia_valid = 0;
 		BUG_ON(nd->intent.open.flags & O_CREAT);
@@ -1426,8 +1443,12 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 	parent = dentry->d_parent;
 	/* Protect against concurrent sillydeletes */
 	nfs_block_sillyrename(parent);
-	state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred);
+	state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, label, cred);
 	put_rpccred(cred);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		security_release_secctx(l.label, l.len);
+#endif
 	if (IS_ERR(state)) {
 		if (PTR_ERR(state) == -ENOENT) {
 			d_add(dentry, NULL);
@@ -1458,7 +1479,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
 	cred = rpc_lookup_cred();
 	if (IS_ERR(cred))
 		return PTR_ERR(cred);
-	state = nfs4_do_open(dir, &path, openflags, NULL, cred);
+	state = nfs4_do_open(dir, &path, openflags, NULL, NULL, cred);
 	put_rpccred(cred);
 	if (IS_ERR(state)) {
 		switch (PTR_ERR(state)) {
@@ -1500,6 +1521,13 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
 		memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask));
 		if (res.attr_bitmask[0] & FATTR4_WORD0_ACL)
 			server->caps |= NFS_CAP_ACLS;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		if (server->flags & NFS4_MOUNT_SECURITY_LABEL &&
+		    res.attr_bitmask[1] & FATTR4_WORD1_SECURITY_LABEL) {
+			server->caps |= NFS_CAP_SECURITY_LABEL;
+		} else
+#endif
+		server->attr_bitmask[1] &= ~FATTR4_WORD1_SECURITY_LABEL;
 		if (res.has_links != 0)
 			server->caps |= NFS_CAP_HARDLINKS;
 		if (res.has_symlinks != 0)
@@ -1680,9 +1708,11 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 		state = ctx->state;
 	}
 
-	status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
-	if (status == 0)
+	status = nfs4_do_setattr(inode, cred, fattr, sattr, NULL, state);
+	if (status == 0) {
 		nfs_setattr_update_inode(inode, sattr);
+		nfs_setsecurity(inode, fattr);
+	}
 	return status;
 }
 
@@ -1903,6 +1933,7 @@ static int
 nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                  int flags, struct nameidata *nd)
 {
+	struct nfs4_label l, *label = NULL;
 	struct path path = {
 		.mnt = nd->path.mnt,
 		.dentry = dentry,
@@ -1916,7 +1947,18 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 		status = PTR_ERR(cred);
 		goto out;
 	}
-	state = nfs4_do_open(dir, &path, flags, sattr, cred);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (((nd->flags & LOOKUP_CREATE) != 0) &&
+	      nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+		status = security_dentry_init_security(dentry,
+				sattr->ia_mode, &l.label, &l.len);
+		/* XXX: should this be more fatal? */
+		if (status == 0)
+			label = &l;
+	}
+#endif
+
+	state = nfs4_do_open(dir, &path, flags, sattr, label, cred);
 	d_drop(dentry);
 	if (IS_ERR(state)) {
 		status = PTR_ERR(state);
@@ -1931,10 +1973,12 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 		if (nfs_server_capable(state->inode, NFS_CAP_SECURITY_LABEL))
 			nfs_fattr_alloc(&fattr, GFP_KERNEL);
 #endif
-		status = nfs4_do_setattr(state->inode, cred, &fattr, sattr, state);
-		if (status == 0)
+		status = nfs4_do_setattr(state->inode, cred, &fattr, sattr, label, state);
+		if (status == 0) {
 			nfs_setattr_update_inode(state->inode, sattr);
-		nfs_post_op_update_inode(state->inode, &fattr);
+			nfs_post_op_update_inode(state->inode, &fattr);
+			nfs_setsecurity(state->inode, &fattr);
+		}
 		nfs_fattr_fini(&fattr);
 	}
 	if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
@@ -1944,6 +1988,10 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 out_putcred:
 	put_rpccred(cred);
 out:
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		security_release_secctx(label->label, label->len);
+#endif
 	return status;
 }
 
@@ -2206,7 +2254,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;
@@ -2222,6 +2271,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);
 
@@ -2234,18 +2284,33 @@ 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 l, *label = NULL;
 	int err;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+		err = security_dentry_init_security(dentry,
+				sattr->ia_mode, &l.label, &l.len);
+		if (err == 0)
+			label = &l;
+	}
+#endif
+
 	do {
 		err = nfs4_handle_exception(NFS_SERVER(dir),
 				_nfs4_proc_symlink(dir, dentry, page,
-							len, sattr),
+							len, sattr, label),
 				&exception);
 	} while (exception.retry);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		security_release_secctx(l.label, l.len);
+#endif
 	return err;
 }
 
 static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
-		struct iattr *sattr)
+		struct iattr *sattr, struct nfs4_label *label)
 {
 	struct nfs4_createdata *data;
 	int status = -ENOMEM;
@@ -2254,6 +2319,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);
@@ -2265,12 +2331,27 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr)
 {
 	struct nfs4_exception exception = { };
+	struct nfs4_label l, *label = NULL;
 	int err;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+		err = security_dentry_init_security(dentry,
+				sattr->ia_mode, &l.label, &l.len);
+		if (err == 0)
+			label = &l;
+	}
+#endif
+
 	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);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		security_release_secctx(l.label, l.len);
+#endif
 	return err;
 }
 
@@ -2325,7 +2406,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;
@@ -2350,7 +2431,7 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 		data->arg.u.device.specdata1 = MAJOR(rdev);
 		data->arg.u.device.specdata2 = MINOR(rdev);
 	}
-	
+	data->arg.label = label;
 	status = nfs4_do_create(dir, dentry, data);
 
 	nfs4_free_createdata(data);
@@ -2362,12 +2443,27 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr, dev_t rdev)
 {
 	struct nfs4_exception exception = { };
+	struct nfs4_label l, *label = NULL;
 	int err;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+		err = security_dentry_init_security(dentry,
+				sattr->ia_mode, &l.label, &l.len);
+		if (err == 0)
+			label = &l;
+	}
+#endif
+
 	do {
 		err = nfs4_handle_exception(NFS_SERVER(dir),
-				_nfs4_proc_mknod(dir, dentry, sattr, rdev),
+				_nfs4_proc_mknod(dir, dentry, sattr, label, rdev),
 				&exception);
 	} while (exception.retry);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		security_release_secctx(l.label, l.len);
+#endif
 	return err;
 }
 
@@ -2815,6 +2911,163 @@ 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;
+	u32 bitmask[2] = { 0, FATTR4_WORD1_SECURITY_LABEL };
+	struct nfs4_getattr_arg args = {
+		.fh		= NFS_FH(inode),
+		.bitmask	= bitmask,
+	};
+	struct nfs4_getattr_res res = {
+		.fattr		= &fattr,
+		.server		= server,
+	};
+	struct rpc_message msg = {
+		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
+		.rpc_argp	= &args,
+		.rpc_resp	= &res,
+	};
+	int ret;
+
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+	nfs_fattr_alloc(&fattr, GFP_KERNEL);
+	nfs_fattr_init(&fattr);
+
+	ret = rpc_call_sync(server->client, &msg, 0);
+	if (ret)
+		goto out;
+	if (!(fattr.bitmap[1] & FATTR4_WORD1_SECURITY_LABEL))
+		return -ENOENT;
+	if (buflen < fattr.label_len) {
+		ret = -ERANGE;
+		goto out;
+	}
+	memcpy(buf, fattr.label, fattr.label_len);
+out:
+	nfs_fattr_fini(&fattr);
+	return ret;
+}
+
+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 *label,
+				      struct nfs_fattr *fattr,
+				      struct nfs4_state *state)
+{
+
+	struct iattr sattr;
+	struct nfs_server *server = NFS_SERVER(inode);
+	const u32 bitmask[2] = { 0, FATTR4_WORD1_SECURITY_LABEL };
+	struct nfs_setattrargs args = {
+		.fh             = NFS_FH(inode),
+		.iap            = &sattr,
+		.server		= server,
+		.bitmask	= bitmask,
+		.label		= label,
+	};
+	struct nfs_setattrres res = {
+		.fattr		= fattr,
+		.server		= server,
+	};
+	struct rpc_message msg = {
+		.rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
+		.rpc_argp       = &args,
+		.rpc_resp       = &res,
+	};
+	unsigned long timestamp = jiffies;
+	int status;
+
+	memset(&sattr, 0, sizeof(struct iattr));
+
+	if (nfs4_copy_delegation_stateid(&args.stateid, inode)) {
+		/* Use that stateid */
+	} else if (state != NULL) {
+		msg.rpc_cred = state->owner->so_cred;
+		nfs4_copy_stateid(&args.stateid, state, current->files);
+	} else
+		memcpy(&args.stateid, &zero_stateid, sizeof(args.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 *label,
+				     struct nfs_fattr *fattr,
+				     struct nfs4_state *state)
+{
+	struct nfs4_exception exception = { };
+	int err;
+
+	do {
+		err = nfs4_handle_exception(NFS_SERVER(inode),
+			_nfs4_do_set_security_label(inode, label, fattr, 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 label;
+	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;
+
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+	nfs_fattr_alloc(&fattr, GFP_KERNEL);
+	nfs_fattr_init(&fattr);
+
+	label.label = (char *)buf;
+	label.len = buflen;
+
+	cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+	if (IS_ERR(cred))
+		return PTR_ERR(cred);
+
+	/* 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, &label, &fattr, state);
+	if (status == 0)
+		nfs_setsecurity(inode, &fattr);
+	if (ctx != NULL)
+		put_nfs_open_context(ctx);
+	put_rpccred(cred);
+	nfs_fattr_fini(&fattr);
+	return status;
+}
+#endif	/* CONFIG_NFS_V4_SECURITY_LABEL */
+
 static int
 nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server)
 {
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index b916297..3e53fb7 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -601,7 +601,7 @@ static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *ve
 	xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE);
 }
 
-static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
+static int 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];
@@ -651,6 +651,10 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
 		}
 		len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
 	}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		len += 4 + (XDR_QUADLEN(label->len) << 2);
+#endif
 	if (iap->ia_valid & ATTR_ATIME_SET)
 		len += 16;
 	else if (iap->ia_valid & ATTR_ATIME)
@@ -709,6 +713,13 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
 		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
 		WRITE32(NFS4_SET_TO_SERVER_TIME);
 	}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL) {
+		bmval1 |= FATTR4_WORD1_SECURITY_LABEL;
+		WRITE32(label->len);
+		WRITEMEM(label->label, label->len);
+	}
+#endif
 	
 	/*
 	 * Now we backfill the bitmap and the attribute buffer length.
@@ -792,7 +803,7 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c
 	WRITE32(create->name->len);
 	WRITEMEM(create->name->name, create->name->len);
 
-	return encode_attrs(xdr, create->attrs, create->server);
+	return encode_attrs(xdr, create->attrs, create->label, create->server);
 }
 
 static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
@@ -1000,7 +1011,7 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
 	switch(arg->open_flags & O_EXCL) {
 		case 0:
 			WRITE32(NFS4_CREATE_UNCHECKED);
-			encode_attrs(xdr, arg->u.attrs, arg->server);
+			encode_attrs(xdr, arg->u.attrs, arg->label, arg->server);
 			break;
 		default:
 			WRITE32(NFS4_CREATE_EXCLUSIVE);
@@ -1301,7 +1312,7 @@ static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *
         WRITE32(OP_SETATTR);
 	WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE);
 
-        if ((status = encode_attrs(xdr, arg->iap, server)))
+        if ((status = encode_attrs(xdr, arg->iap, arg->label, server)))
 		return status;
 
         return 0;
@@ -2954,6 +2965,39 @@ static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, str
 	return status;
 }
 
+static int decode_attr_security_label(struct xdr_stream *xdr, uint32_t *bitmap, char **ctx, u32 *ctxlen)
+{
+	__u32 len;
+	__be32 *p;
+	int rc = 0;
+
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_SECURITY_LABEL - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_SECURITY_LABEL)) {
+		READ_BUF(4);
+		READ32(len);
+		READ_BUF(len);
+		if (len < XDR_MAX_NETOBJ && len < NFS4_MAX_CONTEXT_LEN) {
+			if (*ctx != NULL) {
+				if (*ctxlen < len) {
+					printk(KERN_ERR
+						"%s(): ctxlen %d < len %d\n",
+						__func__, *ctxlen, len);
+					/* rc = -ENOMEM; */
+					*ctx = NULL;	/* leak */
+				} else {
+					memcpy(*ctx, p, len);
+				}
+			}
+			*ctxlen = len;
+		} else
+			printk(KERN_WARNING "%s: label too long (%u)!\n",
+					__FUNCTION__, len);
+		bitmap[1] &= ~FATTR4_WORD1_SECURITY_LABEL;
+	}
+	return rc;
+}
+
 static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
 {
 	unsigned int attrwords = XDR_QUADLEN(attrlen);
@@ -3188,6 +3232,9 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
 		goto xdr_error;
 	if ((status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid)) != 0)
 		goto xdr_error;
+	if ((status = decode_attr_security_label(xdr, bitmap,
+				&fattr->label, &fattr->label_len)) != 0)
+		goto xdr_error;
 	if (fattr->fileid == 0 && fileid != 0)
 		fattr->fileid = fileid;
 	if ((status = verify_attr_len(xdr, savep, attrlen)) == 0)
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 81cf6c5..bca62c1 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -554,8 +554,13 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
 		nfs_show_mountd_options(m, nfss, showdefaults);
 
 #ifdef CONFIG_NFS_V4
-	if (clp->rpc_ops->version == 4)
+	if (clp->rpc_ops->version == 4) {
 		seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		if (nfss->caps & NFS_CAP_SECURITY_LABEL)
+			seq_printf(m, ",security_label");
+#endif
+	}
 #endif
 }
 
@@ -612,6 +617,10 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
 		seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
 		seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
 		seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		if (nfss->caps & NFS_CAP_SECURITY_LABEL)
+			seq_printf(m, ",security_label");
+#endif
 	}
 #endif
 
@@ -2367,6 +2376,11 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
 		goto error_splat_super;
 	}
 
+#ifdef CONFIG_SECURITY_SELINUX
+	if (server->caps & NFS_CAP_SECURITY_LABEL)
+		security_sb_parse_opts_str("native_labels", &data->lsm_opts);
+#endif
+
 	error = security_sb_set_mnt_opts(s, &data->lsm_opts);
 	if (error)
 		goto error_splat_root;
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 192c056..7fdb309 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -196,6 +196,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
@@ -341,6 +342,7 @@ extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *map
 extern int nfs_revalidate_mapping_nolock(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);
 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, int mode);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 05a10be..f388235 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2851,7 +2851,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;
 }
 
@@ -2941,7 +2944,9 @@ 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.5.5.1

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

* [PATCH 13/14] NFS: Extend NFS xattr handlers to accept the security namespace
       [not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
                     ` (6 preceding siblings ...)
  2008-09-29 17:06   ` [PATCH 12/14] NFS: Client implementation of Labeled-NFS David P. Quigley
@ 2008-09-29 17:06   ` David P. Quigley
  2008-09-29 17:06   ` [PATCH 14/14] NFSD: Server implementation of MAC Labeling David P. Quigley
  8 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
  To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
	casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
	matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
	trond.myklebust-41N18TsMXrtuMpJDpNschA,
	bfields-uC3wQj2KruNg9hUCZPvPmw
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	linux-security-module-u79uwXL29TY76Z2rM5mHXA,
	selinux-+05T5uksL2qpZYMLLGbcSA,
	labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
	Matthew N. Dodd

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-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
 fs/nfs/nfs4proc.c   |   52 ++++++++++++++++++++++++++++++++++++++++----------
 security/security.c |    1 +
 2 files changed, 42 insertions(+), 11 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 622bf71..845e1da 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3934,10 +3934,17 @@ int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf,
 {
 	struct inode *inode = dentry->d_inode;
 
-	if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0)
-		return -EOPNOTSUPP;
-
-	return nfs4_proc_set_acl(inode, buf, buflen);
+	if (strcmp(key, XATTR_NAME_NFSV4_ACL) == 0) {
+		if (!S_ISREG(inode->i_mode) &&
+		   (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
+			return -EPERM;
+		return nfs4_proc_set_acl(inode, buf, buflen);
+	}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (security_ismaclabel(key))
+		return nfs4_set_security_label(dentry, buf, buflen);
+#endif
+	return -EOPNOTSUPP;
 }
 
 /* The getxattr man page suggests returning -ENODATA for unknown attributes,
@@ -3949,22 +3956,45 @@ ssize_t nfs4_getxattr(struct dentry *dentry, const char *key, void *buf,
 {
 	struct inode *inode = dentry->d_inode;
 
-	if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0)
-		return -EOPNOTSUPP;
+	if (strcmp(key, XATTR_NAME_NFSV4_ACL) == 0)
+		return nfs4_proc_get_acl(inode, buf, buflen);
 
-	return nfs4_proc_get_acl(inode, buf, buflen);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (security_ismaclabel(key))
+		return nfs4_get_security_label(inode, buf, buflen);
+#endif
+	return -EOPNOTSUPP;
 }
 
 ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
 {
-	size_t len = strlen(XATTR_NAME_NFSV4_ACL) + 1;
+	size_t len = 0, l;
+	char *p;
 
-	if (!nfs4_server_supports_acls(NFS_SERVER(dentry->d_inode)))
+	if (nfs4_server_supports_acls(NFS_SERVER(dentry->d_inode)))
+		len += strlen(XATTR_NAME_NFSV4_ACL) + 1;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (nfs_server_capable(dentry->d_inode, NFS_CAP_SECURITY_LABEL))
+		len += security_inode_listsecurity(dentry->d_inode, NULL, 0);
+#endif
+	if (!len)
 		return 0;
 	if (buf && buflen < len)
 		return -ERANGE;
-	if (buf)
-		memcpy(buf, XATTR_NAME_NFSV4_ACL, len);
+	if (!buf)
+		return len;
+
+	p = buf;
+	if (nfs4_server_supports_acls(NFS_SERVER(dentry->d_inode))) {
+		l = strlen(XATTR_NAME_NFSV4_ACL) + 1;
+		memcpy(p, XATTR_NAME_NFSV4_ACL, l);
+		p += l;
+	}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (nfs_server_capable(dentry->d_inode, NFS_CAP_SECURITY_LABEL))
+		p += security_inode_listsecurity(dentry->d_inode, p,
+			buflen - (p - buf));
+#endif
 	return len;
 }
 
diff --git a/security/security.c b/security/security.c
index 2337d7f..44d6e37 100644
--- a/security/security.c
+++ b/security/security.c
@@ -536,6 +536,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.5.5.1

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

* [PATCH 14/14] NFSD: Server implementation of MAC Labeling
       [not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
                     ` (7 preceding siblings ...)
  2008-09-29 17:06   ` [PATCH 13/14] NFS: Extend NFS xattr handlers to accept the security namespace David P. Quigley
@ 2008-09-29 17:06   ` David P. Quigley
  8 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
  To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
	casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
	matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
	trond.myklebust-41N18TsMXrtuMpJDpNschA,
	bfields-uC3wQj2KruNg9hUCZPvPmw
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	linux-security-module-u79uwXL29TY76Z2rM5mHXA,
	selinux-+05T5uksL2qpZYMLLGbcSA,
	labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
	Matthew N. Dodd

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-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
 fs/nfsd/export.c          |    3 +
 fs/nfsd/nfs4proc.c        |   25 +++++++++++-
 fs/nfsd/nfs4xdr.c         |  101 ++++++++++++++++++++++++++++++++++++++++++---
 fs/nfsd/vfs.c             |   22 ++++++++++
 include/linux/nfsd/nfsd.h |    2 +
 5 files changed, 146 insertions(+), 7 deletions(-)

diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 9dc036f..2523420 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1436,6 +1436,9 @@ static struct flags {
 	{ NFSEXP_ALLSQUASH, {"all_squash", ""}},
 	{ NFSEXP_ASYNC, {"async", "sync"}},
 	{ NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+	{ NFSEXP_SECURITY_LABEL, {"security_label", ""}},
+#endif
 	{ NFSEXP_NOHIDE, {"nohide", ""}},
 	{ NFSEXP_CROSSMOUNT, {"crossmnt", ""}},
 	{ NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index e5b51ff..b5576ed 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -49,6 +49,10 @@
 #include <linux/nfs4_acl.h>
 #include <linux/sunrpc/gss_api.h>
 
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+#include <linux/security.h>
+#endif
+
 #define NFSDDBG_FACILITY		NFSDDBG_PROC
 
 static inline void
@@ -103,6 +107,13 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
 					(u32 *)open->op_verf.data,
 					&open->op_truncate, &created);
 
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+		if (!status && open->op_label != NULL)
+		/* Is it appropriate to just kick back an error? */
+			status = security_inode_setsecctx(resfh.fh_dentry,
+				open->op_label->label, open->op_label->len);
+#endif
+
 		/* If we ever decide to use different attrs to store the
 		 * verifier in nfsd_create_v3, then we'll need to change this
 		 */
@@ -432,6 +443,13 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 		status = nfserr_badtype;
 	}
 
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+	if (!status && create->cr_label != NULL)
+		/* Is it appropriate to just kick back an error? */
+		status = security_inode_setsecctx(resfh.fh_dentry,
+			create->cr_label->label, create->cr_label->len);
+#endif
+
 	if (!status) {
 		fh_unlock(&cstate->current_fh);
 		set_change_info(&create->cr_cinfo, &cstate->current_fh);
@@ -670,6 +688,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:
@@ -964,7 +987,7 @@ out:
 	return status;
 }
 
-static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = {
+static struct nfsd4_operation nfsd4_ops[LAST_NFS4_OP+1] = {
 	[OP_ACCESS] = {
 		.op_func = (nfsd4op_func)nfsd4_access,
 		.op_name = "OP_ACCESS",
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 14ba4d9..84019d4 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -59,6 +59,10 @@
 #include <linux/sunrpc/gss_api.h>
 #include <linux/sunrpc/svcauth_gss.h>
 
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+#include <linux/security.h>
+#endif
+
 #define NFSDDBG_FACILITY		NFSDDBG_XDR
 
 /*
@@ -249,7 +253,7 @@ 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 nfs4_acl **acl, struct nfs4_label **label)
 {
 	int expected_len, len = 0;
 	u32 dummy32;
@@ -402,6 +406,36 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia
 			goto xdr_error;
 		}
 	}
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+	if (bmval[1] & FATTR4_WORD1_SECURITY_LABEL) {
+		*label = kzalloc(sizeof(struct nfs4_label), GFP_ATOMIC);
+		if (*label == NULL) {
+			host_err = -ENOMEM;
+			goto out_nfserr;
+		}
+
+		READ_BUF(4);
+		len += 4;
+		READ32(dummy32);
+		READ_BUF(dummy32);
+		len += (XDR_QUADLEN(dummy32) << 2);
+		READMEM(buf, dummy32);
+		(*label)->len = dummy32;
+
+		(*label)->label = kmalloc(dummy32 + 1, GFP_ATOMIC);
+		if ((*label)->label == NULL) {
+			host_err = -ENOMEM;
+			kfree(*label);
+			goto out_nfserr;
+		}
+
+		memcpy((*label)->label, buf, dummy32);
+		((char *)(*label)->label)[dummy32 + 1] = '\0';
+
+		defer_free(argp, kfree, (*label)->label);
+		defer_free(argp, kfree, *label);
+	}
+#endif
 	if (len != expected_len)
 		goto xdr_error;
 
@@ -484,7 +518,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
 	if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval)))
 		return status;
 
-	if ((status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, &create->cr_acl)))
+	if ((status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, &create->cr_acl, &create->cr_label)))
 		goto out;
 
 	DECODE_TAIL;
@@ -645,7 +679,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
 		switch (open->op_createmode) {
 		case NFS4_CREATE_UNCHECKED:
 		case NFS4_CREATE_GUARDED:
-			if ((status = nfsd4_decode_fattr(argp, open->op_bmval, &open->op_iattr, &open->op_acl)))
+			if ((status = nfsd4_decode_fattr(argp, open->op_bmval, &open->op_iattr, &open->op_acl, &open->op_label)))
 				goto out;
 			break;
 		case NFS4_CREATE_EXCLUSIVE:
@@ -839,7 +873,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta
 	READ_BUF(sizeof(stateid_t));
 	READ32(setattr->sa_stateid.si_generation);
 	COPYMEM(&setattr->sa_stateid.si_opaque, sizeof(stateid_opaque_t));
-	if ((status = nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, &setattr->sa_acl)))
+	if ((status = nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, &setattr->sa_acl, &setattr->sa_label)))
 		goto out;
 
 	DECODE_TAIL;
@@ -905,7 +939,7 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify
 	 * nfsd4_proc_verify; however we still decode here just to return
 	 * correct error in case of bad xdr. */
 #if 0
-	status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl);
+	status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl, &ve_label);
 	if (status == nfserr_inval) {
 		status = nfserrno(status);
 		goto out;
@@ -1368,6 +1402,34 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
 	return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen);
 }
 
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+static inline __be32
+nfsd4_encode_security_label(struct svc_rqst *rqstp, struct dentry *dentry, __be32 **p, int *buflen)
+{
+	void *context;
+	int err;
+	int len;
+
+	err = 0;
+	(void)security_inode_getsecctx(dentry->d_inode, &context, &len);
+	if (len < 0)
+		return nfserrno(len);
+
+	if (*buflen < ((XDR_QUADLEN(len) << 2) + 4)) {
+		err = nfserr_resource;
+		goto out;
+	}
+
+	*p = xdr_encode_opaque(*p, context, len);
+	*buflen -= (XDR_QUADLEN(len) << 2) + 4;
+	BUG_ON(*buflen < 0);
+
+out:
+	security_release_secctx(context, len);
+	return err;
+}
+#endif
+
 #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
 			      FATTR4_WORD0_RDATTR_ERROR)
 #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
@@ -1463,6 +1525,14 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
 			bmval0 &= ~FATTR4_WORD0_FS_LOCATIONS;
 		}
 	}
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+	if (bmval1 & FATTR4_WORD1_SECURITY_LABEL) {
+		if (/* XXX !selinux_enabled */ 0)
+			bmval1 &= ~FATTR4_WORD1_SECURITY_LABEL;
+	}
+#else
+	bmval1 &= ~FATTR4_WORD1_SECURITY_LABEL;
+#endif
 	if ((buflen -= 16) < 0)
 		goto out_resource;
 
@@ -1473,15 +1543,24 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
 
 	if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
 		u32 word0 = NFSD_SUPPORTED_ATTRS_WORD0;
+		u32 word1 = NFSD_SUPPORTED_ATTRS_WORD1;
 		if ((buflen -= 12) < 0)
 			goto out_resource;
 		if (!aclsupport)
 			word0 &= ~FATTR4_WORD0_ACL;
 		if (!exp->ex_fslocs.locations)
 			word0 &= ~FATTR4_WORD0_FS_LOCATIONS;
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+		if (exp->ex_flags & NFSEXP_SECURITY_LABEL)
+			word1 |= FATTR4_WORD1_SECURITY_LABEL;
+		else
+			word1 &= ~FATTR4_WORD1_SECURITY_LABEL;
+#else
+		word1 &= ~FATTR4_WORD1_SECURITY_LABEL;
+#endif
 		WRITE32(2);
 		WRITE32(word0);
-		WRITE32(NFSD_SUPPORTED_ATTRS_WORD1);
+		WRITE32(word1);
 	}
 	if (bmval0 & FATTR4_WORD0_TYPE) {
 		if ((buflen -= 4) < 0)
@@ -1791,6 +1870,16 @@ out_acl:
 		}
 		WRITE64(stat.ino);
 	}
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+	if (bmval1 & FATTR4_WORD1_SECURITY_LABEL) {
+		status = nfsd4_encode_security_label(rqstp, dentry,
+				&p, &buflen);
+		if (status == nfserr_resource)
+			goto out_resource;
+		if (status)
+			goto out;
+	}
+#endif
 	*attrlenp = htonl((char *)p - (char *)attrlenp - 4);
 	*countp = p - buffer;
 	status = nfs_ok;
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 18060be..7113705 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -553,6 +553,28 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_ac
 	return error;
 }
 
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+__be32
+nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
+    struct nfs4_label *label)
+{
+	__be32 error;
+	int host_error;
+	struct dentry *dentry;
+
+	/* Get inode */
+	/* XXX: should we have a MAY_SSECCTX? */
+	error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR);
+	if (error)
+		return error;
+
+	dentry = fhp->fh_dentry;
+
+	host_error = security_inode_setsecctx(dentry, label->label, label->len);
+	return nfserrno(host_error);
+}
+#endif
+
 #endif /* defined(CONFIG_NFS_V4) */
 
 #ifdef CONFIG_NFSD_V3
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index f329b96..0b8a8cb 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -86,6 +86,8 @@ __be32		nfsd_setattr(struct svc_rqst *, struct svc_fh *,
 __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,
-- 
1.5.5.1

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

* Re: [PATCH 01/14] VFS: Factor out part of vfs_setxattr so it can be called from the SELinux hook for inode_setsecctx.
  2008-09-29 17:06 ` [PATCH 01/14] VFS: Factor out part of vfs_setxattr so it can be called from the SELinux hook for inode_setsecctx David P. Quigley
@ 2008-09-30 19:51   ` Serge E. Hallyn
  0 siblings, 0 replies; 33+ messages in thread
From: Serge E. Hallyn @ 2008-09-30 19:51 UTC (permalink / raw)
  To: David P. Quigley
  Cc: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields,
	linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs

Quoting David P. Quigley (dpquigl@tycho.nsa.gov):
> This factors out the part of the vfs_setxattr function that performs the
> setting of the xattr and its notification. This is needed so the SELinux
> implementation of inode_setsecctx can handle the setting of it's xattr while
> maintaining the proper separation of layers.
> 
> Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>

This part surely looks reasonable.

Acked-by: Serge Hallyn <serue@us.ibm.com>
> ---
>  fs/xattr.c            |   55 +++++++++++++++++++++++++++++++++++++-----------
>  include/linux/xattr.h |    1 +
>  2 files changed, 43 insertions(+), 13 deletions(-)
> 
> diff --git a/fs/xattr.c b/fs/xattr.c
> index 468377e..2f93006 100644
> --- a/fs/xattr.c
> +++ b/fs/xattr.c
> @@ -66,22 +66,28 @@ xattr_permission(struct inode *inode, const char *name, int mask)
>  	return inode_permission(inode, mask);
>  }
> 
> -int
> -vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
> -		size_t size, int flags)
> +/**
> + *  __vfs_setxattr_noperm - perform setxattr operation without performing
> + *  permission checks.
> + *
> + *  @dentry - object to perform setxattr on
> + *  @name - xattr name to set
> + *  @value - value to set @name to
> + *  @size - size of @value
> + *  @flags - flags to pass into filesystem operations
> + *
> + *  returns the result of the internal setxattr or setsecurity operations.
> + *
> + *  This function requires the caller to lock the inode's i_mutex before it
> + *  is executed. It also assumes that the caller will make the appropriate
> + *  permission checks.
> + */
> +int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
> +		const void *value, size_t size, int flags)
>  {
>  	struct inode *inode = dentry->d_inode;
> -	int error;
> -
> -	error = xattr_permission(inode, name, MAY_WRITE);
> -	if (error)
> -		return error;
> +	int error = -EOPNOTSUPP;
> 
> -	mutex_lock(&inode->i_mutex);
> -	error = security_inode_setxattr(dentry, name, value, size, flags);
> -	if (error)
> -		goto out;
> -	error = -EOPNOTSUPP;
>  	if (inode->i_op->setxattr) {
>  		error = inode->i_op->setxattr(dentry, name, value, size, flags);
>  		if (!error) {
> @@ -97,6 +103,29 @@ vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
>  		if (!error)
>  			fsnotify_xattr(dentry);
>  	}
> +
> +	return error;
> +}
> +
> +
> +int
> +vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
> +		size_t size, int flags)
> +{
> +	struct inode *inode = dentry->d_inode;
> +	int error;
> +
> +	error = xattr_permission(inode, name, MAY_WRITE);
> +	if (error)
> +		return error;
> +
> +	mutex_lock(&inode->i_mutex);
> +	error = security_inode_setxattr(dentry, name, value, size, flags);
> +	if (error)
> +		goto out;
> +
> +	error = __vfs_setxattr_noperm(dentry, name, value, size, flags);
> +
>  out:
>  	mutex_unlock(&inode->i_mutex);
>  	return error;
> diff --git a/include/linux/xattr.h b/include/linux/xattr.h
> index d131e35..5c84af8 100644
> --- a/include/linux/xattr.h
> +++ b/include/linux/xattr.h
> @@ -49,6 +49,7 @@ struct xattr_handler {
>  ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
>  ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t);
>  ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
> +int __vfs_setxattr_noperm(struct dentry *, const char *, const void *, size_t, int);
>  int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int);
>  int vfs_removexattr(struct dentry *, const char *);
> 
> -- 
> 1.5.5.1
> 
> --
> 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

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

* Re: [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information.
  2008-09-29 17:06   ` [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information David P. Quigley
@ 2008-09-30 20:01     ` Serge E. Hallyn
  2008-10-06 20:52       ` David P. Quigley
  2008-09-30 20:22     ` Serge E. Hallyn
  1 sibling, 1 reply; 33+ messages in thread
From: Serge E. Hallyn @ 2008-09-30 20:01 UTC (permalink / raw)
  To: David P. Quigley
  Cc: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields,
	linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs

Quoting David P. Quigley (dpquigl@tycho.nsa.gov):
> This patch introduces three new hooks. The inode_getsecctx hook is used to get
> all relevant information from an LSM about an inode. The inode_setsecctx is
> used to set both the in-core and on-disk state for the inode based on a context
> derived from inode_getsecctx.The final hook inode_notifysecctx will notify the
> LSM of a change for the in-core state of the inode in question. These hooks are
> for use in the labeled NFS code and addresses concerns of how to set security
> on an inode in a multi-xattr LSM. For historical reasons Stephen Smalley's
> explanation of the reason for these hooks is pasted below.
> 
> Quote Stephen Smalley
> 
> inode_setsecctx:  Change the security context of an inode.  Updates the
> in core security context managed by the security module and invokes the
> fs code as needed (via __vfs_setxattr_noperm) to update any backing
> xattrs that represent the context.  Example usage:  NFS server invokes
> this hook to change the security context in its incore inode and on the
> backing file system to a value provided by the client on a SETATTR
> operation.
> 
> inode_notifysecctx:  Notify the security module of what the security
> context of an inode should be.  Initializes the incore security context
> managed by the security module for this inode.  Example usage:  NFS
> client invokes this hook to initialize the security context in its
> incore inode to the value provided by the server for the file when the
> server returned the file's attributes to the client.
> 
> Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
> ---
>  include/linux/security.h |   50 ++++++++++++++++++++++++++++++++++++++++++++++
>  security/security.c      |   18 ++++++++++++++++
>  security/selinux/hooks.c |   25 +++++++++++++++++++++++
>  3 files changed, 93 insertions(+), 0 deletions(-)
> 
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 80c4d00..8b5b041 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -1289,6 +1289,36 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
>   *	audit_rule_init.
>   *	@rule contains the allocated rule
>   *
> + * @inode_notifysecctx:
> + *	Notify the security module of what the security context of an inode
> + *	should be.  Initializes the incore security context managed by the
> + *	security module for this inode.  Example usage:  NFS client invokes
> + *	this hook to initialize the security context in its incore inode to the
> + *	value provided by the server for the file when the server returned the
> + *	file's attributes to the client.
> + *
> + * 	@inode we wish to set the security context of.
> + * 	@ctx contains the string which we wish to set in the inode.
> + * 	@ctxlen contains the length of @ctx.
> + *
> + * @inode_setsecctx:
> + * 	Change the security context of an inode.  Updates the
> + * 	incore security context managed by the security module and invokes the
> + * 	fs code as needed (via __vfs_setxattr_noperm) to update any backing
> + * 	xattrs that represent the context.  Example usage:  NFS server invokes
> + * 	this hook to change the security context in its incore inode and on the
> + * 	backing filesystem to a value provided by the client on a SETATTR
> + * 	operation.
> + *
> + * 	@dentry contains the inode we wish to set the security context of.
> + * 	@ctx contains the string which we wish to set in the inode.
> + * 	@ctxlen contains the length of @ctx.
> + *
> + * @inode_getsecctx:
> + * 	Returns a string containing all relavent security context information
> + * 	@inode we wish to set the security context of.
> + *	@ctx is a pointer to place the allocated security context should be placed.

sentence above is odd.  How about

	@ctx is a pointer in which to place the allocated security context

> + *	@ctxlen points to the place to put the length of @ctx.
>   * This is the main security structure.
>   */
>  struct security_operations {
> @@ -1479,6 +1509,10 @@ struct security_operations {
>  	int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
>  	void (*release_secctx) (char *secdata, u32 seclen);
> 
> +	int (*inode_notifysecctx)(struct inode *inode, void *ctx, u32 ctxlen);
> +	int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen);
> +	int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen);
> +
>  #ifdef CONFIG_SECURITY_NETWORK
>  	int (*unix_stream_connect) (struct socket *sock,
>  				    struct socket *other, struct sock *newsk);
> @@ -1727,6 +1761,9 @@ 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);
> 
> +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
> +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
> +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
>  #else /* CONFIG_SECURITY */
>  struct security_mnt_opts {
>  };
> @@ -2458,6 +2495,19 @@ static inline int security_secctx_to_secid(const char *secdata,
>  static inline void security_release_secctx(char *secdata, u32 seclen)
>  {
>  }
> +
> +static inline int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> +{
> +	return -EOPNOTSUPP;
> +}
> +static inline int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> +{
> +	return -EOPNOTSUPP;
> +}
> +static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> +{
> +	return -EOPNOTSUPP;
> +}
>  #endif	/* CONFIG_SECURITY */
> 
>  #ifdef CONFIG_SECURITY_NETWORK
> diff --git a/security/security.c b/security/security.c
> index 3a4b4f5..d0fd42a 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -869,6 +869,24 @@ void security_release_secctx(char *secdata, u32 seclen)
>  }
>  EXPORT_SYMBOL(security_release_secctx);
> 
> +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> +{
> +	return security_ops->inode_notifysecctx(inode, ctx, ctxlen);
> +}
> +EXPORT_SYMBOL(security_inode_notifysecctx);
> +
> +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> +{
> +	return security_ops->inode_setsecctx(dentry, ctx, ctxlen);
> +}
> +EXPORT_SYMBOL(security_inode_setsecctx);
> +
> +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> +{
> +	return security_ops->inode_getsecctx(inode, ctx, ctxlen);
> +}
> +EXPORT_SYMBOL(security_inode_getsecctx);
> +
>  #ifdef CONFIG_SECURITY_NETWORK
> 
>  int security_unix_stream_connect(struct socket *sock, struct socket *other,
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 03fc6a8..b07871b 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -5285,6 +5285,28 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
>  	kfree(secdata);
>  }
> 
> +/*
> + *	This hook requires that the inode i_mutex be locked

'called with inode->i_mutex locked' would make more sense here.
Requirements on the callers would make more sense in the comments
in include/linux/security.h, right?

No code objections, though.

Acked-by: Serge Hallyn <serue@us.ibm.com>

> + */
> +static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> +{
> +	return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
> +}
> +
> +/*
> + *	This hook requires that the inode i_mutex be locked
> + */
> +static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> +{
> +	return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
> +}
> +
> +static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> +{
> +	*ctxlen = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
> +						ctx, true);
> +	return *ctxlen;
> +}
>  #ifdef CONFIG_KEYS
> 
>  static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
> @@ -5491,6 +5513,9 @@ static struct security_operations selinux_ops = {
>  	.secid_to_secctx =		selinux_secid_to_secctx,
>  	.secctx_to_secid =		selinux_secctx_to_secid,
>  	.release_secctx =		selinux_release_secctx,
> +	.inode_notifysecctx =		selinux_inode_notifysecctx,
> +	.inode_setsecctx =		selinux_inode_setsecctx,
> +	.inode_getsecctx =		selinux_inode_getsecctx,
> 
>  	.unix_stream_connect =		selinux_socket_unix_stream_connect,
>  	.unix_may_send =		selinux_socket_unix_may_send,
> -- 
> 1.5.5.1
> 
> 
> --
> 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] 33+ messages in thread

* Re: [PATCH 03/14] Security: Add hook to calculate context based on a negative dentry.
  2008-09-29 17:06   ` [PATCH 03/14] Security: Add hook to calculate context based on a negative dentry David P. Quigley
@ 2008-09-30 20:15     ` Serge E. Hallyn
       [not found]       ` <20080930201524.GC21039-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 33+ messages in thread
From: Serge E. Hallyn @ 2008-09-30 20:15 UTC (permalink / raw)
  To: David P. Quigley
  Cc: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields,
	linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs

Quoting David P. Quigley (dpquigl@tycho.nsa.gov):
> 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: David P. Quigley <dpquigl@tycho.nsa.gov>
> ---
>  include/linux/security.h |   14 ++++++++++++++
>  security/security.c      |    7 +++++++
>  security/selinux/hooks.c |   36 ++++++++++++++++++++++++++++++++++++
>  3 files changed, 57 insertions(+), 0 deletions(-)
> 
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 8b5b041..42b9128 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -1379,6 +1379,9 @@ 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,
> +				     void **ctx, u32 *ctxlen);

This of course needs a description at top of include/linux/security.h.

> +
> 
>  	int (*inode_alloc_security) (struct inode *inode);
>  	void (*inode_free_security) (struct inode *inode);
> @@ -1651,6 +1654,8 @@ 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,
> +				   void **ctx, u32 *ctxlen);
> 
>  int security_inode_alloc(struct inode *inode);
>  void security_inode_free(struct inode *inode);
> @@ -1994,6 +1999,15 @@ 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,
> +						 void **ctx,
> +						 u32 *ctxlen)
> +{
> +	return -EOPNOTSUPP;
> +}
> +
> +
>  static inline int security_inode_init_security(struct inode *inode,
>  						struct inode *dir,
>  						char **name,
> diff --git a/security/security.c b/security/security.c
> index d0fd42a..b22a110 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -349,6 +349,13 @@ void security_inode_free(struct inode *inode)
>  	security_ops->inode_free_security(inode);
>  }
> 
> +int security_dentry_init_security (struct dentry *dentry, int mode,
> +				   void **ctx, u32 *ctxlen)
> +{
> +	return security_ops->dentry_init_security (dentry, mode, ctx, ctxlen);
> +}
> +EXPORT_SYMBOL(security_dentry_init_security);
> +
>  int security_inode_init_security(struct inode *inode, struct inode *dir,
>  				  char **name, void **value, size_t *len)
>  {
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index b07871b..680db1d 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -2504,6 +2504,41 @@ static void selinux_inode_free_security(struct inode *inode)
>  	inode_free_security(inode);
>  }
> 
> +/*
> + * For now, we need a way to compute a SID for

Just 'Compute a SID for...' ?

> + * a dentry as the inode is not yet available
> + * (and under NFSv4 has no label backed by an EA anyway.
> + */
> +static int selinux_dentry_init_security(struct dentry *dentry, int mode, void **ctx, u32 *ctxlen)
> +{
> +	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 = current->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),
> +					     &newsid);
> +		if (rc) {
> +			printk(KERN_WARNING "%s:  "
> +			       "security_transition_sid failed, rc=%d\n",
> +			       __FUNCTION__, -rc);
> +			return rc;
> +		}
> +	}
> +
> +	return security_sid_to_context(newsid, (char **)ctx, ctxlen);
> +}
> +
>  static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
>  				       char **name, void **value,
>  				       size_t *len)
> @@ -5413,6 +5448,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.5.5.1
> 
> 
> --
> 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] 33+ messages in thread

* Re: [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information.
  2008-09-29 17:06   ` [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information David P. Quigley
  2008-09-30 20:01     ` Serge E. Hallyn
@ 2008-09-30 20:22     ` Serge E. Hallyn
  2008-10-06 20:52       ` David P. Quigley
  1 sibling, 1 reply; 33+ messages in thread
From: Serge E. Hallyn @ 2008-09-30 20:22 UTC (permalink / raw)
  To: David P. Quigley
  Cc: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields,
	linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs

Quoting David P. Quigley (dpquigl@tycho.nsa.gov):
> This patch introduces three new hooks. The inode_getsecctx hook is used to get
> all relevant information from an LSM about an inode. The inode_setsecctx is
> used to set both the in-core and on-disk state for the inode based on a context
> derived from inode_getsecctx.The final hook inode_notifysecctx will notify the
> LSM of a change for the in-core state of the inode in question. These hooks are
> for use in the labeled NFS code and addresses concerns of how to set security
> on an inode in a multi-xattr LSM. For historical reasons Stephen Smalley's
> explanation of the reason for these hooks is pasted below.
> 
> Quote Stephen Smalley
> 
> inode_setsecctx:  Change the security context of an inode.  Updates the
> in core security context managed by the security module and invokes the
> fs code as needed (via __vfs_setxattr_noperm) to update any backing
> xattrs that represent the context.  Example usage:  NFS server invokes
> this hook to change the security context in its incore inode and on the
> backing file system to a value provided by the client on a SETATTR
> operation.
> 
> inode_notifysecctx:  Notify the security module of what the security
> context of an inode should be.  Initializes the incore security context
> managed by the security module for this inode.  Example usage:  NFS
> client invokes this hook to initialize the security context in its
> incore inode to the value provided by the server for the file when the
> server returned the file's attributes to the client.
> 
> Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>

Hmm, sorry, for all of these new hooks which you introduce, you do not
define empty cap_* versions and assign them when need in
security_fixup_ops().  But you unconditionally call them if
CONFIG_SECURITY=y.  So if you compile a kernel with CONFIG_SECURITY=y
but CONFIG_SECURITY_SELINUX=n, don't you hose your box?

> ---
>  include/linux/security.h |   50 ++++++++++++++++++++++++++++++++++++++++++++++
>  security/security.c      |   18 ++++++++++++++++
>  security/selinux/hooks.c |   25 +++++++++++++++++++++++
>  3 files changed, 93 insertions(+), 0 deletions(-)
> 
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 80c4d00..8b5b041 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -1289,6 +1289,36 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
>   *	audit_rule_init.
>   *	@rule contains the allocated rule
>   *
> + * @inode_notifysecctx:
> + *	Notify the security module of what the security context of an inode
> + *	should be.  Initializes the incore security context managed by the
> + *	security module for this inode.  Example usage:  NFS client invokes
> + *	this hook to initialize the security context in its incore inode to the
> + *	value provided by the server for the file when the server returned the
> + *	file's attributes to the client.
> + *
> + * 	@inode we wish to set the security context of.
> + * 	@ctx contains the string which we wish to set in the inode.
> + * 	@ctxlen contains the length of @ctx.
> + *
> + * @inode_setsecctx:
> + * 	Change the security context of an inode.  Updates the
> + * 	incore security context managed by the security module and invokes the
> + * 	fs code as needed (via __vfs_setxattr_noperm) to update any backing
> + * 	xattrs that represent the context.  Example usage:  NFS server invokes
> + * 	this hook to change the security context in its incore inode and on the
> + * 	backing filesystem to a value provided by the client on a SETATTR
> + * 	operation.
> + *
> + * 	@dentry contains the inode we wish to set the security context of.
> + * 	@ctx contains the string which we wish to set in the inode.
> + * 	@ctxlen contains the length of @ctx.
> + *
> + * @inode_getsecctx:
> + * 	Returns a string containing all relavent security context information
> + * 	@inode we wish to set the security context of.
> + *	@ctx is a pointer to place the allocated security context should be placed.
> + *	@ctxlen points to the place to put the length of @ctx.
>   * This is the main security structure.
>   */
>  struct security_operations {
> @@ -1479,6 +1509,10 @@ struct security_operations {
>  	int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
>  	void (*release_secctx) (char *secdata, u32 seclen);
> 
> +	int (*inode_notifysecctx)(struct inode *inode, void *ctx, u32 ctxlen);
> +	int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen);
> +	int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen);
> +
>  #ifdef CONFIG_SECURITY_NETWORK
>  	int (*unix_stream_connect) (struct socket *sock,
>  				    struct socket *other, struct sock *newsk);
> @@ -1727,6 +1761,9 @@ 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);
> 
> +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
> +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
> +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
>  #else /* CONFIG_SECURITY */
>  struct security_mnt_opts {
>  };
> @@ -2458,6 +2495,19 @@ static inline int security_secctx_to_secid(const char *secdata,
>  static inline void security_release_secctx(char *secdata, u32 seclen)
>  {
>  }
> +
> +static inline int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> +{
> +	return -EOPNOTSUPP;
> +}
> +static inline int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> +{
> +	return -EOPNOTSUPP;
> +}
> +static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> +{
> +	return -EOPNOTSUPP;
> +}
>  #endif	/* CONFIG_SECURITY */
> 
>  #ifdef CONFIG_SECURITY_NETWORK
> diff --git a/security/security.c b/security/security.c
> index 3a4b4f5..d0fd42a 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -869,6 +869,24 @@ void security_release_secctx(char *secdata, u32 seclen)
>  }
>  EXPORT_SYMBOL(security_release_secctx);
> 
> +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> +{
> +	return security_ops->inode_notifysecctx(inode, ctx, ctxlen);
> +}
> +EXPORT_SYMBOL(security_inode_notifysecctx);
> +
> +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> +{
> +	return security_ops->inode_setsecctx(dentry, ctx, ctxlen);
> +}
> +EXPORT_SYMBOL(security_inode_setsecctx);
> +
> +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> +{
> +	return security_ops->inode_getsecctx(inode, ctx, ctxlen);
> +}
> +EXPORT_SYMBOL(security_inode_getsecctx);
> +
>  #ifdef CONFIG_SECURITY_NETWORK
> 
>  int security_unix_stream_connect(struct socket *sock, struct socket *other,
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 03fc6a8..b07871b 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -5285,6 +5285,28 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
>  	kfree(secdata);
>  }
> 
> +/*
> + *	This hook requires that the inode i_mutex be locked
> + */
> +static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> +{
> +	return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
> +}
> +
> +/*
> + *	This hook requires that the inode i_mutex be locked
> + */
> +static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> +{
> +	return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
> +}
> +
> +static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> +{
> +	*ctxlen = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
> +						ctx, true);
> +	return *ctxlen;
> +}
>  #ifdef CONFIG_KEYS
> 
>  static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
> @@ -5491,6 +5513,9 @@ static struct security_operations selinux_ops = {
>  	.secid_to_secctx =		selinux_secid_to_secctx,
>  	.secctx_to_secid =		selinux_secctx_to_secid,
>  	.release_secctx =		selinux_release_secctx,
> +	.inode_notifysecctx =		selinux_inode_notifysecctx,
> +	.inode_setsecctx =		selinux_inode_setsecctx,
> +	.inode_getsecctx =		selinux_inode_getsecctx,
> 
>  	.unix_stream_connect =		selinux_socket_unix_stream_connect,
>  	.unix_may_send =		selinux_socket_unix_may_send,
> -- 
> 1.5.5.1
> 
> 
> --
> 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] 33+ messages in thread

* Re: [PATCH 06/14] KConfig: Add KConfig entries for Labeled NFS
  2008-09-29 17:06 ` [PATCH 06/14] KConfig: Add KConfig entries for Labeled NFS David P. Quigley
@ 2008-09-30 20:40   ` Serge E. Hallyn
  0 siblings, 0 replies; 33+ messages in thread
From: Serge E. Hallyn @ 2008-09-30 20:40 UTC (permalink / raw)
  To: David P. Quigley
  Cc: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields,
	linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs

Quoting David P. Quigley (dpquigl@tycho.nsa.gov):
> This patch adds two entries into the fs/KConfig file. The first entry
> NFS_V4_SECURITY_LABEL enables security label support for the NFSv4 client while
> the second entry NFSD_V4_SECURITY_LABEL enables security labeling support on
> the server side.
> 
> Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
> ---
>  fs/Kconfig |   17 +++++++++++++++++
>  1 files changed, 17 insertions(+), 0 deletions(-)
> 
> diff --git a/fs/Kconfig b/fs/Kconfig
> index abccb5d..47ffb42 100644
> --- a/fs/Kconfig
> +++ b/fs/Kconfig
> @@ -1633,6 +1633,7 @@ config NFS_V4
> 
>  	  If unsure, say N.
> 
> +
>  config ROOT_NFS
>  	bool "Root file system on NFS"
>  	depends on NFS_FS=y && IP_PNP
> @@ -1644,6 +1645,15 @@ config ROOT_NFS
> 
>  	  Most people say N here.
> 
> +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 label attribute support for NFS version 4.

A little more here :)

"Say Y here if you want 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.

If you do not wish to enforce SELinux or Smack policies on NFSv4 files,
say N."

Or something...  the idea being to make it clear to anyone configuring
a new kernel whether they should say n or y.

> +
> +
> +	  If unsure, say N.
> +
>  config NFSD
>  	tristate "NFS server support"
>  	depends on INET
> @@ -1725,6 +1735,13 @@ 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
> +	  If you would like to include support for label file attributes
> +	  over NFSv4, say Y here.
> +
>  config LOCKD
>  	tristate
> 
> -- 
> 1.5.5.1
> 
> --
> 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

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

* Re: [PATCH 11/14] NFS/RPC: Add the auth_seclabel security flavor to allow the process label to be sent to the server.
  2008-09-29 17:06 ` [PATCH 11/14] NFS/RPC: Add the auth_seclabel security flavor to allow the process label to be sent to the server David P. Quigley
@ 2008-10-03 14:23   ` Andy Whitcroft
  2008-10-03 15:44     ` Matthew N. Dodd
  0 siblings, 1 reply; 33+ messages in thread
From: Andy Whitcroft @ 2008-10-03 14:23 UTC (permalink / raw)
  To: David P. Quigley
  Cc: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields,
	linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs

On Mon, Sep 29, 2008 at 01:06:23PM -0400, David P. Quigley wrote:
[...]
>  
> +	if (dom->flavour != &svcauth_unix
> +#ifdef CONFIG_SECURITY
> +	    && dom->flavour != &svcauth_seclabel
> +#endif
> +	   )
>  	if (dom->flavour != &svcauth_unix)
>  		return -EINVAL;
>  	udom = container_of(dom, struct unix_domain, h);
> @@ -873,3 +889,80 @@ struct auth_ops svcauth_unix = {
>  	.set_client	= svcauth_unix_set_client,
>  };

checkpatch picked up on a suspect code indent for this hunk.  It is
unhappy about the second if expecting it to be indented.  By the looks
of this I am suspecting a miss-merge of the change in this function and
the second if should have been removed.  To my reading it actually still
does the right thing but ...

-apw

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

* Re: [PATCH 11/14] NFS/RPC: Add the auth_seclabel security flavor to allow the process label to be sent to the server.
  2008-10-03 14:23   ` Andy Whitcroft
@ 2008-10-03 15:44     ` Matthew N. Dodd
  0 siblings, 0 replies; 33+ messages in thread
From: Matthew N. Dodd @ 2008-10-03 15:44 UTC (permalink / raw)
  To: Andy Whitcroft
  Cc: David P. Quigley, hch, viro, casey, sds, trond.myklebust, bfields,
	linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs

Andy Whitcroft wrote:
> On Mon, Sep 29, 2008 at 01:06:23PM -0400, David P. Quigley wrote:
> [...]
>>  
>> +	if (dom->flavour != &svcauth_unix
>> +#ifdef CONFIG_SECURITY
>> +	    && dom->flavour != &svcauth_seclabel
>> +#endif
>> +	   )
>>  	if (dom->flavour != &svcauth_unix)
>>  		return -EINVAL;
>>  	udom = container_of(dom, struct unix_domain, h);
>> @@ -873,3 +889,80 @@ struct auth_ops svcauth_unix = {
>>  	.set_client	= svcauth_unix_set_client,
>>  };
> 
> checkpatch picked up on a suspect code indent for this hunk.  It is
> unhappy about the second if expecting it to be indented.  By the looks
> of this I am suspecting a miss-merge of the change in this function and
> the second if should have been removed.  To my reading it actually still
> does the right thing but ...

This does appear to be a miss-merge.

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

* Re: [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information.
  2008-09-30 20:01     ` Serge E. Hallyn
@ 2008-10-06 20:52       ` David P. Quigley
  0 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-10-06 20:52 UTC (permalink / raw)
  To: Serge E. Hallyn
  Cc: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields,
	linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs

Fixed.

On Tue, 2008-09-30 at 15:01 -0500, Serge E. Hallyn wrote:
> Quoting David P. Quigley (dpquigl@tycho.nsa.gov):
> > This patch introduces three new hooks. The inode_getsecctx hook is used to get
> > all relevant information from an LSM about an inode. The inode_setsecctx is
> > used to set both the in-core and on-disk state for the inode based on a context
> > derived from inode_getsecctx.The final hook inode_notifysecctx will notify the
> > LSM of a change for the in-core state of the inode in question. These hooks are
> > for use in the labeled NFS code and addresses concerns of how to set security
> > on an inode in a multi-xattr LSM. For historical reasons Stephen Smalley's
> > explanation of the reason for these hooks is pasted below.
> > 
> > Quote Stephen Smalley
> > 
> > inode_setsecctx:  Change the security context of an inode.  Updates the
> > in core security context managed by the security module and invokes the
> > fs code as needed (via __vfs_setxattr_noperm) to update any backing
> > xattrs that represent the context.  Example usage:  NFS server invokes
> > this hook to change the security context in its incore inode and on the
> > backing file system to a value provided by the client on a SETATTR
> > operation.
> > 
> > inode_notifysecctx:  Notify the security module of what the security
> > context of an inode should be.  Initializes the incore security context
> > managed by the security module for this inode.  Example usage:  NFS
> > client invokes this hook to initialize the security context in its
> > incore inode to the value provided by the server for the file when the
> > server returned the file's attributes to the client.
> > 
> > Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> > Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
> > ---
> >  include/linux/security.h |   50 ++++++++++++++++++++++++++++++++++++++++++++++
> >  security/security.c      |   18 ++++++++++++++++
> >  security/selinux/hooks.c |   25 +++++++++++++++++++++++
> >  3 files changed, 93 insertions(+), 0 deletions(-)
> > 
> > diff --git a/include/linux/security.h b/include/linux/security.h
> > index 80c4d00..8b5b041 100644
> > --- a/include/linux/security.h
> > +++ b/include/linux/security.h
> > @@ -1289,6 +1289,36 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
> >   *	audit_rule_init.
> >   *	@rule contains the allocated rule
> >   *
> > + * @inode_notifysecctx:
> > + *	Notify the security module of what the security context of an inode
> > + *	should be.  Initializes the incore security context managed by the
> > + *	security module for this inode.  Example usage:  NFS client invokes
> > + *	this hook to initialize the security context in its incore inode to the
> > + *	value provided by the server for the file when the server returned the
> > + *	file's attributes to the client.
> > + *
> > + * 	@inode we wish to set the security context of.
> > + * 	@ctx contains the string which we wish to set in the inode.
> > + * 	@ctxlen contains the length of @ctx.
> > + *
> > + * @inode_setsecctx:
> > + * 	Change the security context of an inode.  Updates the
> > + * 	incore security context managed by the security module and invokes the
> > + * 	fs code as needed (via __vfs_setxattr_noperm) to update any backing
> > + * 	xattrs that represent the context.  Example usage:  NFS server invokes
> > + * 	this hook to change the security context in its incore inode and on the
> > + * 	backing filesystem to a value provided by the client on a SETATTR
> > + * 	operation.
> > + *
> > + * 	@dentry contains the inode we wish to set the security context of.
> > + * 	@ctx contains the string which we wish to set in the inode.
> > + * 	@ctxlen contains the length of @ctx.
> > + *
> > + * @inode_getsecctx:
> > + * 	Returns a string containing all relavent security context information
> > + * 	@inode we wish to set the security context of.
> > + *	@ctx is a pointer to place the allocated security context should be placed.
> 
> sentence above is odd.  How about
> 
> 	@ctx is a pointer in which to place the allocated security context
> 
> > + *	@ctxlen points to the place to put the length of @ctx.
> >   * This is the main security structure.
> >   */
> >  struct security_operations {
> > @@ -1479,6 +1509,10 @@ struct security_operations {
> >  	int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
> >  	void (*release_secctx) (char *secdata, u32 seclen);
> > 
> > +	int (*inode_notifysecctx)(struct inode *inode, void *ctx, u32 ctxlen);
> > +	int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen);
> > +	int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen);
> > +
> >  #ifdef CONFIG_SECURITY_NETWORK
> >  	int (*unix_stream_connect) (struct socket *sock,
> >  				    struct socket *other, struct sock *newsk);
> > @@ -1727,6 +1761,9 @@ 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);
> > 
> > +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
> > +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
> > +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
> >  #else /* CONFIG_SECURITY */
> >  struct security_mnt_opts {
> >  };
> > @@ -2458,6 +2495,19 @@ static inline int security_secctx_to_secid(const char *secdata,
> >  static inline void security_release_secctx(char *secdata, u32 seclen)
> >  {
> >  }
> > +
> > +static inline int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> > +{
> > +	return -EOPNOTSUPP;
> > +}
> > +static inline int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> > +{
> > +	return -EOPNOTSUPP;
> > +}
> > +static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> > +{
> > +	return -EOPNOTSUPP;
> > +}
> >  #endif	/* CONFIG_SECURITY */
> > 
> >  #ifdef CONFIG_SECURITY_NETWORK
> > diff --git a/security/security.c b/security/security.c
> > index 3a4b4f5..d0fd42a 100644
> > --- a/security/security.c
> > +++ b/security/security.c
> > @@ -869,6 +869,24 @@ void security_release_secctx(char *secdata, u32 seclen)
> >  }
> >  EXPORT_SYMBOL(security_release_secctx);
> > 
> > +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> > +{
> > +	return security_ops->inode_notifysecctx(inode, ctx, ctxlen);
> > +}
> > +EXPORT_SYMBOL(security_inode_notifysecctx);
> > +
> > +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> > +{
> > +	return security_ops->inode_setsecctx(dentry, ctx, ctxlen);
> > +}
> > +EXPORT_SYMBOL(security_inode_setsecctx);
> > +
> > +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> > +{
> > +	return security_ops->inode_getsecctx(inode, ctx, ctxlen);
> > +}
> > +EXPORT_SYMBOL(security_inode_getsecctx);
> > +
> >  #ifdef CONFIG_SECURITY_NETWORK
> > 
> >  int security_unix_stream_connect(struct socket *sock, struct socket *other,
> > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > index 03fc6a8..b07871b 100644
> > --- a/security/selinux/hooks.c
> > +++ b/security/selinux/hooks.c
> > @@ -5285,6 +5285,28 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
> >  	kfree(secdata);
> >  }
> > 
> > +/*
> > + *	This hook requires that the inode i_mutex be locked
> 
> 'called with inode->i_mutex locked' would make more sense here.
> Requirements on the callers would make more sense in the comments
> in include/linux/security.h, right?
> 
> No code objections, though.
> 
> Acked-by: Serge Hallyn <serue@us.ibm.com>
> 
> > + */
> > +static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> > +{
> > +	return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
> > +}
> > +
> > +/*
> > + *	This hook requires that the inode i_mutex be locked
> > + */
> > +static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> > +{
> > +	return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
> > +}
> > +
> > +static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> > +{
> > +	*ctxlen = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
> > +						ctx, true);
> > +	return *ctxlen;
> > +}
> >  #ifdef CONFIG_KEYS
> > 
> >  static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
> > @@ -5491,6 +5513,9 @@ static struct security_operations selinux_ops = {
> >  	.secid_to_secctx =		selinux_secid_to_secctx,
> >  	.secctx_to_secid =		selinux_secctx_to_secid,
> >  	.release_secctx =		selinux_release_secctx,
> > +	.inode_notifysecctx =		selinux_inode_notifysecctx,
> > +	.inode_setsecctx =		selinux_inode_setsecctx,
> > +	.inode_getsecctx =		selinux_inode_getsecctx,
> > 
> >  	.unix_stream_connect =		selinux_socket_unix_stream_connect,
> >  	.unix_may_send =		selinux_socket_unix_may_send,
> > -- 
> > 1.5.5.1
> > 
> > 
> > --
> > 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] 33+ messages in thread

* Re: [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information.
  2008-09-30 20:22     ` Serge E. Hallyn
@ 2008-10-06 20:52       ` David P. Quigley
  0 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-10-06 20:52 UTC (permalink / raw)
  To: Serge E. Hallyn
  Cc: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields,
	linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs

Fixed

On Tue, 2008-09-30 at 15:22 -0500, Serge E. Hallyn wrote:
> Quoting David P. Quigley (dpquigl@tycho.nsa.gov):
> > This patch introduces three new hooks. The inode_getsecctx hook is used to get
> > all relevant information from an LSM about an inode. The inode_setsecctx is
> > used to set both the in-core and on-disk state for the inode based on a context
> > derived from inode_getsecctx.The final hook inode_notifysecctx will notify the
> > LSM of a change for the in-core state of the inode in question. These hooks are
> > for use in the labeled NFS code and addresses concerns of how to set security
> > on an inode in a multi-xattr LSM. For historical reasons Stephen Smalley's
> > explanation of the reason for these hooks is pasted below.
> > 
> > Quote Stephen Smalley
> > 
> > inode_setsecctx:  Change the security context of an inode.  Updates the
> > in core security context managed by the security module and invokes the
> > fs code as needed (via __vfs_setxattr_noperm) to update any backing
> > xattrs that represent the context.  Example usage:  NFS server invokes
> > this hook to change the security context in its incore inode and on the
> > backing file system to a value provided by the client on a SETATTR
> > operation.
> > 
> > inode_notifysecctx:  Notify the security module of what the security
> > context of an inode should be.  Initializes the incore security context
> > managed by the security module for this inode.  Example usage:  NFS
> > client invokes this hook to initialize the security context in its
> > incore inode to the value provided by the server for the file when the
> > server returned the file's attributes to the client.
> > 
> > Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> > Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
> 
> Hmm, sorry, for all of these new hooks which you introduce, you do not
> define empty cap_* versions and assign them when need in
> security_fixup_ops().  But you unconditionally call them if
> CONFIG_SECURITY=y.  So if you compile a kernel with CONFIG_SECURITY=y
> but CONFIG_SECURITY_SELINUX=n, don't you hose your box?
> 
> > ---
> >  include/linux/security.h |   50 ++++++++++++++++++++++++++++++++++++++++++++++
> >  security/security.c      |   18 ++++++++++++++++
> >  security/selinux/hooks.c |   25 +++++++++++++++++++++++
> >  3 files changed, 93 insertions(+), 0 deletions(-)
> > 
> > diff --git a/include/linux/security.h b/include/linux/security.h
> > index 80c4d00..8b5b041 100644
> > --- a/include/linux/security.h
> > +++ b/include/linux/security.h
> > @@ -1289,6 +1289,36 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
> >   *	audit_rule_init.
> >   *	@rule contains the allocated rule
> >   *
> > + * @inode_notifysecctx:
> > + *	Notify the security module of what the security context of an inode
> > + *	should be.  Initializes the incore security context managed by the
> > + *	security module for this inode.  Example usage:  NFS client invokes
> > + *	this hook to initialize the security context in its incore inode to the
> > + *	value provided by the server for the file when the server returned the
> > + *	file's attributes to the client.
> > + *
> > + * 	@inode we wish to set the security context of.
> > + * 	@ctx contains the string which we wish to set in the inode.
> > + * 	@ctxlen contains the length of @ctx.
> > + *
> > + * @inode_setsecctx:
> > + * 	Change the security context of an inode.  Updates the
> > + * 	incore security context managed by the security module and invokes the
> > + * 	fs code as needed (via __vfs_setxattr_noperm) to update any backing
> > + * 	xattrs that represent the context.  Example usage:  NFS server invokes
> > + * 	this hook to change the security context in its incore inode and on the
> > + * 	backing filesystem to a value provided by the client on a SETATTR
> > + * 	operation.
> > + *
> > + * 	@dentry contains the inode we wish to set the security context of.
> > + * 	@ctx contains the string which we wish to set in the inode.
> > + * 	@ctxlen contains the length of @ctx.
> > + *
> > + * @inode_getsecctx:
> > + * 	Returns a string containing all relavent security context information
> > + * 	@inode we wish to set the security context of.
> > + *	@ctx is a pointer to place the allocated security context should be placed.
> > + *	@ctxlen points to the place to put the length of @ctx.
> >   * This is the main security structure.
> >   */
> >  struct security_operations {
> > @@ -1479,6 +1509,10 @@ struct security_operations {
> >  	int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
> >  	void (*release_secctx) (char *secdata, u32 seclen);
> > 
> > +	int (*inode_notifysecctx)(struct inode *inode, void *ctx, u32 ctxlen);
> > +	int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen);
> > +	int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen);
> > +
> >  #ifdef CONFIG_SECURITY_NETWORK
> >  	int (*unix_stream_connect) (struct socket *sock,
> >  				    struct socket *other, struct sock *newsk);
> > @@ -1727,6 +1761,9 @@ 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);
> > 
> > +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
> > +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
> > +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
> >  #else /* CONFIG_SECURITY */
> >  struct security_mnt_opts {
> >  };
> > @@ -2458,6 +2495,19 @@ static inline int security_secctx_to_secid(const char *secdata,
> >  static inline void security_release_secctx(char *secdata, u32 seclen)
> >  {
> >  }
> > +
> > +static inline int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> > +{
> > +	return -EOPNOTSUPP;
> > +}
> > +static inline int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> > +{
> > +	return -EOPNOTSUPP;
> > +}
> > +static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> > +{
> > +	return -EOPNOTSUPP;
> > +}
> >  #endif	/* CONFIG_SECURITY */
> > 
> >  #ifdef CONFIG_SECURITY_NETWORK
> > diff --git a/security/security.c b/security/security.c
> > index 3a4b4f5..d0fd42a 100644
> > --- a/security/security.c
> > +++ b/security/security.c
> > @@ -869,6 +869,24 @@ void security_release_secctx(char *secdata, u32 seclen)
> >  }
> >  EXPORT_SYMBOL(security_release_secctx);
> > 
> > +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> > +{
> > +	return security_ops->inode_notifysecctx(inode, ctx, ctxlen);
> > +}
> > +EXPORT_SYMBOL(security_inode_notifysecctx);
> > +
> > +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> > +{
> > +	return security_ops->inode_setsecctx(dentry, ctx, ctxlen);
> > +}
> > +EXPORT_SYMBOL(security_inode_setsecctx);
> > +
> > +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> > +{
> > +	return security_ops->inode_getsecctx(inode, ctx, ctxlen);
> > +}
> > +EXPORT_SYMBOL(security_inode_getsecctx);
> > +
> >  #ifdef CONFIG_SECURITY_NETWORK
> > 
> >  int security_unix_stream_connect(struct socket *sock, struct socket *other,
> > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > index 03fc6a8..b07871b 100644
> > --- a/security/selinux/hooks.c
> > +++ b/security/selinux/hooks.c
> > @@ -5285,6 +5285,28 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
> >  	kfree(secdata);
> >  }
> > 
> > +/*
> > + *	This hook requires that the inode i_mutex be locked
> > + */
> > +static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> > +{
> > +	return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
> > +}
> > +
> > +/*
> > + *	This hook requires that the inode i_mutex be locked
> > + */
> > +static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> > +{
> > +	return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
> > +}
> > +
> > +static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> > +{
> > +	*ctxlen = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
> > +						ctx, true);
> > +	return *ctxlen;
> > +}
> >  #ifdef CONFIG_KEYS
> > 
> >  static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
> > @@ -5491,6 +5513,9 @@ static struct security_operations selinux_ops = {
> >  	.secid_to_secctx =		selinux_secid_to_secctx,
> >  	.secctx_to_secid =		selinux_secctx_to_secid,
> >  	.release_secctx =		selinux_release_secctx,
> > +	.inode_notifysecctx =		selinux_inode_notifysecctx,
> > +	.inode_setsecctx =		selinux_inode_setsecctx,
> > +	.inode_getsecctx =		selinux_inode_getsecctx,
> > 
> >  	.unix_stream_connect =		selinux_socket_unix_stream_connect,
> >  	.unix_may_send =		selinux_socket_unix_may_send,
> > -- 
> > 1.5.5.1
> > 
> > 
> > --
> > 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] 33+ messages in thread

* Re: [PATCH 03/14] Security: Add hook to calculate context based on a negative dentry.
       [not found]       ` <20080930201524.GC21039-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
@ 2008-10-10 17:54         ` David P. Quigley
  2008-10-10 18:26           ` Serge E. Hallyn
  0 siblings, 1 reply; 33+ messages in thread
From: David P. Quigley @ 2008-10-10 17:54 UTC (permalink / raw)
  To: Serge E. Hallyn
  Cc: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
	casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
	matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
	trond.myklebust-41N18TsMXrtuMpJDpNschA,
	bfields-uC3wQj2KruNg9hUCZPvPmw,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	linux-security-module-u79uwXL29TY76Z2rM5mHXA,
	selinux-+05T5uksL2qpZYMLLGbcSA,
	labeled-nfs-6DNke4IJHB0gsBAKwltoeQ

Should I implement this hook in the capabilities module as well?

Dave


On Tue, 2008-09-30 at 15:15 -0500, Serge E. Hallyn wrote:
> Quoting David P. Quigley (dpquigl-+05T5uksL2qpZYMLLGbcSA@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.
> > 
> > Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
> > Signed-off-by: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
> > ---
> >  include/linux/security.h |   14 ++++++++++++++
> >  security/security.c      |    7 +++++++
> >  security/selinux/hooks.c |   36 ++++++++++++++++++++++++++++++++++++
> >  3 files changed, 57 insertions(+), 0 deletions(-)
> > 
> > diff --git a/include/linux/security.h b/include/linux/security.h
> > index 8b5b041..42b9128 100644
> > --- a/include/linux/security.h
> > +++ b/include/linux/security.h
> > @@ -1379,6 +1379,9 @@ 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,
> > +				     void **ctx, u32 *ctxlen);
> 
> This of course needs a description at top of include/linux/security.h.
> 
> > +
> > 
> >  	int (*inode_alloc_security) (struct inode *inode);
> >  	void (*inode_free_security) (struct inode *inode);
> > @@ -1651,6 +1654,8 @@ 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,
> > +				   void **ctx, u32 *ctxlen);
> > 
> >  int security_inode_alloc(struct inode *inode);
> >  void security_inode_free(struct inode *inode);
> > @@ -1994,6 +1999,15 @@ 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,
> > +						 void **ctx,
> > +						 u32 *ctxlen)
> > +{
> > +	return -EOPNOTSUPP;
> > +}
> > +
> > +
> >  static inline int security_inode_init_security(struct inode *inode,
> >  						struct inode *dir,
> >  						char **name,
> > diff --git a/security/security.c b/security/security.c
> > index d0fd42a..b22a110 100644
> > --- a/security/security.c
> > +++ b/security/security.c
> > @@ -349,6 +349,13 @@ void security_inode_free(struct inode *inode)
> >  	security_ops->inode_free_security(inode);
> >  }
> > 
> > +int security_dentry_init_security (struct dentry *dentry, int mode,
> > +				   void **ctx, u32 *ctxlen)
> > +{
> > +	return security_ops->dentry_init_security (dentry, mode, ctx, ctxlen);
> > +}
> > +EXPORT_SYMBOL(security_dentry_init_security);
> > +
> >  int security_inode_init_security(struct inode *inode, struct inode *dir,
> >  				  char **name, void **value, size_t *len)
> >  {
> > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > index b07871b..680db1d 100644
> > --- a/security/selinux/hooks.c
> > +++ b/security/selinux/hooks.c
> > @@ -2504,6 +2504,41 @@ static void selinux_inode_free_security(struct inode *inode)
> >  	inode_free_security(inode);
> >  }
> > 
> > +/*
> > + * For now, we need a way to compute a SID for
> 
> Just 'Compute a SID for...' ?
> 
> > + * a dentry as the inode is not yet available
> > + * (and under NFSv4 has no label backed by an EA anyway.
> > + */
> > +static int selinux_dentry_init_security(struct dentry *dentry, int mode, void **ctx, u32 *ctxlen)
> > +{
> > +	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 = current->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),
> > +					     &newsid);
> > +		if (rc) {
> > +			printk(KERN_WARNING "%s:  "
> > +			       "security_transition_sid failed, rc=%d\n",
> > +			       __FUNCTION__, -rc);
> > +			return rc;
> > +		}
> > +	}
> > +
> > +	return security_sid_to_context(newsid, (char **)ctx, ctxlen);
> > +}
> > +
> >  static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
> >  				       char **name, void **value,
> >  				       size_t *len)
> > @@ -5413,6 +5448,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.5.5.1
> > 
> > 
> > --
> > This message was distributed to subscribers of the selinux mailing list.
> > If you no longer wish to subscribe, send mail to majordomo-+05T5uksL2qpZYMLLGbcSA@public.gmane.org with
> > the words "unsubscribe selinux" without quotes as the message.

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

* Re: [PATCH 03/14] Security: Add hook to calculate context based on a negative dentry.
  2008-10-10 17:54         ` David P. Quigley
@ 2008-10-10 18:26           ` Serge E. Hallyn
  0 siblings, 0 replies; 33+ messages in thread
From: Serge E. Hallyn @ 2008-10-10 18:26 UTC (permalink / raw)
  To: David P. Quigley
  Cc: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields,
	linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs

Quoting David P. Quigley (dpquigl@tycho.nsa.gov):
> Should I implement this hook in the capabilities module as well?

Yup.

-serge

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

* Re: [RFC v3] Security Label Support for NFSv4
  2008-09-29 17:06 [RFC v3] Security Label Support for NFSv4 David P. Quigley
                   ` (5 preceding siblings ...)
       [not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
@ 2008-10-13 23:31 ` James Morris
  2008-10-14  2:15   ` [Labeled-nfs] " Matthew N. Dodd
  6 siblings, 1 reply; 33+ messages in thread
From: James Morris @ 2008-10-13 23:31 UTC (permalink / raw)
  To: David P. Quigley
  Cc: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields,
	linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs

On Mon, 29 Sep 2008, David P. Quigley wrote:

> 	* New security flavor (auth_seclabel) to transport process label to
> 	  server. This is a derivative of auth_unix so it does not support
> 	  kerberos which has its own issues that need to be dealt with.

This is a problem, as discussed last year:

http://linux-nfs.org/pipermail/labeled-nfs/2007-November/000110.html

We can't require the use of a new auth flavor which is incompatible with 
auth_gss.


- James
-- 
James Morris
<jmorris@namei.org>

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

* Re: [Labeled-nfs] [RFC v3] Security Label Support for NFSv4
  2008-10-13 23:31 ` [RFC v3] Security Label Support for NFSv4 James Morris
@ 2008-10-14  2:15   ` Matthew N. Dodd
  2008-10-14 13:20     ` Trond Myklebust
  0 siblings, 1 reply; 33+ messages in thread
From: Matthew N. Dodd @ 2008-10-14  2:15 UTC (permalink / raw)
  To: James Morris
  Cc: David P. Quigley, labeled-nfs, linux-kernel, linux-fsdevel,
	linux-security-module, viro, selinux

James Morris wrote:
> On Mon, 29 Sep 2008, David P. Quigley wrote:
> 
>> 	* New security flavor (auth_seclabel) to transport process label to
>> 	  server. This is a derivative of auth_unix so it does not support
>> 	  kerberos which has its own issues that need to be dealt with.
> 
> This is a problem, as discussed last year:
> 
> http://linux-nfs.org/pipermail/labeled-nfs/2007-November/000110.html
> 
> We can't require the use of a new auth flavor which is incompatible with 
> auth_gss.

auth_seclabel demonstrates the flavor independent changes required for 
any RPC layer process label transport.  A GSS solution is currently 
under discussion.

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

* Re: [Labeled-nfs] [RFC v3] Security Label Support for NFSv4
  2008-10-14  2:15   ` [Labeled-nfs] " Matthew N. Dodd
@ 2008-10-14 13:20     ` Trond Myklebust
  2008-10-14 14:28       ` David P. Quigley
  0 siblings, 1 reply; 33+ messages in thread
From: Trond Myklebust @ 2008-10-14 13:20 UTC (permalink / raw)
  To: Matthew N. Dodd
  Cc: James Morris, David P. Quigley, labeled-nfs, linux-kernel,
	linux-fsdevel, linux-security-module, viro, selinux

On Mon, 2008-10-13 at 22:15 -0400, Matthew N. Dodd wrote:
> James Morris wrote:
> > On Mon, 29 Sep 2008, David P. Quigley wrote:
> > 
> >> 	* New security flavor (auth_seclabel) to transport process label to
> >> 	  server. This is a derivative of auth_unix so it does not support
> >> 	  kerberos which has its own issues that need to be dealt with.
> > 
> > This is a problem, as discussed last year:
> > 
> > http://linux-nfs.org/pipermail/labeled-nfs/2007-November/000110.html
> > 
> > We can't require the use of a new auth flavor which is incompatible with 
> > auth_gss.
> 
> auth_seclabel demonstrates the flavor independent changes required for 
> any RPC layer process label transport.  A GSS solution is currently 
> under discussion.

Right, but I'm not particularly interested in merging "demonstration"
code that might end up requiring permanent support. I'd very much like
to see all of this get further through the IETF process before we talk
about merging into mainline.

Cheers
  Trond

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

* Re: [Labeled-nfs] [RFC v3] Security Label Support for NFSv4
  2008-10-14 13:20     ` Trond Myklebust
@ 2008-10-14 14:28       ` David P. Quigley
  0 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-10-14 14:28 UTC (permalink / raw)
  To: Trond Myklebust
  Cc: Matthew N. Dodd, James Morris, labeled-nfs, linux-kernel,
	linux-fsdevel, linux-security-module, viro, selinux

On Tue, 2008-10-14 at 09:20 -0400, Trond Myklebust wrote:
> On Mon, 2008-10-13 at 22:15 -0400, Matthew N. Dodd wrote:
> > James Morris wrote:
> > > On Mon, 29 Sep 2008, David P. Quigley wrote:
> > > 
> > >> 	* New security flavor (auth_seclabel) to transport process label to
> > >> 	  server. This is a derivative of auth_unix so it does not support
> > >> 	  kerberos which has its own issues that need to be dealt with.
> > > 
> > > This is a problem, as discussed last year:
> > > 
> > > http://linux-nfs.org/pipermail/labeled-nfs/2007-November/000110.html
> > > 
> > > We can't require the use of a new auth flavor which is incompatible with 
> > > auth_gss.
> > 
> > auth_seclabel demonstrates the flavor independent changes required for 
> > any RPC layer process label transport.  A GSS solution is currently 
> > under discussion.
> 
> Right, but I'm not particularly interested in merging "demonstration"
> code that might end up requiring permanent support. I'd very much like
> to see all of this get further through the IETF process before we talk
> about merging into mainline.
> 
> Cheers
>   Trond

Hello,
    Nico seems to have come up with a reasonable solution for this
problem we just need to sit down and draw up a document for it.
Apparently he already created a mechanism in rpcsec_gss for allowing you
to bind the rpc session to more than just the normal credentials. Once
we finalize this and get it into a draft we will work on implementing it
in the rpcsec_gss auth flavor.

Dave


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

* [PATCH 12/14] NFS: Client implementation of Labeled-NFS
  2008-11-26 21:03 [Labeled-nfs] [RFC v4] " David P. Quigley
@ 2008-11-26 21:03 ` David P. Quigley
  2008-12-05  9:39   ` James Morris
  0 siblings, 1 reply; 33+ messages in thread
From: David P. Quigley @ 2008-11-26 21:03 UTC (permalink / raw)
  To: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields
  Cc: linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs, David P. Quigley, Matthew N. Dodd

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: David P. Quigley <dpquigl@tycho.nsa.gov>
---
 fs/nfs/inode.c           |   49 +++++++-
 fs/nfs/nfs4proc.c        |  303 ++++++++++++++++++++++++++++++++++++++++++----
 fs/nfs/nfs4xdr.c         |   55 ++++++++-
 fs/nfs/super.c           |   33 +++++-
 include/linux/nfs_fs.h   |    2 +
 security/selinux/hooks.c |    5 +
 6 files changed, 412 insertions(+), 35 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 33ae87b..c025624 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -143,10 +143,13 @@ static void nfs_zap_caches_locked(struct inode *inode)
 	nfsi->attrtimeo_timestamp = jiffies;
 
 	memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
+	nfsi->cache_validity |= NFS_INO_INVALID_ATTR| \
+				NFS_INO_INVALID_LABEL| \
+				NFS_INO_INVALID_ACCESS| \
+				NFS_INO_INVALID_ACL| \
+				NFS_INO_REVAL_PAGECACHE;
 	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;
-	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_DATA;
 }
 
 void nfs_zap_caches(struct inode *inode)
@@ -235,6 +238,33 @@ nfs_init_locked(struct inode *inode, void *opaque)
 /* Don't use READDIRPLUS on directories that we believe are too large */
 #define NFS_LIMIT_READDIRPLUS (8*PAGE_SIZE)
 
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr)
+{
+	int error;
+
+/*	BUG_ON(!mutex_is_locked(&inode->i_mutex)); */
+
+	if ((fattr->valid & NFS_ATTR_FATTR_V4) &&
+	    (fattr->bitmap[1] & FATTR4_WORD1_SECURITY_LABEL) &&
+	    (fattr->label != NULL) &&
+	    (inode->i_security != NULL)) {
+		error = security_inode_notifysecctx(inode, fattr->label,
+						   fattr->label_len);
+		/* XXX: debug output */
+		if (error)
+			printk(KERN_ERR "%s() %s %d "
+				"security_inode_notifysecctx() %d\n",
+				__func__,
+				(char *)fattr->label, fattr->label_len, error);
+	}
+}
+#else
+void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr)
+{
+}
+#endif
+
 /*
  * This is our front-end to iget that looks up inodes by file handle
  * instead of inode number.
@@ -315,6 +345,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 		inode->i_nlink = fattr->nlink;
 		inode->i_uid = fattr->uid;
 		inode->i_gid = fattr->gid;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		nfs_setsecurity(inode, fattr);
+#endif
+
 		if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
 			/*
 			 * report the blocks in 512byte units
@@ -749,7 +784,7 @@ int nfs_attribute_timeout(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_timeout(inode))
 		return NFS_STALE(inode) ? -ESTALE : 0;
 	return __nfs_revalidate_inode(server, inode);
@@ -1183,6 +1218,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 	inode->i_nlink = fattr->nlink;
 	inode->i_uid = fattr->uid;
 	inode->i_gid = fattr->gid;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	nfs_setsecurity(inode, fattr);
+#endif
 
 	if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
 		/*
@@ -1194,7 +1232,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
  	}
 
 	/* 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;
@@ -1207,6 +1245,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
 		}
 	}
 	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 3a0d25f..9db51ea 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -48,6 +48,7 @@
 #include <linux/smp_lock.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
+#include <linux/nfs4_mount.h>
 
 #include "nfs4_fs.h"
 #include "delegation.h"
@@ -97,6 +98,9 @@ const u32 nfs4_fattr_bitmap[2] = {
 	| FATTR4_WORD1_TIME_ACCESS
 	| FATTR4_WORD1_TIME_METADATA
 	| FATTR4_WORD1_TIME_MODIFY
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	| FATTR4_WORD1_SECURITY_LABEL
+#endif
 };
 
 const u32 nfs4_statfs_bitmap[2] = {
@@ -251,7 +255,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
 
 static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
 		struct nfs4_state_owner *sp, int flags,
-		const struct iattr *attrs)
+		const struct iattr *attrs, struct nfs4_label *label)
 {
 	struct dentry *parent = dget_parent(path->dentry);
 	struct inode *dir = parent->d_inode;
@@ -277,6 +281,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
 	p->o_arg.server = server;
 	p->o_arg.bitmask = server->attr_bitmask;
 	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
+	p->o_arg.label = label;
 	if (flags & O_EXCL) {
 		u32 *s = (u32 *) p->o_arg.u.verifier.data;
 		s[0] = jiffies;
@@ -567,7 +572,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context
 {
 	struct nfs4_opendata *opendata;
 
-	opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL);
+	opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL, NULL);
 	if (opendata == NULL)
 		return ERR_PTR(-ENOMEM);
 	opendata->state = state;
@@ -1046,7 +1051,7 @@ static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct
 /*
  * Returns a referenced nfs4_state
  */
-static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res)
+static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct nfs4_label *label, struct rpc_cred *cred, struct nfs4_state **res)
 {
 	struct nfs4_state_owner  *sp;
 	struct nfs4_state     *state = NULL;
@@ -1068,7 +1073,7 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct
 		nfs4_return_incompatible_delegation(path->dentry->d_inode, flags & (FMODE_READ|FMODE_WRITE));
 	down_read(&clp->cl_sem);
 	status = -ENOMEM;
-	opendata = nfs4_opendata_alloc(path, sp, flags, sattr);
+	opendata = nfs4_opendata_alloc(path, sp, flags, sattr, label);
 	if (opendata == NULL)
 		goto err_release_rwsem;
 
@@ -1103,14 +1108,14 @@ out_err:
 }
 
 
-static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred)
+static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct nfs4_label *label, struct rpc_cred *cred)
 {
 	struct nfs4_exception exception = { };
 	struct nfs4_state *res;
 	int status;
 
 	do {
-		status = _nfs4_do_open(dir, path, flags, sattr, cred, &res);
+		status = _nfs4_do_open(dir, path, flags, sattr, label, cred, &res);
 		if (status == 0)
 			break;
 		/* NOTE: BAD_SEQID means the server and client disagree about the
@@ -1154,14 +1159,15 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int
 
 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_label *label, struct nfs4_state *state)
 {
 	struct nfs_server *server = NFS_SERVER(inode);
         struct nfs_setattrargs  arg = {
                 .fh             = NFS_FH(inode),
                 .iap            = sattr,
 		.server		= server,
-		.bitmask = server->attr_bitmask,
+		.bitmask 	= server->attr_bitmask,
+		.label		= label,
         };
         struct nfs_setattrres  res = {
 		.fattr		= fattr,
@@ -1193,14 +1199,14 @@ 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_label *label, struct nfs4_state *state)
 {
 	struct nfs_server *server = NFS_SERVER(inode);
 	struct nfs4_exception exception = { };
 	int err;
 	do {
 		err = nfs4_handle_exception(server,
-				_nfs4_do_setattr(inode, cred, fattr, sattr, state),
+				_nfs4_do_setattr(inode, cred, fattr, sattr, label, state),
 				&exception);
 	} while (exception.retry);
 	return err;
@@ -1406,6 +1412,7 @@ out_close:
 struct dentry *
 nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 {
+	struct nfs4_label l, *label = NULL;
 	struct path path = {
 		.mnt = nd->path.mnt,
 		.dentry = dentry,
@@ -1416,11 +1423,21 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 	struct nfs4_state *state;
 	struct dentry *res;
 
+	memset(&attr, 0, sizeof(struct iattr));
 	if (nd->flags & LOOKUP_CREATE) {
 		attr.ia_mode = nd->intent.open.create_mode;
 		attr.ia_valid = ATTR_MODE;
 		if (!IS_POSIXACL(dir))
 			attr.ia_mode &= ~current->fs->umask;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+			int error;
+			error = security_dentry_init_security(dentry,
+					attr.ia_mode, &l.label, &l.len);
+			if (error == 0)
+				label = &l;
+		}
+#endif
 	} else {
 		attr.ia_valid = 0;
 		BUG_ON(nd->intent.open.flags & O_CREAT);
@@ -1432,8 +1449,12 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 	parent = dentry->d_parent;
 	/* Protect against concurrent sillydeletes */
 	nfs_block_sillyrename(parent);
-	state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred);
+	state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, label, cred);
 	put_rpccred(cred);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		security_release_secctx(l.label, l.len);
+#endif
 	if (IS_ERR(state)) {
 		if (PTR_ERR(state) == -ENOENT) {
 			d_add(dentry, NULL);
@@ -1464,7 +1485,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
 	cred = rpc_lookup_cred();
 	if (IS_ERR(cred))
 		return PTR_ERR(cred);
-	state = nfs4_do_open(dir, &path, openflags, NULL, cred);
+	state = nfs4_do_open(dir, &path, openflags, NULL, NULL, cred);
 	put_rpccred(cred);
 	if (IS_ERR(state)) {
 		switch (PTR_ERR(state)) {
@@ -1506,6 +1527,13 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
 		memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask));
 		if (res.attr_bitmask[0] & FATTR4_WORD0_ACL)
 			server->caps |= NFS_CAP_ACLS;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		if (server->flags & NFS4_MOUNT_SECURITY_LABEL &&
+		    res.attr_bitmask[1] & FATTR4_WORD1_SECURITY_LABEL) {
+			server->caps |= NFS_CAP_SECURITY_LABEL;
+		} else
+#endif
+		server->attr_bitmask[1] &= ~FATTR4_WORD1_SECURITY_LABEL;
 		if (res.has_links != 0)
 			server->caps |= NFS_CAP_HARDLINKS;
 		if (res.has_symlinks != 0)
@@ -1688,9 +1716,11 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 		}
 	}
 
-	status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
-	if (status == 0)
+	status = nfs4_do_setattr(inode, cred, fattr, sattr, NULL, state);
+	if (status == 0) {
 		nfs_setattr_update_inode(inode, sattr);
+		nfs_setsecurity(inode, fattr);
+	}
 	return status;
 }
 
@@ -1913,6 +1943,7 @@ static int
 nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                  int flags, struct nameidata *nd)
 {
+	struct nfs4_label l, *label = NULL;
 	struct path path = {
 		.mnt = nd->path.mnt,
 		.dentry = dentry,
@@ -1926,7 +1957,18 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 		status = PTR_ERR(cred);
 		goto out;
 	}
-	state = nfs4_do_open(dir, &path, flags, sattr, cred);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (((nd->flags & LOOKUP_CREATE) != 0) &&
+	      nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+		status = security_dentry_init_security(dentry,
+				sattr->ia_mode, &l.label, &l.len);
+		/* XXX: should this be more fatal? */
+		if (status == 0)
+			label = &l;
+	}
+#endif
+
+	state = nfs4_do_open(dir, &path, flags, sattr, label, cred);
 	d_drop(dentry);
 	if (IS_ERR(state)) {
 		status = PTR_ERR(state);
@@ -1945,10 +1987,12 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 		if (status < 0)
 			goto out;
 #endif
-		status = nfs4_do_setattr(state->inode, cred, &fattr, sattr, state);
-		if (status == 0)
+		status = nfs4_do_setattr(state->inode, cred, &fattr, sattr, label, state);
+		if (status == 0) {
 			nfs_setattr_update_inode(state->inode, sattr);
-		nfs_post_op_update_inode(state->inode, &fattr);
+			nfs_post_op_update_inode(state->inode, &fattr);
+			nfs_setsecurity(state->inode, &fattr);
+		}
 		nfs_fattr_fini(&fattr);
 	}
 	if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
@@ -1958,6 +2002,10 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 out_putcred:
 	put_rpccred(cred);
 out:
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		security_release_secctx(label->label, label->len);
+#endif
 	return status;
 }
 
@@ -2241,7 +2289,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;
@@ -2257,6 +2306,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);
 
@@ -2269,18 +2319,33 @@ 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 l, *label = NULL;
 	int err;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+		err = security_dentry_init_security(dentry,
+				sattr->ia_mode, &l.label, &l.len);
+		if (err == 0)
+			label = &l;
+	}
+#endif
+
 	do {
 		err = nfs4_handle_exception(NFS_SERVER(dir),
 				_nfs4_proc_symlink(dir, dentry, page,
-							len, sattr),
+							len, sattr, label),
 				&exception);
 	} while (exception.retry);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		security_release_secctx(l.label, l.len);
+#endif
 	return err;
 }
 
 static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
-		struct iattr *sattr)
+		struct iattr *sattr, struct nfs4_label *label)
 {
 	struct nfs4_createdata *data;
 	int status = -ENOMEM;
@@ -2289,6 +2354,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);
@@ -2300,12 +2366,27 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr)
 {
 	struct nfs4_exception exception = { };
+	struct nfs4_label l, *label = NULL;
 	int err;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+		err = security_dentry_init_security(dentry,
+				sattr->ia_mode, &l.label, &l.len);
+		if (err == 0)
+			label = &l;
+	}
+#endif
+
 	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);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		security_release_secctx(l.label, l.len);
+#endif
 	return err;
 }
 
@@ -2360,7 +2441,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;
@@ -2385,7 +2466,7 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 		data->arg.u.device.specdata1 = MAJOR(rdev);
 		data->arg.u.device.specdata2 = MINOR(rdev);
 	}
-	
+	data->arg.label = label;
 	status = nfs4_do_create(dir, dentry, data);
 
 	nfs4_free_createdata(data);
@@ -2397,12 +2478,27 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 		struct iattr *sattr, dev_t rdev)
 {
 	struct nfs4_exception exception = { };
+	struct nfs4_label l, *label = NULL;
 	int err;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+		err = security_dentry_init_security(dentry,
+				sattr->ia_mode, &l.label, &l.len);
+		if (err == 0)
+			label = &l;
+	}
+#endif
+
 	do {
 		err = nfs4_handle_exception(NFS_SERVER(dir),
-				_nfs4_proc_mknod(dir, dentry, sattr, rdev),
+				_nfs4_proc_mknod(dir, dentry, sattr, label, rdev),
 				&exception);
 	} while (exception.retry);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		security_release_secctx(l.label, l.len);
+#endif
 	return err;
 }
 
@@ -2850,6 +2946,163 @@ 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;
+	u32 bitmask[2] = { 0, FATTR4_WORD1_SECURITY_LABEL };
+	struct nfs4_getattr_arg args = {
+		.fh		= NFS_FH(inode),
+		.bitmask	= bitmask,
+	};
+	struct nfs4_getattr_res res = {
+		.fattr		= &fattr,
+		.server		= server,
+	};
+	struct rpc_message msg = {
+		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
+		.rpc_argp	= &args,
+		.rpc_resp	= &res,
+	};
+	int ret;
+
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+	nfs_fattr_alloc(&fattr, GFP_KERNEL);
+	nfs_fattr_init(&fattr);
+
+	ret = rpc_call_sync(server->client, &msg, 0);
+	if (ret)
+		goto out;
+	if (!(fattr.bitmap[1] & FATTR4_WORD1_SECURITY_LABEL))
+		return -ENOENT;
+	if (buflen < fattr.label_len) {
+		ret = -ERANGE;
+		goto out;
+	}
+	memcpy(buf, fattr.label, fattr.label_len);
+out:
+	nfs_fattr_fini(&fattr);
+	return ret;
+}
+
+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 *label,
+				      struct nfs_fattr *fattr,
+				      struct nfs4_state *state)
+{
+
+	struct iattr sattr;
+	struct nfs_server *server = NFS_SERVER(inode);
+	const u32 bitmask[2] = { 0, FATTR4_WORD1_SECURITY_LABEL };
+	struct nfs_setattrargs args = {
+		.fh             = NFS_FH(inode),
+		.iap            = &sattr,
+		.server		= server,
+		.bitmask	= bitmask,
+		.label		= label,
+	};
+	struct nfs_setattrres res = {
+		.fattr		= fattr,
+		.server		= server,
+	};
+	struct rpc_message msg = {
+		.rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
+		.rpc_argp       = &args,
+		.rpc_resp       = &res,
+	};
+	unsigned long timestamp = jiffies;
+	int status;
+
+	memset(&sattr, 0, sizeof(struct iattr));
+
+	if (nfs4_copy_delegation_stateid(&args.stateid, inode)) {
+		/* Use that stateid */
+	} else if (state != NULL) {
+		msg.rpc_cred = state->owner->so_cred;
+		nfs4_copy_stateid(&args.stateid, state, current->files);
+	} else
+		memcpy(&args.stateid, &zero_stateid, sizeof(args.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 *label,
+				     struct nfs_fattr *fattr,
+				     struct nfs4_state *state)
+{
+	struct nfs4_exception exception = { };
+	int err;
+
+	do {
+		err = nfs4_handle_exception(NFS_SERVER(inode),
+			_nfs4_do_set_security_label(inode, label, fattr, 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 label;
+	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;
+
+	memset(&fattr, 0, sizeof(struct nfs_fattr));
+	nfs_fattr_alloc(&fattr, GFP_KERNEL);
+	nfs_fattr_init(&fattr);
+
+	label.label = (char *)buf;
+	label.len = buflen;
+
+	cred = rpc_lookup_cred();
+	if (IS_ERR(cred))
+		return PTR_ERR(cred);
+
+	/* 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, &label, &fattr, state);
+	if (status == 0)
+		nfs_setsecurity(inode, &fattr);
+	if (ctx != NULL)
+		put_nfs_open_context(ctx);
+	put_rpccred(cred);
+	nfs_fattr_fini(&fattr);
+	return status;
+}
+#endif	/* CONFIG_NFS_V4_SECURITY_LABEL */
+
 static int
 nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server)
 {
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index b916297..104fd29 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -601,7 +601,7 @@ static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *ve
 	xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE);
 }
 
-static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
+static int 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];
@@ -651,6 +651,10 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
 		}
 		len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
 	}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL)
+		len += 4 + (XDR_QUADLEN(label->len) << 2);
+#endif
 	if (iap->ia_valid & ATTR_ATIME_SET)
 		len += 16;
 	else if (iap->ia_valid & ATTR_ATIME)
@@ -709,6 +713,13 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
 		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
 		WRITE32(NFS4_SET_TO_SERVER_TIME);
 	}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	if (label != NULL) {
+		bmval1 |= FATTR4_WORD1_SECURITY_LABEL;
+		WRITE32(label->len);
+		WRITEMEM(label->label, label->len);
+	}
+#endif
 	
 	/*
 	 * Now we backfill the bitmap and the attribute buffer length.
@@ -792,7 +803,7 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c
 	WRITE32(create->name->len);
 	WRITEMEM(create->name->name, create->name->len);
 
-	return encode_attrs(xdr, create->attrs, create->server);
+	return encode_attrs(xdr, create->attrs, create->label, create->server);
 }
 
 static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
@@ -1000,7 +1011,7 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
 	switch(arg->open_flags & O_EXCL) {
 		case 0:
 			WRITE32(NFS4_CREATE_UNCHECKED);
-			encode_attrs(xdr, arg->u.attrs, arg->server);
+			encode_attrs(xdr, arg->u.attrs, arg->label, arg->server);
 			break;
 		default:
 			WRITE32(NFS4_CREATE_EXCLUSIVE);
@@ -1301,7 +1312,7 @@ static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *
         WRITE32(OP_SETATTR);
 	WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE);
 
-        if ((status = encode_attrs(xdr, arg->iap, server)))
+        if ((status = encode_attrs(xdr, arg->iap, arg->label, server)))
 		return status;
 
         return 0;
@@ -2954,6 +2965,39 @@ static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, str
 	return status;
 }
 
+static int decode_attr_security_label(struct xdr_stream *xdr, uint32_t *bitmap, void **ctx, __u32 *ctxlen)
+{
+	__u32 len;
+	__be32 *p;
+	int rc = 0;
+
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_SECURITY_LABEL - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_SECURITY_LABEL)) {
+		READ_BUF(4);
+		READ32(len);
+		READ_BUF(len);
+		if (len < XDR_MAX_NETOBJ) {
+			if (*ctx != NULL) {
+				if (*ctxlen < len) {
+					printk(KERN_ERR
+						"%s(): ctxlen %d < len %d\n",
+						__func__, *ctxlen, len);
+					/* rc = -ENOMEM; */
+					*ctx = NULL;	/* leak */
+				} else {
+					memcpy(*ctx, p, len);
+				}
+			}
+			*ctxlen = len;
+		} else
+			printk(KERN_WARNING "%s: label too long (%u)!\n",
+					__FUNCTION__, len);
+		bitmap[1] &= ~FATTR4_WORD1_SECURITY_LABEL;
+	}
+	return rc;
+}
+
 static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
 {
 	unsigned int attrwords = XDR_QUADLEN(attrlen);
@@ -3188,6 +3232,9 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
 		goto xdr_error;
 	if ((status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid)) != 0)
 		goto xdr_error;
+	if ((status = decode_attr_security_label(xdr, bitmap,
+				&fattr->label, &fattr->label_len)) != 0)
+		goto xdr_error;
 	if (fattr->fileid == 0 && fileid != 0)
 		fattr->fileid = fileid;
 	if ((status = verify_attr_len(xdr, savep, attrlen)) == 0)
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index ab071e1..41c979a 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -565,8 +565,15 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
 		nfs_show_mountd_options(m, nfss, showdefaults);
 
 #ifdef CONFIG_NFS_V4
-	if (clp->rpc_ops->version == 4)
+	if (clp->rpc_ops->version == 4) {
 		seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		if (nfss->caps & NFS_CAP_SECURITY_LABEL)
+			seq_printf(m, ",security_label");
+		else
+			seq_printf(m, ",nosecurity_label");
+#endif
+	}
 #endif
 }
 
@@ -623,6 +630,12 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
 		seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
 		seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
 		seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+		if (nfss->caps & NFS_CAP_SECURITY_LABEL)
+			seq_printf(m, ",security_label");
+		else
+			seq_printf(m, ",nosecurity_label");
+#endif
 	}
 #endif
 
@@ -2212,6 +2225,9 @@ static int nfs4_validate_mount_data(void *options,
 	if (data == NULL)
 		goto out_no_data;
 
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+	args->flags		|= NFS4_MOUNT_SECURITY_LABEL; /* Default */
+#endif
 	args->rsize		= NFS_MAX_FILE_IO_SIZE;
 	args->wsize		= NFS_MAX_FILE_IO_SIZE;
 	args->acregmin		= NFS_DEF_ACREGMIN;
@@ -2399,6 +2415,21 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
 		goto error_splat_super;
 	}
 
+#ifdef CONFIG_SECURITY_SELINUX
+	if (server->caps & NFS_CAP_SECURITY_LABEL)
+		security_sb_parse_opts_str("native_labels", &data->lsm_opts);
+	else
+		data->flags &= ~NFS4_MOUNT_SECURITY_LABEL;
+		/* XXX: we need a way to separate the default use of
+			security labels if supported from the userland
+			passing in the requirment that they be present.
+
+			default			- will
+			-o nosecurity_label 	- won't
+			-o security_label	- must
+		*/
+#endif
+
 	error = security_sb_set_mnt_opts(s, &data->lsm_opts);
 	if (error)
 		goto error_splat_root;
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 6120a28..4dc2fc1 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -197,6 +197,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
@@ -341,6 +342,7 @@ extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *map
 extern int nfs_revalidate_mapping_nolock(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);
 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, int mode);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 9e73750..4560f8f 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2844,7 +2844,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;
 }
 
@@ -2934,7 +2937,9 @@ 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.5.5.1


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

* Re: [PATCH 12/14] NFS: Client implementation of Labeled-NFS
  2008-11-26 21:03 ` [PATCH 12/14] NFS: Client implementation of Labeled-NFS David P. Quigley
@ 2008-12-05  9:39   ` James Morris
  0 siblings, 0 replies; 33+ messages in thread
From: James Morris @ 2008-12-05  9:39 UTC (permalink / raw)
  To: David P. Quigley
  Cc: hch, viro, casey, sds, Matthew N. Dodd, trond.myklebust, bfields,
	linux-kernel, linux-fsdevel, linux-security-module, selinux,
	labeled-nfs

On Wed, 26 Nov 2008, David P. Quigley wrote:

> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> +	if (((nd->flags & LOOKUP_CREATE) != 0) &&
> +	      nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
> +		status = security_dentry_init_security(dentry,
> +				sattr->ia_mode, &l.label, &l.len);
> +		/* XXX: should this be more fatal? */
> +		if (status == 0)
> +			label = &l;
> +	}
> +#endif

Per the comment, it seems this function should fail and propagate an error 
if status != 0.

> +	memset(&fattr, 0, sizeof(struct nfs_fattr));
> +	nfs_fattr_alloc(&fattr, GFP_KERNEL);

Need to check the return value.

> +	nfs_fattr_alloc(&fattr, GFP_KERNEL);

Ditto.

> +static int decode_attr_security_label(struct xdr_stream *xdr, uint32_t *bitmap, void **ctx, __u32 *ctxlen)
> +{
> +	__u32 len;
> +	__be32 *p;
> +	int rc = 0;
> +
> +	if (unlikely(bitmap[1] & (FATTR4_WORD1_SECURITY_LABEL - 1U)))
> +		return -EIO;
> +	if (likely(bitmap[1] & FATTR4_WORD1_SECURITY_LABEL)) {
> +		READ_BUF(4);
> +		READ32(len);
> +		READ_BUF(len);
> +		if (len < XDR_MAX_NETOBJ) {
> +			if (*ctx != NULL) {
> +				if (*ctxlen < len) {
> +					printk(KERN_ERR
> +						"%s(): ctxlen %d < len %d\n",
> +						__func__, *ctxlen, len);
> +					/* rc = -ENOMEM; */
> +					*ctx = NULL;	/* leak */

Shouldn't the function stop processing and return an error?

> +				} else {
> +					memcpy(*ctx, p, len);
> +				}
> +			}
> +			*ctxlen = len;
> +		} else
> +			printk(KERN_WARNING "%s: label too long (%u)!\n",
> +					__FUNCTION__, len);
> +		bitmap[1] &= ~FATTR4_WORD1_SECURITY_LABEL;
> +	}
> +	return rc;
> +}
> +



-- 
James Morris
<jmorris@namei.org>

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

end of thread, other threads:[~2008-12-05  9:39 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-29 17:06 [RFC v3] Security Label Support for NFSv4 David P. Quigley
2008-09-29 17:06 ` [PATCH 01/14] VFS: Factor out part of vfs_setxattr so it can be called from the SELinux hook for inode_setsecctx David P. Quigley
2008-09-30 19:51   ` Serge E. Hallyn
2008-09-29 17:06 ` [PATCH 05/14] SELinux: Add new labeling type native labels David P. Quigley
2008-09-29 17:06 ` [PATCH 06/14] KConfig: Add KConfig entries for Labeled NFS David P. Quigley
2008-09-30 20:40   ` Serge E. Hallyn
2008-09-29 17:06 ` [PATCH 10/14] NFSv4: Introduce new label structure David P. Quigley
2008-09-29 17:06 ` [PATCH 11/14] NFS/RPC: Add the auth_seclabel security flavor to allow the process label to be sent to the server David P. Quigley
2008-10-03 14:23   ` Andy Whitcroft
2008-10-03 15:44     ` Matthew N. Dodd
     [not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
2008-09-29 17:06   ` [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information David P. Quigley
2008-09-30 20:01     ` Serge E. Hallyn
2008-10-06 20:52       ` David P. Quigley
2008-09-30 20:22     ` Serge E. Hallyn
2008-10-06 20:52       ` David P. Quigley
2008-09-29 17:06   ` [PATCH 03/14] Security: Add hook to calculate context based on a negative dentry David P. Quigley
2008-09-30 20:15     ` Serge E. Hallyn
     [not found]       ` <20080930201524.GC21039-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
2008-10-10 17:54         ` David P. Quigley
2008-10-10 18:26           ` Serge E. Hallyn
2008-09-29 17:06   ` [PATCH 04/14] Security: Add Hook to test if the particular xattr is part of a MAC model David P. Quigley
2008-09-29 17:06   ` [PATCH 07/14] NFSv4: Add label recommended attribute and NFSv4 flags David P. Quigley
2008-09-29 17:06   ` [PATCH 08/14] NFS: Add security_label text mount option and handling code to NFS David P. Quigley
2008-09-29 17:06   ` [PATCH 09/14] NFS: Introduce lifecycle management for label attribute David P. Quigley
2008-09-29 17:06   ` [PATCH 12/14] NFS: Client implementation of Labeled-NFS David P. Quigley
2008-09-29 17:06   ` [PATCH 13/14] NFS: Extend NFS xattr handlers to accept the security namespace David P. Quigley
2008-09-29 17:06   ` [PATCH 14/14] NFSD: Server implementation of MAC Labeling David P. Quigley
2008-10-13 23:31 ` [RFC v3] Security Label Support for NFSv4 James Morris
2008-10-14  2:15   ` [Labeled-nfs] " Matthew N. Dodd
2008-10-14 13:20     ` Trond Myklebust
2008-10-14 14:28       ` David P. Quigley
  -- strict thread matches above, loose matches on Subject: below --
2008-11-26 21:03 [Labeled-nfs] [RFC v4] " David P. Quigley
2008-11-26 21:03 ` [PATCH 12/14] NFS: Client implementation of Labeled-NFS David P. Quigley
2008-12-05  9:39   ` James Morris
2008-09-15 20:41 [RFC] Labeled NFS Take 2 David P. Quigley
2008-09-15 20:41 ` [PATCH 12/14] NFS: Client implementation of Labeled-NFS David P. Quigley

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).