* [PATCH 01/13] VFS/Security: Rework inode_getsecurity and callers to return resulting buffer
2007-11-16 20:03 [RFC Labeled NFS] Labeling support for NFSv4 David P. Quigley
@ 2007-11-16 20:05 ` David P. Quigley
2007-11-16 20:06 ` [PATCH 02/13] VFS: Reorder vfs_getxattr to avoid unnecessary calls to the LSM David P. Quigley
` (12 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: David P. Quigley @ 2007-11-16 20:05 UTC (permalink / raw)
To: labeled-nfs; +Cc: selinux
This patch modifies the interface to inode_getsecurity to have the function
return a buffer containing the security blob and its length via parameters
instead of relying on the calling function to give it an appropriately sized
buffer. Security blobs obtained with this function should be freed using the
release_secctx LSM hook. This alleviates the problem of the caller having to
guess a length and preallocate a buffer for this function allowing it to be
used elsewhere for Labeled NFS. The patch also removed the unused err
parameter. The conversion is similar to the one performed by Al Viro for the
security_getprocattr hook.
Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
---
fs/xattr.c | 30 ++++++++++++++++++++++++++++--
include/linux/security.h | 21 +++++++++------------
include/linux/xattr.h | 1 +
mm/shmem.c | 3 +--
security/dummy.c | 2 +-
security/security.c | 4 ++--
security/selinux/hooks.c | 43 +++++++++++++++----------------------------
7 files changed, 57 insertions(+), 47 deletions(-)
diff --git a/fs/xattr.c b/fs/xattr.c
index 6645b73..56b5b88 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -105,6 +105,33 @@ out:
EXPORT_SYMBOL_GPL(vfs_setxattr);
ssize_t
+xattr_getsecurity(struct inode *inode, const char *name, void *value,
+ size_t size)
+{
+ void *buffer = NULL;
+ ssize_t len;
+
+ if (!value || !size) {
+ len = security_inode_getsecurity(inode, name, &buffer, false);
+ goto out_noalloc;
+ }
+
+ len = security_inode_getsecurity(inode, name, &buffer, true);
+ if (len < 0)
+ return len;
+ if (size < len) {
+ len = -ERANGE;
+ goto out;
+ }
+ memcpy(value, buffer, len);
+out:
+ security_release_secctx(buffer, len);
+out_noalloc:
+ return len;
+}
+EXPORT_SYMBOL_GPL(xattr_getsecurity);
+
+ssize_t
vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
{
struct inode *inode = dentry->d_inode;
@@ -126,8 +153,7 @@ vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
if (!strncmp(name, XATTR_SECURITY_PREFIX,
XATTR_SECURITY_PREFIX_LEN)) {
const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
- int ret = security_inode_getsecurity(inode, suffix, value,
- size, error);
+ int ret = xattr_getsecurity(inode, suffix, value, size);
/*
* Only overwrite the return value if a security module
* is actually active.
diff --git a/include/linux/security.h b/include/linux/security.h
index ac05083..3c4c91e 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -404,15 +404,12 @@ struct request_sock;
* identified by @name for @dentry.
* Return 0 if permission is granted.
* @inode_getsecurity:
- * Copy the extended attribute representation of the security label
- * associated with @name for @inode into @buffer. @buffer may be
- * NULL to request the size of the buffer required. @size indicates
- * the size of @buffer in bytes. Note that @name is the remainder
- * of the attribute name after the security. prefix has been removed.
- * @err is the return value from the preceding fs getxattr call,
- * and can be used by the security module to determine whether it
- * should try and canonicalize the attribute value.
- * Return number of bytes used/required on success.
+ * Retrieve a copy of the extended attribute representation of the
+ * security label associated with @name for @inode via @buffer. Note that
+ * @name is the remainder of the attribute name after the security prefix
+ * has been removed. @alloc is used to specify of the call should return a
+ * value via the buffer or just the value length Return size of buffer on
+ * success.
* @inode_setsecurity:
* Set the security label associated with @name for @inode from the
* extended attribute value @value. @size indicates the size of the
@@ -1275,7 +1272,7 @@ struct security_operations {
int (*inode_removexattr) (struct dentry *dentry, char *name);
int (*inode_need_killpriv) (struct dentry *dentry);
int (*inode_killpriv) (struct dentry *dentry);
- int (*inode_getsecurity)(const struct inode *inode, const char *name, void *buffer, size_t size, int err);
+ int (*inode_getsecurity)(const struct inode *inode, const char *name, void **buffer, bool alloc);
int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
@@ -1529,7 +1526,7 @@ int security_inode_listxattr(struct dentry *dentry);
int security_inode_removexattr(struct dentry *dentry, char *name);
int security_inode_need_killpriv(struct dentry *dentry);
int security_inode_killpriv(struct dentry *dentry);
-int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err);
+int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc);
int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags);
int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size);
int security_file_permission(struct file *file, int mask);
@@ -1933,7 +1930,7 @@ static inline int security_inode_killpriv(struct dentry *dentry)
return cap_inode_killpriv(dentry);
}
-static inline int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
+static inline int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
{
return -EOPNOTSUPP;
}
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index def131a..df6b95d 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -46,6 +46,7 @@ struct xattr_handler {
size_t size, int flags);
};
+ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
ssize_t vfs_getxattr(struct dentry *, char *, void *, size_t);
ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
int vfs_setxattr(struct dentry *, char *, void *, size_t, int);
diff --git a/mm/shmem.c b/mm/shmem.c
index 253d205..ba59f48 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1995,8 +1995,7 @@ static int shmem_xattr_security_get(struct inode *inode, const char *name,
{
if (strcmp(name, "") == 0)
return -EINVAL;
- return security_inode_getsecurity(inode, name, buffer, size,
- -EOPNOTSUPP);
+ return xattr_getsecurity(inode, name, buffer, size);
}
static int shmem_xattr_security_set(struct inode *inode, const char *name,
diff --git a/security/dummy.c b/security/dummy.c
index 6d895ad..7de65dc 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -384,7 +384,7 @@ static int dummy_inode_killpriv(struct dentry *dentry)
return 0;
}
-static int dummy_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
+static int dummy_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
{
return -EOPNOTSUPP;
}
diff --git a/security/security.c b/security/security.c
index 0e1f1f1..39de3f4 100644
--- a/security/security.c
+++ b/security/security.c
@@ -478,11 +478,11 @@ int security_inode_killpriv(struct dentry *dentry)
return security_ops->inode_killpriv(dentry);
}
-int security_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
+int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
{
if (unlikely(IS_PRIVATE(inode)))
return 0;
- return security_ops->inode_getsecurity(inode, name, buffer, size, err);
+ return security_ops->inode_getsecurity(inode, name, buffer, alloc);
}
int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 9f3124b..128f363 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -127,32 +127,6 @@ static DEFINE_SPINLOCK(sb_security_lock);
static struct kmem_cache *sel_inode_cache;
-/* Return security context for a given sid or just the context
- length if the buffer is null or length is 0 */
-static int selinux_getsecurity(u32 sid, void *buffer, size_t size)
-{
- char *context;
- unsigned len;
- int rc;
-
- rc = security_sid_to_context(sid, &context, &len);
- if (rc)
- return rc;
-
- if (!buffer || !size)
- goto getsecurity_exit;
-
- if (size < len) {
- len = -ERANGE;
- goto getsecurity_exit;
- }
- memcpy(buffer, context, len);
-
-getsecurity_exit:
- kfree(context);
- return len;
-}
-
/* Allocate and free functions for each kind of security blob. */
static int task_alloc_security(struct task_struct *task)
@@ -2416,14 +2390,27 @@ static int selinux_inode_removexattr (struct dentry *dentry, char *name)
*
* Permission check is handled by selinux_inode_getxattr hook.
*/
-static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
+static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
{
+ u32 size;
+ int error;
+ char *context = NULL;
struct inode_security_struct *isec = inode->i_security;
if (strcmp(name, XATTR_SELINUX_SUFFIX))
return -EOPNOTSUPP;
- return selinux_getsecurity(isec->sid, buffer, size);
+ error = security_sid_to_context(isec->sid, &context, &size);
+ if (error)
+ return error;
+ error = size;
+ if (alloc) {
+ *buffer = context;
+ goto out_nofree;
+ }
+ kfree(context);
+out_nofree:
+ return error;
}
static int selinux_inode_setsecurity(struct inode *inode, const char *name,
--
1.5.3.4
--
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 related [flat|nested] 21+ messages in thread* [PATCH 02/13] VFS: Reorder vfs_getxattr to avoid unnecessary calls to the LSM
2007-11-16 20:03 [RFC Labeled NFS] Labeling support for NFSv4 David P. Quigley
2007-11-16 20:05 ` [PATCH 01/13] VFS/Security: Rework inode_getsecurity and callers to return resulting buffer David P. Quigley
@ 2007-11-16 20:06 ` David P. Quigley
2007-11-16 20:07 ` [PATCH 03/13] Security: Add hook to get full security xattr name David P. Quigley
` (11 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: David P. Quigley @ 2007-11-16 20:06 UTC (permalink / raw)
To: labeled-nfs; +Cc: selinux
Originally vfs_getxattr would pull the security xattr variable using
the inode getxattr handle and then proceed to clobber it with a subsequent call
to the LSM. This patch reorders the two operations such that when the xattr
requested is in the security namespace it first attempts to grab the value from
the LSM directly. If it fails to obtain the value because there is no module
present or the module does not support the operation it will fall back to using
the inode getxattr operation. In the event that both are inaccessible it
returns EOPNOTSUPP.
Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
---
fs/xattr.c | 15 ++++++++-------
1 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/fs/xattr.c b/fs/xattr.c
index 56b5b88..91c7929 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -145,11 +145,6 @@ vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
if (error)
return error;
- if (inode->i_op->getxattr)
- error = inode->i_op->getxattr(dentry, name, value, size);
- else
- error = -EOPNOTSUPP;
-
if (!strncmp(name, XATTR_SECURITY_PREFIX,
XATTR_SECURITY_PREFIX_LEN)) {
const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
@@ -158,9 +153,15 @@ vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
* Only overwrite the return value if a security module
* is actually active.
*/
- if (ret != -EOPNOTSUPP)
- error = ret;
+ if (ret == -EOPNOTSUPP)
+ goto nolsm;
+ return ret;
}
+nolsm:
+ if (inode->i_op->getxattr)
+ error = inode->i_op->getxattr(dentry, name, value, size);
+ else
+ error = -EOPNOTSUPP;
return error;
}
--
1.5.3.4
--
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 related [flat|nested] 21+ messages in thread* [PATCH 03/13] Security: Add hook to get full security xattr name
2007-11-16 20:03 [RFC Labeled NFS] Labeling support for NFSv4 David P. Quigley
2007-11-16 20:05 ` [PATCH 01/13] VFS/Security: Rework inode_getsecurity and callers to return resulting buffer David P. Quigley
2007-11-16 20:06 ` [PATCH 02/13] VFS: Reorder vfs_getxattr to avoid unnecessary calls to the LSM David P. Quigley
@ 2007-11-16 20:07 ` David P. Quigley
2007-11-17 0:34 ` Casey Schaufler
2007-11-16 20:07 ` [PATCH 04/13] VFS: Add label field to the iattr structure David P. Quigley
` (10 subsequent siblings)
13 siblings, 1 reply; 21+ messages in thread
From: David P. Quigley @ 2007-11-16 20:07 UTC (permalink / raw)
To: labeled-nfs; +Cc: selinux
When a caller wishes to get pull the extended attribute name for the security
module for use they normally concatinate the security namespace segment and the
suffix provided by the lsm. This hook provides a mechanism to obtain the full
LSM xattr name. The patch also provides implementations for the dummy security
module and SELinux.
Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
---
include/linux/security.h | 7 +++++++
security/dummy.c | 6 ++++++
security/security.c | 6 ++++++
security/selinux/hooks.c | 6 ++++++
4 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/include/linux/security.h b/include/linux/security.h
index 3c4c91e..8c0d687 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1272,6 +1272,7 @@ struct security_operations {
int (*inode_removexattr) (struct dentry *dentry, char *name);
int (*inode_need_killpriv) (struct dentry *dentry);
int (*inode_killpriv) (struct dentry *dentry);
+ const char *(*inode_xattr_getname) (void);
int (*inode_getsecurity)(const struct inode *inode, const char *name, void **buffer, bool alloc);
int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
@@ -1526,6 +1527,7 @@ int security_inode_listxattr(struct dentry *dentry);
int security_inode_removexattr(struct dentry *dentry, char *name);
int security_inode_need_killpriv(struct dentry *dentry);
int security_inode_killpriv(struct dentry *dentry);
+const char *security_inode_xattr_getname(void);
int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc);
int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags);
int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size);
@@ -1930,6 +1932,11 @@ static inline int security_inode_killpriv(struct dentry *dentry)
return cap_inode_killpriv(dentry);
}
+static inline const char *security_inode_xattr_getname(void)
+{
+ return NULL;
+}
+
static inline int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
{
return -EOPNOTSUPP;
diff --git a/security/dummy.c b/security/dummy.c
index 7de65dc..c2524ab 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -384,6 +384,11 @@ static int dummy_inode_killpriv(struct dentry *dentry)
return 0;
}
+static const char *dummy_inode_xattr_getname(void)
+{
+ return NULL;
+}
+
static int dummy_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
{
return -EOPNOTSUPP;
@@ -1022,6 +1027,7 @@ void security_fixup_ops (struct security_operations *ops)
set_to_dummy_if_null(ops, inode_removexattr);
set_to_dummy_if_null(ops, inode_need_killpriv);
set_to_dummy_if_null(ops, inode_killpriv);
+ set_to_dummy_if_null(ops, inode_xattr_getname);
set_to_dummy_if_null(ops, inode_getsecurity);
set_to_dummy_if_null(ops, inode_setsecurity);
set_to_dummy_if_null(ops, inode_listsecurity);
diff --git a/security/security.c b/security/security.c
index 39de3f4..cf853a7 100644
--- a/security/security.c
+++ b/security/security.c
@@ -478,6 +478,12 @@ int security_inode_killpriv(struct dentry *dentry)
return security_ops->inode_killpriv(dentry);
}
+const char *security_inode_xattr_getname(void)
+{
+ return security_ops->inode_xattr_getname();
+}
+EXPORT_SYMBOL(security_inode_xattr_getname);
+
int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
{
if (unlikely(IS_PRIVATE(inode)))
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 128f363..9083390 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2383,6 +2383,11 @@ static int selinux_inode_removexattr (struct dentry *dentry, char *name)
return -EACCES;
}
+static const char *selinux_inode_xattr_getname(void)
+{
+ return XATTR_NAME_SELINUX;
+}
+
/*
* Copy the in-core inode security context value to the user. If the
* getxattr() prior to this succeeded, check to see if we need to
@@ -4809,6 +4814,7 @@ static struct security_operations selinux_ops = {
.inode_getxattr = selinux_inode_getxattr,
.inode_listxattr = selinux_inode_listxattr,
.inode_removexattr = selinux_inode_removexattr,
+ .inode_xattr_getname = selinux_inode_xattr_getname,
.inode_getsecurity = selinux_inode_getsecurity,
.inode_setsecurity = selinux_inode_setsecurity,
.inode_listsecurity = selinux_inode_listsecurity,
--
1.5.3.4
--
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 related [flat|nested] 21+ messages in thread* Re: [PATCH 03/13] Security: Add hook to get full security xattr name
2007-11-16 20:07 ` [PATCH 03/13] Security: Add hook to get full security xattr name David P. Quigley
@ 2007-11-17 0:34 ` Casey Schaufler
2007-11-19 14:42 ` David P. Quigley
0 siblings, 1 reply; 21+ messages in thread
From: Casey Schaufler @ 2007-11-17 0:34 UTC (permalink / raw)
To: David P. Quigley, labeled-nfs; +Cc: selinux
--- "David P. Quigley" <dpquigl@tycho.nsa.gov> wrote:
> When a caller wishes to get pull the extended attribute name for the security
> module for use they normally concatinate the security namespace segment and
> the
> suffix provided by the lsm. This hook provides a mechanism to obtain the full
> LSM xattr name. The patch also provides implementations for the dummy
> security
> module and SELinux.
What is the problem with the concatination scheme currently in
use? I'm not going to defend it, but why change it?
> Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
> Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> ---
> include/linux/security.h | 7 +++++++
> security/dummy.c | 6 ++++++
> security/security.c | 6 ++++++
> security/selinux/hooks.c | 6 ++++++
> 4 files changed, 25 insertions(+), 0 deletions(-)
Please cross post proposed LSM changes to the LSM mailing list.
Casey Schaufler
casey@schaufler-ca.com
--
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] 21+ messages in thread
* Re: [PATCH 03/13] Security: Add hook to get full security xattr name
2007-11-17 0:34 ` Casey Schaufler
@ 2007-11-19 14:42 ` David P. Quigley
0 siblings, 0 replies; 21+ messages in thread
From: David P. Quigley @ 2007-11-19 14:42 UTC (permalink / raw)
To: casey; +Cc: labeled-nfs, selinux
On Fri, 2007-11-16 at 16:34 -0800, Casey Schaufler wrote:
> --- "David P. Quigley" <dpquigl@tycho.nsa.gov> wrote:
>
> > When a caller wishes to get pull the extended attribute name for the security
> > module for use they normally concatinate the security namespace segment and
> > the
> > suffix provided by the lsm. This hook provides a mechanism to obtain the full
> > LSM xattr name. The patch also provides implementations for the dummy
> > security
> > module and SELinux.
>
> What is the problem with the concatination scheme currently in
> use? I'm not going to defend it, but why change it?
Well the current getsuffix call has been removed by a patch submitted by
Adrian Bunk I think. Regardless it is no longer in the stable kernel and
other places in the xattr code take the xattr that they receive and then
pass an offset into it for the component. There are examples of this
method in the kernel already and it seems better to do this rather than
concatenating them.
Pointer + offset as opposed to string concatenation.
Dave
>
> > Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
> > Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> > ---
> > include/linux/security.h | 7 +++++++
> > security/dummy.c | 6 ++++++
> > security/security.c | 6 ++++++
> > security/selinux/hooks.c | 6 ++++++
> > 4 files changed, 25 insertions(+), 0 deletions(-)
>
> Please cross post proposed LSM changes to the LSM mailing list.
>
>
>
> Casey Schaufler
> casey@schaufler-ca.com
--
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] 21+ messages in thread
* [PATCH 04/13] VFS: Add label field to the iattr structure
2007-11-16 20:03 [RFC Labeled NFS] Labeling support for NFSv4 David P. Quigley
` (2 preceding siblings ...)
2007-11-16 20:07 ` [PATCH 03/13] Security: Add hook to get full security xattr name David P. Quigley
@ 2007-11-16 20:07 ` David P. Quigley
2007-11-16 20:08 ` [PATCH 05/13] Security: Add hook to calculate context based on a negative dentry David P. Quigley
` (9 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: David P. Quigley @ 2007-11-16 20:07 UTC (permalink / raw)
To: labeled-nfs; +Cc: selinux
The ia_label and ia_label_len fields are used to hold the information taken
from the wire to be passed with the other file attributes to be set. This patch
also modifies inode_setattr to make use of the new iattr fields.
Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
---
fs/attr.c | 40 ++++++++++++++++++++++++++++++++++++++++
fs/xattr.c | 31 +++++++++++++++++++++++++------
include/linux/fs.h | 11 +++++++++++
include/linux/xattr.h | 1 +
4 files changed, 77 insertions(+), 6 deletions(-)
diff --git a/fs/attr.c b/fs/attr.c
index 966b73e..50e34b9 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -5,6 +5,7 @@
* changes by Thomas Schoebel-Theuer
*/
+#include <linux/fs.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/mm.h>
@@ -14,9 +15,32 @@
#include <linux/fcntl.h>
#include <linux/quotaops.h>
#include <linux/security.h>
+#include <linux/xattr.h>
/* Taken over from the old code... */
+int inode_setsecurity(struct inode *inode, struct iattr *attr)
+{
+ const char *key = security_inode_xattr_getname();
+ const char *suffix = key + XATTR_SECURITY_PREFIX_LEN;
+ int error;
+
+ if (inode->i_security == NULL)
+ return -EOPNOTSUPP;
+
+ if (!attr->ia_valid & ATTR_SECURITY_LABEL)
+ return -EINVAL;
+
+ error = security_inode_setsecurity(inode, suffix, attr->ia_label,
+ attr->ia_label_len, 0);
+ if (error)
+ printk("%s() %s %d security_inode_setsecurity() %d\n", __func__,
+ (char *)attr->ia_label, attr->ia_label_len, error);
+
+ return (0);
+}
+EXPORT_SYMBOL(inode_setsecurity);
+
/* POSIX UID/GID verification for setting inode attributes. */
int inode_change_ok(struct inode *inode, struct iattr *attr)
{
@@ -94,6 +118,10 @@ int inode_setattr(struct inode * inode, struct iattr * attr)
mode &= ~S_ISGID;
inode->i_mode = mode;
}
+#ifdef CONFIG_SECURITY
+ if (ia_valid & ATTR_SECURITY_LABEL)
+ inode_setsecurity(inode, attr);
+#endif
mark_inode_dirty(inode);
return 0;
@@ -157,6 +185,18 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
if (ia_valid & ATTR_SIZE)
down_write(&dentry->d_inode->i_alloc_sem);
+#ifdef CONFIG_SECURITY
+ if (ia_valid & ATTR_SECURITY_LABEL) {
+ char *key = (char *)security_inode_xattr_getname();
+ vfs_setxattr_locked(dentry, key,
+ attr->ia_label, attr->ia_label_len, 0);
+ /* Avoid calling inode_setsecurity()
+ * via inode_setattr() below
+ */
+ attr->ia_valid &= ~ATTR_SECURITY_LABEL;
+ }
+#endif
+
if (inode->i_op && inode->i_op->setattr) {
error = security_inode_setattr(dentry, attr);
if (!error)
diff --git a/fs/xattr.c b/fs/xattr.c
index 91c7929..b7ebc85 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -67,9 +67,9 @@ xattr_permission(struct inode *inode, const char *name, int mask)
return permission(inode, mask, NULL);
}
-int
-vfs_setxattr(struct dentry *dentry, char *name, void *value,
- size_t size, int flags)
+static int
+_vfs_setxattr(struct dentry *dentry, char *name, void *value,
+ size_t size, int flags, int lock)
{
struct inode *inode = dentry->d_inode;
int error;
@@ -78,7 +78,8 @@ vfs_setxattr(struct dentry *dentry, char *name, void *value,
if (error)
return error;
- mutex_lock(&inode->i_mutex);
+ if (lock)
+ mutex_lock(&inode->i_mutex);
error = security_inode_setxattr(dentry, name, value, size, flags);
if (error)
goto out;
@@ -95,15 +96,33 @@ vfs_setxattr(struct dentry *dentry, char *name, void *value,
const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
error = security_inode_setsecurity(inode, suffix, value,
size, flags);
- if (!error)
+ if (!error) {
+ fsnotify_change(dentry, ATTR_SECURITY_LABEL);
fsnotify_xattr(dentry);
+ }
}
out:
- mutex_unlock(&inode->i_mutex);
+ if (lock)
+ mutex_unlock(&inode->i_mutex);
return error;
}
+
+int
+vfs_setxattr(struct dentry *dentry, char *name, void *value,
+ size_t size, int flags)
+{
+ return _vfs_setxattr(dentry, name, value, size, flags, 1);
+}
EXPORT_SYMBOL_GPL(vfs_setxattr);
+int
+vfs_setxattr_locked(struct dentry *dentry, char *name, void *value,
+ size_t size, int flags)
+{
+ return _vfs_setxattr(dentry, name, value, size, flags, 0);
+}
+EXPORT_SYMBOL_GPL(vfs_setxattr_locked);
+
ssize_t
xattr_getsecurity(struct inode *inode, const char *name, void *value,
size_t size)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b3ec4a4..3383ae4 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -333,6 +333,10 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
#define ATTR_KILL_PRIV 16384
#define ATTR_OPEN 32768 /* Truncating from open(O_TRUNC) */
+#ifdef CONFIG_SECURITY
+#define ATTR_SECURITY_LABEL 65536
+#endif
+
/*
* This is the Inode Attributes structure, used for notify_change(). It
* uses the above definitions as flags, to know which values have changed.
@@ -358,6 +362,10 @@ struct iattr {
* check for (ia_valid & ATTR_FILE), and not for (ia_file != NULL).
*/
struct file *ia_file;
+#ifdef CONFIG_SECURITY
+ void *ia_label;
+ u32 ia_label_len;
+#endif
};
/*
@@ -1974,6 +1982,9 @@ extern int buffer_migrate_page(struct address_space *,
#define buffer_migrate_page NULL
#endif
+#ifdef CONFIG_SECURITY
+extern int inode_setsecurity(struct inode *inode, struct iattr *attr);
+#endif
extern int inode_change_ok(struct inode *, struct iattr *);
extern int __must_check inode_setattr(struct inode *, struct iattr *);
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index df6b95d..1169963 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -50,6 +50,7 @@ ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
ssize_t vfs_getxattr(struct dentry *, char *, void *, size_t);
ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
int vfs_setxattr(struct dentry *, char *, void *, size_t, int);
+int vfs_setxattr_locked(struct dentry *, char *, void *, size_t, int);
int vfs_removexattr(struct dentry *, char *);
ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size);
--
1.5.3.4
--
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 related [flat|nested] 21+ messages in thread* [PATCH 05/13] Security: Add hook to calculate context based on a negative dentry.
2007-11-16 20:03 [RFC Labeled NFS] Labeling support for NFSv4 David P. Quigley
` (3 preceding siblings ...)
2007-11-16 20:07 ` [PATCH 04/13] VFS: Add label field to the iattr structure David P. Quigley
@ 2007-11-16 20:08 ` David P. Quigley
2007-11-16 20:08 ` [PATCH 06/13] KConfig: Add KConfig entries for SELinux labeled NFS David P. Quigley
` (8 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: David P. Quigley @ 2007-11-16 20:08 UTC (permalink / raw)
To: labeled-nfs; +Cc: selinux
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 sid based on the process and the parent directory contexts.
Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
---
include/linux/security.h | 11 +++++++++++
security/dummy.c | 7 +++++++
security/security.c | 9 +++++++++
security/selinux/hooks.c | 46 ++++++++++++++++++++++++++++++++++++++++++++--
4 files changed, 71 insertions(+), 2 deletions(-)
diff --git a/include/linux/security.h b/include/linux/security.h
index 8c0d687..6ccb010 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1240,6 +1240,8 @@ struct security_operations {
void (*sb_post_pivotroot) (struct nameidata * old_nd,
struct nameidata * new_nd);
+ 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);
int (*inode_init_security) (struct inode *inode, struct inode *dir,
@@ -1497,6 +1499,7 @@ void security_sb_post_mountroot(void);
void security_sb_post_addmount(struct vfsmount *mnt, struct nameidata *mountpoint_nd);
int security_sb_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd);
void security_sb_post_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd);
+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);
int security_inode_init_security(struct inode *inode, struct inode *dir,
@@ -1793,6 +1796,14 @@ static inline void security_sb_post_pivotroot (struct nameidata *old_nd,
struct nameidata *new_nd)
{ }
+static inline int security_dentry_init_security(struct dentry *dentry,
+ int mode,
+ void **ctx,
+ u32 *ctxlen)
+{
+ return 0;
+}
+
static inline int security_inode_alloc (struct inode *inode)
{
return 0;
diff --git a/security/dummy.c b/security/dummy.c
index c2524ab..9a91650 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -245,6 +245,12 @@ static void dummy_sb_post_pivotroot (struct nameidata *old_nd, struct nameidata
return;
}
+static int dummy_dentry_init_security(struct dentry *dentry, int mode,
+ void **ctx, u32 *ctxlen)
+{
+ return -EOPNOTSUPP;
+}
+
static int dummy_inode_alloc_security (struct inode *inode)
{
return 0;
@@ -1003,6 +1009,7 @@ void security_fixup_ops (struct security_operations *ops)
set_to_dummy_if_null(ops, sb_post_addmount);
set_to_dummy_if_null(ops, sb_pivotroot);
set_to_dummy_if_null(ops, sb_post_pivotroot);
+ set_to_dummy_if_null(ops, dentry_init_security);
set_to_dummy_if_null(ops, inode_alloc_security);
set_to_dummy_if_null(ops, inode_free_security);
set_to_dummy_if_null(ops, inode_init_security);
diff --git a/security/security.c b/security/security.c
index cf853a7..c481405 100644
--- a/security/security.c
+++ b/security/security.c
@@ -308,6 +308,15 @@ void security_sb_post_pivotroot(struct nameidata *old_nd, struct nameidata *new_
security_ops->sb_post_pivotroot(old_nd, new_nd);
}
+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_alloc(struct inode *inode)
{
inode->i_security = NULL;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 9083390..c9f5abc 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -60,6 +60,7 @@
#include <linux/udp.h>
#include <linux/dccp.h>
#include <linux/quota.h>
+#include <linux/fsnotify.h>
#include <linux/un.h> /* for Unix socket types */
#include <net/af_unix.h> /* for Unix socket types */
#include <linux/parser.h>
@@ -2086,6 +2087,42 @@ static int selinux_umount(struct vfsmount *mnt, int flags)
/* inode security operations */
+/*
+ * 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_alloc_security(struct inode *inode)
{
return inode_alloc_security(inode);
@@ -2358,8 +2395,11 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, char *name,
"%s, rc=%d\n", __FUNCTION__, (char*)value, -rc);
return;
}
-
+ isec->sclass = inode_mode_to_security_class(inode->i_mode);
isec->sid = newsid;
+ isec->initialized = 1;
+
+ fsnotify_change(dentry, ATTR_SECURITY_LABEL);
return;
}
@@ -2434,8 +2474,9 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
rc = security_context_to_sid((void*)value, size, &newsid);
if (rc)
return rc;
-
+ isec->sclass = inode_mode_to_security_class(inode->i_mode);
isec->sid = newsid;
+ isec->initialized = 1;
return 0;
}
@@ -4793,6 +4834,7 @@ static struct security_operations selinux_ops = {
.sb_mount = selinux_mount,
.sb_umount = selinux_umount,
+ .dentry_init_security = selinux_dentry_init_security,
.inode_alloc_security = selinux_inode_alloc_security,
.inode_free_security = selinux_inode_free_security,
.inode_init_security = selinux_inode_init_security,
--
1.5.3.4
--
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 related [flat|nested] 21+ messages in thread* [PATCH 06/13] KConfig: Add KConfig entries for SELinux labeled NFS
2007-11-16 20:03 [RFC Labeled NFS] Labeling support for NFSv4 David P. Quigley
` (4 preceding siblings ...)
2007-11-16 20:08 ` [PATCH 05/13] Security: Add hook to calculate context based on a negative dentry David P. Quigley
@ 2007-11-16 20:08 ` David P. Quigley
2007-11-16 20:09 ` [PATCH 07/13] NFSv4: Add label recommended attribute and NFSv4 flags David P. Quigley
` (7 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: David P. Quigley @ 2007-11-16 20:08 UTC (permalink / raw)
To: labeled-nfs; +Cc: selinux
This patch adds two entries into the fs/KConfig file. The first entry
NFS_V4_SELINUX enables SELinux labeling support to the NFSv4 client
while the second
entry NFSD_V4_SELINUX enables SELinux labeling support on the server
side.
Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
---
fs/Kconfig | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/fs/Kconfig b/fs/Kconfig
index 429a002..896085f 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1634,6 +1634,15 @@ config NFS_V4
If unsure, say N.
+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 NFS_DIRECTIO
bool "Allow direct I/O on NFS files"
depends on NFS_FS
@@ -1723,6 +1732,15 @@ config NFSD_V4
should only be used if you are interested in helping to test NFSv4.
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.
+
+ If unsure, say N.
+
config NFSD_TCP
bool "Provide NFS server over TCP support"
depends on NFSD
--
1.5.3.4
--
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 related [flat|nested] 21+ messages in thread* [PATCH 07/13] NFSv4: Add label recommended attribute and NFSv4 flags
2007-11-16 20:03 [RFC Labeled NFS] Labeling support for NFSv4 David P. Quigley
` (5 preceding siblings ...)
2007-11-16 20:08 ` [PATCH 06/13] KConfig: Add KConfig entries for SELinux labeled NFS David P. Quigley
@ 2007-11-16 20:09 ` David P. Quigley
2007-11-16 20:10 ` [PATCH 08/13] NFS: Introduce lifecycle managment for label attribute David P. Quigley
` (6 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: David P. Quigley @ 2007-11-16 20:09 UTC (permalink / raw)
To: labeled-nfs; +Cc: selinux
This patch adds a new recommended attribute named label into the NFSv4 file
attribute structure. In addition 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: David P. Quigley <dpquigl@tycho.nsa.gov>
Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
---
fs/nfs/nfs4proc.c | 3 +++
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 | 5 +++--
6 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index f03d9d5..dfa6179 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -96,6 +96,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] = {
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 8726491..af90403 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 255
#define NFS4_ACCESS_READ 0x0001
#define NFS4_ACCESS_LOOKUP 0x0002
@@ -348,6 +349,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 0cac49b..6f190c2 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -118,5 +118,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 daab252..9393572 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 bcb7aba..fba3d6e 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 604a0d7..6c4b122 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -311,7 +311,7 @@ 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_DELTA | FATTR4_WORD1_TIME_METADATA \
| FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID)
/* These will return ERR_INVAL if specified in GETATTR or READDIR. */
@@ -323,7 +323,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_METADATA | 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.3.4
--
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 related [flat|nested] 21+ messages in thread* [PATCH 08/13] NFS: Introduce lifecycle managment for label attribute.
2007-11-16 20:03 [RFC Labeled NFS] Labeling support for NFSv4 David P. Quigley
` (6 preceding siblings ...)
2007-11-16 20:09 ` [PATCH 07/13] NFSv4: Add label recommended attribute and NFSv4 flags David P. Quigley
@ 2007-11-16 20:10 ` David P. Quigley
2007-11-19 11:33 ` [Labeled-nfs] " James Morris
2007-11-16 20:11 ` [PATCH 09/13] NFS: Client implementation of SELINUX Labeling David P. Quigley
` (5 subsequent siblings)
13 siblings, 1 reply; 21+ messages in thread
From: David P. Quigley @ 2007-11-16 20:10 UTC (permalink / raw)
To: labeled-nfs; +Cc: selinux
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.
Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
---
fs/nfs/client.c | 16 ++++++
fs/nfs/dir.c | 25 ++++++++++
fs/nfs/getroot.c | 33 +++++++++++++
fs/nfs/inode.c | 16 ++++++
fs/nfs/namespace.c | 3 +
fs/nfs/nfs3proc.c | 15 ++++++
fs/nfs/nfs4proc.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++-
fs/nfs/proc.c | 13 +++++-
fs/nfs/super.c | 4 ++
include/linux/nfs4.h | 1 -
include/linux/nfs_fs.h | 37 ++++++++++++++
11 files changed, 283 insertions(+), 5 deletions(-)
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 70587f3..2382f98 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -778,6 +778,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);
@@ -828,10 +830,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);
}
@@ -957,6 +961,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);
@@ -1008,11 +1014,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);
}
@@ -1030,6 +1038,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);
@@ -1084,11 +1094,13 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
server->mount_time = jiffies;
+ nfs_fattr_fini(&fattr);
dprintk("<-- nfs_create_referral_server() = %p\n", server);
return server;
error:
nfs_free_server(server);
+ nfs_fattr_fini(&fattr);
dprintk("<-- nfs4_create_referral_server() = error %d\n", error);
return ERR_PTR(error);
}
@@ -1110,6 +1122,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);
@@ -1150,11 +1164,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 3533453..02e68ff 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -534,6 +534,8 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
(long long)filp->f_pos);
nfs_inc_stats(inode, NFSIOS_VFSGETDENTS);
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+
lock_kernel();
res = nfs_revalidate_mapping_nolock(inode, filp->f_mapping);
@@ -592,6 +594,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
res = 0;
break;
}
+ nfs_fattr_fini(&fattr);
}
nfs_unblock_sillyrename(dentry);
unlock_kernel();
@@ -751,6 +754,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);
lock_kernel();
dir = parent->d_inode;
@@ -780,6 +785,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);
+ #endif
+
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
if (error)
goto out_bad;
@@ -792,6 +802,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
out_valid:
unlock_kernel();
dput(parent);
+ nfs_fattr_fini(&fattr);
dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is valid\n",
__FUNCTION__, dentry->d_parent->d_name.name,
dentry->d_name.name);
@@ -811,6 +822,7 @@ out_zap_parent:
d_drop(dentry);
unlock_kernel();
dput(parent);
+ nfs_fattr_fini(&fattr);
dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n",
__FUNCTION__, dentry->d_parent->d_name.name,
dentry->d_name.name);
@@ -878,6 +890,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;
@@ -899,6 +913,11 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
parent = dentry->d_parent;
/* Protect against concurrent sillydeletes */
+ #ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL))
+ nfs_fattr_alloc(&fattr);
+ #endif
+
nfs_block_sillyrename(parent);
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
if (error == -ENOENT)
@@ -925,6 +944,8 @@ out_unblock_sillyrename:
out_unlock:
unlock_kernel();
out:
+ /* Label will give 'unused' warning on 'no_entry' case. */
+ nfs_fattr_fini(&fattr);
return res;
}
@@ -1193,6 +1214,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;
@@ -1226,6 +1248,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;
@@ -1252,6 +1275,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;
@@ -1459,6 +1483,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 522e5ad..8ac024e 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -54,6 +54,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));
+
/* create a dummy root dentry with dummy inode for this superblock */
if (!sb->s_root) {
struct nfs_fh dummyfh;
@@ -112,6 +114,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;
}
@@ -136,6 +139,10 @@ 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
+ nfs_fattr_alloc(&fattr); /* Unconditional, no server caps yet. */
+#endif
fsinfo.fattr = &fattr;
nfs_fattr_init(&fattr);
@@ -147,12 +154,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;
}
@@ -160,6 +169,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;
}
@@ -192,6 +202,7 @@ eat_dot_dir:
) {
printk(KERN_ERR "nfs4_get_root:"
" Mount path contains reference to \"..\"\n");
+ nfs_fattr_fini(&fattr);
return -EINVAL;
}
@@ -200,16 +211,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);
+#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;
}
@@ -217,6 +237,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;
}
@@ -224,6 +245,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;
}
@@ -276,19 +298,30 @@ 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
+ /* XXX: Should this be nfs_server_capable(NFS_CAP_SECURITY_LABEL) ?*/
+ if (server->caps & NFS_CAP_SECURITY_LABEL)
+ nfs_fattr_alloc(&fattr);
+#endif
+
/* get the actual root for this mount */
error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr);
if (error < 0) {
dprintk("nfs_get_root: getattr error = %d\n", -error);
+ nfs_fattr_fini(&fattr);
return ERR_PTR(error);
}
inode = nfs_fhget(sb, mntfh, &fattr);
if (IS_ERR(inode)) {
dprintk("nfs_get_root: get root inode failed\n");
+ nfs_fattr_fini(&fattr);
return ERR_PTR(PTR_ERR(inode));
}
+ nfs_fattr_fini(&fattr);
+
/* root dentries normally start off anonymous and get spliced in later
* if the dentry tree reaches them; however if the dentry already
* exists, we'll pick it up at this point and use it as the root
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index db5d96d..4c3d501 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -357,6 +357,12 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
nfs_inc_stats(inode, NFSIOS_VFSSETATTR);
+ 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);
+#endif
+
/* skip mode change if it's just for clearing setuid/setgid */
if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
attr->ia_valid &= ~ATTR_MODE;
@@ -386,6 +392,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
if (error == 0)
nfs_refresh_inode(inode, &fattr);
unlock_kernel();
+ nfs_fattr_fini(&fattr);
return error;
}
@@ -637,6 +644,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));
+
lock_kernel();
if (is_bad_inode(inode))
goto out_nowait;
@@ -651,6 +661,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);
+#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",
@@ -687,6 +702,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
out_nowait:
unlock_kernel();
+ nfs_fattr_fini(&fattr);
return status;
}
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index acfc56f..79858c7 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", __FUNCTION__);
dput(nd->dentry);
@@ -141,6 +143,7 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
nd->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", __FUNCTION__, err);
dprintk("<-- nfs_follow_mountpoint() = %d\n", err);
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 4cdc236..1df7137 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -383,6 +383,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;
}
@@ -482,6 +483,9 @@ nfs3_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));
+ memset(&dir_attr, 0, sizeof(struct nfs_fattr));
+
nfs_fattr_init(&dir_attr);
nfs_fattr_init(&fattr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
@@ -490,6 +494,8 @@ nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
goto out;
status = nfs_instantiate(dentry, &fhandle, &fattr);
out:
+ nfs_fattr_fini(&fattr);
+ nfs_fattr_fini(&dir_attr);
dprintk("NFS reply symlink: %d\n", status);
return status;
}
@@ -522,6 +528,8 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
sattr->ia_mode &= ~current->fs->umask;
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+ memset(&dir_attr, 0, sizeof(struct nfs_fattr));
nfs_fattr_init(&dir_attr);
nfs_fattr_init(&fattr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
@@ -533,6 +541,8 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
goto out;
status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
out:
+ nfs_fattr_fini(&fattr);
+ nfs_fattr_fini(&dir_attr);
dprintk("NFS reply mkdir: %d\n", status);
return status;
}
@@ -640,6 +650,9 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
mode_t mode = sattr->ia_mode;
int status;
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+ memset(&dir_attr, 0, sizeof(struct nfs_fattr));
+
switch (sattr->ia_mode & S_IFMT) {
case S_IFBLK: arg.type = NF3BLK; break;
case S_IFCHR: arg.type = NF3CHR; break;
@@ -664,6 +677,8 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
goto out;
status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
out:
+ nfs_fattr_fini(&fattr);
+ nfs_fattr_fini(&dir_attr);
dprintk("NFS reply mknod: %d\n", status);
return status;
}
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index dfa6179..59dd4eb 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.f_attr = &p->f_attr;
p->o_res.dir_attr = &p->dir_attr;
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);
}
@@ -275,6 +277,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;
+ memset(&p->attrs, 0, sizeof(struct iattr));
if (flags & O_EXCL) {
u32 *s = (u32 *) p->o_arg.u.verifier.data;
s[0] = jiffies;
@@ -282,12 +285,22 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
} else if (flags & O_CREAT) {
p->o_arg.u.attrs = &p->attrs;
memcpy(&p->attrs, attrs, sizeof(p->attrs));
+ /* The above creates an additional reference to ia_label.
+ * The CALLER must free this, not nfs4_opendata_free()
+ */
}
p->c_arg.fh = &p->o_res.fh;
p->c_arg.stateid = &p->o_res.stateid;
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);
+ nfs_fattr_alloc(&p->dir_attr);
+ }
+#endif
return p;
err_free:
kfree(p);
@@ -304,6 +317,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);
dput(p->path.dentry);
@@ -1213,6 +1228,7 @@ static void nfs4_free_closedata(void *data)
nfs4_put_state_owner(sp);
dput(calldata->path.dentry);
mntput(calldata->path.mnt);
+ nfs_fattr_fini(&calldata->fattr);
kfree(calldata);
}
@@ -1319,6 +1335,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
calldata = kmalloc(sizeof(*calldata), GFP_KERNEL);
if (calldata == NULL)
goto out;
+ memset(calldata, 0, sizeof(*calldata));
calldata->inode = state->inode;
calldata->state = state;
calldata->arg.fh = NFS_FH(state->inode);
@@ -1333,6 +1350,12 @@ 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);
+ memset(&calldata->fattr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL)
+ nfs_fattr_alloc(&calldata->fattr);
+#endif
+
task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_close_ops, calldata);
if (IS_ERR(task))
return PTR_ERR(task);
@@ -1342,6 +1365,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);
@@ -1387,7 +1411,13 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
struct rpc_cred *cred;
struct nfs4_state *state;
struct dentry *res;
+ int error;
+
+ cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
+ 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;
@@ -1398,9 +1428,6 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
BUG_ON(nd->intent.open.flags & O_CREAT);
}
- cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
- if (IS_ERR(cred))
- return (struct dentry *)cred;
parent = dentry->d_parent;
/* Protect against concurrent sillydeletes */
nfs_block_sillyrename(parent);
@@ -1761,6 +1788,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...
*/
@@ -1777,6 +1806,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);
+#endif
nfs_fattr_init(&fattr);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
if (!status) {
@@ -1789,6 +1822,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 +1936,17 @@ 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);
+#endif
status = nfs4_do_setattr(state->inode, &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);
@@ -1934,12 +1975,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);
+#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;
}
@@ -1964,6 +2011,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);
+#endif
+ nfs_fattr_init(&res->dir_attr);
}
static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
@@ -1974,6 +2028,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;
}
@@ -2001,6 +2056,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);
+ nfs_fattr_alloc(&new_fattr);
+ }
+#endif
nfs_fattr_init(res.old_fattr);
nfs_fattr_init(res.new_fattr);
status = rpc_call_sync(server->client, &msg, 0);
@@ -2011,6 +2075,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;
}
@@ -2050,6 +2116,16 @@ 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);
+ nfs_fattr_alloc(&dir_attr);
+ }
+#endif
+
nfs_fattr_init(res.fattr);
nfs_fattr_init(res.dir_attr);
status = rpc_call_sync(server->client, &msg, 0);
@@ -2059,6 +2135,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;
}
@@ -2104,6 +2182,16 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
if (len > NFS4_MAXPATHLEN)
return -ENAMETOOLONG;
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+ memset(&dir_fattr, 0, sizeof(struct nfs_fattr));
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL) {
+ nfs_fattr_alloc(&fattr);
+ nfs_fattr_alloc(&dir_fattr);
+ }
+#endif
+
arg.u.symlink.pages = &page;
arg.u.symlink.len = len;
nfs_fattr_init(&fattr);
@@ -2115,6 +2203,8 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
nfs_post_op_update_inode(dir, res.dir_fattr);
status = nfs_instantiate(dentry, &fhandle, &fattr);
}
+ nfs_fattr_fini(&fattr);
+ nfs_fattr_fini(&dir_fattr);
return status;
}
@@ -2159,6 +2249,16 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
};
int status;
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+ memset(&dir_fattr, 0, sizeof(struct nfs_fattr));
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL) {
+ nfs_fattr_alloc(&fattr);
+ nfs_fattr_alloc(&dir_fattr);
+ }
+#endif
+
nfs_fattr_init(&fattr);
nfs_fattr_init(&dir_fattr);
@@ -2168,6 +2268,8 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
nfs_post_op_update_inode(dir, res.dir_fattr);
status = nfs_instantiate(dentry, &fhandle, &fattr);
}
+ nfs_fattr_fini(&fattr);
+ nfs_fattr_fini(&dir_fattr);
return status;
}
@@ -2261,6 +2363,15 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
int status;
int mode = sattr->ia_mode;
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+ memset(&dir_fattr, 0, sizeof(struct nfs_fattr));
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL) {
+ nfs_fattr_alloc(&fattr);
+ nfs_fattr_alloc(&dir_fattr);
+ }
+#endif
nfs_fattr_init(&fattr);
nfs_fattr_init(&dir_fattr);
@@ -2287,6 +2398,8 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
nfs_post_op_update_inode(dir, res.dir_fattr);
status = nfs_instantiate(dentry, &fh, &fattr);
}
+ nfs_fattr_fini(&fattr);
+ nfs_fattr_fini(&dir_fattr);
return status;
}
@@ -3001,6 +3114,11 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *calldata)
.rpc_resp = &data->res,
.rpc_cred = data->cred,
};
+ memset(data->res.fattr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (data->res.server->caps & NFS_CAP_SECURITY_LABEL)
+ nfs_fattr_alloc(data->res.fattr);
+#endif
nfs_fattr_init(data->res.fattr);
rpc_call_setup(task, &msg, 0);
}
@@ -3017,6 +3135,7 @@ static void nfs4_delegreturn_release(void *calldata)
{
struct nfs4_delegreturndata *data = calldata;
+ nfs_fattr_fini(data->res.fattr);
put_rpccred(data->cred);
kfree(calldata);
}
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 4f80d88..76f9951 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -208,12 +208,15 @@ 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);
+
+ 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 create: %d\n", status);
return status;
}
@@ -255,6 +258,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);
@@ -266,6 +270,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;
}
@@ -378,6 +383,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);
@@ -392,6 +399,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;
}
@@ -419,11 +427,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 fa517ae..c8f64da 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -340,6 +340,8 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
};
int error;
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+
lock_kernel();
error = server->nfs_client->rpc_ops->statfs(server, fh, &res);
@@ -374,11 +376,13 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
buf->f_namelen = server->namelen;
unlock_kernel();
+ nfs_fattr_fini(&fattr);
return 0;
out_err:
dprintk("%s: statfs error = %d\n", __FUNCTION__, -error);
unlock_kernel();
+ nfs_fattr_fini(&fattr);
return error;
}
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index af90403..d7130b4 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -21,7 +21,6 @@
#define NFS4_FHSIZE 128
#define NFS4_MAXPATHLEN PATH_MAX
#define NFS4_MAXNAMLEN NAME_MAX
-#define NFS4_MAXLABELLEN 255
#define NFS4_ACCESS_READ 0x0001
#define NFS4_ACCESS_LOOKUP 0x0002
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index e82a6eb..de22a0d 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -564,6 +564,43 @@ extern void * nfs_root_data(void);
# else
# define ifdebug(fac) if (0)
# endif
+
+
+/*This was originally in nfs4.h however it can't be since it is
+ * used nfsv3 code */
+#define NFS_MAXLABELLEN 255
+
+#ifdef CONFIG_SECURITY
+#define nfs_fattr_alloc(fattr) \
+{ \
+ (fattr)->label = kmalloc(NFS_MAXLABELLEN, GFP_ATOMIC); \
+ (fattr)->label_len = NFS_MAXLABELLEN; \
+ memset((fattr)->label, 0, NFS_MAXLABELLEN); \
+}
+
+#define nfs_fattr_fini(fattr) \
+{ \
+ if ((fattr)->label == NULL) { \
+ if ((fattr)->label_len != 0) { \
+ printk("%s:%d %s() nfs_fattr label available (%d)\n",\
+ __FILE__, __LINE__, __func__, \
+ (fattr)->label_len); \
+ } \
+ } else { \
+ if ((fattr)->label_len == NFS_MAXLABELLEN) \
+ printk("%s:%d %s() nfs_fattr label unused\n", \
+ __FILE__, __LINE__, __func__); \
+ \
+ kfree((fattr)->label); \
+ (fattr)->label = NULL; \
+ (fattr)->label_len = 0; \
+ } \
+}
+#else
+#define nfs_fattr_alloc(fattr)
+#define nfs_fattr_fini(fattr)
+#endif /* CONFIG_SECURITY */
+
#endif /* __KERNEL */
#endif
--
1.5.3.4
--
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 related [flat|nested] 21+ messages in thread* Re: [Labeled-nfs] [PATCH 08/13] NFS: Introduce lifecycle managment for label attribute.
2007-11-16 20:10 ` [PATCH 08/13] NFS: Introduce lifecycle managment for label attribute David P. Quigley
@ 2007-11-19 11:33 ` James Morris
2007-11-19 16:00 ` Casey Schaufler
[not found] ` <4741C77D.9080209@sparta.com>
0 siblings, 2 replies; 21+ messages in thread
From: James Morris @ 2007-11-19 11:33 UTC (permalink / raw)
To: David P. Quigley; +Cc: Labeled NFS, selinux
On Fri, 16 Nov 2007, David P. Quigley wrote:
> +#ifdef CONFIG_SECURITY
> +#define nfs_fattr_alloc(fattr) \
> +{ \
> + (fattr)->label = kmalloc(NFS_MAXLABELLEN, GFP_ATOMIC); \
> + (fattr)->label_len = NFS_MAXLABELLEN; \
> + memset((fattr)->label, 0, NFS_MAXLABELLEN); \
> +}
These should be normal functions, perhaps in their own file which is
conditionally built (and containing other label-specific code).
You need to check the return of kmalloc().
I suggest passing a gfp_t parameter to the allocation function to allow
the caller to determine the allocation flags (unless you know it will
always be GFP_ATOMIC).
Use kzalloc() instead of kmalloc() + memset().
It seems wasteful to always allocate the maximum sized label.
--
James Morris
<jmorris@namei.org>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [Labeled-nfs] [PATCH 08/13] NFS: Introduce lifecycle managment for label attribute.
2007-11-19 11:33 ` [Labeled-nfs] " James Morris
@ 2007-11-19 16:00 ` Casey Schaufler
[not found] ` <4741C77D.9080209@sparta.com>
1 sibling, 0 replies; 21+ messages in thread
From: Casey Schaufler @ 2007-11-19 16:00 UTC (permalink / raw)
To: James Morris, David P. Quigley; +Cc: Labeled NFS, selinux
--- James Morris <jmorris@namei.org> wrote:
> On Fri, 16 Nov 2007, David P. Quigley wrote:
>
>
> > +#ifdef CONFIG_SECURITY
> > +#define nfs_fattr_alloc(fattr) \
> > +{ \
> > + (fattr)->label = kmalloc(NFS_MAXLABELLEN, GFP_ATOMIC); \
> > + (fattr)->label_len = NFS_MAXLABELLEN; \
> > + memset((fattr)->label, 0, NFS_MAXLABELLEN); \
> > +}
>
> These should be normal functions, perhaps in their own file which is
> conditionally built (and containing other label-specific code).
>
> You need to check the return of kmalloc().
>
> I suggest passing a gfp_t parameter to the allocation function to allow
> the caller to determine the allocation flags (unless you know it will
> always be GFP_ATOMIC).
>
> Use kzalloc() instead of kmalloc() + memset().
>
> It seems wasteful to always allocate the maximum sized label.
You could have a look at the smack_import() scheme. If you're
looking at a gazillion enormous, short lived labels on a system
it would be a bad choice, but even if you're labeling every file
differently (please say you're not) you may find it a better
mechanism. Your label lifecycle management issues go "poof".
Just a thought.
Casey Schaufler
casey@schaufler-ca.com
--
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] 21+ messages in thread[parent not found: <4741C77D.9080209@sparta.com>]
* Re: [Labeled-nfs] [PATCH 08/13] NFS: Introduce lifecycle managment for label attribute.
[not found] ` <4741C77D.9080209@sparta.com>
@ 2007-11-19 21:44 ` James Morris
0 siblings, 0 replies; 21+ messages in thread
From: James Morris @ 2007-11-19 21:44 UTC (permalink / raw)
To: Matthew N. Dodd; +Cc: David P. Quigley, Labeled NFS, selinux
On Mon, 19 Nov 2007, Matthew N. Dodd wrote:
> >
> > You need to check the return of kmalloc().
>
> If kmalloc() returns NULL then any label data returned by the GETATTR
> operation will not be used. Labeling would be performed by the policy in the
> 'd_instantiate' function.
I suspect this would lead to inconsistent behavior & confuse folk.
Perhaps try and return an error (which seems typical in much of the
surrounding code) as a first option.
--
James Morris
<jmorris@namei.org>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 09/13] NFS: Client implementation of SELINUX Labeling
2007-11-16 20:03 [RFC Labeled NFS] Labeling support for NFSv4 David P. Quigley
` (7 preceding siblings ...)
2007-11-16 20:10 ` [PATCH 08/13] NFS: Introduce lifecycle managment for label attribute David P. Quigley
@ 2007-11-16 20:11 ` David P. Quigley
2007-11-19 11:44 ` [Labeled-nfs] " James Morris
2007-11-16 20:11 ` [PATCH 10/13] NFS: Extend nfs xattr handlers to accept the security namespace David P. Quigley
` (4 subsequent siblings)
13 siblings, 1 reply; 21+ messages in thread
From: David P. Quigley @ 2007-11-16 20:11 UTC (permalink / raw)
To: labeled-nfs; +Cc: selinux
There are several places where recommended attributes are implemented in the
NFSv4 client code. This patch adds two functions to encode and decode the secid
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. Even though the code is there to encode a
label to be sent back to the server there does not appear to be an interface to
use it yet.
Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
---
fs/nfs/dir.c | 72 ++++++++++++++++++++-
fs/nfs/inode.c | 40 +++++++++++-
fs/nfs/nfs4proc.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++-
fs/nfs/nfs4xdr.c | 47 +++++++++++++
fs/nfs/super.c | 11 +++
security/security.c | 2 +
6 files changed, 353 insertions(+), 3 deletions(-)
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 02e68ff..0738827 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -39,6 +39,10 @@
#include "delegation.h"
#include "iostat.h"
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+#include <linux/security.h>
+#endif
+
/* #define NFS_DEBUG_VERBOSE 1 */
static int nfs_opendir(struct inode *, struct file *);
@@ -1218,18 +1222,36 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;
- if ((nd->flags & LOOKUP_CREATE) != 0)
+ if ((nd->flags & LOOKUP_CREATE) != 0) {
open_flags = nd->intent.open.flags;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+ error = security_dentry_init_security(dentry,
+ attr.ia_mode,
+ &attr.ia_label, &attr.ia_label_len);
+ if (error == 0)
+ attr.ia_valid |= ATTR_SECURITY_LABEL;
+ }
+#endif
+ }
lock_kernel();
error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, nd);
if (error != 0)
goto out_err;
unlock_kernel();
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (attr.ia_label != NULL)
+ kfree(attr.ia_label);
+#endif
return 0;
out_err:
unlock_kernel();
d_drop(dentry);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (attr.ia_label != NULL)
+ kfree(attr.ia_label);
+#endif
return error;
}
@@ -1252,8 +1274,22 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+ status = security_dentry_init_security(dentry,
+ attr.ia_mode,
+ &attr.ia_label, &attr.ia_label_len);
+ if (status == 0)
+ attr.ia_valid |= ATTR_SECURITY_LABEL;
+ }
+#endif
+
lock_kernel();
status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (attr.ia_label != NULL)
+ kfree(attr.ia_label);
+#endif
if (status != 0)
goto out_err;
unlock_kernel();
@@ -1279,15 +1315,31 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
attr.ia_valid = ATTR_MODE;
attr.ia_mode = mode | S_IFDIR;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+ error = security_dentry_init_security(dentry, attr.ia_mode,
+ &attr.ia_label, &attr.ia_label_len);
+ if (error == 0)
+ attr.ia_valid |= ATTR_SECURITY_LABEL;
+ }
+#endif
lock_kernel();
error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr);
if (error != 0)
goto out_err;
unlock_kernel();
+ #ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (attr.ia_label != NULL)
+ kfree(attr.ia_label);
+ #endif
return 0;
out_err:
d_drop(dentry);
unlock_kernel();
+ #ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (attr.ia_label != NULL)
+ kfree(attr.ia_label);
+ #endif
return error;
}
@@ -1487,6 +1539,16 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
attr.ia_mode = S_IFLNK | S_IRWXUGO;
attr.ia_valid = ATTR_MODE;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+ error = security_dentry_init_security(dentry,
+ attr.ia_mode,
+ &attr.ia_label, &attr.ia_label_len);
+ if (error == 0)
+ attr.ia_valid |= ATTR_SECURITY_LABEL;
+ }
+#endif
+
lock_kernel();
page = alloc_page(GFP_HIGHUSER);
@@ -1509,6 +1571,10 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
d_drop(dentry);
__free_page(page);
unlock_kernel();
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (attr.ia_label != NULL)
+ kfree(attr.ia_label);
+#endif
return error;
}
@@ -1527,6 +1593,10 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
__free_page(page);
unlock_kernel();
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (attr.ia_label != NULL)
+ kfree(attr.ia_label);
+#endif
return 0;
}
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 4c3d501..3982867 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -37,7 +37,7 @@
#include <linux/vfs.h>
#include <linux/inet.h>
#include <linux/nfs_xdr.h>
-
+#include <linux/xattr.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -47,6 +47,10 @@
#include "iostat.h"
#include "internal.h"
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+#include <linux/security.h>
+#endif
+
#define NFSDBG_FACILITY NFSDBG_VFS
#define NFS_64_BIT_INODE_NUMBERS_ENABLED 1
@@ -237,6 +241,26 @@ 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
+static inline void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr)
+{
+ int error;
+
+ if ((fattr->valid & NFS_ATTR_FATTR_V4) &&
+ (fattr->bitmap[1] & FATTR4_WORD1_SECURITY_LABEL) &&
+ (fattr->label != NULL) &&
+ (inode->i_security != NULL)) {
+ const char *suffix = security_inode_xattr_getname() +
+ XATTR_SECURITY_PREFIX_LEN;
+ error = security_inode_setsecurity(inode, suffix, fattr->label,
+ fattr->label_len, 0);
+ if (error)
+ printk("%s() %s %d security_inode_setsecurity() %d\n",
+ __func__, 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.
@@ -317,6 +341,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 /* CONFIG_NFS_V4_SECURITY_LABEL */
+
if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
/*
* report the blocks in 512byte units
@@ -425,6 +454,11 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
inode->i_size = attr->ia_size;
vmtruncate(inode, attr->ia_size);
}
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if ((attr->ia_valid & ATTR_SECURITY_LABEL) != 0)
+ inode_setsecurity(inode, attr);
+#endif
}
static int nfs_wait_schedule(void *word)
@@ -1077,6 +1111,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
inode->i_uid = fattr->uid;
inode->i_gid = fattr->gid;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ nfs_setsecurity(inode, fattr);
+#endif /* CONFIG_NFS_V4_SECURITY_LABEL */
+
if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
/*
* report the blocks in 512byte units
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 59dd4eb..47fa612 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -48,11 +48,16 @@
#include <linux/smp_lock.h>
#include <linux/namei.h>
#include <linux/mount.h>
+#include <linux/xattr.h>
#include "nfs4_fs.h"
#include "delegation.h"
#include "iostat.h"
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+#include <linux/security.h>
+#endif
+
#define NFSDBG_FACILITY NFSDBG_PROC
#define NFS4_POLL_RETRY_MIN (HZ/10)
@@ -1411,7 +1416,6 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
struct rpc_cred *cred;
struct nfs4_state *state;
struct dentry *res;
- int error;
cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
if (IS_ERR(cred))
@@ -1423,6 +1427,16 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
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,
+ &attr.ia_label, &attr.ia_label_len);
+ if (error == 0)
+ attr.ia_valid |= ATTR_SECURITY_LABEL;
+ }
+#endif
} else {
attr.ia_valid = 0;
BUG_ON(nd->intent.open.flags & O_CREAT);
@@ -1433,6 +1447,10 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
nfs_block_sillyrename(parent);
state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred);
put_rpccred(cred);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (attr.ia_label != NULL)
+ kfree(attr.ia_label);
+#endif
if (IS_ERR(state)) {
if (PTR_ERR(state) == -ENOENT) {
d_add(dentry, NULL);
@@ -1505,6 +1523,12 @@ 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 (res.attr_bitmask[1] & FATTR4_WORD1_SECURITY_LABEL)
+ server->caps |= NFS_CAP_SECURITY_LABEL;
+#else
+ server->attr_bitmask[1] &= ~FATTR4_WORD1_SECURITY_LABEL;
+#endif
if (res.has_links != 0)
server->caps |= NFS_CAP_HARDLINKS;
if (res.has_symlinks != 0)
@@ -2890,6 +2914,164 @@ 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;
+
+ return -EOPNOTSUPP;
+
+ nfs_fattr_alloc(&fattr);
+ 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 iattr *sattr,
+ struct nfs_fattr *fattr,
+ struct nfs4_state *state)
+{
+ 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,
+ };
+ 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;
+
+ 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 iattr *sattr,
+ 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, sattr,
+ fattr, state),
+ &exception);
+ } while (exception.retry);
+ return err;
+}
+
+static int
+nfs4_set_security_label(struct dentry *dentry, const void *buf, size_t buflen)
+{
+ struct nfs_fattr fattr;
+ struct iattr sattr;
+ 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);
+ nfs_fattr_init(&fattr);
+
+ memset(&sattr, 0, sizeof(struct iattr));
+ sattr.ia_valid = ATTR_SECURITY_LABEL;
+ sattr.ia_label = (char *)buf;
+ sattr.ia_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, &sattr, &fattr, state);
+ if (status == 0)
+ nfs_setattr_update_inode(inode, &sattr);
+ if (ctx != NULL)
+ put_nfs_open_context(ctx);
+ put_rpccred(cred);
+ nfs_fattr_fini(&fattr);
+ return status;
+}
+#endif
+
+
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 51dd380..3736817 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -51,6 +51,7 @@
#include <linux/nfs4.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_idmap.h>
+#include <linux/security.h>
#include "nfs4_fs.h"
#define NFSDBG_FACILITY NFSDBG_XDR
@@ -649,6 +650,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 (iap->ia_valid & ATTR_SECURITY_LABEL)
+ len += 4 + (XDR_QUADLEN(iap->ia_label_len) << 2);
+#endif
if (iap->ia_valid & ATTR_ATIME_SET)
len += 16;
else if (iap->ia_valid & ATTR_ATIME)
@@ -707,6 +712,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 (iap->ia_valid & ATTR_SECURITY_LABEL) {
+ bmval1 |= FATTR4_WORD1_SECURITY_LABEL;
+ WRITE32(iap->ia_label_len);
+ WRITEMEM(iap->ia_label, iap->ia_label_len);
+ }
+#endif /* CONFIG_NFS_V4_SECURITY_LABEL */
/*
* Now we backfill the bitmap and the attribute buffer length.
@@ -2952,6 +2964,37 @@ 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)
+{
+ uint32_t 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("%s(): ctxlen (%d) < len (%d)\n",
+ __func__, *ctxlen, len);
+ } else {
+ memcpy(*ctx, (char *)p, len);
+ (*ctx)[len + 1] = '\0';
+ }
+ }
+ *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);
@@ -3184,6 +3227,10 @@ 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 c8f64da..012211f 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -462,6 +462,13 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
seq_printf(m, ",timeo=%lu", 10U * clp->retrans_timeo / HZ);
seq_printf(m, ",retrans=%u", clp->retrans_count);
seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor));
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if ((nfss->nfs_client->cl_nfsversion == 4) &&
+ (nfss->attr_bitmask[1] & FATTR4_WORD1_SECURITY_LABEL))
+ seq_printf(m, ",security_label");
+#endif /* CONFIG_NFS_V4_SECURITY_LABEL */
+
}
/*
@@ -516,6 +523,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->attr_bitmask[1] & FATTR4_WORD1_SECURITY_LABEL)
+ seq_printf(m, ",security_label");
+#endif /* CONFIG_NFS_V4_SECURITY_LABEL */
}
#endif
diff --git a/security/security.c b/security/security.c
index c481405..5471489 100644
--- a/security/security.c
+++ b/security/security.c
@@ -499,6 +499,7 @@ int security_inode_getsecurity(const struct inode *inode, const char *name, void
return 0;
return security_ops->inode_getsecurity(inode, name, buffer, alloc);
}
+EXPORT_SYMBOL(security_inode_getsecurity);
int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags)
{
@@ -506,6 +507,7 @@ int security_inode_setsecurity(struct inode *inode, const char *name, const void
return 0;
return security_ops->inode_setsecurity(inode, name, value, size, flags);
}
+EXPORT_SYMBOL(security_inode_setsecurity);
int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
{
--
1.5.3.4
--
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 related [flat|nested] 21+ messages in thread* Re: [Labeled-nfs] [PATCH 09/13] NFS: Client implementation of SELINUX Labeling
2007-11-16 20:11 ` [PATCH 09/13] NFS: Client implementation of SELINUX Labeling David P. Quigley
@ 2007-11-19 11:44 ` James Morris
0 siblings, 0 replies; 21+ messages in thread
From: James Morris @ 2007-11-19 11:44 UTC (permalink / raw)
To: David P. Quigley; +Cc: labeled-nfs, selinux
On Fri, 16 Nov 2007, David P. Quigley wrote:
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> + if (attr.ia_label != NULL)
> + kfree(attr.ia_label);
> +#endif
Will it be typical for ia_label to be non-NULL ? If so, you can leave out
the NULL check, as kfree() does that via unlikely(). i.e. only check for
NULL if you think it is likely (>90%) that it will be NULL.
Generally, you'll likely need to remove all of the #ifdefs from the core
code, and use static inlines or normal functions instead (to be compiled
away when not required).
> + sattr.ia_label = (char *)buf;
No need to cast void pointers.
--
James Morris
<jmorris@namei.org>
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 10/13] NFS: Extend nfs xattr handlers to accept the security namespace
2007-11-16 20:03 [RFC Labeled NFS] Labeling support for NFSv4 David P. Quigley
` (8 preceding siblings ...)
2007-11-16 20:11 ` [PATCH 09/13] NFS: Client implementation of SELINUX Labeling David P. Quigley
@ 2007-11-16 20:11 ` David P. Quigley
2007-11-16 20:12 ` [PATCH 11/13] NFSD: Server implementation of MAC Labeling David P. Quigley
` (3 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: David P. Quigley @ 2007-11-16 20:11 UTC (permalink / raw)
To: labeled-nfs; +Cc: selinux
The existing nfs4 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: David P. Quigley <dpquigl@tycho.nsa.gov>
Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
---
fs/nfs/nfs4proc.c | 61 ++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 46 insertions(+), 15 deletions(-)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 47fa612..2d71e44 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3926,14 +3926,18 @@ 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;
-
- if (!S_ISREG(inode->i_mode) &&
- (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
- return -EPERM;
+ 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);
+ return nfs4_proc_set_acl(inode, buf, buflen);
+ }
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (strcmp(key, security_inode_xattr_getname()) == 0)
+ return nfs4_set_security_label(dentry, buf, buflen);
+#endif
+ return -EOPNOTSUPP;
}
/* The getxattr man page suggests returning -ENODATA for unknown attributes,
@@ -3945,22 +3949,49 @@ 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;
-
- return nfs4_proc_get_acl(inode, buf, buflen);
+ if (strcmp(key, XATTR_NAME_NFSV4_ACL) == 0)
+ return nfs4_proc_get_acl(inode, buf, buflen);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (strcmp(key, security_inode_xattr_getname()) == 0)
+ 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;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ const char *security_name = security_inode_xattr_getname();
+#endif
+ 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 += strlen(security_name) + 1;
+#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)) {
+ l = strlen(security_name) + 1;
+ memcpy(p, security_name, l);
+ p += l;
+ }
+#endif
return len;
}
--
1.5.3.4
--
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 related [flat|nested] 21+ messages in thread* [PATCH 11/13] NFSD: Server implementation of MAC Labeling
2007-11-16 20:03 [RFC Labeled NFS] Labeling support for NFSv4 David P. Quigley
` (9 preceding siblings ...)
2007-11-16 20:11 ` [PATCH 10/13] NFS: Extend nfs xattr handlers to accept the security namespace David P. Quigley
@ 2007-11-16 20:12 ` David P. Quigley
2007-11-16 20:12 ` [PATCH 12/13] NFS: Label change notification for NFSv4 Clients David P. Quigley
` (2 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: David P. Quigley @ 2007-11-16 20:12 UTC (permalink / raw)
To: labeled-nfs; +Cc: selinux
This patch implements the encoding of a MAC label on the server side to be
sent across the wire to the NFSv4 client. At this time there is no method of
receiving a label from the client to be set on the server.
Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
---
fs/nfsd/nfs4xdr.c | 91 +++++++++++++++++++++++++++++++++++++++++++-
fs/nfsd/vfs.c | 7 +++
2 files changed, 97 insertions(+), 1 deletions(-)
create mode 100644 fs/nfs/doimap.c
create mode 100644 include/linux/nfs_doimap.h
diff --git a/fs/nfs/doimap.c b/fs/nfs/doimap.c
new file mode 100644
index 0000000..e69de29
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 5733394..9972b14 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -50,6 +50,7 @@
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/clnt.h>
+#include <linux/nfs_fs.h>
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/state.h>
#include <linux/nfsd/xdr4.h>
@@ -58,6 +59,8 @@
#include <linux/nfs4_acl.h>
#include <linux/sunrpc/gss_api.h>
#include <linux/sunrpc/svcauth_gss.h>
+#include <linux/security.h>
+#include <linux/xattr.h>
#define NFSDDBG_FACILITY NFSDDBG_XDR
@@ -411,6 +414,22 @@ 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) {
+ READ_BUF(4);
+ len += 4;
+ READ32(dummy32);
+ READ_BUF(dummy32);
+ len += (XDR_QUADLEN(dummy32) << 2);
+ READMEM(buf, dummy32);
+ iattr->ia_label_len = dummy32;
+ iattr->ia_label = kmalloc(dummy32 + 1, GFP_ATOMIC);
+ memcpy(iattr->ia_label, buf, dummy32);
+ ((char *)iattr->ia_label)[dummy32 + 1] = '\0';
+ iattr->ia_valid |= ATTR_SECURITY_LABEL;
+ defer_free(argp, kfree, iattr->ia_label);
+ }
+#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
if (len != expected_len)
goto xdr_error;
@@ -1418,6 +1437,44 @@ 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 = 0, len;
+
+ const char *suffix = security_inode_xattr_getname()
+ + XATTR_SECURITY_PREFIX_LEN;
+
+ len = security_inode_getsecurity(dentry->d_inode, suffix, &context, true);
+ if (len < 0) {
+ err = nfserrno(len);
+ goto out;
+ }
+
+ if (len > NFS_MAXLABELLEN) {
+ err = nfserrno(len);
+ goto out_err;
+ }
+ if (*buflen < ((XDR_QUADLEN(len) << 2) + 4)) {
+ err = nfserr_resource;
+ goto out_err;
+ }
+
+ *p = xdr_encode_opaque(*p, context, len);
+ *buflen -= (XDR_QUADLEN(len) << 2) + 4;
+ BUG_ON(*buflen < 0);
+
+out_err:
+ security_release_secctx(context, len);
+out:
+ return err;
+}
+#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
+
#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
@@ -1513,6 +1570,16 @@ 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;
@@ -1523,15 +1590,26 @@ 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
+ /* XXX: turn this on unconditionally for now ...*/
+ if (1 || exp->ex_flags & NFSEXP_SECURITY_LABEL)
+ word1 |= FATTR4_WORD1_SECURITY_LABEL;
+ else
+ word1 &= ~FATTR4_WORD1_SECURITY_LABEL;
+#else
+ word1 &= ~FATTR4_WORD1_SECURITY_LABEL;
+#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
+
WRITE32(2);
WRITE32(word0);
- WRITE32(NFSD_SUPPORTED_ATTRS_WORD1);
+ WRITE32(word1);
}
if (bmval0 & FATTR4_WORD0_TYPE) {
if ((buflen -= 4) < 0)
@@ -1836,6 +1914,17 @@ 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 /* CONFIG_NFSD_V4_SECURITY_LABEL */
+
*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 d019918..0cf1884 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1528,6 +1528,13 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (!host_err) {
if (EX_ISSYNC(fhp->fh_export))
host_err = nfsd_sync_dir(dentry);
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ if (iap && (iap->ia_valid & ATTR_SECURITY_LABEL)) {
+ char *key = (char *)security_inode_xattr_getname();
+ vfs_setxattr_locked(dnew, key,
+ iap->ia_label, iap->ia_label_len, 0);
+ }
+#endif
}
err = nfserrno(host_err);
fh_unlock(fhp);
diff --git a/include/linux/nfs_doimap.h b/include/linux/nfs_doimap.h
new file mode 100644
index 0000000..e69de29
--
1.5.3.4
--
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 related [flat|nested] 21+ messages in thread* [PATCH 12/13] NFS: Label change notification for NFSv4 Clients
2007-11-16 20:03 [RFC Labeled NFS] Labeling support for NFSv4 David P. Quigley
` (10 preceding siblings ...)
2007-11-16 20:12 ` [PATCH 11/13] NFSD: Server implementation of MAC Labeling David P. Quigley
@ 2007-11-16 20:12 ` David P. Quigley
2007-11-16 20:13 ` [PATCH 13/13] NFSD: Label change notification for NFSv4 Server David P. Quigley
2007-11-16 20:56 ` [RFC Labeled NFS] Labeling support for NFSv4 Peter Staubach
13 siblings, 0 replies; 21+ messages in thread
From: David P. Quigley @ 2007-11-16 20:12 UTC (permalink / raw)
To: labeled-nfs; +Cc: selinux
NFSv4 Provides methods for detecting changes in attributes and recalling
delegations when state has changed on the server. This has been extended to
include this functionality for label changes on the server. This patch provides
the client implementation for a new callback used to signal relabeling of
files.
Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
---
fs/nfs/callback.h | 10 ++++
fs/nfs/callback_proc.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++
fs/nfs/callback_xdr.c | 34 +++++++++++++++
fs/nfs/internal.h | 1 +
fs/nfs/nfs3proc.c | 5 ++-
fs/nfs/nfs4proc.c | 13 ++++-
fs/nfs/proc.c | 5 ++-
fs/nfs/super.c | 13 ++++++
include/linux/fcntl.h | 1 +
include/linux/fsnotify.h | 5 ++
include/linux/inotify.h | 3 +-
11 files changed, 188 insertions(+), 6 deletions(-)
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h
index c2bb14e..dfb85d2 100644
--- a/fs/nfs/callback.h
+++ b/fs/nfs/callback.h
@@ -20,6 +20,7 @@ enum nfs4_callback_procnum {
enum nfs4_callback_opnum {
OP_CB_GETATTR = 3,
OP_CB_RECALL = 4,
+ OP_CB_RELABEL = 5,
OP_CB_ILLEGAL = 10044,
};
@@ -59,8 +60,17 @@ struct cb_recallargs {
uint32_t truncate;
};
+struct cb_relabelargs {
+ struct sockaddr_in *addr;
+ unsigned long ino;
+ struct nfs_fh fh;
+ const char *label;
+ int labellen;
+};
+
extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res);
extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy);
+extern __be32 nfs4_callback_relabel(struct cb_relabelargs *args, void *dummy);
#ifdef CONFIG_NFS_V4
extern int nfs_callback_up(void);
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 72e55d8..6eddc48 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -7,6 +7,8 @@
*/
#include <linux/nfs4.h>
#include <linux/nfs_fs.h>
+#include <linux/xattr.h>
+#include <linux/security.h>
#include "nfs4_fs.h"
#include "callback.h"
#include "delegation.h"
@@ -86,3 +88,105 @@ out:
dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res));
return res;
}
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+
+struct nfs_testfh_desc {
+ struct nfs_fh *fh;
+ unsigned long ino;
+};
+
+ static int
+nfs_testfh(struct inode *inode, void *opaque)
+{
+ struct nfs_testfh_desc *desc = (struct nfs_testfh_desc *)opaque;
+
+ if (inode->i_ino != desc->ino)
+ return (0);
+ if (nfs_compare_fh(NFS_FH(inode), desc->fh))
+ return (0);
+ if (is_bad_inode(inode) || NFS_STALE(inode))
+ return (0);
+ return (1);
+}
+
+/*
+ * Lookup an inode by filehandle, i_ino
+ */
+struct inode *nfs_client_inode(struct nfs_client *client, struct nfs_fh *fh, unsigned long ino)
+{
+ struct nfs_testfh_desc desc = {
+ .fh = fh,
+ .ino = ino
+ };
+ struct nfs_server *server;
+ struct super_block *sb;
+ struct inode *inode;
+
+ list_for_each_entry(server, &client->cl_superblocks, client_link) {
+ sb = nfs4_server_get_sb(server);
+ if (IS_ERR(sb))
+ continue;
+
+ inode = ilookup5_nowait(sb, ino, nfs_testfh, &desc);
+ if (inode != NULL)
+ return (inode);
+ }
+ return (NULL);
+}
+
+__be32 nfs4_callback_relabel(struct cb_relabelargs *args, void *dummy)
+{
+ struct nfs_client *clp;
+ struct inode *inode;
+ void *context;
+ const char *key;
+ int len;
+ __be32 res;
+
+ res = htonl(NFS4ERR_BADHANDLE);
+ clp = nfs_find_client(args->addr, 4);
+ if (clp == NULL) {
+ printk("%s() nfs_find_client() returned NULL\n", __func__);
+ goto out;
+ }
+
+ inode = nfs_client_inode(clp, &args->fh, args->ino);
+ if (inode == NULL) {
+ printk("%s() nfs_client_inode() returned NULL\n", __func__);
+ goto out_putclient;
+ }
+
+ key = security_inode_xattr_getname() + XATTR_SECURITY_PREFIX_LEN;
+
+ len = security_inode_getsecurity(inode, key, &context, true);
+ if (len < 0) {
+ /* XXX: really should return the error in 'len' */
+ goto out_iput;
+ }
+ if (len > NFS_MAXLABELLEN) {
+ security_release_secctx(context, len);
+ res = -EINVAL;
+ goto out_iput;
+ }
+ if (args->labellen != len ||
+ strncmp(args->label, context, args->labellen) != 0) {
+ (void)security_inode_setsecurity(inode, key,
+ args->label, args->labellen, 0);
+
+ printk("%s() ino %ld label %.*s -> %.*s\n", __func__,
+ inode->i_ino, len, (char *)context, args->labellen, args->label);
+ }
+
+ res = 0;
+
+out_iput:
+ iput(inode);
+out_putclient:
+ nfs_put_client(clp);
+out:
+ dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res));
+ return res;
+}
+
+#endif /* CONFIG_NFS_V4_SECURITY_LABEL */
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index 058ade7..ebf68a8 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -12,6 +12,7 @@
#include "nfs4_fs.h"
#include "callback.h"
+#define CB_OP_COMPOUND_MAXSZ (16)
#define CB_OP_TAGLEN_MAXSZ (512)
#define CB_OP_HDR_RES_MAXSZ (2 + CB_OP_TAGLEN_MAXSZ)
#define CB_OP_GETATTR_BITMAP_MAXSZ (4)
@@ -19,6 +20,7 @@
CB_OP_GETATTR_BITMAP_MAXSZ + \
2 + 2 + 3 + 3)
#define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
+#define CB_OP_RELABEL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
#define NFSDBG_FACILITY NFSDBG_CALLBACK
@@ -204,6 +206,30 @@ out:
return status;
}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+static __be32 decode_relabel_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_relabelargs *args)
+{
+ __be32 status;
+ __be32 *p;
+
+ p = read_buf(xdr, 8);
+ if (unlikely(p == NULL)) {
+ status = htonl(NFS4ERR_RESOURCE);
+ goto out;
+ }
+ p = xdr_decode_hyper(p, (__u64 *)&args->ino);
+
+ status = decode_fh(xdr, &args->fh);
+ if (unlikely(status != 0))
+ goto out;
+ args->addr = svc_addr_in(rqstp);
+ status = decode_string(xdr, &args->labellen, &args->label);
+out:
+ dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
+ return status;
+}
+#endif
+
static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
{
__be32 *p;
@@ -369,6 +395,7 @@ static __be32 process_op(struct svc_rqst *rqstp,
switch (op_nr) {
case OP_CB_GETATTR:
case OP_CB_RECALL:
+ case OP_CB_RELABEL:
op = &callback_ops[op_nr];
break;
default:
@@ -452,7 +479,14 @@ static struct callback_op callback_ops[] = {
.process_op = (callback_process_op_t)nfs4_callback_recall,
.decode_args = (callback_decode_arg_t)decode_recall_args,
.res_maxsize = CB_OP_RECALL_RES_MAXSZ,
+ },
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ [OP_CB_RELABEL] = {
+ .process_op = (callback_process_op_t)nfs4_callback_relabel,
+ .decode_args = (callback_decode_arg_t)decode_relabel_args,
+ .res_maxsize = CB_OP_RELABEL_RES_MAXSZ,
}
+#endif
};
/*
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index f3acf48..0e6d403 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -160,6 +160,7 @@ extern struct rpc_stat nfs_rpcstat;
extern int __init register_nfs_fs(void);
extern void __exit unregister_nfs_fs(void);
+extern struct super_block *nfs4_server_get_sb(struct nfs_server *);
/* namespace.c */
extern char *nfs_path(const char *base,
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 1df7137..6b3fcb9 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -17,6 +17,7 @@
#include <linux/nfs_page.h>
#include <linux/lockd/bind.h>
#include <linux/nfs_mount.h>
+#include <linux/fsnotify.h>
#include "iostat.h"
#include "internal.h"
@@ -134,8 +135,10 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
dprintk("NFS call setattr\n");
nfs_fattr_init(fattr);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
- if (status == 0)
+ if (status == 0) {
nfs_setattr_update_inode(inode, sattr);
+ fsnotify_change(dentry, sattr->ia_valid);
+ }
dprintk("NFS reply setattr: %d\n", status);
return status;
}
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 2d71e44..f8f3b78 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -49,6 +49,7 @@
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/xattr.h>
+#include <linux/fsnotify.h>
#include "nfs4_fs.h"
#include "delegation.h"
@@ -1711,8 +1712,10 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
state = ctx->state;
status = nfs4_do_setattr(inode, fattr, sattr, state);
- if (status == 0)
+ if (status == 0) {
nfs_setattr_update_inode(inode, sattr);
+ fsnotify_change(dentry, sattr->ia_valid);
+ }
if (ctx != NULL)
put_nfs_open_context(ctx);
put_rpccred(cred);
@@ -1966,8 +1969,10 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
nfs_fattr_alloc(&fattr);
#endif
status = nfs4_do_setattr(state->inode, &fattr, sattr, state);
- if (status == 0)
+ if (status == 0) {
nfs_setattr_update_inode(state->inode, sattr);
+ fsnotify_change(dentry, sattr->ia_valid);
+ }
nfs_post_op_update_inode(state->inode, &fattr);
nfs_fattr_fini(&fattr);
@@ -3061,8 +3066,10 @@ nfs4_set_security_label(struct dentry *dentry, const void *buf, size_t buflen)
state = ctx->state;
status = nfs4_do_set_security_label(inode, &sattr, &fattr, state);
- if (status == 0)
+ if (status == 0) {
nfs_setattr_update_inode(inode, &sattr);
+ fsnotify_change(dentry, sattr.ia_valid);
+ }
if (ctx != NULL)
put_nfs_open_context(ctx);
put_rpccred(cred);
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 76f9951..a558e5e 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -43,6 +43,7 @@
#include <linux/nfs_fs.h>
#include <linux/nfs_page.h>
#include <linux/lockd/bind.h>
+#include <linux/fsnotify.h>
#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_PROC
@@ -131,8 +132,10 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
dprintk("NFS call setattr\n");
nfs_fattr_init(fattr);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
- if (status == 0)
+ if (status == 0) {
nfs_setattr_update_inode(inode, sattr);
+ fsnotify_change(dentry, sattr->ia_valid);
+ }
dprintk("NFS reply setattr: %d\n", status);
return status;
}
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 012211f..5faa9ac 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1929,4 +1929,17 @@ error_splat_super:
return error;
}
+struct super_block *
+nfs4_server_get_sb(struct nfs_server *server)
+{
+ struct super_block *s;
+
+ list_for_each_entry(s, &nfs4_fs_type.fs_supers, s_instances) {
+ if (server == NFS_SB(s))
+ return (s);
+ /* XXX: refcount? */
+ }
+ return NULL;
+}
+
#endif /* CONFIG_NFS_V4 */
diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h
index 8603740..1b4a576 100644
--- a/include/linux/fcntl.h
+++ b/include/linux/fcntl.h
@@ -30,6 +30,7 @@
#define DN_DELETE 0x00000008 /* File removed */
#define DN_RENAME 0x00000010 /* File renamed */
#define DN_ATTRIB 0x00000020 /* File changed attibutes */
+#define DN_LABEL 0x00000040 /* File (re)labeled */
#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */
#define AT_FDCWD -100 /* Special value used to indicate
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index 2bd31fa..bfef9c2 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -231,6 +231,11 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
in_mask |= IN_ATTRIB;
dn_mask |= DN_ATTRIB;
}
+ if (ia_valid & ATTR_SECURITY_LABEL) {
+ in_mask |= IN_LABEL;
+ dn_mask |= DN_LABEL;
+ }
+
if (dn_mask)
dnotify_parent(dentry, dn_mask);
diff --git a/include/linux/inotify.h b/include/linux/inotify.h
index 742b917..10f3ace 100644
--- a/include/linux/inotify.h
+++ b/include/linux/inotify.h
@@ -36,6 +36,7 @@ struct inotify_event {
#define IN_DELETE 0x00000200 /* Subfile was deleted */
#define IN_DELETE_SELF 0x00000400 /* Self was deleted */
#define IN_MOVE_SELF 0x00000800 /* Self was moved */
+#define IN_LABEL 0x00001000 /* Self was (re)labeled */
/* the following are legal events. they are sent as needed to any watch */
#define IN_UNMOUNT 0x00002000 /* Backing fs was unmounted */
@@ -61,7 +62,7 @@ struct inotify_event {
#define IN_ALL_EVENTS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | \
IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | \
IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF | \
- IN_MOVE_SELF)
+ IN_MOVE_SELF | IN_LABEL)
#ifdef __KERNEL__
--
1.5.3.4
--
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 related [flat|nested] 21+ messages in thread* [PATCH 13/13] NFSD: Label change notification for NFSv4 Server
2007-11-16 20:03 [RFC Labeled NFS] Labeling support for NFSv4 David P. Quigley
` (11 preceding siblings ...)
2007-11-16 20:12 ` [PATCH 12/13] NFS: Label change notification for NFSv4 Clients David P. Quigley
@ 2007-11-16 20:13 ` David P. Quigley
2007-11-16 20:56 ` [RFC Labeled NFS] Labeling support for NFSv4 Peter Staubach
13 siblings, 0 replies; 21+ messages in thread
From: David P. Quigley @ 2007-11-16 20:13 UTC (permalink / raw)
To: labeled-nfs; +Cc: selinux
NFSv4 Provides methods for detecting changes in attributes and recalling
delegations when state has changed on the server. This has been extended to
include this functionality for label changes on the server. This patch provides
the server implementation for a new callback used to signal relabeling of
files.
Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
---
fs/nfsd/nfs4callback.c | 125 +++++++++++++++++++++++++++++++++++++++++++-
fs/nfsd/nfs4state.c | 95 ++++++++++++++++++++++++++++++++-
include/linux/nfsd/state.h | 17 ++++++
3 files changed, 233 insertions(+), 4 deletions(-)
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 9d536a8..6fe48b1 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -40,6 +40,8 @@
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/kthread.h>
+#include <linux/security.h>
+#include <linux/xattr.h>
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/clnt.h>
@@ -49,6 +51,7 @@
#include <linux/nfs4.h>
#define NFSDDBG_FACILITY NFSDDBG_PROC
+#define NFS_MAXLABELLEN 255
#define NFSPROC4_CB_NULL 0
#define NFSPROC4_CB_COMPOUND 1
@@ -61,10 +64,12 @@ static const struct rpc_call_ops nfs4_cb_null_ops;
enum {
NFSPROC4_CLNT_CB_NULL = 0,
NFSPROC4_CLNT_CB_RECALL,
+ NFSPROC4_CLNT_CB_RELABEL,
};
enum nfs_cb_opnum4 {
OP_CB_RECALL = 4,
+ OP_CB_RELABEL = 5,
};
#define NFS4_MAXTAGLEN 20
@@ -76,6 +81,8 @@ enum nfs_cb_opnum4 {
#define op_enc_sz 1
#define op_dec_sz 2
#define enc_nfs4_fh_sz (1 + (NFS4_FHSIZE >> 2))
+#define enc_nfs4_label_sz (1 + (NFS_MAXLABELLEN >> 2))
+#define enc_i_ino_sz 1
#define enc_stateid_sz (NFS4_STATEID_SIZE >> 2)
#define NFS4_enc_cb_recall_sz (cb_compound_enc_hdr_sz + \
1 + enc_stateid_sz + \
@@ -84,6 +91,13 @@ enum nfs_cb_opnum4 {
#define NFS4_dec_cb_recall_sz (cb_compound_dec_hdr_sz + \
op_dec_sz)
+#define NFS4_enc_cb_relabel_sz (cb_compound_enc_hdr_sz + \
+ op_enc_sz + \
+ enc_i_ino_sz + \
+ enc_nfs4_fh_sz + \
+ enc_nfs4_label_sz)
+#define NFS4_dec_cb_relabel_sz (cb_compound_dec_hdr_sz + \
+ op_dec_sz)
/*
* Generic encode routines from fs/nfs/nfs4xdr.c
*/
@@ -233,6 +247,24 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec)
}
static int
+encode_cb_relabel(struct xdr_stream *xdr, struct nfs4_cb_relabel *cbr)
+{
+ __be32 *p;
+
+ RESERVE_SPACE(12 + 8 + cbr->fhlen + cbr->label_len);
+ WRITE32(OP_CB_RELABEL);
+ /* ino_t */
+ p = xdr_encode_hyper(p, cbr->ino);
+ /* File handle */
+ WRITE32(cbr->fhlen);
+ WRITEMEM(cbr->fhval, cbr->fhlen);
+ /* Label */
+ WRITE32(cbr->label_len);
+ WRITEMEM(cbr->label, cbr->label_len);
+ return 0;
+}
+
+static int
nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p)
{
struct xdr_stream xdrs, *xdr = &xdrs;
@@ -256,6 +288,19 @@ nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_cb_recall *a
return (encode_cb_recall(&xdr, args));
}
+static int
+nfs4_xdr_enc_cb_relabel(struct rpc_rqst *req, __be32 *p, struct nfs4_cb_relabel *args)
+{
+ struct xdr_stream xdr;
+ struct nfs4_cb_compound_hdr hdr = {
+ .ident = args->ident,
+ .nops = 1,
+ };
+
+ xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+ encode_cb_compound_hdr(&xdr, &hdr);
+ return (encode_cb_relabel(&xdr, args));
+}
static int
decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){
@@ -314,6 +359,22 @@ out:
return status;
}
+static int
+nfs4_xdr_dec_cb_relabel(struct rpc_rqst *rqstp, __be32 *p)
+{
+ struct xdr_stream xdr;
+ struct nfs4_cb_compound_hdr hdr;
+ int status;
+
+ xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+ status = decode_cb_compound_hdr(&xdr, &hdr);
+ if (status)
+ goto out;
+ status = decode_cb_op_hdr(&xdr, OP_CB_RELABEL);
+out:
+ return status;
+}
+
/*
* RPC procedure tables
*/
@@ -329,8 +390,9 @@ out:
}
static struct rpc_procinfo nfs4_cb_procedures[] = {
- PROC(CB_NULL, NULL, enc_cb_null, dec_cb_null),
- PROC(CB_RECALL, COMPOUND, enc_cb_recall, dec_cb_recall),
+ PROC(CB_NULL, NULL, enc_cb_null, dec_cb_null),
+ PROC(CB_RECALL, COMPOUND, enc_cb_recall, dec_cb_recall),
+ PROC(CB_RELABEL, COMPOUND, enc_cb_relabel, dec_cb_relabel),
};
static struct rpc_version nfs_cb_version4 = {
@@ -490,3 +552,62 @@ out_put_cred:
nfs4_put_delegation(dp);
return;
}
+
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+void
+nfsd4_cb_relabel(struct nfs4_stateid *stp)
+{
+ struct nfs4_client *clp = stp->st_stateowner->so_client;
+ struct rpc_clnt *clnt = clp->cl_callback.cb_client;
+ struct nfs4_cb_relabel args;
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RELABEL],
+ .rpc_argp = &args,
+ };
+ void *context;
+ const char *key;
+ int len;
+ int retries = 1;
+ int status = 0;
+
+ key = security_inode_xattr_getname() + XATTR_SECURITY_PREFIX_LEN;
+ len = security_inode_getsecurity(stp->st_file->fi_inode, key, &context
+ , true);
+ if (len < 0) {
+ goto out;
+ }
+ if (len > NFS_MAXLABELLEN) {
+ security_release_secctx(context, len);
+ goto out;
+ }
+ args.ident = clp->cl_callback.cb_ident;
+ args.ino = stp->st_file->fi_inode->i_ino;
+ args.fhlen = stp->st_fh.fh_handle.fh_size;
+ memcpy(args.fhval, &stp->st_fh.fh_handle.fh_base, args.fhlen);
+ args.label = context;
+ args.label_len = len;
+
+ status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
+ while (retries--) {
+ switch (status) {
+ case -EIO:
+ /* Network partition? */
+ case -EBADHANDLE:
+ case -NFS4ERR_BAD_STATEID:
+ /* Race: client probably got cb_recall
+ * before open reply granting delegation */
+ break;
+ default:
+ goto out_put_cred;
+ }
+ ssleep(2);
+ status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
+ }
+
+out_put_cred:
+ security_release_secctx(context, len);
+out:
+ /* XXX: need to release references! */
+ return;
+}
+#endif
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 31673cd..dcd7f69 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -79,6 +79,17 @@ static void release_stateid_lockowners(struct nfs4_stateid *open_stp);
static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
static void nfs4_set_recdir(char *recdir);
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+static struct inotify_handle *nfsd_ih = NULL;
+static void nfsd_watch_event(struct inotify_watch *, u32, u32, u32,
+ const char *, struct inode *);
+static void nfsd_watch_destroy(struct inotify_watch *);
+static struct inotify_operations nfsd_state_event_handler = {
+ .handle_event = nfsd_watch_event,
+ .destroy_watch = nfsd_watch_destroy,
+};
+#endif
+
/* Locking:
*
* client_mutex:
@@ -135,7 +146,13 @@ free_nfs4_file(struct kref *kref)
struct nfs4_file *fp = container_of(kref, struct nfs4_file, fi_ref);
list_del(&fp->fi_hash);
iput(fp->fi_inode);
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ (void)inotify_rm_watch(nfsd_ih, &fp->fi_wdata);
+ put_inotify_watch(&fp->fi_wdata);
+ /* Defer free to nfsd_watch_destroy() */
+#else
kmem_cache_free(file_slab, fp);
+#endif
}
static inline void
@@ -988,6 +1005,11 @@ alloc_init_file(struct inode *ino)
fp->fi_inode = igrab(ino);
fp->fi_id = current_fileid++;
fp->fi_had_conflict = false;
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ inotify_init_watch(&fp->fi_wdata);
+ get_inotify_watch(&fp->fi_wdata);
+ (void)inotify_add_watch(nfsd_ih, &fp->fi_wdata, ino, IN_LABEL);
+#endif
return fp;
}
return NULL;
@@ -1137,7 +1159,9 @@ release_stateowner(struct nfs4_stateowner *sop)
}
static inline void
-init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
+init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct svc_fh *fh,
+ struct nfsd4_open *open)
+{
struct nfs4_stateowner *sop = open->op_stateowner;
unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id);
@@ -1160,6 +1184,9 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *
__set_bit(open->op_share_access, &stp->st_access_bmap);
__set_bit(open->op_share_deny, &stp->st_deny_bmap);
stp->st_openstp = NULL;
+
+ fh_init(&stp->st_fh, NFS4_FHSIZE);
+ (void)fh_compose(&stp->st_fh, fh->fh_export, fh->fh_dentry, fh);
}
static void
@@ -1177,6 +1204,7 @@ release_stateid(struct nfs4_stateid *stp, int flags)
} else if (flags & LOCK_STATE)
locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner);
put_nfs4_file(stp->st_file);
+ fh_put(&stp->st_fh);
kmem_cache_free(stateid_slab, stp);
}
@@ -1791,7 +1819,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags);
if (status)
goto out;
- init_stateid(stp, fp, open);
+ init_stateid(stp, fp, current_fh, open);
status = nfsd4_truncate(rqstp, current_fh, open);
if (status) {
release_stateid(stp, OPEN_STATE);
@@ -3241,6 +3269,9 @@ nfs4_state_start(void)
{
if (nfs4_init)
return;
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ nfsd_ih = inotify_init(&nfsd_state_event_handler);
+#endif
nfsd4_load_reboot_recovery_data();
__nfs4_state_start();
nfs4_init = 1;
@@ -3350,3 +3381,63 @@ nfs4_reset_lease(time_t leasetime)
user_lease_time = leasetime;
unlock_kernel();
}
+
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+
+ static int
+do_relabel(void *__stp)
+{
+ struct nfs4_stateid *stp = __stp;
+
+ daemonize("nfsv4-relabel");
+
+ nfsd4_cb_relabel(stp);
+ return (0);
+}
+
+ static void
+nfsd_watch_event(struct inotify_watch *watch, u32 wd, u32 mask, u32 cookie,
+ const char *name, struct inode *inode)
+{
+ struct nfs4_file *fp;
+ struct nfs4_stateid *stp;
+ struct task_struct *t;
+
+ fp = container_of(watch, struct nfs4_file, fi_wdata);
+
+ if (mask & IN_IGNORED) {
+ put_inotify_watch(&fp->fi_wdata);
+ return;
+ }
+
+ if ((mask & IN_LABEL) == 0)
+ return;
+
+ list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
+ struct nfs4_client *clp = stp->st_stateowner->so_client;
+
+ /* XXX: need to refcount something! */
+
+ printk("%s() STP client \"%.*s\" fh \"%s\"\n", __func__,
+ clp->cl_name.len, clp->cl_name.data,
+ SVCFH_fmt(&stp->st_fh));
+
+ t = kthread_run(do_relabel, stp, "%s", "nfs4_cb_relabel");
+ if (IS_ERR(t)) {
+ printk(KERN_INFO "NFSD: Callback thread failed for "
+ "for client (clientid %08x/%08x)\n",
+ clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
+ }
+
+ }
+}
+
+ static void
+nfsd_watch_destroy(struct inotify_watch *watch)
+{
+ struct nfs4_file *fp;
+
+ fp = container_of(watch, struct nfs4_file, fi_wdata);
+ kmem_cache_free(file_slab, fp);
+}
+#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index db348f7..043f800 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -40,6 +40,7 @@
#include <linux/list.h>
#include <linux/kref.h>
#include <linux/sunrpc/clnt.h>
+#include <linux/inotify.h>
#define NFS4_OPAQUE_LIMIT 1024
typedef struct {
@@ -71,6 +72,15 @@ struct nfs4_cb_recall {
struct nfs4_delegation *cbr_dp;
};
+struct nfs4_cb_relabel {
+ u32 ident;
+ unsigned long ino;
+ u32 fhlen;
+ u32 fhval[NFS4_FHSIZE];
+ char * label;
+ int label_len;
+};
+
struct nfs4_delegation {
struct list_head dl_perfile;
struct list_head dl_perclnt;
@@ -85,6 +95,7 @@ struct nfs4_delegation {
struct nfs4_cb_recall dl_recall;
};
+#define dl_ident dl_recall.cbr_ident
#define dl_stateid dl_recall.cbr_stateid
#define dl_fhlen dl_recall.cbr_fhlen
#define dl_fhval dl_recall.cbr_fhval
@@ -225,6 +236,10 @@ struct nfs4_file {
u32 fi_id; /* used with stateowner->so_id
* for stateid_hashtbl hash */
bool fi_had_conflict;
+
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ struct inotify_watch fi_wdata;
+#endif
};
/*
@@ -251,6 +266,7 @@ struct nfs4_stateid {
struct list_head st_lockowners;
struct nfs4_stateowner * st_stateowner;
struct nfs4_file * st_file;
+ struct svc_fh st_fh;
stateid_t st_stateid;
struct file * st_vfs_file;
unsigned long st_access_bmap;
@@ -284,6 +300,7 @@ extern void put_nfs4_client(struct nfs4_client *clp);
extern void nfs4_free_stateowner(struct kref *kref);
extern void nfsd4_probe_callback(struct nfs4_client *clp);
extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
+extern void nfsd4_cb_relabel(struct nfs4_stateid *stp);
extern void nfs4_put_delegation(struct nfs4_delegation *dp);
extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
extern void nfsd4_init_recdir(char *recdir_name);
--
1.5.3.4
--
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 related [flat|nested] 21+ messages in thread* Re: [RFC Labeled NFS] Labeling support for NFSv4
2007-11-16 20:03 [RFC Labeled NFS] Labeling support for NFSv4 David P. Quigley
` (12 preceding siblings ...)
2007-11-16 20:13 ` [PATCH 13/13] NFSD: Label change notification for NFSv4 Server David P. Quigley
@ 2007-11-16 20:56 ` Peter Staubach
13 siblings, 0 replies; 21+ messages in thread
From: Peter Staubach @ 2007-11-16 20:56 UTC (permalink / raw)
To: David P. Quigley; +Cc: labeled-nfs, selinux
David P. Quigley wrote:
> This is the first set of patches for the labeled-nfs work since early August.
> Much has changed since then and we have a reasonably functional prototype of
> the dumb server implementation. This patch series provides the ability to
> retrieve and set labels on the server, provides callback notification for label
> changes on the server, and life-cycle management for the fattr structure which
> is used to transport the labels.
>
> The patch series should apply on top of any 2.6.24-rc2 kernel and I know for a
> fact that it will apply on top of commit
> 9418d5dc9ba40b88737580457bf3b7c63c60ec43 in Linus's git tree. To get the tree
> up and running for testing just apply the patch and have fun.
How is the work going on with the NFSv4 IETF WG?
Thanx...
ps
--
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] 21+ messages in thread