security: filesystem capabilities: fix fragile setuid fixup code

This commit includes a bugfix for the fragile setuid fixup code in the
case that filesystem capabilities are supported (in access()).  The effect
of this fix is gated on filesystem capability support because changing
securebits is only supported when filesystem capabilities support is
configured.)

[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Andrew G. Morgan <morgan@kernel.org>
Acked-by: Serge Hallyn <serue@us.ibm.com>
Acked-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Andrew G. Morgan 2008-07-04 09:59:58 -07:00 committed by Linus Torvalds
parent abbaeff38c
commit 086f7316f0
4 changed files with 53 additions and 22 deletions

View file

@ -16,6 +16,7 @@
#include <linux/namei.h>
#include <linux/backing-dev.h>
#include <linux/capability.h>
#include <linux/securebits.h>
#include <linux/security.h>
#include <linux/mount.h>
#include <linux/vfs.h>
@ -425,7 +426,7 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
{
struct nameidata nd;
int old_fsuid, old_fsgid;
kernel_cap_t old_cap;
kernel_cap_t uninitialized_var(old_cap); /* !SECURE_NO_SETUID_FIXUP */
int res;
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
@ -433,23 +434,27 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
old_fsuid = current->fsuid;
old_fsgid = current->fsgid;
old_cap = current->cap_effective;
current->fsuid = current->uid;
current->fsgid = current->gid;
/*
* Clear the capabilities if we switch to a non-root user
*
* FIXME: There is a race here against sys_capset. The
* capabilities can change yet we will restore the old
* value below. We should hold task_capabilities_lock,
* but we cannot because user_path_walk can sleep.
*/
if (current->uid)
cap_clear(current->cap_effective);
else
current->cap_effective = current->cap_permitted;
if (!issecure(SECURE_NO_SETUID_FIXUP)) {
/*
* Clear the capabilities if we switch to a non-root user
*/
#ifndef CONFIG_SECURITY_FILE_CAPABILITIES
/*
* FIXME: There is a race here against sys_capset. The
* capabilities can change yet we will restore the old
* value below. We should hold task_capabilities_lock,
* but we cannot because user_path_walk can sleep.
*/
#endif /* ndef CONFIG_SECURITY_FILE_CAPABILITIES */
if (current->uid)
old_cap = cap_set_effective(__cap_empty_set);
else
old_cap = cap_set_effective(current->cap_permitted);
}
res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
if (res)
@ -478,7 +483,9 @@ out_path_release:
out:
current->fsuid = old_fsuid;
current->fsgid = old_fsgid;
current->cap_effective = old_cap;
if (!issecure(SECURE_NO_SETUID_FIXUP))
cap_set_effective(old_cap);
return res;
}