From: James Morris <jmorris@namei.org>
To: Nagendra Singh Tomar <nagendra_tomar@adaptec.com>
Cc: Greg KH <greg@kroah.com>, Tejun Heo <htejun@gmail.com>,
Stephen Smalley <sds@tycho.nsa.gov>,
Eric Paris <eparis@redhat.com>,
linux-kernel@vger.kernel.org,
Andrew Morton <akpm@linux-foundation.org>
Subject: [RFC PATCH] Re: BUG in sysfs_remove_group
Date: Thu, 19 Apr 2007 17:50:36 -0400 (EDT) [thread overview]
Message-ID: <Line.LNX.4.64.0704191222460.1633@d.namei> (raw)
In-Reply-To: <20070417100756.32454f9d.akpm@linux-foundation.org>
On Tue, 17 Apr 2007, Nagendra Singh Tomar wrote:
> The return value of lookup_one_len() is used without testing for error return.
> This results in the following oops when SELinux is enabled and enforced. The
> reason for the Oops is as follows.
> The shell's (bash) SELinux domain is not allowed "search" permission in sysfs
> filesystem (type sysfs_t in the default SELinux policy), due to which the
> lookup_one_len->__lookup_hash->permission->security_inode_permission
> returns -EACCESS. This -ve number is passed as the 'dir' argument to
> remove_files() and then to sysfs_hash_and_remove() which accesses this bogus
> pointer resulting in the crash.
> A simple fix will be to check for IS_ERR(dir) in sysfs_remove_group() and
> return (without doing anything) if true, but this will result in the
> corresponding sysfs dirent entries to be leaked. IMHO the proper fix will be
> to not check for "search" permissions in such cases where the internal kernel
> code is trying to free up sysfs entries like the current case.
I hit the same issue a couple of days before with MLS policy, and your
report and analysis proved most useful, thanks.
A preliminary patch for this is below, based on suggestions from Stephen
Smalley.
Please review, and Nagendra, let me know if this works for you.
Prevent permission checking from being peformed when the kernel wants to
unconditionally remove a sysfs group, by introducing an kernel-only
variant of lookup_one_len(), lookup_one_len_kern().
Additionally, as sysfs_remove_group() does not check the return value of
the lookup before using it, a BUG_ON has been added to pinpoint the cause
of any problems potentially caused by this (and as a form of annotation).
Signed-off-by: James Morris <jmorris@namei.org>
---
fs/namei.c | 29 +++++++++++++++++++++--------
fs/sysfs/group.c | 6 ++++--
include/linux/namei.h | 1 +
3 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index ee60cc4..70d3c46 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1248,17 +1248,20 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags,
* needs parent already locked. Doesn't follow mounts.
* SMP-safe.
*/
-static struct dentry * __lookup_hash(struct qstr *name, struct dentry * base, struct nameidata *nd)
+static struct dentry * __lookup_hash(struct qstr *name, struct dentry * base, struct nameidata *nd, int kern)
{
struct dentry * dentry;
struct inode *inode;
int err;
inode = base->d_inode;
- err = permission(inode, MAY_EXEC, nd);
- dentry = ERR_PTR(err);
- if (err)
- goto out;
+
+ if (likely(!kern)) {
+ err = permission(inode, MAY_EXEC, nd);
+ dentry = ERR_PTR(err);
+ if (err)
+ goto out;
+ }
/*
* See if the low-level filesystem might want
@@ -1289,11 +1292,11 @@ out:
static struct dentry *lookup_hash(struct nameidata *nd)
{
- return __lookup_hash(&nd->last, nd->dentry, nd);
+ return __lookup_hash(&nd->last, nd->dentry, nd, 0);
}
/* SMP-safe */
-struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
+static inline struct dentry * __lookup_one_len(const char * name, struct dentry * base, int len, int kern)
{
unsigned long hash;
struct qstr this;
@@ -1313,11 +1316,21 @@ struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
}
this.hash = end_name_hash(hash);
- return __lookup_hash(&this, base, NULL);
+ return __lookup_hash(&this, base, NULL, kern);
access:
return ERR_PTR(-EACCES);
}
+struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
+{
+ return __lookup_one_len(name, base, len, 0);
+}
+
+struct dentry * lookup_one_len_kern(const char * name, struct dentry * base, int len)
+{
+ return __lookup_one_len(name, base, len, 1);
+}
+
/*
* namei()
*
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index b20951c..52eed2a 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -70,9 +70,11 @@ void sysfs_remove_group(struct kobject * kobj,
{
struct dentry * dir;
- if (grp->name)
- dir = lookup_one_len(grp->name, kobj->dentry,
+ if (grp->name) {
+ dir = lookup_one_len_kern(grp->name, kobj->dentry,
strlen(grp->name));
+ BUG_ON(IS_ERR(dir));
+ }
else
dir = dget(kobj->dentry);
diff --git a/include/linux/namei.h b/include/linux/namei.h
index d39a5a6..d4031ff 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -82,6 +82,7 @@ extern struct file *nameidata_to_filp(struct nameidata *nd, int flags);
extern void release_open_intent(struct nameidata *);
extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
+extern struct dentry * lookup_one_len_kern(const char *, struct dentry *, int);
extern int follow_down(struct vfsmount **, struct dentry **);
extern int follow_up(struct vfsmount **, struct dentry **);
next parent reply other threads:[~2007-04-19 21:50 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20070417100756.32454f9d.akpm@linux-foundation.org>
2007-04-19 21:50 ` James Morris [this message]
2007-04-21 0:22 ` [RFC PATCH - Try #2] " James Morris
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Line.LNX.4.64.0704191222460.1633@d.namei \
--to=jmorris@namei.org \
--cc=akpm@linux-foundation.org \
--cc=eparis@redhat.com \
--cc=greg@kroah.com \
--cc=htejun@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=nagendra_tomar@adaptec.com \
--cc=sds@tycho.nsa.gov \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®