From: "J. Bruce Fields" <bfields@fieldses.org>
To: Steve Dickson <SteveD@redhat.com>
Cc: Trond Myklebust <Trond.Myklebust@netapp.com>,
"J. Bruce Fields" <bfields@redhat.com>,
"David P. Quigley" <dpquigl@tycho.nsa.gov>,
Linux NFS list <linux-nfs@vger.kernel.org>,
Linux FS devel list <linux-fsdevel@vger.kernel.org>,
Linux Security List <linux-security-module@vger.kernel.org>,
SELinux List <selinux@tycho.nsa.gov>
Subject: Re: [PATCH 10/15] NFS: Client implementation of Labeled-NFS
Date: Tue, 12 Feb 2013 18:03:46 -0500 [thread overview]
Message-ID: <20130212230346.GN10267@fieldses.org> (raw)
In-Reply-To: <1360327163-20360-11-git-send-email-SteveD@redhat.com>
On Fri, Feb 08, 2013 at 07:39:18AM -0500, Steve Dickson wrote:
> From: David Quigley <dpquigl@davequigley.com>
>
> This patch implements the client transport and handling support for labeled
> NFS. The patch adds two functions to encode and decode the security label
> recommended attribute which makes use of the LSM hooks added earlier. It also
> adds code to grab the label from the file attribute structures and encode the
> label to be sent back to the server.
>
> Signed-off-by: Matthew N. Dodd <Matthew.Dodd@sparta.com>
> Signed-off-by: Miguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
> Signed-off-by: Phua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
> Signed-off-by: Khin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
> ---
> fs/nfs/inode.c | 55 ++++++++-
> fs/nfs/nfs4proc.c | 298 ++++++++++++++++++++++++++++++++++++++++++++--
> fs/nfs/nfs4xdr.c | 179 ++++++++++++++++++++++------
> fs/nfs/super.c | 17 ++-
> include/linux/nfs_fs.h | 3 +
> include/linux/nfs_fs_sb.h | 7 ++
> security/selinux/hooks.c | 4 +
> 7 files changed, 507 insertions(+), 56 deletions(-)
>
> diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> index 0cb67cf..0d412c4 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(struct nfs_server *server, gfp_t flags)
> {
> struct nfs4_label *label = NULL;
> @@ -286,7 +312,15 @@ void nfs4_label_init(struct nfs4_label *label)
> return;
> }
> EXPORT_SYMBOL_GPL(nfs4_label_init);
> +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
> @@ -415,6 +449,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;
> @@ -777,6 +814,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)
> {
> @@ -905,7 +943,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);
> @@ -1504,6 +1543,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;
> @@ -1525,7 +1567,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;
> @@ -1538,6 +1580,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 5c9233d1..280bb22 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -87,6 +87,39 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
> static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *);
> static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *);
> #endif
> +
> +#ifdef CONFIG_NFS_V4_SECURITY_LABEL
> +static inline struct nfs4_label *
> +nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
> + struct iattr *sattr, struct nfs4_label *l)
> +{
> + int err;
> +
> + if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL)) {
> + err = security_dentry_init_security(dentry, sattr->ia_mode,
> + &dentry->d_name, (void **)&l->label, &l->len);
> + if (err == 0)
> + return l;
> + }
> + return NULL;
> +}
> +static inline void
> +nfs4_label_release_security(struct nfs4_label *label)
> +{
> + if (label)
> + security_release_secctx(label->label, label->len);
> +}
> +#else
> +static inline struct nfs4_label *
> +nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
> + struct iattr *sattr, struct nfs4_label *l)
> +{ return NULL; }
> +
> +static inline void
> +nfs4_label_release_security(struct nfs4_label *label)
> +{ return; }
> +#endif
> +
> /* Prevent leaks of NFSv4 errors into userland */
> static int nfs4_map_errors(int err)
> {
> @@ -131,7 +164,8 @@ const u32 nfs4_fattr_bitmap[3] = {
> | FATTR4_WORD1_SPACE_USED
> | FATTR4_WORD1_TIME_ACCESS
> | FATTR4_WORD1_TIME_METADATA
> - | FATTR4_WORD1_TIME_MODIFY
> + | FATTR4_WORD1_TIME_MODIFY,
> + FATTR4_WORD2_SECURITY_LABEL
> };
>
> static const u32 nfs4_pnfs_open_bitmap[3] = {
> @@ -1939,6 +1973,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);
> }
> }
>
> @@ -2052,6 +2087,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) {
> @@ -2279,7 +2317,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;
> @@ -2309,11 +2347,16 @@ 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;
> +
> + label = nfs4_label_init_security(dir, ctx->dentry, attr, &l);
>
> /* Protect against concurrent sillydeletes */
> state = nfs4_do_open(dir, ctx->dentry, ctx->mode, open_flags, attr, label,
> ctx->cred, &ctx->mdsthreshold);
> +
> + nfs4_label_release_security(label);
> +
> if (IS_ERR(state))
> return ERR_CAST(state);
> ctx->state = state;
> @@ -2373,10 +2416,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;
> }
> @@ -2399,8 +2459,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,
> @@ -2413,6 +2474,13 @@ 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];
> + /*
> + * Process the label in the upcoming getfattr
> + */
> + bitmask[2] = nfs4_fattr_bitmap[2] & ~FATTR4_WORD2_SECURITY_LABEL;
> +
> nfs_fattr_init(info->fattr);
> return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
> }
> @@ -2599,7 +2667,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);
> }
> @@ -2694,6 +2765,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 = {
> @@ -2702,6 +2774,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);
> @@ -2808,7 +2883,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...
> @@ -2923,7 +2998,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;
> @@ -2932,6 +3007,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
> if (IS_ERR(ctx))
> return PTR_ERR(ctx);
>
> + ilabel = nfs4_label_init_security(dir, dentry, sattr, &l);
> +
> sattr->ia_mode &= ~current_umask();
> state = nfs4_do_open(dir, dentry, ctx->mode,
> flags, sattr, ilabel, ctx->cred,
> @@ -2945,6 +3022,7 @@ 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:
> + nfs4_label_release_security(ilabel);
> put_nfs_open_context(ctx);
> return status;
> }
> @@ -2994,6 +3072,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)
> @@ -3263,14 +3343,19 @@ 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;
> +
> + label = nfs4_label_init_security(dir, dentry, sattr, &l);
> +
> do {
> err = nfs4_handle_exception(NFS_SERVER(dir),
> _nfs4_proc_symlink(dir, dentry, page,
> len, sattr, label),
> &exception);
> } while (exception.retry);
> +
> + nfs4_label_release_security(label);
> return err;
> }
>
> @@ -3296,15 +3381,19 @@ 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;
>
> + label = nfs4_label_init_security(dir, dentry, sattr, &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);
> + nfs4_label_release_security(label);
> +
> return err;
> }
>
> @@ -3320,7 +3409,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,
> @@ -3400,15 +3491,20 @@ 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;
>
> + label = nfs4_label_init_security(dir, dentry, sattr, &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);
> +
> + nfs4_label_release_security(label);
> +
> return err;
> }
>
> @@ -3624,7 +3720,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
>
> if (!data->write_done_cb)
> data->write_done_cb = nfs4_write_done_cb;
> @@ -4049,6 +4149,178 @@ 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 = {0, 0, buflen, buf};
> + 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;
> +
> + 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 = {0};
> + 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;
> +
> + 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(NFS_SERVER(inode), GFP_KERNEL);
> + if (IS_ERR(olabel)) {
> + status = -PTR_ERR(olabel);
> + 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)
> {
> @@ -4337,7 +4609,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..3725433 100644
> --- a/fs/nfs/nfs4xdr.c
> +++ b/fs/nfs/nfs4xdr.c
> @@ -102,12 +102,23 @@ 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))
> +#define encode_readdir_space 24
> +#define encode_readdir_bitmask_sz 3
> +#else
> +#define nfs4_label_maxsz 0
> +#define encode_readdir_space 20
> +#define encode_readdir_bitmask_sz 2
> +#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 +126,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 +204,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 +986,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 +1038,8 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
> }
> len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
> }
> + if (label)
> + 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 +1096,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) {
> + 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 +1169,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 +1402,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 +1597,34 @@ 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);
> - p = reserve_space(xdr, 20);
> + p = reserve_space(xdr, encode_readdir_space);
> *p++ = cpu_to_be32(dircount);
> *p++ = cpu_to_be32(readdir->count);
> - *p++ = cpu_to_be32(2);
> -
> + *p++ = cpu_to_be32(encode_readdir_bitmask_sz);
> *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]);
> - *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
> + *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
> + if (encode_readdir_bitmask_sz > 2) {
> + p++, *p++ = cpu_to_be32(readdir->bitmask[2]);
> + }
> 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 +1683,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 +4101,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) {
If I remember the earlier patch right, nfs4_label_init() just set
label->len to NFS4_MAXLABELLEN.
Doesn't that overwrite the length that was passed into
nfs4_get_security_label?
This doesn't seem right.
--b.
> + 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 +4504,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 +4612,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 +4624,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 +4643,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 +4655,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 +5991,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 +6017,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 +6046,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 +6072,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 +6164,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 +6193,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 +6225,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 +6327,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 +6358,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 +6408,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 +6435,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 +6615,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 +6796,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 +6829,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 +7110,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 +7242,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 c98b434..4e78f93 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 41b0b6d..ff4f72a 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. */
> 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. */
> 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 dda436f..af947f8 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;
> --
> 1.7.11.7
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2013-02-12 23:03 UTC|newest]
Thread overview: 47+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-02-08 12:39 [PATCH 00/15] lnfs: 3.8-rc6 release Steve Dickson
2013-02-08 12:39 ` [PATCH 01/15] Security: Add hook to calculate context based on a negative dentry Steve Dickson
2013-02-08 12:39 ` [PATCH 02/15] Security: Add Hook to test if the particular xattr is part of a MAC model Steve Dickson
2013-02-08 12:39 ` [PATCH 03/15] LSM: Add flags field to security_sb_set_mnt_opts for in kernel mount data Steve Dickson
2013-02-08 12:39 ` [PATCH 04/15] SELinux: Add new labeling type native labels Steve Dickson
2013-02-08 12:39 ` [PATCH 05/15] NFSv4: Add label recommended attribute and NFSv4 flags Steve Dickson
2013-02-08 12:39 ` [PATCH 06/15] NFSv4: Introduce new label structure Steve Dickson
2013-02-12 22:07 ` J. Bruce Fields
[not found] ` <20130212220741.GJ10267-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
2013-02-12 22:28 ` Myklebust, Trond
2013-02-12 22:32 ` J. Bruce Fields
2013-02-12 22:40 ` Myklebust, Trond
2013-02-12 23:06 ` J. Bruce Fields
2013-02-13 0:30 ` Steve Dickson
2013-02-08 12:39 ` [PATCH 07/15] NFSv4: Extend fattr bitmaps to support all 3 words Steve Dickson
2013-02-08 12:39 ` [PATCH 08/15] NFS:Add labels to client function prototypes Steve Dickson
2013-02-08 12:39 ` [PATCH 09/15] NFS: Add label lifecycle management Steve Dickson
2013-02-12 22:27 ` J. Bruce Fields
2013-02-16 20:28 ` Steve Dickson
[not found] ` <1360327163-20360-1-git-send-email-SteveD-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-02-08 12:39 ` [PATCH 10/15] NFS: Client implementation of Labeled-NFS Steve Dickson
2013-02-12 23:03 ` J. Bruce Fields [this message]
2013-02-16 20:35 ` Steve Dickson
[not found] ` <511FED8E.7020308-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
2013-02-16 22:30 ` J. Bruce Fields
2013-02-17 1:24 ` Steve Dickson
2013-02-17 1:47 ` Steve Dickson
2013-02-08 12:39 ` [PATCH 11/15] NFS: Extend NFS xattr handlers to accept the security namespace Steve Dickson
2013-02-08 12:39 ` [PATCH 12/15] lnfs: Do not sleep holding the inode spin lock Steve Dickson
[not found] ` <1360327163-20360-13-git-send-email-SteveD-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2013-02-13 15:16 ` J. Bruce Fields
[not found] ` <20130213151610.GI14195-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
2013-02-16 20:36 ` Steve Dickson
2013-02-08 12:39 ` [PATCH 13/15] Kconfig: Add Kconfig entry for Labeled NFS V4 client Steve Dickson
2013-02-08 12:39 ` [PATCH 14/15] NFSD: Server implementation of MAC Labeling Steve Dickson
2013-02-12 22:54 ` J. Bruce Fields
2013-02-12 23:07 ` J. Bruce Fields
[not found] ` <20130212225425.GM10267-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
2013-02-16 20:44 ` Steve Dickson
[not found] ` <511FEFCB.2090002-AfCzQyP5zfLQT0dZR+AlfA@public.gmane.org>
2013-02-16 22:34 ` J. Bruce Fields
2013-02-08 12:39 ` [PATCH 15/15] Kconfig: Add Kconfig entry for Labeled NFS V4 server Steve Dickson
2013-02-12 21:41 ` [PATCH 00/15] lnfs: 3.8-rc6 release J. Bruce Fields
2013-02-12 22:02 ` Casey Schaufler
2013-02-12 22:13 ` J. Bruce Fields
2013-02-13 0:32 ` Steve Dickson
2013-02-13 0:55 ` Casey Schaufler
2013-02-12 23:11 ` J. Bruce Fields
[not found] ` <20130212231113.GQ10267-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
2013-02-12 23:18 ` Myklebust, Trond
2013-02-13 0:11 ` J. Bruce Fields
2013-02-13 0:21 ` J. Bruce Fields
2013-02-13 0:28 ` Steve Dickson
2013-02-13 15:05 ` J. Bruce Fields
2013-02-13 15:33 ` J. Bruce Fields
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20130212230346.GN10267@fieldses.org \
--to=bfields@fieldses.org \
--cc=SteveD@redhat.com \
--cc=Trond.Myklebust@netapp.com \
--cc=bfields@redhat.com \
--cc=dpquigl@tycho.nsa.gov \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=selinux@tycho.nsa.gov \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).