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:
Trond Myklebust 2013-06-28 16:29:51 -04:00
commit 959d921f5e
30 changed files with 1123 additions and 171 deletions

View File

@ -104,6 +104,15 @@ config NFS_V4_1
If unsure, say N. 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 config PNFS_FILE_LAYOUT
tristate tristate
depends on NFS_V4_1 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 If the NFS client is unchanged from the upstream kernel, this
option should be set to the default "kernel.org". 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 config ROOT_NFS
bool "Root file system on NFS" bool "Root file system on NFS"
depends on NFS_FS=y && IP_PNP depends on NFS_FS=y && IP_PNP

View File

@ -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); ret = nfs4_callback_up_net(serv, net);
break; break;
case 1: case 1:
case 2:
ret = nfs41_callback_up_net(serv, net); ret = nfs41_callback_up_net(serv, net);
break; break;
default: default:

View File

@ -32,6 +32,8 @@ enum nfs4_callback_opnum {
OP_CB_WANTS_CANCELLED = 12, OP_CB_WANTS_CANCELLED = 12,
OP_CB_NOTIFY_LOCK = 13, OP_CB_NOTIFY_LOCK = 13,
OP_CB_NOTIFY_DEVICEID = 14, OP_CB_NOTIFY_DEVICEID = 14,
/* Callback operations new to NFSv4.2 */
OP_CB_OFFLOAD = 15,
OP_CB_ILLEGAL = 10044, OP_CB_ILLEGAL = 10044,
}; };
@ -39,6 +41,7 @@ struct cb_process_state {
__be32 drc_status; __be32 drc_status;
struct nfs_client *clp; struct nfs_client *clp;
u32 slotid; u32 slotid;
u32 minorversion;
struct net *net; struct net *net;
}; };

View File

@ -406,7 +406,8 @@ __be32 nfs4_callback_sequence(struct cb_sequenceargs *args,
int i; int i;
__be32 status = htonl(NFS4ERR_BADSESSION); __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) if (clp == NULL)
goto out; goto out;

View File

@ -166,9 +166,9 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound
if (unlikely(p == NULL)) if (unlikely(p == NULL))
return htonl(NFS4ERR_RESOURCE); return htonl(NFS4ERR_RESOURCE);
hdr->minorversion = ntohl(*p++); hdr->minorversion = ntohl(*p++);
/* Check minor version is zero or one. */ /* Check for minor version support */
if (hdr->minorversion <= 1) { if (hdr->minorversion <= NFS4_MAX_MINOR_VERSION) {
hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 */ hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 and v4.2 */
} else { } else {
pr_warn_ratelimited("NFS: %s: NFSv4 server callback with " pr_warn_ratelimited("NFS: %s: NFSv4 server callback with "
"illegal minor version %u!\n", "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 */ #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 static __be32
preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op) 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); return htonl(NFS_OK);
} }
static __be32 process_op(uint32_t minorversion, int nop, static __be32 process_op(int nop, struct svc_rqst *rqstp,
struct svc_rqst *rqstp,
struct xdr_stream *xdr_in, void *argp, struct xdr_stream *xdr_in, void *argp,
struct xdr_stream *xdr_out, void *resp, struct xdr_stream *xdr_out, void *resp,
struct cb_process_state *cps) struct cb_process_state *cps)
@ -819,10 +838,22 @@ static __be32 process_op(uint32_t minorversion, int nop,
return status; return status;
dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", 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)) if (status == htonl(NFS4ERR_OP_ILLEGAL))
op_nr = OP_CB_ILLEGAL; op_nr = OP_CB_ILLEGAL;
if (status) if (status)
@ -885,14 +916,15 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
return rpc_drop_reply; return rpc_drop_reply;
} }
cps.minorversion = hdr_arg.minorversion;
hdr_res.taglen = hdr_arg.taglen; hdr_res.taglen = hdr_arg.taglen;
hdr_res.tag = hdr_arg.tag; hdr_res.tag = hdr_arg.tag;
if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0)
return rpc_system_err; return rpc_system_err;
while (status == 0 && nops != hdr_arg.nops) { while (status == 0 && nops != hdr_arg.nops) {
status = process_op(hdr_arg.minorversion, nops, rqstp, status = process_op(nops, rqstp, &xdr_in,
&xdr_in, argp, &xdr_out, resp, &cps); argp, &xdr_out, resp, &cps);
nops++; nops++;
} }

View File

