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>
This commit is contained in:
@@ -2299,6 +2299,7 @@ static int do_remount(struct path *path, int ms_flags, int sb_flags,
|
|||||||
int err;
|
int err;
|
||||||
struct super_block *sb = path->mnt->mnt_sb;
|
struct super_block *sb = path->mnt->mnt_sb;
|
||||||
struct mount *mnt = real_mount(path->mnt);
|
struct mount *mnt = real_mount(path->mnt);
|
||||||
|
struct security_mnt_opts opts;
|
||||||
|
|
||||||
if (!check_mnt(mnt))
|
if (!check_mnt(mnt))
|
||||||
return -EINVAL;
|
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))
|
if (!can_change_locked_flags(mnt, mnt_flags))
|
||||||
return -EPERM;
|
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)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
|||||||
@@ -1462,7 +1462,8 @@ union security_list_options {
|
|||||||
int (*sb_alloc_security)(struct super_block *sb);
|
int (*sb_alloc_security)(struct super_block *sb);
|
||||||
void (*sb_free_security)(struct super_block *sb);
|
void (*sb_free_security)(struct super_block *sb);
|
||||||
int (*sb_copy_data)(char *orig, char *copy);
|
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,
|
int (*sb_kern_mount)(struct super_block *sb, int flags,
|
||||||
struct security_mnt_opts *opts);
|
struct security_mnt_opts *opts);
|
||||||
int (*sb_show_options)(struct seq_file *m, struct super_block *sb);
|
int (*sb_show_options)(struct seq_file *m, struct super_block *sb);
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ void security_bprm_committed_creds(struct linux_binprm *bprm);
|
|||||||
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);
|
||||||
int security_sb_copy_data(char *orig, char *copy);
|
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,
|
int security_sb_kern_mount(struct super_block *sb, int flags,
|
||||||
struct security_mnt_opts *opts);
|
struct security_mnt_opts *opts);
|
||||||
int security_sb_show_options(struct seq_file *m, struct super_block *sb);
|
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;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -390,9 +390,10 @@ int security_sb_copy_data(char *orig, char *copy)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(security_sb_copy_data);
|
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,
|
int security_sb_kern_mount(struct super_block *sb, int flags,
|
||||||
|
|||||||
@@ -2812,39 +2812,22 @@ out:
|
|||||||
return rc;
|
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;
|
int i, *flags;
|
||||||
struct security_mnt_opts opts;
|
char **mount_options;
|
||||||
char *secdata, **mount_options;
|
|
||||||
struct superblock_security_struct *sbsec = sb->s_security;
|
struct superblock_security_struct *sbsec = sb->s_security;
|
||||||
|
|
||||||
if (!(sbsec->flags & SE_SBINITIALIZED))
|
if (!(sbsec->flags & SE_SBINITIALIZED))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!data)
|
mount_options = opts->mnt_opts;
|
||||||
return 0;
|
flags = opts->mnt_opts_flags;
|
||||||
|
|
||||||
if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
|
for (i = 0; i < opts->num_mnt_opts; i++) {
|
||||||
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;
|
|
||||||
|
|
||||||
for (i = 0; i < opts.num_mnt_opts; i++) {
|
|
||||||
u32 sid;
|
u32 sid;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (flags[i] == SBLABEL_MNT)
|
if (flags[i] == SBLABEL_MNT)
|
||||||
continue;
|
continue;
|
||||||
@@ -2855,9 +2838,8 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
|
|||||||
pr_warn("SELinux: security_context_str_to_sid"
|
pr_warn("SELinux: security_context_str_to_sid"
|
||||||
"(%s) failed for (dev %s, type %s) errno=%d\n",
|
"(%s) failed for (dev %s, type %s) errno=%d\n",
|
||||||
mount_options[i], sb->s_id, sb->s_type->name, rc);
|
mount_options[i], sb->s_id, sb->s_type->name, rc);
|
||||||
goto out_free_opts;
|
return rc;
|
||||||
}
|
}
|
||||||
rc = -EINVAL;
|
|
||||||
switch (flags[i]) {
|
switch (flags[i]) {
|
||||||
case FSCONTEXT_MNT:
|
case FSCONTEXT_MNT:
|
||||||
if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
|
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;
|
goto out_bad_option;
|
||||||
break;
|
break;
|
||||||
default:
|
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:
|
out_bad_option:
|
||||||
pr_warn("SELinux: unable to change security options "
|
pr_warn("SELinux: unable to change security options "
|
||||||
"during remount (dev %s, type=%s)\n", sb->s_id,
|
"during remount (dev %s, type=%s)\n", sb->s_id,
|
||||||
sb->s_type->name);
|
sb->s_type->name);
|
||||||
goto out_free_opts;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int selinux_sb_kern_mount(struct super_block *sb, int flags,
|
static int selinux_sb_kern_mount(struct super_block *sb, int flags,
|
||||||
|
|||||||
Reference in New Issue
Block a user