lkml.org 
[lkml]   [2022]   [Jan]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patches in this message
/
Date
From
SubjectRe: [PATCH RFC v2 1/2] selinux: Fix selinux_sb_mnt_opts_compat()
On Tue, 25 Jan 2022, Paul Moore wrote:

> On Tue, Jan 25, 2022 at 1:51 PM Scott Mayhew <smayhew@redhat.com> wrote:
> > On Tue, 25 Jan 2022, Paul Moore wrote:
> > > On Tue, Jan 25, 2022 at 12:31 PM Scott Mayhew <smayhew@redhat.com> wrote:
> > > > On Mon, 24 Jan 2022, Paul Moore wrote:
> > > > > On Thu, Jan 20, 2022 at 4:50 PM Scott Mayhew <smayhew@redhat.com> wrote:
> > > > > >
> > > > > > selinux_sb_mnt_opts_compat() is called under the sb_lock spinlock and
> > > > > > shouldn't be performing any memory allocations. Fix this by parsing the
> > > > > > sids at the same time we're chopping up the security mount options
> > > > > > string and then using the pre-parsed sids when doing the comparison.
> > > > > >
> > > > > > Fixes: cc274ae7763d ("selinux: fix sleeping function called from invalid context")
> > > > > > Fixes: 69c4a42d72eb ("lsm,selinux: add new hook to compare new mount to an existing mount")
> > > > > > Signed-off-by: Scott Mayhew <smayhew@redhat.com>
> > > > > > ---
> > > > > > security/selinux/hooks.c | 112 ++++++++++++++++++++++++++-------------
> > > > > > 1 file changed, 76 insertions(+), 36 deletions(-)
> > >
> > > ...
> > >
> > > > > > switch (token) {
> > > > > > case Opt_context:
> > > > > > if (opts->context || opts->defcontext)
> > > > > > goto err;
> > > > > > opts->context = s;
> > > > > > + if (preparse_sid) {
> > > > > > + rc = parse_sid(NULL, s, &sid);
> > > > > > + if (rc == 0) {
> > > > > > + opts->context_sid = sid;
> > > > > > + opts->preparsed |= CONTEXT_MNT;
> > > > > > + }
> > > > > > + }
> > > > >
> > > > > Is there a reason why we need a dedicated sid variable as opposed to
> > > > > passing opt->context_sid as the parameter? For example:
> > > > >
> > > > > rc = parse_sid(NULL, s, &opts->context_sid);
> > > >
> > > > We don't need a dedicated sid variable. Should I make similar changes
> > > > in the second patch (get rid of the local sid variable in
> > > > selinux_sb_remount() and the *context_sid variables in
> > > > selinux_set_mnt_opts())?
> > >
> > > Yes please, I should have explicitly mentioned that.
> >
> > Actually, delayed_superblock_init() calls selinux_set_mnt_opts() with
> > mnt_opts == NULL, so there would have to be a lot of checks like
> >
> > if (opts && opts->fscontext_sid) {
> >
> > in the later parts of that function, which is kind of clunky. I can
> > still do it if you want though.
>
> I might be misunderstanding your concern, but in
> selinux_set_mnt_opts() all of the "opts->XXX" if-conditionals are
> protected by being inside an if-statement that checks to ensure "opts"
> is not NULL. Am I missing something?

Sorry for being unclear. The parts where the sids are (potentially)
being parsed are inside an "if (opts) { ... }" block... but later in the
function those sids are used in various tests/assignments. So if we
wanted to eliminate the four local context_sid variables (using the
variables in opts instead), then there would need to be additional
checks to avoid dereferencing opts when it's NULL.

In other words, if the local context_sid variables are kept, then the
change to selinux_set_mnt_opts() would look like this (option A):

---8<---
@@ -676,36 +676,48 @@ static int selinux_set_mnt_opts(struct super_block *sb,
*/
if (opts) {
if (opts->fscontext) {
- rc = parse_sid(sb, opts->fscontext, &fscontext_sid);
- if (rc)
- goto out;
+ if (opts->fscontext_sid == SECSID_NULL ) {
+ rc = parse_sid(sb, opts->fscontext, &fscontext_sid);
+ if (rc)
+ goto out;
+ } else
+ fscontext_sid = opts->fscontext_sid;
if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
fscontext_sid))
goto out_double_mount;
sbsec->flags |= FSCONTEXT_MNT;
}
if (opts->context) {
- rc = parse_sid(sb, opts->context, &context_sid);
- if (rc)
- goto out;
+ if (opts->context_sid == SECSID_NULL) {
+ rc = parse_sid(sb, opts->context, &context_sid);
+ if (rc)
+ goto out;
+ } else
+ context_sid = opts->context_sid;
if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
context_sid))
goto out_double_mount;
sbsec->flags |= CONTEXT_MNT;
}
if (opts->rootcontext) {
- rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid);
- if (rc)
- goto out;
+ if (opts->rootcontext_sid == SECSID_NULL) {
+ rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid);
+ if (rc)
+ goto out;
+ } else
+ rootcontext_sid = opts->rootcontext_sid;
if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
rootcontext_sid))
goto out_double_mount;
sbsec->flags |= ROOTCONTEXT_MNT;
}
if (opts->defcontext) {
- rc = parse_sid(sb, opts->defcontext, &defcontext_sid);
- if (rc)
- goto out;
+ if (opts->defcontext_sid == SECSID_NULL) {
+ rc = parse_sid(sb, opts->defcontext, &defcontext_sid);
+ if (rc)
+ goto out;
+ } else
+ defcontext_sid = opts->defcontext_sid;
if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
defcontext_sid))
goto out_double_mount;
---8<---
and if the local context_sid variables are removed, the change to selinux_set_mnt_opts()
would look like this (option B):