@ -1074,7 +1074,7 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
} }
if (!(fattr->valid & NFS_ATTR_FATTR)) { 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) { if (error < 0) {
dprintk("nfs_create_server: getattr error = %d\n", -error); dprintk("nfs_create_server: getattr error = %d\n", -error);
goto error; goto error;

View File

@ -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)
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)
@ -460,7 +463,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
if (dentry == NULL) if (dentry == NULL)
return; 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)) if (IS_ERR(inode))
goto out; 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) if (entry.fh == NULL || entry.fattr == NULL)
goto out; 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); array = nfs_readdir_get_array(page);
if (IS_ERR(array)) { if (IS_ERR(array)) {
status = PTR_ERR(array); status = PTR_ERR(array);
goto out; goto out_label_free;
} }
memset(array, 0, sizeof(struct nfs_cache_array)); memset(array, 0, sizeof(struct nfs_cache_array));
array->eof_index = -1; 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); nfs_readdir_free_large_page(pages_ptr, pages, array_size);
out_release_array: out_release_array:
nfs_readdir_release_array(page); nfs_readdir_release_array(page);
out_label_free:
nfs4_label_free(entry.label);
out: out:
nfs_free_fattr(entry.fattr); nfs_free_fattr(entry.fattr);
nfs_free_fhandle(entry.fh); nfs_free_fhandle(entry.fh);
@ -1040,6 +1051,7 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
struct dentry *parent; struct dentry *parent;
struct nfs_fh *fhandle = NULL; struct nfs_fh *fhandle = NULL;
struct nfs_fattr *fattr = NULL; struct nfs_fattr *fattr = NULL;
struct nfs4_label *label = NULL;
int error; int error;
if (flags & LOOKUP_RCU) if (flags & LOOKUP_RCU)
@ -1082,7 +1094,11 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
if (fhandle == NULL || fattr == NULL) if (fhandle == NULL || fattr == NULL)
goto out_error; 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) if (error)
goto out_bad; goto out_bad;
if (nfs_compare_fh(NFS_FH(inode), fhandle)) 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) 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);
out_set_verifier: out_set_verifier:
nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
out_valid: out_valid:
@ -1108,6 +1128,7 @@ out_zap_parent:
out_bad: out_bad:
nfs_free_fattr(fattr); nfs_free_fattr(fattr);
nfs_free_fhandle(fhandle); nfs_free_fhandle(fhandle);
nfs4_label_free(label);
nfs_mark_for_revalidate(dir); nfs_mark_for_revalidate(dir);
if (inode && S_ISDIR(inode->i_mode)) { if (inode && S_ISDIR(inode->i_mode)) {
/* Purge readdir caches. */ /* Purge readdir caches. */
@ -1128,6 +1149,7 @@ out_zap_parent:
out_error: out_error:
nfs_free_fattr(fattr); nfs_free_fattr(fattr);
nfs_free_fhandle(fhandle); nfs_free_fhandle(fhandle);
nfs4_label_free(label);
dput(parent); dput(parent);
dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) lookup returned error %d\n", dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) lookup returned error %d\n",
__func__, dentry->d_parent->d_name.name, __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 inode *inode = NULL;
struct nfs_fh *fhandle = NULL; struct nfs_fh *fhandle = NULL;
struct nfs_fattr *fattr = NULL; struct nfs_fattr *fattr = NULL;
struct nfs4_label *label = NULL;
int error; int error;
dfprintk(VFS, "NFS: lookup(%s/%s)\n", 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) if (fhandle == NULL || fattr == NULL)
goto out; goto out;
label = nfs4_label_alloc(NFS_SERVER(dir), GFP_NOWAIT);
if (IS_ERR(label))
goto out;
parent = dentry->d_parent; parent = dentry->d_parent;
/* Protect against concurrent sillydeletes */ /* Protect against concurrent sillydeletes */
nfs_block_sillyrename(parent); 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) if (error == -ENOENT)
goto no_entry; goto no_entry;
if (error < 0) { if (error < 0) {
res = ERR_PTR(error); res = ERR_PTR(error);
goto out_unblock_sillyrename; 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); res = ERR_CAST(inode);
if (IS_ERR(res)) if (IS_ERR(res))
goto out_unblock_sillyrename; goto out_unblock_sillyrename;
@ -1310,6 +1337,7 @@ no_entry:
nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
out_unblock_sillyrename: out_unblock_sillyrename:
nfs_unblock_sillyrename(parent); nfs_unblock_sillyrename(parent);
nfs4_label_free(label);
out: out:
nfs_free_fattr(fattr); nfs_free_fattr(fattr);
nfs_free_fhandle(fhandle); nfs_free_fhandle(fhandle);
@ -1508,7 +1536,8 @@ no_open:
* Code common to create, mkdir, and mknod. * Code common to create, mkdir, and mknod.
*/ */
int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle, 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 dentry *parent = dget_parent(dentry);
struct inode *dir = parent->d_inode; struct inode *dir = parent->d_inode;
@ -1521,18 +1550,18 @@ int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
if (dentry->d_inode) if (dentry->d_inode)
goto out; goto out;
if (fhandle->size == 0) { 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) if (error)
goto out_error; goto out_error;
} }
nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
if (!(fattr->valid & NFS_ATTR_FATTR)) { if (!(fattr->valid & NFS_ATTR_FATTR)) {
struct nfs_server *server = NFS_SB(dentry->d_sb); 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) if (error < 0)
goto out_error; goto out_error;
} }
inode = nfs_fhget(dentry->d_sb, fhandle, fattr); inode = nfs_fhget(dentry->d_sb, fhandle, fattr, label);
error = PTR_ERR(inode); error = PTR_ERR(inode);
if (IS_ERR(inode)) if (IS_ERR(inode))
goto out_error; goto out_error;

View File

@ -95,7 +95,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
goto out; goto out;
} }
inode = nfs_fhget(sb, mntfh, fsinfo.fattr); inode = nfs_fhget(sb, mntfh, fsinfo.fattr, NULL);
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
dprintk("nfs_get_root: get root inode failed\n"); dprintk("nfs_get_root: get root inode failed\n");
ret = ERR_CAST(inode); ret = ERR_CAST(inode);

View File

@ -161,11 +161,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)
@ -256,12 +264,72 @@ nfs_init_locked(struct inode *inode, void *opaque)
return 0; 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 * This is our front-end to iget that looks up inodes by file handle
* instead of inode number. * instead of inode number.
*/ */
struct inode * 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 = { struct nfs_find_desc desc = {
.fh = fh, .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); 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;
@ -392,6 +463,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
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),
@ -448,7 +520,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;
@ -797,6 +869,7 @@ int
__nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
{ {
int status = -ESTALE; int status = -ESTALE;
struct nfs4_label *label = NULL;
struct nfs_fattr *fattr = NULL; struct nfs_fattr *fattr = NULL;
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
@ -814,7 +887,14 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
goto out; goto out;
nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE); 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) { if (status != 0) {
dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n", dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
inode->i_sb->s_id, 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)) if (!S_ISDIR(inode->i_mode))
set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
} }
goto out; goto err_out;
} }
status = nfs_refresh_inode(inode, fattr); 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", dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n",
inode->i_sb->s_id, inode->i_sb->s_id,
(long long)NFS_FILEID(inode), status); (long long)NFS_FILEID(inode), status);
goto out; goto err_out;
} }
if (nfsi->cache_validity & NFS_INO_INVALID_ACL) 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, inode->i_sb->s_id,
(long long)NFS_FILEID(inode)); (long long)NFS_FILEID(inode));
out: err_out:
nfs4_label_free(label);
out:
nfs_free_fattr(fattr); nfs_free_fattr(fattr);
return status; 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) 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);
@ -1250,6 +1333,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);
@ -1490,7 +1574,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;
@ -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_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)))

View File

@ -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_ident(struct net *, int);
extern struct nfs_client * extern struct nfs_client *
nfs4_find_client_sessionid(struct net *, const struct sockaddr *, 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 *, extern struct nfs_server *nfs_create_server(struct nfs_mount_info *,
struct nfs_subversion *); struct nfs_subversion *);
extern struct nfs_server *nfs4_create_server( extern struct nfs_server *nfs4_create_server(

View File

@ -280,7 +280,7 @@ struct vfsmount *nfs_submount(struct nfs_server *server, struct dentry *dentry,
struct dentry *parent = dget_parent(dentry); struct dentry *parent = dget_parent(dentry);
/* Look it up again to get its attributes */ /* 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); dput(parent);
if (err != 0) if (err != 0)
return ERR_PTR(err); return ERR_PTR(err);

View File

@ -98,7 +98,7 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
*/ */
static int static int
nfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, 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 = { struct rpc_message msg = {
.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR], .rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR],
@ -143,7 +143,8 @@ nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
static int static int
nfs3_proc_lookup(struct inode *dir, struct qstr *name, 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 = { struct nfs3_diropargs arg = {
.fh = NFS_FH(dir), .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); status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0);
nfs_post_op_update_inode(dir, data->res.dir_attr); nfs_post_op_update_inode(dir, data->res.dir_attr);
if (status == 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);
return status; return status;
} }

View File

@ -303,10 +303,10 @@ is_ds_client(struct nfs_client *clp)
extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[]; extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[];
extern const u32 nfs4_fattr_bitmap[3]; extern const u32 nfs4_fattr_bitmap[3];
extern const u32 nfs4_statfs_bitmap[2]; extern const u32 nfs4_statfs_bitmap[3];
extern const u32 nfs4_pathconf_bitmap[2]; extern const u32 nfs4_pathconf_bitmap[3];
extern const u32 nfs4_fsinfo_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 *); void nfs4_free_client(struct nfs_client *);

View File

@ -66,6 +66,11 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
if (err) if (err)
goto error; goto error;
if (cl_init->minorversion > NFS4_MAX_MINOR_VERSION) {
err = -EINVAL;
goto error;
}
spin_lock_init(&clp->cl_lock); spin_lock_init(&clp->cl_lock);
INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); 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 * struct nfs_client *
nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr, 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_client *clp;
struct nfs_net *nn = net_generic(net, nfs_net_id); struct nfs_net *nn = net_generic(net, nfs_net_id);
spin_lock(&nn->nfs_client_lock); spin_lock(&nn->nfs_client_lock);
list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { 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; continue;
if (!nfs4_has_session(clp)) if (!nfs4_has_session(clp))
@ -592,7 +597,7 @@ nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
struct nfs_client * struct nfs_client *
nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr, nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
struct nfs4_sessionid *sid) struct nfs4_sessionid *sid, u32 minorversion)
{ {
return NULL; return NULL;
} }

File diff suppressed because it is too large Load Diff

View File

@ -102,12 +102,23 @@ static int nfs4_stat_to_errno(int);
#define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2)) #define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2))
#define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) #define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
#define nfs4_group_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 */ /* We support only one layout type per file system */
#define decode_mdsthreshold_maxsz (1 + 1 + nfs4_fattr_bitmap_maxsz + 1 + 8) #define decode_mdsthreshold_maxsz (1 + 1 + nfs4_fattr_bitmap_maxsz + 1 + 8)
/* This is based on getfattr, which uses the most attributes: */ /* 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 + \ #define nfs4_fattr_value_maxsz (1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \
3 + 3 + 3 + nfs4_owner_maxsz + \ 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 + \ #define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \
nfs4_fattr_value_maxsz) nfs4_fattr_value_maxsz)
#define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_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 + \ 1 + 2 + 1 + \
nfs4_owner_maxsz + \ nfs4_owner_maxsz + \
nfs4_group_maxsz + \ nfs4_group_maxsz + \
nfs4_label_maxsz + \
4 + 4) 4 + 4)
#define encode_savefh_maxsz (op_encode_hdr_maxsz) #define encode_savefh_maxsz (op_encode_hdr_maxsz)
#define decode_savefh_maxsz (op_decode_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) encode_stateid_maxsz + 3)
#define decode_read_maxsz (op_decode_hdr_maxsz + 2) #define decode_read_maxsz (op_decode_hdr_maxsz + 2)
#define encode_readdir_maxsz (op_encode_hdr_maxsz + \ #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 + \ #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 encode_readlink_maxsz (op_encode_hdr_maxsz)
#define decode_readlink_maxsz (op_decode_hdr_maxsz + 1) #define decode_readlink_maxsz (op_decode_hdr_maxsz + 1)
#define encode_write_maxsz (op_encode_hdr_maxsz + \ #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); 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_name[IDMAP_NAMESZ];
char owner_group[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; int len;
uint32_t bmval0 = 0; uint32_t bmval0 = 0;
uint32_t bmval1 = 0; uint32_t bmval1 = 0;
uint32_t bmval2 = 0;
/* /*
* We reserve enough space to write the entire attribute buffer at once. * We reserve enough space to write the entire attribute buffer at once.
* In the worst-case, this would be * In the worst-case, this would be
* 12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime) * 16(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
* = 36 bytes, plus any contribution from variable-length fields * = 40 bytes, plus any contribution from variable-length fields
* such as owner/group. * such as owner/group.
*/ */
len = 16; len = 20;
/* Sigh */ /* Sigh */
if (iap->ia_valid & ATTR_SIZE) 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); 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) if (iap->ia_valid & ATTR_ATIME_SET)
len += 16; len += 16;
else if (iap->ia_valid & ATTR_ATIME) 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 * We write the bitmap length now, but leave the bitmap and the attribute
* buffer length to be backfilled at the end of this routine. * buffer length to be backfilled at the end of this routine.
*/ */
*p++ = cpu_to_be32(2); *p++ = cpu_to_be32(3);
q = p; q = p;
p += 3; p += 4;
if (iap->ia_valid & ATTR_SIZE) { if (iap->ia_valid & ATTR_SIZE) {
bmval0 |= FATTR4_WORD0_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; bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME); *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. * 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); len, ((char *)p - (char *)q) + 4);
BUG(); BUG();
} }
len = (char *)p - (char *)q - 12; len = (char *)p - (char *)q - 16;
*q++ = htonl(bmval0); *q++ = htonl(bmval0);
*q++ = htonl(bmval1); *q++ = htonl(bmval1);
*q++ = htonl(bmval2);
*q = htonl(len); *q = htonl(len);
/* out: */ /* 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_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) 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) 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], encode_getattr_three(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
bitmask[1] & nfs4_fattr_bitmap[1], hdr); 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, 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) { switch(arg->createmode) {
case NFS4_CREATE_UNCHECKED: case NFS4_CREATE_UNCHECKED:
*p = cpu_to_be32(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; break;
case NFS4_CREATE_GUARDED: case NFS4_CREATE_GUARDED:
*p = cpu_to_be32(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; break;
case NFS4_CREATE_EXCLUSIVE: case NFS4_CREATE_EXCLUSIVE:
*p = cpu_to_be32(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); *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
encode_nfs4_verifier(xdr, &arg->u.verifier); encode_nfs4_verifier(xdr, &arg->u.verifier);
dummy.ia_valid = 0; 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) 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_WORD0_RDATTR_ERROR,
FATTR4_WORD1_MOUNTED_ON_FILEID, 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_op_hdr(xdr, OP_READDIR, decode_readdir_maxsz, hdr);
encode_uint64(xdr, readdir->cookie); encode_uint64(xdr, readdir->cookie);
encode_nfs4_verifier(xdr, &readdir->verifier); 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(dircount);
*p++ = cpu_to_be32(readdir->count); *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[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)); 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__, __func__,
(unsigned long long)readdir->cookie, (unsigned long long)readdir->cookie,
verf[0], verf[1], verf[0], verf[1],
attrs[0] & readdir->bitmask[0], 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) 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_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr);
encode_nfs4_stateid(xdr, &arg->stateid); 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) 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; 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) static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
{ {
int status = 0; int status = 0;
@ -4386,7 +4471,7 @@ out_overflow:
static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
struct nfs_fattr *fattr, struct nfs_fh *fh, 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) const struct nfs_server *server)
{ {
int status; int status;
@ -4494,6 +4579,13 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
if (status < 0) if (status < 0)
goto xdr_error; goto xdr_error;
if (label) {
status = decode_attr_security_label(xdr, bitmap, label);
if (status < 0)
goto xdr_error;
fattr->valid |= status;
}
xdr_error: xdr_error:
dprintk("%s: xdr returned %d\n", __func__, -status); dprintk("%s: xdr returned %d\n", __func__, -status);
return status; return status;
@ -4501,7 +4593,7 @@ xdr_error:
static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr, static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr,
struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc, 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; unsigned int savep;
uint32_t attrlen, uint32_t attrlen,
@ -4520,7 +4612,8 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
if (status < 0) if (status < 0)
goto xdr_error; 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) if (status < 0)
goto xdr_error; goto xdr_error;
@ -4530,10 +4623,16 @@ xdr_error:
return status; 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, static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
const struct nfs_server *server) 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); status = decode_getfh(xdr, res->fh);
if (status) if (status)
goto out; goto out;
status = decode_getfattr(xdr, res->fattr, res->server); status = decode_getfattr_label(xdr, res->fattr, res->label, res->server);
out: out:
return status; return status;
} }
@ -5951,7 +6050,8 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp,
goto out; goto out;
status = decode_getfh(xdr, res->fh); status = decode_getfh(xdr, res->fh);
if (status == 0) if (status == 0)
status = decode_getfattr(xdr, res->fattr, res->server); status = decode_getfattr_label(xdr, res->fattr,
res->label, res->server);
out: out:
return status; return status;
} }
@ -6042,7 +6142,7 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
status = decode_restorefh(xdr); status = decode_restorefh(xdr);
if (status) if (status)
goto out; goto out;
decode_getfattr(xdr, res->fattr, res->server); decode_getfattr_label(xdr, res->fattr, res->label, res->server);
out: out:
return status; 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); status = decode_getfh(xdr, res->fh);
if (status) if (status)
goto out; goto out;
decode_getfattr(xdr, res->fattr, res->server); decode_getfattr_label(xdr, res->fattr, res->label, res->server);
out: out:
return status; return status;
} }
@ -6103,7 +6203,7 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
status = decode_putfh(xdr); status = decode_putfh(xdr);
if (status) if (status)
goto out; goto out;
status = decode_getfattr(xdr, res->fattr, res->server); status = decode_getfattr_label(xdr, res->fattr, res->label, res->server);
out: out:
return status; return status;
} }
@ -6236,7 +6336,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
goto out; goto out;
if (res->access_request) if (res->access_request)
decode_access(xdr, &res->access_supported, &res->access_result); 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: out:
return status; return status;
} }
@ -6313,7 +6413,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp,
status = decode_setattr(xdr); status = decode_setattr(xdr);
if (status) if (status)
goto out; goto out;
decode_getfattr(xdr, res->fattr, res->server); decode_getfattr_label(xdr, res->fattr, res->label, res->server);
out: out:
return status; return status;
} }
@ -6702,7 +6802,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
xdr_enter_page(xdr, PAGE_SIZE); xdr_enter_page(xdr, PAGE_SIZE);
status = decode_getfattr_generic(xdr, &res->fs_locations->fattr, status = decode_getfattr_generic(xdr, &res->fs_locations->fattr,
NULL, res->fs_locations, NULL, res->fs_locations,
res->fs_locations->server); NULL, res->fs_locations->server);
out: out:
return status; return status;
} }
@ -7115,7 +7215,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
goto out_overflow; goto out_overflow;
if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
NULL, entry->server) < 0) NULL, entry->label, entry->server) < 0)
goto out_overflow; goto out_overflow;
if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
entry->ino = entry->fattr->mounted_on_fileid; entry->ino = entry->fattr->mounted_on_fileid;

View File

@ -98,7 +98,7 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
*/ */
static int static int
nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, 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 = { struct rpc_message msg = {
.rpc_proc = &nfs_procedures[NFSPROC_GETATTR], .rpc_proc = &nfs_procedures[NFSPROC_GETATTR],
@ -146,7 +146,8 @@ nfs_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
static int static int
nfs_proc_lookup(struct inode *dir, struct qstr *name, 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 = { struct nfs_diropargs arg = {
.fh = NFS_FH(dir), .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); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_mark_for_revalidate(dir); nfs_mark_for_revalidate(dir);
if (status == 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); nfs_free_createdata(data);
out: out:
dprintk("NFS reply create: %d\n", status); 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); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
} }
if (status == 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); nfs_free_createdata(data);
out: out:
dprintk("NFS reply mknod: %d\n", status); 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. * should fill in the data with a LOOKUP call on the wire.
*/ */
if (status == 0) if (status == 0)
status = nfs_instantiate(dentry, fh, fattr); status = nfs_instantiate(dentry, fh, fattr, NULL);
out_free: out_free:
nfs_free_fattr(fattr); 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); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
nfs_mark_for_revalidate(dir); nfs_mark_for_revalidate(dir);
if (status == 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); nfs_free_createdata(data);
out: out:
dprintk("NFS reply mkdir: %d\n", status); dprintk("NFS reply mkdir: %d\n", status);

