new helper: security_sb_eat_lsm_opts()

combination of alloc_secdata(), security_sb_copy_data(),
security_sb_parse_opt_str() and free_secdata().

Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index b362b45..6fc8e96 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1461,20 +1461,7 @@ static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid,
 static int parse_security_options(char *orig_opts,
 				  struct security_mnt_opts *sec_opts)
 {
-	char *secdata = NULL;
-	int ret = 0;
-
-	secdata = alloc_secdata();
-	if (!secdata)
-		return -ENOMEM;
-	ret = security_sb_copy_data(orig_opts, secdata);
-	if (ret) {
-		free_secdata(secdata);
-		return ret;
-	}
-	ret = security_sb_parse_opts_str(secdata, sec_opts);
-	free_secdata(secdata);
-	return ret;
+	return security_sb_eat_lsm_opts(orig_opts, sec_opts);
 }
 
 static int setup_security_options(struct btrfs_fs_info *fs_info,
diff --git a/fs/namespace.c b/fs/namespace.c
index 341793f..39aca7b 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2312,16 +2312,7 @@ static int do_remount(struct path *path, int ms_flags, int sb_flags,
 
 	security_init_mnt_opts(&opts);
 	if (data && !(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)) {
-		char *secdata = alloc_secdata();
-		if (!secdata)
-			return -ENOMEM;
-		err = security_sb_copy_data(data, secdata);
-		if (err) {
-			free_secdata(secdata);
-			return err;
-		}
-		err = security_sb_parse_opts_str(secdata, &opts);
-		free_secdata(secdata);
+		err = security_sb_eat_lsm_opts(data, &opts);
 		if (err)
 			return err;
 	}
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index ac4b2f0..f9c8847 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1206,7 +1206,7 @@ static int nfs_get_option_ul_bound(substring_t args[], unsigned long *option,
 static int nfs_parse_mount_options(char *raw,
 				   struct nfs_parsed_mount_data *mnt)
 {
-	char *p, *string, *secdata;
+	char *p, *string;
 	int rc, sloppy = 0, invalid_option = 0;
 	unsigned short protofamily = AF_UNSPEC;
 	unsigned short mountfamily = AF_UNSPEC;
@@ -1217,20 +1217,10 @@ static int nfs_parse_mount_options(char *raw,
 	}
 	dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw);
 
-	secdata = alloc_secdata();
-	if (!secdata)
-		goto out_nomem;
-
-	rc = security_sb_copy_data(raw, secdata);
+	rc = security_sb_eat_lsm_opts(raw, &mnt->lsm_opts);
 	if (rc)
 		goto out_security_failure;
 
-	rc = security_sb_parse_opts_str(secdata, &mnt->lsm_opts);
-	if (rc)
-		goto out_security_failure;
-
-	free_secdata(secdata);
-
 	while ((p = strsep(&raw, ",")) != NULL) {
 		substring_t args[MAX_OPT_ARGS];
 		unsigned long option;
@@ -1682,7 +1672,6 @@ static int nfs_parse_mount_options(char *raw,
 	printk(KERN_INFO "NFS: not enough memory to parse option\n");
 	return 0;
 out_security_failure:
-	free_secdata(secdata);
 	printk(KERN_INFO "NFS: security options invalid: %d\n", rc);
 	return 0;
 }
diff --git a/fs/super.c b/fs/super.c
index 8d9c919..d571527 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1252,18 +1252,7 @@ mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
 	security_init_mnt_opts(&opts);
 
 	if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
-		char *secdata = alloc_secdata();
-		if (!secdata)
-			return ERR_PTR(-ENOMEM);
-
-		error = security_sb_copy_data(data, secdata);
-		if (error) {
-			free_secdata(secdata);
-			return ERR_PTR(error);
-		}
-
-		error = security_sb_parse_opts_str(secdata, &opts);
-		free_secdata(secdata);
+		error = security_sb_eat_lsm_opts(data, &opts);
 		if (error)
 			return ERR_PTR(error);
 	}
diff --git a/include/linux/security.h b/include/linux/security.h
index 4fc6d98..262e598 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -248,7 +248,7 @@ void security_bprm_committing_creds(struct linux_binprm *bprm);
 void security_bprm_committed_creds(struct linux_binprm *bprm);
 int security_sb_alloc(struct super_block *sb);
 void security_sb_free(struct super_block *sb);
-int security_sb_copy_data(char *orig, char *copy);
+int security_sb_eat_lsm_opts(char *options, struct security_mnt_opts *opts);
 int security_sb_remount(struct super_block *sb, struct security_mnt_opts *opts);
 int security_sb_kern_mount(struct super_block *sb, int flags,
 			   struct security_mnt_opts *opts);
@@ -556,7 +556,8 @@ static inline int security_sb_alloc(struct super_block *sb)
 static inline void security_sb_free(struct super_block *sb)
 { }
 
-static inline int security_sb_copy_data(char *orig, char *copy)
+static inline int security_sb_eat_lsm_opts(char *options,
+					   struct security_mnt_opts *opts)
 {
 	return 0;
 }
@@ -1823,28 +1824,5 @@ static inline void security_bpf_prog_free(struct bpf_prog_aux *aux)
 #endif /* CONFIG_SECURITY */
 #endif /* CONFIG_BPF_SYSCALL */
 
-#ifdef CONFIG_SECURITY
-
-static inline char *alloc_secdata(void)
-{
-	return (char *)get_zeroed_page(GFP_KERNEL);
-}
-
-static inline void free_secdata(void *secdata)
-{
-	free_page((unsigned long)secdata);
-}
-
-#else
-
-static inline char *alloc_secdata(void)
-{
-        return (char *)1;
-}
-
-static inline void free_secdata(void *secdata)
-{ }
-#endif /* CONFIG_SECURITY */
-
 #endif /* ! __LINUX_SECURITY_H */
 
diff --git a/security/security.c b/security/security.c
index 3f50beb..02c656d 100644
--- a/security/security.c
+++ b/security/security.c
@@ -384,11 +384,20 @@ void security_sb_free(struct super_block *sb)
 	call_void_hook(sb_free_security, sb);
 }
 
-int security_sb_copy_data(char *orig, char *copy)
+int security_sb_eat_lsm_opts(char *options, struct security_mnt_opts *opts)
 {
-	return call_int_hook(sb_copy_data, 0, orig, copy);
+	char *s = (char *)get_zeroed_page(GFP_KERNEL);
+	int err;
+
+	if (!s)
+		return -ENOMEM;
+	err = call_int_hook(sb_copy_data, 0, options, s);
+	if (!err)
+		err = call_int_hook(sb_parse_opts_str, 0, s, opts);
+	free_page((unsigned long)s);
+	return err;
 }
-EXPORT_SYMBOL(security_sb_copy_data);
+EXPORT_SYMBOL(security_sb_eat_lsm_opts);
 
 int security_sb_remount(struct super_block *sb,
 			struct security_mnt_opts *opts)