Subject: | Linux panic on recursive mtpt rmdir |
Date: | Wed, 12 Oct 2011 18:04:21 -0500 |
To: | security@openafs.org |
From: | Andrew Deason <adeason@sinenomine.net> |
I am submitting this to the security queue, because it allows at least
anyone with 'a' privs anywhere in AFS to panic the client. I think this
is representative of the "we're in the kernel, so almost any bug is a
local DoS" notion, so I don't know how much of a "security" issue this
should be in general. But since it's so trivial to execute... I'm just
being safe.
Doing the following appears to always cause a BUG on Linux (so, I think
depending on the config, causes a panic) if 'foo' is a volume:
fs mkm foo foo
cd foo
fs mkm foo foo
rmdir foo
This happens on at least RHEL5 (2.6.18) OpenAFS 1.4.14, and master; I
assume virtually all versions of either are applicable, since I don't
see much variation in the relevant code paths. The BUG is in may_delete:
BUG_ON(victim->d_parent->d_inode != dir);
This should not be surprising, as this should be rather familiar:
https://lists.openafs.org/pipermail/openafs-devel/2005-December/013334.html
I believe the reason is that, while afs_linux_lookup tries to invalidate
the alias dentry when we look up a directory, we cannot invalidate a
dentry that is in use. And when we rmdir, we look up the "parent" mount
point, grab a ref, and then lookup the "child". So when we look up the
child, the parent dentry is the one associated with the inode, and we
can't invalidate it because it is in use by the caller. So we return the
"parent" dentry, which of course has a different d_parent (it's one
level higher) and so that bug triggers.
I am not entirely sure what can be done about this. The naive workaround
is just to add the duplicate dentry anyway when d_invalidate fails,
resulting in (at least) two dentries for the vol root inode. As far as I
know this is against the "rules", but it does not seem to immediately
panic the box or anything. So, one possibly terrible idea is to do that
for the lookup, but get something else (another background daemon or
whatever) to try and remove the duplicate dentries as quickly as
possible immediately afterwards.
Or we can just add multiple dentries on the inode, and just give our
best effort to try and reduce how many we have. In that linked thread,
chas says we used to not care how many dentries we had on the inode. Any
idea how that causes problems specifically? (I mean, I know _why_
conceptually Linux doesn't like it, but I'm not sure what specifically
will explode if we do) And even if doing that results in a panic or
something sometimes... well, that's better than the 100% of the time
that the current situation is.
--
Andrew Deason
adeason@sinenomine.net
anyone with 'a' privs anywhere in AFS to panic the client. I think this
is representative of the "we're in the kernel, so almost any bug is a
local DoS" notion, so I don't know how much of a "security" issue this
should be in general. But since it's so trivial to execute... I'm just
being safe.
Doing the following appears to always cause a BUG on Linux (so, I think
depending on the config, causes a panic) if 'foo' is a volume:
fs mkm foo foo
cd foo
fs mkm foo foo
rmdir foo
This happens on at least RHEL5 (2.6.18) OpenAFS 1.4.14, and master; I
assume virtually all versions of either are applicable, since I don't
see much variation in the relevant code paths. The BUG is in may_delete:
BUG_ON(victim->d_parent->d_inode != dir);
This should not be surprising, as this should be rather familiar:
https://lists.openafs.org/pipermail/openafs-devel/2005-December/013334.html
I believe the reason is that, while afs_linux_lookup tries to invalidate
the alias dentry when we look up a directory, we cannot invalidate a
dentry that is in use. And when we rmdir, we look up the "parent" mount
point, grab a ref, and then lookup the "child". So when we look up the
child, the parent dentry is the one associated with the inode, and we
can't invalidate it because it is in use by the caller. So we return the
"parent" dentry, which of course has a different d_parent (it's one
level higher) and so that bug triggers.
I am not entirely sure what can be done about this. The naive workaround
is just to add the duplicate dentry anyway when d_invalidate fails,
resulting in (at least) two dentries for the vol root inode. As far as I
know this is against the "rules", but it does not seem to immediately
panic the box or anything. So, one possibly terrible idea is to do that
for the lookup, but get something else (another background daemon or
whatever) to try and remove the duplicate dentries as quickly as
possible immediately afterwards.
Or we can just add multiple dentries on the inode, and just give our
best effort to try and reduce how many we have. In that linked thread,
chas says we used to not care how many dentries we had on the inode. Any
idea how that causes problems specifically? (I mean, I know _why_
conceptually Linux doesn't like it, but I'm not sure what specifically
will explode if we do) And even if doing that results in a panic or
something sometimes... well, that's better than the 100% of the time
that the current situation is.
--
Andrew Deason
adeason@sinenomine.net