Loading security/selinux/hooks.c +101 −161 Original line number Diff line number Diff line Loading @@ -433,16 +433,17 @@ static void superblock_free_security(struct super_block *sb) kfree(sbsec); } struct selinux_mnt_opts { const char *fscontext, *context, *rootcontext, *defcontext; }; static void selinux_free_mnt_opts(void *mnt_opts) { struct security_mnt_opts *opts = mnt_opts; int i; if (opts->mnt_opts) for (i = 0; i < opts->num_mnt_opts; i++) kfree(opts->mnt_opts[i]); kfree(opts->mnt_opts); kfree(opts->mnt_opts_flags); struct selinux_mnt_opts *opts = mnt_opts; kfree(opts->fscontext); kfree(opts->context); kfree(opts->rootcontext); kfree(opts->defcontext); kfree(opts); } Loading Loading @@ -624,6 +625,17 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag, return 0; } static int parse_sid(struct super_block *sb, const char *s, u32 *sid) { int rc = security_context_str_to_sid(&selinux_state, s, sid, GFP_KERNEL); if (rc) pr_warn("SELinux: security_context_str_to_sid" "(%s) failed for (dev %s, type %s) errno=%d\n", s, sb->s_id, sb->s_type->name, rc); return rc; } /* * Allow filesystems with binary mount data to explicitly set mount point * labeling information. Loading @@ -634,22 +646,18 @@ static int selinux_set_mnt_opts(struct super_block *sb, unsigned long *set_kern_flags) { const struct cred *cred = current_cred(); int rc = 0, i; struct superblock_security_struct *sbsec = sb->s_security; const char *name = sb->s_type->name; struct dentry *root = sbsec->sb->s_root; struct selinux_mnt_opts *opts = mnt_opts; struct inode_security_struct *root_isec; u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; u32 defcontext_sid = 0; struct security_mnt_opts *opts = mnt_opts; char **mount_options = opts ? opts->mnt_opts : NULL; int *flags = opts ? opts->mnt_opts_flags : NULL; int num_opts = opts ? opts->num_mnt_opts : 0; int rc = 0; mutex_lock(&sbsec->lock); if (!selinux_state.initialized) { if (!num_opts) { if (!opts) { /* Defer initialization until selinux_complete_init, after the initial policy is loaded and the security server is ready to handle calls. */ Loading Loading @@ -679,7 +687,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, * will be used for both mounts) */ if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) && (num_opts == 0)) && !opts) goto out; root_isec = backing_inode_security_novalidate(root); Loading @@ -689,68 +697,48 @@ static int selinux_set_mnt_opts(struct super_block *sb, * also check if someone is trying to mount the same sb more * than once with different security options. */ for (i = 0; i < num_opts; i++) { u32 sid; if (flags[i] == SBLABEL_MNT) continue; rc = security_context_str_to_sid(&selinux_state, mount_options[i], &sid, GFP_KERNEL); if (rc) { pr_warn("SELinux: security_context_str_to_sid" "(%s) failed for (dev %s, type %s) errno=%d\n", mount_options[i], sb->s_id, name, rc); if (opts) { if (opts->fscontext) { rc = parse_sid(sb, opts->fscontext, &fscontext_sid); if (rc) goto out; } switch (flags[i]) { case FSCONTEXT_MNT: fscontext_sid = sid; if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, fscontext_sid)) goto out_double_mount; sbsec->flags |= FSCONTEXT_MNT; break; case CONTEXT_MNT: context_sid = sid; } if (opts->context) { rc = parse_sid(sb, opts->context, &context_sid); if (rc) goto out; if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, context_sid)) goto out_double_mount; sbsec->flags |= CONTEXT_MNT; break; case ROOTCONTEXT_MNT: rootcontext_sid = sid; } if (opts->rootcontext) { rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid); if (rc) goto out; if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, rootcontext_sid)) goto out_double_mount; sbsec->flags |= ROOTCONTEXT_MNT; break; case DEFCONTEXT_MNT: defcontext_sid = sid; } if (opts->defcontext) { rc = parse_sid(sb, opts->defcontext, &defcontext_sid); if (rc) goto out; if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, defcontext_sid)) goto out_double_mount; sbsec->flags |= DEFCONTEXT_MNT; break; default: rc = -EINVAL; goto out; } } if (sbsec->flags & SE_SBINITIALIZED) { /* previously mounted with options, but not on this attempt? */ if ((sbsec->flags & SE_MNTMASK) && !num_opts) if ((sbsec->flags & SE_MNTMASK) && !opts) goto out_double_mount; rc = 0; goto out; Loading Loading @@ -883,7 +871,8 @@ static int selinux_set_mnt_opts(struct super_block *sb, out_double_mount: rc = -EINVAL; pr_warn("SELinux: mount invalid. Same superblock, different " "security settings for (dev %s, type %s)\n", sb->s_id, name); "security settings for (dev %s, type %s)\n", sb->s_id, sb->s_type->name); goto out; } Loading Loading @@ -998,20 +987,9 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, static int selinux_parse_opts_str(char *options, void **mnt_opts) { struct selinux_mnt_opts *opts = *mnt_opts; char *p; char *context = NULL, *defcontext = NULL; char *fscontext = NULL, *rootcontext = NULL; int rc, num_mnt_opts = 0; struct security_mnt_opts *opts = *mnt_opts; if (!opts) { opts = kzalloc(sizeof(struct security_mnt_opts), GFP_KERNEL); *mnt_opts = opts; if (!opts) return -ENOMEM; } opts->num_mnt_opts = 0; int rc; /* Standard string-based options. */ while ((p = strsep(&options, "|")) != NULL) { Loading @@ -1023,54 +1001,60 @@ static int selinux_parse_opts_str(char *options, token = match_token(p, tokens, args); if (!opts) { opts = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL); if (!opts) return -ENOMEM; } switch (token) { case Opt_context: if (context || defcontext) { if (opts->context || opts->defcontext) { rc = -EINVAL; pr_warn(SEL_MOUNT_FAIL_MSG); goto out_err; } context = match_strdup(&args[0]); if (!context) { opts->context = match_strdup(&args[0]); if (!opts->context) { rc = -ENOMEM; goto out_err; } break; case Opt_fscontext: if (fscontext) { if (opts->fscontext) { rc = -EINVAL; pr_warn(SEL_MOUNT_FAIL_MSG); goto out_err; } fscontext = match_strdup(&args[0]); if (!fscontext) { opts->fscontext = match_strdup(&args[0]); if (!opts->fscontext) { rc = -ENOMEM; goto out_err; } break; case Opt_rootcontext: if (rootcontext) { if (opts->rootcontext) { rc = -EINVAL; pr_warn(SEL_MOUNT_FAIL_MSG); goto out_err; } rootcontext = match_strdup(&args[0]); if (!rootcontext) { opts->rootcontext = match_strdup(&args[0]); if (!opts->rootcontext) { rc = -ENOMEM; goto out_err; } break; case Opt_defcontext: if (context || defcontext) { if (opts->context || opts->defcontext) { rc = -EINVAL; pr_warn(SEL_MOUNT_FAIL_MSG); goto out_err; } defcontext = match_strdup(&args[0]); if (!defcontext) { opts->defcontext = match_strdup(&args[0]); if (!opts->defcontext) { rc = -ENOMEM; goto out_err; } Loading @@ -1084,43 +1068,12 @@ static int selinux_parse_opts_str(char *options, } } rc = -ENOMEM; opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_KERNEL); if (!opts->mnt_opts) goto out_err; opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_KERNEL); if (!opts->mnt_opts_flags) goto out_err; if (fscontext) { opts->mnt_opts[num_mnt_opts] = fscontext; opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT; } if (context) { opts->mnt_opts[num_mnt_opts] = context; opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT; } if (rootcontext) { opts->mnt_opts[num_mnt_opts] = rootcontext; opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT; } if (defcontext) { opts->mnt_opts[num_mnt_opts] = defcontext; opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT; } opts->num_mnt_opts = num_mnt_opts; *mnt_opts = opts; return 0; out_err: security_free_mnt_opts(mnt_opts); kfree(context); kfree(defcontext); kfree(fscontext); kfree(rootcontext); if (opts) selinux_free_mnt_opts(opts); return rc; } Loading Loading @@ -2752,10 +2705,10 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts) static int selinux_sb_remount(struct super_block *sb, void *mnt_opts) { struct security_mnt_opts *opts = mnt_opts; int i, *flags; char **mount_options; struct selinux_mnt_opts *opts = mnt_opts; struct superblock_security_struct *sbsec = sb->s_security; u32 sid; int rc; if (!(sbsec->flags & SE_SBINITIALIZED)) return 0; Loading @@ -2763,48 +2716,35 @@ static int selinux_sb_remount(struct super_block *sb, void *mnt_opts) if (!opts) return 0; mount_options = opts->mnt_opts; flags = opts->mnt_opts_flags; for (i = 0; i < opts->num_mnt_opts; i++) { u32 sid; int rc; if (flags[i] == SBLABEL_MNT) continue; rc = security_context_str_to_sid(&selinux_state, mount_options[i], &sid, GFP_KERNEL); if (rc) { 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); if (opts->fscontext) { rc = parse_sid(sb, opts->fscontext, &sid); if (rc) return rc; } switch (flags[i]) { case FSCONTEXT_MNT: if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid)) goto out_bad_option; break; case CONTEXT_MNT: } if (opts->context) { rc = parse_sid(sb, opts->context, &sid); if (rc) return rc; if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid)) goto out_bad_option; break; case ROOTCONTEXT_MNT: { } if (opts->rootcontext) { struct inode_security_struct *root_isec; root_isec = backing_inode_security(sb->s_root); rc = parse_sid(sb, opts->rootcontext, &sid); if (rc) return rc; if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid)) goto out_bad_option; break; } case DEFCONTEXT_MNT: if (opts->defcontext) { rc = parse_sid(sb, opts->defcontext, &sid); if (rc) return rc; if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid)) goto out_bad_option; break; default: return -EINVAL; } } return 0; Loading Loading
security/selinux/hooks.c +101 −161 Original line number Diff line number Diff line Loading @@ -433,16 +433,17 @@ static void superblock_free_security(struct super_block *sb) kfree(sbsec); } struct selinux_mnt_opts { const char *fscontext, *context, *rootcontext, *defcontext; }; static void selinux_free_mnt_opts(void *mnt_opts) { struct security_mnt_opts *opts = mnt_opts; int i; if (opts->mnt_opts) for (i = 0; i < opts->num_mnt_opts; i++) kfree(opts->mnt_opts[i]); kfree(opts->mnt_opts); kfree(opts->mnt_opts_flags); struct selinux_mnt_opts *opts = mnt_opts; kfree(opts->fscontext); kfree(opts->context); kfree(opts->rootcontext); kfree(opts->defcontext); kfree(opts); } Loading Loading @@ -624,6 +625,17 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag, return 0; } static int parse_sid(struct super_block *sb, const char *s, u32 *sid) { int rc = security_context_str_to_sid(&selinux_state, s, sid, GFP_KERNEL); if (rc) pr_warn("SELinux: security_context_str_to_sid" "(%s) failed for (dev %s, type %s) errno=%d\n", s, sb->s_id, sb->s_type->name, rc); return rc; } /* * Allow filesystems with binary mount data to explicitly set mount point * labeling information. Loading @@ -634,22 +646,18 @@ static int selinux_set_mnt_opts(struct super_block *sb, unsigned long *set_kern_flags) { const struct cred *cred = current_cred(); int rc = 0, i; struct superblock_security_struct *sbsec = sb->s_security; const char *name = sb->s_type->name; struct dentry *root = sbsec->sb->s_root; struct selinux_mnt_opts *opts = mnt_opts; struct inode_security_struct *root_isec; u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; u32 defcontext_sid = 0; struct security_mnt_opts *opts = mnt_opts; char **mount_options = opts ? opts->mnt_opts : NULL; int *flags = opts ? opts->mnt_opts_flags : NULL; int num_opts = opts ? opts->num_mnt_opts : 0; int rc = 0; mutex_lock(&sbsec->lock); if (!selinux_state.initialized) { if (!num_opts) { if (!opts) { /* Defer initialization until selinux_complete_init, after the initial policy is loaded and the security server is ready to handle calls. */ Loading Loading @@ -679,7 +687,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, * will be used for both mounts) */ if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) && (num_opts == 0)) && !opts) goto out; root_isec = backing_inode_security_novalidate(root); Loading @@ -689,68 +697,48 @@ static int selinux_set_mnt_opts(struct super_block *sb, * also check if someone is trying to mount the same sb more * than once with different security options. */ for (i = 0; i < num_opts; i++) { u32 sid; if (flags[i] == SBLABEL_MNT) continue; rc = security_context_str_to_sid(&selinux_state, mount_options[i], &sid, GFP_KERNEL); if (rc) { pr_warn("SELinux: security_context_str_to_sid" "(%s) failed for (dev %s, type %s) errno=%d\n", mount_options[i], sb->s_id, name, rc); if (opts) { if (opts->fscontext) { rc = parse_sid(sb, opts->fscontext, &fscontext_sid); if (rc) goto out; } switch (flags[i]) { case FSCONTEXT_MNT: fscontext_sid = sid; if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, fscontext_sid)) goto out_double_mount; sbsec->flags |= FSCONTEXT_MNT; break; case CONTEXT_MNT: context_sid = sid; } if (opts->context) { rc = parse_sid(sb, opts->context, &context_sid); if (rc) goto out; if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, context_sid)) goto out_double_mount; sbsec->flags |= CONTEXT_MNT; break; case ROOTCONTEXT_MNT: rootcontext_sid = sid; } if (opts->rootcontext) { rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid); if (rc) goto out; if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, rootcontext_sid)) goto out_double_mount; sbsec->flags |= ROOTCONTEXT_MNT; break; case DEFCONTEXT_MNT: defcontext_sid = sid; } if (opts->defcontext) { rc = parse_sid(sb, opts->defcontext, &defcontext_sid); if (rc) goto out; if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, defcontext_sid)) goto out_double_mount; sbsec->flags |= DEFCONTEXT_MNT; break; default: rc = -EINVAL; goto out; } } if (sbsec->flags & SE_SBINITIALIZED) { /* previously mounted with options, but not on this attempt? */ if ((sbsec->flags & SE_MNTMASK) && !num_opts) if ((sbsec->flags & SE_MNTMASK) && !opts) goto out_double_mount; rc = 0; goto out; Loading Loading @@ -883,7 +871,8 @@ static int selinux_set_mnt_opts(struct super_block *sb, out_double_mount: rc = -EINVAL; pr_warn("SELinux: mount invalid. Same superblock, different " "security settings for (dev %s, type %s)\n", sb->s_id, name); "security settings for (dev %s, type %s)\n", sb->s_id, sb->s_type->name); goto out; } Loading Loading @@ -998,20 +987,9 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, static int selinux_parse_opts_str(char *options, void **mnt_opts) { struct selinux_mnt_opts *opts = *mnt_opts; char *p; char *context = NULL, *defcontext = NULL; char *fscontext = NULL, *rootcontext = NULL; int rc, num_mnt_opts = 0; struct security_mnt_opts *opts = *mnt_opts; if (!opts) { opts = kzalloc(sizeof(struct security_mnt_opts), GFP_KERNEL); *mnt_opts = opts; if (!opts) return -ENOMEM; } opts->num_mnt_opts = 0; int rc; /* Standard string-based options. */ while ((p = strsep(&options, "|")) != NULL) { Loading @@ -1023,54 +1001,60 @@ static int selinux_parse_opts_str(char *options, token = match_token(p, tokens, args); if (!opts) { opts = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL); if (!opts) return -ENOMEM; } switch (token) { case Opt_context: if (context || defcontext) { if (opts->context || opts->defcontext) { rc = -EINVAL; pr_warn(SEL_MOUNT_FAIL_MSG); goto out_err; } context = match_strdup(&args[0]); if (!context) { opts->context = match_strdup(&args[0]); if (!opts->context) { rc = -ENOMEM; goto out_err; } break; case Opt_fscontext: if (fscontext) { if (opts->fscontext) { rc = -EINVAL; pr_warn(SEL_MOUNT_FAIL_MSG); goto out_err; } fscontext = match_strdup(&args[0]); if (!fscontext) { opts->fscontext = match_strdup(&args[0]); if (!opts->fscontext) { rc = -ENOMEM; goto out_err; } break; case Opt_rootcontext: if (rootcontext) { if (opts->rootcontext) { rc = -EINVAL; pr_warn(SEL_MOUNT_FAIL_MSG); goto out_err; } rootcontext = match_strdup(&args[0]); if (!rootcontext) { opts->rootcontext = match_strdup(&args[0]); if (!opts->rootcontext) { rc = -ENOMEM; goto out_err; } break; case Opt_defcontext: if (context || defcontext) { if (opts->context || opts->defcontext) { rc = -EINVAL; pr_warn(SEL_MOUNT_FAIL_MSG); goto out_err; } defcontext = match_strdup(&args[0]); if (!defcontext) { opts->defcontext = match_strdup(&args[0]); if (!opts->defcontext) { rc = -ENOMEM; goto out_err; } Loading @@ -1084,43 +1068,12 @@ static int selinux_parse_opts_str(char *options, } } rc = -ENOMEM; opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_KERNEL); if (!opts->mnt_opts) goto out_err; opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_KERNEL); if (!opts->mnt_opts_flags) goto out_err; if (fscontext) { opts->mnt_opts[num_mnt_opts] = fscontext; opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT; } if (context) { opts->mnt_opts[num_mnt_opts] = context; opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT; } if (rootcontext) { opts->mnt_opts[num_mnt_opts] = rootcontext; opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT; } if (defcontext) { opts->mnt_opts[num_mnt_opts] = defcontext; opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT; } opts->num_mnt_opts = num_mnt_opts; *mnt_opts = opts; return 0; out_err: security_free_mnt_opts(mnt_opts); kfree(context); kfree(defcontext); kfree(fscontext); kfree(rootcontext); if (opts) selinux_free_mnt_opts(opts); return rc; } Loading Loading @@ -2752,10 +2705,10 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts) static int selinux_sb_remount(struct super_block *sb, void *mnt_opts) { struct security_mnt_opts *opts = mnt_opts; int i, *flags; char **mount_options; struct selinux_mnt_opts *opts = mnt_opts; struct superblock_security_struct *sbsec = sb->s_security; u32 sid; int rc; if (!(sbsec->flags & SE_SBINITIALIZED)) return 0; Loading @@ -2763,48 +2716,35 @@ static int selinux_sb_remount(struct super_block *sb, void *mnt_opts) if (!opts) return 0; mount_options = opts->mnt_opts; flags = opts->mnt_opts_flags; for (i = 0; i < opts->num_mnt_opts; i++) { u32 sid; int rc; if (flags[i] == SBLABEL_MNT) continue; rc = security_context_str_to_sid(&selinux_state, mount_options[i], &sid, GFP_KERNEL); if (rc) { 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); if (opts->fscontext) { rc = parse_sid(sb, opts->fscontext, &sid); if (rc) return rc; } switch (flags[i]) { case FSCONTEXT_MNT: if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid)) goto out_bad_option; break; case CONTEXT_MNT: } if (opts->context) { rc = parse_sid(sb, opts->context, &sid); if (rc) return rc; if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid)) goto out_bad_option; break; case ROOTCONTEXT_MNT: { } if (opts->rootcontext) { struct inode_security_struct *root_isec; root_isec = backing_inode_security(sb->s_root); rc = parse_sid(sb, opts->rootcontext, &sid); if (rc) return rc; if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid)) goto out_bad_option; break; } case DEFCONTEXT_MNT: if (opts->defcontext) { rc = parse_sid(sb, opts->defcontext, &sid); if (rc) return rc; if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid)) goto out_bad_option; break; default: return -EINVAL; } } return 0; Loading