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

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
Loading
Loading
Loading
Loading
+67 −0
Original line number Diff line number Diff line
@@ -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,
+2 −0
Original line number Diff line number Diff line
@@ -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);
+7 −0
Original line number Diff line number Diff line
@@ -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;
+6 −0
Original line number Diff line number Diff line
@@ -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)
{
+5 −0
Original line number Diff line number Diff line
@@ -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);
Loading