introduce cloning of fs_context
new primitive: vfs_dup_fs_context(). Comes with fs_context method (->dup()) for copying the filesystem-specific parts of fs_context, along with LSM one (->fs_context_dup()) for doing the same to LSM parts. [needs better commit message, and change of Author:, anyway] Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
cb50b348c7
commit
0b52075ee6
@ -337,6 +337,47 @@ void fc_drop_locked(struct fs_context *fc)
|
||||
|
||||
static void legacy_fs_context_free(struct fs_context *fc);
|
||||
|
||||
/**
|
||||
* vfs_dup_fc_config: Duplicate a filesystem context.
|
||||
* @src_fc: The context to copy.
|
||||
*/
|
||||
struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc)
|
||||
{
|
||||
struct fs_context *fc;
|
||||
int ret;
|
||||
|
||||
if (!src_fc->ops->dup)
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
|
||||
fc = kmemdup(src_fc, sizeof(struct fs_context), GFP_KERNEL);
|
||||
if (!fc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
fc->fs_private = NULL;
|
||||
fc->s_fs_info = NULL;
|
||||
fc->source = NULL;
|
||||
fc->security = NULL;
|
||||
get_filesystem(fc->fs_type);
|
||||
get_net(fc->net_ns);
|
||||
get_user_ns(fc->user_ns);
|
||||
get_cred(fc->cred);
|
||||
|
||||
/* Can't call put until we've called ->dup */
|
||||
ret = fc->ops->dup(fc, src_fc);
|
||||
if (ret < 0)
|
||||
goto err_fc;
|
||||
|
||||
ret = security_fs_context_dup(fc, src_fc);
|
||||
if (ret < 0)
|
||||
goto err_fc;
|
||||
return fc;
|
||||
|
||||
err_fc:
|
||||
put_fs_context(fc);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_dup_fs_context);
|
||||
|
||||
/**
|
||||
* put_fs_context - Dispose of a superblock configuration context.
|
||||
* @fc: The context to dispose of.
|
||||
@ -380,6 +421,31 @@ static void legacy_fs_context_free(struct fs_context *fc)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Duplicate a legacy config.
|
||||
*/
|
||||
static int legacy_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
|
||||
{
|
||||
struct legacy_fs_context *ctx;
|
||||
struct legacy_fs_context *src_ctx = src_fc->fs_private;
|
||||
|
||||
ctx = kmemdup(src_ctx, sizeof(*src_ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ctx->param_type == LEGACY_FS_INDIVIDUAL_PARAMS) {
|
||||
ctx->legacy_data = kmemdup(src_ctx->legacy_data,
|
||||
src_ctx->data_size, GFP_KERNEL);
|
||||
if (!ctx->legacy_data) {
|
||||
kfree(ctx);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
fc->fs_private = ctx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a parameter to a legacy config. We build up a comma-separated list of
|
||||
* options.
|
||||
@ -514,6 +580,7 @@ static int legacy_reconfigure(struct fs_context *fc)
|
||||
|
||||
const struct fs_context_operations legacy_fs_context_ops = {
|
||||
.free = legacy_fs_context_free,
|
||||
.dup = legacy_fs_context_dup,
|
||||
.parse_param = legacy_parse_param,
|
||||
.parse_monolithic = legacy_parse_monolithic,
|
||||
.get_tree = legacy_get_tree,
|
||||
|
@ -94,6 +94,7 @@ struct fs_context {
|
||||
|
||||
struct fs_context_operations {
|
||||
void (*free)(struct fs_context *fc);
|
||||
int (*dup)(struct fs_context *fc, struct fs_context *src_fc);
|
||||
int (*parse_param)(struct fs_context *fc, struct fs_parameter *param);
|
||||
int (*parse_monolithic)(struct fs_context *fc, void *data);
|
||||
int (*get_tree)(struct fs_context *fc);
|
||||
@ -111,6 +112,7 @@ extern struct fs_context *fs_context_for_reconfigure(struct dentry *dentry,
|
||||
extern struct fs_context *fs_context_for_submount(struct file_system_type *fs_type,
|
||||
struct dentry *reference);
|
||||
|
||||
extern struct fs_context *vfs_dup_fs_context(struct fs_context *fc);
|
||||
extern int vfs_parse_fs_param(struct fs_context *fc, struct fs_parameter *param);
|
||||
extern int vfs_parse_fs_string(struct fs_context *fc, const char *key,
|
||||
const char *value, size_t v_size);
|
||||
|
@ -79,6 +79,11 @@
|
||||
* Security hooks for mount using fs_context.
|
||||
* [See also Documentation/filesystems/mounting.txt]
|
||||
*
|
||||
* @fs_context_dup:
|
||||
* Allocate and attach a security structure to sc->security. This pointer
|
||||
* is initialised to NULL by the caller.
|
||||
* @fc indicates the new filesystem context.
|
||||
* @src_fc indicates the original filesystem context.
|
||||
* @fs_context_parse_param:
|
||||
* Userspace provided a parameter to configure a superblock. The LSM may
|
||||
* reject it with an error and may use it for itself, in which case it
|
||||
@ -1470,6 +1475,7 @@ union security_list_options {
|
||||
void (*bprm_committing_creds)(struct linux_binprm *bprm);
|
||||
void (*bprm_committed_creds)(struct linux_binprm *bprm);
|
||||
|
||||
int (*fs_context_dup)(struct fs_context *fc, struct fs_context *src_sc);
|
||||
int (*fs_context_parse_param)(struct fs_context *fc, struct fs_parameter *param);
|
||||
|
||||
int (*sb_alloc_security)(struct super_block *sb);
|
||||
@ -1813,6 +1819,7 @@ struct security_hook_heads {
|
||||
struct hlist_head bprm_check_security;
|
||||
struct hlist_head bprm_committing_creds;
|
||||
struct hlist_head bprm_committed_creds;
|
||||
struct hlist_head fs_context_dup;
|
||||
struct hlist_head fs_context_parse_param;
|
||||
struct hlist_head sb_alloc_security;
|
||||
struct hlist_head sb_free_security;
|
||||
|
@ -223,6 +223,7 @@ int security_bprm_set_creds(struct linux_binprm *bprm);
|
||||
int security_bprm_check(struct linux_binprm *bprm);
|
||||
void security_bprm_committing_creds(struct linux_binprm *bprm);
|
||||
void security_bprm_committed_creds(struct linux_binprm *bprm);
|
||||
int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc);
|
||||
int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param);
|
||||
int security_sb_alloc(struct super_block *sb);
|
||||
void security_sb_free(struct super_block *sb);
|
||||
@ -521,6 +522,11 @@ static inline void security_bprm_committed_creds(struct linux_binprm *bprm)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int security_fs_context_dup(struct fs_context *fc,
|
||||
struct fs_context *src_fc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int security_fs_context_parse_param(struct fs_context *fc,
|
||||
struct fs_parameter *param)
|
||||
{
|
||||
|
@ -374,6 +374,11 @@ void security_bprm_committed_creds(struct linux_binprm *bprm)
|
||||
call_void_hook(bprm_committed_creds, bprm);
|
||||
}
|
||||
|
||||
int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
|
||||
{
|
||||
return call_int_hook(fs_context_dup, 0, fc, src_fc);
|
||||
}
|
||||
|
||||
int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
||||
{
|
||||
return call_int_hook(fs_context_parse_param, -ENOPARAM, fc, param);
|
||||
|
@ -2764,6 +2764,44 @@ static int selinux_umount(struct vfsmount *mnt, int flags)
|
||||
FILESYSTEM__UNMOUNT, NULL);
|
||||
}
|
||||
|
||||
static int selinux_fs_context_dup(struct fs_context *fc,
|
||||
struct fs_context *src_fc)
|
||||
{
|
||||
const struct selinux_mnt_opts *src = src_fc->security;
|
||||
struct selinux_mnt_opts *opts;
|
||||
|
||||
if (!src)
|
||||
return 0;
|
||||
|
||||
fc->security = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL);
|
||||
if (!fc->security)
|
||||
return -ENOMEM;
|
||||
|
||||
opts = fc->security;
|
||||
|
||||
if (src->fscontext) {
|
||||
opts->fscontext = kstrdup(src->fscontext, GFP_KERNEL);
|
||||
if (!opts->fscontext)
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (src->context) {
|
||||
opts->context = kstrdup(src->context, GFP_KERNEL);
|
||||
if (!opts->context)
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (src->rootcontext) {
|
||||
opts->rootcontext = kstrdup(src->rootcontext, GFP_KERNEL);
|
||||
if (!opts->rootcontext)
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (src->defcontext) {
|
||||
opts->defcontext = kstrdup(src->defcontext, GFP_KERNEL);
|
||||
if (!opts->defcontext)
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct fs_parameter_spec selinux_param_specs[] = {
|
||||
fsparam_string(CONTEXT_STR, Opt_context),
|
||||
fsparam_string(DEFCONTEXT_STR, Opt_defcontext),
|
||||
@ -6745,6 +6783,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
|
||||
LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
|
||||
LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
|
||||
|
||||
LSM_HOOK_INIT(fs_context_dup, selinux_fs_context_dup),
|
||||
LSM_HOOK_INIT(fs_context_parse_param, selinux_fs_context_parse_param),
|
||||
|
||||
LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
|
||||
|
@ -647,6 +647,54 @@ out_opt_err:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* smack_fs_context_dup - Duplicate the security data on fs_context duplication
|
||||
* @fc: The new filesystem context.
|
||||
* @src_fc: The source filesystem context being duplicated.
|
||||
*
|
||||
* Returns 0 on success or -ENOMEM on error.
|
||||
*/
|
||||
static int smack_fs_context_dup(struct fs_context *fc,
|
||||
struct fs_context *src_fc)
|
||||
{
|
||||
struct smack_mnt_opts *dst, *src = src_fc->security;
|
||||
|
||||
if (!src)
|
||||
return 0;
|
||||
|
||||
fc->security = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL);
|
||||
if (!fc->security)
|
||||
return -ENOMEM;
|
||||
dst = fc->security;
|
||||
|
||||
if (src->fsdefault) {
|
||||
dst->fsdefault = kstrdup(src->fsdefault, GFP_KERNEL);
|
||||
if (!dst->fsdefault)
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (src->fsfloor) {
|
||||
dst->fsfloor = kstrdup(src->fsfloor, GFP_KERNEL);
|
||||
if (!dst->fsfloor)
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (src->fshat) {
|
||||
dst->fshat = kstrdup(src->fshat, GFP_KERNEL);
|
||||
if (!dst->fshat)
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (src->fsroot) {
|
||||
dst->fsroot = kstrdup(src->fsroot, GFP_KERNEL);
|
||||
if (!dst->fsroot)
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (src->fstransmute) {
|
||||
dst->fstransmute = kstrdup(src->fstransmute, GFP_KERNEL);
|
||||
if (!dst->fstransmute)
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct fs_parameter_spec smack_param_specs[] = {
|
||||
fsparam_string("fsdefault", Opt_fsdefault),
|
||||
fsparam_string("fsfloor", Opt_fsfloor),
|
||||
@ -4626,6 +4674,7 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
|
||||
LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
|
||||
LSM_HOOK_INIT(syslog, smack_syslog),
|
||||
|
||||
LSM_HOOK_INIT(fs_context_dup, smack_fs_context_dup),
|
||||
LSM_HOOK_INIT(fs_context_parse_param, smack_fs_context_parse_param),
|
||||
|
||||
LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security),
|
||||
|
Loading…
Reference in New Issue
Block a user