Return-Path: linux-nfs-owner@vger.kernel.org Received: from mx12.netapp.com ([216.240.18.77]:51820 "EHLO mx12.netapp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750837Ab3AWTrB convert rfc822-to-8bit (ORCPT ); Wed, 23 Jan 2013 14:47:01 -0500 From: "Myklebust, Trond" To: Steve Dickson CC: David Quigley , "J. Bruce Fields" , Linux NFS Mailing list Subject: Re: [PATCH 11/14] NFS: Client implementation of Labeled-NFS Date: Wed, 23 Jan 2013 19:46:57 +0000 Message-ID: <4FA345DA4F4AE44899BD2B03EEEC2FA918333653@sacexcmbx05-prd.hq.netapp.com> References: <1358862042-27520-1-git-send-email-steved@redhat.com> <1358862042-27520-12-git-send-email-steved@redhat.com> In-Reply-To: <1358862042-27520-12-git-send-email-steved@redhat.com> Content-Type: text/plain; charset=US-ASCII MIME-Version: 1.0 Sender: linux-nfs-owner@vger.kernel.org List-ID: On Tue, 2013-01-22 at 08:40 -0500, Steve Dickson wrote: > From: David Quigley > > 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 > Signed-off-by: Miguel Rodel Felipe > Signed-off-by: Phua Eu Gene > Signed-off-by: Khin Mi Mi Aung > --- > fs/nfs/dir.c | 4 - > fs/nfs/inode.c | 58 +++++++-- > fs/nfs/nfs4proc.c | 296 ++++++++++++++++++++++++++++++++++++++++++++-- > fs/nfs/nfs4xdr.c | 178 +++++++++++++++++++++++----- > fs/nfs/super.c | 17 ++- > include/linux/nfs_fs.h | 3 + > include/linux/nfs_fs_sb.h | 7 ++ > security/selinux/hooks.c | 4 + > 8 files changed, 508 insertions(+), 59 deletions(-) > > diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c > index d01fd1f..e7605fe 100644 > --- a/fs/nfs/dir.c > +++ b/fs/nfs/dir.c > @@ -1107,10 +1107,8 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) > nfs_free_fattr(fattr); > nfs_free_fhandle(fhandle); > > -#ifdef CONFIG_NFS_V4_SECURITY_LABEL > if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) > nfs4_label_free(label); > -#endif > > out_set_verifier: > nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); > @@ -1299,10 +1297,8 @@ no_entry: > out_unblock_sillyrename: > nfs_unblock_sillyrename(parent); > out: > -#ifdef CONFIG_NFS_V4_SECURITY_LABEL > if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) > nfs4_label_free(label); > -#endif > nfs_free_fattr(fattr); > nfs_free_fhandle(fhandle); > return res; > diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c > index 30ce1e0..56cd542 100644 > --- a/fs/nfs/inode.c > +++ b/fs/nfs/inode.c > @@ -162,11 +162,19 @@ static void nfs_zap_caches_locked(struct inode *inode) > > memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf)); > if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { > - nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; > nfs_fscache_invalidate(inode); > - } else { > - nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; > - } > + nfsi->cache_validity |= NFS_INO_INVALID_ATTR > + | NFS_INO_INVALID_LABEL > + | NFS_INO_INVALID_DATA > + | NFS_INO_INVALID_ACCESS > + | NFS_INO_INVALID_ACL > + | NFS_INO_REVAL_PAGECACHE; > + } else > + nfsi->cache_validity |= NFS_INO_INVALID_ATTR > + | NFS_INO_INVALID_LABEL > + | NFS_INO_INVALID_ACCESS > + | NFS_INO_INVALID_ACL > + | NFS_INO_REVAL_PAGECACHE; > } > > void nfs_zap_caches(struct inode *inode) > @@ -256,6 +264,24 @@ nfs_init_locked(struct inode *inode, void *opaque) > } > > #ifdef CONFIG_NFS_V4_SECURITY_LABEL > +void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, > + struct nfs4_label *label) > +{ > + int error; > + > + if ((fattr->valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL) && > + label && inode->i_security) { > + error = security_inode_notifysecctx(inode, label->label, > + label->len); > + if (error) > + printk(KERN_ERR "%s() %s %d " > + "security_inode_notifysecctx() %d\n", > + __func__, > + (char *)label->label, > + label->len, error); > + } > +} > + > struct nfs4_label *nfs4_label_alloc(gfp_t flags) > { > struct nfs4_label *label = NULL; > @@ -293,7 +319,14 @@ void nfs4_label_free(struct nfs4_label *label) > return; > } > EXPORT_SYMBOL_GPL(nfs4_label_free); > + > +#else > +void inline nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, > + struct nfs4_label *label) > +{ > +} > #endif > +EXPORT_SYMBOL_GPL(nfs_setsecurity); > > /* > * This is our front-end to iget that looks up inodes by file handle > @@ -422,6 +455,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st > */ > inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used); > } > + > + nfs_setsecurity(inode, fattr, label); > + > nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); > nfsi->attrtimeo_timestamp = now; > nfsi->access_cache = RB_ROOT; > @@ -784,6 +820,7 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c > spin_unlock(&inode->i_lock); > return ctx; > } > +EXPORT_SYMBOL_GPL(nfs_find_open_context); > > static void nfs_file_clear_open_context(struct file *filp) > { > @@ -885,10 +922,10 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) > (long long)NFS_FILEID(inode)); > > out: > -#ifdef CONFIG_NFS_V4_SECURITY_LABEL > + > if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) > nfs4_label_free(label); > -#endif > + > nfs_free_fattr(fattr); > return status; > } > @@ -916,7 +953,8 @@ static int nfs_attribute_cache_expired(struct inode *inode) > */ > int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) > { > - if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATTR) > + if (!(NFS_I(inode)->cache_validity & > + (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) > && !nfs_attribute_cache_expired(inode)) > return NFS_STALE(inode) ? -ESTALE : 0; > return __nfs_revalidate_inode(server, inode); > @@ -1515,6 +1553,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct > | NFS_INO_INVALID_ACL > | NFS_INO_REVAL_FORCED); > > + if (label && (server->caps & NFS_CAP_SECURITY_LABEL)) > + nfs_setsecurity(inode, fattr, label); > + > if (fattr->valid & NFS_ATTR_FATTR_NLINK) { > if (inode->i_nlink != fattr->nlink) { > invalid |= NFS_INO_INVALID_ATTR; > @@ -1536,7 +1577,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct > inode->i_blocks = fattr->du.nfs2.blocks; > > /* Update attrtimeo value if we're out of the unstable period */ > - if (invalid & NFS_INO_INVALID_ATTR) { > + if (invalid & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) { > nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); > nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); > nfsi->attrtimeo_timestamp = now; > @@ -1549,6 +1590,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, struct > } > } > invalid &= ~NFS_INO_INVALID_ATTR; > + invalid &= ~NFS_INO_INVALID_LABEL; > /* Don't invalidate the data if we were to blame */ > if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) > || S_ISLNK(inode->i_mode))) > diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c > index d08f033..ba4f268 100644 > --- a/fs/nfs/nfs4proc.c > +++ b/fs/nfs/nfs4proc.c > @@ -132,7 +132,7 @@ const u32 nfs4_fattr_bitmap[3] = { > | FATTR4_WORD1_TIME_ACCESS > | FATTR4_WORD1_TIME_METADATA > | FATTR4_WORD1_TIME_MODIFY, > - 0 > + FATTR4_WORD2_SECURITY_LABEL > }; > > static const u32 nfs4_pnfs_open_bitmap[3] = { > @@ -1947,6 +1947,7 @@ static int _nfs4_do_open(struct inode *dir, > if (status == 0) { > nfs_setattr_update_inode(state->inode, sattr); > nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr, olabel); > + nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel); > } > } > > @@ -2059,6 +2060,9 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, > unsigned long timestamp = jiffies; > int status; > > + if (ilabel == NULL || olabel == NULL) > + arg.bitmask = server->attr_bitmask_nl; > + > nfs_fattr_init(fattr); > > if (state != NULL) { > @@ -2286,7 +2290,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait) > if (calldata->arg.seqid == NULL) > goto out_free_calldata; > calldata->arg.fmode = 0; > - calldata->arg.bitmask = server->cache_consistency_bitmask; > + calldata->arg.bitmask = server->cache_consistency_bitmask_nl; > calldata->res.fattr = &calldata->fattr; > calldata->res.seqid = calldata->arg.seqid; > calldata->res.server = server; > @@ -2316,11 +2320,24 @@ static struct inode * > nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr) > { > struct nfs4_state *state; > - struct nfs4_label *label = NULL; > + struct nfs4_label l, *label = NULL; > + > + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) { > + struct dentry *dentry = ctx->dentry; > + int error; > + error = security_dentry_init_security(dentry, attr->ia_mode, > + &dentry->d_name, &l.label, &l.len); > + if (error == 0) > + label = &l; > + } > > /* Protect against concurrent sillydeletes */ > state = nfs4_do_open(dir, ctx->dentry, ctx->mode, open_flags, attr, label, > ctx->cred, &ctx->mdsthreshold); > + > + if (label) > + security_release_secctx(l.label, l.len); > + > if (IS_ERR(state)) > return ERR_CAST(state); > ctx->state = state; > @@ -2380,10 +2397,27 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f > server->caps |= NFS_CAP_CTIME; > if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY) > server->caps |= NFS_CAP_MTIME; > +#ifdef CONFIG_NFS_V4_SECURITY_LABEL > + if (res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL) { > + server->caps |= NFS_CAP_SECURITY_LABEL; > + } else > +#endif > + server->attr_bitmask[2] &= ~FATTR4_WORD2_SECURITY_LABEL; > + > + if (server->caps & NFS_CAP_SECURITY_LABEL) { > + memcpy(server->attr_bitmask_nl, res.attr_bitmask, > + sizeof(server->attr_bitmask)); > + server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL; > + } > > memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask)); > server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE; > - server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; > + server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA | > + FATTR4_WORD1_TIME_MODIFY; > + server->cache_consistency_bitmask[2] &= FATTR4_WORD2_SECURITY_LABEL; > + memcpy(server->cache_consistency_bitmask_nl, server->cache_consistency_bitmask, > + sizeof(server->cache_consistency_bitmask_nl)); > + server->cache_consistency_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL; > server->acl_bitmask = res.acl_bitmask; > server->fh_expire_type = res.fh_expire_type; > } > @@ -2406,8 +2440,9 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) > static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, > struct nfs_fsinfo *info) > { > + u32 bitmask[3]; > struct nfs4_lookup_root_arg args = { > - .bitmask = nfs4_fattr_bitmap, > + .bitmask = bitmask, > }; > struct nfs4_lookup_res res = { > .server = server, > @@ -2420,6 +2455,10 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, > .rpc_resp = &res, > }; > > + bitmask[0] = nfs4_fattr_bitmap[0]; > + bitmask[1] = nfs4_fattr_bitmap[1]; > + bitmask[2] = nfs4_fattr_bitmap[2] & ~FATTR4_WORD2_SECURITY_LABEL; Why this? Shouldn't we be retrieving the security label too? If not, then a comment would be appropriate. > + > nfs_fattr_init(info->fattr); > return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); > } > @@ -2607,7 +2646,10 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, > .rpc_argp = &args, > .rpc_resp = &res, > }; > - > + > + if (!label) > + args.bitmask = server->attr_bitmask_nl; > + > nfs_fattr_init(fattr); > return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); > } > @@ -2703,6 +2745,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, > struct nfs4_lookup_res res = { > .server = server, > .fattr = fattr, > + .label = label, > .fh = fhandle, > }; > struct rpc_message msg = { > @@ -2711,6 +2754,9 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, > .rpc_resp = &res, > }; > > + if (label == NULL) > + args.bitmask = server->attr_bitmask_nl; > + > nfs_fattr_init(fattr); > > dprintk("NFS call lookup %s\n", name->name); > @@ -2817,7 +2863,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry > .rpc_cred = entry->cred, > }; > int mode = entry->mask; > - int status; > + int status = 0; > > /* > * Determine which access bits we want to ask for... > @@ -2935,7 +2981,7 @@ static int > nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, > int flags) > { > - struct nfs4_label *ilabel = NULL; > + struct nfs4_label l, *ilabel = NULL; > struct nfs_open_context *ctx; > struct nfs4_state *state; > int status = 0; > @@ -2944,6 +2990,13 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, > if (IS_ERR(ctx)) > return PTR_ERR(ctx); > > + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) { Wrapper? > + status = security_dentry_init_security(dentry, sattr->ia_mode, > + &dentry->d_name, &l.label, &l.len); > + if (status == 0) > + ilabel = &l; > + } > + > sattr->ia_mode &= ~current_umask(); > state = nfs4_do_open(dir, dentry, ctx->mode, > flags, sattr, ilabel, ctx->cred, > @@ -2957,6 +3010,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, > nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); > ctx->state = state; > out: > + if (ilabel) > + security_release_secctx(ilabel->label, ilabel->len); Worried... ilabel->len is initialised to 4096 if the label string is empty... > put_nfs_open_context(ctx); > return status; > } > @@ -3006,6 +3061,8 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir) > res->server = server; > msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE]; > nfs41_init_sequence(&args->seq_args, &res->seq_res, 1); > + > + nfs_fattr_init(res->dir_attr); > } > > static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data) > @@ -3278,14 +3335,25 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, > struct page *page, unsigned int len, struct iattr *sattr) > { > struct nfs4_exception exception = { }; > - struct nfs4_label *label = NULL; > + struct nfs4_label l, *label = NULL; > int err; > + > + > + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) { See above.... > + err = security_dentry_init_security(dentry, sattr->ia_mode, > + &dentry->d_name, &l.label, &l.len); > + if (err == 0) > + label = &l; > + } > + > do { > err = nfs4_handle_exception(NFS_SERVER(dir), > _nfs4_proc_symlink(dir, dentry, page, > len, sattr, label), > &exception); > } while (exception.retry); > + if (label) > + security_release_secctx(l.label, l.len); > return err; > } > > @@ -3311,15 +3379,24 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, > struct iattr *sattr) > { > struct nfs4_exception exception = { }; > - struct nfs4_label *label = NULL; > + struct nfs4_label l, *label = NULL; > int err; > > + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) { .... > + err = security_dentry_init_security(dentry, sattr->ia_mode, > + &dentry->d_name, &l.label, &l.len); > + if (err == 0) > + label = &l; > + } > + > sattr->ia_mode &= ~current_umask(); > do { > err = nfs4_handle_exception(NFS_SERVER(dir), > _nfs4_proc_mkdir(dir, dentry, sattr, label), > &exception); > } while (exception.retry); > + if (label) > + security_release_secctx(l.label, l.len); > return err; > } > > @@ -3335,7 +3412,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, > .bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask, > .plus = plus, > }; > - struct nfs4_readdir_res res; > + struct nfs4_readdir_res res = { > + .pgbase = 0, > + }; > struct rpc_message msg = { > .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READDIR], > .rpc_argp = &args, > @@ -3415,15 +3494,26 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, > struct iattr *sattr, dev_t rdev) > { > struct nfs4_exception exception = { }; > - struct nfs4_label *label = NULL; > + struct nfs4_label l, *label = NULL; > int err; > > + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) { .... > + err = security_dentry_init_security(dentry, sattr->ia_mode, > + &dentry->d_name, &l.label, &l.len); > + if (err == 0) > + label = &l; > + } > + > sattr->ia_mode &= ~current_umask(); > do { > err = nfs4_handle_exception(NFS_SERVER(dir), > _nfs4_proc_mknod(dir, dentry, sattr, label, rdev), > &exception); > } while (exception.retry); > + > + if (label) > + security_release_secctx(l.label, l.len); > + > return err; > } > > @@ -3639,7 +3729,11 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag > data->args.bitmask = NULL; > data->res.fattr = NULL; > } else > +#ifdef CONFIG_NFS_V4_SECURITY_LABEL > + data->args.bitmask = server->cache_consistency_bitmask_nl; > +#else > data->args.bitmask = server->cache_consistency_bitmask; > +#endif OK... Why do we rename server->cache_consistency_bitmask? > > if (!data->write_done_cb) > data->write_done_cb = nfs4_write_done_cb; > @@ -4064,6 +4158,182 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen > return err; > } > > +#ifdef CONFIG_NFS_V4_SECURITY_LABEL > +static int _nfs4_get_security_label(struct inode *inode, void *buf, > + size_t buflen) > +{ > + struct nfs_server *server = NFS_SERVER(inode); > + struct nfs_fattr fattr; > + struct nfs4_label label; > + u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL }; > + struct nfs4_getattr_arg args = { > + .fh = NFS_FH(inode), > + .bitmask = bitmask, > + }; > + struct nfs4_getattr_res res = { > + .fattr = &fattr, > + .label = &label, > + .server = server, > + }; > + struct rpc_message msg = { > + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR], > + .rpc_argp = &args, > + .rpc_resp = &res, > + }; > + int ret; > + > + label.label = buf; > + label.len = buflen; Initialise in the declaration above? > + nfs_fattr_init(&fattr); > + > + ret = rpc_call_sync(server->client, &msg, 0); > + if (ret) > + return ret; > + if (!(fattr.valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL)) > + return -ENOENT; > + if (buflen < label.len) > + return -ERANGE; > + return 0; > +} > + > +static int nfs4_get_security_label(struct inode *inode, void *buf, > + size_t buflen) > +{ > + struct nfs4_exception exception = { }; > + int err; > + > + if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) > + return -EOPNOTSUPP; > + > + do { > + err = nfs4_handle_exception(NFS_SERVER(inode), > + _nfs4_get_security_label(inode, buf, buflen), > + &exception); > + } while (exception.retry); > + return err; > +} > + > +static int _nfs4_do_set_security_label(struct inode *inode, > + struct nfs4_label *ilabel, > + struct nfs_fattr *fattr, > + struct nfs4_label *olabel, > + struct nfs4_state *state) > +{ > + > + struct iattr sattr; > + struct nfs_server *server = NFS_SERVER(inode); > + const u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL }; > + struct nfs_setattrargs args = { > + .fh = NFS_FH(inode), > + .iap = &sattr, > + .server = server, > + .bitmask = bitmask, > + .label = ilabel, > + }; > + struct nfs_setattrres res = { > + .fattr = fattr, > + .label = olabel, > + .server = server, > + }; > + struct rpc_message msg = { > + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR], > + .rpc_argp = &args, > + .rpc_resp = &res, > + }; > + unsigned long timestamp = jiffies; > + int status; > + > + memset(&sattr, 0, sizeof(struct iattr)); Just declare as '= {0};'? > + > + if (state != NULL) { > + struct nfs_lockowner lockowner = { > + .l_owner = current->files, > + .l_pid = current->tgid, > + }; > + > + msg.rpc_cred = state->owner->so_cred; > + nfs4_select_rw_stateid(&args.stateid, state, FMODE_WRITE, > + &lockowner); > + } else if (nfs4_copy_delegation_stateid(&args.stateid, inode, > + FMODE_WRITE)) { > + /* Use that stateid */ > + } else > + nfs4_stateid_copy(&args.stateid, &zero_stateid); > + > + status = rpc_call_sync(server->client, &msg, 0); > + if (status == 0 && state != NULL) > + renew_lease(server, timestamp); > + return status; > +} > + > +static int nfs4_do_set_security_label(struct inode *inode, > + struct nfs4_label *ilabel, > + struct nfs_fattr *fattr, > + struct nfs4_label *olabel, > + struct nfs4_state *state) > +{ > + struct nfs4_exception exception = { }; > + int err; > + > + do { > + err = nfs4_handle_exception(NFS_SERVER(inode), > + _nfs4_do_set_security_label(inode, ilabel, > + fattr, olabel, state), > + &exception); > + } while (exception.retry); > + return err; > +} > + > +static int > +nfs4_set_security_label(struct dentry *dentry, const void *buf, size_t buflen) > +{ > + struct nfs4_label ilabel, *olabel = NULL; > + struct nfs_fattr fattr; > + struct rpc_cred *cred; > + struct nfs_open_context *ctx; > + struct nfs4_state *state = NULL; > + struct inode *inode = dentry->d_inode; > + int status; > + > + if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) > + return -EOPNOTSUPP; > + > + nfs_fattr_init(&fattr); > + > + ilabel.pi = 0; > + ilabel.lfs = 0; > + ilabel.label = (char *)buf; > + ilabel.len = buflen; > + > + cred = rpc_lookup_cred(); > + if (IS_ERR(cred)) > + return PTR_ERR(cred); > + > + olabel = nfs4_label_alloc(GFP_KERNEL); > + if (olabel == NULL) { > + status = -ENOMEM; > + goto out; > + } > + > + /* Search for an existing open(O_WRITE) file */ > + ctx = nfs_find_open_context(inode, cred, FMODE_WRITE); > + if (ctx != NULL) > + state = ctx->state; > + > + status = nfs4_do_set_security_label(inode, &ilabel, &fattr, olabel, > + state); > + if (status == 0) > + nfs_setsecurity(inode, &fattr, olabel); > + if (ctx != NULL) > + put_nfs_open_context(ctx); > + nfs4_label_free(olabel); > +out: > + put_rpccred(cred); > + return status; > +} > +#endif /* CONFIG_NFS_V4_SECURITY_LABEL */ > + > + > static int > nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) > { > @@ -4352,7 +4622,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co > nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1); > data->args.fhandle = &data->fh; > data->args.stateid = &data->stateid; > - data->args.bitmask = server->cache_consistency_bitmask; > + data->args.bitmask = server->cache_consistency_bitmask_nl; > nfs_copy_fh(&data->fh, NFS_FH(inode)); > nfs4_stateid_copy(&data->stateid, stateid); > data->res.fattr = &data->fattr; > diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c > index a9353d1..49f6d1a 100644 > --- a/fs/nfs/nfs4xdr.c > +++ b/fs/nfs/nfs4xdr.c > @@ -102,12 +102,19 @@ static int nfs4_stat_to_errno(int); > #define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2)) > #define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) > #define nfs4_group_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) > +#ifdef CONFIG_NFS_V4_SECURITY_LABEL > +/* PI(4 bytes) + LFS(4 bytes) + 1(for null terminator?) + MAXLABELLEN */ > +#define nfs4_label_maxsz (4 + 4 + 1 + XDR_QUADLEN(NFS4_MAXLABELLEN)) > +#else > +#define nfs4_label_maxsz 0 > +#endif > /* We support only one layout type per file system */ > #define decode_mdsthreshold_maxsz (1 + 1 + nfs4_fattr_bitmap_maxsz + 1 + 8) > /* This is based on getfattr, which uses the most attributes: */ > #define nfs4_fattr_value_maxsz (1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \ > 3 + 3 + 3 + nfs4_owner_maxsz + \ > - nfs4_group_maxsz + decode_mdsthreshold_maxsz)) > + nfs4_group_maxsz + nfs4_label_maxsz + \ > + decode_mdsthreshold_maxsz)) > #define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \ > nfs4_fattr_value_maxsz) > #define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz) > @@ -115,6 +122,7 @@ static int nfs4_stat_to_errno(int); > 1 + 2 + 1 + \ > nfs4_owner_maxsz + \ > nfs4_group_maxsz + \ > + nfs4_label_maxsz + \ > 4 + 4) > #define encode_savefh_maxsz (op_encode_hdr_maxsz) > #define decode_savefh_maxsz (op_decode_hdr_maxsz) > @@ -192,9 +200,11 @@ static int nfs4_stat_to_errno(int); > encode_stateid_maxsz + 3) > #define decode_read_maxsz (op_decode_hdr_maxsz + 2) > #define encode_readdir_maxsz (op_encode_hdr_maxsz + \ > - 2 + encode_verifier_maxsz + 5) > + 2 + encode_verifier_maxsz + 5 + \ > + nfs4_label_maxsz) > #define decode_readdir_maxsz (op_decode_hdr_maxsz + \ > - decode_verifier_maxsz) > + decode_verifier_maxsz + \ > + nfs4_label_maxsz + nfs4_fattr_maxsz) > #define encode_readlink_maxsz (op_encode_hdr_maxsz) > #define decode_readlink_maxsz (op_decode_hdr_maxsz + 1) > #define encode_write_maxsz (op_encode_hdr_maxsz + \ > @@ -972,7 +982,9 @@ static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *ve > encode_opaque_fixed(xdr, verf->data, NFS4_VERIFIER_SIZE); > } > > -static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server) > +static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, > + const struct nfs4_label *label, > + const struct nfs_server *server) > { > char owner_name[IDMAP_NAMESZ]; > char owner_group[IDMAP_NAMESZ]; > @@ -1022,6 +1034,8 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const > } > len += 4 + (XDR_QUADLEN(owner_grouplen) << 2); > } > + if (label && (server->caps & NFS_CAP_SECURITY_LABEL)) Why the extra check for server->caps? > + len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2); > if (iap->ia_valid & ATTR_ATIME_SET) > len += 16; > else if (iap->ia_valid & ATTR_ATIME) > @@ -1078,6 +1092,13 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const > bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET; > *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME); > } > + if (label && (server->caps & NFS_CAP_SECURITY_LABEL)) { Ditto... > + bmval2 |= FATTR4_WORD2_SECURITY_LABEL; > + *p++ = cpu_to_be32(label->lfs); > + *p++ = cpu_to_be32(label->pi); > + *p++ = cpu_to_be32(label->len); > + p = xdr_encode_opaque_fixed(p, label->label, label->len); > + } > > /* > * Now we backfill the bitmap and the attribute buffer length. > @@ -1144,7 +1165,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * > } > > encode_string(xdr, create->name->len, create->name->name); > - encode_attrs(xdr, create->attrs, create->server); > + encode_attrs(xdr, create->attrs, create->label, create->server); > } > > static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr) > @@ -1377,21 +1398,23 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op > switch(arg->open_flags & O_EXCL) { > case 0: > *p = cpu_to_be32(NFS4_CREATE_UNCHECKED); > - encode_attrs(xdr, arg->u.attrs, arg->server); > + encode_attrs(xdr, arg->u.attrs, arg->label, arg->server); > break; > default: > clp = arg->server->nfs_client; > if (clp->cl_mvops->minor_version > 0) { > if (nfs4_has_persistent_session(clp)) { > *p = cpu_to_be32(NFS4_CREATE_GUARDED); > - encode_attrs(xdr, arg->u.attrs, arg->server); > + encode_attrs(xdr, arg->u.attrs, arg->label, > + arg->server); > } else { > struct iattr dummy; > > *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1); > encode_nfs4_verifier(xdr, &arg->u.verifier); > dummy.ia_valid = 0; > - encode_attrs(xdr, &dummy, arg->server); > + encode_attrs(xdr, &dummy, arg->label, > + arg->server); > } > } else { > *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE); > @@ -1570,20 +1593,43 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg > encode_op_hdr(xdr, OP_READDIR, decode_readdir_maxsz, hdr); > encode_uint64(xdr, readdir->cookie); > encode_nfs4_verifier(xdr, &readdir->verifier); > +#ifdef CONFIG_NFS_V4_SECURITY_LABEL > + p = reserve_space(xdr, 24); > +#else > p = reserve_space(xdr, 20); > +#endif Ewwww......................................... > *p++ = cpu_to_be32(dircount); > *p++ = cpu_to_be32(readdir->count); > +#ifdef CONFIG_NFS_V4_SECURITY_LABEL > + *p++ = cpu_to_be32(3); > +#else > *p++ = cpu_to_be32(2); > - > +#endif Ewwwwwwwwww.................................... > *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]); > +#ifdef CONFIG_NFS_V4_SECURITY_LABEL > + *p++ = cpu_to_be32(attrs[1] & readdir->bitmask[1]); > + *p = cpu_to_be32(readdir->bitmask[2]); > +#else > *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]); > +#endif Ewwwwwwwwwwwwwwwwwwwwwww........................ > memcpy(verf, readdir->verifier.data, sizeof(verf)); > - dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", > +#ifdef CONFIG_NFS_V4_SECURITY_LABEL > + dprintk("%s: cookie = %llu, verifier = %08x:%08x, bitmap = %08x:%08x:%08x\n", > + __func__, > + (unsigned long long)readdir->cookie, > + verf[0], verf[1], > + attrs[0] & readdir->bitmask[0], > + attrs[1] & readdir->bitmask[1], > + readdir->bitmask[2]); > +#else > + dprintk("%s: cookie = %llu, verifier = %08x:%08x, bitmap = %08x:%08x\n", > __func__, > (unsigned long long)readdir->cookie, > verf[0], verf[1], > attrs[0] & readdir->bitmask[0], > attrs[1] & readdir->bitmask[1]); > +#endif > + > } > > static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr) > @@ -1642,7 +1688,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs > { > encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr); > encode_nfs4_stateid(xdr, &arg->stateid); > - encode_attrs(xdr, arg->iap, server); > + encode_attrs(xdr, arg->iap, arg->label, server); > } > > static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr) > @@ -4060,6 +4106,67 @@ static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap, > return status; > } > > +static int decode_attr_security_label(struct xdr_stream *xdr, uint32_t *bitmap, > + struct nfs4_label *label) > +{ > + uint32_t pi = 0; > + uint32_t lfs = 0; > + __u32 len; > + __be32 *p; > + int status = 0; > + > + if (unlikely(bitmap[2] & (FATTR4_WORD2_SECURITY_LABEL - 1U))) > + return -EIO; > + if (likely(bitmap[2] & FATTR4_WORD2_SECURITY_LABEL)) { > + p = xdr_inline_decode(xdr, 4); > + if (unlikely(!p)) > + goto out_overflow; > + lfs = be32_to_cpup(p++); > + p = xdr_inline_decode(xdr, 4); > + if (unlikely(!p)) > + goto out_overflow; > + pi = be32_to_cpup(p++); > + p = xdr_inline_decode(xdr, 4); > + if (unlikely(!p)) > + goto out_overflow; > + len = be32_to_cpup(p++); > + p = xdr_inline_decode(xdr, len); > + if (unlikely(!p)) > + goto out_overflow; > + if (len < XDR_MAX_NETOBJ) { > + if (label) { > + nfs4_label_init(label); > + if (label->len < len) { > + printk(KERN_ERR > + "%s(): label->len %d < len %d\n", > + __func__, label->len, len); > + } else { > + memcpy(label->label, p, len); > + label->len = len; > + label->pi = pi; > + label->lfs = lfs; > + status = NFS_ATTR_FATTR_V4_SECURITY_LABEL; > + } > + } else { > + printk("%s(): NULL label.\n", __func__); > + dump_stack(); > + goto out_overflow; > + } > + bitmap[2] &= ~FATTR4_WORD2_SECURITY_LABEL; > + } else > + printk(KERN_WARNING "%s: label too long (%u)!\n", > + __func__, len); > + } > + if (label && label->label) > + dprintk("%s: label=%s, len=%d, PI=%d, LFS=%d\n", __func__, > + (char *)label->label, label->len, label->pi, label->lfs); > + return status; > + > +out_overflow: > + print_overflow_msg(__func__, xdr); > + return -EIO; > +} > + > static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time) > { > int status = 0; > @@ -4402,7 +4509,7 @@ out_overflow: > > static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, > struct nfs_fattr *fattr, struct nfs_fh *fh, > - struct nfs4_fs_locations *fs_loc, > + struct nfs4_fs_locations *fs_loc, struct nfs4_label *label, > const struct nfs_server *server) > { > int status; > @@ -4510,6 +4617,11 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, > if (status < 0) > goto xdr_error; > > + status = decode_attr_security_label(xdr, bitmap, label); > + if (status < 0) > + goto xdr_error; > + fattr->valid |= status; > + > xdr_error: > dprintk("%s: xdr returned %d\n", __func__, -status); > return status; > @@ -4517,7 +4629,7 @@ xdr_error: > > static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr, > struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc, > - const struct nfs_server *server) > + struct nfs4_label *label, const struct nfs_server *server) > { > unsigned int savep; > uint32_t attrlen, > @@ -4536,7 +4648,8 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat > if (status < 0) > goto xdr_error; > > - status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, fs_loc, server); > + status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, fs_loc, > + label, server); > if (status < 0) > goto xdr_error; > > @@ -4547,9 +4660,9 @@ xdr_error: > } > > static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, > - const struct nfs_server *server) > + struct nfs4_label *label, const struct nfs_server *server) > { > - return decode_getfattr_generic(xdr, fattr, NULL, NULL, server); > + return decode_getfattr_generic(xdr, fattr, NULL, NULL, label, server); > } > > /* > @@ -5883,7 +5996,7 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, > status = decode_open_downgrade(xdr, res); > if (status != 0) > goto out; > - decode_getfattr(xdr, res->fattr, res->server); > + decode_getfattr(xdr, res->fattr, res->label, res->server); > out: > return status; > } > @@ -5909,7 +6022,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr, > status = decode_access(xdr, &res->supported, &res->access); > if (status != 0) > goto out; > - decode_getfattr(xdr, res->fattr, res->server); > + decode_getfattr(xdr, res->fattr, res->label, res->server); > out: > return status; > } > @@ -5938,7 +6051,7 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr, > status = decode_getfh(xdr, res->fh); > if (status) > goto out; > - status = decode_getfattr(xdr, res->fattr, res->server); > + status = decode_getfattr(xdr, res->fattr, res->label, res->server); > out: > return status; > } > @@ -5964,7 +6077,8 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, > goto out; > status = decode_getfh(xdr, res->fh); > if (status == 0) > - status = decode_getfattr(xdr, res->fattr, res->server); > + status = decode_getfattr(xdr, res->fattr, > + res->label, res->server); > out: > return status; > } > @@ -6055,7 +6169,7 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr, > status = decode_restorefh(xdr); > if (status) > goto out; > - decode_getfattr(xdr, res->fattr, res->server); > + decode_getfattr(xdr, res->fattr, res->label, res->server); > out: > return status; > } > @@ -6084,7 +6198,7 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr, > status = decode_getfh(xdr, res->fh); > if (status) > goto out; > - decode_getfattr(xdr, res->fattr, res->server); > + decode_getfattr(xdr, res->fattr, res->label, res->server); > out: > return status; > } > @@ -6116,7 +6230,7 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr, > status = decode_putfh(xdr); > if (status) > goto out; > - status = decode_getfattr(xdr, res->fattr, res->server); > + status = decode_getfattr(xdr, res->fattr, res->label, res->server); > out: > return status; > } > @@ -6218,7 +6332,7 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr, > * an ESTALE error. Shouldn't be a problem, > * though, since fattr->valid will remain unset. > */ > - decode_getfattr(xdr, res->fattr, res->server); > + decode_getfattr(xdr, res->fattr, res->label, res->server); > out: > return status; > } > @@ -6249,7 +6363,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr, > goto out; > if (res->access_request) > decode_access(xdr, &res->access_supported, &res->access_result); > - decode_getfattr(xdr, res->f_attr, res->server); > + decode_getfattr(xdr, res->f_attr, res->f_label, res->server); > out: > return status; > } > @@ -6299,7 +6413,7 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, > goto out; > if (res->access_request) > decode_access(xdr, &res->access_supported, &res->access_result); > - decode_getfattr(xdr, res->f_attr, res->server); > + decode_getfattr(xdr, res->f_attr, NULL, res->server); > out: > return status; > } > @@ -6326,7 +6440,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, > status = decode_setattr(xdr); > if (status) > goto out; > - decode_getfattr(xdr, res->fattr, res->server); > + decode_getfattr(xdr, res->fattr, res->label, res->server); > out: > return status; > } > @@ -6506,7 +6620,7 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr, > if (status) > goto out; > if (res->fattr) > - decode_getfattr(xdr, res->fattr, res->server); > + decode_getfattr(xdr, res->fattr, NULL, res->server); > if (!status) > status = res->count; > out: > @@ -6687,7 +6801,7 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, > status = decode_putfh(xdr); > if (status != 0) > goto out; > - status = decode_getfattr(xdr, res->fattr, res->server); > + status = decode_getfattr(xdr, res->fattr, res->label, res->server); > if (status != 0) > goto out; > status = decode_delegreturn(xdr); > @@ -6720,7 +6834,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, > xdr_enter_page(xdr, PAGE_SIZE); > status = decode_getfattr_generic(xdr, &res->fs_locations->fattr, > NULL, res->fs_locations, > - res->fs_locations->server); > + NULL, res->fs_locations->server); > out: > return status; > } > @@ -7001,7 +7115,7 @@ static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp, > status = decode_layoutcommit(xdr, rqstp, res); > if (status) > goto out; > - decode_getfattr(xdr, res->fattr, res->server); > + decode_getfattr(xdr, res->fattr, NULL, res->server); > out: > return status; > } > @@ -7133,7 +7247,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, > goto out_overflow; > > if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, > - NULL, entry->server) < 0) > + NULL, entry->label, entry->server) < 0) > goto out_overflow; > if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) > entry->ino = entry->fattr->mounted_on_fileid; > diff --git a/fs/nfs/super.c b/fs/nfs/super.c > index 86442f4..5cf7ee5 100644 > --- a/fs/nfs/super.c > +++ b/fs/nfs/super.c > @@ -2419,8 +2419,21 @@ static int nfs_bdi_register(struct nfs_server *server) > int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot, > struct nfs_mount_info *mount_info) > { > - return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts, > - 0, NULL); > + int error; > + unsigned long kflags = 0, kflags_out = 0; > + if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL) > + kflags |= SECURITY_LSM_NATIVE_LABELS; > + > + error = security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts, > + kflags, &kflags_out); > + if (error) > + goto err; > + > + if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL && > + !(kflags_out & SECURITY_LSM_NATIVE_LABELS)) > + NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL; > +err: > + return error; > } > EXPORT_SYMBOL_GPL(nfs_set_sb_security); > > diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h > index 9082979..822ca73 100644 > --- a/include/linux/nfs_fs.h > +++ b/include/linux/nfs_fs.h > @@ -199,6 +199,7 @@ struct nfs_inode { > #define NFS_INO_INVALID_ACL 0x0010 /* cached acls are invalid */ > #define NFS_INO_REVAL_PAGECACHE 0x0020 /* must revalidate pagecache */ > #define NFS_INO_REVAL_FORCED 0x0040 /* force revalidation ignoring a delegation */ > +#define NFS_INO_INVALID_LABEL 0x0080 /* cached label is invalid */ > > /* > * Bit offsets in flags field > @@ -344,6 +345,8 @@ extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); > extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping); > extern int nfs_setattr(struct dentry *, struct iattr *); > extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr); > +extern void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, > + struct nfs4_label *label); > extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); > extern void put_nfs_open_context(struct nfs_open_context *ctx); > extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode); > diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h > index e6ed3c2..2a4f1d4 100644 > --- a/include/linux/nfs_fs_sb.h > +++ b/include/linux/nfs_fs_sb.h > @@ -145,11 +145,18 @@ struct nfs_server { > u32 attr_bitmask[3];/* V4 bitmask representing the set > of attributes supported on this > filesystem */ > + u32 attr_bitmask_nl[3]; > + /* V4 bitmask representing the > + set of attributes supported > + on this filesystem excluding > + the label support bit. */ Can't we just have attr_bitmask_nl point to attr_bitmask when not #ifdef CONFIG_NFS_V4_SECURITY_LABEL? > u32 cache_consistency_bitmask[3]; > /* V4 bitmask representing the subset > of change attribute, size, ctime > and mtime attributes supported by > the server */ > + u32 cache_consistency_bitmask_nl[3]; > + /* As above, excluding label. */ Ditto... > u32 acl_bitmask; /* V4 bitmask representing the ACEs > that are supported on this > filesystem */ > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c > index 8f233ff..3e1b84d 100644 > --- a/security/selinux/hooks.c > +++ b/security/selinux/hooks.c > @@ -2876,7 +2876,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; > } > > @@ -2964,6 +2967,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name, > if (rc) > return rc; > > + isec->sclass = inode_mode_to_security_class(inode->i_mode); > isec->sid = newsid; > isec->initialized = 1; > return 0; -- Trond Myklebust Linux NFS client maintainer NetApp Trond.Myklebust@netapp.com www.netapp.com