* [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information.
[not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
@ 2008-09-29 17:06 ` David P. Quigley
2008-09-30 20:01 ` Serge E. Hallyn
2008-09-30 20:22 ` Serge E. Hallyn
2008-09-29 17:06 ` [PATCH 03/14] Security: Add hook to calculate context based on a negative dentry David P. Quigley
` (7 subsequent siblings)
8 siblings, 2 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
trond.myklebust-41N18TsMXrtuMpJDpNschA,
bfields-uC3wQj2KruNg9hUCZPvPmw
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
selinux-+05T5uksL2qpZYMLLGbcSA,
labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
Matthew N. Dodd
This patch introduces three new hooks. The inode_getsecctx hook is used to get
all relevant information from an LSM about an inode. The inode_setsecctx is
used to set both the in-core and on-disk state for the inode based on a context
derived from inode_getsecctx.The final hook inode_notifysecctx will notify the
LSM of a change for the in-core state of the inode in question. These hooks are
for use in the labeled NFS code and addresses concerns of how to set security
on an inode in a multi-xattr LSM. For historical reasons Stephen Smalley's
explanation of the reason for these hooks is pasted below.
Quote Stephen Smalley
inode_setsecctx: Change the security context of an inode. Updates the
in core security context managed by the security module and invokes the
fs code as needed (via __vfs_setxattr_noperm) to update any backing
xattrs that represent the context. Example usage: NFS server invokes
this hook to change the security context in its incore inode and on the
backing file system to a value provided by the client on a SETATTR
operation.
inode_notifysecctx: Notify the security module of what the security
context of an inode should be. Initializes the incore security context
managed by the security module for this inode. Example usage: NFS
client invokes this hook to initialize the security context in its
incore inode to the value provided by the server for the file when the
server returned the file's attributes to the client.
Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
include/linux/security.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++
security/security.c | 18 ++++++++++++++++
security/selinux/hooks.c | 25 +++++++++++++++++++++++
3 files changed, 93 insertions(+), 0 deletions(-)
diff --git a/include/linux/security.h b/include/linux/security.h
index 80c4d00..8b5b041 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1289,6 +1289,36 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* audit_rule_init.
* @rule contains the allocated rule
*
+ * @inode_notifysecctx:
+ * Notify the security module of what the security context of an inode
+ * should be. Initializes the incore security context managed by the
+ * security module for this inode. Example usage: NFS client invokes
+ * this hook to initialize the security context in its incore inode to the
+ * value provided by the server for the file when the server returned the
+ * file's attributes to the client.
+ *
+ * @inode we wish to set the security context of.
+ * @ctx contains the string which we wish to set in the inode.
+ * @ctxlen contains the length of @ctx.
+ *
+ * @inode_setsecctx:
+ * Change the security context of an inode. Updates the
+ * incore security context managed by the security module and invokes the
+ * fs code as needed (via __vfs_setxattr_noperm) to update any backing
+ * xattrs that represent the context. Example usage: NFS server invokes
+ * this hook to change the security context in its incore inode and on the
+ * backing filesystem to a value provided by the client on a SETATTR
+ * operation.
+ *
+ * @dentry contains the inode we wish to set the security context of.
+ * @ctx contains the string which we wish to set in the inode.
+ * @ctxlen contains the length of @ctx.
+ *
+ * @inode_getsecctx:
+ * Returns a string containing all relavent security context information
+ * @inode we wish to set the security context of.
+ * @ctx is a pointer to place the allocated security context should be placed.
+ * @ctxlen points to the place to put the length of @ctx.
* This is the main security structure.
*/
struct security_operations {
@@ -1479,6 +1509,10 @@ struct security_operations {
int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
void (*release_secctx) (char *secdata, u32 seclen);
+ int (*inode_notifysecctx)(struct inode *inode, void *ctx, u32 ctxlen);
+ int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen);
+ int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen);
+
#ifdef CONFIG_SECURITY_NETWORK
int (*unix_stream_connect) (struct socket *sock,
struct socket *other, struct sock *newsk);
@@ -1727,6 +1761,9 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void security_release_secctx(char *secdata, u32 seclen);
+int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
+int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
+int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
#else /* CONFIG_SECURITY */
struct security_mnt_opts {
};
@@ -2458,6 +2495,19 @@ static inline int security_secctx_to_secid(const char *secdata,
static inline void security_release_secctx(char *secdata, u32 seclen)
{
}
+
+static inline int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
+{
+ return -EOPNOTSUPP;
+}
+static inline int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
+{
+ return -EOPNOTSUPP;
+}
+static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+{
+ return -EOPNOTSUPP;
+}
#endif /* CONFIG_SECURITY */
#ifdef CONFIG_SECURITY_NETWORK
diff --git a/security/security.c b/security/security.c
index 3a4b4f5..d0fd42a 100644
--- a/security/security.c
+++ b/security/security.c
@@ -869,6 +869,24 @@ void security_release_secctx(char *secdata, u32 seclen)
}
EXPORT_SYMBOL(security_release_secctx);
+int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
+{
+ return security_ops->inode_notifysecctx(inode, ctx, ctxlen);
+}
+EXPORT_SYMBOL(security_inode_notifysecctx);
+
+int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
+{
+ return security_ops->inode_setsecctx(dentry, ctx, ctxlen);
+}
+EXPORT_SYMBOL(security_inode_setsecctx);
+
+int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+{
+ return security_ops->inode_getsecctx(inode, ctx, ctxlen);
+}
+EXPORT_SYMBOL(security_inode_getsecctx);
+
#ifdef CONFIG_SECURITY_NETWORK
int security_unix_stream_connect(struct socket *sock, struct socket *other,
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 03fc6a8..b07871b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5285,6 +5285,28 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
kfree(secdata);
}
+/*
+ * This hook requires that the inode i_mutex be locked
+ */
+static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
+{
+ return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
+}
+
+/*
+ * This hook requires that the inode i_mutex be locked
+ */
+static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
+{
+ return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
+}
+
+static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+{
+ *ctxlen = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
+ ctx, true);
+ return *ctxlen;
+}
#ifdef CONFIG_KEYS
static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
@@ -5491,6 +5513,9 @@ static struct security_operations selinux_ops = {
.secid_to_secctx = selinux_secid_to_secctx,
.secctx_to_secid = selinux_secctx_to_secid,
.release_secctx = selinux_release_secctx,
+ .inode_notifysecctx = selinux_inode_notifysecctx,
+ .inode_setsecctx = selinux_inode_setsecctx,
+ .inode_getsecctx = selinux_inode_getsecctx,
.unix_stream_connect = selinux_socket_unix_stream_connect,
.unix_may_send = selinux_socket_unix_may_send,
--
1.5.5.1
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information.
2008-09-29 17:06 ` [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information David P. Quigley
@ 2008-09-30 20:01 ` Serge E. Hallyn
2008-10-06 20:52 ` David P. Quigley
2008-09-30 20:22 ` Serge E. Hallyn
1 sibling, 1 reply; 33+ messages in thread
From: Serge E. Hallyn @ 2008-09-30 20:01 UTC (permalink / raw)
To: David P. Quigley
Cc: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields,
linux-kernel, linux-fsdevel, linux-security-module, selinux,
labeled-nfs
Quoting David P. Quigley (dpquigl@tycho.nsa.gov):
> This patch introduces three new hooks. The inode_getsecctx hook is used to get
> all relevant information from an LSM about an inode. The inode_setsecctx is
> used to set both the in-core and on-disk state for the inode based on a context
> derived from inode_getsecctx.The final hook inode_notifysecctx will notify the
> LSM of a change for the in-core state of the inode in question. These hooks are
> for use in the labeled NFS code and addresses concerns of how to set security
> on an inode in a multi-xattr LSM. For historical reasons Stephen Smalley's
> explanation of the reason for these hooks is pasted below.
>
> Quote Stephen Smalley
>
> inode_setsecctx: Change the security context of an inode. Updates the
> in core security context managed by the security module and invokes the
> fs code as needed (via __vfs_setxattr_noperm) to update any backing
> xattrs that represent the context. Example usage: NFS server invokes
> this hook to change the security context in its incore inode and on the
> backing file system to a value provided by the client on a SETATTR
> operation.
>
> inode_notifysecctx: Notify the security module of what the security
> context of an inode should be. Initializes the incore security context
> managed by the security module for this inode. Example usage: NFS
> client invokes this hook to initialize the security context in its
> incore inode to the value provided by the server for the file when the
> server returned the file's attributes to the client.
>
> Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
> ---
> include/linux/security.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++
> security/security.c | 18 ++++++++++++++++
> security/selinux/hooks.c | 25 +++++++++++++++++++++++
> 3 files changed, 93 insertions(+), 0 deletions(-)
>
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 80c4d00..8b5b041 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -1289,6 +1289,36 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
> * audit_rule_init.
> * @rule contains the allocated rule
> *
> + * @inode_notifysecctx:
> + * Notify the security module of what the security context of an inode
> + * should be. Initializes the incore security context managed by the
> + * security module for this inode. Example usage: NFS client invokes
> + * this hook to initialize the security context in its incore inode to the
> + * value provided by the server for the file when the server returned the
> + * file's attributes to the client.
> + *
> + * @inode we wish to set the security context of.
> + * @ctx contains the string which we wish to set in the inode.
> + * @ctxlen contains the length of @ctx.
> + *
> + * @inode_setsecctx:
> + * Change the security context of an inode. Updates the
> + * incore security context managed by the security module and invokes the
> + * fs code as needed (via __vfs_setxattr_noperm) to update any backing
> + * xattrs that represent the context. Example usage: NFS server invokes
> + * this hook to change the security context in its incore inode and on the
> + * backing filesystem to a value provided by the client on a SETATTR
> + * operation.
> + *
> + * @dentry contains the inode we wish to set the security context of.
> + * @ctx contains the string which we wish to set in the inode.
> + * @ctxlen contains the length of @ctx.
> + *
> + * @inode_getsecctx:
> + * Returns a string containing all relavent security context information
> + * @inode we wish to set the security context of.
> + * @ctx is a pointer to place the allocated security context should be placed.
sentence above is odd. How about
@ctx is a pointer in which to place the allocated security context
> + * @ctxlen points to the place to put the length of @ctx.
> * This is the main security structure.
> */
> struct security_operations {
> @@ -1479,6 +1509,10 @@ struct security_operations {
> int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
> void (*release_secctx) (char *secdata, u32 seclen);
>
> + int (*inode_notifysecctx)(struct inode *inode, void *ctx, u32 ctxlen);
> + int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen);
> + int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen);
> +
> #ifdef CONFIG_SECURITY_NETWORK
> int (*unix_stream_connect) (struct socket *sock,
> struct socket *other, struct sock *newsk);
> @@ -1727,6 +1761,9 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
> int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
> void security_release_secctx(char *secdata, u32 seclen);
>
> +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
> +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
> +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
> #else /* CONFIG_SECURITY */
> struct security_mnt_opts {
> };
> @@ -2458,6 +2495,19 @@ static inline int security_secctx_to_secid(const char *secdata,
> static inline void security_release_secctx(char *secdata, u32 seclen)
> {
> }
> +
> +static inline int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> +{
> + return -EOPNOTSUPP;
> +}
> +static inline int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> +{
> + return -EOPNOTSUPP;
> +}
> +static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> +{
> + return -EOPNOTSUPP;
> +}
> #endif /* CONFIG_SECURITY */
>
> #ifdef CONFIG_SECURITY_NETWORK
> diff --git a/security/security.c b/security/security.c
> index 3a4b4f5..d0fd42a 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -869,6 +869,24 @@ void security_release_secctx(char *secdata, u32 seclen)
> }
> EXPORT_SYMBOL(security_release_secctx);
>
> +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> +{
> + return security_ops->inode_notifysecctx(inode, ctx, ctxlen);
> +}
> +EXPORT_SYMBOL(security_inode_notifysecctx);
> +
> +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> +{
> + return security_ops->inode_setsecctx(dentry, ctx, ctxlen);
> +}
> +EXPORT_SYMBOL(security_inode_setsecctx);
> +
> +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> +{
> + return security_ops->inode_getsecctx(inode, ctx, ctxlen);
> +}
> +EXPORT_SYMBOL(security_inode_getsecctx);
> +
> #ifdef CONFIG_SECURITY_NETWORK
>
> int security_unix_stream_connect(struct socket *sock, struct socket *other,
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 03fc6a8..b07871b 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -5285,6 +5285,28 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
> kfree(secdata);
> }
>
> +/*
> + * This hook requires that the inode i_mutex be locked
'called with inode->i_mutex locked' would make more sense here.
Requirements on the callers would make more sense in the comments
in include/linux/security.h, right?
No code objections, though.
Acked-by: Serge Hallyn <serue@us.ibm.com>
> + */
> +static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> +{
> + return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
> +}
> +
> +/*
> + * This hook requires that the inode i_mutex be locked
> + */
> +static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> +{
> + return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
> +}
> +
> +static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> +{
> + *ctxlen = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
> + ctx, true);
> + return *ctxlen;
> +}
> #ifdef CONFIG_KEYS
>
> static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
> @@ -5491,6 +5513,9 @@ static struct security_operations selinux_ops = {
> .secid_to_secctx = selinux_secid_to_secctx,
> .secctx_to_secid = selinux_secctx_to_secid,
> .release_secctx = selinux_release_secctx,
> + .inode_notifysecctx = selinux_inode_notifysecctx,
> + .inode_setsecctx = selinux_inode_setsecctx,
> + .inode_getsecctx = selinux_inode_getsecctx,
>
> .unix_stream_connect = selinux_socket_unix_stream_connect,
> .unix_may_send = selinux_socket_unix_may_send,
> --
> 1.5.5.1
>
>
> --
> This message was distributed to subscribers of the selinux mailing list.
> If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
> the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information.
2008-09-30 20:01 ` Serge E. Hallyn
@ 2008-10-06 20:52 ` David P. Quigley
0 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-10-06 20:52 UTC (permalink / raw)
To: Serge E. Hallyn
Cc: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields,
linux-kernel, linux-fsdevel, linux-security-module, selinux,
labeled-nfs
Fixed.
On Tue, 2008-09-30 at 15:01 -0500, Serge E. Hallyn wrote:
> Quoting David P. Quigley (dpquigl@tycho.nsa.gov):
> > This patch introduces three new hooks. The inode_getsecctx hook is used to get
> > all relevant information from an LSM about an inode. The inode_setsecctx is
> > used to set both the in-core and on-disk state for the inode based on a context
> > derived from inode_getsecctx.The final hook inode_notifysecctx will notify the
> > LSM of a change for the in-core state of the inode in question. These hooks are
> > for use in the labeled NFS code and addresses concerns of how to set security
> > on an inode in a multi-xattr LSM. For historical reasons Stephen Smalley's
> > explanation of the reason for these hooks is pasted below.
> >
> > Quote Stephen Smalley
> >
> > inode_setsecctx: Change the security context of an inode. Updates the
> > in core security context managed by the security module and invokes the
> > fs code as needed (via __vfs_setxattr_noperm) to update any backing
> > xattrs that represent the context. Example usage: NFS server invokes
> > this hook to change the security context in its incore inode and on the
> > backing file system to a value provided by the client on a SETATTR
> > operation.
> >
> > inode_notifysecctx: Notify the security module of what the security
> > context of an inode should be. Initializes the incore security context
> > managed by the security module for this inode. Example usage: NFS
> > client invokes this hook to initialize the security context in its
> > incore inode to the value provided by the server for the file when the
> > server returned the file's attributes to the client.
> >
> > Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> > Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
> > ---
> > include/linux/security.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++
> > security/security.c | 18 ++++++++++++++++
> > security/selinux/hooks.c | 25 +++++++++++++++++++++++
> > 3 files changed, 93 insertions(+), 0 deletions(-)
> >
> > diff --git a/include/linux/security.h b/include/linux/security.h
> > index 80c4d00..8b5b041 100644
> > --- a/include/linux/security.h
> > +++ b/include/linux/security.h
> > @@ -1289,6 +1289,36 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
> > * audit_rule_init.
> > * @rule contains the allocated rule
> > *
> > + * @inode_notifysecctx:
> > + * Notify the security module of what the security context of an inode
> > + * should be. Initializes the incore security context managed by the
> > + * security module for this inode. Example usage: NFS client invokes
> > + * this hook to initialize the security context in its incore inode to the
> > + * value provided by the server for the file when the server returned the
> > + * file's attributes to the client.
> > + *
> > + * @inode we wish to set the security context of.
> > + * @ctx contains the string which we wish to set in the inode.
> > + * @ctxlen contains the length of @ctx.
> > + *
> > + * @inode_setsecctx:
> > + * Change the security context of an inode. Updates the
> > + * incore security context managed by the security module and invokes the
> > + * fs code as needed (via __vfs_setxattr_noperm) to update any backing
> > + * xattrs that represent the context. Example usage: NFS server invokes
> > + * this hook to change the security context in its incore inode and on the
> > + * backing filesystem to a value provided by the client on a SETATTR
> > + * operation.
> > + *
> > + * @dentry contains the inode we wish to set the security context of.
> > + * @ctx contains the string which we wish to set in the inode.
> > + * @ctxlen contains the length of @ctx.
> > + *
> > + * @inode_getsecctx:
> > + * Returns a string containing all relavent security context information
> > + * @inode we wish to set the security context of.
> > + * @ctx is a pointer to place the allocated security context should be placed.
>
> sentence above is odd. How about
>
> @ctx is a pointer in which to place the allocated security context
>
> > + * @ctxlen points to the place to put the length of @ctx.
> > * This is the main security structure.
> > */
> > struct security_operations {
> > @@ -1479,6 +1509,10 @@ struct security_operations {
> > int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
> > void (*release_secctx) (char *secdata, u32 seclen);
> >
> > + int (*inode_notifysecctx)(struct inode *inode, void *ctx, u32 ctxlen);
> > + int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen);
> > + int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen);
> > +
> > #ifdef CONFIG_SECURITY_NETWORK
> > int (*unix_stream_connect) (struct socket *sock,
> > struct socket *other, struct sock *newsk);
> > @@ -1727,6 +1761,9 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
> > int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
> > void security_release_secctx(char *secdata, u32 seclen);
> >
> > +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
> > +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
> > +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
> > #else /* CONFIG_SECURITY */
> > struct security_mnt_opts {
> > };
> > @@ -2458,6 +2495,19 @@ static inline int security_secctx_to_secid(const char *secdata,
> > static inline void security_release_secctx(char *secdata, u32 seclen)
> > {
> > }
> > +
> > +static inline int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> > +{
> > + return -EOPNOTSUPP;
> > +}
> > +static inline int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> > +{
> > + return -EOPNOTSUPP;
> > +}
> > +static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> > +{
> > + return -EOPNOTSUPP;
> > +}
> > #endif /* CONFIG_SECURITY */
> >
> > #ifdef CONFIG_SECURITY_NETWORK
> > diff --git a/security/security.c b/security/security.c
> > index 3a4b4f5..d0fd42a 100644
> > --- a/security/security.c
> > +++ b/security/security.c
> > @@ -869,6 +869,24 @@ void security_release_secctx(char *secdata, u32 seclen)
> > }
> > EXPORT_SYMBOL(security_release_secctx);
> >
> > +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> > +{
> > + return security_ops->inode_notifysecctx(inode, ctx, ctxlen);
> > +}
> > +EXPORT_SYMBOL(security_inode_notifysecctx);
> > +
> > +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> > +{
> > + return security_ops->inode_setsecctx(dentry, ctx, ctxlen);
> > +}
> > +EXPORT_SYMBOL(security_inode_setsecctx);
> > +
> > +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> > +{
> > + return security_ops->inode_getsecctx(inode, ctx, ctxlen);
> > +}
> > +EXPORT_SYMBOL(security_inode_getsecctx);
> > +
> > #ifdef CONFIG_SECURITY_NETWORK
> >
> > int security_unix_stream_connect(struct socket *sock, struct socket *other,
> > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > index 03fc6a8..b07871b 100644
> > --- a/security/selinux/hooks.c
> > +++ b/security/selinux/hooks.c
> > @@ -5285,6 +5285,28 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
> > kfree(secdata);
> > }
> >
> > +/*
> > + * This hook requires that the inode i_mutex be locked
>
> 'called with inode->i_mutex locked' would make more sense here.
> Requirements on the callers would make more sense in the comments
> in include/linux/security.h, right?
>
> No code objections, though.
>
> Acked-by: Serge Hallyn <serue@us.ibm.com>
>
> > + */
> > +static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> > +{
> > + return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
> > +}
> > +
> > +/*
> > + * This hook requires that the inode i_mutex be locked
> > + */
> > +static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> > +{
> > + return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
> > +}
> > +
> > +static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> > +{
> > + *ctxlen = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
> > + ctx, true);
> > + return *ctxlen;
> > +}
> > #ifdef CONFIG_KEYS
> >
> > static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
> > @@ -5491,6 +5513,9 @@ static struct security_operations selinux_ops = {
> > .secid_to_secctx = selinux_secid_to_secctx,
> > .secctx_to_secid = selinux_secctx_to_secid,
> > .release_secctx = selinux_release_secctx,
> > + .inode_notifysecctx = selinux_inode_notifysecctx,
> > + .inode_setsecctx = selinux_inode_setsecctx,
> > + .inode_getsecctx = selinux_inode_getsecctx,
> >
> > .unix_stream_connect = selinux_socket_unix_stream_connect,
> > .unix_may_send = selinux_socket_unix_may_send,
> > --
> > 1.5.5.1
> >
> >
> > --
> > This message was distributed to subscribers of the selinux mailing list.
> > If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
> > the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information.
2008-09-29 17:06 ` [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information David P. Quigley
2008-09-30 20:01 ` Serge E. Hallyn
@ 2008-09-30 20:22 ` Serge E. Hallyn
2008-10-06 20:52 ` David P. Quigley
1 sibling, 1 reply; 33+ messages in thread
From: Serge E. Hallyn @ 2008-09-30 20:22 UTC (permalink / raw)
To: David P. Quigley
Cc: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields,
linux-kernel, linux-fsdevel, linux-security-module, selinux,
labeled-nfs
Quoting David P. Quigley (dpquigl@tycho.nsa.gov):
> This patch introduces three new hooks. The inode_getsecctx hook is used to get
> all relevant information from an LSM about an inode. The inode_setsecctx is
> used to set both the in-core and on-disk state for the inode based on a context
> derived from inode_getsecctx.The final hook inode_notifysecctx will notify the
> LSM of a change for the in-core state of the inode in question. These hooks are
> for use in the labeled NFS code and addresses concerns of how to set security
> on an inode in a multi-xattr LSM. For historical reasons Stephen Smalley's
> explanation of the reason for these hooks is pasted below.
>
> Quote Stephen Smalley
>
> inode_setsecctx: Change the security context of an inode. Updates the
> in core security context managed by the security module and invokes the
> fs code as needed (via __vfs_setxattr_noperm) to update any backing
> xattrs that represent the context. Example usage: NFS server invokes
> this hook to change the security context in its incore inode and on the
> backing file system to a value provided by the client on a SETATTR
> operation.
>
> inode_notifysecctx: Notify the security module of what the security
> context of an inode should be. Initializes the incore security context
> managed by the security module for this inode. Example usage: NFS
> client invokes this hook to initialize the security context in its
> incore inode to the value provided by the server for the file when the
> server returned the file's attributes to the client.
>
> Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
Hmm, sorry, for all of these new hooks which you introduce, you do not
define empty cap_* versions and assign them when need in
security_fixup_ops(). But you unconditionally call them if
CONFIG_SECURITY=y. So if you compile a kernel with CONFIG_SECURITY=y
but CONFIG_SECURITY_SELINUX=n, don't you hose your box?
> ---
> include/linux/security.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++
> security/security.c | 18 ++++++++++++++++
> security/selinux/hooks.c | 25 +++++++++++++++++++++++
> 3 files changed, 93 insertions(+), 0 deletions(-)
>
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 80c4d00..8b5b041 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -1289,6 +1289,36 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
> * audit_rule_init.
> * @rule contains the allocated rule
> *
> + * @inode_notifysecctx:
> + * Notify the security module of what the security context of an inode
> + * should be. Initializes the incore security context managed by the
> + * security module for this inode. Example usage: NFS client invokes
> + * this hook to initialize the security context in its incore inode to the
> + * value provided by the server for the file when the server returned the
> + * file's attributes to the client.
> + *
> + * @inode we wish to set the security context of.
> + * @ctx contains the string which we wish to set in the inode.
> + * @ctxlen contains the length of @ctx.
> + *
> + * @inode_setsecctx:
> + * Change the security context of an inode. Updates the
> + * incore security context managed by the security module and invokes the
> + * fs code as needed (via __vfs_setxattr_noperm) to update any backing
> + * xattrs that represent the context. Example usage: NFS server invokes
> + * this hook to change the security context in its incore inode and on the
> + * backing filesystem to a value provided by the client on a SETATTR
> + * operation.
> + *
> + * @dentry contains the inode we wish to set the security context of.
> + * @ctx contains the string which we wish to set in the inode.
> + * @ctxlen contains the length of @ctx.
> + *
> + * @inode_getsecctx:
> + * Returns a string containing all relavent security context information
> + * @inode we wish to set the security context of.
> + * @ctx is a pointer to place the allocated security context should be placed.
> + * @ctxlen points to the place to put the length of @ctx.
> * This is the main security structure.
> */
> struct security_operations {
> @@ -1479,6 +1509,10 @@ struct security_operations {
> int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
> void (*release_secctx) (char *secdata, u32 seclen);
>
> + int (*inode_notifysecctx)(struct inode *inode, void *ctx, u32 ctxlen);
> + int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen);
> + int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen);
> +
> #ifdef CONFIG_SECURITY_NETWORK
> int (*unix_stream_connect) (struct socket *sock,
> struct socket *other, struct sock *newsk);
> @@ -1727,6 +1761,9 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
> int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
> void security_release_secctx(char *secdata, u32 seclen);
>
> +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
> +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
> +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
> #else /* CONFIG_SECURITY */
> struct security_mnt_opts {
> };
> @@ -2458,6 +2495,19 @@ static inline int security_secctx_to_secid(const char *secdata,
> static inline void security_release_secctx(char *secdata, u32 seclen)
> {
> }
> +
> +static inline int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> +{
> + return -EOPNOTSUPP;
> +}
> +static inline int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> +{
> + return -EOPNOTSUPP;
> +}
> +static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> +{
> + return -EOPNOTSUPP;
> +}
> #endif /* CONFIG_SECURITY */
>
> #ifdef CONFIG_SECURITY_NETWORK
> diff --git a/security/security.c b/security/security.c
> index 3a4b4f5..d0fd42a 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -869,6 +869,24 @@ void security_release_secctx(char *secdata, u32 seclen)
> }
> EXPORT_SYMBOL(security_release_secctx);
>
> +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> +{
> + return security_ops->inode_notifysecctx(inode, ctx, ctxlen);
> +}
> +EXPORT_SYMBOL(security_inode_notifysecctx);
> +
> +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> +{
> + return security_ops->inode_setsecctx(dentry, ctx, ctxlen);
> +}
> +EXPORT_SYMBOL(security_inode_setsecctx);
> +
> +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> +{
> + return security_ops->inode_getsecctx(inode, ctx, ctxlen);
> +}
> +EXPORT_SYMBOL(security_inode_getsecctx);
> +
> #ifdef CONFIG_SECURITY_NETWORK
>
> int security_unix_stream_connect(struct socket *sock, struct socket *other,
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 03fc6a8..b07871b 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -5285,6 +5285,28 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
> kfree(secdata);
> }
>
> +/*
> + * This hook requires that the inode i_mutex be locked
> + */
> +static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> +{
> + return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
> +}
> +
> +/*
> + * This hook requires that the inode i_mutex be locked
> + */
> +static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> +{
> + return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
> +}
> +
> +static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> +{
> + *ctxlen = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
> + ctx, true);
> + return *ctxlen;
> +}
> #ifdef CONFIG_KEYS
>
> static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
> @@ -5491,6 +5513,9 @@ static struct security_operations selinux_ops = {
> .secid_to_secctx = selinux_secid_to_secctx,
> .secctx_to_secid = selinux_secctx_to_secid,
> .release_secctx = selinux_release_secctx,
> + .inode_notifysecctx = selinux_inode_notifysecctx,
> + .inode_setsecctx = selinux_inode_setsecctx,
> + .inode_getsecctx = selinux_inode_getsecctx,
>
> .unix_stream_connect = selinux_socket_unix_stream_connect,
> .unix_may_send = selinux_socket_unix_may_send,
> --
> 1.5.5.1
>
>
> --
> This message was distributed to subscribers of the selinux mailing list.
> If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
> the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information.
2008-09-30 20:22 ` Serge E. Hallyn
@ 2008-10-06 20:52 ` David P. Quigley
0 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-10-06 20:52 UTC (permalink / raw)
To: Serge E. Hallyn
Cc: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields,
linux-kernel, linux-fsdevel, linux-security-module, selinux,
labeled-nfs
Fixed
On Tue, 2008-09-30 at 15:22 -0500, Serge E. Hallyn wrote:
> Quoting David P. Quigley (dpquigl@tycho.nsa.gov):
> > This patch introduces three new hooks. The inode_getsecctx hook is used to get
> > all relevant information from an LSM about an inode. The inode_setsecctx is
> > used to set both the in-core and on-disk state for the inode based on a context
> > derived from inode_getsecctx.The final hook inode_notifysecctx will notify the
> > LSM of a change for the in-core state of the inode in question. These hooks are
> > for use in the labeled NFS code and addresses concerns of how to set security
> > on an inode in a multi-xattr LSM. For historical reasons Stephen Smalley's
> > explanation of the reason for these hooks is pasted below.
> >
> > Quote Stephen Smalley
> >
> > inode_setsecctx: Change the security context of an inode. Updates the
> > in core security context managed by the security module and invokes the
> > fs code as needed (via __vfs_setxattr_noperm) to update any backing
> > xattrs that represent the context. Example usage: NFS server invokes
> > this hook to change the security context in its incore inode and on the
> > backing file system to a value provided by the client on a SETATTR
> > operation.
> >
> > inode_notifysecctx: Notify the security module of what the security
> > context of an inode should be. Initializes the incore security context
> > managed by the security module for this inode. Example usage: NFS
> > client invokes this hook to initialize the security context in its
> > incore inode to the value provided by the server for the file when the
> > server returned the file's attributes to the client.
> >
> > Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> > Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
>
> Hmm, sorry, for all of these new hooks which you introduce, you do not
> define empty cap_* versions and assign them when need in
> security_fixup_ops(). But you unconditionally call them if
> CONFIG_SECURITY=y. So if you compile a kernel with CONFIG_SECURITY=y
> but CONFIG_SECURITY_SELINUX=n, don't you hose your box?
>
> > ---
> > include/linux/security.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++
> > security/security.c | 18 ++++++++++++++++
> > security/selinux/hooks.c | 25 +++++++++++++++++++++++
> > 3 files changed, 93 insertions(+), 0 deletions(-)
> >
> > diff --git a/include/linux/security.h b/include/linux/security.h
> > index 80c4d00..8b5b041 100644
> > --- a/include/linux/security.h
> > +++ b/include/linux/security.h
> > @@ -1289,6 +1289,36 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
> > * audit_rule_init.
> > * @rule contains the allocated rule
> > *
> > + * @inode_notifysecctx:
> > + * Notify the security module of what the security context of an inode
> > + * should be. Initializes the incore security context managed by the
> > + * security module for this inode. Example usage: NFS client invokes
> > + * this hook to initialize the security context in its incore inode to the
> > + * value provided by the server for the file when the server returned the
> > + * file's attributes to the client.
> > + *
> > + * @inode we wish to set the security context of.
> > + * @ctx contains the string which we wish to set in the inode.
> > + * @ctxlen contains the length of @ctx.
> > + *
> > + * @inode_setsecctx:
> > + * Change the security context of an inode. Updates the
> > + * incore security context managed by the security module and invokes the
> > + * fs code as needed (via __vfs_setxattr_noperm) to update any backing
> > + * xattrs that represent the context. Example usage: NFS server invokes
> > + * this hook to change the security context in its incore inode and on the
> > + * backing filesystem to a value provided by the client on a SETATTR
> > + * operation.
> > + *
> > + * @dentry contains the inode we wish to set the security context of.
> > + * @ctx contains the string which we wish to set in the inode.
> > + * @ctxlen contains the length of @ctx.
> > + *
> > + * @inode_getsecctx:
> > + * Returns a string containing all relavent security context information
> > + * @inode we wish to set the security context of.
> > + * @ctx is a pointer to place the allocated security context should be placed.
> > + * @ctxlen points to the place to put the length of @ctx.
> > * This is the main security structure.
> > */
> > struct security_operations {
> > @@ -1479,6 +1509,10 @@ struct security_operations {
> > int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
> > void (*release_secctx) (char *secdata, u32 seclen);
> >
> > + int (*inode_notifysecctx)(struct inode *inode, void *ctx, u32 ctxlen);
> > + int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen);
> > + int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen);
> > +
> > #ifdef CONFIG_SECURITY_NETWORK
> > int (*unix_stream_connect) (struct socket *sock,
> > struct socket *other, struct sock *newsk);
> > @@ -1727,6 +1761,9 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
> > int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
> > void security_release_secctx(char *secdata, u32 seclen);
> >
> > +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
> > +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
> > +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
> > #else /* CONFIG_SECURITY */
> > struct security_mnt_opts {
> > };
> > @@ -2458,6 +2495,19 @@ static inline int security_secctx_to_secid(const char *secdata,
> > static inline void security_release_secctx(char *secdata, u32 seclen)
> > {
> > }
> > +
> > +static inline int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> > +{
> > + return -EOPNOTSUPP;
> > +}
> > +static inline int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> > +{
> > + return -EOPNOTSUPP;
> > +}
> > +static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> > +{
> > + return -EOPNOTSUPP;
> > +}
> > #endif /* CONFIG_SECURITY */
> >
> > #ifdef CONFIG_SECURITY_NETWORK
> > diff --git a/security/security.c b/security/security.c
> > index 3a4b4f5..d0fd42a 100644
> > --- a/security/security.c
> > +++ b/security/security.c
> > @@ -869,6 +869,24 @@ void security_release_secctx(char *secdata, u32 seclen)
> > }
> > EXPORT_SYMBOL(security_release_secctx);
> >
> > +int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> > +{
> > + return security_ops->inode_notifysecctx(inode, ctx, ctxlen);
> > +}
> > +EXPORT_SYMBOL(security_inode_notifysecctx);
> > +
> > +int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> > +{
> > + return security_ops->inode_setsecctx(dentry, ctx, ctxlen);
> > +}
> > +EXPORT_SYMBOL(security_inode_setsecctx);
> > +
> > +int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> > +{
> > + return security_ops->inode_getsecctx(inode, ctx, ctxlen);
> > +}
> > +EXPORT_SYMBOL(security_inode_getsecctx);
> > +
> > #ifdef CONFIG_SECURITY_NETWORK
> >
> > int security_unix_stream_connect(struct socket *sock, struct socket *other,
> > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > index 03fc6a8..b07871b 100644
> > --- a/security/selinux/hooks.c
> > +++ b/security/selinux/hooks.c
> > @@ -5285,6 +5285,28 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
> > kfree(secdata);
> > }
> >
> > +/*
> > + * This hook requires that the inode i_mutex be locked
> > + */
> > +static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
> > +{
> > + return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
> > +}
> > +
> > +/*
> > + * This hook requires that the inode i_mutex be locked
> > + */
> > +static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
> > +{
> > + return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
> > +}
> > +
> > +static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
> > +{
> > + *ctxlen = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
> > + ctx, true);
> > + return *ctxlen;
> > +}
> > #ifdef CONFIG_KEYS
> >
> > static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
> > @@ -5491,6 +5513,9 @@ static struct security_operations selinux_ops = {
> > .secid_to_secctx = selinux_secid_to_secctx,
> > .secctx_to_secid = selinux_secctx_to_secid,
> > .release_secctx = selinux_release_secctx,
> > + .inode_notifysecctx = selinux_inode_notifysecctx,
> > + .inode_setsecctx = selinux_inode_setsecctx,
> > + .inode_getsecctx = selinux_inode_getsecctx,
> >
> > .unix_stream_connect = selinux_socket_unix_stream_connect,
> > .unix_may_send = selinux_socket_unix_may_send,
> > --
> > 1.5.5.1
> >
> >
> > --
> > This message was distributed to subscribers of the selinux mailing list.
> > If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
> > the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 03/14] Security: Add hook to calculate context based on a negative dentry.
[not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
2008-09-29 17:06 ` [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information David P. Quigley
@ 2008-09-29 17:06 ` David P. Quigley
2008-09-30 20:15 ` Serge E. Hallyn
2008-09-29 17:06 ` [PATCH 04/14] Security: Add Hook to test if the particular xattr is part of a MAC model David P. Quigley
` (6 subsequent siblings)
8 siblings, 1 reply; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
trond.myklebust-41N18TsMXrtuMpJDpNschA,
bfields-uC3wQj2KruNg9hUCZPvPmw
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
selinux-+05T5uksL2qpZYMLLGbcSA,
labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
Matthew N. Dodd
There is a time where we need to calculate a context without the
inode having been created yet. To do this we take the negative dentry and
calculate a context based on the process and the parent directory contexts.
Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
include/linux/security.h | 14 ++++++++++++++
security/security.c | 7 +++++++
security/selinux/hooks.c | 36 ++++++++++++++++++++++++++++++++++++
3 files changed, 57 insertions(+), 0 deletions(-)
diff --git a/include/linux/security.h b/include/linux/security.h
index 8b5b041..42b9128 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1379,6 +1379,9 @@ struct security_operations {
void (*sb_clone_mnt_opts) (const struct super_block *oldsb,
struct super_block *newsb);
int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
+ int (*dentry_init_security) (struct dentry *dentry, int mode,
+ void **ctx, u32 *ctxlen);
+
int (*inode_alloc_security) (struct inode *inode);
void (*inode_free_security) (struct inode *inode);
@@ -1651,6 +1654,8 @@ int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *o
void security_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb);
int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);
+int security_dentry_init_security (struct dentry *dentry, int mode,
+ void **ctx, u32 *ctxlen);
int security_inode_alloc(struct inode *inode);
void security_inode_free(struct inode *inode);
@@ -1994,6 +1999,15 @@ static inline int security_inode_alloc(struct inode *inode)
static inline void security_inode_free(struct inode *inode)
{ }
+static inline int security_dentry_init_security (struct dentry *dentry,
+ int mode,
+ void **ctx,
+ u32 *ctxlen)
+{
+ return -EOPNOTSUPP;
+}
+
+
static inline int security_inode_init_security(struct inode *inode,
struct inode *dir,
char **name,
diff --git a/security/security.c b/security/security.c
index d0fd42a..b22a110 100644
--- a/security/security.c
+++ b/security/security.c
@@ -349,6 +349,13 @@ void security_inode_free(struct inode *inode)
security_ops->inode_free_security(inode);
}
+int security_dentry_init_security (struct dentry *dentry, int mode,
+ void **ctx, u32 *ctxlen)
+{
+ return security_ops->dentry_init_security (dentry, mode, ctx, ctxlen);
+}
+EXPORT_SYMBOL(security_dentry_init_security);
+
int security_inode_init_security(struct inode *inode, struct inode *dir,
char **name, void **value, size_t *len)
{
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b07871b..680db1d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2504,6 +2504,41 @@ static void selinux_inode_free_security(struct inode *inode)
inode_free_security(inode);
}
+/*
+ * For now, we need a way to compute a SID for
+ * a dentry as the inode is not yet available
+ * (and under NFSv4 has no label backed by an EA anyway.
+ */
+static int selinux_dentry_init_security(struct dentry *dentry, int mode, void **ctx, u32 *ctxlen)
+{
+ struct task_security_struct *tsec;
+ struct inode_security_struct *dsec;
+ struct superblock_security_struct *sbsec;
+ struct inode *dir = dentry->d_parent->d_inode;
+ u32 newsid;
+ int rc;
+
+ tsec = current->security;
+ dsec = dir->i_security;
+ sbsec = dir->i_sb->s_security;
+
+ if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
+ newsid = tsec->create_sid;
+ } else {
+ rc = security_transition_sid(tsec->sid, dsec->sid,
+ inode_mode_to_security_class(mode),
+ &newsid);
+ if (rc) {
+ printk(KERN_WARNING "%s: "
+ "security_transition_sid failed, rc=%d\n",
+ __FUNCTION__, -rc);
+ return rc;
+ }
+ }
+
+ return security_sid_to_context(newsid, (char **)ctx, ctxlen);
+}
+
static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
char **name, void **value,
size_t *len)
@@ -5413,6 +5448,7 @@ static struct security_operations selinux_ops = {
.sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
.sb_parse_opts_str = selinux_parse_opts_str,
+ .dentry_init_security = selinux_dentry_init_security,
.inode_alloc_security = selinux_inode_alloc_security,
.inode_free_security = selinux_inode_free_security,
--
1.5.5.1
^ permalink raw reply related [flat|nested] 33+ messages in thread
* Re: [PATCH 03/14] Security: Add hook to calculate context based on a negative dentry.
2008-09-29 17:06 ` [PATCH 03/14] Security: Add hook to calculate context based on a negative dentry David P. Quigley
@ 2008-09-30 20:15 ` Serge E. Hallyn
[not found] ` <20080930201524.GC21039-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
0 siblings, 1 reply; 33+ messages in thread
From: Serge E. Hallyn @ 2008-09-30 20:15 UTC (permalink / raw)
To: David P. Quigley
Cc: hch, viro, casey, sds, matthew.dodd, trond.myklebust, bfields,
linux-kernel, linux-fsdevel, linux-security-module, selinux,
labeled-nfs
Quoting David P. Quigley (dpquigl@tycho.nsa.gov):
> There is a time where we need to calculate a context without the
> inode having been created yet. To do this we take the negative dentry and
> calculate a context based on the process and the parent directory contexts.
>
> Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov>
> ---
> include/linux/security.h | 14 ++++++++++++++
> security/security.c | 7 +++++++
> security/selinux/hooks.c | 36 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 57 insertions(+), 0 deletions(-)
>
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 8b5b041..42b9128 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -1379,6 +1379,9 @@ struct security_operations {
> void (*sb_clone_mnt_opts) (const struct super_block *oldsb,
> struct super_block *newsb);
> int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
> + int (*dentry_init_security) (struct dentry *dentry, int mode,
> + void **ctx, u32 *ctxlen);
This of course needs a description at top of include/linux/security.h.
> +
>
> int (*inode_alloc_security) (struct inode *inode);
> void (*inode_free_security) (struct inode *inode);
> @@ -1651,6 +1654,8 @@ int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *o
> void security_sb_clone_mnt_opts(const struct super_block *oldsb,
> struct super_block *newsb);
> int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);
> +int security_dentry_init_security (struct dentry *dentry, int mode,
> + void **ctx, u32 *ctxlen);
>
> int security_inode_alloc(struct inode *inode);
> void security_inode_free(struct inode *inode);
> @@ -1994,6 +1999,15 @@ static inline int security_inode_alloc(struct inode *inode)
> static inline void security_inode_free(struct inode *inode)
> { }
>
> +static inline int security_dentry_init_security (struct dentry *dentry,
> + int mode,
> + void **ctx,
> + u32 *ctxlen)
> +{
> + return -EOPNOTSUPP;
> +}
> +
> +
> static inline int security_inode_init_security(struct inode *inode,
> struct inode *dir,
> char **name,
> diff --git a/security/security.c b/security/security.c
> index d0fd42a..b22a110 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -349,6 +349,13 @@ void security_inode_free(struct inode *inode)
> security_ops->inode_free_security(inode);
> }
>
> +int security_dentry_init_security (struct dentry *dentry, int mode,
> + void **ctx, u32 *ctxlen)
> +{
> + return security_ops->dentry_init_security (dentry, mode, ctx, ctxlen);
> +}
> +EXPORT_SYMBOL(security_dentry_init_security);
> +
> int security_inode_init_security(struct inode *inode, struct inode *dir,
> char **name, void **value, size_t *len)
> {
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index b07871b..680db1d 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -2504,6 +2504,41 @@ static void selinux_inode_free_security(struct inode *inode)
> inode_free_security(inode);
> }
>
> +/*
> + * For now, we need a way to compute a SID for
Just 'Compute a SID for...' ?
> + * a dentry as the inode is not yet available
> + * (and under NFSv4 has no label backed by an EA anyway.
> + */
> +static int selinux_dentry_init_security(struct dentry *dentry, int mode, void **ctx, u32 *ctxlen)
> +{
> + struct task_security_struct *tsec;
> + struct inode_security_struct *dsec;
> + struct superblock_security_struct *sbsec;
> + struct inode *dir = dentry->d_parent->d_inode;
> + u32 newsid;
> + int rc;
> +
> + tsec = current->security;
> + dsec = dir->i_security;
> + sbsec = dir->i_sb->s_security;
> +
> + if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
> + newsid = tsec->create_sid;
> + } else {
> + rc = security_transition_sid(tsec->sid, dsec->sid,
> + inode_mode_to_security_class(mode),
> + &newsid);
> + if (rc) {
> + printk(KERN_WARNING "%s: "
> + "security_transition_sid failed, rc=%d\n",
> + __FUNCTION__, -rc);
> + return rc;
> + }
> + }
> +
> + return security_sid_to_context(newsid, (char **)ctx, ctxlen);
> +}
> +
> static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
> char **name, void **value,
> size_t *len)
> @@ -5413,6 +5448,7 @@ static struct security_operations selinux_ops = {
> .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
> .sb_parse_opts_str = selinux_parse_opts_str,
>
> + .dentry_init_security = selinux_dentry_init_security,
>
> .inode_alloc_security = selinux_inode_alloc_security,
> .inode_free_security = selinux_inode_free_security,
> --
> 1.5.5.1
>
>
> --
> This message was distributed to subscribers of the selinux mailing list.
> If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
> the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 33+ messages in thread
* [PATCH 04/14] Security: Add Hook to test if the particular xattr is part of a MAC model.
[not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
2008-09-29 17:06 ` [PATCH 02/14] LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information David P. Quigley
2008-09-29 17:06 ` [PATCH 03/14] Security: Add hook to calculate context based on a negative dentry David P. Quigley
@ 2008-09-29 17:06 ` David P. Quigley
2008-09-29 17:06 ` [PATCH 07/14] NFSv4: Add label recommended attribute and NFSv4 flags David P. Quigley
` (5 subsequent siblings)
8 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
trond.myklebust-41N18TsMXrtuMpJDpNschA,
bfields-uC3wQj2KruNg9hUCZPvPmw
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
selinux-+05T5uksL2qpZYMLLGbcSA,
labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
Matthew N. Dodd
There are areas in the Labeled NFS code where where we need to test if the
attribute being requested exhibits the semantics of a MAC model. This allows us
to make sure that we get the desired semantics from the attribute instead of
something else such as capabilities or a time based LSM.
Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
include/linux/security.h | 11 +++++++++++
security/security.c | 6 ++++++
security/selinux/hooks.c | 6 ++++++
security/smack/smack_lsm.c | 10 ++++++++++
4 files changed, 33 insertions(+), 0 deletions(-)
diff --git a/include/linux/security.h b/include/linux/security.h
index 42b9128..3031e6c 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1244,6 +1244,10 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @pages contains the number of pages.
* Return 0 if permission is granted.
*
+ * @ismaclabel:
+ * Check if the extended attribute specified by @name represents a MAC label.
+ * @name full extended attribute name to check against LSM as a MAC label.
+ *
* @secid_to_secctx:
* Convert secid to security context.
* @secid contains the security ID.
@@ -1508,6 +1512,7 @@ struct security_operations {
int (*getprocattr) (struct task_struct *p, char *name, char **value);
int (*setprocattr) (struct task_struct *p, char *name, void *value, size_t size);
+ int (*ismaclabel) (const char * name);
int (*secid_to_secctx) (u32 secid, char **secdata, u32 *seclen);
int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
void (*release_secctx) (char *secdata, u32 seclen);
@@ -1762,6 +1767,7 @@ int security_getprocattr(struct task_struct *p, char *name, char **value);
int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size);
int security_netlink_send(struct sock *sk, struct sk_buff *skb);
int security_netlink_recv(struct sk_buff *skb, int cap);
+int security_ismaclabel(const char *name);
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void security_release_secctx(char *secdata, u32 seclen);
@@ -2494,6 +2500,11 @@ static inline void securityfs_remove(struct dentry *dentry)
{
}
+static inline int security_ismaclabel(const char *name)
+{
+ return 0;
+}
+
static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
return -EOPNOTSUPP;
diff --git a/security/security.c b/security/security.c
index b22a110..1955094 100644
--- a/security/security.c
+++ b/security/security.c
@@ -858,6 +858,12 @@ int security_netlink_recv(struct sk_buff *skb, int cap)
}
EXPORT_SYMBOL(security_netlink_recv);
+int security_ismaclabel(const char *name)
+{
+ return security_ops->ismaclabel(name);
+}
+EXPORT_SYMBOL(security_ismaclabel);
+
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
return security_ops->secid_to_secctx(secid, secdata, seclen);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 680db1d..248fa5c 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5305,6 +5305,11 @@ static int selinux_setprocattr(struct task_struct *p,
return size;
}
+static int selinux_ismaclabel(const char *name)
+{
+ return (strcmp(name,XATTR_NAME_SELINUX) == 0);
+}
+
static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
return security_sid_to_context(secid, secdata, seclen);
@@ -5546,6 +5551,7 @@ static struct security_operations selinux_ops = {
.getprocattr = selinux_getprocattr,
.setprocattr = selinux_setprocattr,
+ .ismaclabel = selinux_ismaclabel,
.secid_to_secctx = selinux_secid_to_secctx,
.secctx_to_secid = selinux_secctx_to_secid,
.release_secctx = selinux_release_secctx,
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 87d7541..46e9888 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2526,6 +2526,15 @@ static void smack_audit_rule_free(void *vrule)
#endif /* CONFIG_AUDIT */
/*
+ * smack_ismaclabel - check if xattr @name references a smack MAC label
+ * @name: Full xattr name to check.
+ */
+static int smack_ismaclabel(const char *name)
+{
+ return (strcmp(name, XATTR_NAME_SMACK) == 0);
+}
+
+/*
* smack_secid_to_secctx - return the smack label for a secid
* @secid: incoming integer
* @secdata: destination
@@ -2703,6 +2712,7 @@ struct security_operations smack_ops = {
.audit_rule_free = smack_audit_rule_free,
#endif /* CONFIG_AUDIT */
+ .ismaclabel = smack_ismaclabel,
.secid_to_secctx = smack_secid_to_secctx,
.secctx_to_secid = smack_secctx_to_secid,
.release_secctx = smack_release_secctx,
--
1.5.5.1
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 07/14] NFSv4: Add label recommended attribute and NFSv4 flags
[not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
` (2 preceding siblings ...)
2008-09-29 17:06 ` [PATCH 04/14] Security: Add Hook to test if the particular xattr is part of a MAC model David P. Quigley
@ 2008-09-29 17:06 ` David P. Quigley
2008-09-29 17:06 ` [PATCH 08/14] NFS: Add security_label text mount option and handling code to NFS David P. Quigley
` (4 subsequent siblings)
8 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
trond.myklebust-41N18TsMXrtuMpJDpNschA,
bfields-uC3wQj2KruNg9hUCZPvPmw
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
selinux-+05T5uksL2qpZYMLLGbcSA,
labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
Matthew N. Dodd
This patch adds a new recommended attribute named label into the NFSv4 file
attribute structure. It also adds several new flags to allow the NFS client and
server to determine if this attribute is supported and if it is being sent over
the wire.
Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
include/linux/nfs4.h | 2 ++
include/linux/nfs_fs_sb.h | 2 +-
include/linux/nfs_xdr.h | 4 ++++
include/linux/nfsd/export.h | 5 +++--
include/linux/nfsd/nfsd.h | 7 ++++---
5 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index ea03667..144eacf 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -21,6 +21,7 @@
#define NFS4_FHSIZE 128
#define NFS4_MAXPATHLEN PATH_MAX
#define NFS4_MAXNAMLEN NAME_MAX
+#define NFS4_MAXLABELLEN 4096
#define NFS4_ACCESS_READ 0x0001
#define NFS4_ACCESS_LOOKUP 0x0002
@@ -345,6 +346,7 @@ enum lock_type4 {
#define FATTR4_WORD1_TIME_MODIFY (1UL << 21)
#define FATTR4_WORD1_TIME_MODIFY_SET (1UL << 22)
#define FATTR4_WORD1_MOUNTED_ON_FILEID (1UL << 23)
+#define FATTR4_WORD1_SECURITY_LABEL (1UL << 31)
#define NFSPROC4_NULL 0
#define NFSPROC4_COMPOUND 1
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index c9beacd..9475bb0 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -135,5 +135,5 @@ struct nfs_server {
#define NFS_CAP_SYMLINKS (1U << 2)
#define NFS_CAP_ACLS (1U << 3)
#define NFS_CAP_ATOMIC_OPEN (1U << 4)
-
+#define NFS_CAP_SECURITY_LABEL (1U << 5)
#endif
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 8c77c11..0d77568 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -56,6 +56,10 @@ struct nfs_fattr {
__u64 change_attr; /* NFSv4 change attribute */
__u64 pre_change_attr;/* pre-op NFSv4 change attribute */
unsigned long time_start;
+#ifdef CONFIG_SECURITY
+ void *label;
+ __u32 label_len;
+#endif
};
#define NFS_ATTR_WCC 0x0001 /* pre-op WCC data */
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
index 5431512..bb831fc 100644
--- a/include/linux/nfsd/export.h
+++ b/include/linux/nfsd/export.h
@@ -32,7 +32,8 @@
#define NFSEXP_ALLSQUASH 0x0008
#define NFSEXP_ASYNC 0x0010
#define NFSEXP_GATHERED_WRITES 0x0020
-/* 40 80 100 currently unused */
+#define NFSEXP_SECURITY_LABEL 0x0040 /* Support security label fattr4 */
+/* 80 100 currently unused */
#define NFSEXP_NOHIDE 0x0200
#define NFSEXP_NOSUBTREECHECK 0x0400
#define NFSEXP_NOAUTHNLM 0x0800 /* Don't authenticate NLM requests - just trust */
@@ -40,7 +41,7 @@
#define NFSEXP_FSID 0x2000
#define NFSEXP_CROSSMOUNT 0x4000
#define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */
-#define NFSEXP_ALLFLAGS 0xFE3F
+#define NFSEXP_ALLFLAGS 0xFE7F
/* The flags that may vary depending on security flavor: */
#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 108f47e..f329b96 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -317,8 +317,8 @@ extern struct timeval nfssvc_boot;
| FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP | FATTR4_WORD1_RAWDEV \
| FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL \
| FATTR4_WORD1_SPACE_USED | FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_ACCESS_SET \
- | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA \
- | FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID)
+ | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY \
+ | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID | FATTR4_WORD1_SECURITY_LABEL)
/* These will return ERR_INVAL if specified in GETATTR or READDIR. */
#define NFSD_WRITEONLY_ATTRS_WORD1 \
@@ -329,7 +329,8 @@ extern struct timeval nfssvc_boot;
(FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL )
#define NFSD_WRITEABLE_ATTRS_WORD1 \
(FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
- | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
+ | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY_SET \
+ | FATTR4_WORD1_SECURITY_LABEL)
#endif /* CONFIG_NFSD_V4 */
--
1.5.5.1
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 08/14] NFS: Add security_label text mount option and handling code to NFS
[not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
` (3 preceding siblings ...)
2008-09-29 17:06 ` [PATCH 07/14] NFSv4: Add label recommended attribute and NFSv4 flags David P. Quigley
@ 2008-09-29 17:06 ` David P. Quigley
2008-09-29 17:06 ` [PATCH 09/14] NFS: Introduce lifecycle management for label attribute David P. Quigley
` (3 subsequent siblings)
8 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
trond.myklebust-41N18TsMXrtuMpJDpNschA,
bfields-uC3wQj2KruNg9hUCZPvPmw
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
selinux-+05T5uksL2qpZYMLLGbcSA,
labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
Matthew N. Dodd
This patch adds two new text options to to the NFS mount options to specify
security labeling. It also sends certain LSM related mount options into the
module for handling.
Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
fs/nfs/super.c | 9 +++++++++
include/linux/nfs4_mount.h | 6 +++++-
security/selinux/hooks.c | 2 +-
3 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 9abcd2b..256ce27 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -75,6 +75,7 @@ enum {
Opt_acl, Opt_noacl,
Opt_rdirplus, Opt_nordirplus,
Opt_sharecache, Opt_nosharecache,
+ Opt_security_label, Opt_nosecurity_label,
/* Mount options that take integer arguments */
Opt_port,
@@ -128,6 +129,8 @@ static match_table_t nfs_mount_option_tokens = {
{ Opt_nordirplus, "nordirplus" },
{ Opt_sharecache, "sharecache" },
{ Opt_nosharecache, "nosharecache" },
+ { Opt_security_label, "security_label" },
+ { Opt_nosecurity_label, "nosecurity_label" },
{ Opt_port, "port=%u" },
{ Opt_rsize, "rsize=%u" },
@@ -1033,6 +1036,12 @@ static int nfs_parse_mount_options(char *raw,
case Opt_nosharecache:
mnt->flags |= NFS_MOUNT_UNSHARED;
break;
+ case Opt_nosecurity_label:
+ mnt->flags &= ~NFS4_MOUNT_SECURITY_LABEL;
+ break;
+ case Opt_security_label:
+ mnt->flags |= NFS4_MOUNT_SECURITY_LABEL;
+ break;
/*
* options that take numeric values
diff --git a/include/linux/nfs4_mount.h b/include/linux/nfs4_mount.h
index a0dcf66..e65067b 100644
--- a/include/linux/nfs4_mount.h
+++ b/include/linux/nfs4_mount.h
@@ -17,6 +17,7 @@
* but here they are anyway.
*/
#define NFS4_MOUNT_VERSION 1
+#define NFS4_MAX_CONTEXT_LEN 4096
struct nfs_string {
unsigned int len;
@@ -53,6 +54,8 @@ struct nfs4_mount_data {
/* Pseudo-flavours to use for authentication. See RFC2623 */
int auth_flavourlen; /* 1 */
int __user *auth_flavours; /* 1 */
+
+ char context[NFS4_MAX_CONTEXT_LEN + 1]; /* 2 */
};
/* bits in the flags field */
@@ -66,6 +69,7 @@ struct nfs4_mount_data {
#define NFS4_MOUNT_NOAC 0x0020 /* 1 */
#define NFS4_MOUNT_STRICTLOCK 0x1000 /* 1 */
#define NFS4_MOUNT_UNSHARED 0x8000 /* 1 */
-#define NFS4_MOUNT_FLAGMASK 0x9033
+#define NFS4_MOUNT_SECURITY_LABEL 0x10000 /* 2 */
+#define NFS4_MOUNT_FLAGMASK 0x19033
#endif
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 78e79d3..6919766 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -612,7 +612,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
for (i = 0; i < num_opts; i++) {
u32 sid;
if (flags[i] == NATIVE_LABELS_MNT) {
- sbsec->flags | = NATIVE_LABELS_MNT;
+ sbsec->flags |= NATIVE_LABELS_MNT;
continue;
}
rc = security_context_to_sid(mount_options[i],
--
1.5.5.1
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 09/14] NFS: Introduce lifecycle management for label attribute.
[not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
` (4 preceding siblings ...)
2008-09-29 17:06 ` [PATCH 08/14] NFS: Add security_label text mount option and handling code to NFS David P. Quigley
@ 2008-09-29 17:06 ` David P. Quigley
2008-09-29 17:06 ` [PATCH 12/14] NFS: Client implementation of Labeled-NFS David P. Quigley
` (2 subsequent siblings)
8 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
trond.myklebust-41N18TsMXrtuMpJDpNschA,
bfields-uC3wQj2KruNg9hUCZPvPmw
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
selinux-+05T5uksL2qpZYMLLGbcSA,
labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
Matthew N. Dodd
Two fields have been added to the nfs_fattr structure to carry the security
label and its length. This has raised the need to provide lifecycle management
for these values. This patch introduces two macros nfs_fattr_alloc and
nfs_fattr_fini which are used to allocate and destroy these fields inside the
nfs_fattr structure. These macros do not modify any other components of the
structure so nfs_fattr_init still has to be used on these structures. In the
event that CONFIG_SECURITY is not set these calls should compile away.
Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
fs/nfs/client.c | 18 +++++++++-
fs/nfs/dir.c | 24 +++++++++++++
fs/nfs/getroot.c | 35 ++++++++++++++++++-
fs/nfs/inode.c | 16 +++++++++
fs/nfs/namespace.c | 3 ++
fs/nfs/nfs3proc.c | 7 ++++
fs/nfs/nfs4proc.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++-
fs/nfs/proc.c | 12 ++++++-
fs/nfs/super.c | 4 ++
include/linux/nfs_fs.h | 46 +++++++++++++++++++++++++
10 files changed, 248 insertions(+), 5 deletions(-)
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 5ee23e7..756d554 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -902,6 +902,8 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data,
struct nfs_fattr fattr;
int error;
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+
server = nfs_alloc_server();
if (!server)
return ERR_PTR(-ENOMEM);
@@ -952,10 +954,12 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data,
spin_unlock(&nfs_client_lock);
server->mount_time = jiffies;
+ nfs_fattr_fini(&fattr);
return server;
error:
nfs_free_server(server);
+ nfs_fattr_fini(&fattr);
return ERR_PTR(error);
}
@@ -1073,7 +1077,7 @@ static int nfs4_init_server(struct nfs_server *server,
goto error;
/* Initialise the client representation from the mount data */
- server->flags = data->flags & NFS_MOUNT_FLAGMASK;
+ server->flags = data->flags & NFS4_MOUNT_FLAGMASK;
server->caps |= NFS_CAP_ATOMIC_OPEN;
if (data->rsize)
@@ -1109,6 +1113,8 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
dprintk("--> nfs4_create_server()\n");
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+
server = nfs_alloc_server();
if (!server)
return ERR_PTR(-ENOMEM);
@@ -1149,11 +1155,13 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
spin_unlock(&nfs_client_lock);
server->mount_time = jiffies;
+ nfs_fattr_fini(&fattr);
dprintk("<-- nfs4_create_server() = %p\n", server);
return server;
error:
nfs_free_server(server);
+ nfs_fattr_fini(&fattr);
dprintk("<-- nfs4_create_server() = error %d\n", error);
return ERR_PTR(error);
}
@@ -1171,6 +1179,8 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
dprintk("--> nfs4_create_referral_server()\n");
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+
server = nfs_alloc_server();
if (!server)
return ERR_PTR(-ENOMEM);
@@ -1227,10 +1237,12 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
server->mount_time = jiffies;
dprintk("<-- nfs_create_referral_server() = %p\n", server);
+ nfs_fattr_fini(&fattr);
return server;
error:
nfs_free_server(server);
+ nfs_fattr_fini(&fattr);
dprintk("<-- nfs4_create_referral_server() = error %d\n", error);
return ERR_PTR(error);
}
@@ -1252,6 +1264,8 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source,
(unsigned long long) fattr->fsid.major,
(unsigned long long) fattr->fsid.minor);
+ memset(&fattr_fsinfo, 0, sizeof(struct nfs_fattr));
+
server = nfs_alloc_server();
if (!server)
return ERR_PTR(-ENOMEM);
@@ -1294,11 +1308,13 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source,
server->mount_time = jiffies;
+ nfs_fattr_fini(&fattr_fsinfo);
dprintk("<-- nfs_clone_server() = %p\n", server);
return server;
out_free_server:
nfs_free_server(server);
+ nfs_fattr_fini(&fattr_fsinfo);
dprintk("<-- nfs_clone_server() = error %d\n", error);
return ERR_PTR(error);
}
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 74f92b7..db43b69 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -551,6 +551,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
my_entry.eof = 0;
my_entry.fh = &fh;
my_entry.fattr = &fattr;
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
nfs_fattr_init(&fattr);
desc->entry = &my_entry;
@@ -588,6 +589,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
res = 0;
break;
}
+ nfs_fattr_fini(&fattr);
}
out:
nfs_unblock_sillyrename(dentry);
@@ -773,6 +775,8 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
struct nfs_fh fhandle;
struct nfs_fattr fattr;
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+
parent = dget_parent(dentry);
dir = parent->d_inode;
nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
@@ -801,6 +805,11 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
if (NFS_STALE(inode))
goto out_bad;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL))
+ nfs_fattr_alloc(&fattr, GFP_NOWAIT);
+#endif
+
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
if (error)
goto out_bad;
@@ -812,6 +821,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
out_valid:
dput(parent);
+ nfs_fattr_fini(&fattr);
dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is valid\n",
__func__, dentry->d_parent->d_name.name,
dentry->d_name.name);
@@ -830,6 +840,7 @@ out_zap_parent:
}
d_drop(dentry);
dput(parent);
+ nfs_fattr_fini(&fattr);
dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n",
__func__, dentry->d_parent->d_name.name,
dentry->d_name.name);
@@ -906,6 +917,8 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
dentry->d_parent->d_name.name, dentry->d_name.name);
nfs_inc_stats(dir, NFSIOS_VFSLOOKUP);
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+
res = ERR_PTR(-ENAMETOOLONG);
if (dentry->d_name.len > NFS_SERVER(dir)->namelen)
goto out;
@@ -923,6 +936,11 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
goto out;
}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL))
+ nfs_fattr_alloc(&fattr, GFP_NOWAIT);
+#endif
+
parent = dentry->d_parent;
/* Protect against concurrent sillydeletes */
nfs_block_sillyrename(parent);
@@ -949,6 +967,8 @@ no_entry:
out_unblock_sillyrename:
nfs_unblock_sillyrename(parent);
out:
+ /* Label will give 'unused' warning on 'no_entry' case. */
+ nfs_fattr_fini(&fattr);
return res;
}
@@ -1214,6 +1234,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
dfprintk(VFS, "NFS: create(%s/%ld), %s\n",
dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
+ memset(&attr, 0, sizeof(struct iattr));
attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;
@@ -1244,6 +1265,7 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
if (!new_valid_dev(rdev))
return -EINVAL;
+ memset(&attr, 0, sizeof(struct iattr));
attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;
@@ -1267,6 +1289,7 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
dfprintk(VFS, "NFS: mkdir(%s/%ld), %s\n",
dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
+ memset(&attr, 0, sizeof(struct iattr));
attr.ia_valid = ATTR_MODE;
attr.ia_mode = mode | S_IFDIR;
@@ -1476,6 +1499,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
if (pathlen > PAGE_SIZE)
return -ENAMETOOLONG;
+ memset(&attr, 0, sizeof(struct iattr));
attr.ia_mode = S_IFLNK | S_IRWXUGO;
attr.ia_valid = ATTR_MODE;
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index fae9719..bc23077 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -31,7 +31,6 @@
#include <linux/vfs.h>
#include <linux/namei.h>
#include <linux/mnt_namespace.h>
-#include <linux/security.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -84,6 +83,8 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
struct inode *inode;
int error;
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+
/* get the actual root for this mount */
fsinfo.fattr = &fattr;
@@ -119,6 +120,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
if (!mntroot->d_op)
mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops;
+ nfs_fattr_fini(&fattr);
return mntroot;
}
@@ -143,6 +145,12 @@ int nfs4_path_walk(struct nfs_server *server,
dprintk("--> nfs4_path_walk(,,%s)\n", path);
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ /* Unconditional, no server caps yet. */
+ nfs_fattr_alloc(&fattr, GFP_KERNEL);
+#endif
+
fsinfo.fattr = &fattr;
nfs_fattr_init(&fattr);
@@ -154,12 +162,14 @@ int nfs4_path_walk(struct nfs_server *server,
ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
if (ret < 0) {
dprintk("nfs4_get_root: getroot error = %d\n", -ret);
+ nfs_fattr_fini(&fattr);
return ret;
}
if (fattr.type != NFDIR) {
printk(KERN_ERR "nfs4_get_root:"
" getroot encountered non-directory\n");
+ nfs_fattr_fini(&fattr);
return -ENOTDIR;
}
@@ -167,6 +177,7 @@ int nfs4_path_walk(struct nfs_server *server,
if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) {
printk(KERN_ERR "nfs4_get_root:"
" getroot obtained referral\n");
+ nfs_fattr_fini(&fattr);
return -EREMOTE;
}
@@ -199,6 +210,7 @@ eat_dot_dir:
) {
printk(KERN_ERR "nfs4_get_root:"
" Mount path contains reference to \"..\"\n");
+ nfs_fattr_fini(&fattr);
return -EINVAL;
}
@@ -207,16 +219,25 @@ eat_dot_dir:
dprintk("LookupFH: %*.*s [%s]\n", name.len, name.len, name.name, path);
+ nfs_fattr_fini(&fattr);
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL)
+ nfs_fattr_alloc(&fattr, GFP_KERNEL);
+#endif
+
ret = server->nfs_client->rpc_ops->lookupfh(server, &lastfh, &name,
mntfh, &fattr);
if (ret < 0) {
dprintk("nfs4_get_root: getroot error = %d\n", -ret);
+ nfs_fattr_fini(&fattr);
return ret;
}
if (fattr.type != NFDIR) {
printk(KERN_ERR "nfs4_get_root:"
" lookupfh encountered non-directory\n");
+ nfs_fattr_fini(&fattr);
return -ENOTDIR;
}
@@ -224,6 +245,7 @@ eat_dot_dir:
if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) {
printk(KERN_ERR "nfs4_get_root:"
" lookupfh obtained referral\n");
+ nfs_fattr_fini(&fattr);
return -EREMOTE;
}
@@ -231,6 +253,7 @@ eat_dot_dir:
path_walk_complete:
memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid));
+ nfs_fattr_fini(&fattr);
dprintk("<-- nfs4_path_walk() = 0\n");
return 0;
}
@@ -256,19 +279,29 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
return ERR_PTR(error);
}
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL)
+ nfs_fattr_alloc(&fattr, GFP_KERNEL);
+#endif
+
/* get the actual root for this mount */
error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr);
if (error < 0) {
+ nfs_fattr_fini(&fattr);
dprintk("nfs_get_root: getattr error = %d\n", -error);
return ERR_PTR(error);
}
inode = nfs_fhget(sb, mntfh, &fattr);
if (IS_ERR(inode)) {
+ nfs_fattr_fini(&fattr);
dprintk("nfs_get_root: get root inode failed\n");
return ERR_CAST(inode);
}
+ nfs_fattr_fini(&fattr);
+
error = nfs_superblock_set_dummy_root(sb, inode);
if (error != 0)
return ERR_PTR(error);
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 52daefa..40d7142 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -360,6 +360,12 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
attr->ia_valid &= ~ATTR_MODE;
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
+ nfs_fattr_alloc(&fattr, GFP_KERNEL);
+#endif
+
if (attr->ia_valid & ATTR_SIZE) {
if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode))
attr->ia_valid &= ~ATTR_SIZE;
@@ -383,6 +389,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr);
if (error == 0)
nfs_refresh_inode(inode, &fattr);
+ nfs_fattr_fini(&fattr);
return error;
}
@@ -698,6 +705,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
inode->i_sb->s_id, (long long)NFS_FILEID(inode));
nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
+
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+
if (is_bad_inode(inode))
goto out_nowait;
if (NFS_STALE(inode))
@@ -711,6 +721,11 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
if (NFS_STALE(inode))
goto out;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
+ nfs_fattr_alloc(&fattr, GFP_KERNEL);
+#endif
+
status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), &fattr);
if (status != 0) {
dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
@@ -746,6 +761,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
nfs_wake_up_inode(inode);
out_nowait:
+ nfs_fattr_fini(&fattr);
return status;
}
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 66df08d..a20b428 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -105,6 +105,8 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
dprintk("--> nfs_follow_mountpoint()\n");
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+
BUG_ON(IS_ROOT(dentry));
dprintk("%s: enter\n", __func__);
dput(nd->path.dentry);
@@ -142,6 +144,7 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
nd->path.dentry = dget(mnt->mnt_root);
schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
out:
+ nfs_fattr_fini(&fattr);
dprintk("%s: done, returned %d\n", __func__, err);
dprintk("<-- nfs_follow_mountpoint() = %d\n", err);
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 1e750e4..c49a2aa 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -294,6 +294,9 @@ static int nfs3_do_create(struct inode *dir, struct dentry *dentry, struct nfs3_
static void nfs3_free_createdata(struct nfs3_createdata *data)
{
+
+ nfs_fattr_fini(data->res.fattr);
+ nfs_fattr_fini(data->res.dir_attr);
kfree(data);
}
@@ -420,6 +423,7 @@ nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir)
return 0;
res = task->tk_msg.rpc_resp;
nfs_post_op_update_inode(dir, &res->dir_attr);
+ nfs_fattr_fini(&res->dir_attr);
return 1;
}
@@ -618,6 +622,9 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
dprintk("NFS call readdir%s %d\n",
plus? "plus" : "", (unsigned int) cookie);
+
+ memset(&dir_attr, 0, sizeof(struct nfs_fattr));
+
nfs_fattr_init(&dir_attr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index c910413..c4a4271 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -243,6 +243,8 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
p->o_res.seqid = p->o_arg.seqid;
p->c_res.seqid = p->c_arg.seqid;
p->o_res.server = p->o_arg.server;
+ memset(&p->f_attr, 0, sizeof(struct nfs_fattr));
+ memset(&p->dir_attr, 0, sizeof(struct nfs_fattr));
nfs_fattr_init(&p->f_attr);
nfs_fattr_init(&p->dir_attr);
}
@@ -288,6 +290,13 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
p->c_arg.seqid = p->o_arg.seqid;
nfs4_init_opendata_res(p);
kref_init(&p->kref);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL) {
+ nfs_fattr_alloc(&p->f_attr, GFP_KERNEL);
+ nfs_fattr_alloc(&p->dir_attr, GFP_KERNEL);
+ }
+#endif
+
return p;
err_free:
kfree(p);
@@ -304,6 +313,8 @@ static void nfs4_opendata_free(struct kref *kref)
nfs_free_seqid(p->o_arg.seqid);
if (p->state != NULL)
nfs4_put_open_state(p->state);
+ nfs_fattr_fini(&p->f_attr);
+ nfs_fattr_fini(&p->dir_attr);
nfs4_put_state_owner(p->owner);
dput(p->dir);
path_put(&p->path);
@@ -1210,6 +1221,7 @@ static void nfs4_free_closedata(void *data)
nfs_free_seqid(calldata->arg.seqid);
nfs4_put_state_owner(sp);
path_put(&calldata->path);
+ nfs_fattr_fini(&calldata->fattr);
kfree(calldata);
}
@@ -1317,7 +1329,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
};
int status = -ENOMEM;
- calldata = kmalloc(sizeof(*calldata), GFP_KERNEL);
+ calldata = kzalloc(sizeof(*calldata), GFP_KERNEL);
if (calldata == NULL)
goto out;
calldata->inode = state->inode;
@@ -1335,6 +1347,10 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
calldata->path.mnt = mntget(path->mnt);
calldata->path.dentry = dget(path->dentry);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL)
+ nfs_fattr_alloc(&calldata->fattr, GFP_KERNEL);
+#endif
msg.rpc_argp = &calldata->arg,
msg.rpc_resp = &calldata->res,
task_setup_data.callback_data = calldata;
@@ -1347,6 +1363,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
rpc_put_task(task);
return status;
out_free_calldata:
+ nfs_fattr_fini(&calldata->fattr);
kfree(calldata);
out:
nfs4_put_open_state(state);
@@ -1762,6 +1779,8 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
int mode = entry->mask;
int status;
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+
/*
* Determine which access bits we want to ask for...
*/
@@ -1778,6 +1797,10 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
if (mode & MAY_EXEC)
args.access |= NFS4_ACCESS_EXECUTE;
}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL)
+ nfs_fattr_alloc(&fattr, GFP_KERNEL);
+#endif
nfs_fattr_init(&fattr);
status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
if (!status) {
@@ -1790,6 +1813,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
entry->mask |= MAY_EXEC;
nfs_refresh_inode(inode, &fattr);
}
+ nfs_fattr_fini(&fattr);
return status;
}
@@ -1902,10 +1926,16 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
if (flags & O_EXCL) {
struct nfs_fattr fattr;
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(state->inode, NFS_CAP_SECURITY_LABEL))
+ nfs_fattr_alloc(&fattr, GFP_KERNEL);
+#endif
status = nfs4_do_setattr(state->inode, cred, &fattr, sattr, state);
if (status == 0)
nfs_setattr_update_inode(state->inode, sattr);
nfs_post_op_update_inode(state->inode, &fattr);
+ nfs_fattr_fini(&fattr);
}
if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
status = nfs4_intent_set_file(nd, &path, state);
@@ -1936,12 +1966,18 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
};
int status;
+ memset(&res.dir_attr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL)
+ nfs_fattr_alloc(&res.dir_attr, GFP_KERNEL);
+#endif
nfs_fattr_init(&res.dir_attr);
status = rpc_call_sync(server->client, &msg, 0);
if (status == 0) {
update_changeattr(dir, &res.cinfo);
nfs_post_op_update_inode(dir, &res.dir_attr);
}
+ nfs_fattr_fini(&res.dir_attr);
return status;
}
@@ -1966,6 +2002,13 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
args->bitmask = server->attr_bitmask;
res->server = server;
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
+
+ memset(&res->dir_attr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL)
+ nfs_fattr_alloc(&res->dir_attr, GFP_KERNEL);
+#endif
+ nfs_fattr_init(&res->dir_attr);
}
static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
@@ -1976,6 +2019,7 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
return 0;
update_changeattr(dir, &res->cinfo);
nfs_post_op_update_inode(dir, &res->dir_attr);
+ nfs_fattr_fini(&res->dir_attr);
return 1;
}
@@ -2003,6 +2047,15 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
};
int status;
+ memset(&old_fattr, 0, sizeof(struct nfs_fattr));
+ memset(&new_fattr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL) {
+ nfs_fattr_alloc(&old_fattr, GFP_KERNEL);
+ nfs_fattr_alloc(&new_fattr, GFP_KERNEL);
+ }
+#endif
+
nfs_fattr_init(res.old_fattr);
nfs_fattr_init(res.new_fattr);
status = rpc_call_sync(server->client, &msg, 0);
@@ -2013,6 +2066,8 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
update_changeattr(new_dir, &res.new_cinfo);
nfs_post_op_update_inode(new_dir, res.new_fattr);
}
+ nfs_fattr_fini(&old_fattr);
+ nfs_fattr_fini(&new_fattr);
return status;
}
@@ -2052,6 +2107,15 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
};
int status;
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+ memset(&dir_attr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL) {
+ nfs_fattr_alloc(&fattr, GFP_KERNEL);
+ nfs_fattr_alloc(&dir_attr, GFP_KERNEL);
+ }
+#endif
+
nfs_fattr_init(res.fattr);
nfs_fattr_init(res.dir_attr);
status = rpc_call_sync(server->client, &msg, 0);
@@ -2061,6 +2125,8 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *
nfs_post_op_update_inode(inode, res.fattr);
}
+ nfs_fattr_fini(&fattr);
+ nfs_fattr_fini(&dir_attr);
return status;
}
@@ -2107,6 +2173,14 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
data->res.fh = &data->fh;
data->res.fattr = &data->fattr;
data->res.dir_fattr = &data->dir_fattr;
+ memset(&data->fattr, 0, sizeof(struct nfs_fattr));
+ memset(&data->dir_fattr, 0, sizeof(struct nfs_fattr));
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL) {
+ nfs_fattr_alloc(&data->fattr, GFP_KERNEL);
+ nfs_fattr_alloc(&data->dir_fattr, GFP_KERNEL);
+ }
+#endif
nfs_fattr_init(data->res.fattr);
nfs_fattr_init(data->res.dir_fattr);
}
@@ -2126,6 +2200,8 @@ static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_
static void nfs4_free_createdata(struct nfs4_createdata *data)
{
+ nfs_fattr_fini(&data->fattr);
+ nfs_fattr_fini(&data->dir_fattr);
kfree(data);
}
@@ -2958,6 +3034,9 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
static void nfs4_delegreturn_release(void *calldata)
{
+ struct nfs4_delegreturndata *data = calldata;
+
+ nfs_fattr_fini(data->res.fattr);
kfree(calldata);
}
@@ -2983,7 +3062,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
};
int status = 0;
- data = kmalloc(sizeof(*data), GFP_KERNEL);
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
data->args.fhandle = &data->fh;
@@ -2997,6 +3076,11 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
data->timestamp = jiffies;
data->rpc_status = 0;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->caps & NFS_CAP_SECURITY_LABEL)
+ nfs_fattr_alloc(&data->fattr, GFP_KERNEL);
+#endif
+
task_setup_data.callback_data = data;
msg.rpc_argp = &data->args,
msg.rpc_resp = &data->res,
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 4dbb84d..3ff1bdf 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -210,12 +210,14 @@ nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
};
int status;
- nfs_fattr_init(&fattr);
dprintk("NFS call create %s\n", dentry->d_name.name);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+ nfs_fattr_init(&fattr);
nfs_mark_for_revalidate(dir);
if (status == 0)
status = nfs_instantiate(dentry, &fhandle, &fattr);
+ nfs_fattr_fini(&fattr);
dprintk("NFS reply create: %d\n", status);
return status;
}
@@ -257,6 +259,7 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
sattr->ia_size = new_encode_dev(rdev);/* get out your barf bag */
}
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
nfs_fattr_init(&fattr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_mark_for_revalidate(dir);
@@ -268,6 +271,7 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
}
if (status == 0)
status = nfs_instantiate(dentry, &fhandle, &fattr);
+ nfs_fattr_fini(&fattr);
dprintk("NFS reply mknod: %d\n", status);
return status;
}
@@ -380,6 +384,8 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
dprintk("NFS call symlink %s\n", dentry->d_name.name);
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_mark_for_revalidate(dir);
@@ -394,6 +400,7 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
status = nfs_instantiate(dentry, &fhandle, &fattr);
}
+ nfs_fattr_fini(&fattr);
dprintk("NFS reply symlink: %d\n", status);
return status;
}
@@ -421,11 +428,14 @@ nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
int status;
dprintk("NFS call mkdir %s\n", dentry->d_name.name);
+
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
nfs_fattr_init(&fattr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_mark_for_revalidate(dir);
if (status == 0)
status = nfs_instantiate(dentry, &fhandle, &fattr);
+ nfs_fattr_fini(&fattr);
dprintk("NFS reply mkdir: %d\n", status);
return status;
}
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 256ce27..81cf6c5 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -377,6 +377,8 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
};
int error;
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+
error = server->nfs_client->rpc_ops->statfs(server, fh, &res);
if (error < 0)
goto out_err;
@@ -408,10 +410,12 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
buf->f_namelen = server->namelen;
+ nfs_fattr_fini(&fattr);
return 0;
out_err:
dprintk("%s: statfs error = %d\n", __func__, -error);
+ nfs_fattr_fini(&fattr);
return error;
}
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 78a5922..192c056 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -355,6 +355,52 @@ static inline void nfs_fattr_init(struct nfs_fattr *fattr)
fattr->time_start = jiffies;
}
+#ifdef CONFIG_SECURITY
+void security_release_secctx(char *secdata, u32 seclen);
+
+static inline void nfs_fattr_alloc(struct nfs_fattr *fattr, gfp_t flags)
+{
+ fattr->label = kzalloc(NFS4_MAXLABELLEN, flags);
+ if (fattr->label == NULL)
+ panic("Can't allocate security label.");
+ fattr->label_len = NFS4_MAXLABELLEN;
+}
+
+#define nfs_fattr_fini(fattr) _nfs_fattr_fini(fattr, __FILE__, __LINE__, __func__)
+static inline void _nfs_fattr_fini(struct nfs_fattr *fattr,
+ const char *file, int line, const char *func)
+{
+ if ((fattr)->label == NULL) {
+ if (fattr->label_len != 0) {
+ printk(KERN_WARNING
+ "%s:%d %s() nfs_fattr label available (%d)\n",
+ file, line, func,
+ fattr->label_len);
+ }
+ } else {
+ if (fattr->label_len == NFS4_MAXLABELLEN)
+ printk(KERN_WARNING
+ "%s:%d %s() nfs_fattr label unused\n",
+ file, line, func);
+ else
+ if (fattr->label_len != (strlen(fattr->label) + 1))
+ printk(KERN_WARNING
+ "%s:%d %s() nfs_fattr label size mismatch (label_len %d, strlen %d)\n",
+ file, line, func,
+ fattr->label_len, strlen(fattr->label) + 1);
+
+
+ security_release_secctx(fattr->label, fattr->label_len);
+ fattr->label = NULL;
+ fattr->label_len = 0;
+ }
+}
+#else
+#define nfs_fattr_alloc(fattr, flags)
+#define nfs_fattr_fini(fattr)
+#endif
+
+
/*
* linux/fs/nfs/file.c
*/
--
1.5.5.1
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 12/14] NFS: Client implementation of Labeled-NFS
[not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
` (5 preceding siblings ...)
2008-09-29 17:06 ` [PATCH 09/14] NFS: Introduce lifecycle management for label attribute David P. Quigley
@ 2008-09-29 17:06 ` David P. Quigley
2008-09-29 17:06 ` [PATCH 13/14] NFS: Extend NFS xattr handlers to accept the security namespace David P. Quigley
2008-09-29 17:06 ` [PATCH 14/14] NFSD: Server implementation of MAC Labeling David P. Quigley
8 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
trond.myklebust-41N18TsMXrtuMpJDpNschA,
bfields-uC3wQj2KruNg9hUCZPvPmw
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
selinux-+05T5uksL2qpZYMLLGbcSA,
labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
Matthew N. Dodd
This patch implements the client transport and handling support for labeled
NFS. The patch adds two functions to encode and decode the security label
recommended attribute which makes use of the LSM hooks added earlier. It also
adds code to grab the label from the file attribute structures and encode the
label to be sent back to the server.
Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
fs/nfs/inode.c | 45 ++++++-
fs/nfs/nfs4proc.c | 303 ++++++++++++++++++++++++++++++++++++++++++----
fs/nfs/nfs4xdr.c | 55 ++++++++-
fs/nfs/super.c | 16 +++-
include/linux/nfs_fs.h | 2 +
security/selinux/hooks.c | 5 +
6 files changed, 391 insertions(+), 35 deletions(-)
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 40d7142..dde0667 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -143,10 +143,13 @@ static void nfs_zap_caches_locked(struct inode *inode)
nfsi->attrtimeo_timestamp = jiffies;
memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
+ nfsi->cache_validity |= NFS_INO_INVALID_ATTR| \
+ NFS_INO_INVALID_LABEL| \
+ NFS_INO_INVALID_ACCESS| \
+ NFS_INO_INVALID_ACL| \
+ NFS_INO_REVAL_PAGECACHE;
if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))
- nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
- else
- nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE;
+ nfsi->cache_validity |= NFS_INO_INVALID_DATA;
}
void nfs_zap_caches(struct inode *inode)
@@ -235,6 +238,29 @@ nfs_init_locked(struct inode *inode, void *opaque)
/* Don't use READDIRPLUS on directories that we believe are too large */
#define NFS_LIMIT_READDIRPLUS (8*PAGE_SIZE)
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr)
+{
+ int error;
+
+/* BUG_ON(!mutex_is_locked(&inode->i_mutex)); */
+
+ if ((fattr->valid & NFS_ATTR_FATTR_V4) &&
+ (fattr->bitmap[1] & FATTR4_WORD1_SECURITY_LABEL) &&
+ (fattr->label != NULL) &&
+ (inode->i_security != NULL)) {
+ error = security_inode_notifysecctx(inode, fattr->label,
+ fattr->label_len);
+ /* XXX: debug output */
+ if (error)
+ printk(KERN_ERR "%s() %s %d "
+ "security_inode_notifysecctx() %d\n",
+ __func__,
+ (char *)fattr->label, fattr->label_len, error);
+ }
+}
+#endif
+
/*
* This is our front-end to iget that looks up inodes by file handle
* instead of inode number.
@@ -316,6 +342,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
inode->i_nlink = fattr->nlink;
inode->i_uid = fattr->uid;
inode->i_gid = fattr->gid;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ nfs_setsecurity(inode, fattr);
+#endif
+
if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
/*
* report the blocks in 512byte units
@@ -790,7 +821,7 @@ int nfs_attribute_timeout(struct inode *inode)
*/
int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
{
- if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATTR)
+ if (!(NFS_I(inode)->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL))
&& !nfs_attribute_timeout(inode))
return NFS_STALE(inode) ? -ESTALE : 0;
return __nfs_revalidate_inode(server, inode);
@@ -1146,6 +1177,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
inode->i_nlink = fattr->nlink;
inode->i_uid = fattr->uid;
inode->i_gid = fattr->gid;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ nfs_setsecurity(inode, fattr);
+#endif
if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
/*
@@ -1157,7 +1191,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
}
/* Update attrtimeo value if we're out of the unstable period */
- if (invalid & NFS_INO_INVALID_ATTR) {
+ if (invalid & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) {
nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
nfsi->attrtimeo_timestamp = now;
@@ -1175,6 +1209,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
nfsi->last_updated = nfsi->read_cache_jiffies;
}
invalid &= ~NFS_INO_INVALID_ATTR;
+ invalid &= ~NFS_INO_INVALID_LABEL;
/* Don't invalidate the data if we were to blame */
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
|| S_ISLNK(inode->i_mode)))
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 92522cc..622bf71 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -48,6 +48,7 @@
#include <linux/smp_lock.h>
#include <linux/namei.h>
#include <linux/mount.h>
+#include <linux/nfs4_mount.h>
#include "nfs4_fs.h"
#include "delegation.h"
@@ -97,6 +98,9 @@ const u32 nfs4_fattr_bitmap[2] = {
| FATTR4_WORD1_TIME_ACCESS
| FATTR4_WORD1_TIME_METADATA
| FATTR4_WORD1_TIME_MODIFY
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ | FATTR4_WORD1_SECURITY_LABEL
+#endif
};
const u32 nfs4_statfs_bitmap[2] = {
@@ -251,7 +255,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
struct nfs4_state_owner *sp, int flags,
- const struct iattr *attrs)
+ const struct iattr *attrs, struct nfs4_label *label)
{
struct dentry *parent = dget_parent(path->dentry);
struct inode *dir = parent->d_inode;
@@ -277,6 +281,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
p->o_arg.server = server;
p->o_arg.bitmask = server->attr_bitmask;
p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
+ p->o_arg.label = label;
if (flags & O_EXCL) {
u32 *s = (u32 *) p->o_arg.u.verifier.data;
s[0] = jiffies;
@@ -563,7 +568,7 @@ static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context
{
struct nfs4_opendata *opendata;
- opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL);
+ opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL, NULL);
if (opendata == NULL)
return ERR_PTR(-ENOMEM);
opendata->state = state;
@@ -1042,7 +1047,7 @@ static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct
/*
* Returns a referenced nfs4_state
*/
-static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res)
+static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct nfs4_label *label, struct rpc_cred *cred, struct nfs4_state **res)
{
struct nfs4_state_owner *sp;
struct nfs4_state *state = NULL;
@@ -1064,7 +1069,7 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct
nfs4_return_incompatible_delegation(path->dentry->d_inode, flags & (FMODE_READ|FMODE_WRITE));
down_read(&clp->cl_sem);
status = -ENOMEM;
- opendata = nfs4_opendata_alloc(path, sp, flags, sattr);
+ opendata = nfs4_opendata_alloc(path, sp, flags, sattr, label);
if (opendata == NULL)
goto err_release_rwsem;
@@ -1099,14 +1104,14 @@ out_err:
}
-static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred)
+static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct nfs4_label *label, struct rpc_cred *cred)
{
struct nfs4_exception exception = { };
struct nfs4_state *res;
int status;
do {
- status = _nfs4_do_open(dir, path, flags, sattr, cred, &res);
+ status = _nfs4_do_open(dir, path, flags, sattr, label, cred, &res);
if (status == 0)
break;
/* NOTE: BAD_SEQID means the server and client disagree about the
@@ -1150,14 +1155,15 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int
static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
struct nfs_fattr *fattr, struct iattr *sattr,
- struct nfs4_state *state)
+ struct nfs4_label *label, struct nfs4_state *state)
{
struct nfs_server *server = NFS_SERVER(inode);
struct nfs_setattrargs arg = {
.fh = NFS_FH(inode),
.iap = sattr,
.server = server,
- .bitmask = server->attr_bitmask,
+ .bitmask = server->attr_bitmask,
+ .label = label,
};
struct nfs_setattrres res = {
.fattr = fattr,
@@ -1189,14 +1195,14 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
struct nfs_fattr *fattr, struct iattr *sattr,
- struct nfs4_state *state)
+ struct nfs4_label *label, struct nfs4_state *state)
{
struct nfs_server *server = NFS_SERVER(inode);
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(server,
- _nfs4_do_setattr(inode, cred, fattr, sattr, state),
+ _nfs4_do_setattr(inode, cred, fattr, sattr, label, state),
&exception);
} while (exception.retry);
return err;
@@ -1400,6 +1406,7 @@ out_close:
struct dentry *
nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{
+ struct nfs4_label l, *label = NULL;
struct path path = {
.mnt = nd->path.mnt,
.dentry = dentry,
@@ -1413,11 +1420,21 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
cred = rpc_lookup_cred();
if (IS_ERR(cred))
return (struct dentry *)cred;
+ memset(&attr, 0, sizeof(struct iattr));
if (nd->flags & LOOKUP_CREATE) {
attr.ia_mode = nd->intent.open.create_mode;
attr.ia_valid = ATTR_MODE;
if (!IS_POSIXACL(dir))
attr.ia_mode &= ~current->fs->umask;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+ int error;
+ error = security_dentry_init_security(dentry,
+ attr.ia_mode, &l.label, &l.len);
+ if (error == 0)
+ label = &l;
+ }
+#endif
} else {
attr.ia_valid = 0;
BUG_ON(nd->intent.open.flags & O_CREAT);
@@ -1426,8 +1443,12 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
parent = dentry->d_parent;
/* Protect against concurrent sillydeletes */
nfs_block_sillyrename(parent);
- state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred);
+ state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, label, cred);
put_rpccred(cred);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (label != NULL)
+ security_release_secctx(l.label, l.len);
+#endif
if (IS_ERR(state)) {
if (PTR_ERR(state) == -ENOENT) {
d_add(dentry, NULL);
@@ -1458,7 +1479,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
cred = rpc_lookup_cred();
if (IS_ERR(cred))
return PTR_ERR(cred);
- state = nfs4_do_open(dir, &path, openflags, NULL, cred);
+ state = nfs4_do_open(dir, &path, openflags, NULL, NULL, cred);
put_rpccred(cred);
if (IS_ERR(state)) {
switch (PTR_ERR(state)) {
@@ -1500,6 +1521,13 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask));
if (res.attr_bitmask[0] & FATTR4_WORD0_ACL)
server->caps |= NFS_CAP_ACLS;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (server->flags & NFS4_MOUNT_SECURITY_LABEL &&
+ res.attr_bitmask[1] & FATTR4_WORD1_SECURITY_LABEL) {
+ server->caps |= NFS_CAP_SECURITY_LABEL;
+ } else
+#endif
+ server->attr_bitmask[1] &= ~FATTR4_WORD1_SECURITY_LABEL;
if (res.has_links != 0)
server->caps |= NFS_CAP_HARDLINKS;
if (res.has_symlinks != 0)
@@ -1680,9 +1708,11 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
state = ctx->state;
}
- status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
- if (status == 0)
+ status = nfs4_do_setattr(inode, cred, fattr, sattr, NULL, state);
+ if (status == 0) {
nfs_setattr_update_inode(inode, sattr);
+ nfs_setsecurity(inode, fattr);
+ }
return status;
}
@@ -1903,6 +1933,7 @@ static int
nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
int flags, struct nameidata *nd)
{
+ struct nfs4_label l, *label = NULL;
struct path path = {
.mnt = nd->path.mnt,
.dentry = dentry,
@@ -1916,7 +1947,18 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
status = PTR_ERR(cred);
goto out;
}
- state = nfs4_do_open(dir, &path, flags, sattr, cred);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (((nd->flags & LOOKUP_CREATE) != 0) &&
+ nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+ status = security_dentry_init_security(dentry,
+ sattr->ia_mode, &l.label, &l.len);
+ /* XXX: should this be more fatal? */
+ if (status == 0)
+ label = &l;
+ }
+#endif
+
+ state = nfs4_do_open(dir, &path, flags, sattr, label, cred);
d_drop(dentry);
if (IS_ERR(state)) {
status = PTR_ERR(state);
@@ -1931,10 +1973,12 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
if (nfs_server_capable(state->inode, NFS_CAP_SECURITY_LABEL))
nfs_fattr_alloc(&fattr, GFP_KERNEL);
#endif
- status = nfs4_do_setattr(state->inode, cred, &fattr, sattr, state);
- if (status == 0)
+ status = nfs4_do_setattr(state->inode, cred, &fattr, sattr, label, state);
+ if (status == 0) {
nfs_setattr_update_inode(state->inode, sattr);
- nfs_post_op_update_inode(state->inode, &fattr);
+ nfs_post_op_update_inode(state->inode, &fattr);
+ nfs_setsecurity(state->inode, &fattr);
+ }
nfs_fattr_fini(&fattr);
}
if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
@@ -1944,6 +1988,10 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
out_putcred:
put_rpccred(cred);
out:
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (label != NULL)
+ security_release_secctx(label->label, label->len);
+#endif
return status;
}
@@ -2206,7 +2254,8 @@ static void nfs4_free_createdata(struct nfs4_createdata *data)
}
static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
- struct page *page, unsigned int len, struct iattr *sattr)
+ struct page *page, unsigned int len, struct iattr *sattr,
+ struct nfs4_label *label)
{
struct nfs4_createdata *data;
int status = -ENAMETOOLONG;
@@ -2222,6 +2271,7 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK];
data->arg.u.symlink.pages = &page;
data->arg.u.symlink.len = len;
+ data->arg.label = label;
status = nfs4_do_create(dir, dentry, data);
@@ -2234,18 +2284,33 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
struct page *page, unsigned int len, struct iattr *sattr)
{
struct nfs4_exception exception = { };
+ struct nfs4_label l, *label = NULL;
int err;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+ err = security_dentry_init_security(dentry,
+ sattr->ia_mode, &l.label, &l.len);
+ if (err == 0)
+ label = &l;
+ }
+#endif
+
do {
err = nfs4_handle_exception(NFS_SERVER(dir),
_nfs4_proc_symlink(dir, dentry, page,
- len, sattr),
+ len, sattr, label),
&exception);
} while (exception.retry);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (label != NULL)
+ security_release_secctx(l.label, l.len);
+#endif
return err;
}
static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
- struct iattr *sattr)
+ struct iattr *sattr, struct nfs4_label *label)
{
struct nfs4_createdata *data;
int status = -ENOMEM;
@@ -2254,6 +2319,7 @@ static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
if (data == NULL)
goto out;
+ data->arg.label = label;
status = nfs4_do_create(dir, dentry, data);
nfs4_free_createdata(data);
@@ -2265,12 +2331,27 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
struct iattr *sattr)
{
struct nfs4_exception exception = { };
+ struct nfs4_label l, *label = NULL;
int err;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+ err = security_dentry_init_security(dentry,
+ sattr->ia_mode, &l.label, &l.len);
+ if (err == 0)
+ label = &l;
+ }
+#endif
+
do {
err = nfs4_handle_exception(NFS_SERVER(dir),
- _nfs4_proc_mkdir(dir, dentry, sattr),
+ _nfs4_proc_mkdir(dir, dentry, sattr, label),
&exception);
} while (exception.retry);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (label != NULL)
+ security_release_secctx(l.label, l.len);
+#endif
return err;
}
@@ -2325,7 +2406,7 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
}
static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
- struct iattr *sattr, dev_t rdev)
+ struct iattr *sattr, struct nfs4_label *label, dev_t rdev)
{
struct nfs4_createdata *data;
int mode = sattr->ia_mode;
@@ -2350,7 +2431,7 @@ static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
data->arg.u.device.specdata1 = MAJOR(rdev);
data->arg.u.device.specdata2 = MINOR(rdev);
}
-
+ data->arg.label = label;
status = nfs4_do_create(dir, dentry, data);
nfs4_free_createdata(data);
@@ -2362,12 +2443,27 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
struct iattr *sattr, dev_t rdev)
{
struct nfs4_exception exception = { };
+ struct nfs4_label l, *label = NULL;
int err;
+
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
+ err = security_dentry_init_security(dentry,
+ sattr->ia_mode, &l.label, &l.len);
+ if (err == 0)
+ label = &l;
+ }
+#endif
+
do {
err = nfs4_handle_exception(NFS_SERVER(dir),
- _nfs4_proc_mknod(dir, dentry, sattr, rdev),
+ _nfs4_proc_mknod(dir, dentry, sattr, label, rdev),
&exception);
} while (exception.retry);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (label != NULL)
+ security_release_secctx(l.label, l.len);
+#endif
return err;
}
@@ -2815,6 +2911,163 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
return err;
}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+static int _nfs4_get_security_label(struct inode *inode, void *buf, size_t buflen)
+{
+ struct nfs_server *server = NFS_SERVER(inode);
+ struct nfs_fattr fattr;
+ u32 bitmask[2] = { 0, FATTR4_WORD1_SECURITY_LABEL };
+ struct nfs4_getattr_arg args = {
+ .fh = NFS_FH(inode),
+ .bitmask = bitmask,
+ };
+ struct nfs4_getattr_res res = {
+ .fattr = &fattr,
+ .server = server,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
+ .rpc_argp = &args,
+ .rpc_resp = &res,
+ };
+ int ret;
+
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+ nfs_fattr_alloc(&fattr, GFP_KERNEL);
+ nfs_fattr_init(&fattr);
+
+ ret = rpc_call_sync(server->client, &msg, 0);
+ if (ret)
+ goto out;
+ if (!(fattr.bitmap[1] & FATTR4_WORD1_SECURITY_LABEL))
+ return -ENOENT;
+ if (buflen < fattr.label_len) {
+ ret = -ERANGE;
+ goto out;
+ }
+ memcpy(buf, fattr.label, fattr.label_len);
+out:
+ nfs_fattr_fini(&fattr);
+ return ret;
+}
+
+static int nfs4_get_security_label(struct inode *inode, void *buf, size_t buflen)
+{
+ struct nfs4_exception exception = { };
+ int err;
+
+ if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
+ return -EOPNOTSUPP;
+
+ do {
+ err = nfs4_handle_exception(NFS_SERVER(inode),
+ _nfs4_get_security_label(inode, buf, buflen),
+ &exception);
+ } while (exception.retry);
+ return err;
+}
+
+static int _nfs4_do_set_security_label(struct inode *inode,
+ struct nfs4_label *label,
+ struct nfs_fattr *fattr,
+ struct nfs4_state *state)
+{
+
+ struct iattr sattr;
+ struct nfs_server *server = NFS_SERVER(inode);
+ const u32 bitmask[2] = { 0, FATTR4_WORD1_SECURITY_LABEL };
+ struct nfs_setattrargs args = {
+ .fh = NFS_FH(inode),
+ .iap = &sattr,
+ .server = server,
+ .bitmask = bitmask,
+ .label = label,
+ };
+ struct nfs_setattrres res = {
+ .fattr = fattr,
+ .server = server,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
+ .rpc_argp = &args,
+ .rpc_resp = &res,
+ };
+ unsigned long timestamp = jiffies;
+ int status;
+
+ memset(&sattr, 0, sizeof(struct iattr));
+
+ if (nfs4_copy_delegation_stateid(&args.stateid, inode)) {
+ /* Use that stateid */
+ } else if (state != NULL) {
+ msg.rpc_cred = state->owner->so_cred;
+ nfs4_copy_stateid(&args.stateid, state, current->files);
+ } else
+ memcpy(&args.stateid, &zero_stateid, sizeof(args.stateid));
+
+ status = rpc_call_sync(server->client, &msg, 0);
+ if (status == 0 && state != NULL)
+ renew_lease(server, timestamp);
+ return status;
+}
+
+static int nfs4_do_set_security_label(struct inode *inode,
+ struct nfs4_label *label,
+ struct nfs_fattr *fattr,
+ struct nfs4_state *state)
+{
+ struct nfs4_exception exception = { };
+ int err;
+
+ do {
+ err = nfs4_handle_exception(NFS_SERVER(inode),
+ _nfs4_do_set_security_label(inode, label, fattr, state),
+ &exception);
+ } while (exception.retry);
+ return err;
+}
+
+static int
+nfs4_set_security_label(struct dentry *dentry, const void *buf, size_t buflen)
+{
+ struct nfs4_label label;
+ struct nfs_fattr fattr;
+ struct rpc_cred *cred;
+ struct nfs_open_context *ctx;
+ struct nfs4_state *state = NULL;
+ struct inode *inode = dentry->d_inode;
+ int status;
+
+ if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
+ return -EOPNOTSUPP;
+
+ memset(&fattr, 0, sizeof(struct nfs_fattr));
+ nfs_fattr_alloc(&fattr, GFP_KERNEL);
+ nfs_fattr_init(&fattr);
+
+ label.label = (char *)buf;
+ label.len = buflen;
+
+ cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+ if (IS_ERR(cred))
+ return PTR_ERR(cred);
+
+ /* Search for an existing open(O_WRITE) file */
+ ctx = nfs_find_open_context(inode, cred, FMODE_WRITE);
+ if (ctx != NULL)
+ state = ctx->state;
+
+ status = nfs4_do_set_security_label(inode, &label, &fattr, state);
+ if (status == 0)
+ nfs_setsecurity(inode, &fattr);
+ if (ctx != NULL)
+ put_nfs_open_context(ctx);
+ put_rpccred(cred);
+ nfs_fattr_fini(&fattr);
+ return status;
+}
+#endif /* CONFIG_NFS_V4_SECURITY_LABEL */
+
static int
nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server)
{
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index b916297..3e53fb7 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -601,7 +601,7 @@ static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *ve
xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE);
}
-static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
+static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs4_label *label, const struct nfs_server *server)
{
char owner_name[IDMAP_NAMESZ];
char owner_group[IDMAP_NAMESZ];
@@ -651,6 +651,10 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
}
len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (label != NULL)
+ len += 4 + (XDR_QUADLEN(label->len) << 2);
+#endif
if (iap->ia_valid & ATTR_ATIME_SET)
len += 16;
else if (iap->ia_valid & ATTR_ATIME)
@@ -709,6 +713,13 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
WRITE32(NFS4_SET_TO_SERVER_TIME);
}
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (label != NULL) {
+ bmval1 |= FATTR4_WORD1_SECURITY_LABEL;
+ WRITE32(label->len);
+ WRITEMEM(label->label, label->len);
+ }
+#endif
/*
* Now we backfill the bitmap and the attribute buffer length.
@@ -792,7 +803,7 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c
WRITE32(create->name->len);
WRITEMEM(create->name->name, create->name->len);
- return encode_attrs(xdr, create->attrs, create->server);
+ return encode_attrs(xdr, create->attrs, create->label, create->server);
}
static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
@@ -1000,7 +1011,7 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
switch(arg->open_flags & O_EXCL) {
case 0:
WRITE32(NFS4_CREATE_UNCHECKED);
- encode_attrs(xdr, arg->u.attrs, arg->server);
+ encode_attrs(xdr, arg->u.attrs, arg->label, arg->server);
break;
default:
WRITE32(NFS4_CREATE_EXCLUSIVE);
@@ -1301,7 +1312,7 @@ static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *
WRITE32(OP_SETATTR);
WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE);
- if ((status = encode_attrs(xdr, arg->iap, server)))
+ if ((status = encode_attrs(xdr, arg->iap, arg->label, server)))
return status;
return 0;
@@ -2954,6 +2965,39 @@ static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, str
return status;
}
+static int decode_attr_security_label(struct xdr_stream *xdr, uint32_t *bitmap, char **ctx, u32 *ctxlen)
+{
+ __u32 len;
+ __be32 *p;
+ int rc = 0;
+
+ if (unlikely(bitmap[1] & (FATTR4_WORD1_SECURITY_LABEL - 1U)))
+ return -EIO;
+ if (likely(bitmap[1] & FATTR4_WORD1_SECURITY_LABEL)) {
+ READ_BUF(4);
+ READ32(len);
+ READ_BUF(len);
+ if (len < XDR_MAX_NETOBJ && len < NFS4_MAX_CONTEXT_LEN) {
+ if (*ctx != NULL) {
+ if (*ctxlen < len) {
+ printk(KERN_ERR
+ "%s(): ctxlen %d < len %d\n",
+ __func__, *ctxlen, len);
+ /* rc = -ENOMEM; */
+ *ctx = NULL; /* leak */
+ } else {
+ memcpy(*ctx, p, len);
+ }
+ }
+ *ctxlen = len;
+ } else
+ printk(KERN_WARNING "%s: label too long (%u)!\n",
+ __FUNCTION__, len);
+ bitmap[1] &= ~FATTR4_WORD1_SECURITY_LABEL;
+ }
+ return rc;
+}
+
static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
{
unsigned int attrwords = XDR_QUADLEN(attrlen);
@@ -3188,6 +3232,9 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
goto xdr_error;
if ((status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid)) != 0)
goto xdr_error;
+ if ((status = decode_attr_security_label(xdr, bitmap,
+ &fattr->label, &fattr->label_len)) != 0)
+ goto xdr_error;
if (fattr->fileid == 0 && fileid != 0)
fattr->fileid = fileid;
if ((status = verify_attr_len(xdr, savep, attrlen)) == 0)
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 81cf6c5..bca62c1 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -554,8 +554,13 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
nfs_show_mountd_options(m, nfss, showdefaults);
#ifdef CONFIG_NFS_V4
- if (clp->rpc_ops->version == 4)
+ if (clp->rpc_ops->version == 4) {
seq_printf(m, ",clientaddr=%s", clp->cl_ipaddr);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfss->caps & NFS_CAP_SECURITY_LABEL)
+ seq_printf(m, ",security_label");
+#endif
+ }
#endif
}
@@ -612,6 +617,10 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfss->caps & NFS_CAP_SECURITY_LABEL)
+ seq_printf(m, ",security_label");
+#endif
}
#endif
@@ -2367,6 +2376,11 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
goto error_splat_super;
}
+#ifdef CONFIG_SECURITY_SELINUX
+ if (server->caps & NFS_CAP_SECURITY_LABEL)
+ security_sb_parse_opts_str("native_labels", &data->lsm_opts);
+#endif
+
error = security_sb_set_mnt_opts(s, &data->lsm_opts);
if (error)
goto error_splat_root;
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 192c056..7fdb309 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -196,6 +196,7 @@ struct nfs_inode {
#define NFS_INO_INVALID_ACL 0x0010 /* cached acls are invalid */
#define NFS_INO_REVAL_PAGECACHE 0x0020 /* must revalidate pagecache */
#define NFS_INO_REVAL_FORCED 0x0040 /* force revalidation ignoring a delegation */
+#define NFS_INO_INVALID_LABEL 0x0080 /* cached label is invalid */
/*
* Bit offsets in flags field
@@ -341,6 +342,7 @@ extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *map
extern int nfs_revalidate_mapping_nolock(struct inode *inode, struct address_space *mapping);
extern int nfs_setattr(struct dentry *, struct iattr *);
extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr);
+extern void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr);
extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
extern void put_nfs_open_context(struct nfs_open_context *ctx);
extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 05a10be..f388235 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2851,7 +2851,10 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
return;
}
+ isec->sclass = inode_mode_to_security_class(inode->i_mode);
isec->sid = newsid;
+ isec->initialized = 1;
+
return;
}
@@ -2941,7 +2944,9 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
if (rc)
return rc;
+ isec->sclass = inode_mode_to_security_class(inode->i_mode);
isec->sid = newsid;
+ isec->initialized = 1;
return 0;
}
--
1.5.5.1
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 13/14] NFS: Extend NFS xattr handlers to accept the security namespace
[not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
` (6 preceding siblings ...)
2008-09-29 17:06 ` [PATCH 12/14] NFS: Client implementation of Labeled-NFS David P. Quigley
@ 2008-09-29 17:06 ` David P. Quigley
2008-09-29 17:06 ` [PATCH 14/14] NFSD: Server implementation of MAC Labeling David P. Quigley
8 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
trond.myklebust-41N18TsMXrtuMpJDpNschA,
bfields-uC3wQj2KruNg9hUCZPvPmw
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
selinux-+05T5uksL2qpZYMLLGbcSA,
labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
Matthew N. Dodd
The existing NFSv4 xattr handlers do not accept xattr calls to the security
namespace. This patch extends these handlers to accept xattrs from the security
namespace in addition to the default NFSv4 ACL namespace.
Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
fs/nfs/nfs4proc.c | 52 ++++++++++++++++++++++++++++++++++++++++----------
security/security.c | 1 +
2 files changed, 42 insertions(+), 11 deletions(-)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 622bf71..845e1da 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3934,10 +3934,17 @@ int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf,
{
struct inode *inode = dentry->d_inode;
- if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0)
- return -EOPNOTSUPP;
-
- return nfs4_proc_set_acl(inode, buf, buflen);
+ if (strcmp(key, XATTR_NAME_NFSV4_ACL) == 0) {
+ if (!S_ISREG(inode->i_mode) &&
+ (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
+ return -EPERM;
+ return nfs4_proc_set_acl(inode, buf, buflen);
+ }
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (security_ismaclabel(key))
+ return nfs4_set_security_label(dentry, buf, buflen);
+#endif
+ return -EOPNOTSUPP;
}
/* The getxattr man page suggests returning -ENODATA for unknown attributes,
@@ -3949,22 +3956,45 @@ ssize_t nfs4_getxattr(struct dentry *dentry, const char *key, void *buf,
{
struct inode *inode = dentry->d_inode;
- if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0)
- return -EOPNOTSUPP;
+ if (strcmp(key, XATTR_NAME_NFSV4_ACL) == 0)
+ return nfs4_proc_get_acl(inode, buf, buflen);
- return nfs4_proc_get_acl(inode, buf, buflen);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (security_ismaclabel(key))
+ return nfs4_get_security_label(inode, buf, buflen);
+#endif
+ return -EOPNOTSUPP;
}
ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
{
- size_t len = strlen(XATTR_NAME_NFSV4_ACL) + 1;
+ size_t len = 0, l;
+ char *p;
- if (!nfs4_server_supports_acls(NFS_SERVER(dentry->d_inode)))
+ if (nfs4_server_supports_acls(NFS_SERVER(dentry->d_inode)))
+ len += strlen(XATTR_NAME_NFSV4_ACL) + 1;
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dentry->d_inode, NFS_CAP_SECURITY_LABEL))
+ len += security_inode_listsecurity(dentry->d_inode, NULL, 0);
+#endif
+ if (!len)
return 0;
if (buf && buflen < len)
return -ERANGE;
- if (buf)
- memcpy(buf, XATTR_NAME_NFSV4_ACL, len);
+ if (!buf)
+ return len;
+
+ p = buf;
+ if (nfs4_server_supports_acls(NFS_SERVER(dentry->d_inode))) {
+ l = strlen(XATTR_NAME_NFSV4_ACL) + 1;
+ memcpy(p, XATTR_NAME_NFSV4_ACL, l);
+ p += l;
+ }
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+ if (nfs_server_capable(dentry->d_inode, NFS_CAP_SECURITY_LABEL))
+ p += security_inode_listsecurity(dentry->d_inode, p,
+ buflen - (p - buf));
+#endif
return len;
}
diff --git a/security/security.c b/security/security.c
index 2337d7f..44d6e37 100644
--- a/security/security.c
+++ b/security/security.c
@@ -536,6 +536,7 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer
return 0;
return security_ops->inode_listsecurity(inode, buffer, buffer_size);
}
+EXPORT_SYMBOL(security_inode_listsecurity);
void security_inode_getsecid(const struct inode *inode, u32 *secid)
{
--
1.5.5.1
^ permalink raw reply related [flat|nested] 33+ messages in thread
* [PATCH 14/14] NFSD: Server implementation of MAC Labeling
[not found] ` <1222707986-26606-1-git-send-email-dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
` (7 preceding siblings ...)
2008-09-29 17:06 ` [PATCH 13/14] NFS: Extend NFS xattr handlers to accept the security namespace David P. Quigley
@ 2008-09-29 17:06 ` David P. Quigley
8 siblings, 0 replies; 33+ messages in thread
From: David P. Quigley @ 2008-09-29 17:06 UTC (permalink / raw)
To: hch-wEGCiKHe2LqWVfeAwA7xHQ, viro-RmSDqhL/yNMiFSDQTTA3OLVCufUGDwFn,
casey-iSGtlc1asvQWG2LlvL+J4A, sds-+05T5uksL2qpZYMLLGbcSA,
matthew.dodd-DABiIiYg7OfQT0dZR+AlfA,
trond.myklebust-41N18TsMXrtuMpJDpNschA,
bfields-uC3wQj2KruNg9hUCZPvPmw
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
selinux-+05T5uksL2qpZYMLLGbcSA,
labeled-nfs-6DNke4IJHB0gsBAKwltoeQ, David P. Quigley,
Matthew N. Dodd
This patch adds the ability to encode and decode file labels on the server for
the purpose of sending them to the client and also to process label change
requests from the client.
Signed-off-by: Matthew N. Dodd <Matthew.Dodd-DABiIiYg7OfQT0dZR+AlfA@public.gmane.org>
Signed-off-by: David P. Quigley <dpquigl-+05T5uksL2qpZYMLLGbcSA@public.gmane.org>
---
fs/nfsd/export.c | 3 +
fs/nfsd/nfs4proc.c | 25 +++++++++++-
fs/nfsd/nfs4xdr.c | 101 ++++++++++++++++++++++++++++++++++++++++++---
fs/nfsd/vfs.c | 22 ++++++++++
include/linux/nfsd/nfsd.h | 2 +
5 files changed, 146 insertions(+), 7 deletions(-)
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 9dc036f..2523420 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1436,6 +1436,9 @@ static struct flags {
{ NFSEXP_ALLSQUASH, {"all_squash", ""}},
{ NFSEXP_ASYNC, {"async", "sync"}},
{ NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ { NFSEXP_SECURITY_LABEL, {"security_label", ""}},
+#endif
{ NFSEXP_NOHIDE, {"nohide", ""}},
{ NFSEXP_CROSSMOUNT, {"crossmnt", ""}},
{ NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index e5b51ff..b5576ed 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -49,6 +49,10 @@
#include <linux/nfs4_acl.h>
#include <linux/sunrpc/gss_api.h>
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+#include <linux/security.h>
+#endif
+
#define NFSDDBG_FACILITY NFSDDBG_PROC
static inline void
@@ -103,6 +107,13 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
(u32 *)open->op_verf.data,
&open->op_truncate, &created);
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ if (!status && open->op_label != NULL)
+ /* Is it appropriate to just kick back an error? */
+ status = security_inode_setsecctx(resfh.fh_dentry,
+ open->op_label->label, open->op_label->len);
+#endif
+
/* If we ever decide to use different attrs to store the
* verifier in nfsd_create_v3, then we'll need to change this
*/
@@ -432,6 +443,13 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfserr_badtype;
}
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ if (!status && create->cr_label != NULL)
+ /* Is it appropriate to just kick back an error? */
+ status = security_inode_setsecctx(resfh.fh_dentry,
+ create->cr_label->label, create->cr_label->len);
+#endif
+
if (!status) {
fh_unlock(&cstate->current_fh);
set_change_info(&create->cr_cinfo, &cstate->current_fh);
@@ -670,6 +688,11 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
setattr->sa_acl);
if (status)
goto out;
+ if (setattr->sa_label != NULL)
+ status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh,
+ setattr->sa_label);
+ if (status)
+ goto out;
status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr,
0, (time_t)0);
out:
@@ -964,7 +987,7 @@ out:
return status;
}
-static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = {
+static struct nfsd4_operation nfsd4_ops[LAST_NFS4_OP+1] = {
[OP_ACCESS] = {
.op_func = (nfsd4op_func)nfsd4_access,
.op_name = "OP_ACCESS",
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 14ba4d9..84019d4 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -59,6 +59,10 @@
#include <linux/sunrpc/gss_api.h>
#include <linux/sunrpc/svcauth_gss.h>
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+#include <linux/security.h>
+#endif
+
#define NFSDDBG_FACILITY NFSDDBG_XDR
/*
@@ -249,7 +253,7 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
static __be32
nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *iattr,
- struct nfs4_acl **acl)
+ struct nfs4_acl **acl, struct nfs4_label **label)
{
int expected_len, len = 0;
u32 dummy32;
@@ -402,6 +406,36 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia
goto xdr_error;
}
}
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ if (bmval[1] & FATTR4_WORD1_SECURITY_LABEL) {
+ *label = kzalloc(sizeof(struct nfs4_label), GFP_ATOMIC);
+ if (*label == NULL) {
+ host_err = -ENOMEM;
+ goto out_nfserr;
+ }
+
+ READ_BUF(4);
+ len += 4;
+ READ32(dummy32);
+ READ_BUF(dummy32);
+ len += (XDR_QUADLEN(dummy32) << 2);
+ READMEM(buf, dummy32);
+ (*label)->len = dummy32;
+
+ (*label)->label = kmalloc(dummy32 + 1, GFP_ATOMIC);
+ if ((*label)->label == NULL) {
+ host_err = -ENOMEM;
+ kfree(*label);
+ goto out_nfserr;
+ }
+
+ memcpy((*label)->label, buf, dummy32);
+ ((char *)(*label)->label)[dummy32 + 1] = '\0';
+
+ defer_free(argp, kfree, (*label)->label);
+ defer_free(argp, kfree, *label);
+ }
+#endif
if (len != expected_len)
goto xdr_error;
@@ -484,7 +518,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval)))
return status;
- if ((status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, &create->cr_acl)))
+ if ((status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, &create->cr_acl, &create->cr_label)))
goto out;
DECODE_TAIL;
@@ -645,7 +679,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
switch (open->op_createmode) {
case NFS4_CREATE_UNCHECKED:
case NFS4_CREATE_GUARDED:
- if ((status = nfsd4_decode_fattr(argp, open->op_bmval, &open->op_iattr, &open->op_acl)))
+ if ((status = nfsd4_decode_fattr(argp, open->op_bmval, &open->op_iattr, &open->op_acl, &open->op_label)))
goto out;
break;
case NFS4_CREATE_EXCLUSIVE:
@@ -839,7 +873,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta
READ_BUF(sizeof(stateid_t));
READ32(setattr->sa_stateid.si_generation);
COPYMEM(&setattr->sa_stateid.si_opaque, sizeof(stateid_opaque_t));
- if ((status = nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, &setattr->sa_acl)))
+ if ((status = nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, &setattr->sa_acl, &setattr->sa_label)))
goto out;
DECODE_TAIL;
@@ -905,7 +939,7 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify
* nfsd4_proc_verify; however we still decode here just to return
* correct error in case of bad xdr. */
#if 0
- status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl);
+ status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl, &ve_label);
if (status == nfserr_inval) {
status = nfserrno(status);
goto out;
@@ -1368,6 +1402,34 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen);
}
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+static inline __be32
+nfsd4_encode_security_label(struct svc_rqst *rqstp, struct dentry *dentry, __be32 **p, int *buflen)
+{
+ void *context;
+ int err;
+ int len;
+
+ err = 0;
+ (void)security_inode_getsecctx(dentry->d_inode, &context, &len);
+ if (len < 0)
+ return nfserrno(len);
+
+ if (*buflen < ((XDR_QUADLEN(len) << 2) + 4)) {
+ err = nfserr_resource;
+ goto out;
+ }
+
+ *p = xdr_encode_opaque(*p, context, len);
+ *buflen -= (XDR_QUADLEN(len) << 2) + 4;
+ BUG_ON(*buflen < 0);
+
+out:
+ security_release_secctx(context, len);
+ return err;
+}
+#endif
+
#define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
FATTR4_WORD0_RDATTR_ERROR)
#define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
@@ -1463,6 +1525,14 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
bmval0 &= ~FATTR4_WORD0_FS_LOCATIONS;
}
}
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ if (bmval1 & FATTR4_WORD1_SECURITY_LABEL) {
+ if (/* XXX !selinux_enabled */ 0)
+ bmval1 &= ~FATTR4_WORD1_SECURITY_LABEL;
+ }
+#else
+ bmval1 &= ~FATTR4_WORD1_SECURITY_LABEL;
+#endif
if ((buflen -= 16) < 0)
goto out_resource;
@@ -1473,15 +1543,24 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
u32 word0 = NFSD_SUPPORTED_ATTRS_WORD0;
+ u32 word1 = NFSD_SUPPORTED_ATTRS_WORD1;
if ((buflen -= 12) < 0)
goto out_resource;
if (!aclsupport)
word0 &= ~FATTR4_WORD0_ACL;
if (!exp->ex_fslocs.locations)
word0 &= ~FATTR4_WORD0_FS_LOCATIONS;
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ if (exp->ex_flags & NFSEXP_SECURITY_LABEL)
+ word1 |= FATTR4_WORD1_SECURITY_LABEL;
+ else
+ word1 &= ~FATTR4_WORD1_SECURITY_LABEL;
+#else
+ word1 &= ~FATTR4_WORD1_SECURITY_LABEL;
+#endif
WRITE32(2);
WRITE32(word0);
- WRITE32(NFSD_SUPPORTED_ATTRS_WORD1);
+ WRITE32(word1);
}
if (bmval0 & FATTR4_WORD0_TYPE) {
if ((buflen -= 4) < 0)
@@ -1791,6 +1870,16 @@ out_acl:
}
WRITE64(stat.ino);
}
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+ if (bmval1 & FATTR4_WORD1_SECURITY_LABEL) {
+ status = nfsd4_encode_security_label(rqstp, dentry,
+ &p, &buflen);
+ if (status == nfserr_resource)
+ goto out_resource;
+ if (status)
+ goto out;
+ }
+#endif
*attrlenp = htonl((char *)p - (char *)attrlenp - 4);
*countp = p - buffer;
status = nfs_ok;
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 18060be..7113705 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -553,6 +553,28 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_ac
return error;
}
+#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
+__be32
+nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ struct nfs4_label *label)
+{
+ __be32 error;
+ int host_error;
+ struct dentry *dentry;
+
+ /* Get inode */
+ /* XXX: should we have a MAY_SSECCTX? */
+ error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR);
+ if (error)
+ return error;
+
+ dentry = fhp->fh_dentry;
+
+ host_error = security_inode_setsecctx(dentry, label->label, label->len);
+ return nfserrno(host_error);
+}
+#endif
+
#endif /* defined(CONFIG_NFS_V4) */
#ifdef CONFIG_NFSD_V3
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index f329b96..0b8a8cb 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -86,6 +86,8 @@ __be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *,
__be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
struct nfs4_acl *);
int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **);
+__be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *,
+ struct nfs4_label *);
#endif /* CONFIG_NFSD_V4 */
__be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
char *name, int len, struct iattr *attrs,
--
1.5.5.1
^ permalink raw reply related [flat|nested] 33+ messages in thread