Commit 0b52075e authored by Al Viro's avatar Al Viro

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent cb50b348
...@@ -337,6 +337,47 @@ void fc_drop_locked(struct fs_context *fc) ...@@ -337,6 +337,47 @@ void fc_drop_locked(struct fs_context *fc)
static void legacy_fs_context_free(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. * put_fs_context - Dispose of a superblock configuration context.
* @fc: The context to dispose of. * @fc: The context to dispose of.
...@@ -380,6 +421,31 @@ static void legacy_fs_context_free(struct fs_context *fc) ...@@ -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 * Add a parameter to a legacy config. We build up a comma-separated list of
* options. * options.
...@@ -514,6 +580,7 @@ static int legacy_reconfigure(struct fs_context *fc) ...@@ -514,6 +580,7 @@ static int legacy_reconfigure(struct fs_context *fc)
const struct fs_context_operations legacy_fs_context_ops = { const struct fs_context_operations legacy_fs_context_ops = {
.free = legacy_fs_context_free, .free = legacy_fs_context_free,
.dup = legacy_fs_context_dup,
.parse_param = legacy_parse_param, .parse_param = legacy_parse_param,
.parse_monolithic = legacy_parse_monolithic, .parse_monolithic = legacy_parse_monolithic,
.get_tree = legacy_get_tree, .get_tree = legacy_get_tree,
......
...@@ -94,6 +94,7 @@ struct fs_context { ...@@ -94,6 +94,7 @@ struct fs_context {
struct fs_context_operations { struct fs_context_operations {
void (*free)(struct fs_context *fc); 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_param)(struct fs_context *fc, struct fs_parameter *param);
int (*parse_monolithic)(struct fs_context *fc, void *data); int (*parse_monolithic)(struct fs_context *fc, void *data);
int (*get_tree)(struct fs_context *fc); int (*get_tree)(struct fs_context *fc);
...@@ -111,6 +112,7 @@ extern struct fs_context *fs_context_for_reconfigure(struct dentry *dentry, ...@@ -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, extern struct fs_context *fs_context_for_submount(struct file_system_type *fs_type,
struct dentry *reference); 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_param(struct fs_context *fc, struct fs_parameter *param);
extern int vfs_parse_fs_string(struct fs_context *fc, const char *key, extern int vfs_parse_fs_string(struct fs_context *fc, const char *key,
const char *value, size_t v_size); const char *value, size_t v_size);
......
...@@ -79,6 +79,11 @@ ...@@ -79,6 +79,11 @@
* Security hooks for mount using fs_context. * Security hooks for mount using fs_context.
* [See also Documentation/filesystems/mounting.txt] * [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: * @fs_context_parse_param:
* Userspace provided a parameter to configure a superblock. The LSM may * 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 * reject it with an error and may use it for itself, in which case it
...@@ -1470,6 +1475,7 @@ union security_list_options { ...@@ -1470,6 +1475,7 @@ union security_list_options {
void (*bprm_committing_creds)(struct linux_binprm *bprm); void (*bprm_committing_creds)(struct linux_binprm *bprm);
void (*bprm_committed_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 (*fs_context_parse_param)(struct fs_context *fc, struct fs_parameter *param);
int (*sb_alloc_security)(struct super_block *sb); int (*sb_alloc_security)(struct super_block *sb);
...@@ -1813,6 +1819,7 @@ struct security_hook_heads { ...@@ -1813,6 +1819,7 @@ struct security_hook_heads {
struct hlist_head bprm_check_security; struct hlist_head bprm_check_security;
struct hlist_head bprm_committing_creds; struct hlist_head bprm_committing_creds;
struct hlist_head bprm_committed_creds; struct hlist_head bprm_committed_creds;
struct hlist_head fs_context_dup;
struct hlist_head fs_context_parse_param; struct hlist_head fs_context_parse_param;
struct hlist_head sb_alloc_security; struct hlist_head sb_alloc_security;
struct hlist_head sb_free_security; struct hlist_head sb_free_security;
......
...@@ -223,6 +223,7 @@ int security_bprm_set_creds(struct linux_binprm *bprm); ...@@ -223,6 +223,7 @@ int security_bprm_set_creds(struct linux_binprm *bprm);
int security_bprm_check(struct linux_binprm *bprm); int security_bprm_check(struct linux_binprm *bprm);
void security_bprm_committing_creds(struct linux_binprm *bprm); void security_bprm_committing_creds(struct linux_binprm *bprm);
void security_bprm_committed_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_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param);
int security_sb_alloc(struct super_block *sb); int security_sb_alloc(struct super_block *sb);
void security_sb_free(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) ...@@ -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, static inline int security_fs_context_parse_param(struct fs_context *fc,
struct fs_parameter *param) struct fs_parameter *param)
{ {
......
...@@ -374,6 +374,11 @@ void security_bprm_committed_creds(struct linux_binprm *bprm) ...@@ -374,6 +374,11 @@ void security_bprm_committed_creds(struct linux_binprm *bprm)
call_void_hook(bprm_committed_creds, 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) 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); return call_int_hook(fs_context_parse_param, -ENOPARAM, fc, param);
......
...@@ -2764,6 +2764,44 @@ static int selinux_umount(struct vfsmount *mnt, int flags) ...@@ -2764,6 +2764,44 @@ static int selinux_umount(struct vfsmount *mnt, int flags)
FILESYSTEM__UNMOUNT, NULL); 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[] = { static const struct fs_parameter_spec selinux_param_specs[] = {
fsparam_string(CONTEXT_STR, Opt_context), fsparam_string(CONTEXT_STR, Opt_context),
fsparam_string(DEFCONTEXT_STR, Opt_defcontext), fsparam_string(DEFCONTEXT_STR, Opt_defcontext),
...@@ -6745,6 +6783,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { ...@@ -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_committing_creds, selinux_bprm_committing_creds),
LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_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(fs_context_parse_param, selinux_fs_context_parse_param),
LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security), LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
......
...@@ -647,6 +647,54 @@ static int smack_add_opt(int token, const char *s, void **mnt_opts) ...@@ -647,6 +647,54 @@ static int smack_add_opt(int token, const char *s, void **mnt_opts)
return -EINVAL; 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[] = { static const struct fs_parameter_spec smack_param_specs[] = {
fsparam_string("fsdefault", Opt_fsdefault), fsparam_string("fsdefault", Opt_fsdefault),
fsparam_string("fsfloor", Opt_fsfloor), fsparam_string("fsfloor", Opt_fsfloor),
...@@ -4626,6 +4674,7 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { ...@@ -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(ptrace_traceme, smack_ptrace_traceme),
LSM_HOOK_INIT(syslog, smack_syslog), 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(fs_context_parse_param, smack_fs_context_parse_param),
LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security), LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment