aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2018-12-01 23:06:57 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2018-12-21 11:45:41 -0500
commitc039bc3c2498724946304a8f964244a9b6af1043 (patch)
treece98ee8e698a28cbaed969460457941e8b34f2e3
parent6be8750b4cba8c37170f46b29841d112f1be749b (diff)
downloadlinux-c039bc3c2498724946304a8f964244a9b6af1043.tar.gz
LSM: lift extracting and parsing LSM options into the caller of ->sb_remount()
This paves the way for retaining the LSM options from a common filesystem mount context during a mount parameter parsing phase to be instituted prior to actual mount/reconfiguration actions. Reviewed-by: David Howells <dhowells@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/namespace.c19
-rw-r--r--include/linux/lsm_hooks.h3
-rw-r--r--include/linux/security.h5
-rw-r--r--security/security.c5
-rw-r--r--security/selinux/hooks.c47
5 files changed, 38 insertions, 41 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 08cffdad6665..341793fbd390 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2299,6 +2299,7 @@ static int do_remount(struct path *path, int ms_flags, int sb_flags,
int err;
struct super_block *sb = path->mnt->mnt_sb;
struct mount *mnt = real_mount(path->mnt);
+ struct security_mnt_opts opts;
if (!check_mnt(mnt))
return -EINVAL;
@@ -2309,7 +2310,23 @@ static int do_remount(struct path *path, int ms_flags, int sb_flags,
if (!can_change_locked_flags(mnt, mnt_flags))
return -EPERM;
- err = security_sb_remount(sb, data);
+ 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);
+ if (err)
+ return err;
+ }
+ err = security_sb_remount(sb, &opts);
+ security_free_mnt_opts(&opts);
if (err)
return err;
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index c7f67341fd1d..e1a12a1e2b32 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1462,7 +1462,8 @@ union security_list_options {
int (*sb_alloc_security)(struct super_block *sb);
void (*sb_free_security)(struct super_block *sb);
int (*sb_copy_data)(char *orig, char *copy);
- int (*sb_remount)(struct super_block *sb, void *data);
+ int (*sb_remount)(struct super_block *sb,
+ struct security_mnt_opts *opts);
int (*sb_kern_mount)(struct super_block *sb, int flags,
struct security_mnt_opts *opts);
int (*sb_show_options)(struct seq_file *m, struct super_block *sb);
diff --git a/include/linux/security.h b/include/linux/security.h
index f2f88e41f35f..4fc6d98bc7a6 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -249,7 +249,7 @@ 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_remount(struct super_block *sb, void *data);
+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);
int security_sb_show_options(struct seq_file *m, struct super_block *sb);
@@ -561,7 +561,8 @@ static inline int security_sb_copy_data(char *orig, char *copy)
return 0;
}
-static inline int security_sb_remount(struct super_block *sb, void *data)
+static inline int security_sb_remount(struct super_block *sb,
+ struct security_mnt_opts *opts)
{
return 0;
}
diff --git a/security/security.c b/security/security.c
index b5fc8e1e849c..3f50beb30fb1 100644
--- a/security/security.c
+++ b/security/security.c
@@ -390,9 +390,10 @@ int security_sb_copy_data(char *orig, char *copy)
}
EXPORT_SYMBOL(security_sb_copy_data);
-int security_sb_remount(struct super_block *sb, void *data)
+int security_sb_remount(struct super_block *sb,
+ struct security_mnt_opts *opts)
{
- return call_int_hook(sb_remount, 0, sb, data);
+ return call_int_hook(sb_remount, 0, sb, opts);
}
int security_sb_kern_mount(struct super_block *sb, int flags,
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index ba229d4a64d3..ba3e2917bd24 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2812,39 +2812,22 @@ out:
return rc;
}
-static int selinux_sb_remount(struct super_block *sb, void *data)
+static int selinux_sb_remount(struct super_block *sb,
+ struct security_mnt_opts *opts)
{
- int rc, i, *flags;
- struct security_mnt_opts opts;
- char *secdata, **mount_options;
+ int i, *flags;
+ char **mount_options;
struct superblock_security_struct *sbsec = sb->s_security;
if (!(sbsec->flags & SE_SBINITIALIZED))
return 0;
- if (!data)
- return 0;
-
- if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
- return 0;
-
- security_init_mnt_opts(&opts);
- secdata = alloc_secdata();
- if (!secdata)
- return -ENOMEM;
- rc = selinux_sb_copy_data(data, secdata);
- if (rc)
- goto out_free_secdata;
-
- rc = selinux_parse_opts_str(secdata, &opts);
- if (rc)
- goto out_free_secdata;
+ mount_options = opts->mnt_opts;
+ flags = opts->mnt_opts_flags;
- mount_options = opts.mnt_opts;
- flags = opts.mnt_opts_flags;
-
- for (i = 0; i < opts.num_mnt_opts; i++) {
+ for (i = 0; i < opts->num_mnt_opts; i++) {
u32 sid;
+ int rc;
if (flags[i] == SBLABEL_MNT)
continue;
@@ -2855,9 +2838,8 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
pr_warn("SELinux: security_context_str_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n",
mount_options[i], sb->s_id, sb->s_type->name, rc);
- goto out_free_opts;
+ return rc;
}
- rc = -EINVAL;
switch (flags[i]) {
case FSCONTEXT_MNT:
if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
@@ -2880,21 +2862,16 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
goto out_bad_option;
break;
default:
- goto out_free_opts;
+ return -EINVAL;
}
}
+ return 0;
- rc = 0;
-out_free_opts:
- security_free_mnt_opts(&opts);
-out_free_secdata:
- free_secdata(secdata);
- return rc;
out_bad_option:
pr_warn("SELinux: unable to change security options "
"during remount (dev %s, type=%s)\n", sb->s_id,
sb->s_type->name);
- goto out_free_opts;
+ return -EINVAL;
}
static int selinux_sb_kern_mount(struct super_block *sb, int flags,