View File

@ -269,7 +269,7 @@ static match_table_t nfs_local_lock_tokens = {
enum { enum {
Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0, 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 Opt_vers_err
}; };
@ -280,6 +280,7 @@ static match_table_t nfs_vers_tokens = {
{ Opt_vers_4, "4" }, { Opt_vers_4, "4" },
{ Opt_vers_4_0, "4.0" }, { Opt_vers_4_0, "4.0" },
{ Opt_vers_4_1, "4.1" }, { Opt_vers_4_1, "4.1" },
{ Opt_vers_4_2, "4.2" },
{ Opt_vers_err, NULL } { 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, "\n\tnfsv4:\t");
seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]); seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]); 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); seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
show_sessions(m, nfss); show_sessions(m, nfss);
show_pnfs(m, nfss); show_pnfs(m, nfss);
@ -1097,6 +1099,10 @@ static int nfs_parse_version_string(char *string,
mnt->version = 4; mnt->version = 4;
mnt->minorversion = 1; mnt->minorversion = 1;
break; break;
case Opt_vers_4_2:
mnt->version = 4;
mnt->minorversion = 2;
break;
default: default:
return 0; 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, 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;
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);

View File

@ -243,6 +243,12 @@ void nfsd_lockd_shutdown(void);
#define nfserr_reject_deleg cpu_to_be32(NFS4ERR_REJECT_DELEG) #define nfserr_reject_deleg cpu_to_be32(NFS4ERR_REJECT_DELEG)
#define nfserr_returnconflict cpu_to_be32(NFS4ERR_RETURNCONFLICT) #define nfserr_returnconflict cpu_to_be32(NFS4ERR_RETURNCONFLICT)
#define nfserr_deleg_revoked cpu_to_be32(NFS4ERR_DELEG_REVOKED) #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 */ /* error codes for internal use */
/* if a request fails due to kmalloc failure, it gets dropped. /* if a request fails due to kmalloc failure, it gets dropped.

View File

@ -32,6 +32,15 @@ struct nfs4_acl {
struct nfs4_ace aces[0]; 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; typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
struct nfs_stateid4 { struct nfs_stateid4 {
@ -219,6 +228,14 @@ enum nfsstat4 {
NFS4ERR_REJECT_DELEG = 10085, /* on callback */ NFS4ERR_REJECT_DELEG = 10085, /* on callback */
NFS4ERR_RETURNCONFLICT = 10086, /* outstanding layoutreturn */ NFS4ERR_RETURNCONFLICT = 10086, /* outstanding layoutreturn */
NFS4ERR_DELEG_REVOKED = 10087, /* deleg./layout revoked */ 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) 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_WORD1_FS_LAYOUT_TYPES (1UL << 30)
#define FATTR4_WORD2_LAYOUT_BLKSIZE (1UL << 1) #define FATTR4_WORD2_LAYOUT_BLKSIZE (1UL << 1)
#define FATTR4_WORD2_MDSTHRESHOLD (1UL << 4) #define FATTR4_WORD2_MDSTHRESHOLD (1UL << 4)
#define FATTR4_WORD2_SECURITY_LABEL (1UL << 17)
/* MDS threshold bitmap bits */ /* MDS threshold bitmap bits */
#define THRESHOLD_RD (1UL << 0) #define THRESHOLD_RD (1UL << 0)
@ -390,11 +408,15 @@ enum lock_type4 {
#define NFS4_VERSION 4 #define NFS4_VERSION 4
#define NFS4_MINOR_VERSION 0 #define NFS4_MINOR_VERSION 0
#if defined(CONFIG_NFS_V4_2)
#define NFS4_MAX_MINOR_VERSION 2
#else
#if defined(CONFIG_NFS_V4_1) #if defined(CONFIG_NFS_V4_1)
#define NFS4_MAX_MINOR_VERSION 1 #define NFS4_MAX_MINOR_VERSION 1
#else #else
#define NFS4_MAX_MINOR_VERSION 0 #define NFS4_MAX_MINOR_VERSION 0
#endif /* CONFIG_NFS_V4_1 */ #endif /* CONFIG_NFS_V4_1 */
#endif /* CONFIG_NFS_V4_2 */
#define NFS4_DEBUG 1 #define NFS4_DEBUG 1

View File

@ -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
@ -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_zap_caches(struct inode *);
extern void nfs_invalidate_atime(struct inode *); extern void nfs_invalidate_atime(struct inode *);
extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *, 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_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(struct inode *inode, struct nfs_fattr *fattr);
extern int nfs_post_op_update_inode_force_wcc(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_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);
@ -469,7 +472,8 @@ extern const struct file_operations nfs_dir_operations;
extern const struct dentry_operations nfs_dentry_operations; extern const struct dentry_operations nfs_dentry_operations;
extern void nfs_force_lookup_revalidate(struct inode *dir); 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 int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags);
extern void nfs_access_zap_cache(struct inode *inode); 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 int nfs_mountpoint_expiry_timeout;
extern void nfs_release_automount_timer(void); 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 * linux/fs/nfs/unlink.c
*/ */

