Skip to contentSkip to conversation

Capabilities: BUG when an invalid capability is requested

PATCH In review Eric Paris 4 participants 4 messages Oct 29, 2008 – Oct 30, 2008 Capabilities

lore
Share & tools
lore

Eric Paris

author
#0 lore raw

PATCH 1/1 Capabilities: BUG when an invalid capability is requested

If an invalid (large) capability is requested the capabilities system may panic as it is dereferencing an array of fixed (short) length. Its possible (and actually often happens) that the capability system accidentally stumbled into a valid memory region but it also regularly happens that it hits invalid memory and BUGs. If such an operation does get past cap_capable then the selinux system is sure to have problems as it already does a (simple) validity check and BUG. This is known to happen by the broken and buggy firegl driver.

This patch cleanly checks all capable calls and BUG if a call is for an invalid capability. This will likely break the firegl driver for some situations, but it is the right thing to do. Garbage into a security system gets you killed/bugged

---

 kernel/capability.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)
kernel/capability.c +5 -0
index 33e51e7..50d9d99 100644
@@ -498,6 +498,11 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
  */
 int capable(int cap)
 {
+	if (unlikely(!cap_valid(cap))) {
+		printk(KERN_CRIT "capable() called with invalid cap=%u\n", cap);
+		BUG();
+	}
+
 	if (has_capability(current, cap)) {
 		current->flags |= PF_SUPERPRIV;
 		return 1;
Acked-by on v1 1/1
#1 lore raw
Quoted 9 lines · On Wed, 29 Oct 2008 11:42:12 -0400 Eric Paris <[email protected]> wrote:

If an invalid (large) capability is requested the capabilities system may panic as it is dereferencing an array of fixed (short) length. Its possible (and actually often happens) that the capability system accidentally stumbled into a valid memory region but it also regularly happens that it hits invalid memory and BUGs. If such an operation does get past cap_capable then the selinux system is sure to have problems as it already does a (simple) validity check and BUG. This is known to happen by the broken and buggy firegl driver.

Quoted 7 lines

This patch cleanly checks all capable calls and BUG if a call is for an invalid capability. This will likely break the firegl driver for some situations, but it is the right thing to do. Garbage into a security system gets you killed/bugged

Acked-by on v1 1/1
#2 lore raw
In reply to Eric Paris
Quoted 9 lines · Eric Paris

If an invalid (large) capability is requested the capabilities system may panic as it is dereferencing an array of fixed (short) length. Its possible (and actually often happens) that the capability system accidentally stumbled into a valid memory region but it also regularly happens that it hits invalid memory and BUGs. If such an operation does get past cap_capable then the selinux system is sure to have problems as it already does a (simple) validity check and BUG. This is known to happen by the broken and buggy firegl driver.

Quoted 6 lines

This patch cleanly checks all capable calls and BUG if a call is for an invalid capability. This will likely break the firegl driver for some situations, but it is the right thing to do. Garbage into a security system gets you killed/bugged

I really don't like this, but I'm not sure we really have a choice.

I suppose we can think later about whether it's worthwhile (a) having a separate capable() function exported, keeping one without the check for compiled-in use only, and/or (b) changing the cap_valid() definition to be "(((unsigned int)cap) <= CAP_LAST_CAP)" which seems to work and shave one whopping instruction. I suspect the answer will be no to both.

Thanks, Eric.

-serge

Quoted 23 lines

---

 kernel/capability.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)
kernel/capability.c +5 -0
index 33e51e7..50d9d99 100644
@@ -498,6 +498,11 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
  */
 int capable(int cap)
 {
+	if (unlikely(!cap_valid(cap))) {
+		printk(KERN_CRIT "capable() called with invalid cap=%u\n", cap);
+		BUG();
+	}
+
 	if (has_capability(current, cap)) {
 		current->flags |= PF_SUPERPRIV;
 		return 1;
#3 lore raw

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Cheers

Andrew

Quoted 45 lines · Serge E. Hallyn
Quoted 9 lines · Eric Paris

If an invalid (large) capability is requested the capabilities system may panic as it is dereferencing an array of fixed (short) length. Its possible (and actually often happens) that the capability system accidentally stumbled into a valid memory region but it also regularly happens that it hits invalid memory and BUGs. If such an operation does get past cap_capable then the selinux system is sure to have problems as it already does a (simple) validity check and BUG. This is known to happen by the broken and buggy firegl driver.

Quoted 6 lines

This patch cleanly checks all capable calls and BUG if a call is for an invalid capability. This will likely break the firegl driver for some situations, but it is the right thing to do. Garbage into a security system gets you killed/bugged

I really don't like this, but I'm not sure we really have a choice.

I suppose we can think later about whether it's worthwhile (a) having a separate capable() function exported, keeping one without the check for compiled-in use only, and/or (b) changing the cap_valid() definition to be "(((unsigned int)cap) <= CAP_LAST_CAP)" which seems to work and shave one whopping instruction. I suspect the answer will be no to both.

Thanks, Eric.

-serge

Quoted 14 lines

---

 kernel/capability.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)
kernel/capability.c +1 -0
index 33e51e7..50d9d99 100644
@@ -498,6 +498,11 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
  */
 int capable(int cap)
 {
+	if (unlikely(!cap_valid(cap))) {
Quoted 8 lines

kernel/capability.c asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data) · line 508

Quoted 8 lines
kernel/capability.c +4 -0
+		printk(KERN_CRIT "capable() called with invalid cap=%u\n", cap);
+		BUG();
+	}
+
 	if (has_capability(current, cap)) {
 		current->flags |= PF_SUPERPRIV;
 		return 1;

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (Darwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFJCQu++bHCR3gb8jsRAi/GAKCgAFXp+wRi8oWffVDWJUAeZMzsuwCcCAd6 AbXnEetgq2fI8t2lIJikmtQ=
=dl4H
-----END PGP SIGNATURE-----