Commit aa9c2669 authored by David Quigley's avatar David Quigley Committed by Trond Myklebust

NFS: Client implementation of Labeled-NFS

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.
Acked-by: default avatarJames Morris <james.l.morris@oracle.com>
Signed-off-by: default avatarMatthew N. Dodd <Matthew.Dodd@sparta.com>
Signed-off-by: default avatarMiguel Rodel Felipe <Rodel_FM@dsi.a-star.edu.sg>
Signed-off-by: default avatarPhua Eu Gene <PHUA_Eu_Gene@dsi.a-star.edu.sg>
Signed-off-by: default avatarKhin Mi Mi Aung <Mi_Mi_AUNG@dsi.a-star.edu.sg>
Signed-off-by: default avatarSteve Dickson <steved@redhat.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 14c43f76
...@@ -435,6 +435,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) ...@@ -435,6 +435,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
struct dentry *alias; struct dentry *alias;
struct inode *dir = parent->d_inode; struct inode *dir = parent->d_inode;
struct inode *inode; struct inode *inode;
int status;
if (filename.name[0] == '.') { if (filename.name[0] == '.') {
if (filename.len == 1) if (filename.len == 1)
...@@ -447,7 +448,9 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) ...@@ -447,7 +448,9 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
dentry = d_lookup(parent, &filename); dentry = d_lookup(parent, &filename);
if (dentry != NULL) { if (dentry != NULL) {
if (nfs_same_file(dentry, entry)) { if (nfs_same_file(dentry, entry)) {
nfs_refresh_inode(dentry->d_inode, entry->fattr); status = nfs_refresh_inode(dentry->d_inode, entry->fattr);
if (!status)
nfs_setsecurity(dentry->d_inode, entry->fattr, entry->label);
goto out; goto out;
} else { } else {
if (d_invalidate(dentry) != 0) if (d_invalidate(dentry) != 0)
...@@ -1103,6 +1106,8 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) ...@@ -1103,6 +1106,8 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
if ((error = nfs_refresh_inode(inode, fattr)) != 0) if ((error = nfs_refresh_inode(inode, fattr)) != 0)
goto out_bad; goto out_bad;
nfs_setsecurity(inode, fattr, label);
nfs_free_fattr(fattr); nfs_free_fattr(fattr);
nfs_free_fhandle(fhandle); nfs_free_fhandle(fhandle);
nfs4_label_free(label); nfs4_label_free(label);
......
...@@ -162,11 +162,19 @@ static void nfs_zap_caches_locked(struct inode *inode) ...@@ -162,11 +162,19 @@ static void nfs_zap_caches_locked(struct inode *inode)
memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf)); memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf));
if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { 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); nfs_fscache_invalidate(inode);
} else { nfsi->cache_validity |= NFS_INO_INVALID_ATTR
nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; | 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) void nfs_zap_caches(struct inode *inode)
...@@ -258,6 +266,32 @@ nfs_init_locked(struct inode *inode, void *opaque) ...@@ -258,6 +266,32 @@ nfs_init_locked(struct inode *inode, void *opaque)
} }
#ifdef CONFIG_NFS_V4_SECURITY_LABEL #ifdef CONFIG_NFS_V4_SECURITY_LABEL
void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
struct nfs4_label *label)
{
int error;
if (label == NULL)
return;
if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL) == 0)
return;
if (NFS_SERVER(inode)->nfs_client->cl_minorversion < 2)
return;
if ((fattr->valid & NFS_ATTR_FATTR_V4_SECURITY_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 *nfs4_label_alloc(struct nfs_server *server, gfp_t flags)
{ {
struct nfs4_label *label = NULL; struct nfs4_label *label = NULL;
...@@ -283,7 +317,13 @@ struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags) ...@@ -283,7 +317,13 @@ struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags)
return label; return label;
} }
EXPORT_SYMBOL_GPL(nfs4_label_alloc); EXPORT_SYMBOL_GPL(nfs4_label_alloc);
#else
void inline nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
struct nfs4_label *label)
{
}
#endif #endif
EXPORT_SYMBOL_GPL(nfs_setsecurity);
/* /*
* This is our front-end to iget that looks up inodes by file handle * This is our front-end to iget that looks up inodes by file handle
...@@ -412,6 +452,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st ...@@ -412,6 +452,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); inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
} }
nfs_setsecurity(inode, fattr, label);
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
nfsi->attrtimeo_timestamp = now; nfsi->attrtimeo_timestamp = now;
nfsi->access_cache = RB_ROOT; nfsi->access_cache = RB_ROOT;
...@@ -421,6 +464,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st ...@@ -421,6 +464,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
unlock_new_inode(inode); unlock_new_inode(inode);
} else } else
nfs_refresh_inode(inode, fattr); nfs_refresh_inode(inode, fattr);
nfs_setsecurity(inode, fattr, label);
dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n", dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n",
inode->i_sb->s_id, inode->i_sb->s_id,
(long long)NFS_FILEID(inode), (long long)NFS_FILEID(inode),
...@@ -477,7 +521,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -477,7 +521,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
NFS_PROTO(inode)->return_delegation(inode); NFS_PROTO(inode)->return_delegation(inode);
error = NFS_PROTO(inode)->setattr(dentry, fattr, attr); error = NFS_PROTO(inode)->setattr(dentry, fattr, attr);
if (error == 0) if (error == 0)
nfs_refresh_inode(inode, fattr); error = nfs_refresh_inode(inode, fattr);
nfs_free_fattr(fattr); nfs_free_fattr(fattr);
out: out:
return error; return error;
...@@ -901,7 +945,8 @@ static int nfs_attribute_cache_expired(struct inode *inode) ...@@ -901,7 +945,8 @@ static int nfs_attribute_cache_expired(struct inode *inode)
*/ */
int nfs_revalidate_inode(struct nfs_server *server, 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)) && !nfs_attribute_cache_expired(inode))
return NFS_STALE(inode) ? -ESTALE : 0; return NFS_STALE(inode) ? -ESTALE : 0;
return __nfs_revalidate_inode(server, inode); return __nfs_revalidate_inode(server, inode);
...@@ -1281,6 +1326,7 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1281,6 +1326,7 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
status = nfs_post_op_update_inode_locked(inode, fattr); status = nfs_post_op_update_inode_locked(inode, fattr);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
return status; return status;
} }
EXPORT_SYMBOL_GPL(nfs_post_op_update_inode); EXPORT_SYMBOL_GPL(nfs_post_op_update_inode);
...@@ -1521,7 +1567,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1521,7 +1567,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
inode->i_blocks = fattr->du.nfs2.blocks; inode->i_blocks = fattr->du.nfs2.blocks;
/* Update attrtimeo value if we're out of the unstable period */ /* 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); nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
nfsi->attrtimeo_timestamp = now; nfsi->attrtimeo_timestamp = now;
...@@ -1534,6 +1580,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) ...@@ -1534,6 +1580,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
} }
} }
invalid &= ~NFS_INO_INVALID_ATTR; invalid &= ~NFS_INO_INVALID_ATTR;
invalid &= ~NFS_INO_INVALID_LABEL;
/* Don't invalidate the data if we were to blame */ /* Don't invalidate the data if we were to blame */
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
|| S_ISLNK(inode->i_mode))) || S_ISLNK(inode->i_mode)))
......
This diff is collapsed.
This diff is collapsed.
...@@ -2417,8 +2417,21 @@ static int nfs_bdi_register(struct nfs_server *server) ...@@ -2417,8 +2417,21 @@ static int nfs_bdi_register(struct nfs_server *server)
int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot, int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot,
struct nfs_mount_info *mount_info) struct nfs_mount_info *mount_info)
{ {
return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts, int error;
0, NULL); 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); EXPORT_SYMBOL_GPL(nfs_set_sb_security);
......
...@@ -207,6 +207,7 @@ struct nfs_inode { ...@@ -207,6 +207,7 @@ struct nfs_inode {
#define NFS_INO_INVALID_ACL 0x0010 /* cached acls are invalid */ #define NFS_INO_INVALID_ACL 0x0010 /* cached acls are invalid */
#define NFS_INO_REVAL_PAGECACHE 0x0020 /* must revalidate pagecache */ #define NFS_INO_REVAL_PAGECACHE 0x0020 /* must revalidate pagecache */
#define NFS_INO_REVAL_FORCED 0x0040 /* force revalidation ignoring a delegation */ #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 * Bit offsets in flags field
...@@ -352,6 +353,8 @@ extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); ...@@ -352,6 +353,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_revalidate_mapping(struct inode *inode, struct address_space *mapping);
extern int nfs_setattr(struct dentry *, struct iattr *); extern int nfs_setattr(struct dentry *, struct iattr *);
extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr); 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 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 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); extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode);
......
...@@ -146,6 +146,11 @@ struct nfs_server { ...@@ -146,6 +146,11 @@ struct nfs_server {
u32 attr_bitmask[3];/* V4 bitmask representing the set u32 attr_bitmask[3];/* V4 bitmask representing the set
of attributes supported on this of attributes supported on this
filesystem */ 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]; u32 cache_consistency_bitmask[3];
/* V4 bitmask representing the subset /* V4 bitmask representing the subset
of change attribute, size, ctime of change attribute, size, ctime
......
...@@ -2908,7 +2908,10 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, ...@@ -2908,7 +2908,10 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
return; return;
} }
isec->sclass = inode_mode_to_security_class(inode->i_mode);
isec->sid = newsid; isec->sid = newsid;
isec->initialized = 1;
return; return;
} }
...@@ -2996,6 +2999,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name, ...@@ -2996,6 +2999,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
if (rc) if (rc)
return rc; return rc;
isec->sclass = inode_mode_to_security_class(inode->i_mode);
isec->sid = newsid; isec->sid = newsid;
isec->initialized = 1; isec->initialized = 1;
return 0; return 0;
......
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