---8<---
@@ -627,8 +627,6 @@ static int selinux_set_mnt_opts(struct super_block *sb,
struct dentry *root = 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;
int rc = 0;

mutex_lock(&sbsec->lock);
@@ -676,38 +674,50 @@ static int selinux_set_mnt_opts(struct super_block *sb,
*/
if (opts) {
if (opts->fscontext) {
- rc = parse_sid(sb, opts->fscontext, &fscontext_sid);
- if (rc)
- goto out;
+ if (opts->fscontext_sid == SECSID_NULL ) {
+ rc = parse_sid(sb, opts->fscontext,
+ &opts->fscontext_sid);
+ if (rc)
+ goto out;
+ }
if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
- fscontext_sid))
+ opts->fscontext_sid))
goto out_double_mount;
sbsec->flags |= FSCONTEXT_MNT;
}
if (opts->context) {
- rc = parse_sid(sb, opts->context, &context_sid);
- if (rc)
- goto out;
+ if (opts->context_sid == SECSID_NULL) {
+ rc = parse_sid(sb, opts->context,
+ &opts->context_sid);
+ if (rc)
+ goto out;
+ }
if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
- context_sid))
+ opts->context_sid))
goto out_double_mount;
sbsec->flags |= CONTEXT_MNT;
}
if (opts->rootcontext) {
- rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid);
- if (rc)
- goto out;
+ if (opts->rootcontext_sid == SECSID_NULL) {
+ rc = parse_sid(sb, opts->rootcontext,
+ &opts->rootcontext_sid);
+ if (rc)
+ goto out;
+ }
if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
- rootcontext_sid))
+ opts->rootcontext_sid))
goto out_double_mount;
sbsec->flags |= ROOTCONTEXT_MNT;
}
if (opts->defcontext) {
- rc = parse_sid(sb, opts->defcontext, &defcontext_sid);
- if (rc)
- goto out;
+ if (opts->defcontext_sid == SECSID_NULL) {
+ rc = parse_sid(sb, opts->defcontext,
+ &opts->defcontext_sid);
+ if (rc)
+ goto out;
+ }
if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
- defcontext_sid))
+ opts->defcontext_sid))
goto out_double_mount;
sbsec->flags |= DEFCONTEXT_MNT;
}
@@ -760,8 +770,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
strcmp(sb->s_type->name, "ramfs") &&
strcmp(sb->s_type->name, "devpts") &&
strcmp(sb->s_type->name, "overlay")) {
- if (context_sid || fscontext_sid || rootcontext_sid ||
- defcontext_sid) {
+ if (opts && (opts->context_sid || opts->fscontext_sid ||
+ opts->rootcontext_sid || opts->defcontext_sid)) {
rc = -EACCES;
goto out;
}
@@ -779,12 +789,13 @@ static int selinux_set_mnt_opts(struct super_block *sb,
}

/* sets the context of the superblock for the fs being mounted. */
- if (fscontext_sid) {
- rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
+ if (opts && opts->fscontext_sid) {
+ rc = may_context_mount_sb_relabel(opts->fscontext_sid,
+ sbsec, cred);
if (rc)
goto out;

- sbsec->sid = fscontext_sid;
+ sbsec->sid = opts->fscontext_sid;
}

/*
@@ -792,42 +803,43 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* sets the label used on all file below the mountpoint, and will set
* the superblock context if not already set.
*/
- if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
+ if (kern_flags & SECURITY_LSM_NATIVE_LABELS &&
+ !(opts && opts->context_sid)) {
sbsec->behavior = SECURITY_FS_USE_NATIVE;
*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
}

- if (context_sid) {
- if (!fscontext_sid) {
- rc = may_context_mount_sb_relabel(context_sid, sbsec,
- cred);
+ if (opts && opts->context_sid) {
+ if (!opts->fscontext_sid) {
+ rc = may_context_mount_sb_relabel(opts->context_sid,
+ sbsec, cred);
if (rc)
goto out;
- sbsec->sid = context_sid;
+ sbsec->sid = opts->context_sid;
} else {
- rc = may_context_mount_inode_relabel(context_sid, sbsec,
- cred);
+ rc = may_context_mount_inode_relabel(opts->context_sid,
+ sbsec, cred);
if (rc)
goto out;
}
- if (!rootcontext_sid)
- rootcontext_sid = context_sid;
+ if (!opts->rootcontext_sid)
+ opts->rootcontext_sid = opts->context_sid;

- sbsec->mntpoint_sid = context_sid;
+ sbsec->mntpoint_sid = opts->context_sid;
sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
}

- if (rootcontext_sid) {
- rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
- cred);
+ if (opts && opts->rootcontext_sid) {
+ rc = may_context_mount_inode_relabel(opts->rootcontext_sid,
+ sbsec, cred);
if (rc)
goto out;

- root_isec->sid = rootcontext_sid;
+ root_isec->sid = opts->rootcontext_sid;
root_isec->initialized = LABEL_INITIALIZED;
}

- if (defcontext_sid) {
+ if (opts && opts->defcontext_sid) {
if (sbsec->behavior != SECURITY_FS_USE_XATTR &&
sbsec->behavior != SECURITY_FS_USE_NATIVE) {
rc = -EINVAL;
@@ -836,14 +848,14 @@ static int selinux_set_mnt_opts(struct super_block *sb,
goto out;
}

- if (defcontext_sid != sbsec->def_sid) {
- rc = may_context_mount_inode_relabel(defcontext_sid,
+ if (opts->defcontext_sid != sbsec->def_sid) {
+ rc = may_context_mount_inode_relabel(opts->defcontext_sid,
sbsec, cred);
if (rc)
goto out;
}

- sbsec->def_sid = defcontext_sid;
+ sbsec->def_sid = opts->defcontext_sid;
}

out_set_opts:
---8<---
-Scott
>
> --
> paul-moore.com
>

\
 
 \ /
  Last update: 2022-01-26 21:42    [W:0.063 / U:2.812 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site