Commit d6a97d3f authored by NeilBrown's avatar NeilBrown Committed by Chuck Lever

NFSD: add security label to struct nfsd_attrs

nfsd_setattr() now sets a security label if provided, and nfsv4 provides
it in the 'open' and 'create' paths and the 'setattr' path.
If setting the label failed (including because the kernel doesn't
support labels), an error field in 'struct nfsd_attrs' is set, and the
caller can respond.  The open/create callers clear
FATTR4_WORD2_SECURITY_LABEL in the returned attr set in this case.
The setattr caller returns the error.
Signed-off-by: default avatarNeilBrown <neilb@suse.de>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 93adc1e3
...@@ -64,36 +64,6 @@ MODULE_PARM_DESC(nfsd4_ssc_umount_timeout, ...@@ -64,36 +64,6 @@ MODULE_PARM_DESC(nfsd4_ssc_umount_timeout,
"idle msecs before unmount export from source server"); "idle msecs before unmount export from source server");
#endif #endif
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
#include <linux/security.h>
static inline void
nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval)
{
struct inode *inode = d_inode(resfh->fh_dentry);
int status;
inode_lock(inode);
status = security_inode_setsecctx(resfh->fh_dentry,
label->data, label->len);
inode_unlock(inode);
if (status)
/*
* XXX: We should really fail the whole open, but we may
* already have created a new file, so it may be too
* late. For now this seems the least of evils:
*/
bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
return;
}
#else
static inline void
nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval)
{ }
#endif
#define NFSDDBG_FACILITY NFSDDBG_PROC #define NFSDDBG_FACILITY NFSDDBG_PROC
static u32 nfsd_attrmask[] = { static u32 nfsd_attrmask[] = {
...@@ -288,6 +258,7 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -288,6 +258,7 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct iattr *iap = &open->op_iattr; struct iattr *iap = &open->op_iattr;
struct nfsd_attrs attrs = { struct nfsd_attrs attrs = {
.na_iattr = iap, .na_iattr = iap,
.na_seclabel = &open->op_label,
}; };
struct dentry *parent, *child; struct dentry *parent, *child;
__u32 v_mtime, v_atime; __u32 v_mtime, v_atime;
...@@ -409,6 +380,8 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -409,6 +380,8 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
set_attr: set_attr:
status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs); status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs);
if (attrs.na_labelerr)
open->op_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
out: out:
fh_unlock(fhp); fh_unlock(fhp);
if (child && !IS_ERR(child)) if (child && !IS_ERR(child))
...@@ -450,9 +423,6 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru ...@@ -450,9 +423,6 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
status = nfsd4_create_file(rqstp, current_fh, *resfh, open); status = nfsd4_create_file(rqstp, current_fh, *resfh, open);
current->fs->umask = 0; current->fs->umask = 0;
if (!status && open->op_label.len)
nfsd4_security_inode_setsecctx(*resfh, &open->op_label, open->op_bmval);
/* /*
* Following rfc 3530 14.2.16, and rfc 5661 18.16.4 * Following rfc 3530 14.2.16, and rfc 5661 18.16.4
* use the returned bitmask to indicate which attributes * use the returned bitmask to indicate which attributes
...@@ -792,6 +762,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -792,6 +762,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_create *create = &u->create; struct nfsd4_create *create = &u->create;
struct nfsd_attrs attrs = { struct nfsd_attrs attrs = {
.na_iattr = &create->cr_iattr, .na_iattr = &create->cr_iattr,
.na_seclabel = &create->cr_label,
}; };
struct svc_fh resfh; struct svc_fh resfh;
__be32 status; __be32 status;
...@@ -864,8 +835,8 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -864,8 +835,8 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (status) if (status)
goto out; goto out;
if (create->cr_label.len) if (attrs.na_labelerr)
nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval); create->cr_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
if (create->cr_acl != NULL) if (create->cr_acl != NULL)
do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, do_set_nfs4_acl(rqstp, &resfh, create->cr_acl,
...@@ -1150,6 +1121,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -1150,6 +1121,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_setattr *setattr = &u->setattr; struct nfsd4_setattr *setattr = &u->setattr;
struct nfsd_attrs attrs = { struct nfsd_attrs attrs = {
.na_iattr = &setattr->sa_iattr, .na_iattr = &setattr->sa_iattr,
.na_seclabel = &setattr->sa_label,
}; };
__be32 status = nfs_ok; __be32 status = nfs_ok;
int err; int err;
...@@ -1178,13 +1150,10 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -1178,13 +1150,10 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
setattr->sa_acl); setattr->sa_acl);
if (status) if (status)
goto out; goto out;
if (setattr->sa_label.len)
status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh,
&setattr->sa_label);
if (status)
goto out;
status = nfsd_setattr(rqstp, &cstate->current_fh, &attrs, status = nfsd_setattr(rqstp, &cstate->current_fh, &attrs,
0, (time64_t)0); 0, (time64_t)0);
if (!status)
status = nfserrno(attrs.na_labelerr);
out: out:
fh_drop_write(&cstate->current_fh); fh_drop_write(&cstate->current_fh);
return status; return status;
......
...@@ -458,6 +458,9 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -458,6 +458,9 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
host_err = notify_change(&init_user_ns, dentry, iap, NULL); host_err = notify_change(&init_user_ns, dentry, iap, NULL);
out_unlock: out_unlock:
if (attr->na_seclabel && attr->na_seclabel->len)
attr->na_labelerr = security_inode_setsecctx(dentry,
attr->na_seclabel->data, attr->na_seclabel->len);
fh_unlock(fhp); fh_unlock(fhp);
if (size_change) if (size_change)
put_write_access(inode); put_write_access(inode);
...@@ -496,32 +499,6 @@ int nfsd4_is_junction(struct dentry *dentry) ...@@ -496,32 +499,6 @@ int nfsd4_is_junction(struct dentry *dentry)
return 0; return 0;
return 1; return 1;
} }
#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct xdr_netobj *label)
{
__be32 error;
int host_error;
struct dentry *dentry;
error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR);
if (error)
return error;
dentry = fhp->fh_dentry;
inode_lock(d_inode(dentry));
host_error = security_inode_setsecctx(dentry, label->data, label->len);
inode_unlock(d_inode(dentry));
return nfserrno(host_error);
}
#else
__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct xdr_netobj *label)
{
return nfserr_notsupp;
}
#endif
static struct nfsd4_compound_state *nfsd4_get_cstate(struct svc_rqst *rqstp) static struct nfsd4_compound_state *nfsd4_get_cstate(struct svc_rqst *rqstp)
{ {
......
...@@ -44,6 +44,9 @@ typedef int (*nfsd_filldir_t)(void *, const char *, int, loff_t, u64, unsigned); ...@@ -44,6 +44,9 @@ typedef int (*nfsd_filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
/* nfsd/vfs.c */ /* nfsd/vfs.c */
struct nfsd_attrs { struct nfsd_attrs {
struct iattr *na_iattr; /* input */ struct iattr *na_iattr; /* input */
struct xdr_netobj *na_seclabel; /* input */
int na_labelerr; /* output */
}; };
int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
...@@ -57,8 +60,6 @@ __be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *, ...@@ -57,8 +60,6 @@ __be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *,
struct nfsd_attrs *, int, time64_t); struct nfsd_attrs *, int, time64_t);
int nfsd_mountpoint(struct dentry *, struct svc_export *); int nfsd_mountpoint(struct dentry *, struct svc_export *);
#ifdef CONFIG_NFSD_V4 #ifdef CONFIG_NFSD_V4
__be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *,
struct xdr_netobj *);
__be32 nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *, __be32 nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *,
struct file *, loff_t, loff_t, int); struct file *, loff_t, loff_t, int);
__be32 nfsd4_clone_file_range(struct svc_rqst *rqstp, __be32 nfsd4_clone_file_range(struct svc_rqst *rqstp,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment