|
@@ -2363,6 +2363,91 @@ out:
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
+static int selinux_sb_remount(struct super_block *sb, void *data)
|
|
|
+{
|
|
|
+ int rc, i, *flags;
|
|
|
+ struct security_mnt_opts opts;
|
|
|
+ char *secdata, **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;
|
|
|
+
|
|
|
+ for (i = 0; i < opts.num_mnt_opts; i++) {
|
|
|
+ u32 sid;
|
|
|
+ size_t len;
|
|
|
+
|
|
|
+ if (flags[i] == SE_SBLABELSUPP)
|
|
|
+ continue;
|
|
|
+ len = strlen(mount_options[i]);
|
|
|
+ rc = security_context_to_sid(mount_options[i], len, &sid);
|
|
|
+ if (rc) {
|
|
|
+ printk(KERN_WARNING "SELinux: security_context_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;
|
|
|
+ }
|
|
|
+ rc = -EINVAL;
|
|
|
+ switch (flags[i]) {
|
|
|
+ case FSCONTEXT_MNT:
|
|
|
+ if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
|
|
|
+ goto out_bad_option;
|
|
|
+ break;
|
|
|
+ case CONTEXT_MNT:
|
|
|
+ if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
|
|
|
+ goto out_bad_option;
|
|
|
+ break;
|
|
|
+ case ROOTCONTEXT_MNT: {
|
|
|
+ struct inode_security_struct *root_isec;
|
|
|
+ root_isec = sb->s_root->d_inode->i_security;
|
|
|
+
|
|
|
+ if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
|
|
|
+ goto out_bad_option;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case DEFCONTEXT_MNT:
|
|
|
+ if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
|
|
|
+ goto out_bad_option;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ goto out_free_opts;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ rc = 0;
|
|
|
+out_free_opts:
|
|
|
+ security_free_mnt_opts(&opts);
|
|
|
+out_free_secdata:
|
|
|
+ free_secdata(secdata);
|
|
|
+ return rc;
|
|
|
+out_bad_option:
|
|
|
+ printk(KERN_WARNING "SELinux: unable to change security options "
|
|
|
+ "during remount (dev %s, type=%s)\n", sb->s_id,
|
|
|
+ sb->s_type->name);
|
|
|
+ goto out_free_opts;
|
|
|
+}
|
|
|
+
|
|
|
static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
|
|
|
{
|
|
|
const struct cred *cred = current_cred();
|
|
@@ -5356,6 +5441,7 @@ static struct security_operations selinux_ops = {
|
|
|
.sb_alloc_security = selinux_sb_alloc_security,
|
|
|
.sb_free_security = selinux_sb_free_security,
|
|
|
.sb_copy_data = selinux_sb_copy_data,
|
|
|
+ .sb_remount = selinux_sb_remount,
|
|
|
.sb_kern_mount = selinux_sb_kern_mount,
|
|
|
.sb_show_options = selinux_sb_show_options,
|
|
|
.sb_statfs = selinux_sb_statfs,
|