Merge branch 'labeled-nfs' into linux-next
* labeled-nfs: NFS: Apply v4.1 capabilities to v4.2 NFS: Add in v4.2 callback operation NFS: Make callbacks minor version generic Kconfig: Add Kconfig entry for Labeled NFS V4 client NFS: Extend NFS xattr handlers to accept the security namespace NFS: Client implementation of Labeled-NFS NFS: Add label lifecycle management NFS:Add labels to client function prototypes NFSv4: Extend fattr bitmaps to support all 3 words NFSv4: Introduce new label structure NFSv4: Add label recommended attribute and NFSv4 flags NFSv4.2: Added NFS v4.2 support to the NFS client SELinux: Add new labeling type native labels LSM: Add flags field to security_sb_set_mnt_opts for in kernel mount data. Security: Add Hook to test if the particular xattr is part of a MAC model. Security: Add hook to calculate context based on a negative dentry. NFS: Add NFSv4.2 protocol constants Conflicts: fs/nfs/nfs4proc.c
This commit is contained in:
commit
959d921f5e
|
@ -104,6 +104,15 @@ config NFS_V4_1
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
config NFS_V4_2
|
||||
bool "NFS client support for NFSv4.2"
|
||||
depends on NFS_V4_1
|
||||
help
|
||||
This option enables support for minor version 2 of the NFSv4 protocol
|
||||
in the kernel's NFS client.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config PNFS_FILE_LAYOUT
|
||||
tristate
|
||||
depends on NFS_V4_1
|
||||
|
@ -131,6 +140,11 @@ config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN
|
|||
If the NFS client is unchanged from the upstream kernel, this
|
||||
option should be set to the default "kernel.org".
|
||||
|
||||
config NFS_V4_SECURITY_LABEL
|
||||
bool
|
||||
depends on NFS_V4_2 && SECURITY
|
||||
default y
|
||||
|
||||
config ROOT_NFS
|
||||
bool "Root file system on NFS"
|
||||
depends on NFS_FS=y && IP_PNP
|
||||
|
|
|
@ -282,6 +282,7 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, struct n
|
|||
ret = nfs4_callback_up_net(serv, net);
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
ret = nfs41_callback_up_net(serv, net);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -32,6 +32,8 @@ enum nfs4_callback_opnum {
|
|||
OP_CB_WANTS_CANCELLED = 12,
|
||||
OP_CB_NOTIFY_LOCK = 13,
|
||||
OP_CB_NOTIFY_DEVICEID = 14,
|
||||
/* Callback operations new to NFSv4.2 */
|
||||
OP_CB_OFFLOAD = 15,
|
||||
OP_CB_ILLEGAL = 10044,
|
||||
};
|
||||
|
||||
|
@ -39,6 +41,7 @@ struct cb_process_state {
|
|||
__be32 drc_status;
|
||||
struct nfs_client *clp;
|
||||
u32 slotid;
|
||||
u32 minorversion;
|
||||
struct net *net;
|
||||
};
|
||||
|
||||
|
|
|
@ -406,7 +406,8 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
|
|||
int i;
|
||||
__be32 status = htonl(NFS4ERR_BADSESSION);
|
||||
|
||||
clp = nfs4_find_client_sessionid(cps->net, args->csa_addr, &args->csa_sessionid);
|
||||
clp = nfs4_find_client_sessionid(cps->net, args->csa_addr,
|
||||
&args->csa_sessionid, cps->minorversion);
|
||||
if (clp == NULL)
|
||||
goto out;
|
||||
|
||||
|
|
|
@ -166,9 +166,9 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound
|
|||
if (unlikely(p == NULL))
|
||||
return htonl(NFS4ERR_RESOURCE);
|
||||
hdr->minorversion = ntohl(*p++);
|
||||
/* Check minor version is zero or one. */
|
||||
if (hdr->minorversion <= 1) {
|
||||
hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 */
|
||||
/* Check for minor version support */
|
||||
if (hdr->minorversion <= NFS4_MAX_MINOR_VERSION) {
|
||||
hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 and v4.2 */
|
||||
} else {
|
||||
pr_warn_ratelimited("NFS: %s: NFSv4 server callback with "
|
||||
"illegal minor version %u!\n",
|
||||
|
@ -786,6 +786,26 @@ static void nfs4_cb_free_slot(struct cb_process_state *cps)
|
|||
}
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
static __be32
|
||||
preprocess_nfs42_op(int nop, unsigned int op_nr, struct callback_op **op)
|
||||
{
|
||||
__be32 status = preprocess_nfs41_op(nop, op_nr, op);
|
||||
if (status != htonl(NFS4ERR_OP_ILLEGAL))
|
||||
return status;
|
||||
|
||||
if (op_nr == OP_CB_OFFLOAD)
|
||||
return htonl(NFS4ERR_NOTSUPP);
|
||||
return htonl(NFS4ERR_OP_ILLEGAL);
|
||||
}
|
||||
#else /* CONFIG_NFS_V4_2 */
|
||||
static __be32
|
||||
preprocess_nfs42_op(int nop, unsigned int op_nr, struct callback_op **op)
|
||||
{
|
||||
return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_2 */
|
||||
|
||||
static __be32
|
||||
preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op)
|
||||
{
|
||||
|
@ -801,8 +821,7 @@ preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op)
|
|||
return htonl(NFS_OK);
|
||||
}
|
||||
|
||||
static __be32 process_op(uint32_t minorversion, int nop,
|
||||
struct svc_rqst *rqstp,
|
||||
static __be32 process_op(int nop, struct svc_rqst *rqstp,
|
||||
struct xdr_stream *xdr_in, void *argp,
|
||||
struct xdr_stream *xdr_out, void *resp,
|
||||
struct cb_process_state *cps)
|
||||
|
@ -819,10 +838,22 @@ static __be32 process_op(uint32_t minorversion, int nop,
|
|||
return status;
|
||||
|
||||
dprintk("%s: minorversion=%d nop=%d op_nr=%u\n",
|
||||
__func__, minorversion, nop, op_nr);
|
||||
__func__, cps->minorversion, nop, op_nr);
|
||||
|
||||
switch (cps->minorversion) {
|
||||
case 0:
|
||||
status = preprocess_nfs4_op(op_nr, &op);
|
||||
break;
|
||||
case 1:
|
||||
status = preprocess_nfs41_op(nop, op_nr, &op);
|
||||
break;
|
||||
case 2:
|
||||
status = preprocess_nfs42_op(nop, op_nr, &op);
|
||||
break;
|
||||
default:
|
||||
status = htonl(NFS4ERR_MINOR_VERS_MISMATCH);
|
||||
}
|
||||
|
||||
status = minorversion ? preprocess_nfs41_op(nop, op_nr, &op) :
|
||||
preprocess_nfs4_op(op_nr, &op);
|
||||
if (status == htonl(NFS4ERR_OP_ILLEGAL))
|
||||
op_nr = OP_CB_ILLEGAL;
|
||||
if (status)
|
||||
|
@ -885,14 +916,15 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
|
|||
return rpc_drop_reply;
|
||||
}
|
||||
|
||||
cps.minorversion = hdr_arg.minorversion;
|
||||
hdr_res.taglen = hdr_arg.taglen;
|
||||
hdr_res.tag = hdr_arg.tag;
|
||||
if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0)
|
||||
return rpc_system_err;
|
||||
|
||||
while (status == 0 && nops != hdr_arg.nops) {
|
||||
status = process_op(hdr_arg.minorversion, nops, rqstp,
|
||||
&xdr_in, argp, &xdr_out, resp, &cps);
|
||||
status = process_op(nops, rqstp, &xdr_in,
|
||||
argp, &xdr_out, resp, &cps);
|
||||
nops++;
|
||||
}
|
||||
|
||||
|
|
|
@ -1074,7 +1074,7 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
|
|||
}
|
||||
|
||||
if (!(fattr->valid & NFS_ATTR_FATTR)) {
|
||||
error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh, fattr);
|
||||
error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh, fattr, NULL);
|
||||
if (error < 0) {
|
||||
dprintk("nfs_create_server: getattr error = %d\n", -error);
|
||||
goto error;
|
||||
|
|
49
fs/nfs/dir.c
49
fs/nfs/dir.c
|
@ -435,6 +435,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
|
|||
struct dentry *alias;
|
||||
struct inode *dir = parent->d_inode;
|
||||
struct inode *inode;
|
||||
int status;
|
||||
|
||||
if (filename.name[0] == '.') {
|
||||
if (filename.len == 1)
|
||||
|
@ -447,7 +448,9 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
|
|||
dentry = d_lookup(parent, &filename);
|
||||
if (dentry != NULL) {
|
||||
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;
|
||||
} else {
|
||||
if (d_invalidate(dentry) != 0)
|
||||
|
@ -460,7 +463,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
|
|||
if (dentry == NULL)
|
||||
return;
|
||||
|
||||
inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr);
|
||||
inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr, entry->label);
|
||||
if (IS_ERR(inode))
|
||||
goto out;
|
||||
|
||||
|
@ -585,10 +588,16 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
|
|||
if (entry.fh == NULL || entry.fattr == NULL)
|
||||
goto out;
|
||||
|
||||
entry.label = nfs4_label_alloc(NFS_SERVER(inode), GFP_NOWAIT);
|
||||
if (IS_ERR(entry.label)) {
|
||||
status = PTR_ERR(entry.label);
|
||||
goto out;
|
||||
}
|
||||
|
||||
array = nfs_readdir_get_array(page);
|
||||
if (IS_ERR(array)) {
|
||||
status = PTR_ERR(array);
|
||||
goto out;
|
||||
goto out_label_free;
|
||||
}
|
||||
memset(array, 0, sizeof(struct nfs_cache_array));
|
||||
array->eof_index = -1;
|
||||
|
@ -614,6 +623,8 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
|
|||
nfs_readdir_free_large_page(pages_ptr, pages, array_size);
|
||||
out_release_array:
|
||||
nfs_readdir_release_array(page);
|
||||
out_label_free:
|
||||
nfs4_label_free(entry.label);
|
||||
out:
|
||||
nfs_free_fattr(entry.fattr);
|
||||
nfs_free_fhandle(entry.fh);
|
||||
|
@ -1040,6 +1051,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
|
|||
struct dentry *parent;
|
||||
struct nfs_fh *fhandle = NULL;
|
||||
struct nfs_fattr *fattr = NULL;
|
||||
struct nfs4_label *label = NULL;
|
||||
int error;
|
||||
|
||||
if (flags & LOOKUP_RCU)
|
||||
|
@ -1082,7 +1094,11 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
|
|||
if (fhandle == NULL || fattr == NULL)
|
||||
goto out_error;
|
||||
|
||||
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
|
||||
label = nfs4_label_alloc(NFS_SERVER(inode), GFP_NOWAIT);
|
||||
if (IS_ERR(label))
|
||||
goto out_error;
|
||||
|
||||
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
|
||||
if (error)
|
||||
goto out_bad;
|
||||
if (nfs_compare_fh(NFS_FH(inode), fhandle))
|
||||
|
@ -1090,8 +1106,12 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
|
|||
if ((error = nfs_refresh_inode(inode, fattr)) != 0)
|
||||
goto out_bad;
|
||||
|
||||
nfs_setsecurity(inode, fattr, label);
|
||||
|
||||
nfs_free_fattr(fattr);
|
||||
nfs_free_fhandle(fhandle);
|
||||
nfs4_label_free(label);
|
||||
|
||||
out_set_verifier:
|
||||
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
|
||||
out_valid:
|
||||
|
@ -1108,6 +1128,7 @@ out_zap_parent:
|
|||
out_bad:
|
||||
nfs_free_fattr(fattr);
|
||||
nfs_free_fhandle(fhandle);
|
||||
nfs4_label_free(label);
|
||||
nfs_mark_for_revalidate(dir);
|
||||
if (inode && S_ISDIR(inode->i_mode)) {
|
||||
/* Purge readdir caches. */
|
||||
|
@ -1128,6 +1149,7 @@ out_zap_parent:
|
|||
out_error:
|
||||
nfs_free_fattr(fattr);
|
||||
nfs_free_fhandle(fhandle);
|
||||
nfs4_label_free(label);
|
||||
dput(parent);
|
||||
dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) lookup returned error %d\n",
|
||||
__func__, dentry->d_parent->d_name.name,
|
||||
|
@ -1256,6 +1278,7 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
|
|||
struct inode *inode = NULL;
|
||||
struct nfs_fh *fhandle = NULL;
|
||||
struct nfs_fattr *fattr = NULL;
|
||||
struct nfs4_label *label = NULL;
|
||||
int error;
|
||||
|
||||
dfprintk(VFS, "NFS: lookup(%s/%s)\n",
|
||||
|
@ -1282,17 +1305,21 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
|
|||
if (fhandle == NULL || fattr == NULL)
|
||||
goto out;
|
||||
|
||||
label = nfs4_label_alloc(NFS_SERVER(dir), GFP_NOWAIT);
|
||||
if (IS_ERR(label))
|
||||
goto out;
|
||||
|
||||
parent = dentry->d_parent;
|
||||
/* Protect against concurrent sillydeletes */
|
||||
nfs_block_sillyrename(parent);
|
||||
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
|
||||
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
|
||||
if (error == -ENOENT)
|
||||
goto no_entry;
|
||||
if (error < 0) {
|
||||
res = ERR_PTR(error);
|
||||
goto out_unblock_sillyrename;
|
||||
}
|
||||
inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
|
||||
inode = nfs_fhget(dentry->d_sb, fhandle, fattr, label);
|
||||
res = ERR_CAST(inode);
|
||||
if (IS_ERR(res))
|
||||
goto out_unblock_sillyrename;
|
||||
|
@ -1310,6 +1337,7 @@ no_entry:
|
|||
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
|
||||
out_unblock_sillyrename:
|
||||
nfs_unblock_sillyrename(parent);
|
||||
nfs4_label_free(label);
|
||||
out:
|
||||
nfs_free_fattr(fattr);
|
||||
nfs_free_fhandle(fhandle);
|
||||
|
@ -1508,7 +1536,8 @@ no_open:
|
|||
* Code common to create, mkdir, and mknod.
|
||||
*/
|
||||
int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
|
||||
struct nfs_fattr *fattr)
|
||||
struct nfs_fattr *fattr,
|
||||
struct nfs4_label *label)
|
||||
{
|
||||
struct dentry *parent = dget_parent(dentry);
|
||||
struct inode *dir = parent->d_inode;
|
||||
|
@ -1521,18 +1550,18 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
|
|||
if (dentry->d_inode)
|
||||
goto out;
|
||||
if (fhandle->size == 0) {
|
||||
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
|
||||
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, NULL);
|
||||
if (error)
|
||||
goto out_error;
|
||||
}
|
||||
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
|
||||
if (!(fattr->valid & NFS_ATTR_FATTR)) {
|
||||
struct nfs_server *server = NFS_SB(dentry->d_sb);
|
||||
error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr);
|
||||
error = server->nfs_client->rpc_ops->getattr(server, fhandle, fattr, NULL);
|
||||
if (error < 0)
|
||||
goto out_error;
|
||||
}
|
||||
inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
|
||||
inode = nfs_fhget(dentry->d_sb, fhandle, fattr, label);
|
||||
error = PTR_ERR(inode);
|
||||
if (IS_ERR(inode))
|
||||
goto out_error;
|
||||
|
|
|
@ -95,7 +95,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
|
|||
goto out;
|
||||
}
|
||||
|
||||
inode = nfs_fhget(sb, mntfh, fsinfo.fattr);
|
||||
inode = nfs_fhget(sb, mntfh, fsinfo.fattr, NULL);
|
||||
if (IS_ERR(inode)) {
|
||||
dprintk("nfs_get_root: get root inode failed\n");
|
||||
ret = ERR_CAST(inode);
|
||||
|
|
109
fs/nfs/inode.c
109
fs/nfs/inode.c
|
@ -161,11 +161,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,12 +264,72 @@ nfs_init_locked(struct inode *inode, void *opaque)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#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 *label = NULL;
|
||||
int minor_version = server->nfs_client->cl_minorversion;
|
||||
|
||||
if (minor_version < 2)
|
||||
return label;
|
||||
|
||||
if (!(server->caps & NFS_CAP_SECURITY_LABEL))
|
||||
return label;
|
||||
|
||||
label = kzalloc(sizeof(struct nfs4_label), flags);
|
||||
if (label == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
label->label = kzalloc(NFS4_MAXLABELLEN, flags);
|
||||
if (label->label == NULL) {
|
||||
kfree(label);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
label->len = NFS4_MAXLABELLEN;
|
||||
|
||||
return label;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs4_label_alloc);
|
||||
#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
|
||||
* instead of inode number.
|
||||
*/
|
||||
struct inode *
|
||||
nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
|
||||
nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, struct nfs4_label *label)
|
||||
{
|
||||
struct nfs_find_desc desc = {
|
||||
.fh = fh,
|
||||
|
@ -383,6 +451,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
|
|||
*/
|
||||
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;
|
||||
|
@ -392,6 +463,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
|
|||
unlock_new_inode(inode);
|
||||
} else
|
||||
nfs_refresh_inode(inode, fattr);
|
||||
nfs_setsecurity(inode, fattr, label);
|
||||
dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n",
|
||||
inode->i_sb->s_id,
|
||||
(long long)NFS_FILEID(inode),
|
||||
|
@ -448,7 +520,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
|
|||
NFS_PROTO(inode)->return_delegation(inode);
|
||||
error = NFS_PROTO(inode)->setattr(dentry, fattr, attr);
|
||||
if (error == 0)
|
||||
nfs_refresh_inode(inode, fattr);
|
||||
error = nfs_refresh_inode(inode, fattr);
|
||||
nfs_free_fattr(fattr);
|
||||
out:
|
||||
return error;
|
||||
|
@ -797,6 +869,7 @@ int
|
|||
__nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
|
||||
{
|
||||
int status = -ESTALE;
|
||||
struct nfs4_label *label = NULL;
|
||||
struct nfs_fattr *fattr = NULL;
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
|
||||
|
@ -814,7 +887,14 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
|
|||
goto out;
|
||||
|
||||
nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
|
||||
status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr);
|
||||
|
||||
label = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL);
|
||||
if (IS_ERR(label)) {
|
||||
status = PTR_ERR(label);
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr, label);
|
||||
if (status != 0) {
|
||||
dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
|
||||
inode->i_sb->s_id,
|
||||
|
@ -824,7 +904,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
|
|||
if (!S_ISDIR(inode->i_mode))
|
||||
set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
|
||||
}
|
||||
goto out;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
status = nfs_refresh_inode(inode, fattr);
|
||||
|
@ -832,7 +912,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
|
|||
dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n",
|
||||
inode->i_sb->s_id,
|
||||
(long long)NFS_FILEID(inode), status);
|
||||
goto out;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (nfsi->cache_validity & NFS_INO_INVALID_ACL)
|
||||
|
@ -842,7 +922,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
|
|||
inode->i_sb->s_id,
|
||||
(long long)NFS_FILEID(inode));
|
||||
|
||||
out:
|
||||
err_out:
|
||||
nfs4_label_free(label);
|
||||
out:
|
||||
nfs_free_fattr(fattr);
|
||||
return status;
|
||||
}
|
||||
|
@ -870,7 +952,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);
|
||||
|
@ -1250,6 +1333,7 @@ int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|||
spin_lock(&inode->i_lock);
|
||||
status = nfs_post_op_update_inode_locked(inode, fattr);
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_post_op_update_inode);
|
||||
|
@ -1490,7 +1574,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|||
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;
|
||||
|
@ -1503,6 +1587,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
|||
}
|
||||
}
|
||||
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)))
|
||||
|
|
|
@ -165,7 +165,7 @@ extern void nfs_free_client(struct nfs_client *);
|
|||
extern struct nfs_client *nfs4_find_client_ident(struct net *, int);
|
||||
extern struct nfs_client *
|
||||
nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
|
||||
struct nfs4_sessionid *);
|
||||
struct nfs4_sessionid *, u32);
|
||||
extern struct nfs_server *nfs_create_server(struct nfs_mount_info *,
|
||||
struct nfs_subversion *);
|
||||
extern struct nfs_server *nfs4_create_server(
|
||||
|
|
|
@ -280,7 +280,7 @@ struct vfsmount *nfs_submount(struct nfs_server *server, struct dentry *dentry,
|
|||
struct dentry *parent = dget_parent(dentry);
|
||||
|
||||
/* Look it up again to get its attributes */
|
||||
err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &dentry->d_name, fh, fattr);
|
||||
err = server->nfs_client->rpc_ops->lookup(parent->d_inode, &dentry->d_name, fh, fattr, NULL);
|
||||
dput(parent);
|
||||
if (err != 0)
|
||||
return ERR_PTR(err);
|
||||
|
|
|
@ -98,7 +98,7 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
|||
*/
|
||||
static int
|
||||
nfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
struct nfs_fattr *fattr)
|
||||
struct nfs_fattr *fattr, struct nfs4_label *label)
|
||||
{
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR],
|
||||
|
@ -143,7 +143,8 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
|
|||
|
||||
static int
|
||||
nfs3_proc_lookup(struct inode *dir, struct qstr *name,
|
||||
struct nfs_fh *fhandle, struct nfs_fattr *fattr)
|
||||
struct nfs_fh *fhandle, struct nfs_fattr *fattr,
|
||||
struct nfs4_label *label)
|
||||
{
|
||||
struct nfs3_diropargs arg = {
|
||||
.fh = NFS_FH(dir),
|
||||
|
@ -300,7 +301,7 @@ static int nfs3_do_create(struct inode *dir, struct dentry *dentry, struct nfs3_
|
|||
status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0);
|
||||
nfs_post_op_update_inode(dir, data->res.dir_attr);
|
||||
if (status == 0)
|
||||
status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
|
||||
status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
@ -303,10 +303,10 @@ is_ds_client(struct nfs_client *clp)
|
|||
extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[];
|
||||
|
||||
extern const u32 nfs4_fattr_bitmap[3];
|
||||
extern const u32 nfs4_statfs_bitmap[2];
|
||||
extern const u32 nfs4_pathconf_bitmap[2];
|
||||
extern const u32 nfs4_statfs_bitmap[3];
|
||||
extern const u32 nfs4_pathconf_bitmap[3];
|
||||
extern const u32 nfs4_fsinfo_bitmap[3];
|
||||
extern const u32 nfs4_fs_locations_bitmap[2];
|
||||
extern const u32 nfs4_fs_locations_bitmap[3];
|
||||
|
||||
void nfs4_free_client(struct nfs_client *);
|
||||
|
||||
|
|
|
@ -66,6 +66,11 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
|
|||
if (err)
|
||||
goto error;
|
||||
|
||||
if (cl_init->minorversion > NFS4_MAX_MINOR_VERSION) {
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
spin_lock_init(&clp->cl_lock);
|
||||
INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
|
||||
rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
|
||||
|
@ -562,14 +567,14 @@ static bool nfs4_cb_match_client(const struct sockaddr *addr,
|
|||
*/
|
||||
struct nfs_client *
|
||||
nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
|
||||
struct nfs4_sessionid *sid)
|
||||
struct nfs4_sessionid *sid, u32 minorversion)
|
||||
{
|
||||
struct nfs_client *clp;
|
||||
struct nfs_net *nn = net_generic(net, nfs_net_id);
|
||||
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
|
||||
if (nfs4_cb_match_client(addr, clp, 1) == false)
|
||||
if (nfs4_cb_match_client(addr, clp, minorversion) == false)
|
||||
continue;
|
||||
|
||||
if (!nfs4_has_session(clp))
|
||||
|
@ -592,7 +597,7 @@ nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
|
|||
|
||||
struct nfs_client *
|
||||
nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
|
||||
struct nfs4_sessionid *sid)
|
||||
struct nfs4_sessionid *sid, u32 minorversion)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
174
fs/nfs/nfs4xdr.c
174
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 + \
|
||||
|
@ -974,7 +988,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];
|
||||
|
@ -985,15 +1001,16 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
|
|||
int len;
|
||||
uint32_t bmval0 = 0;
|
||||
uint32_t bmval1 = 0;
|
||||
uint32_t bmval2 = 0;
|
||||
|
||||
/*
|
||||
* We reserve enough space to write the entire attribute buffer at once.
|
||||
* In the worst-case, this would be
|
||||
* 12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
|
||||
* = 36 bytes, plus any contribution from variable-length fields
|
||||
* 16(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
|
||||
* = 40 bytes, plus any contribution from variable-length fields
|
||||
* such as owner/group.
|
||||
*/
|
||||
len = 16;
|
||||
len = 20;
|
||||
|
||||
/* Sigh */
|
||||
if (iap->ia_valid & ATTR_SIZE)
|
||||
|
@ -1023,6 +1040,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)
|
||||
|
@ -1037,9 +1056,9 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
|
|||
* We write the bitmap length now, but leave the bitmap and the attribute
|
||||
* buffer length to be backfilled at the end of this routine.
|
||||
*/
|
||||
*p++ = cpu_to_be32(2);
|
||||
*p++ = cpu_to_be32(3);
|
||||
q = p;
|
||||
p += 3;
|
||||
p += 4;
|
||||
|
||||
if (iap->ia_valid & ATTR_SIZE) {
|
||||
bmval0 |= FATTR4_WORD0_SIZE;
|
||||
|
@ -1077,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.
|
||||
|
@ -1086,9 +1112,10 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
|
|||
len, ((char *)p - (char *)q) + 4);
|
||||
BUG();
|
||||
}
|
||||
len = (char *)p - (char *)q - 12;
|
||||
len = (char *)p - (char *)q - 16;
|
||||
*q++ = htonl(bmval0);
|
||||
*q++ = htonl(bmval1);
|
||||
*q++ = htonl(bmval2);
|
||||
*q = htonl(len);
|
||||
|
||||
/* out: */
|
||||
|
@ -1142,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)
|
||||
|
@ -1194,8 +1221,10 @@ encode_getattr_three(struct xdr_stream *xdr,
|
|||
|
||||
static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
|
||||
{
|
||||
encode_getattr_two(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
|
||||
bitmask[1] & nfs4_fattr_bitmap[1], hdr);
|
||||
encode_getattr_three(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
|
||||
bitmask[1] & nfs4_fattr_bitmap[1],
|
||||
bitmask[2] & nfs4_fattr_bitmap[2],
|
||||
hdr);
|
||||
}
|
||||
|
||||
static void encode_getfattr_open(struct xdr_stream *xdr, const u32 *bitmask,
|
||||
|
@ -1373,11 +1402,11 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
|
|||
switch(arg->createmode) {
|
||||
case NFS4_CREATE_UNCHECKED:
|
||||
*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;
|
||||
case NFS4_CREATE_GUARDED:
|
||||
*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);
|
||||
break;
|
||||
case NFS4_CREATE_EXCLUSIVE:
|
||||
*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
|
||||
|
@ -1387,7 +1416,7 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
|
|||
*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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1538,7 +1567,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
|
|||
|
||||
static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
|
||||
{
|
||||
uint32_t attrs[2] = {
|
||||
uint32_t attrs[3] = {
|
||||
FATTR4_WORD0_RDATTR_ERROR,
|
||||
FATTR4_WORD1_MOUNTED_ON_FILEID,
|
||||
};
|
||||
|
@ -1561,20 +1590,26 @@ 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) {
|
||||
if (hdr->minorversion > 1)
|
||||
attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
|
||||
p++, *p++ = cpu_to_be32(attrs[2] & readdir->bitmask[2]);
|
||||
}
|
||||
memcpy(verf, readdir->verifier.data, sizeof(verf));
|
||||
dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
|
||||
|
||||
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]);
|
||||
attrs[1] & readdir->bitmask[1],
|
||||
attrs[2] & readdir->bitmask[2]);
|
||||
}
|
||||
|
||||
static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
|
||||
|
@ -1633,7 +1668,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)
|
||||
|
@ -4044,6 +4079,56 @@ 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 < NFS4_MAXLABELLEN) {
|
||||
if (label) {
|
||||
memcpy(label->label, p, len);
|
||||
label->len = len;
|
||||
label->pi = pi;
|
||||
label->lfs = lfs;
|
||||
status = NFS_ATTR_FATTR_V4_SECURITY_LABEL;
|
||||
}
|
||||
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;
|
||||
|
@ -4386,7 +4471,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;
|
||||
|
@ -4494,6 +4579,13 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
|
|||
if (status < 0)
|
||||
goto xdr_error;
|
||||
|
||||
if (label) {
|
||||
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;
|
||||
|
@ -4501,7 +4593,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,
|
||||
|
@ -4520,7 +4612,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;
|
||||
|
||||
|
@ -4530,10 +4623,16 @@ xdr_error:
|
|||
return status;
|
||||
}
|
||||
|
||||
static int decode_getfattr_label(struct xdr_stream *xdr, struct nfs_fattr *fattr,
|
||||
struct nfs4_label *label, const struct nfs_server *server)
|
||||
{
|
||||
return decode_getfattr_generic(xdr, fattr, NULL, NULL, label, server);
|
||||
}
|
||||
|
||||
static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
|
||||
const struct nfs_server *server)
|
||||
{
|
||||
return decode_getfattr_generic(xdr, fattr, NULL, NULL, server);
|
||||
return decode_getfattr_generic(xdr, fattr, NULL, NULL, NULL, server);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -5925,7 +6024,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_label(xdr, res->fattr, res->label, res->server);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
@ -5951,7 +6050,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_label(xdr, res->fattr,
|
||||
res->label, res->server);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
@ -6042,7 +6142,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_label(xdr, res->fattr, res->label, res->server);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
@ -6071,7 +6171,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_label(xdr, res->fattr, res->label, res->server);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
@ -6103,7 +6203,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_label(xdr, res->fattr, res->label, res->server);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
@ -6236,7 +6336,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_label(xdr, res->f_attr, res->f_label, res->server);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
@ -6313,7 +6413,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_label(xdr, res->fattr, res->label, res->server);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
@ -6702,7 +6802,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;
|
||||
}
|
||||
|
@ -7115,7 +7215,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;
|
||||
|
|
|
@ -98,7 +98,7 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
|
|||
*/
|
||||
static int
|
||||
nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
struct nfs_fattr *fattr)
|
||||
struct nfs_fattr *fattr, struct nfs4_label *label)
|
||||
{
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs_procedures[NFSPROC_GETATTR],
|
||||
|
@ -146,7 +146,8 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
|
|||
|
||||
static int
|
||||
nfs_proc_lookup(struct inode *dir, struct qstr *name,
|
||||
struct nfs_fh *fhandle, struct nfs_fattr *fattr)
|
||||
struct nfs_fh *fhandle, struct nfs_fattr *fattr,
|
||||
struct nfs4_label *label)
|
||||
{
|
||||
struct nfs_diropargs arg = {
|
||||
.fh = NFS_FH(dir),
|
||||
|
@ -243,7 +244,7 @@ nfs_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
|
|||
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
|
||||
nfs_mark_for_revalidate(dir);
|
||||
if (status == 0)
|
||||
status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
|
||||
status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL);
|
||||
nfs_free_createdata(data);
|
||||
out:
|
||||
dprintk("NFS reply create: %d\n", status);
|
||||
|
@ -290,7 +291,7 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
|
|||
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
|
||||
}
|
||||
if (status == 0)
|
||||
status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
|
||||
status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL);
|
||||
nfs_free_createdata(data);
|
||||
out:
|
||||
dprintk("NFS reply mknod: %d\n", status);
|
||||
|
@ -442,7 +443,7 @@ nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
|
|||
* should fill in the data with a LOOKUP call on the wire.
|
||||
*/
|
||||
if (status == 0)
|
||||
status = nfs_instantiate(dentry, fh, fattr);
|
||||
status = nfs_instantiate(dentry, fh, fattr, NULL);
|
||||
|
||||
out_free:
|
||||
nfs_free_fattr(fattr);
|
||||
|
@ -471,7 +472,7 @@ nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
|
|||
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
|
||||
nfs_mark_for_revalidate(dir);
|
||||
if (status == 0)
|
||||
status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
|
||||
status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, NULL);
|
||||
nfs_free_createdata(data);
|
||||
out:
|
||||
dprintk("NFS reply mkdir: %d\n", status);
|
||||
|
|
|
@ -269,7 +269,7 @@ static match_table_t nfs_local_lock_tokens = {
|
|||
|
||||
enum {
|
||||
Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0,
|
||||
Opt_vers_4_1,
|
||||
Opt_vers_4_1, Opt_vers_4_2,
|
||||
|
||||
Opt_vers_err
|
||||
};
|
||||
|
@ -280,6 +280,7 @@ static match_table_t nfs_vers_tokens = {
|
|||
{ Opt_vers_4, "4" },
|
||||
{ Opt_vers_4_0, "4.0" },
|
||||
{ Opt_vers_4_1, "4.1" },
|
||||
{ Opt_vers_4_2, "4.2" },
|
||||
|
||||
{ Opt_vers_err, NULL }
|
||||
};
|
||||
|
@ -832,6 +833,7 @@ int nfs_show_stats(struct seq_file *m, struct dentry *root)
|
|||
seq_printf(m, "\n\tnfsv4:\t");
|
||||
seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
|
||||
seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
|
||||
seq_printf(m, ",bm2=0x%x", nfss->attr_bitmask[2]);
|
||||
seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
|
||||
show_sessions(m, nfss);
|
||||
show_pnfs(m, nfss);
|
||||
|
@ -1097,6 +1099,10 @@ static int nfs_parse_version_string(char *string,
|
|||
mnt->version = 4;
|
||||
mnt->minorversion = 1;
|
||||
break;
|
||||
case Opt_vers_4_2:
|
||||
mnt->version = 4;
|
||||
mnt->minorversion = 2;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -2423,7 +2429,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);
|
||||
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);
|
||||
|
||||
|
|
|
@ -243,6 +243,12 @@ void nfsd_lockd_shutdown(void);
|
|||
#define nfserr_reject_deleg cpu_to_be32(NFS4ERR_REJECT_DELEG)
|
||||
#define nfserr_returnconflict cpu_to_be32(NFS4ERR_RETURNCONFLICT)
|
||||
#define nfserr_deleg_revoked cpu_to_be32(NFS4ERR_DELEG_REVOKED)
|
||||
#define nfserr_partner_notsupp cpu_to_be32(NFS4ERR_PARTNER_NOTSUPP)
|
||||
#define nfserr_partner_no_auth cpu_to_be32(NFS4ERR_PARTNER_NO_AUTH)
|
||||
#define nfserr_metadata_notsupp cpu_to_be32(NFS4ERR_METADATA_NOTSUPP)
|
||||
#define nfserr_offload_denied cpu_to_be32(NFS4ERR_OFFLOAD_DENIED)
|
||||
#define nfserr_wrong_lfs cpu_to_be32(NFS4ERR_WRONG_LFS)
|
||||
#define nfserr_badlabel cpu_to_be32(NFS4ERR_BADLABEL)
|
||||
|
||||
/* error codes for internal use */
|
||||
/* if a request fails due to kmalloc failure, it gets dropped.
|
||||
|
|
|
@ -32,6 +32,15 @@ struct nfs4_acl {
|
|||
struct nfs4_ace aces[0];
|
||||
};
|
||||
|
||||
#define NFS4_MAXLABELLEN 2048
|
||||
|
||||
struct nfs4_label {
|
||||
uint32_t lfs;
|
||||
uint32_t pi;
|
||||
u32 len;
|
||||
char *label;
|
||||
};
|
||||
|
||||
typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
|
||||
|
||||
struct nfs_stateid4 {
|
||||
|
@ -219,6 +228,14 @@ enum nfsstat4 {
|
|||
NFS4ERR_REJECT_DELEG = 10085, /* on callback */
|
||||
NFS4ERR_RETURNCONFLICT = 10086, /* outstanding layoutreturn */
|
||||
NFS4ERR_DELEG_REVOKED = 10087, /* deleg./layout revoked */
|
||||
|
||||
/* nfs42 */
|
||||
NFS4ERR_PARTNER_NOTSUPP = 10088,
|
||||
NFS4ERR_PARTNER_NO_AUTH = 10089,
|
||||
NFS4ERR_METADATA_NOTSUPP = 10090,
|
||||
NFS4ERR_OFFLOAD_DENIED = 10091,
|
||||
NFS4ERR_WRONG_LFS = 10092,
|
||||
NFS4ERR_BADLABEL = 10093,
|
||||
};
|
||||
|
||||
static inline bool seqid_mutating_err(u32 err)
|
||||
|
@ -378,6 +395,7 @@ enum lock_type4 {
|
|||
#define FATTR4_WORD1_FS_LAYOUT_TYPES (1UL << 30)
|
||||
#define FATTR4_WORD2_LAYOUT_BLKSIZE (1UL << 1)
|
||||
#define FATTR4_WORD2_MDSTHRESHOLD (1UL << 4)
|
||||
#define FATTR4_WORD2_SECURITY_LABEL (1UL << 17)
|
||||
|
||||
/* MDS threshold bitmap bits */
|
||||
#define THRESHOLD_RD (1UL << 0)
|
||||
|
@ -390,11 +408,15 @@ enum lock_type4 {
|
|||
#define NFS4_VERSION 4
|
||||
#define NFS4_MINOR_VERSION 0
|
||||
|
||||
#if defined(CONFIG_NFS_V4_2)
|
||||
#define NFS4_MAX_MINOR_VERSION 2
|
||||
#else
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
#define NFS4_MAX_MINOR_VERSION 1
|
||||
#else
|
||||
#define NFS4_MAX_MINOR_VERSION 0
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
#endif /* CONFIG_NFS_V4_2 */
|
||||
|
||||
#define NFS4_DEBUG 1
|
||||
|
||||
|
|
|
@ -207,6 +207,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
|
||||
|
@ -336,7 +337,7 @@ extern void nfs_zap_mapping(struct inode *inode, struct address_space *mapping);
|
|||
extern void nfs_zap_caches(struct inode *);
|
||||
extern void nfs_invalidate_atime(struct inode *);
|
||||
extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
|
||||
struct nfs_fattr *);
|
||||
struct nfs_fattr *, struct nfs4_label *);
|
||||
extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
|
||||
extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
|
||||
extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
|
||||
|
@ -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_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);
|
||||
|
@ -469,7 +472,8 @@ extern const struct file_operations nfs_dir_operations;
|
|||
extern const struct dentry_operations nfs_dentry_operations;
|
||||
|
||||
extern void nfs_force_lookup_revalidate(struct inode *dir);
|
||||
extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr);
|
||||
extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh,
|
||||
struct nfs_fattr *fattr, struct nfs4_label *label);
|
||||
extern int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags);
|
||||
extern void nfs_access_zap_cache(struct inode *inode);
|
||||
|
||||
|
@ -497,6 +501,24 @@ extern const struct inode_operations nfs_referral_inode_operations;
|
|||
extern int nfs_mountpoint_expiry_timeout;
|
||||
extern void nfs_release_automount_timer(void);
|
||||
|
||||
/*
|
||||
* linux/fs/nfs/nfs4proc.c
|
||||
*/
|
||||
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
|
||||
extern struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags);
|
||||
static inline void nfs4_label_free(struct nfs4_label *label)
|
||||
{
|
||||
if (label) {
|
||||
kfree(label->label);
|
||||
kfree(label);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#else
|
||||
static inline struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags) { return NULL; }
|
||||
static inline void nfs4_label_free(void *label) {}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* linux/fs/nfs/unlink.c
|
||||
*/
|
||||
|
|
|
@ -146,7 +146,12 @@ struct nfs_server {
|
|||
u32 attr_bitmask[3];/* V4 bitmask representing the set
|
||||
of attributes supported on this
|
||||
filesystem */
|
||||
u32 cache_consistency_bitmask[2];
|
||||
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
|
||||
|
@ -200,5 +205,6 @@ struct nfs_server {
|
|||
#define NFS_CAP_UIDGID_NOMAP (1U << 15)
|
||||
#define NFS_CAP_STATEID_NFSV41 (1U << 16)
|
||||
#define NFS_CAP_ATOMIC_OPEN_V1 (1U << 17)
|
||||
#define NFS_CAP_SECURITY_LABEL (1U << 18)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -101,6 +101,7 @@ struct nfs_fattr {
|
|||
#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 22)
|
||||
#define NFS_ATTR_FATTR_OWNER_NAME (1U << 23)
|
||||
#define NFS_ATTR_FATTR_GROUP_NAME (1U << 24)
|
||||
#define NFS_ATTR_FATTR_V4_SECURITY_LABEL (1U << 25)
|
||||
|
||||
#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
|
||||
| NFS_ATTR_FATTR_MODE \
|
||||
|
@ -120,7 +121,8 @@ struct nfs_fattr {
|
|||
#define NFS_ATTR_FATTR_V3 (NFS_ATTR_FATTR \
|
||||
| NFS_ATTR_FATTR_SPACE_USED)
|
||||
#define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \
|
||||
| NFS_ATTR_FATTR_SPACE_USED)
|
||||
| NFS_ATTR_FATTR_SPACE_USED \
|
||||
| NFS_ATTR_FATTR_V4_SECURITY_LABEL)
|
||||
|
||||
/*
|
||||
* Info on the file system
|
||||
|
@ -348,6 +350,7 @@ struct nfs_openargs {
|
|||
const u32 * open_bitmap;
|
||||
__u32 claim;
|
||||
enum createmode4 createmode;
|
||||
const struct nfs4_label *label;
|
||||
};
|
||||
|
||||
struct nfs_openres {
|
||||
|
@ -357,6 +360,7 @@ struct nfs_openres {
|
|||
struct nfs4_change_info cinfo;
|
||||
__u32 rflags;
|
||||
struct nfs_fattr * f_attr;
|
||||
struct nfs4_label *f_label;
|
||||
struct nfs_seqid * seqid;
|
||||
const struct nfs_server *server;
|
||||
fmode_t delegation_type;
|
||||
|
@ -599,6 +603,7 @@ struct nfs_entry {
|
|||
int eof;
|
||||
struct nfs_fh * fh;
|
||||
struct nfs_fattr * fattr;
|
||||
struct nfs4_label *label;
|
||||
unsigned char d_type;
|
||||
struct nfs_server * server;
|
||||
};
|
||||
|
@ -631,6 +636,7 @@ struct nfs_setattrargs {
|
|||
struct iattr * iap;
|
||||
const struct nfs_server * server; /* Needed for name mapping */
|
||||
const u32 * bitmask;
|
||||
const struct nfs4_label *label;
|
||||
};
|
||||
|
||||
struct nfs_setaclargs {
|
||||
|
@ -666,6 +672,7 @@ struct nfs_getaclres {
|
|||
struct nfs_setattrres {
|
||||
struct nfs4_sequence_res seq_res;
|
||||
struct nfs_fattr * fattr;
|
||||
struct nfs4_label *label;
|
||||
const struct nfs_server * server;
|
||||
};
|
||||
|
||||
|
@ -863,6 +870,7 @@ struct nfs4_create_arg {
|
|||
const struct iattr * attrs;
|
||||
const struct nfs_fh * dir_fh;
|
||||
const u32 * bitmask;
|
||||
const struct nfs4_label *label;
|
||||
};
|
||||
|
||||
struct nfs4_create_res {
|
||||
|
@ -870,6 +878,7 @@ struct nfs4_create_res {
|
|||
const struct nfs_server * server;
|
||||
struct nfs_fh * fh;
|
||||
struct nfs_fattr * fattr;
|
||||
struct nfs4_label *label;
|
||||
struct nfs4_change_info dir_cinfo;
|
||||
};
|
||||
|
||||
|
@ -894,6 +903,7 @@ struct nfs4_getattr_res {
|
|||
struct nfs4_sequence_res seq_res;
|
||||
const struct nfs_server * server;
|
||||
struct nfs_fattr * fattr;
|
||||
struct nfs4_label *label;
|
||||
};
|
||||
|
||||
struct nfs4_link_arg {
|
||||
|
@ -908,6 +918,7 @@ struct nfs4_link_res {
|
|||
struct nfs4_sequence_res seq_res;
|
||||
const struct nfs_server * server;
|
||||
struct nfs_fattr * fattr;
|
||||
struct nfs4_label *label;
|
||||
struct nfs4_change_info cinfo;
|
||||
struct nfs_fattr * dir_attr;
|
||||
};
|
||||
|
@ -925,6 +936,7 @@ struct nfs4_lookup_res {
|
|||
const struct nfs_server * server;
|
||||
struct nfs_fattr * fattr;
|
||||
struct nfs_fh * fh;
|
||||
struct nfs4_label *label;
|
||||
};
|
||||
|
||||
struct nfs4_lookup_root_arg {
|
||||
|
@ -1367,11 +1379,12 @@ struct nfs_rpc_ops {
|
|||
struct dentry *(*try_mount) (int, const char *, struct nfs_mount_info *,
|
||||
struct nfs_subversion *);
|
||||
int (*getattr) (struct nfs_server *, struct nfs_fh *,
|
||||
struct nfs_fattr *);
|
||||
struct nfs_fattr *, struct nfs4_label *);
|
||||
int (*setattr) (struct dentry *, struct nfs_fattr *,
|
||||
struct iattr *);
|
||||
int (*lookup) (struct inode *, struct qstr *,
|
||||
struct nfs_fh *, struct nfs_fattr *);
|
||||
struct nfs_fh *, struct nfs_fattr *,
|
||||
struct nfs4_label *);
|
||||
int (*access) (struct inode *, struct nfs_access_entry *);
|
||||
int (*readlink)(struct inode *, struct page *, unsigned int,
|
||||
unsigned int);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/capability.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
struct linux_binprm;
|
||||
struct cred;
|
||||
|
@ -60,6 +61,9 @@ struct mm_struct;
|
|||
#define SECURITY_CAP_NOAUDIT 0
|
||||
#define SECURITY_CAP_AUDIT 1
|
||||
|
||||
/* LSM Agnostic defines for sb_set_mnt_opts */
|
||||
#define SECURITY_LSM_NATIVE_LABELS 1
|
||||
|
||||
struct ctl_table;
|
||||
struct audit_krule;
|
||||
struct user_namespace;
|
||||
|
@ -306,6 +310,15 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
|
|||
* Parse a string of security data filling in the opts structure
|
||||
* @options string containing all mount options known by the LSM
|
||||
* @opts binary data structure usable by the LSM
|
||||
* @dentry_init_security:
|
||||
* Compute a context for a dentry as the inode is not yet available
|
||||
* since NFSv4 has no label backed by an EA anyway.
|
||||
* @dentry dentry to use in calculating the context.
|
||||
* @mode mode used to determine resource type.
|
||||
* @name name of the last path component used to create file
|
||||
* @ctx pointer to place the pointer to the resulting context in.
|
||||
* @ctxlen point to place the length of the resulting context.
|
||||
*
|
||||
*
|
||||
* Security hooks for inode operations.
|
||||
*
|
||||
|
@ -1313,6 +1326,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
|
|||
* @pages contains the number of pages.
|
||||
* Return 0 if permission is granted.
|
||||
*
|
||||
* @ismaclabel:
|
||||
* Check if the extended attribute specified by @name
|
||||
* represents a MAC label. Returns 1 if name is a MAC
|
||||
* attribute otherwise returns 0.
|
||||
* @name full extended attribute name to check against
|
||||
* LSM as a MAC label.
|
||||
*
|
||||
* @secid_to_secctx:
|
||||
* Convert secid to security context. If secdata is NULL the length of
|
||||
* the result will be returned in seclen, but no secdata will be returned.
|
||||
|
@ -1439,10 +1459,16 @@ struct security_operations {
|
|||
int (*sb_pivotroot) (struct path *old_path,
|
||||
struct path *new_path);
|
||||
int (*sb_set_mnt_opts) (struct super_block *sb,
|
||||
struct security_mnt_opts *opts);
|
||||
struct security_mnt_opts *opts,
|
||||
unsigned long kern_flags,
|
||||
unsigned long *set_kern_flags);
|
||||
int (*sb_clone_mnt_opts) (const struct super_block *oldsb,
|
||||
struct super_block *newsb);
|
||||
int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);
|
||||
int (*dentry_init_security) (struct dentry *dentry, int mode,
|
||||
struct qstr *name, void **ctx,
|
||||
u32 *ctxlen);
|
||||
|
||||
|
||||
#ifdef CONFIG_SECURITY_PATH
|
||||
int (*path_unlink) (struct path *dir, struct dentry *dentry);
|
||||
|
@ -1590,6 +1616,7 @@ struct security_operations {
|
|||
|
||||
int (*getprocattr) (struct task_struct *p, char *name, char **value);
|
||||
int (*setprocattr) (struct task_struct *p, char *name, void *value, size_t size);
|
||||
int (*ismaclabel) (const char *name);
|
||||
int (*secid_to_secctx) (u32 secid, char **secdata, u32 *seclen);
|
||||
int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
|
||||
void (*release_secctx) (char *secdata, u32 seclen);
|
||||
|
@ -1725,10 +1752,16 @@ int security_sb_mount(const char *dev_name, struct path *path,
|
|||
const char *type, unsigned long flags, void *data);
|
||||
int security_sb_umount(struct vfsmount *mnt, int flags);
|
||||
int security_sb_pivotroot(struct path *old_path, struct path *new_path);
|
||||
int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts);
|
||||
int security_sb_set_mnt_opts(struct super_block *sb,
|
||||
struct security_mnt_opts *opts,
|
||||
unsigned long kern_flags,
|
||||
unsigned long *set_kern_flags);
|
||||
int security_sb_clone_mnt_opts(const struct super_block *oldsb,
|
||||
struct super_block *newsb);
|
||||
int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);
|
||||
int security_dentry_init_security(struct dentry *dentry, int mode,
|
||||
struct qstr *name, void **ctx,
|
||||
u32 *ctxlen);
|
||||
|
||||
int security_inode_alloc(struct inode *inode);
|
||||
void security_inode_free(struct inode *inode);
|
||||
|
@ -1840,6 +1873,7 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode);
|
|||
int security_getprocattr(struct task_struct *p, char *name, char **value);
|
||||
int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size);
|
||||
int security_netlink_send(struct sock *sk, struct sk_buff *skb);
|
||||
int security_ismaclabel(const char *name);
|
||||
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
|
||||
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
|
||||
void security_release_secctx(char *secdata, u32 seclen);
|
||||
|
@ -2011,7 +2045,9 @@ static inline int security_sb_pivotroot(struct path *old_path,
|
|||
}
|
||||
|
||||
static inline int security_sb_set_mnt_opts(struct super_block *sb,
|
||||
struct security_mnt_opts *opts)
|
||||
struct security_mnt_opts *opts,
|
||||
unsigned long kern_flags,
|
||||
unsigned long *set_kern_flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -2035,6 +2071,16 @@ static inline int security_inode_alloc(struct inode *inode)
|
|||
static inline void security_inode_free(struct inode *inode)
|
||||
{ }
|
||||
|
||||
static inline int security_dentry_init_security(struct dentry *dentry,
|
||||
int mode,
|
||||
struct qstr *name,
|
||||
void **ctx,
|
||||
u32 *ctxlen)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
|
||||
static inline int security_inode_init_security(struct inode *inode,
|
||||
struct inode *dir,
|
||||
const struct qstr *qstr,
|
||||
|
@ -2520,6 +2566,11 @@ static inline int security_netlink_send(struct sock *sk, struct sk_buff *skb)
|
|||
return cap_netlink_send(sk, skb);
|
||||
}
|
||||
|
||||
static inline int security_ismaclabel(const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
|
|
|
@ -91,7 +91,10 @@ static int cap_sb_pivotroot(struct path *old_path, struct path *new_path)
|
|||
}
|
||||
|
||||
static int cap_sb_set_mnt_opts(struct super_block *sb,
|
||||
struct security_mnt_opts *opts)
|
||||
struct security_mnt_opts *opts,
|
||||
unsigned long kern_flags,
|
||||
unsigned long *set_kern_flags)
|
||||
|
||||
{
|
||||
if (unlikely(opts->num_mnt_opts))
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -109,6 +112,13 @@ static int cap_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cap_dentry_init_security(struct dentry *dentry, int mode,
|
||||
struct qstr *name, void **ctx,
|
||||
u32 *ctxlen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cap_inode_alloc_security(struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
|
@ -816,6 +826,11 @@ static int cap_setprocattr(struct task_struct *p, char *name, void *value,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int cap_ismaclabel(const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -931,6 +946,7 @@ void __init security_fixup_ops(struct security_operations *ops)
|
|||
set_to_cap_if_null(ops, sb_set_mnt_opts);
|
||||
set_to_cap_if_null(ops, sb_clone_mnt_opts);
|
||||
set_to_cap_if_null(ops, sb_parse_opts_str);
|
||||
set_to_cap_if_null(ops, dentry_init_security);
|
||||
set_to_cap_if_null(ops, inode_alloc_security);
|
||||
set_to_cap_if_null(ops, inode_free_security);
|
||||
set_to_cap_if_null(ops, inode_init_security);
|
||||
|
@ -1034,6 +1050,7 @@ void __init security_fixup_ops(struct security_operations *ops)
|
|||
set_to_cap_if_null(ops, d_instantiate);
|
||||
set_to_cap_if_null(ops, getprocattr);
|
||||
set_to_cap_if_null(ops, setprocattr);
|
||||
set_to_cap_if_null(ops, ismaclabel);
|
||||
set_to_cap_if_null(ops, secid_to_secctx);
|
||||
set_to_cap_if_null(ops, secctx_to_secid);
|
||||
set_to_cap_if_null(ops, release_secctx);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/capability.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@ -293,9 +294,12 @@ int security_sb_pivotroot(struct path *old_path, struct path *new_path)
|
|||
}
|
||||
|
||||
int security_sb_set_mnt_opts(struct super_block *sb,
|
||||
struct security_mnt_opts *opts)
|
||||
struct security_mnt_opts *opts,
|
||||
unsigned long kern_flags,
|
||||
unsigned long *set_kern_flags)
|
||||
{
|
||||
return security_ops->sb_set_mnt_opts(sb, opts);
|
||||
return security_ops->sb_set_mnt_opts(sb, opts, kern_flags,
|
||||
set_kern_flags);
|
||||
}
|
||||
EXPORT_SYMBOL(security_sb_set_mnt_opts);
|
||||
|
||||
|
@ -324,6 +328,15 @@ void security_inode_free(struct inode *inode)
|
|||
security_ops->inode_free_security(inode);
|
||||
}
|
||||
|
||||
int security_dentry_init_security(struct dentry *dentry, int mode,
|
||||
struct qstr *name, void **ctx,
|
||||
u32 *ctxlen)
|
||||
{
|
||||
return security_ops->dentry_init_security(dentry, mode, name,
|
||||
ctx, ctxlen);
|
||||
}
|
||||
EXPORT_SYMBOL(security_dentry_init_security);
|
||||
|
||||
int security_inode_init_security(struct inode *inode, struct inode *dir,
|
||||
const struct qstr *qstr,
|
||||
const initxattrs initxattrs, void *fs_data)
|
||||
|
@ -647,6 +660,7 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer
|
|||
return 0;
|
||||
return security_ops->inode_listsecurity(inode, buffer, buffer_size);
|
||||
}
|
||||
EXPORT_SYMBOL(security_inode_listsecurity);
|
||||
|
||||
void security_inode_getsecid(const struct inode *inode, u32 *secid)
|
||||
{
|
||||
|
@ -1047,6 +1061,12 @@ int security_netlink_send(struct sock *sk, struct sk_buff *skb)
|
|||
return security_ops->netlink_send(sk, skb);
|
||||
}
|
||||
|
||||
int security_ismaclabel(const char *name)
|
||||
{
|
||||
return security_ops->ismaclabel(name);
|
||||
}
|
||||
EXPORT_SYMBOL(security_ismaclabel);
|
||||
|
||||
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
|
||||
{
|
||||
return security_ops->secid_to_secctx(secid, secdata, seclen);
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
#include <linux/syslog.h>
|
||||
#include <linux/user_namespace.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/msg.h>
|
||||
#include <linux/shm.h>
|
||||
|
||||
|
@ -284,13 +285,14 @@ static void superblock_free_security(struct super_block *sb)
|
|||
|
||||
/* The file system's label must be initialized prior to use. */
|
||||
|
||||
static const char *labeling_behaviors[6] = {
|
||||
static const char *labeling_behaviors[7] = {
|
||||
"uses xattr",
|
||||
"uses transition SIDs",
|
||||
"uses task SIDs",
|
||||
"uses genfs_contexts",
|
||||
"not configured for labeling",
|
||||
"uses mountpoint labeling",
|
||||
"uses native labeling",
|
||||
};
|
||||
|
||||
static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
|
||||
|
@ -552,7 +554,9 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
|
|||
* labeling information.
|
||||
*/
|
||||
static int selinux_set_mnt_opts(struct super_block *sb,
|
||||
struct security_mnt_opts *opts)
|
||||
struct security_mnt_opts *opts,
|
||||
unsigned long kern_flags,
|
||||
unsigned long *set_kern_flags)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
int rc = 0, i;
|
||||
|
@ -580,6 +584,12 @@ static int selinux_set_mnt_opts(struct super_block *sb,
|
|||
"before the security server is initialized\n");
|
||||
goto out;
|
||||
}
|
||||
if (kern_flags && !set_kern_flags) {
|
||||
/* Specifying internal flags without providing a place to
|
||||
* place the results is not allowed */
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Binary mount data FS will come through this function twice. Once
|
||||
|
@ -670,14 +680,21 @@ static int selinux_set_mnt_opts(struct super_block *sb,
|
|||
if (strcmp(sb->s_type->name, "proc") == 0)
|
||||
sbsec->flags |= SE_SBPROC;
|
||||
|
||||
/* Determine the labeling behavior to use for this filesystem type. */
|
||||
rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid);
|
||||
if (rc) {
|
||||
printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n",
|
||||
__func__, sb->s_type->name, rc);
|
||||
goto out;
|
||||
if (!sbsec->behavior) {
|
||||
/*
|
||||
* Determine the labeling behavior to use for this
|
||||
* filesystem type.
|
||||
*/
|
||||
rc = security_fs_use((sbsec->flags & SE_SBPROC) ?
|
||||
"proc" : sb->s_type->name,
|
||||
&sbsec->behavior, &sbsec->sid);
|
||||
if (rc) {
|
||||
printk(KERN_WARNING
|
||||
"%s: security_fs_use(%s) returned %d\n",
|
||||
__func__, sb->s_type->name, rc);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* sets the context of the superblock for the fs being mounted. */
|
||||
if (fscontext_sid) {
|
||||
rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
|
||||
|
@ -692,6 +709,11 @@ static int selinux_set_mnt_opts(struct super_block *sb,
|
|||
* sets the label used on all file below the mountpoint, and will set
|
||||
* the superblock context if not already set.
|
||||
*/
|
||||
if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
|
||||
sbsec->behavior = SECURITY_FS_USE_NATIVE;
|
||||
*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
|
||||
}
|
||||
|
||||
if (context_sid) {
|
||||
if (!fscontext_sid) {
|
||||
rc = may_context_mount_sb_relabel(context_sid, sbsec,
|
||||
|
@ -723,7 +745,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
|
|||
}
|
||||
|
||||
if (defcontext_sid) {
|
||||
if (sbsec->behavior != SECURITY_FS_USE_XATTR) {
|
||||
if (sbsec->behavior != SECURITY_FS_USE_XATTR &&
|
||||
sbsec->behavior != SECURITY_FS_USE_NATIVE) {
|
||||
rc = -EINVAL;
|
||||
printk(KERN_WARNING "SELinux: defcontext option is "
|
||||
"invalid for this filesystem type\n");
|
||||
|
@ -980,7 +1003,7 @@ static int superblock_doinit(struct super_block *sb, void *data)
|
|||
goto out_err;
|
||||
|
||||
out:
|
||||
rc = selinux_set_mnt_opts(sb, &opts);
|
||||
rc = selinux_set_mnt_opts(sb, &opts, 0, NULL);
|
||||
|
||||
out_err:
|
||||
security_free_mnt_opts(&opts);
|
||||
|
@ -1222,6 +1245,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
|
|||
}
|
||||
|
||||
switch (sbsec->behavior) {
|
||||
case SECURITY_FS_USE_NATIVE:
|
||||
break;
|
||||
case SECURITY_FS_USE_XATTR:
|
||||
if (!inode->i_op->getxattr) {
|
||||
isec->sid = sbsec->def_sid;
|
||||
|
@ -2515,6 +2540,40 @@ static void selinux_inode_free_security(struct inode *inode)
|
|||
inode_free_security(inode);
|
||||
}
|
||||
|
||||
static int selinux_dentry_init_security(struct dentry *dentry, int mode,
|
||||
struct qstr *name, void **ctx,
|
||||
u32 *ctxlen)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
struct task_security_struct *tsec;
|
||||
struct inode_security_struct *dsec;
|
||||
struct superblock_security_struct *sbsec;
|
||||
struct inode *dir = dentry->d_parent->d_inode;
|
||||
u32 newsid;
|
||||
int rc;
|
||||
|
||||
tsec = cred->security;
|
||||
dsec = dir->i_security;
|
||||
sbsec = dir->i_sb->s_security;
|
||||
|
||||
if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
|
||||
newsid = tsec->create_sid;
|
||||
} else {
|
||||
rc = security_transition_sid(tsec->sid, dsec->sid,
|
||||
inode_mode_to_security_class(mode),
|
||||
name,
|
||||
&newsid);
|
||||
if (rc) {
|
||||
printk(KERN_WARNING
|
||||
"%s: security_transition_sid failed, rc=%d\n",
|
||||
__func__, -rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return security_sid_to_context(newsid, (char **)ctx, ctxlen);
|
||||
}
|
||||
|
||||
static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
|
||||
const struct qstr *qstr, char **name,
|
||||
void **value, size_t *len)
|
||||
|
@ -2849,7 +2908,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;
|
||||
}
|
||||
|
||||
|
@ -2937,6 +2999,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;
|
||||
|
@ -5420,6 +5483,11 @@ abort_change:
|
|||
return error;
|
||||
}
|
||||
|
||||
static int selinux_ismaclabel(const char *name)
|
||||
{
|
||||
return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
|
||||
}
|
||||
|
||||
static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
|
||||
{
|
||||
return security_sid_to_context(secid, secdata, seclen);
|
||||
|
@ -5562,6 +5630,7 @@ static struct security_operations selinux_ops = {
|
|||
.sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
|
||||
.sb_parse_opts_str = selinux_parse_opts_str,
|
||||
|
||||
.dentry_init_security = selinux_dentry_init_security,
|
||||
|
||||
.inode_alloc_security = selinux_inode_alloc_security,
|
||||
.inode_free_security = selinux_inode_free_security,
|
||||
|
@ -5657,6 +5726,7 @@ static struct security_operations selinux_ops = {
|
|||
.getprocattr = selinux_getprocattr,
|
||||
.setprocattr = selinux_setprocattr,
|
||||
|
||||
.ismaclabel = selinux_ismaclabel,
|
||||
.secid_to_secctx = selinux_secid_to_secctx,
|
||||
.secctx_to_secid = selinux_secctx_to_secid,
|
||||
.release_secctx = selinux_release_secctx,
|
||||
|
|
|
@ -169,6 +169,8 @@ int security_get_allow_unknown(void);
|
|||
#define SECURITY_FS_USE_GENFS 4 /* use the genfs support */
|
||||
#define SECURITY_FS_USE_NONE 5 /* no labeling support */
|
||||
#define SECURITY_FS_USE_MNTPOINT 6 /* use mountpoint labeling */
|
||||
#define SECURITY_FS_USE_NATIVE 7 /* use native label support */
|
||||
#define SECURITY_FS_USE_MAX 7 /* Highest SECURITY_FS_USE_XXX */
|
||||
|
||||
int security_fs_use(const char *fstype, unsigned int *behavior,
|
||||
u32 *sid);
|
||||
|
|
|
@ -2168,7 +2168,10 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
|
|||
|
||||
rc = -EINVAL;
|
||||
c->v.behavior = le32_to_cpu(buf[0]);
|
||||
if (c->v.behavior > SECURITY_FS_USE_NONE)
|
||||
/* Determined at runtime, not in policy DB. */
|
||||
if (c->v.behavior == SECURITY_FS_USE_MNTPOINT)
|
||||
goto out;
|
||||
if (c->v.behavior > SECURITY_FS_USE_MAX)
|
||||
goto out;
|
||||
|
||||
rc = -ENOMEM;
|
||||
|
|
|
@ -3328,6 +3328,16 @@ static void smack_audit_rule_free(void *vrule)
|
|||
|
||||
#endif /* CONFIG_AUDIT */
|
||||
|
||||
/**
|
||||
* smack_ismaclabel - check if xattr @name references a smack MAC label
|
||||
* @name: Full xattr name to check.
|
||||
*/
|
||||
static int smack_ismaclabel(const char *name)
|
||||
{
|
||||
return (strcmp(name, XATTR_SMACK_SUFFIX) == 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* smack_secid_to_secctx - return the smack label for a secid
|
||||
* @secid: incoming integer
|
||||
|
@ -3524,6 +3534,7 @@ struct security_operations smack_ops = {
|
|||
.audit_rule_free = smack_audit_rule_free,
|
||||
#endif /* CONFIG_AUDIT */
|
||||
|
||||
.ismaclabel = smack_ismaclabel,
|
||||
.secid_to_secctx = smack_secid_to_secctx,
|
||||
.secctx_to_secid = smack_secctx_to_secid,
|
||||
.release_secctx = smack_release_secctx,
|
||||
|
|
Loading…
Reference in New Issue