View File

@ -146,7 +146,12 @@ 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 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 /* V4 bitmask representing the subset
of change attribute, size, ctime of change attribute, size, ctime
and mtime attributes supported by and mtime attributes supported by
@ -200,5 +205,6 @@ struct nfs_server {
#define NFS_CAP_UIDGID_NOMAP (1U << 15) #define NFS_CAP_UIDGID_NOMAP (1U << 15)
#define NFS_CAP_STATEID_NFSV41 (1U << 16) #define NFS_CAP_STATEID_NFSV41 (1U << 16)
#define NFS_CAP_ATOMIC_OPEN_V1 (1U << 17) #define NFS_CAP_ATOMIC_OPEN_V1 (1U << 17)
#define NFS_CAP_SECURITY_LABEL (1U << 18)
#endif #endif

View File

@ -101,6 +101,7 @@ struct nfs_fattr {
#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 22) #define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 22)
#define NFS_ATTR_FATTR_OWNER_NAME (1U << 23) #define NFS_ATTR_FATTR_OWNER_NAME (1U << 23)
#define NFS_ATTR_FATTR_GROUP_NAME (1U << 24) #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 \ #define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \
| NFS_ATTR_FATTR_MODE \ | NFS_ATTR_FATTR_MODE \
@ -120,7 +121,8 @@ struct nfs_fattr {
#define NFS_ATTR_FATTR_V3 (NFS_ATTR_FATTR \ #define NFS_ATTR_FATTR_V3 (NFS_ATTR_FATTR \
| NFS_ATTR_FATTR_SPACE_USED) | NFS_ATTR_FATTR_SPACE_USED)
#define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \ #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 * Info on the file system
@ -348,6 +350,7 @@ struct nfs_openargs {
const u32 * open_bitmap; const u32 * open_bitmap;
__u32 claim; __u32 claim;
enum createmode4 createmode; enum createmode4 createmode;
const struct nfs4_label *label;
}; };
struct nfs_openres { struct nfs_openres {
@ -357,6 +360,7 @@ struct nfs_openres {
struct nfs4_change_info cinfo; struct nfs4_change_info cinfo;
__u32 rflags; __u32 rflags;
struct nfs_fattr * f_attr; struct nfs_fattr * f_attr;
struct nfs4_label *f_label;
struct nfs_seqid * seqid; struct nfs_seqid * seqid;
const struct nfs_server *server; const struct nfs_server *server;
fmode_t delegation_type; fmode_t delegation_type;
@ -599,6 +603,7 @@ struct nfs_entry {
int eof; int eof;
struct nfs_fh * fh; struct nfs_fh * fh;
struct nfs_fattr * fattr; struct nfs_fattr * fattr;
struct nfs4_label *label;
unsigned char d_type; unsigned char d_type;
struct nfs_server * server; struct nfs_server * server;
}; };
@ -631,6 +636,7 @@ struct nfs_setattrargs {
struct iattr * iap; struct iattr * iap;
const struct nfs_server * server; /* Needed for name mapping */ const struct nfs_server * server; /* Needed for name mapping */
const u32 * bitmask; const u32 * bitmask;
const struct nfs4_label *label;
}; };
struct nfs_setaclargs { struct nfs_setaclargs {
@ -666,6 +672,7 @@ struct nfs_getaclres {
struct nfs_setattrres { struct nfs_setattrres {
struct nfs4_sequence_res seq_res; struct nfs4_sequence_res seq_res;
struct nfs_fattr * fattr; struct nfs_fattr * fattr;
struct nfs4_label *label;
const struct nfs_server * server; const struct nfs_server * server;
}; };
@ -863,6 +870,7 @@ struct nfs4_create_arg {
const struct iattr * attrs; const struct iattr * attrs;
const struct nfs_fh * dir_fh; const struct nfs_fh * dir_fh;
const u32 * bitmask; const u32 * bitmask;
const struct nfs4_label *label;
}; };
struct nfs4_create_res { struct nfs4_create_res {
@ -870,6 +878,7 @@ struct nfs4_create_res {
const struct nfs_server * server; const struct nfs_server * server;
struct nfs_fh * fh; struct nfs_fh * fh;
struct nfs_fattr * fattr; struct nfs_fattr * fattr;
struct nfs4_label *label;
struct nfs4_change_info dir_cinfo; struct nfs4_change_info dir_cinfo;
}; };
@ -894,6 +903,7 @@ struct nfs4_getattr_res {
struct nfs4_sequence_res seq_res; struct nfs4_sequence_res seq_res;
const struct nfs_server * server; const struct nfs_server * server;
struct nfs_fattr * fattr; struct nfs_fattr * fattr;
struct nfs4_label *label;
}; };
struct nfs4_link_arg { struct nfs4_link_arg {
@ -908,6 +918,7 @@ struct nfs4_link_res {
struct nfs4_sequence_res seq_res; struct nfs4_sequence_res seq_res;
const struct nfs_server * server; const struct nfs_server * server;
struct nfs_fattr * fattr; struct nfs_fattr * fattr;
struct nfs4_label *label;
struct nfs4_change_info cinfo; struct nfs4_change_info cinfo;
struct nfs_fattr * dir_attr; struct nfs_fattr * dir_attr;
}; };
@ -925,6 +936,7 @@ struct nfs4_lookup_res {
const struct nfs_server * server; const struct nfs_server * server;
struct nfs_fattr * fattr; struct nfs_fattr * fattr;
struct nfs_fh * fh; struct nfs_fh * fh;
struct nfs4_label *label;
}; };
struct nfs4_lookup_root_arg { 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 dentry *(*try_mount) (int, const char *, struct nfs_mount_info *,
struct nfs_subversion *); struct nfs_subversion *);
int (*getattr) (struct nfs_server *, struct nfs_fh *, int (*getattr) (struct nfs_server *, struct nfs_fh *,
struct nfs_fattr *); struct nfs_fattr *, struct nfs4_label *);
int (*setattr) (struct dentry *, struct nfs_fattr *, int (*setattr) (struct dentry *, struct nfs_fattr *,
struct iattr *); struct iattr *);
int (*lookup) (struct inode *, struct qstr *, 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 (*access) (struct inode *, struct nfs_access_entry *);
int (*readlink)(struct inode *, struct page *, unsigned int, int (*readlink)(struct inode *, struct page *, unsigned int,
unsigned int); unsigned int);

View File

@ -26,6 +26,7 @@
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/string.h>
struct linux_binprm; struct linux_binprm;
struct cred; struct cred;
@ -60,6 +61,9 @@ struct mm_struct;
#define SECURITY_CAP_NOAUDIT 0 #define SECURITY_CAP_NOAUDIT 0
#define SECURITY_CAP_AUDIT 1 #define SECURITY_CAP_AUDIT 1
/* LSM Agnostic defines for sb_set_mnt_opts */
#define SECURITY_LSM_NATIVE_LABELS 1
struct ctl_table; struct ctl_table;
struct audit_krule; struct audit_krule;
struct user_namespace; 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 * Parse a string of security data filling in the opts structure
* @options string containing all mount options known by the LSM * @options string containing all mount options known by the LSM
* @opts binary data structure usable 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. * 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. * @pages contains the number of pages.
* Return 0 if permission is granted. * 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: * @secid_to_secctx:
* Convert secid to security context. If secdata is NULL the length of * 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. * 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, int (*sb_pivotroot) (struct path *old_path,
struct path *new_path); struct path *new_path);
int (*sb_set_mnt_opts) (struct super_block *sb, 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, int (*sb_clone_mnt_opts) (const struct super_block *oldsb,
struct super_block *newsb); struct super_block *newsb);
int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts); 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 #ifdef CONFIG_SECURITY_PATH
int (*path_unlink) (struct path *dir, struct dentry *dentry); 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 (*getprocattr) (struct task_struct *p, char *name, char **value);
int (*setprocattr) (struct task_struct *p, char *name, void *value, size_t size); 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 (*secid_to_secctx) (u32 secid, char **secdata, u32 *seclen);
int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid); int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
void (*release_secctx) (char *secdata, u32 seclen); 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); const char *type, unsigned long flags, void *data);
int security_sb_umount(struct vfsmount *mnt, int flags); int security_sb_umount(struct vfsmount *mnt, int flags);
int security_sb_pivotroot(struct path *old_path, struct path *new_path); 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, int security_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb); struct super_block *newsb);
int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts); 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); int security_inode_alloc(struct inode *inode);
void security_inode_free(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_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_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_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_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void security_release_secctx(char *secdata, u32 seclen); 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, 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; 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 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, static inline int security_inode_init_security(struct inode *inode,
struct inode *dir, struct inode *dir,
const struct qstr *qstr, 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); 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) static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{ {
return -EOPNOTSUPP; return -EOPNOTSUPP;

View File

@ -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, 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)) if (unlikely(opts->num_mnt_opts))
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -109,6 +112,13 @@ static int cap_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
return 0; 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) static int cap_inode_alloc_security(struct inode *inode)
{ {
return 0; return 0;
@ -816,6 +826,11 @@ static int cap_setprocattr(struct task_struct *p, char *name, void *value,
return -EINVAL; return -EINVAL;
} }
static int cap_ismaclabel(const char *name)
{
return 0;
}
static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{ {
return -EOPNOTSUPP; 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_set_mnt_opts);
set_to_cap_if_null(ops, sb_clone_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, 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_alloc_security);
set_to_cap_if_null(ops, inode_free_security); set_to_cap_if_null(ops, inode_free_security);
set_to_cap_if_null(ops, inode_init_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, d_instantiate);
set_to_cap_if_null(ops, getprocattr); set_to_cap_if_null(ops, getprocattr);
set_to_cap_if_null(ops, setprocattr); 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, secid_to_secctx);
set_to_cap_if_null(ops, secctx_to_secid); set_to_cap_if_null(ops, secctx_to_secid);
set_to_cap_if_null(ops, release_secctx); set_to_cap_if_null(ops, release_secctx);

View File

@ -12,6 +12,7 @@
*/ */
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/dcache.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.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, 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); EXPORT_SYMBOL(security_sb_set_mnt_opts);
@ -324,6 +328,15 @@ void security_inode_free(struct inode *inode)
security_ops->inode_free_security(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, int security_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, const struct qstr *qstr,
const initxattrs initxattrs, void *fs_data) 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 0;
return security_ops->inode_listsecurity(inode, buffer, buffer_size); return security_ops->inode_listsecurity(inode, buffer, buffer_size);
} }
EXPORT_SYMBOL(security_inode_listsecurity);
void security_inode_getsecid(const struct inode *inode, u32 *secid) 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); 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) int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{ {
return security_ops->secid_to_secctx(secid, secdata, seclen); return security_ops->secid_to_secctx(secid, secdata, seclen);

View File

@ -81,6 +81,7 @@
#include <linux/syslog.h> #include <linux/syslog.h>
#include <linux/user_namespace.h> #include <linux/user_namespace.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/security.h>
#include <linux/msg.h> #include <linux/msg.h>
#include <linux/shm.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. */ /* 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 xattr",
"uses transition SIDs", "uses transition SIDs",
"uses task SIDs", "uses task SIDs",
"uses genfs_contexts", "uses genfs_contexts",
"not configured for labeling", "not configured for labeling",
"uses mountpoint labeling", "uses mountpoint labeling",
"uses native labeling",
}; };
static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry); 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. * labeling information.
*/ */
static int selinux_set_mnt_opts(struct super_block *sb, 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(); const struct cred *cred = current_cred();
int rc = 0, i; 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"); "before the security server is initialized\n");
goto out; 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 * 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) if (strcmp(sb->s_type->name, "proc") == 0)
sbsec->flags |= SE_SBPROC; sbsec->flags |= SE_SBPROC;
/* Determine the labeling behavior to use for this filesystem type. */ if (!sbsec->behavior) {
rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid); /*
if (rc) { * Determine the labeling behavior to use for this
printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", * filesystem type.
__func__, sb->s_type->name, rc); */
goto out; 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. */ /* sets the context of the superblock for the fs being mounted. */
if (fscontext_sid) { if (fscontext_sid) {
rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred); 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 * sets the label used on all file below the mountpoint, and will set
* the superblock context if not already 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 (context_sid) {
if (!fscontext_sid) { if (!fscontext_sid) {
rc = may_context_mount_sb_relabel(context_sid, sbsec, 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 (defcontext_sid) {
if (sbsec->behavior != SECURITY_FS_USE_XATTR) { if (sbsec->behavior != SECURITY_FS_USE_XATTR &&
sbsec->behavior != SECURITY_FS_USE_NATIVE) {
rc = -EINVAL; rc = -EINVAL;
printk(KERN_WARNING "SELinux: defcontext option is " printk(KERN_WARNING "SELinux: defcontext option is "
"invalid for this filesystem type\n"); "invalid for this filesystem type\n");
@ -980,7 +1003,7 @@ static int superblock_doinit(struct super_block *sb, void *data)
goto out_err; goto out_err;
out: out:
rc = selinux_set_mnt_opts(sb, &opts); rc = selinux_set_mnt_opts(sb, &opts, 0, NULL);
out_err: out_err:
security_free_mnt_opts(&opts); 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) { switch (sbsec->behavior) {
case SECURITY_FS_USE_NATIVE:
break;
case SECURITY_FS_USE_XATTR: case SECURITY_FS_USE_XATTR:
if (!inode->i_op->getxattr) { if (!inode->i_op->getxattr) {
isec->sid = sbsec->def_sid; isec->sid = sbsec->def_sid;
@ -2515,6 +2540,40 @@ static void selinux_inode_free_security(struct inode *inode)
inode_free_security(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, static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, char **name, const struct qstr *qstr, char **name,
void **value, size_t *len) void **value, size_t *len)
@ -2849,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;
} }
@ -2937,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;
@ -5420,6 +5483,11 @@ abort_change:
return error; 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) static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{ {
return security_sid_to_context(secid, secdata, 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_clone_mnt_opts = selinux_sb_clone_mnt_opts,
.sb_parse_opts_str = selinux_parse_opts_str, .sb_parse_opts_str = selinux_parse_opts_str,
.dentry_init_security = selinux_dentry_init_security,
.inode_alloc_security = selinux_inode_alloc_security, .inode_alloc_security = selinux_inode_alloc_security,
.inode_free_security = selinux_inode_free_security, .inode_free_security = selinux_inode_free_security,
@ -5657,6 +5726,7 @@ static struct security_operations selinux_ops = {
.getprocattr = selinux_getprocattr, .getprocattr = selinux_getprocattr,
.setprocattr = selinux_setprocattr, .setprocattr = selinux_setprocattr,
.ismaclabel = selinux_ismaclabel,
.secid_to_secctx = selinux_secid_to_secctx, .secid_to_secctx = selinux_secid_to_secctx,
.secctx_to_secid = selinux_secctx_to_secid, .secctx_to_secid = selinux_secctx_to_secid,
.release_secctx = selinux_release_secctx, .release_secctx = selinux_release_secctx,

View File

@ -169,6 +169,8 @@ int security_get_allow_unknown(void);
#define SECURITY_FS_USE_GENFS 4 /* use the genfs support */ #define SECURITY_FS_USE_GENFS 4 /* use the genfs support */
#define SECURITY_FS_USE_NONE 5 /* no labeling support */ #define SECURITY_FS_USE_NONE 5 /* no labeling support */
#define SECURITY_FS_USE_MNTPOINT 6 /* use mountpoint labeling */ #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, int security_fs_use(const char *fstype, unsigned int *behavior,
u32 *sid); u32 *sid);

View File

@ -2168,7 +2168,10 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
rc = -EINVAL; rc = -EINVAL;
c->v.behavior = le32_to_cpu(buf[0]); 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; goto out;
rc = -ENOMEM; rc = -ENOMEM;

View File

@ -3328,6 +3328,16 @@ static void smack_audit_rule_free(void *vrule)
#endif /* CONFIG_AUDIT */ #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 * smack_secid_to_secctx - return the smack label for a secid
* @secid: incoming integer * @secid: incoming integer
@ -3524,6 +3534,7 @@ struct security_operations smack_ops = {
.audit_rule_free = smack_audit_rule_free, .audit_rule_free = smack_audit_rule_free,
#endif /* CONFIG_AUDIT */ #endif /* CONFIG_AUDIT */
.ismaclabel = smack_ismaclabel,
.secid_to_secctx = smack_secid_to_secctx, .secid_to_secctx = smack_secid_to_secctx,
.secctx_to_secid = smack_secctx_to_secid, .secctx_to_secid = smack_secctx_to_secid,
.release_secctx = smack_release_secctx, .release_secctx = smack_release_secctx,